[嵌入式AI从0开始到入土]嵌入式AI系列教程
注:等我摸完鱼再把链接补上
可以关注我的B站号工具人呵呵的个人空间,后期会考虑出视频教程,务必催更,以防我变身鸽王。
第1期 昇腾Altas 200 DK上手
第2期 下载昇腾案例并运行
第3期 官方模型适配工具使用
第4期 炼丹炉的搭建(基于Ubuntu23.04 Desktop)
第5期 炼丹炉的搭建(基于wsl2_Ubuntu22.04)
第6期 Ubuntu远程桌面配置
第7期 下载yolo源码及样例运行验证
第8期 在线Gpu环境训练(基于启智ai协作平台)
第9期 转化为昇腾支持的om离线模型
第10期 jupyter lab的使用
第11期 yolov5在昇腾上推理
第12期 yolov5在昇腾上应用
第13期_orangepi aipro开箱测评
第14期 orangepi_aipro小修补含yolov7多线程案例
未完待续…
文章目录
- [嵌入式AI从0开始到入土]嵌入式AI系列教程
- 前言
- 一、注册
- 二、导入项目
- 三、修改代码适配在线环境
- 1、下载预训练模型
- 2、上传模型
- 3、下载数据集
- 4、修改数据集
- 5、上传数据集
- 四、编写启动文件
- 1、修改train.py
- 2、单独启动文件
- 五、创建调试任务
- 1、路径说明
- 2、创建任务
- 3、开始调试
- 4、导出镜像
- 六、创建训练任务
- 1、路径说明
- 2、创建任务
- 3、开始训练
- 4、下载训练结果
- 问题
- 1、无法解压代码
- 总结
前言
当前启智平台每天能够稳定白嫖5个小时Nvidia T4、5小时ascend 910或者其他算力。
一、注册
点击这里进入注册链接。
填写相关信息,完成注册。
二、导入项目
在首页右上角选择迁移外部项目。
如下图所示,填写相关信息
- url:https://github.com/ultralytics/yolov5.git
- 迁移类型:因为我们要做修改,因此不勾选
点击迁移,耐心等待迁移结束。
三、修改代码适配在线环境
1、下载预训练模型
平台访问github有一定几率失败,因此我们需要提前上传。
我个人使用的是yolov5s的预训练模型,这里贴出下载地址:https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.pt
其他几个模型只需要将yolov5s的s修改为n,s,m,l,x,n6,s,6,m6,l6,x6
即可。老规矩,下不动丢迅雷。
区别如下:
2、上传模型
因为我目前只用yolov5s,且模型不大,因此我将其上传到仓库的models文件夹内了。
其他模型请按如下步骤上传
如果是你自己的模型,可以设置为私有
3、下载数据集
这里使用coco128数据集做演示。
下载地址:https://ultralytics.com/assets/coco128.zip
4、修改数据集
为方便接下来的操作,请将数据集调整到这样
coco128.yaml内设置好相关信息,以下仅供参考
# YOLOv5 🚀 by Ultralytics, AGPL-3.0 license
# COCO128 dataset https://www.kaggle.com/ultralytics/coco128 (first 128 images from COCO train2017) by Ultralytics
# Example usage: python train.py --data coco128.yaml
# parent
# ├── yolov5
# └── datasets
# └── coco128 ← downloads here (7 MB)# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
path: ../datasets/coco128 # dataset root dir
train: images/train2017 # train images (relative to 'path') 128 images
val: images/train2017 # val images (relative to 'path') 128 images
test: # test images (optional)# Classes
names:0: person1: bicycle2: car3: motorcycle4: airplane5: bus6: train7: truck8: boat9: traffic light10: fire hydrant11: stop sign12: parking meter13: bench14: bird15: cat16: dog17: horse18: sheep19: cow20: elephant21: bear22: zebra23: giraffe24: backpack25: umbrella26: handbag27: tie28: suitcase29: frisbee30: skis31: snowboard32: sports ball33: kite34: baseball bat35: baseball glove36: skateboard37: surfboard38: tennis racket39: bottle40: wine glass41: cup42: fork43: knife44: spoon45: bowl46: banana47: apple48: sandwich49: orange50: broccoli51: carrot52: hot dog53: pizza54: donut55: cake56: chair57: couch58: potted plant59: bed60: dining table61: toilet62: tv63: laptop64: mouse65: remote66: keyboard67: cell phone68: microwave69: oven70: toaster71: sink72: refrigerator73: book74: clock75: vase76: scissors77: teddy bear78: hair drier79: toothbrush
最后打包压缩,名称要和coco128.yaml中的path一致,否则解压数据的时候会比较麻烦。
为了简单,假设数据集名称为xxx,请将xxx.yaml(path路径为…/datasets/xxx)和相关数据打包到xxx.zip
5、上传数据集
注意:此处应分为CPU/GPU或NPU两种,且互相不能调用
这里我已经在另一个项目中上传了,因此上传失败,你自己的数据集是不会这样的。
四、编写启动文件
启智在训练时会自动加载数据集和模型到指定文件夹,结果也需要保存到指定文件夹。当然,你可以通过调试去训练,但是麻烦程度+999.
这里,如果你在导入的时候没有勾选镜像的话,按照法一直接修改train.py即可。否则建议单独建立分支或者单独编写一个启动文件(法二)。
1、修改train.py
在模块导入最下方添加代码,创建输出目录
import zipfile
import shutil
import subprocessif not os.path.exists("/tmp/output"): # 判断是否存在文件夹如果不存在则创建为文件夹os.makedirs("/tmp/output") print("create '/tmp/output' successed!")
在train函数return结果之前添加代码,保存结果到输出目录
def zip_runs_folder():folder_path = "runs"zip_path = "runs.zip"with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:for root, dirs, files in os.walk(folder_path):for file in files:file_path = os.path.join(root, file)zipf.write(file_path, os.path.relpath(file_path, folder_path))print("Successfully compressed the 'runs' folder and its contents!")zip_runs_folder()shutil.copy('runs.zip','/tmp/output')shutil.copy('runs/train/exp/weights/best.pt','/tmp/output')print("Save training output successfully!")print("Start export onnx model!")subprocess.call(f"python export.py --weights runs/train/exp/weights/best.pt --data {opt.data} --include onnx --opset=12 --simplify --device 0", shell=True)shutil.copy('runs/train/exp/weights/best.onnx','/tmp/output')print("Export onnx model successfully!")
在main函数开头添加代码,解压数据集
#Copy dataset and unzipdata_param = os.path.basename(opt.data) # 获取--data参数的文件名data_name = data_param.split('.')[0] # 获取数据集名称,去除文件后缀dataset_dir = "../datasets" # 数据集目录dataset_path = f"/tmp/dataset/{data_name}.zip" # 数据集压缩文件路径if not os.path.exists(os.path.join(dataset_dir, data_name)):print("start unzip dataset,please wait some times!")f = zipfile.ZipFile(os.path.join(dataset_path),'r')for file in f.namelist():f.extract(file,"../datasets") # 解压到的位置f.close()print("Dataset decompression completed!")
2、单独启动文件
在代码根目录新建start.py文件
import os
import zipfile
import shutil
import subprocess
import argparse
from pathlib import Path
import sysFILE = Path(__file__).resolve()
ROOT = FILE.parents[0] # YOLOv5 root directory
if str(ROOT) not in sys.path:sys.path.append(str(ROOT)) # add ROOT to PATH
ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative# Parse command line arguments
parser = argparse.ArgumentParser()
parser.add_argument("--weights", type=str)
parser.add_argument("--cfg", type=str)
parser.add_argument("--data", type=str)
parser.add_argument("--hyp", type=str)
parser.add_argument("--epochs", type=int)
parser.add_argument("--batch-size", type=int)
parser.add_argument("--imgsz", "--img", "--img-size", type=int)
parser.add_argument("--rect", action="store_true")
parser.add_argument("--resume", nargs="?", const=True)
parser.add_argument("--nosave", action="store_true")
parser.add_argument("--noval", action="store_true")
parser.add_argument("--noautoanchor", action="store_true")
parser.add_argument("--noplots", action="store_true")
parser.add_argument("--evolve", type=int, nargs="?", const=300)
parser.add_argument("--evolve_population", type=str)
parser.add_argument("--resume_evolve", type=str)
parser.add_argument("--bucket", type=str)
parser.add_argument("--cache", type=str, nargs="?", const="ram")
parser.add_argument("--image-weights", action="store_true")
parser.add_argument("--device")
parser.add_argument("--multi-scale", action="store_true")
parser.add_argument("--single-cls", action="store_true")
parser.add_argument("--optimizer", type=str, choices=["SGD", "Adam", "AdamW"])
parser.add_argument("--sync-bn", action="store_true")
parser.add_argument("--workers", type=int)
parser.add_argument("--project")
parser.add_argument("--name")
parser.add_argument("--exist-ok", action="store_true")
parser.add_argument("--quad", action="store_true")
parser.add_argument("--cos-lr", action="store_true")
parser.add_argument("--label-smoothing", type=float)
parser.add_argument("--patience", type=int)
parser.add_argument("--freeze", nargs="+", type=int)
parser.add_argument("--save-period", type=int)
parser.add_argument("--seed", type=int)
parser.add_argument("--local_rank", type=int)
parser.add_argument("--entity")
parser.add_argument("--upload_dataset", nargs="?", const=True)
parser.add_argument("--bbox_interval", type=int)
parser.add_argument("--artifact_alias", type=str)
parser.add_argument("--ndjson-console", action="store_true")
parser.add_argument("--ndjson-file", action="store_true")
opt = parser.parse_args()if not os.path.exists("/tmp/output"): # 判断是否存在文件夹如果不存在则创建为文件夹os.makedirs("/tmp/output") print("create '/tmp/output' successed!")#Copy dataset and unzip
data_param = os.path.basename(opt.data) # 获取--data参数的文件名
data_name = data_param.split('.')[0] # 获取数据集名称,去除文件后缀
dataset_dir = "../datasets" # 数据集目录
dataset_path = f"/tmp/dataset/{data_name}.zip" # 数据集压缩文件路径
if not os.path.exists(os.path.join(dataset_dir, data_name)):print("start unzip dataset,please wait some times!")f = zipfile.ZipFile(os.path.join(dataset_path),'r')for file in f.namelist():f.extract(file,"../datasets") # 解压到的位置f.close()print("Dataset decompression completed!")# zip runs folder
def zip_runs_folder():folder_path = "runs"zip_path = "runs.zip"with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:for root, dirs, files in os.walk(folder_path):for file in files:file_path = os.path.join(root, file)zipf.write(file_path, os.path.relpath(file_path, folder_path))print("Successfully compressed the 'runs' folder and its contents!")#start train
print("Start train model!")
subprocess.call(f"python train.py --weights {opt.weights} --cfg {opt.cfg} --data {opt.data} --hyp {opt.hyp} --epochs {opt.epochs} --batch-size {opt.batch_size} --imgsz {opt.imgsz} --device {opt.device} --name {opt.name} --exist-ok --rect {'--resume' if opt.resume else ''} {'--nosave' if opt.nosave else ''} {'--noval' if opt.noval else ''} {'--noautoanchor' if opt.noautoanchor else ''} {'--noplots' if opt.noplots else ''} {'--evolve' if opt.evolve else ''} {'--resume_evolve' if opt.resume_evolve else ''} {'--cache' if opt.cache else ''} {'--image-weights' if opt.image_weights else ''} {'--multi-scale' if opt.multi_scale else ''} {'--single-cls' if opt.single_cls else ''} --optimizer {opt.optimizer} {'--sync-bn' if opt.sync_bn else ''} --workers {opt.workers} --project {opt.project} --patience {opt.patience} --freeze {' '.join(map(str, opt.freeze))} --save-period {opt.save_period} --seed {opt.seed} --local_rank {opt.local_rank}", shell=True)
print("Training is complete, start saving results!")# Save training output
zip_runs_folder()
shutil.copy('runs.zip','/tmp/output')
shutil.copy('runs/train/exp/weights/best.pt','/tmp/output')
print("Save training output successfully!")# Export onnx model
print("Start export onnx model!")
subprocess.call(f"python export.py --weights runs/train/exp/weights/best.pt --data {opt.data} --include onnx --opset=12 --simplify --device 0", shell=True)
shutil.copy('runs/train/exp/weights/best.onnx','/tmp/output')
print("Export and save onnx model successfully!")
五、创建调试任务
以英伟达GPU环境为例
1、路径说明
第四步中的路径是英伟达gpu训练环境的路径,调试时需要删除/tmp
- /code:本目录对应控制台左侧的文件菜单栏,已经存放代码仓为 master.zip,需要用户手动解压
- /dataset: 本目录下可以找到创建调试任务时选取的数据集,平台已解压
- /pretrainmodel: 本目录下将加载创建调试任务时选取的预训练模型
2、创建任务
如下图所示
建议使用T4卡做前期调试,这样比较节省积分
镜像可以使用这个,这样需要配置的东西就少一些
数据集可以提前下载coco2017val,上传到数据集,节省调试时下载时间。
3、开始调试
不幸的是,笔者在写本文时,英伟达集群似乎都无法创建任务,这里没法放进图了。
首先,打开终端执行以下命令
su
apt update #这一步很重要
apt install unzip
cd /code
unzip master.zip
之后我们只需要打开对应的jupyter文件进行调试即可。
4、导出镜像
在调试完成后,我们需要导出镜像以便我们在训练时使用
注意,必须在任务处于运行状态时提交镜像
提交成功后,在下次创建任务的时候,在我的镜像内就可以看到。
六、创建训练任务
以英伟达GPU环境为例
1、路径说明
- /tmp/code:存放训练脚本
- /tmp/dataset:存放训练数据集
- /tmp/pretrainmodel:存放预训练模型
- /tmp/output:存放训练结果
2、创建任务
如下图所示
注意事项:
- 代码分支:选择存放你训练代码的分支,我这没有去修改master分支,选择从master分支派生出来的适配启智GPU平台的train_gpu分支
- 镜像:请选择你在上一步中提交的镜像,否则可能需要在开始运行前安装缺少的依赖(没有命令交互界面,需要写入main函数)
可以使用我的环境(仅保证GPU环境下可以正常训练和导出onnx模型):192.168.204.22:5000/default-workspace/99280a9940ae44ca8f5892134386fddb/image:yolov5_gpu_240124 - 启动文件:一般为train.py,如果你需要在训练开始前做一些配置的话,可能需要使用start.sh等
- 数据集:训练使用的数据集
- 运行参数:详见train.py内opt函数,和本地训练一致,只需要写与默认参数不同的参数即可
3、开始训练
新建任务后,等待其状态变为running,可以点击任务,日志查看其输出(可能需要手动刷新才会显示新的日志)
下图为任务开始时的日志
下图为训练结束后的日志
4、下载训练结果
点击结果下载,如果使用我的代码,将生成以下三个文件。
文件说明:
- best.onnx:导出的onnx模型
- best.pt:训练获得的原始pt模型
- runs.zip:包含所有训练结果的压缩包
问题
1、无法解压代码
一定要先打开终端执行
su #这里是切换到root用户
apt update #不然没法安装软件
总结
具体细节直接点击平台首页右上角的问号,查看帮助。好像过段时间会统一各个集群的环境内代码等存放位置,请关注公告。