yolov5-face手把手训练实战(带有widerface的测试评估,很全)
yolov5-face的github库:
deepcam-cn/yolov5-face: YOLO5Face: Why Reinventing a Face Detector (https://arxiv.org/abs/2105.12931) ECCV Workshops 2022)yolov5-face的论文:
[2105.12931] YOLO5Face: Why Reinventing a Face Detector
0前言
我的平台是linux,cuda11.8下部署yolov5-face,自己之前配置过mmyolo的环境,所以conda环境直接用的mmyolo的codna环境,conda环境的配置不多赘述。
1.下载yolov5-face的工程和数据集
复制yolov5-face的github工程到当前文件夹
git clone https://github.com/deepcam-cn/yolov5-face.git
下载训练和验证集数据集地址为
WIDER FACE: A Face Detection Benchmark

labels文件下载地址为:
https://drive.google.com/file/d/1tU_IjyOwGQfGNUvZGwWWM4SwxKp2PUQ8/view
下载完大概类似如图放置,train和val文件夹下都是这个布局
![]()
2.转换数据集
因为数据集需要改成yolo适合读取的格式,所以需要转换 。
工程下的yolov5-face/data/train2yolo.py和yolov5-face/data/val2yolo.py为转换数据集所用文件
先新建一个新数据的结构

train部分:
然后先修改train2yolo.py,将主函数部分改成如下:
if __name__ == '__main__':
original_path = '/home/ubuntu/workdir/qita/insightface/data/retinaface/train'
save_path = '/home/ubuntu/workdir/mmyolo/widerface_yolo/train'
save_path_img = os.path.join(save_path, 'images')
save_path_labels = os.path.join(save_path, 'labels')
aa = WiderFaceDetection(os.path.join(original_path, 'label.txt'))
for i in range(len(aa.imgs_path)):
print(i, aa.imgs_path[i])
img = cv2.imread(aa.imgs_path[i])
base_img = os.path.basename(aa.imgs_path[i])
base_txt = os.path.basename(aa.imgs_path[i])[:-4] + ".txt"
save_img_path = os.path.join(save_path_img, base_img)
save_txt_path = os.path.join(save_path_labels, base_txt)
with open(save_txt_path, "w") as f:
height, width, _ = img.shape
labels = aa.words[i]
annotations = np.zeros((0, 14))
if len(labels) == 0:
continue
for idx, label in enumerate(labels):
annotation = np.zeros((1, 14))
# bbox
label[0] = max(0, label[0])
label[1] = max(0, label[1])
label[2] = min(width - 1, label[2])
label[3] = min(height - 1, label[3])
annotation[0, 0] = (label[0] + label[2] / 2) / width # cx
annotation[0, 1] = (label[1] + label[3] / 2) / height # cy
annotation[0, 2] = label[2] / width # w
annotation[0, 3] = label[3] / height # h
#if (label[2] -label[0]) < 8 or (label[3] - label[1]) < 8:
# img[int(label[1]):int(label[3]), int(label[0]):int(label[2])] = 127
# continue
# landmarks
annotation[0, 4] = label[4] / width # l0_x
annotation[0, 5] = label[5] / height # l0_y
annotation[0, 6] = label[7] / width # l1_x
annotation[0, 7] = label[8] / height # l1_y
annotation[0, 8] = label[10] / width # l2_x
annotation[0, 9] = label[11] / height # l2_y
annotation[0, 10] = label[13] / width # l3_x
annotation[0, 11] = label[14] / height # l3_y
annotation[0, 12] = label[16] / width # l4_x
annotation[0, 13] = label[17] / height # l4_y
str_label = "0 "
for i in range(len(annotation[0])):
str_label = str_label + " " + str(annotation[0][i])
str_label = str_label.replace('[', '').replace(']', '')
str_label = str_label.replace(',', '') + '\n'
f.write(str_label)
cv2.imwrite(save_img_path, img)
针对自己的目录修改original_path和save_path的路径然后运行就可以了
val部分:
然后再修改val2yolo.py,将主函数部分改成如下:
if __name__ == '__main__':
save_path = '/home/ubuntu/workdir/mmyolo/widerface_yolo/val'
save_path_img = os.path.join(save_path, 'images')
save_path_labels = os.path.join(save_path, 'labels')
datas = wider2face(root='/home/ubuntu/workdir/qita/insightface/data/retinaface', phase='val')
for idx, data in enumerate(datas.keys()):
pict_name = os.path.basename(data)
out_img = f'{save_path_img}/{idx}.jpg'
out_txt = f'{save_path_labels}/{idx}.txt'
shutil.copyfile(data, out_img)
labels = datas[data]
f = open(out_txt, 'w')
for label in labels:
f.write(label + '\n')
f.close()
针对自己的目录修改datas和save_path的路径然后运行就可以了
3.下载权重
后面我尝试训练的时候,发现报错
FileNotFoundError: [Errno 2] No such file or directory: 'weights/yolov5s.pt'
![]()
官方有给下载权重的办法:
cd mmyolo/yolov5-face #在工程路径下运行
bash weights/download_weights.sh
注:如果官方方法不可以,可以直接下载
wget https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.pt
运行后下载了yolov5s.pt,将其移动到weights文件夹下
![]()
4.训练
修改yolov5-face/data/widerface.yaml文件
# download command/URL (optional)
#download: bash data/scripts/get_voc.sh
# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/]
train: /home/ubuntu/workdir/mmyolo/widerface_yolo/train # 16551 images
val: /home/ubuntu/workdir/mmyolo/widerface_yolo/val # 16551 images
#val: /ssd_1t/derron/yolov5-face/data/widerface/train/ # 4952 images
# number of classes
nc: 1
# class names
names: [ 'face']
运行程序
python train.py
遇到的问题1:
问题:AttributeError: module 'numpy' has no attribute 'int'.
原因:numpy版本高导致的
解决方案::将错误的地方的np.int改成np.int32
#cum_counts = np.cumsum(np.greater(counts, 0, dtype=np.int32))
cum_counts = np.cumsum(np.greater(counts, 0).astype(np.int32))
遇到的问题2:
问题:TypeError: No loop matching the specified signature and casting was found for ufunc greater
原因:NumPy 和 TensorBoard 的兼容性问题
解决方案::
#tb_writer.add_histogram('classes', c, 0)
tb_writer.add_histogram('classes', c.cpu().numpy().astype(float), 0)
遇到的问题3:
问题:TypeError: No loop matching the specified signature and casting was found for ufunc greater
原因:TensorBoard的add_histogram()函数中,NumPy的greater运算与数据类型不兼容。
解决方案::
#cum_counts = np.cumsum(np.greater(counts, 0, dtype=np.int32))
cum_counts = np.cumsum(np.greater(counts, 0).astype(np.int32))
遇到的问题4:
问题:RuntimeError: result type Float can't be cast to the desired output type long int
原因:build_targets() 函数中尝试将浮点数转换为整数时出现的类型不匹配问题
解决方案::参考文章一步真实解决RuntimeError: result type Float can‘t be cast to the desired output type long int_runtimeerror: result type float can't be cast to t-CSDN博客
# anchors = det.anchors[i]
anchors, shape = det.anchors[i], p[i].shape
#indices.append((b, a, gj.clamp_(0, gain[3] - 1), gi.clamp_(0, gain[2] - 1)))
indices.append((b, a, gj.clamp_(0, shape[2] - 1), gi.clamp_(0, shape[3] - 1)))
然后成功开始跑了

具体代码可以是
CUDA_VISIBLE_DEVICES="0,1,2,3" python3 train.py --data data/widerface.yaml --cfg models/yolov5s.yaml --weights 'pretrained models'
5.测试和评估
yolov5-face官方给的测试和评估方案是,也是widerface这个人脸库官方给的测评方案
python3 test_widerface.py --weights 'your test model' --img-size 640
cd widerface_evaluate
python3 evaluation.py
注:后面的测试和评估都是用的yolo变换前的数据集
5.1生成wider_val.txt
遇到的问题1:运行代码python test_widerface.py --weights 'mmyolo/yolov5-face/runs/train/exp/weights/best.pt' --img-size 640时出现报错:
[Errno 2] No such file or directory: '/yolov5-face/data/widerface/val/wider_val.txt'
原因:缺少wider_val.txt'文件
解决方案:后评论区查阅到有人说该文章有解决方法
【人脸检测】复现Pytorch_Retinaface(Pytorch版本)_retinaface要gpu吗-CSDN博客
新建一个文件命名为widerValFile.py,内容为:
import os
import argparse
parser = argparse.ArgumentParser(description='Retinaface')
parser.add_argument('--dataset_folder', default='./data/widerface/val/images/', type=str, help='dataset path')
args = parser.parse_args()
if __name__ == '__main__':
# testing dataset
testset_folder = args.dataset_folder
testset_list = args.dataset_folder[:-7] + "label.txt"
with open(testset_list, 'r') as fr:
test_dataset = fr.read().split()
num_images = len(test_dataset)
for i, img_name in enumerate(test_dataset):
print("line i :{}".format(i))
if img_name.endswith('.jpg'):
print(" img_name :{}".format(img_name))
f = open(args.dataset_folder[:-7] + 'wider_val.txt', 'a')
f.write(img_name+'\n')
f.close()
再运行 ,把后面的文件夹路径换成自己的(数据集用的是未转换成yolo格式的那个数据集)
python widerValFile.py --dataset_folder /home/ubuntu/workdir/qita/insightface/data/retinaface/val/images/
转换成功后,会出现一个 wider_val.txt文件,就是我们缺少的wider_val.txt文件

5.2测试
修改test_widerface.py文件的主函数,内容如下
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--weights', nargs='+', type=str, default='/home/ubuntu/workdir/mmyolo/yolov5-face/runs/train/exp/weights/best.pt', help='model.pt path(s)')
parser.add_argument('--img-size', type=int, default=640, help='inference size (pixels)')
parser.add_argument('--conf-thres', type=float, default=0.02, help='object confidence threshold')
parser.add_argument('--iou-thres', type=float, default=0.5, help='IOU threshold for NMS')
parser.add_argument('--device', default='0', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS')
parser.add_argument('--augment', action='store_true', help='augmented inference')
parser.add_argument('--update', action='store_true', help='update all models')
parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --class 0, or --class 0 2 3')
parser.add_argument('--project', default='runs/detect', help='save results to project/name')
parser.add_argument('--name', default='exp', help='save results to project/name')
parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
parser.add_argument('--save_folder', default='./widerface_evaluate/widerface_txt/', type=str, help='Dir to save txt results')
parser.add_argument('--dataset_folder', default='/home/ubuntu/workdir/qita/insightface/data/retinaface/val/images', type=str, help='dataset path')
parser.add_argument('--folder_pict', default='/home/ubuntu/workdir/qita/insightface/data/retinaface/val/wider_val.txt', type=str, help='folder_pict')
opt = parser.parse_args()
print(opt)
# Load model
device = select_device(opt.device)
model = attempt_load(opt.weights, map_location=device) # load FP32 model
# Read folder_pict to map image names to their subfolders
pict_folder = {}
with open(opt.folder_pict, 'r') as f:
for line in f.readlines():
line = line.strip()
if line: # Skip empty lines
parts = line.split('/')
if len(parts) >= 2: # Ensure valid format: "subfolder/image.jpg"
pict_folder[parts[-1]] = parts[-2]
# Prepare testing dataset
testset_folder = opt.dataset_folder
image_extensions = ('.jpg', '.jpeg', '.png')
# Recursively find all image files in subdirectories
image_paths = []
for root, _, files in os.walk(testset_folder):
for file in files:
if file.lower().endswith(image_extensions):
image_paths.append(os.path.join(root, file))
# Process images
with torch.no_grad():
for image_path in tqdm(image_paths, desc='Processing images'):
img0 = cv2.imread(image_path) # BGR
if img0 is None:
print(f'Warning: Could not read image {image_path}')
continue
# Detect faces
boxes = detect(model, img0)
# Prepare save path
image_name = os.path.basename(image_path)
subfolder = pict_folder.get(image_name, 'unknown') # Default to 'unknown' if not found
txt_name = os.path.splitext(image_name)[0] + ".txt"
save_name = os.path.join(opt.save_folder, subfolder, txt_name)
# Ensure directory exists
os.makedirs(os.path.dirname(save_name), exist_ok=True)
# Save results
with open(save_name, "w") as fd:
fd.write(f"{os.path.basename(save_name)[:-4]}\n")
fd.write(f"{len(boxes)}\n")
for box in boxes:
x, y, w, h, conf = box
fd.write(f"{x} {y} {w} {h} {min(conf, 1):.3f}\n")
print('Evaluation completed.')
并修改test_widerface.py文件的最后两个parser,将default后面修改成自己数据集的路径
parser.add_argument('--dataset_folder', default='/home/ubuntu/workdir/qita/insightface/data/retinaface/val/images', type=str, help='dataset path')
parser.add_argument('--folder_pict', default='/home/ubuntu/workdir/qita/insightface/data/retinaface/val/wider_val.txt', type=str, help='folder_pict')
再运行 ,weights后记得换成自己的路径
python test_widerface.py --weights runs/train/exp/weights/best.pt --img-size 640
成功运行了

5.3评估
后面再运行官方给的
cd widerface_evaluate
python evaluation.py
结果又出现了问题2:AttributeError: module 'numpy' has no attribute 'float'.
原因:还是numpy版本的问题
解决方案:
python setup.py build_ext --inplace
再尝试运行
python evaluation.py
成功运行

可以看到结果是

和论文的结果Our YOLOv5s那行结果94.33 92.61 83.15类似

参考博客:
❀YOLOv5学习❀yolo5-face论文里代码复现,实现运行_yolov5-face train怎么显示过程-CSDN博客yolov5-face模型训练以及测试_yolov5face训练-CSDN博客
更多推荐


所有评论(0)