Ascend-SACT/retinaface
模型介绍文件和版本Pull Requests讨论分析
下载使用量0

适配环境信息

NPU硬件:A2/910B

操作系统:ARM

部署方式:单卡

1 背景

本次工作的核心目标是完成业界顶尖的人脸检测模型RetinaFace在华为昇腾NPU上的端到端迁移与验证。RetinaFace是人脸识别、智能安防、手机解锁等关键应用的基石模型,其多任务(人脸框、关键点、密集对齐)和高效单阶段检测的特性代表了计算机视觉的高复杂度需求。实现其在国产AI硬件上的稳定运行与训练,对构建自主可控的AI应用生态具有重大现实意义。

迁移过程面临以下几个核心挑战,本次工作通过系统性的工程方法逐一攻克: 生态壁垒:RetinaFace原生于CUDA生态,代码中充斥着大量硬编码的 .cuda() 调用和CUDA相关配置。这是迁移的首要障碍。 模型复杂性:其多任务学习架构(同时回归框、关键点和3D信息)对算子的多样性和性能要求极高,增加了NPU兼容性验证的难度。 训练验证的复杂性:相比仅做推理,完成训练验证是更大的挑战。它涉及数据加载、损失计算、反向传播、优化器更新等完整流程,对硬件和软件栈的稳定性要求更为严苛。 本次工作的解决方案亮点: 自动化代码适配:使用脚本全局替换 .cuda() 调用并调整导入顺序,高效地突破了生态壁垒。 渐进式验证策略:从核心推理功能验证入手,成功后再推进到全流程训练验证,有效控制了风险。 数据裁剪:通过裁剪数据集,在保证验证有效性的前提下,将训练验证时间缩短至分钟级,极大提升了调试效率。

2 模型介绍

RetinaFace 是一个非常重要且高效的单阶段人脸检测模型。

简单来说,您可以把它理解为专门用于“在人脸检测这个细分任务上,做到了极致精度和速度的YOLO”。

下面为您详细解析这个模型。

一、核心是什么? RetinaFace 是一个单阶段(one-stage)的人脸检测器,它的核心目标是:在任意复杂的图像或视频中,以极高的准确率找出所有人脸的位置(画出框),并同时定位人脸上的关键点(如眼睛、鼻子、嘴角)。

“单阶段”:意味着它像YOLO一样,直接在网络中预测目标的位置和类别,速度通常比两阶段模型(如Faster R-CNN)更快。 “极致”:它在提出之时,在公认的权威人脸检测基准(如WIDER FACE)上达到了最先进的性能,尤其是在检测各种尺度、尤其是小人脸方面表现非常出色。 二、主要特点和创新 RetinaFace 的成功源于几个关键设计:

多任务学习:这是它最核心的特点。它不仅预测人脸框,还同步进行:

人脸框回归:预测人脸边界框的精确坐标。 人脸关键点定位:通常定位5个点(两只眼睛的眼角、鼻尖、两个嘴角)。 密集人脸对齐(创新点):通过预测像素级的3D人脸形状信息(密集回归),来进一步提升定位精度。这个额外任务作为监督信号,让模型对人脸的几何结构有更深的理解。 特征金字塔网络(FPN):

和YOLOv3/v4等现代检测器一样,RetinaFace使用FPN来有效地融合不同尺度的特征。 这使得模型能够同时很好地检测大脸和小脸,应对尺度变化。 上下文模块:

在预测分支上增加了上下文模块,通过扩大感受野来捕捉更多的上下文信息,有助于减少误检(如将人手误检为人脸)和漏检。 灵活的骨干网络:

原论文使用了MobileNet(轻量、快速)和ResNet(更重、更精确)等作为特征提取的骨干网络,可以根据实际需求在速度和精度之间进行权衡。 三、主要应用场景 RetinaFace 是许多人脸相关应用的“第一步”,也是最关键的一步:

人脸识别系统:首先需要用RetinaFace这样的人脸检测器从图像中截取出标准的人脸区域,然后再送入识别模型进行身份比对。 手机解锁与支付:在解锁瞬间,需要快速准确地检测到人脸。 照片管理软件:自动识别照片中的人脸并进行分类、标签。 视频会议与美颜:实时检测人脸以应用虚拟背景、贴纸或美颜效果。 安防与监控:在视频流中实时检测和跟踪人脸。

3 解决方案

镜像下载:

from atomgit_hub import snapshot_download
snapshot_download("Ascend-SACT/tacotron2",  local_dir = './download')

3.1 模型获取

# 1. 克隆代码库
cd /tmp
git clone https://github.com/biubug6/Pytorch_Retinaface.git
cd Pytorch_Retinaface

# 2. 安装必要依赖
pip install opencv-python-headless huggingface_hub
pip install torch==2.1.0 torchvision==0.16.0 torch_npu==2.1.0

3.2 适配

脚本一键替换所有硬编码的 .cuda() 为 NPU 调用,并修复导入顺序

# 1. 全局替换 .cuda() 为 .to("npu")
find . -name "*.py" | xargs sed -i 's/\.cuda()/.to("npu")/g'

# 2. 修复 train.py 中的 import 顺序 (避免 SyntaxError)
# 先删除第一行可能错误的插入,再在 correct 位置插入 torch_npu
sed -i '1d' train.py
sed -i '/from __future__ import print_function/a import torch_npu' train.py

