[嵌入式AI从0开始到入土]8_在线Gpu环境训练(基于启智ai协作平台)

[嵌入式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多线程案例
未完待续…



前言

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

if 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 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!")

2、单独启动文件

在代码根目录新建start.py文件

import os
import zipfile
import shutil
import subprocess
import argparse
from pathlib import Path
import sys

FILE = 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、创建任务

如下图所示
在这里插入图片描述
注意事项:

  1. 代码分支:选择存放你训练代码的分支,我这没有去修改master分支,选择从master分支派生出来的适配启智GPU平台的train_gpu分支
  2. 镜像:请选择你在上一步中提交的镜像,否则可能需要在开始运行前安装缺少的依赖(没有命令交互界面,需要写入main函数)
    可以使用我的环境(仅保证GPU环境下可以正常训练和导出onnx模型):192.168.204.22:5000/default-workspace/99280a9940ae44ca8f5892134386fddb/image:yolov5_gpu_240124
  3. 启动文件:一般为train.py,如果你需要在训练开始前做一些配置的话,可能需要使用start.sh等
  4. 数据集:训练使用的数据集
  5. 运行参数:详见train.py内opt函数,和本地训练一致,只需要写与默认参数不同的参数即可

3、开始训练

新建任务后,等待其状态变为running,可以点击任务,日志查看其输出(可能需要手动刷新才会显示新的日志)
下图为任务开始时的日志
在这里插入图片描述
下图为训练结束后的日志
在这里插入图片描述

4、下载训练结果

点击结果下载,如果使用我的代码,将生成以下三个文件。
在这里插入图片描述
文件说明:

  • best.onnx:导出的onnx模型
  • best.pt:训练获得的原始pt模型
  • runs.zip:包含所有训练结果的压缩包

问题

1、无法解压代码

一定要先打开终端执行

su	#这里是切换到root用户
apt update	#不然没法安装软件

总结

具体细节直接点击平台首页右上角的问号,查看帮助。好像过段时间会统一各个集群的环境内代码等存放位置,请关注公告。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

工具人呵呵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值