5399| 5
|
[M10教程] AI模型部署到行空板学习笔记 |
本帖最后由 怀若谷 于 2023-2-28 21:22 编辑 演示视频 背景说明 刚刚过去的寒假,有幸参加了首届“新一代人工智能教师成长营”的学习。AI教师成长营课程由上海人工智能实验室智能教育中心AI科创教育顾问谢作如带领教研团队精心设计,内容包括人工智能的发展和应用、AI模型训练、模型转换与部署等,分为入门课程、进阶课程以及项目实践三个部分。 以前本人做过的AI项目基本依赖AI三剑客——语音合成模块、语音识别模块、图像识别模块来完成。说句实话,这些模块就相当于创客器材中的传感器和执行器,使用者根本不需要掌握人工智能知识,也对人工智能学习产生不了多少影响,处于体验层面。而这次学习,让我了解了更专业的人工智能知识,特别是基于深度学习的人工智能应用。 项目实践环节我们小组完成了AI猜拳机器人项目。这个项目是大家熟知的项目,最早是由日本东京大学研制并发布的。我曾使用DFRobot的视觉传感器——二哈识图制作过一个。(项目链接:【HUSKYLENS Inside】AI猜拳机器人)虽然项目没有新意,最后的实现结果也差强人意,但是整个的制作过程仍能体现这次的学习成果。我想,把这个项目的制作过程记录下来,可以作为学习笔记供今后复习,如果他人能从中有所收获,那就更有意义啦。 使用的平台、软件及器材 1. 浦育青少年人工智能开放创新平台OpenInnoLab(下称“平台”) 平台网址:openinnolab.org.cn 2. Mind+软件 下载地址:https://mindplus.cc 3. 器材:行空板*1 IO扩展板*1 SG90舵机*3 USB摄像头*1 前置准备 新建项目——“AI猜拳机器人” 熟悉操作界面 在平台上运行程序,需要先在“服务器运行环境”中选择启动“CPU版”或者“GPU版”。 制作流程 制作数据集—模型训练—推理测试—模型转换—应用部署—结构设计加工—组装调试 1. 制作数据集 拍摄石头、剪刀、布三种手势的图片各200张,拍摄环境背景图片200张。拍照时,每张照片从拍摄角度、距离远近、光线强弱等方面进行调整,力求每张照片都是独一无二的。 在本地电脑上建立一个文件夹“mypic”(名称可自拟),在里面建立4个子文件夹,将拍摄的照片按类别放在4个文件夹中,分别命名为“background”、“paper”、“rock”、“scissors”。 调用下面Python程序制作数据集(也可以手工进行分类整理),可生成ImageNet格式的数据集。该程序可在平台运行,也可以在本地的Python编程软件中运行。【源程序可在附件中下载】 ------------------------------------------------------------------------------------------------------------------ train_rate=float(input('请输入训练集的比例大小,范围是0-1,如0.8')) #一般按8:1:1的比例分配给训练集、验证集、测试集,即输入0.8、0.1、0.1 val_rate=float(input('请输入验证集的比例大小,范围是0-1,如0.1')) test_rate=float(input('请输入测试集的比例大小,范围是0-1,如0.1')) import os save_path=(input('请输入需要保存的路径,默认为'+os.getcwd()+'\my_dataset')) #可以不填,默认保存在文件夹“mypic”中 import shutil # 列出指定目录下的所有文件名,确定分类信息 classes = os.listdir(path) # 定义创建目录的方法 def makeDir(folder_path): if not os.path.exists(folder_path): # 判断是否存在文件夹如果不存在则创建为文件夹 os.makedirs(folder_path) # 指定文件目录 read_dir = path+'/' # 指定原始图片路径 if save_path=='': save_path=os.getcwd()+'\my_dataset' else: save_path+='\my_dataset' train_dir = save_path+r'\training_set\\' # 指定训练集路径 val_dir = save_path+r'\val_set\\'# 指定验证集路径 test_dir = save_path+r'\test_set\\'# 指定测试集路径 for cnt in range(len(classes)): r_dir = read_dir + classes[cnt] + '/' # 指定原始数据某个分类的文件目录 files = os.listdir(r_dir) # 列出某个分类的文件目录下的所有文件名 offset1 = int(len(files) * train_rate) offset2 = int(len(files) * (train_rate+val_rate)) training_data = files[:offset1] val_data = files[offset1:offset2] test_data = files[offset2:] # 根据拆分好的文件名新建文件目录放入图片 for index,fileName in enumerate(training_data): w_dir = train_dir + classes[cnt] + '/' # 指定训练集某个分类的文件目录 makeDir(w_dir) shutil.copy(r_dir + fileName, w_dir + str(index) + '.jpg') for index,fileName in enumerate(val_data): w_dir = val_dir + classes[cnt] + '/' # 指定测试集某个分类的文件目录 makeDir(w_dir) shutil.copy(r_dir + fileName, w_dir + str(index) + '.jpg') for index,fileName in enumerate(test_data): w_dir = test_dir + classes[cnt] + '/' # 指定验证集某个分类的文件目录 makeDir(w_dir) shutil.copy(r_dir + fileName, w_dir + str(index) + '.jpg') print('转换完成,请到'+save_path+'查看') ------------------------------------------------------------------------------------------------------------------------------ 2.模型训练 2.1 上传数据集 打开项目,选择“项目文件”,点击上传按钮,以“上传目录”的方式将制作好的本地数据集“my_dataset”上传到项目文件中(也可以上传到数据集中)。 2.2 上传预训练模型文件 点击上传按钮,以“上传文件”的方式将获得的预训练模型权重文件上传到项目文件中,可自行建立目录。使用预训练模式进行训练,可以获得较理想的效果。 2.3 编写训练程序 以“上传文件”的方式导入训练程序文件,也可以自行新建文件后手动输入代码。 ------------------------------------------------------------------------------------------------------------------------------ from MMEdu import MMClassification as cls # 导入库 model = cls(backbone='MobileNet') #项目实例化 model.num_classes = 4 # 设置种类数,该项目种背景和手势共4类 model.load_dataset(path='my_dataset') # 数据集路径 model.save_fold = 'checkpoints/cls_model' # 权重文件保存路径 checkpoint = 'checkpoints/pre_model/Pre-trained.pth' # 预训练模型路径,如果从0开始训练,该行代码可删除 model.train(epochs=50, lr=0.01, batch_size=4,validate=True,checkpoint = checkpoint) #训练模型,如果不采用预训练模型,checkpoint = checkpoint可删除 ------------------------------------------------------------------------------------------------------------------------------ 2.4 启动程序训练 启动容器,点击“运行”,运行程序。 到权重文件保存路径下查看训练日志。 当训练轮数太多时,可及时删除不是最佳的训练模型文件,已节省存储空间。 3.推理测试 3.1编写推理程序 以“上传文件”的方式导入推理程序文件,也可以自行新建文件后手动输入代码。 ------------------------------------------------------------------------------------------------------ from MMEdu import MMClassification as cls # 导入库 model = cls(backbone='MobileNet') #项目实例化 model.num_classes = 4 # 类别数,该项目中共4类 checkpoint = 'checkpoints/cls_model/best_accuracy_top-1_epoch_30.pth' # 权重文件路径,训练出来的最佳结果 class_path = 'my_dataset/classes.txt' # 类型说明文件路径,训练后在“my_dataset”路径下自动生成 img_path = 'test_pic/8.jpg' # 测试图片路径,图片可上传到项目文件中,也可以利用数据集中的测试图片 result = model.inference(image=img_path,show=True, class_path=class_path,checkpoint = checkpoint) #进行推理 model.print_result(result) #显示推理结果 ------------------------------------------------------------------------------------------------------ 3.2运行程序 运行程序,查看推理结果。 如果置信度不理想,可以返回训练环节继续训练或者修改数据集。 4.模型转换 模型经过推理验证,符合预期后,需要将平台上能否运行的模型转换为能在开源硬件运行的模型。 4.1 编写模型转换程序 以“上传文件”的方式导入模型转换程序文件,也可以自行新建文件后手动输入代码。 -------------------------------------------------------------------------------------------------------------- !pip install onnx !pip install onnxruntime !pip install onnxsim from MMEdu import MMClassification as cls model = cls(backbone='MobileNet') model.num_classes = 4 checkpoint = 'checkpoints/cls_model/best_accuracy_top-1_epoch_30.pth' out_file="out_file/ImageNet1k.onnx" #存放模型转换结果文件路径 model.convert(checkpoint=checkpoint, backend="ONNX", out_file=out_file, class_path='my_dataset/classes.txt') ----------------------------------------------------------------------------------------------------------------- 4.2 运行转换程序 点击“运行”按钮运行程序。 模型转换成功后,在输出结果文件夹下可以看到“ImageNet1k.onnx”和“ImageNet1k.py” 两个文件。其中ImageNet1k.onnx”为模型文件,ImageNet1k.py”为应用示例程序。 4.3 下载相关文件 部署到硬件上需要用到转化结果的两个文件“ImageNet1k.onnx”、“ImageNet1k.py”和项目文件中的“BaseData.py”。 可以手工单个下载,也可以编写程序进行打包下载。 程序如下: ------------------------------------------------------------------------------------------------------ !tar -cvf AI猜拳机器人.tar BaseData.py ./out_file ------------------------------------------------------------------------------------------------------ 运行程序后,项目文件中会生成一个文件“AI猜拳机器人.tar”,将其下载到本地后解压。 5.应用部署 5.1 硬件搭建 将行空板插在扩展板的插槽中;三个舵机分别连接到P2、P3、P10引脚;USB摄像头插入行空板的USB口。 5.2 编写程序 5.2.1 连接设备 将行空板连接电脑 打开Mind+软件,切换到“Python模式” 开启远程连接终端后,连接IP为10.1.2.3的远程终端 5.2.2 上传文件 将“ImageNet1k.onnx”、“ImageNet1k.py”和“BaseData.py”三个文件上传到行空板,注意存放路径。 5.2.3 新建主程序文件 新建一个主程序“main.py”, 将示例程序“ImageNet1k.py”中的代码复制到主程序中。 5.2.4 完善主程序 根据应用需求,完善程序。 ------------------------------------------------------------------------------------ import cv2 import BaseData import onnxruntime as rt import numpy as np from pinpong.extension.unihiker import * from pinpong.board import Board,Pin from pinpong.board import Board from pinpong.board import Servo import time Board().begin() #初始化舵机引脚,设置初始角度15° servo1 = Servo(Pin((Pin.P2))) servo1.write_angle(15) time.sleep(1) servo2 = Servo(Pin((Pin.P3))) servo2.write_angle(15) time.sleep(1) servo3 = Servo(Pin((Pin.P10))) servo3.write_angle(15) screen_rotation = True cap = cv2.VideoCapture(0) # 设置摄像头编号,如果只插了一个USB摄像头,基本上都是0 cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320) # 设置摄像头图像宽度 cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240) # 设置摄像头图像高度 cap.set(cv2.CAP_PROP_BUFFERSIZE, 1) # 设置OpenCV内部的图像缓存,可以极大提高图像的实时性。 cv2.namedWindow('camera', cv2.WND_PROP_FULLSCREEN) # 窗口全屏 cv2.setWindowProperty('camera', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN) # 窗口全屏 sess = rt.InferenceSession('out_file/ImageNet1k.onnx', None) input_name = sess.get_inputs()[0].name out_name = sess.get_outputs()[0].name cnt = 4 global idx idx = 0 tag =['backgroup','paper', 'rock', 'scissors'] def onnx_cls(img): dt = BaseData.ImageData(img, size=(224, 224)) input_data = dt.to_tensor() pred_onx = sess.run([out_name], {input_name: input_data}) result = np.argmax(pred_onx[0], axis=1)[0] return result while cap.isOpened(): success, image = cap.read() cnt = cnt - 1 if not success: print("Ignoring empty camera frame.") break if screen_rotation: # 是否要旋转屏幕 image = cv2.rotate(image, cv2.ROTATE_90_COUNTERCLOCKWISE) # 旋转屏幕 if cnt == 0: idx = onnx_cls(image) if idx == 1: servo2.write_angle(100) time.sleep(2) servo2.write_angle(15) else: if idx == 2: servo3.write_angle(100) time.sleep(2) servo3.write_angle(15) else: if idx == 3: servo1.write_angle(100) time.sleep(2) servo1.write_angle(15) #print('result:' + tag[idx]) cnt = 4 #cv2.putText(image, tag[idx], (0, 40), cv2.FONT_HERSHEY_TRIPLEX, 1, (150, 0, 180), 1) cv2.imshow('camera',image) if cv2.waitKey(5) & 0xFF == 27: break cap.release() ----------------------------------------------------------------------------------------------- 相较于示例程序,本程序增加了行空板屏幕图像显示、预测结果显示及多模态交互模块。这个环节比较考验编程能力,对Python编程及开源硬件控制不熟悉的人来说,比较困难,我就是一个!!! 6.结构设计加工6.1 绘制图纸 使用二维建模软件进行结构及外型的绘制 6.2 切割制件 使用激光切割机切割加工椴木板 7.组装调试 将木件及电子模块组装起来,进行反复调试。 写在最后 这次学习经历是难忘的,因为期间遇到了很多问题,经历了无从下手的时刻。由于花的时间有限,上面的项目也是在囫囵吞枣式的消化后完成的。如有不当之处,望朋友们指正! |
97.89 KB, 下载次数: 2616
© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed