免费APP 微信 网站平台为什么不建议去外包公司上班
文章目录
- 前言
- 软硬件配置
- 自制数据集
- 裁剪视频
- 提取视频帧
- 视频帧标注
- 定义动物行为
- VIA标注软件下载
- 手动标注
- via转ava
- 训练
- 下载预训练权重
- 更改配置文件
- 进行训练
- 报错总结及更改
- 进行训练
- 问题解决(抠抠细节)
- 识别动物没有检测框
- 是否需要deepsort
- ffmpeg切割视频
- 提取视频帧
- 自动标注
- 后言
- 参考链接
前言
实验任务目标是动物行为识别,因此要自制数据集
基础代码为:https://github.com/facebookresearch/SlowFast
软硬件配置
win 11
python 3.8
pytorch 2.0.0
torchvision 0.15.0
CUDA 11.8
RTX3070
自制数据集
选择的动物是白鹇,用六个视频来进行测试,新建一个ava_demo文件夹,存放所有的视频和标注文件,如下图所示
- annotations:存放所有的标注文件
- baixian_video_ava:存放原始视频
- baixian_video_ava_cut:存放裁剪之后的视频
- baixian_video_ava_output:测试输出的视频
- baixian_video_labelframes:每秒每帧,需要标注的视频帧
- baixian_video_rawframes:每秒三十帧,训练的视频帧
- frame_lists:视频帧列表
- annoationslabelmap.txt:制作数据集过程中生成的标签文本
- extract_frames_1s.sh:提取标注帧的代码
- extract_frames_30s.sh:提取原始帧的代码
- Unnamed-VIA Project13Aug2024_16h21m09s_export.csv:标注完成生成的csv文件
- via_project_13Aug2024_16h23m38s.json:标注完成保存的json文件
- video_cut.sh:裁剪视频的代码
裁剪视频
为保证每个视频的每一帧都有动物,将每个视频裁剪为30s,指定输出帧率为30帧/秒(为了避免帧率不对对后续实验造成影响)
创建一个.sh文件,命名为video_cut,代码如下:
将输入输出换成自己的文件夹路径
IN_DATA_DIR="D:/file/ava_demo/baixian_video_ava"
OUT_DATA_DIR="D:/file/ava_demo/baixian_video_ava_cut"if [[ ! -d "${OUT_DATA_DIR}" ]]; thenecho "${OUT_DATA_DIR} doesn't exist. Creating it.";mkdir -p ${OUT_DATA_DIR}
fifor video in $(ls -A1 -U ${IN_DATA_DIR}/*)
doout_name="${OUT_DATA_DIR}/${video##*/}"if [ ! -f "${out_name}" ]; thenffmpeg -ss 00:00:00.0 -to 00:00:30.0 -i "${video}" -r 30 "${out_name}"fi
done
下图是裁剪前和裁剪后
提取视频帧
要提取两种,一个是每秒一帧,用来标注,另一个是每秒三十帧,用来训练(因为slowfast在slow流里1秒会采集到15帧,在fast流里1秒会采集到2帧)
- 每秒一帧
新建一个extract_frames_1.sh文件
IN_DATA_DIR="D:/file/ava_demo/baixian_video_ava_cut"
OUT_DATA_DIR="D:/fil/ava_demo/baixian_video_labelframes"if [[ ! -d "${OUT_DATA_DIR}" ]]; thenecho "${OUT_DATA_DIR} doesn't exist. Creating it.";mkdir -p ${OUT_DATA_DIR}
fifor video in $(ls -A1 -U ${IN_DATA_DIR}/*)
dovideo_name=${video##*/}if [[ $video_name = *".webm" ]]; thenvideo_name=${video_name::-5}elsevideo_name=${video_name::-4}fiout_video_dir=${OUT_DATA_DIR}/${video_name}/mkdir -p "${out_video_dir}"out_name="${out_video_dir}/${video_name}_%06d.jpg"ffmpeg -i "${video}" -r 1 -q:v 1 "${out_name}"
done
提取后的文件夹内,是一个视频单独一个文件夹
- 每秒三十帧:
新建一个extract_frames_30.sh文件
IN_DATA_DIR="D:/file/ava_demo/baixian_video_ava_cut"
OUT_DATA_DIR="D:/file/ava_demo/baixian_video_rawframes"if [[ ! -d "${OUT_DATA_DIR}" ]]; thenecho "${OUT_DATA_DIR} doesn't exist. Creating it.";mkdir -p ${OUT_DATA_DIR}
fifor video in $(ls -A1 -U ${IN_DATA_DIR}/*)
dovideo_name=${video##*/}if [[ $video_name = *".webm" ]]; thenvideo_name=${video_name::-5}elsevideo_name=${video_name::-4}fiout_video_dir=${OUT_DATA_DIR}/${video_name}/mkdir -p "${out_video_dir}"out_name="${out_video_dir}/${video_name}_%06d.jpg"ffmpeg -i "${video}" -r 30 -q:v 1 "${out_name}"
done
提取后的文件夹结构同上
视频帧标注
即对文件夹名为baixian_video_labelframes内的所有图片进行标注
标注分为两种方式,分别是自动标注和手动标注
自动标注是首先使用目标检测模型(FastRCNN)对所有图片进行预标注,得到一个检测框再进行行为标注
手动标注是直接使用VIA进行标注(VIA有一个弊端就是画框没有参考线,导致画出来的框会不准)
由于我的数据量比较小,因此直接使用手动标注的方式,即将所有的图片导入VIA进行框和行为的标注(后续会研究一下自动化的过程)
参考slowfast训练自定义数据集,识别动物行为
定义动物行为
在此次设立了八种行为,分别是:站立、歪头、行走、振翅、梳理、觅食、飞行、对抗
VIA标注软件下载
直接在VIA官网下载
我选择的是via-3.0.13
单击下图中的zip进行下载
解压缩后的目录如下,选择框选出来双击点开
打开之后就是如下图所示,主要使用的按钮就是框选出来的几个
- 导入图片
- 导入标注文件:可以导入via生成的json格式的标注,继续上一次的标注
- 保存:会直接下载生成一个json格式的文件,可用于保存备份
- 导出:可以选择导出csv格式的文件,也就是后续要用到的标注文件
- 矩形框选:用于框标注
- 设置标注行为:设置类别和行为
手动标注
-
首先将baixian_video_labelframes文件夹下的图片导入
-
其次对标注行为进行设置,如图所示
-
进行标注
一些有用的快捷键(n:下一张,m:放大镜,框选之后单击图片会显示行为)
标注完成后导出csv文件
生成一个这样的csv文件,我看教程建议不要用excel打开,可以用别的文本编辑器打开,检查一下有没有空白的行为标签,避免后续报错
via转ava
这里借鉴的是slowfast训练自定义数据集,识别动物行为
但是转换完发现,这种数据格式是适应mmaction2,而不是适应原生的slowfast。后续又有手动进行修改部分文件,对应ava标准的数据集格式
代码的第一行很重要!
# -*- coding: utf-8 -*-"""
这是一个数据格式转换器,根据mmaction2的ava数据格式转换规则将来自网站:
https://www.robots.ox.ac.uk/~vgg/software/via/app/via_video_annotator.html的、标注好的、视频理解类型的csv文件转换为mmaction2指定的数据格式。转换规则:# AVA Annotation Explained```mmaction2├── data│ ├── ava│ │ ├── annotations│ │ | ├── ava_dense_proposals_train.FAIR.recall_93.9.pkl│ │ | ├── ava_dense_proposals_val.FAIR.recall_93.9.pkl│ │ | ├── ava_dense_proposals_test.FAIR.recall_93.9.pkl│ │ | ├── ava_train_v2.1.csv│ │ | ├── ava_val_v2.1.csv│ │ | ├── ava_train_excluded_timestamps_v2.1.csv│ │ | ├── ava_val_excluded_timestamps_v2.1.csv│ │ | ├── ava_action_list_v2.1.pbtxt```## 人类检测器生成在注释文件夹中, `ava_dense_proposals_[train/val/test].FAIR.recall_93.9.pkl` 是由人类检测器生成,分别用于训练、验证和测试. 以 `ava_dense_proposals_train.FAIR.recall_93.9.pkl` 为例. 它是一个大小为203626的字典. key由`videoID`和`timestamp`组成. 例如, the key `-5KQ66BBWC4,0902` 表示值是视频`-5KQ66BBWC4`中第 $$902_{nd}$$ 秒帧的检测结果 . 字典中的值是形状为 $$N \times 5$$ 的numpy数组, $$N$$ 是相应帧中检测到的人体边界框的数量. 边界框的格式为 $$[x_1, y_1, x_2, y_2, score], 0 \le x_1, y_1, x_2, w_2, score \le 1$$. $$(x_1, y_1)$$ 表示边界框的左上角, $$(x_2, y_2)$$ 示边界框的右下角; $$(0, 0)$$ 表示图像的左上角, while $$(1, 1)$$ 表示图像的右下角.## 时空动作检测的真实标签在注释文件夹中, `ava_[train/val]_v[2.1/2.2].csv` 是时空动作检测的真实标签,用于训练和验证. 以 `ava_train_v2.1.csv` 为例, 它是一个包含 837318 行的 csv 文件, 每行是一帧中人类实例的注释. 例如, `ava_train_v2.1.csv` 中的第一行是 `'-5KQ66BBWC4,0902,0.077,0.151,0.283,0.811,80,1'`: 前两项 `-5KQ66BBWC4` 和 `0902` 表示它对应于视频`-5KQ66BBWC4`的第 $$902_{nd}$$ 秒. 接下来的四项 ($$[0.077(x_1), 0.151(y_1), 0.283(x_2), 0.811(y_2)]$$) 表示边界框的位置, bbox格式与人类相同. 下一项 `80` 是动作标签. 最后一项 `1` 是此边界框的id.## Excluded timestamps`ava_[train/val]_excludes_timestamps_v[2.1/2.2].csv` 包含在训练或验证期间未使用的 excluded timestamps. 格式为 `video_id, second_idx` .## 标签图`ava_action_list_v[2.1/2.2]_for_activitynet_[2018/2019].pbtxt` 包含 AVA 数据集的标签图,将动作名称映射到标签索引。
"""# 实现数据格式转换器,将CSV转换为ava格式的训练、验证格式的pkl和csv文件
import csv
import os
from distutils.log import info
import pickle
from matplotlib.pyplot import contour, show
import numpy as np
import cv2
from sklearn.utils import shuffledef transformer(origin_csv_path, frame_image_dir,train_output_pkl_path, train_output_csv_path,valid_output_pkl_path, valid_output_csv_path,exclude_train_output_csv_path, exclude_valid_output_csv_path,out_action_list, out_labelmap_path, dataset_percent=0.9):"""输入:origin_csv_path:从网站导出的csv文件路径。frame_image_dir:以"视频名_第n秒.jpg"格式命名的图片,这些图片是通过逐秒读取的。output_pkl_path:输出pkl文件路径output_csv_path:输出csv文件路径out_labelmap_path:输出labelmap.txt文件路径dataset_percent:训练集和测试集分割输出:无"""# -----------------------------------------------------------------------------------------------get_label_map(origin_csv_path, out_action_list, out_labelmap_path)# -----------------------------------------------------------------------------------------------information_array = [[], [], []] # 分别存储帧图像名称、物体位置信息和动作种类信息# 读取输入csv文件的位置信息段落with open(origin_csv_path, 'r') as csvfile:count = 0content = csv.reader(csvfile)for line in content:# print(line)if count >= 10:frame_image_name = eval(line[1])[0] # str# print(line[-2])location_info = eval(line[4])[1:] # listaction_list = list(eval(line[5]).values())[0].split(',')action_list = [int(x) for x in action_list] # listinformation_array[0].append(frame_image_name)information_array[1].append(location_info)information_array[2].append(action_list)count += 1# 将:对应帧图片名字、物体位置信息、动作种类信息汇总为一个信息数组information_array = np.array(information_array, dtype=object).transpose()# information_array = np.array(information_array)# -----------------------------------------------------------------------------------------------# 划分训练集和验证集num_train = int(dataset_percent * len(information_array))train_info_array = information_array[:num_train]valid_info_array = information_array[num_train:]# 生成pkl和csv文件get_pkl_csv(train_info_array, train_output_pkl_path, train_output_csv_path, exclude_train_output_csv_path,frame_image_dir)get_pkl_csv(valid_info_array, valid_output_pkl_path, valid_output_csv_path, exclude_valid_output_csv_path,frame_image_dir)# 从原始csv文件中提取行为类别信息,生成相应的labelmap.txt和action_list文件
def get_label_map(origin_csv_path, out_action_list, out_labelmap_path):classes_list = 0classes_content = "" # 存储类别labelmap_strings = "" # 生成标签映射字符串# 提取出csv中的第9行的行为下标with open(origin_csv_path, 'r') as csvfile:count = 0content = csv.reader(csvfile)for line in content:if count == 8:classes_list = linebreakcount += 1# 截取种类字典段落st = 0ed = 0for i in range(len(classes_list)):if classes_list[i].startswith('options'):st = iif classes_list[i].startswith('default_option_id'):ed = ifor i in range(st, ed):if i == st:classes_content = classes_content + classes_list[i][len('options:'):] + ','else:classes_content = classes_content + classes_list[i] + ','classes_dict = eval(classes_content)[0]# 写入labelmap.txt文件with open(out_action_list, 'w') as f: # 写入action_list文件for v, k in classes_dict.items():labelmap_strings = labelmap_strings + "label {{\n name: \"{}\"\n label_id: {}\n label_type: PERSON_MOVEMENT\n}}\n".format(k, int(v) + 1)f.write(labelmap_strings)labelmap_strings = ""with open(out_labelmap_path, 'w') as f: # 写入label_map文件for v, k in classes_dict.items():labelmap_strings = labelmap_strings + "{}: {}\n".format(int(v) + 1, k)f.write(labelmap_strings)# 从解析后的信息数组中生成相应的 pkl 和 csv 文件,存储与每帧图像相关的位置信息和动作种类
def get_pkl_csv(information_array, output_pkl_path, output_csv_path, exclude_output_csv_path, frame_image_dir):# 在遍历之前需要对我们的字典进行初始化pkl_data = dict() # 存储pkl键值对信的字典(其值为普通list)csv_data = [] # 存储导出csv文件的2d数组read_data = {} # 存储pkl键值对的字典(方便字典的值化为numpy数组)for i in range(len(information_array)):img_name = information_array[i][0]# -------------------------------------------------------------------------------------------video_name, frame_name = '_'.join(img_name.split('_')[:-1]), format(int(img_name.split('_')[-1][:-4]),'04d') # 我的格式是"视频名称_帧名称",格式不同可自行更改# -------------------------------------------------------------------------------------------pkl_key = video_name + ',' + frame_namepkl_data[pkl_key] = []# 遍历所有的图片进行信息读取并写入pkl数据for i in range(len(information_array)):img_name = information_array[i][0]# -------------------------------------------------------------------------------------------video_name, frame_name = '_'.join(img_name.split('_')[:-1]), str(int(img_name.split('_')[-1][:-4])) # 我的格式是"视频名称_帧名称",格式不同可自行更改# -------------------------------------------------------------------------------------------# imgpath = frame_image_dir + '/' + img_nameimgpath = os.path.join(frame_image_dir, video_name, img_name)location_list = information_array[i][1]action_info = information_array[i][2]image_array = cv2.imread(imgpath)h, w = image_array.shape[:2]# 进行归一化location_list[0] /= wlocation_list[1] /= hlocation_list[2] /= wlocation_list[3] /= hlocation_list[2] = location_list[2] + location_list[0]location_list[3] = location_list[3] + location_list[1]# 置信度置为1# 组装pkl数据for kind_idx in action_info:csv_info = [video_name, frame_name, *location_list, kind_idx + 1, 1]csv_data.append(csv_info)location_list = location_list + [1]pkl_key = video_name + ',' + format(int(frame_name), '04d')pkl_value = location_listpkl_data[pkl_key].append(pkl_value)for k, v in pkl_data.items():read_data[k] = np.array(v)with open(output_pkl_path, 'wb') as f: # 写入pkl文件pickle.dump(read_data, f)with open(output_csv_path, 'w', newline='') as f: # 写入csv文件, 设定参数newline=''可以不换行。f_csv = csv.writer(f)f_csv.writerows(csv_data)with open(exclude_output_csv_path, 'w', newline='') as f: # 写入csv文件, 设定参数newline=''可以不换行。f_csv = csv.writer(f)f_csv.writerows([])# 加载.pkl文件并返回内容
def showpkl(pkl_path):with open(pkl_path, 'rb') as f:content = pickle.load(f)return content# 加载.csv文件并返回内容
def showcsv(csv_path):output = []with open(csv_path, 'r') as f:content = csv.reader(f)for line in content:output.append(line)return output# 加载 labelmap.txt 文件,并将其解析为字典形式返回
def showlabelmap(labelmap_path):classes_dict = dict()with open(labelmap_path, 'r') as f:content = (f.read().split('\n'))[:-1]for item in content:mid_idx = -1for i in range(len(item)):if item[i] == ":":mid_idx = iclasses_dict[item[:mid_idx]] = item[mid_idx + 1:]return classes_dictos.makedirs(r'D:\file\postgrad\experiment\ava_demo\annotations', exist_ok=True)
transformer(r"D:\file\postgrad\experiment\ava_demo\Unnamed-VIA Project13Aug2024_16h21m09s_export.csv", r'D:\file\postgrad\experiment\ava_demo\baixian_video_labelframes',r'D:\file\postgrad\experiment\ava_demo\annotations\ava_dense_proposals_train.FAIR.recall_93.9.pkl', r'D:\file\postgrad\experiment\ava_demo\annotations\ava_train_v2.2.csv',r'D:\file\postgrad\experiment\ava_demo\annotations\ava_dense_proposals_val.FAIR.recall_93.9.pkl', r'D:\file\postgrad\experiment\ava_demo\annotations\ava_val_v2.2.csv',r'D:\file\postgrad\experiment\ava_demo\annotations\ava_train_excluded_timestamps_v2.2.csv',r'D:\file\postgrad\experiment\ava_demo\annotations\ava_val_excluded_timestamps_v2.2.csv',r'D:\file\postgrad\experiment\ava_demo\annotations\ava_action_list_v2.2.pbtxt', r'D:\file\postgrad\experiment\ava_demo\annotations\labelmap.txt', 0.8)
print(showpkl(r'D:\file\postgrad\experiment\ava_demo\annotations\ava_dense_proposals_train.FAIR.recall_93.9.pkl'))
print(showcsv(r'D:\file\postgrad\experiment\ava_demo\annotations\ava_train_v2.2.csv'))
print(showlabelmap(r'D:\file\postgrad\experiment\ava_demo\annotations\labelmap.txt'))
观察上面的代码,生成了ava_train_v2.2.csv、ava_train_excluded_timestamps_v2.2.csv、ava_action_list_v2.2.pbtxt,以及对应的val文件
但是划分训练和验证的时候,把同一个视频的视频帧划分到了两个里面,为了避免出错,手动复制过去了,最后就是四个视频用于训练,两个视频用于测试
因此还缺少标注框文件和frames_lists下的帧列表文件
train标注框文件,是将ava_train_v2.2.csv的前七列进行复制,第八列用置信度填充,设定统一的置信度0.996382
val标注框文件,是将ava_val_v2.2.csv的前六列进行复制,第七列是空值,第八列用置信度填充,设定统一的置信度0.995518
在此文件夹下保存成这种格式
frame_lists文件夹下的文件是根据原始帧列表转换的,按照下面的代码会生成一个output.csv文件
import os
import csvdef generate_csv(folder_path, output_csv_path):# 创建 CSV 文件with open(output_csv_path, 'w', newline='') as csvfile:writer = csv.writer(csvfile)# 写入表头writer.writerow(['original_video_id', 'video_id', 'frame_id', 'path', 'labels'])# 遍历主文件夹中的所有子文件夹(视频)for video_id, video_folder in enumerate(os.listdir(folder_path)):video_folder_path = os.path.join(folder_path, video_folder)if os.path.isdir(video_folder_path):# 遍历视频文件夹中的所有帧for frame_id, frame_file in enumerate(os.listdir(video_folder_path)):if frame_file.lower().endswith(('.jpg', '.png', '.jpeg')): # 仅处理图片文件frame_path = os.path.join(video_folder, frame_file)frame_path = frame_path.replace('\\', '/')# 写入 CSV 文件writer.writerow([video_folder, video_id, frame_id, frame_path, ''])# 设置主文件夹路径和输出 CSV 文件路径
main_folder_path = r'D:\file\postgrad\experiment\ava_demo\baixian_video_rawframes' # 替换为你的主文件夹路径
output_csv_file = r'D:\file\postgrad\experiment\ava_demo\annotations\output.csv' # 替换为你想要生成的 CSV 文件路径# 生成 CSV 文件
generate_csv(main_folder_path, output_csv_file)
生成的output.csv文件是这样的
可以看到labels还是空的,用""
进行填充然后下拉
在F列应用公式=CONCAT(A1," ",B1," ", C1," ",D1," ",E1)
下拉
将F这一列作为一个新的output.csv文件夹,然后手动划分为train.csv和val.csv
这么做的原因呢,就是因为后面会报错,要求这个文件有五列,但是最后一列明明是空的,只能先这样了
至此所有的标注应该制作好了
可以自己检查一下与官方标注有没有什么不同,避免小错误的报错
训练
下载预训练权重
下载预训练权重
选择图中框选的预训练权重进行下载
更改配置文件
复制SLOWFAST_32×2_R101_50_50_SHORT.yaml这个文件
配置文件的ResNet和预训练权重的ResNet网络深度一定要对应
对代码中的这些地方进行更改,注意路径问题
TRAIN:CHECKPOINT_FILE_PATH: 'D:\file\edge_download\SLOWFAST_32x2_R101_50_50_v2.2.pkl'
AVA:FRAME_DIR: 'D:/file/postgrad/experiment/ava_demo/baixian_video_rawframes'FRAME_LIST_DIR: 'D:/file/postgrad/experiment/ava_demo/frame_lists'ANNOTATION_DIR: 'D:/file/postgrad/experiment/ava_demo/annoations'DETECTION_SCORE_THRESH: 0.8TRAIN_PREDICT_BOX_LISTS: ["ava_train_v2.2.csv","person_box_67091280_iou90/ava_detection_train_boxes_and_labels_include_negative_v2.2.csv",]TEST_PREDICT_BOX_LISTS: ["person_box_67091280_iou90/ava_detection_val_boxes_and_labels.csv"]
MODEL:NUM_CLASSES: 8 # 识别种类要改
进行训练
报错总结及更改
有些忘记具体的报错了,但是是对该文件进行了这些更改,最后就成功运行了,如果遇到了类似的问题,可以考虑以下的更改
更改SlowFast-main\slowfast\datasets
下的ava_helper.py
文件
- 第一个更改:预训练权重类型问题
File "D:\file\postgrad\experiment\code\SlowFast-main\tools\train_net.py", line 587, in traincheckpoint_epoch = cu.load_checkpoint(File "d:\file\postgrad\experiment\code\slowfast-main\slowfast\utils\checkpoint.py", line 222, in load_checkpointfor key in caffe2_checkpoint["blobs"].keys():
TypeError: 'int' object is not subscriptable
CHECKPOINT_TYPE: pytorch # 更改变成这样
- 第二个更改:自制数据集时,更改类别数量,会出现尺寸不匹配的问题
File "/usr/local/lib/python3.8/dist-packages/torch/autograd/grad_mode.py", line 27, in decorate_context
return func(*args, **kwargs)
File "/usr/local/lib/python3.8/dist-packages/torch/optim/sgd.py", line 110, in step
F.sgd(params_with_grad,
File "/usr/local/lib/python3.8/dist-packages/torch/optim/functional.py", line 169, in sgd
buf.mul(momentum).add_(d_p, alpha=1 - dampening)
RuntimeError: The size of tensor a (80) must match the size of tensor b (51) at non-singleton dimension 0
_C.TRAIN.CHECKPOINT_EPOCH_RESET = True # 是在defaults.py中更改的
- 第三个更改:因为原csv文件是从902秒开始的,但是自己的视频是从第一秒开始的
"d:\file\postgrad\experiment\code\slowfast-main\slowfast\datasets\ava_helper.py", line 208, in parse_bboxes_fileif box_key not in all_boxes[video_name][frame_sec]:
KeyError: 1
FPS = 30
SECONDS = 30
AVA_VALID_FRAMES = range(1, FPS * SECONDS)
- 第四个更改:是在读取frame_lists时报错的,和自制数据集有关系
video_name_to_idx = {} # 将视频名称映射到唯一的索引video_idx_to_name = [] # 将索引映射回视频名称for list_filename in list_filenames:with pathmgr.open(list_filename, "r") as f:reader = csv.reader(f, delimiter=' ')next(reader)for row in reader:row = ' '.join(row)# The format of each row should follow:# original_vido_id video_id frame_id path labels.row = csv.reader([row], delimiter=' ', quotechar='"').__next__()assert len(row) == 5video_name = row[0]
- 第五个更改:是对路径的转换
image_paths[data_key].append(os.path.join(cfg.AVA.FRAME_DIR, row[3]).replace('/', os.path.sep))
- 第六个更改:是编码格式的一个报错
File "d:\file\postgrad\experiment\code\slowfast-main\slowfast\datasets\ava_helper.py", line 186, in parse_bboxes_filefor line in f:
UnicodeDecodeError: 'gbk' codec can't decode byte 0xbf in position 2: illegal multibyte sequence
for filename, is_gt_box in zip(ann_filenames, ann_is_gt_box):with pathmgr.open(filename, "r", encoding="utf-8") as f:for line in f:row = line.strip().split(",")# When we use predicted boxes to train/eval, we need to# ignore the boxes whose scores are below the threshold.if not is_gt_box:score = float(row[7])if score < detect_thresh:continue
- 第七个更改:另外这个报错有可能是自制数据集的问题,可以使用logging函数分别进行打印,看看维度和内容哪里不对应
File "d:\file\postgrad\experiment\code\slowfast-main\slowfast\datasets\ava_dataset.py", line 77, in _load_dataassert len(boxes_and_labels) == len(self._image_paths) # 确保长度一致
AssertionError
video_name = video_name.lstrip('\ufeff')
进行训练
python tools/run_net.py --cfg configs/AVA/SLOWFAST_32x2_R50_SHORT1.yaml
然后就运行成功啦!
问题解决(抠抠细节)
识别动物没有检测框
可能是因为预训练权重的文件,没有动物,也就是说如果要测试还是需要目标检测器及自己训练的权重
参考这篇文档slowfast训练自定义数据集,识别动物行为是使用mmdetection进行目标检测
目前属于能训练成功,也能得到准确率,但是测试没有框
是否需要deepsort
在考虑动物行为识别是否需要追踪算法,因为独立动物比较多,追踪算法是为例确保这一帧和上一帧的是同一个对象。
ffmpeg切割视频
最初尝试将一个视频切割为三个10秒,出现了切割视频卡顿,部分不清楚的情况,最后改成了每一个视频都是30秒。
提取视频帧
30秒的视频,每秒提取一帧最后提取到了32帧
尝试:下次裁剪视频的时候,精确控制帧率
自动标注
在via行为标注时,分为自动标注和手动标注,自动标注面临的问题就是,其他检测软件生成的标注如何导入via
后言
上述就是我的整个过程,由于训练过程中很多都是手动,因此后面要改为自动化的过程
在问题解决那里也面临着一些我暂时还未解决的问题
后续会继续更新的
希望我的代码会越来越完善!
参考链接
slowfast训练自定义数据集,识别动物行为
自定义ava数据集及训练与测试 完整版 时空动作/行为 视频数据集制作 yolov5, deep sort, VIA MMAction, SlowFast
【slowfast 训练自己的数据集】自定义动作,制作自己的数据集,使用预训练模型进行训练,并检测其结果
[深度学习][原创]使用labelImg+yolov5完成所有slowfast时空动作检测项目-开山篇
自制AVA数据集工具/slowfast模型训练数据集制作