前言
终于入门了用Tensorflow目标检测模型训练自己的模型,本文简单的说下训练自己模型的过程(tensorfleow安装这里就不说了,当然有每个语言的通病就是依赖的版本问题)。我最终的目的想把训练的模型用opencv去加载处理,但目前还有很多问题在等opencv5的发布,也可能后面有时间了会编译下最前没发布的5版本。
说下demo效果
模型训练步骤
下面按照文件布局说下。
文件路径布局
1.标注文件
我用的windows_labelimg,框住你要切割目标标注就行了。然后把生成的xml文件放到标注文件中就可以了。
2.ft文件生成
1.先把要训练的文件分类为训练集和测试集只是文件名(train.txt;val.txt)。
分类工具
import os
import random
'''
将图片划分为训练集和测试集
保存形式为train.txt val.txt
'''
def writ_save(train_val_list:list,train_or_val:str):
with open(train_or_val,"w") as f:
for i in train_val_list:
i_ = i + "\n"
f.write(i_)
def split_data(image_path:str,split_rate:int):
'''
划分数据集
:param image_path: 图片文件夹路径
:param split_rate: 划分为训练集的比例(0-1)
:return:
'''
new_image_name_list = []
for image_name in os.listdir(image_path):
new_image_name = image_name.split(".")[0]
new_image_name_list.append(new_image_name)
# 按比例划分为训练集
train_num = int(len(new_image_name_list) * split_rate)
train_list = random.sample(new_image_name_list,train_num)
#剩下的作为测试集
val_list = []
for new_image_name in new_image_name_list:
if new_image_name not in train_list:
val_list.append(new_image_name)
return train_list,val_list
if __name__ == "__main__":
train_list,val_list = split_data("D:/BaiduNetdiskDownload/test_card/images",0.9)
writ_save(train_list, "D:/BaiduNetdiskDownload/test_card/train.txt")
writ_save(val_list, "D:/BaiduNetdiskDownload/test_card/val.txt")
2.由xml文件生成tfrecord(生成两个一个train一个val)
python create_pascal_tf_record.py --data_dir ./test_card/images --label_map_path ./test_card/training/raccoon_label_map.pbtxt --output_path ./test_card/data/train.record --set train --annotations_dir ./test_card/annotations
模型选择
因为是本地的笔记本运算量和数据集比较小选择了ssd。
表格太大了就不贴了,模型下载这里
- 数据集的特点:不同的目标检测模型适用于不同类型的数据集。
- 例如,如果数据集中的物体尺寸变化较大,可能需要选择对尺度变化具有鲁棒性的模型,如Faster R-CNN或RetinaNet。
- 如果数据集较小,可能会倾向于使用如SSD这样的单阶段检测器,因为它们通常训练起来更快,但可能牺牲一些精度。
- 性能要求:如果您的应用对实时性有较高要求,比如需要在短时间内处理大量图像,那么您可能需要选择一个推理速度较快的模型,如YOLO或MobileNet。
- 如果对精度的要求更高,那么可以考虑使用更复杂的模型,如EfficientDet或NAS-FPN。
很重要!!!模型的配置文件
每个模型下面的这个文件pipeline.config。我下面简单说下我踩坑认为重要的配置属性。其他有些指定目录的需要自己调整。
图像的输入大小问题
model {
ssd {
num_classes: 2 # num_classes为自定义对象检测器所检测的物体分类总数,此处为2
image_resizer {#直接缩放到这个大小
fixed_shape_resizer {
height: 640
width: 640
}
}
#第二种方式 第一个值>1024取1024;否则取600*原始宽高比
image_resizer {
keep_aspect_ratio_resizer {
min_dimension: 600
max_dimension: 1024
pad_to_max_dimension: true
}
随便输入一个图片,那么它会调整最小的维数为600,最大的维数是1024。如果你输入为100100,它会调整到600600,输入为20002000,会调整为10241024,输入为8001000会调整到600750,输入的图像为1200900的像素的图像,经过keep_aspect_astio_resizer后的图像尺寸变为1024768。既保证输入图片的纵横比不变。
在图像处理中,pad_to_max_dimension 可能是指在调整图像大小时,通过添加边框(padding)来使所有图像达到同一尺寸,特别是在保持宽高比的同时进行大小调整时使用。这可以通过设置配置项 keep_aspect_ratio_resizer 中的 pad_to_max_dimension : true 来实现
锚框问题
我之前训练测试了很久没一点效果就是这里出了问题
有些参数的意思还没搞明白,毕竟是小白
anchor_generator {
multiscale_anchor_generator {
min_level: 3
max_level: 7
anchor_scale: 4.0
aspect_ratios: 1.0
aspect_ratios: 2.0
aspect_ratios: 0.5
scales_per_octave: 2
}
}
- min_level: 3:表示锚框生成开始于特征金字塔的第3层(层级索引从0开始)。
- max_level: 7:表示锚框生成结束于特征金字塔的第7层。
- anchor_scale: 4.0:表示锚框尺寸的基础比例因子,用于计算每层的锚框尺寸。
- 这里很重要aspect_ratios: 1.0, 2.0, 0.5:表示锚框的宽高比,分别是正方形、横向和纵向。
- scales_per_octave: 2:表示每个八度音阶(octave)生成两个不同尺寸的锚框
最后注意一点
笔记本GPU有限,关于batch_size的设置可以小点。另外num_stepsu训练的轮数也可以小点。
模型输出文件
文件名raccoon_label_map.pbtxt也可以改。就是写入你要识别的几个类别的描述,复制改下对应的标签。
item {
id: 1
name: 'name'
}
最后关于模型的工具
- git上下载tensorflow2 object detection不要release版本的。
- 工具文件都是在tensorflow2 object detection下面的这个目录tensorflow-object\models\research\object_detection。
- 先训练后导出。
python model_main_tf2.py --model_dir=.\\test_card\\pre-trained-models\\ --num_train_steps=4000 --num_eval_steps=10 --pipeline_config_path=.\\test_card/pre-trained-models\\ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8\\pipeline.config
python exporter_main_v2.py --input_type=image_tensor --pipeline_config_path=.\\test_card\\pre-trained-models\\ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8\\pipeline.config --trained_checkpoint_dir=.\\test_card\\pre-trained-models\\ --output_directory=.\\test_card\\training
4.可以运行测试工具看下效果
训练的效果图表
用TensorBoard查看训练进程