# 3. 禁用 Cudnn Benchmark (NPU 不支持)
sed -i 's/cudnn\.benchmark = True/cudnn.benchmark = False/g' train.py

# 4. 开启 NPU 内存优化配置
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True

3.3 预训练权重获取

python -c "
import os
os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'
from huggingface_hub import hf_hub_download

print('⬇️ 正在下载 ResNet50 权重...')
try:
    os.makedirs('weights', exist_ok=True)
    hf_hub_download(repo_id='akhaliq/RetinaFace-R50', filename='RetinaFace_R50.pth', local_dir='./weights', local_dir_use_symlinks=False)
    # 重命名为代码预期的文件名
    if os.path.exists('weights/RetinaFace_R50.pth'):
        os.rename('weights/RetinaFace_R50.pth', 'weights/Resnet50_Final.pth')
    print('✅ 权重下载并重命名成功!')
except Exception as e:
    print(f'❌ 下载失败: {e}')
"

3.4 推理验证

3.4.1 推理脚本

cat <<EOF > test_npu.py
import torch
import torch_npu
import numpy as np
import time
from models.retinaface import RetinaFace
from data import cfg_re50

def load_model(model, pretrained_path, device):
    pretrained_dict = torch.load(pretrained_path, map_location=device)
    if "state_dict" in pretrained_dict.keys():
        pretrained_dict = {k.replace('module.', ''): v for k, v in pretrained_dict['state_dict'].items()}
    else:
        pretrained_dict = {k.replace('module.', ''): v for k, v in pretrained_dict.items()}
    model.load_state_dict(pretrained_dict, strict=False)
    return model

if __name__ == '__main__':
    torch.set_grad_enabled(False)
    device = torch.device("npu:0")
    print(f"🚀 Device: {device}")

    # Init
    net = RetinaFace(cfg=cfg_re50, phase='test')
    net = load_model(net, './weights/Resnet50_Final.pth', device)
    net = net.to(device)
    net.eval()

    # Data
    img = torch.randn(1, 3, 640, 640).to(device) # Dummy image

    # Warmup
    print("🔥 Warming up...")
    _ = net(img)

    # Inference
    print("⚡ Running Inference...")
    t0 = time.time()
    _ = net(img)
    torch.npu.synchronize()
    t1 = time.time()
    
    print(f"⏱️ Cost: {(t1 - t0) * 1000:.2f} ms")
    print("🎉 Inference Validation Passed!")
EOF

3.4.2 执行验证

# 运行验证
python test_npu.py

3.4.3推理结果

验证通过

3.5 训练验证

3.5.1 数据下载

# 1. 下载数据脚本
python -c "
import os
os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'
from huggingface_hub import hf_hub_download

repo_id = 'CUHK-CSE/wider_face'
files = ['data/WIDER_train.zip', 'data/WIDER_val.zip']

print('🚀 正在下载数据集 (约 3GB)...')
for f in files:
    try:
        hf_hub_download(repo_id=repo_id, filename=f, repo_type='dataset', local_dir='.', local_dir_use_symlinks=False)
        print(f'✅ {f} 下载完成')
    except Exception as e:
        print(f'❌ {f} 失败: {e}')
"

# 2. 解压并整理目录
mkdir -p data/widerface/train
mkdir -p data/widerface/val
unzip -q data/WIDER_train.zip -d data/widerface/train/
mv data/widerface/train/WIDER_train/images data/widerface/train/images

3.5.2 数据裁剪

只保留前 50 行,确保 1 分钟内跑完验证

# 1. 下载标签文件
python -c "
import urllib.request
url = 'https://mirror.ghproxy.com/https://raw.githubusercontent.com/wujixs/RetinaFace-Pytorch/master/data/widerface/train/label.txt'
try:
    urllib.request.urlretrieve(url, 'data/widerface/train/label.txt')
    print('✅ Label 下载成功')
except Exception as e:
    print(f'❌ Label 下载失败: {e}')
"
# 2. 裁剪数据集 (仅保留 50 张图)
python -c "
path = 'data/widerface/train/label.txt'
with open(path, 'r') as f:
    lines = f.readlines()
new_lines = []
count = 0
for line in lines:
    if line.startswith('#'):
        count += 1
        if count > 50: break
    new_lines.append(line)
with open(path, 'w') as f:
    f.writelines(new_lines)
print('✂️ 数据集已裁剪为 50 张图片')
"

3.5.3 修改配置启动训练

# 1. 修改 Batch Size 为 8
sed -i "s/'batch_size': [0-9]\+/'batch_size': 8/g" data/config.py

# 2. 启动训练 (50 Epoch)
# --save_folder: 权重保存路径
python train.py --network resnet50 --num_workers 4 --save_folder ./weights/

总结

本次RetinaFace模型的成功迁移,其价值远超单个模型的运行,主要体现在三个方面:

技术里程碑价值:成功完成了从模型推理到完整训练的端到端验证。这证明了昇腾NPU平台具备支持复杂多任务检测模型全生命周期开发的能力,是其成熟度的重要标志。 方法论与范本价值:为迁移其他基于PyTorch的复杂CV模型提供了可复用的完整范式。从代码适配、权重获取、推理验证到训练调试,形成了一套标准流程,极大降低了后续模型的迁移门槛。