1、配置环境
# install requirements
pip install pycocotools numpy opencv-python tqdm tensorboard tensorboardX pyyaml webcolors
pip install torch==1.4.0
pip install torchvision==0.5.0
2、git源码
git clone https://github.com/zylo117/Yet-Another-EfficientDet-Pytorch
3、准备数据集
本例用的数据集是 BIWI Walking Pedestrians dataset,首先将视频按帧转换成图像序列,然后用labelme标注,保存为json数据格式文件。
之后数据集要转换成coco格式,参考json转coco。
# your dataset structure should be like this
datasets/
-your_project_name/
-train_set_name/
-*.jpg
-val_set_name/
-*.jpg
-annotations
-instances_{train_set_name}.json
-instances_{val_set_name}.json
4、修改配置文件
修改coco.xml:
project_name: coco_people # also the folder name of the dataset that under data_path folder
train_set: train #注意和COCO转化时,选择的年份一致
val_set: val
num_gpus: 1 # 0 means using cpu, 1-N means using gpus
# mean and std in RGB order, actually this part should remain unchanged as long as your dataset is similar to coco.
mean: [0.485, 0.456, 0.406]
std: [0.229, 0.224, 0.225]
# this is coco anchors, change it if necessary
anchors_scales: '[2 ** 0, 2 ** (1.0 / 3.0), 2 ** (2.0 / 3.0)]'#放大的倍数
anchors_ratios: '[(1.0, 1.0), (1.4, 0.7), (0.7, 1.4)]'#长边和短边的比例,一般都是成对出现的(乘积为1)
# objects from all labels from your dataset with the order from your annotations.
# its index must match your dataset's category_id.
# category_id is one_indexed,for example, index of 'people' here is 0, while category_id of is 1
obj_list: ['people'..]
修改train.py:
#主要需要修改的参数有compound_coef、batch_size、num_epochs、save_interval、lr、load_weights
def get_args():
parser = argparse.ArgumentParser('Yet Another EfficientDet Pytorch: SOTA object detection network - Zylo117')
parser.add_argument('-p', '--project', type=str, default='coco_people', help='project file that contains parameters')
#project_name
parser.add_argument('-c', '--compound_coef', type=int, default=0, help='coefficients of efficientdet')
#0-7,选择EfficientDet的模型,对应d0-d7,同时对应EfficientNet网络的b0-b7
parser.add_argument('-n', '--num_workers', type=int, default=2, help='num_workers of dataloader')
#dataloader一次性创建num_workers个worker(工作进程),worker将它负责的batch加载进RAM,然后dataloader从RAM中找本轮迭代要用的batch
#num_worker设置得大,好处是寻batch速度快
#num_workers的经验设置值是自己机器的CPU核心数,如果CPU很强、RAM也很充足,就可以设置得更大些
parser.add_argument('--batch_size', type=int, default=2, help='The number of images per batch among all devices')
#batch:(训练集较大时)将整个训练集分成若干批,batch就是批数
#batch_size:一次训练(一批)的样本数,直接影响到GPU内存的使用情况
#假如GPU内存不大,该数值最好设置小一点
#适当batch_size使得梯度下降方向更加准确
#注意:batch_size增大了,要到达相同的准确度,必须要增大epoch(num_epochs)
parser.add_argument('--head_only', type=boolean_string, default=False,
help='whether finetunes only the regressor and the classifier, '
'useful in early stage convergence or small/easy dataset')
#是否只微调回归器和分类器,适用于早期收敛或小/简单的数据集
parser.add_argument('--lr', type=float, default=1e-4)
#learning-rate,这个模型不要用太大的学习率,经测试,学习率太大不收敛
parser.add_argument('--optim', type=str, default='adamw', help='select optimizer for training, '
'suggest using \'admaw\' until the'
' very final stage then switch to \'sgd\'')
parser.add_argument('--num_epochs', type=int, default=300)
#一个epoch就是将所有训练样本训练一次的过程
#也就是说,所有训练样本在神经网络中都进行了一次正向传播和一次反向传播
#num_epochs太小,欠拟合,太大,过拟合,数据的多样性会影响合适的num_epochs大小
parser.add_argument('--val_interval', type=int, default=1, help='Number of epoches between valing phases')
#每多少个epoch进入val阶段
parser.add_argument('--save_interval', type=int, default=11970, help='Number of steps between saving')
#迭代多少次保存一个模型
parser.add_argument('--es_min_delta', type=float, default=0.0,
help='Early stopping\'s parameter: minimum change loss to qualify as an improvement')
parser.add_argument('--es_patience', type=int, default=0,
help='Early stopping\'s parameter: number of epochs with no improvement after which training will be stopped. Set to 0 to disable this technique.')
parser.add_argument('--data_path', type=str, default='datasets', help='the root folder of dataset')
#数据集的路径
parser.add_argument('--log_path', type=str, default='logs/')
#log保存位置
parser.add_argument('-w', '--load_weights', type=str, default=None,
help='whether to load weights from a checkpoint, set None to initialize, set \'last\' to load last checkpoint')
#加载模型的路径,如果没有一次训练完,再次训练就要用到此参数
parser.add_argument('--saved_path', type=str, default='logs/')
#pth保存位置
parser.add_argument('--debug', type=boolean_string, default=False, help='whether visualize the predicted boxes of trainging, '
'the output images will be in test/')
5、训练
python train.py
运行效果如下所示:
停止训练:
ctrl+c,此时logs目录最下面的pth为total loss最小的模型
继续训练:
python train.py --load_weights xx.pth
6、测试图片
修改efficientdet_test.py:
compound_coef=0~7#和训练时设置的值一样
img_path = 'test/xx.jpg'
threshold = 0.2#过滤分数和交并比
iou_threshold = 0.2
obj_list = ['people']#和训练时的类别顺序一致
model.load_state_dict(torch.load(f'/xx.pth', map_location='cpu'))#模型的路径
运行:
python efficientdet_test.py
测试结果的图片保存在test文件夹下。
7、测试mp4的video
修改efficientdet_test_videos.py:
compound_coef=0~7#和训练时设置的值一样
video_src = 'videotest.mp4'# setmint to use webcam, set str to read from a video file
obj_list = ['people']#和训练时的类别顺序一致
model.load_state_dict(torch.load(f'xx.pth'))#模型的路径
运行:
python efficientdet_test_videos.py
8、模型评估
修改coco_eval.py:
-p project_name
--compound_coef 0~7#和模型训练时设置的值一样
--weights /path#模型的路径
除此之外还要注意数据集要放在datasets目录下。(coco格式)
运行:
python coco_eval.py
运行效果如下所示: