quarta-feira, 23 de outubro de 2024

MILK-V duo 256 - YOLO5 - NEW CASE

 

Com WSL2 e docker 
Tradução

Detecção de objetos YOLOv5 usando TDL SDK da CVITEK.

O fluxo para fazer isso é aproximadamente o seguinte:

  1. Crie um inferência usando TDL SDK
  2. Converter o pré-modelo yolov5s.pt para o modelo ONNX
  3. Crie MLIR do modelo ONNX e cvimodel do MLIR
  4. Copie o inferência e o cvimodel para Milk-V Duo 256
  5. Experimente inferência usando imagens no Milk-V Duo

Em primeiro lugar, o que é o TDL da CVITEK?

O SDK fornecido pela CVITEK fornece este TDL como uma interface de programa unificada que envolve algoritmos de aprendizado de máquina, como detecção de objetos, reconhecimento facial, segmentação e detecção de pose.
Usando este SDK, você pode realizar inferências com eficiência usando o processador TPU integrado.

A propósito, o Milk-V Duo usa um chip CVITEK chamado CV1800B, mas o Duo256M usa um chip SOPHGO? Foi alterado para SG2002 e o desempenho foi melhorado.
Ao especificar o modelo do chip, não funcionará a menos que você faça distinção entre Duo e Duo256M.

O que é cvimodel?

Modelos de aprendizado de máquina criados para as TPUs acima.

Crie um raciocínio usando TDL SDK

> wget https://sophon-file.sophon.cn/sophon-prod-s3/drive/23/03/07/16/host-tools.tar.gz
> tar xvf host-tools.tar.gz
> export PATH=$PATH:$(pwd)/host-tools/gcc/riscv64-linux-musl-x86_64/bin

Depois de baixar o SDK para Duo256M com as variáveis ​​de ambiente acima instaladas, execute o build shell.

Ao executar o shell, um conjunto completo de amostras é compilado.

> git clone https://github.com/milkv-duo/cvitek-tdl-sdk-sg200x.git
> cd cvitek-tdl-sdk-sg200x
> cd sample
> ./compile_sample.sh

Se a compilação for bem-sucedida, cada módulo da amostra será construído. Desta vez usaremos  o módulosample_yolo5 gerado no diretório cvi_yolo .
(Mais tarde, copie este módulo para Duo256M e execute-o)

Crie um modelo de aprendizado de máquina para TPU

Desta vez seguiremos os passos do site oficial, começaremosyolov5s.pt com um modelo PyTorchfinalmente geraremos um cvimodel que possa ser usado com Milk-V Duo256M.

Construindo ambiente YOLOv5 e gerando modelo ONNX

ONNX (Open Neural Network Exchange) é um formato de representação intermediário para modelos usados ​​para converter vários frameworks de treinamento e inferência de aprendizado profundo. Ele suporta múltiplos frameworks de aprendizado profundo, incluindo TensorFlow, PyTorch, Caffe, etc. Converter modelos para o formato ONNX torna mais fácil implantar e inferir em diferentes frameworks de aprendizado profundo sem a necessidade de treinar novamente os modelos.

Em aplicações práticas, os modelos podem ser treinados usando PyTorch ou TensorFlow, exportados para o formato ONNX e então convertidos para o formato de modelo suportado pelo dispositivo de destino. O ONNX define um conjunto de formatos e ambientes padrão independentes de plataforma para aprimorar a interoperabilidade de vários modelos de IA, tornando-o relativamente aberto.

O arquivo ONNX não apenas armazena os pesos do modelo de rede neural, mas também armazena as informações estruturais do modelo e as informações de entrada e saída de cada camada na rede. Ele pode ser visualizado usando Netron, o que facilita ajustes subsequentes do modelo no trabalho de desenvolvimento. Dependendo do modelo, você pode obter o código-fonte. 

Após criar e ativar o ambiente venv, instale os módulos dependentes.

> git clone https://github.com/ultralytics/yolov5.git
> cd yolov5 > python3 -m venv venv > source venv/bin/activate > pip3 install -r requirements.txt > pip3 install onnx

baixar yolov5s.ptyolov5_export.py e exportar modelos ONNX.

> wget https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.pt
> wget https://raw.githubusercontent.com/milkv-duo/cvitek-tdl-sdk-sg200x/main/sample/yolo_export/yolov5_export.py
> python3 yolov5_export.py --weights ./yolov5s.pt --img-size 640 640
> ls *.onnx
yolov5s.onnx

Crie MLIR a partir do modelo ONNX e cvimodel  a partir do MLIR

A conversão direta do modelo ONNX para cvimodel não é possível. Primeiro converta-o em um objeto intermediário chamado MLIR.
Mantendo a pasta yolov5 como diretório atual, prossiga para obter o kit de ferramentas de conversão MLIR e construa seu ambiente de compilação em um contêiner Docker.

> docker run --rm --privileged --name tpudev -v ${PWD}:/workspace -it sophgo/tpuc_dev:latest
root@xxxx:/workspace# git clone https://github.com/milkv-duo/tpu-mlir.git
root@xxxx:/workspace# source ./tpu-mlir/envsetup.sh

A partir de agora iremos gerar arquivos, então crie uma pasta de trabalho e trabalhe nela.

root@xxxx:/workspace# mkdir work && cd work

Converter modelo ONNX em modelo MLIR

root@xxxx:/workspace# model_transform.py \
--model_name yolov5s \ --model_def ../yolov5s.onnx \ --input_shapes [[1,3,640,640]] \ --mean 0.0,0.0,0.0 \ --scale 0.0039216,0.0039216,0.0039216 \ --keep_aspect_ratio \ --pixel_format rgb \ --test_input ../tpu-mlir/regression/image/dog.jpg \ --test_result yolov5s_top_outputs.npz \ --mlir yolov5s.mlir

Calibrar especificando um conjunto de dados? Demora um pouco.

root@xxxx:/workspace# run_calibration.py \
yolov5s.mlir \ --dataset ../tpu-mlir/regression/dataset/COCO2017 \ --input_num 100 \ -o yolov5s_cali_table

Gere cvimodel. Se for para o SG2002, será.--chip cv181x

root@xxxx:/workspace# model_deploy.py \
--mlir yolov5s.mlir \ --quant_input --quant_output \ --quantize INT8 \ --calibration_table yolov5s_cali_table \ --chip cv181x \ --test_input yolov5s_in_f32.npz \ --test_reference yolov5s_top_outputs.npz \ --tolerance 0.85,0.45 \ --model yolov5_cv181x_int8_sym.cvimodel root@xxxx:/workspace# ls *.cvimodel yolov5_cv181x_int8_sym.cvimodel

Experimente inferência com Milk-V Duo256M

Copie todos os arquivos necessários para Milk-V Duo256M. 000000000113.jpg | dog.jpgdo site oficial.


Baixe tpu-sdk

Vá para o diretório  /workspace  no terminal Docker

cd /workspace

Baixe tpu sdk, Se você estiver utilizando Duo,  execute

git clone https://github.com/milkv-duo/tpu-sdk-cv180x.git
mv ./tpu-sdk-cv180x ./tpu-sdk

Caso contrário, se você estiver utilizando Duo 256M/Duo S , execute

git clone https://github.com/milkv-duo/tpu-sdk-sg200x.git
mv ./tpu-sdk-sg200x ./tpu-sdk


Copie arquivos tpu-sdk e modelos para o  Duo

No terminal da placa Duo, crie um novo diretório /mnt/tpu/

# mkdir -p /mnt/tpu && cd /mnt/tpu

No terminal do Docker (ver como executar acima), copie arquivos tpu-sdk e model para o Duo

# scp -r /workspace/tpu-sdk root@192.168.42.1:/mnt/tpu/
# scp yolov5_cv181x_int8_sym.cvimodel root@192.168.42.1:/mnt/tpu/tpu-sdk/

Set as variáveis de ambiente

No terminal da placa Duo, set as variáveis de ambiente

# cd /mnt/tpu/tpu-sdk
# source ./envs_tpu_sdk.sh
> ls
000000000113.jpg  dog.jpg  sample_yolov5  yolov5_cv181x_int8_sym.cvimodel
> scp * root@192.168.42.1:~/
> ssh root@192.168.42.1

Primeiro, vamos inferir dog.jpg

