k210运行YOLOV3,自定义backbone与修改模块,包括训练与部署

前言

等待学位证发放的时间入坑了k210芯片,经过了一段时间学习,现在拿出来分享。如题目所示我会将这些部分总结。非常感谢这个k210项目 ,本文大体上是对这个项目的一些延申。

训练部分

环境配置

首先必须假设你有一些相应的基础(包括学习过maixpy文档,对常见目标检测算法训练有过了解,对linux命令行有过了解等等基础)。
本文主要训练平台为autodl环境配置如下
确保安装了tensorflow2.3以上版本在这里插入图片描述
本文使用了相关的k210项目,项目地址如下:
yolo k210
下载解压后进入主目录
首先需要修改requirements.txt文件

numpy==1.19.2
scikit-learn
imgaug==0.4
opencv-python~=4.5
matplotlib~=3.4
tqdm
pascal_voc_writer
tf2onnx

运行(建议一个一个运行)

pip install -r requirements.txt

如果环境报错建议查阅文档。
为了方便使用将axelerate目录下的train.py放到主目录
在这里插入图片描述

数据集划分

将训练集与测试集的图片与标签放在sample_datasets/detector文件夹中,这里的标签格式是voc格式,具体如下:
在这里插入图片描述
anns与imgs中放入训练集,anns_validation与imgs_validation中放入测试集(这里测试集与验证集合一了)。VOC2012是总的还没有分开的数据集,这里通过split.py进行数据集划分

import os
import shutil
import random

# 设置源文件夹和目标文件夹
src_img_dir = r'/root/autodl-tmp/aXeleRate-master/sample_datasets/detector/VOC2012/JPEGImages'
src_label_dir = r'/root/autodl-tmp/aXeleRate-master/sample_datasets/detector/VOC2012/Annotations'
dst_train_img_dir = r'/root/autodl-tmp/aXeleRate-master/sample_datasets/detector/imgs'
dst_train_label_dir = r'/root/autodl-tmp/aXeleRate-master/sample_datasets/detector/anns'
dst_val_img_dir = r'/root/autodl-tmp/aXeleRate-master/sample_datasets/detector/imgs_validation'
dst_val_label_dir = r'/root/autodl-tmp/aXeleRate-master/sample_datasets/detector/anns_validation'

# 创建目标文件夹
for dir_path in [dst_train_img_dir, dst_train_label_dir, dst_val_img_dir, dst_val_label_dir]:
    if not os.path.exists(dir_path):
        os.makedirs(dir_path)

# 获取所有图片和标签文件名
img_files = os.listdir(src_img_dir)
label_files = os.listdir(src_label_dir)

# 创建图片和标签的映射关系
img_label_map = {}
for img_file in img_files:
    base_name = os.path.splitext(img_file)[0]
    for label_file in label_files:
        if os.path.splitext(label_file)[0] == base_name:
            img_label_map[img_file] = label_file
            break

# 确保图片和标签一一对应
assert len(img_label_map) == len(img_files) == len(label_files)

# 将数据划分为训练集和验证集
num_samples = len(img_label_map)
val_ratio = 0.2  # 验证集占总样本的比例
val_size = int(num_samples * val_ratio)
img_files = list(img_label_map.keys())
random.shuffle(img_files)

val_img_files = img_files[:val_size]
train_img_files = img_files[val_size:]

# 移动图片和标签到目标文件夹
for img_file in val_img_files:
    src_img_path = os.path.join(src_img_dir, img_file)
    src_label_path = os.path.join(src_label_dir, img_label_map[img_file])
    dst_img_path = os.path.join(dst_val_img_dir, img_file)
    dst_label_path = os.path.join(dst_val_label_dir, img_label_map[img_file])
    shutil.move(src_img_path, dst_img_path)
    shutil.move(src_label_path, dst_label_path)

for img_file in train_img_files:
    src_img_path = os.path.join(src_img_dir, img_file)
    src_label_path = os.path.join(src_label_dir, img_label_map[img_file])
    dst_img_path = os.path.join(dst_train_img_dir, img_file)
    dst_label_path = os.path.join(dst_train_label_dir, img_label_map[img_file])
    shutil.move(src_img_path, dst_img_path)
    shutil.move(src_label_path, dst_label_path)

print(f"Data split complete. {val_size} samples in validation set, {num_samples - val_size} samples in training set.")

划分后得到了训练集和测试集,接下来要修改配置文件

修改json配置文件

在configs目录下新建一个.json文件用于配置训练时候的参数,configs文件中有许多json配置文件,建议参考。