> ./sample_yolov5 yolov5_cv181x_int8_sym.cvimodel dog.jpg
version: 1.4.0 yolov5s Build at 2024-05-06 16:30:56 For platform cv181x Max SharedMem size:5734400 model opened:yolov5_cv181x_int8_sym.cvimodel detect res: 137.379303 217.066299 310.982025 541.966858 0.915610 16 detect res: 473.738098 71.988899 683.512390 176.103775 0.722637 2 detect res: 166.451904 118.458267 563.148132 423.640594 0.580343 1

detect res:O valor a seguir está no formato Bounding Boxies, como PyTorch: X1, Y1, X2, Y2, Score, Classes .

O índice Classes utiliza o conjunto de dados COCO2017 , então acompanhe o texto abaixo. No entanto, a saída do índice pela ferramenta é de origem zero, portanto combine o valor +1 com o texto abaixo.

Por exemplo, o resultado acima seria o seguinte.

16 => dog(17)
2 => car(3) 1 => bicycle(2)

https://github.com/amikelive/coco-labels/blob/master/coco-labels-2014_2017.txt

  1. person
  2. bicycle
  3. car
  4. motorcycle
  5. airplane
  6. bus
  7. train
  8. truck
  9. boat
  10. traffic light
  11. fire hydrant
  12. stop sign
  13. parking meter
  14. bench
  15. bird
  16. cat
  17. dog
  18. horse
  19. sheep
  20. cow
  21. elephant
  22. bear
  23. zebra
  24. giraffe
  25. backpack
  26. umbrella
  27. handbag
  28. tie
  29. suitcase
  30. frisbee
  31. skis
  32. snowboard
  33. sports ball
  34. kite
  35. baseball bat
  36. baseball glove
  37. skateboard
  38. surfboard
  39. tennis racket
  40. bottle
  41. wine glass
  42. cup
  43. fork
  44. knife
  45. spoon
  46. bowl
  47. banana
  48. apple
  49. sandwich
  50. orange
  51. broccoli
  52. carrot
  53. hot dog
  54. pizza
  55. donut
  56. cake
  57. chair
  58. couch
  59. potted plant
  60. bed
  61. dining table
  62. toilet
  63. tv
  64. laptop
  65. mouse
  66. remote
  67. keyboard
  68. cell phone
  69. microwave
  70. oven
  71. toaster
  72. sink
  73. refrigerator
  74. book
  75. clock
  76. vase
  77. scissors
  78. teddy bear
  79. hair drier
  80. toothbrush

Usando as informações do BoundingBox acima, tentei desenhar um retângulo usando o programa Python descrito posteriormente e o resultado é mostrado abaixo. Eu reconheço isso corretamente.

Da mesma forma, da próxima vez, tente inferir 000000000113.jpg .

> ./sample_yolov5 yolov5_cv181x_int8_sym.cvimodel 000000000113.jpg
version: 1.4.0
yolov5s Build at 2024-05-06 16:30:56 For platform cv181x
Max SharedMem size:5734400
model opened:yolov5_cv181x_int8_sym.cvimodel
detect res: 149.599243 52.756699 344.154053 434.715759 0.877362 0
detect res: 340.399902 96.056824 415.000000 423.052612 0.866147 0
detect res: 7.182785 34.055344 163.182800 521.089905 0.741203 0
detect res: 159.104950 433.623596 395.260651 550.903992 0.739044 55
detect res: 81.713333 456.810913 125.030563 518.194275 0.683194 41
detect res: 253.461395 364.123352 304.291901 454.123352 0.611235 43
detect res: 282.405457 93.188477 309.046570 121.621582 0.558343 41
detect res: 281.694244 61.441063 309.968231 91.748878 0.553116 41

Descobri que estava funcionando corretamente.

Se você preparar seu próprio modelo personalizado em vez do modelo yolov5s.pt , deverá ser capaz de detectar um objeto específico com Milk-V Duo256M.

Programa Python que desenha um retângulo usando o BoundingBox do resultado da detecção

sample_yolo5 gera apenas informações de BoundingBox, então abaixo está um programa Python que usa essas informações para desenhar um retângulo. As informações do resultado são codificadas, portanto, altere-as de acordo.

> python draw_boundingbox.py
# draw_boudingbox.py
import cv2
import numpy as np

# dog.jpg
input1 = {
  "file":"dog.jpg",
  "bounding_boxes" : [
    [137.379303, 217.066299, 310.982025, 541.966858, 0.915610, 16],
    [473.738098, 71.988899, 683.512390, 176.103775, 0.722637, 2],
    [166.451904, 118.458267, 563.148132, 423.640594, 0.580343, 1],
  ]
}