{
	
    "model" : {
    	#网络功能(Detector表示检测)也有分类与分割
        "type":                 "Detector",
        #使用的backbone模型,['Full Yolo', 'Tiny Yolo', 'MobileNet1_0', 'MobileNet7_5', 'MobileNet5_0', 'MobileNet2_5', 'SqueezeNet', 'NASNetMobile', 'ResNet50', 'DenseNet121']
        "architecture":         "MobileNet7_5",
        #输入尺寸 这里需要注意如果你的k210板子摄像头像素320x240
        #建议修改为   "input_size": [224, 320]
        "input_size":           224,
        # anchor部分,如果想要yolo最后输出两个通道,那么建议设置为2x3x2的维度,也就是六个anchor坐标
        "anchors":              [[[0.76120044, 0.57155991], [0.6923348, 0.88535553], [0.47163042, 0.34163313]]],
        # 类别部分,与数据集类别对应
        "labels":               ["person", "bird", "cat", "cow", "dog", "horse", "sheep", "aeroplane", "bicycle", "boat", "bus", "car", "motorbike", "train","bottle", "chair", "diningtable", "pottedplant", "sofa", "tvmonitor"],
        # 一些置信度 iou 之类的参数,调参使用
        "obj_thresh" : 		    0.5,
        "iou_thresh" : 		    0.5,
        "coord_scale" : 		2.0,
        "object_scale" : 		2.0,            
        "no_object_scale" : 	1.0
    },
    # 预训权重,full表示整个网络的,如果没有可以不填,如果有可以换上权重目录
    # backend 表示backbone部分的权重,部分模型没有,如果有的话在训练时会自动联网下载,也可以提前下载下来
    "weights" : {
        "full":   				"",
        "backend":              "imagenet"
    },
    "train" : {
    	# actual_epoch训练批次
        "actual_epoch":         100,
        # 训练集与验证集的目录
        "train_image_folder":   "/root/autodl-tmp/aXeleRate-master/sample_datasets/detector/imgs",
        "train_annot_folder":   "/root/autodl-tmp/aXeleRate-master/sample_datasets/detector/anns",
        # 这个参数建议看源码
        "train_times":          1,
        "valid_image_folder":   "/root/autodl-tmp/aXeleRate-master/sample_datasets/detector/imgs_validation",
        "valid_annot_folder":   "/root/autodl-tmp/aXeleRate-master/sample_datasets/detector/anns_validation",
        "valid_times":          1,
        # 注意这里每个模型的valid_metric不一样,建议参考例子json,或者训练时候打印一下valid_metric
        "valid_metric":         "recall",
        #batchsize
        "batch_size":           32,
        #学习率
        "learning_rate":        1e-3,
        # 保存的目录
        "saved_folder":   		"pascal",
        # 没用
        "first_trainable_layer": "",
        # 是否图像强化
        "augmentation":		true,
        # 应该是不训练只检测,没试过
        "is_only_detect" : 		false
    },
    "converter" : {
    	#这里如果要生成.tflite与kmodel需要加上,因为k210需要烧录.kmodel文件
        "type":   				["k210", "tflite"]
    }
}

修改完后就可以训练了

训练

上面已经将train.py放到了主目录,运行

python3 train.py -c configs/你的json文件.json

或者修改train.py文件中的
在这里插入图片描述
改为你的json文件
运行后会下载一些东西,例如ncc与一些预训练权重,需要等待一下。然后就可以看到训练过程了
如果报错
AttributeError: module ‘tensorflow.keras.optimizers’ has no attribute ‘legacy’
可能由于tensorflow库函数变动,建议删除legacy部分
例如

tf.keras.optimizers.legacy.Adam

改为

tf.keras.optimizers.Adam

然后等待训练完成
注意要记录一下网络结构图,也就是训练一开始弹出的
在这里插入图片描述
可以在终端中看到训练过程中损失之类的变化
在这里插入图片描述

训练完成或者ctrl+c结束会自动调用ncc生成kmodel文件,等待kmodel生成。
在这里插入图片描述

结束后会在projects目录下生成.kmodel文件
将kmodel文件下载下来即可

部署部分

烧录固件

还是默认已经知道怎么使用k210开发板了,这里使用了项目作者的一个固件库而不使用官方提供的(官方的经过修改应该也可以,但我没试过,如果是官方的建议使用mini版本,因为完整版太大运行占用很多内存)maixpy.bin
使用kflash擦除并且烧录maixpy.bin
在这里插入图片描述
在.kmodel文件目录下新建一个json文件,描述模型的地址
在这里插入图片描述
json文件内容为模型的地址,一半为0x500000或者0x300000
在这里插入图片描述
将两个文件一起压缩为zip格式,然后修改后缀名为kfpkg
在这里插入图片描述
使用kflash烧录该kfpkg文件

运行模型

项目提供的固件支持IDE,所以本文使用MaixPY IDE进行运行,或者可以采用其他方式,maixpy文档中有介绍。运行代码如下

#tested with frimware 5-0.22
import sensor,image,lcd
import KPU as kpu

lcd.init()
#lcd.rotation(2)
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_vflip(1)
sensor.run(1)

classes = ["person", "bird", "cat", "cow", "dog", "horse", "sheep", "aeroplane", "bicycle", "boat", "bus", "car", "motorbike", "train","bottle", "chair", "diningtable", "pottedplant", "sofa", "tvmonitor"]
task = kpu.load(0x500000) #change to "/sd/name_of_the_model_file.kmodel" if loading from SD card
a = kpu.set_outputs(task, 0, 7, 7, 75) #the actual shape needs to match the last layer shape of your model(before Reshape)
#a = kpu.set_outputs(task, 0, 14, 14, 75) #the actual shape needs to match the last layer shape of your model(before Reshape)
anchor = (0.76120044, 0.57155991, 0.6923348, 0.88535553, 0.47163042, 0.34163313)

a = kpu.init_yolo3(task, 0.3, 0.3, 3,1, anchor) #tweak the second parameter if you're getting too many false positives

while(True):
    img = sensor.snapshot()
    img_copy = img.resize(224,224)
    a = img_copy.pix_to_ai()
    code = kpu.run_yolo3(task, img_copy)
    if code:
        for i in code:
            a = img.draw_rectangle(i.rect(),color = (0, 255, 0))
            a = img.draw_string(i.x(), i.y() - 22, classes[i.classid()], color=(255,0,0), scale=1.5)
        a = lcd.display(img)
    else:
        a = lcd.display(img)
a = kpu.deinit(task)

现在来详细介绍这个代码中需要注意的事项
1、该部分修改为你烧录的地址,也就是json文件中的

task = kpu.load(0x500000) #change to "/sd/name_of_the_model_file.kmodel" if loading from SD card

2、特征层输出

a = kpu.set_outputs(task, 0, 7, 7, 75)

这里为重中之重,这里的五个参数分别为
task: 模型地址
0:表示第几个输出,这里0表示输出0
7:模型的宽(这里也就是上面的网络结构图中最终输出的宽高)
7:模型的高
==如果是224x224 那宽高都为7,如果为[224, 320]那么需要修改为a = kpu.set_outputs(task, 0, 10, 8, 21) ==
75:通道数,计算方法(类别数量+5)*anchor数量,例如这里类别20,anchor为3,那么(20+5)*3=75

3、该部分为类别数量

classes = ["person", "bird", "cat", "cow", "dog", "horse", "sheep", "aeroplane", "bicycle", "boat", "bus", "car", "motorbike", "train","bottle", "chair", "diningtable", "pottedplant", "sofa", "tvmonitor"]

4、该部分为anchor

anchor = (0.76120044, 0.57155991, 0.6923348, 0.88535553, 0.47163042, 0.34163313)

5、注意这里使用的是init_yolo3并且参数与官方的init_yolo2不同

a = kpu.init_yolo3(task, 0.3, 0.3, 3,1, anchor) #tweak the second parameter if you're getting too many false positives

6、这里要注意,如果你的模型训练时候设置输入格式为224x224则需要下面两行代码,如果为[224, 320]则不需要并且修改code = kpu.run_yolo3(task, img_copy)中的img_copyimg

    img_copy = img.resize(224,224)
    a = img_copy.pix_to_ai()

7、也是注意这里与官方不同

code = kpu.run_yolo3(task, img_copy)

运行即可得到结果
在这里插入图片描述
可以看到运行没问题,只是我这里训练的批次有点少,所以检测精度较差

一些小贴士

网络魔改

如果你想修改其中的网络结构那么可以修改axelerate\networks\common_utils\feature.py部分,其中有许多模块进行修改即可(做过网络魔改的应该懂)
在这里插入图片描述

输出部分

众所周知,yolo大多是三个输出,这里实际上只用到了一个输出,从anchor中也能看出,上面也提到了如果将anchor设置成2x3x2维度即可两个输出,至于三个输出估计占用内存太大,不太适合。如果是两个输出那么IDE中的程序需要进行修改为

a = kpu.set_outputs(task, 0, 7, 7, 75) 
a = kpu.set_outputs(task, 1, 14, 14, 75)

anchor与init_yolo3也要进行修改
a = kpu.init_yolo3(task, 0.3, 0.3, 3,1, anchor)
改为a = kpu.init_yolo3(task, 0.3, 0.3, 3,2, anchor)

后记

以上就是我对k210的一些理解,可能语言组织的不好也请见谅。k210也就玩到这里了,如果有人想要二手的k210开发板可以在咸鱼上联系我咸鱼网址,接下来可能会实时rk3588

  • 10
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值