# 000000000113.jpg
input2 = {
  "file":"000000000113.jpg",
  "bounding_boxes" : [
    [149.599243, 52.756699, 344.154053, 434.715759, 0.877362, 0],
    [340.399902, 96.056824, 415.000000, 423.052612, 0.866147, 0],
    [7.182785, 34.055344, 163.182800, 521.089905, 0.741203, 0],
    [159.104950, 433.623596, 395.260651, 550.903992, 0.739044, 55],
    [81.713333, 456.810913, 125.030563, 518.194275, 0.683194, 41],
    [253.461395, 364.123352, 304.291901, 454.123352, 0.611235, 43],
    [282.405457, 93.188477, 309.046570, 121.621582, 0.558343, 41],
    [281.694244, 61.441063, 309.968231, 91.748878, 0.553116, 41],
  ]
}

# どのデータを描画するか?
input_data = input2

# COCO2017 Labels
# https://github.com/amikelive/coco-labels/blob/master/coco-labels-2014_2017.txt
coco2017_labels = [
"person",
"bicycle",
"car",
"motorcycle",
"airplane",
"bus",
"train",
"truck",
"boat",
"traffic light",
"fire hydrant",
"stop sign",
"parking meter",
"bench",
"bird",
"cat",
"dog",
"horse",
"sheep",
"cow",
"elephant",
"bear",
"zebra",
"giraffe",
"backpack",
"umbrella",
"handbag",
"tie",
"suitcase",
"frisbee",
"skis",
"snowboard",
"sports ball",
"kite",
"baseball bat",
"baseball glove",
"skateboard",
"surfboard",
"tennis racket",
"bottle",
"wine glass",
"cup",
"fork",
"knife",
"spoon",
"bowl",
"banana",
"apple",
"sandwich",
"orange",
"broccoli",
"carrot",
"hot dog",
"pizza",
"donut",
"cake",
"chair",
"couch",
"potted plant",
"bed",
"dining table",
"toilet",
"tv",
"laptop",
"mouse",
"remote",
"keyboard",
"cell phone",
"microwave",
"oven",
"toaster",
"sink",
"refrigerator",
"book",
"clock",
"vase",
"scissors",
"teddy bear",
"hair drier",
"toothbrush"
]

def draw_bounding_boxes(image, bounding_boxes, labels, color=(0, 255, 255), thickness=2):
  for bbox in bounding_boxes:
    x1, y1, x2, y2, score, classes = bbox
    cv2.rectangle(image, (int(x1), int(y1+10)), (int(x2), int(y2)), color, thickness)
    txt = "%.2f %s"%(float(score), labels[int(classes)])
    cv2.putText(image, txt, (int(x1), int(y1)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0,0,255), 2)
  return image

# 画像の読み込み
image = cv2.imread(input_data["file"])
# Bounding Boxesの描画
image_with_boxes = draw_bounding_boxes(image.copy(), input_data["bounding_boxes"], coco2017_labels)
# 描画された画像の表示
cv2.imshow("Image with Bounding Boxes", image_with_boxes)
cv2.waitKey(0) 

cv2.destroyAllWindows

Alguns testes

cat.jpg


Retornou 15, conforme tabela acima é o 16 (-1)




Ref:

Milk-V Duo256MでYOLOv5の物体検知を行う

TPUMLIR 开源工具链项目 | 通用 AI 编译器工具链项目,高效将模型编译生成 TPU 执行代码

Object Detection Based on YOLOv5 | Milk-V

A SMARTCORE FORNECE CHIPS E MÓDULOS PARA IOT, COMUNICAÇÃO WIRELESS, BIOMETRIA, CONECTIVIDADE, RASTREAMENTO E AUTOMAÇÃO. NOSSO PORTFÓLIO INCLUI MODEM 2G/3G/4G/NB-IOT, SATELITAL, MÓDULOS WIFI, BLUETOOTH, GPS, SIGFOX, LORA, LEITOR DE CARTÃO, LEITOR QR CCODE, MECANISMO DE IMPRESSÃO, MINI-BOARD PC, ANTENA, PIGTAIL, BATERIA, REPETIDOR GPS E SENSORES.

Nenhum comentário:

Postar um comentário