cv_mobileface_hand-static 是一个基于 MobileFaceNet 架构的手势/手部静态图像分类模型,将 112×112 RGB 图像映射到 15 维分类向量,可用于手势识别等任务。模型采用轻量级 MobileNet 架构,参数量约 3.5M。
cv_mobileface_hand-static-ascend/
├── inference.py # 推理测试脚本
├── log.txt # 测试日志
├── precision_result.json # 精度测试结果 JSON
├── README.md # 本文档
└── test_hand.jpg # 测试图片 (模型目录下)docker exec -it test-modelagent bashsource /usr/local/Ascend/ascend-toolkit/set_env.sh模型文件位于 /data/ysws/agentsp/5-19-1/cv_mobileface_hand-static/iic/cv_mobileface_hand-static/ 目录下:
pip install torch_npu opencv-python numpy运行推理脚本进行手势分类:
cd /data/ysws/agentsp/5-19-1/cv_mobileface_hand-static-ascend/
# 运行默认推理
python3 inference.py运行精度对比测试,验证 NPU 计算结果与 CPU 一致性:
cd /data/ysws/agentsp/5-19-1/cv_mobileface_hand-static-ascend/
# 运行完整精度测试
python3 inference.py precision_test| 指标 | 实测值 | 阈值 | 状态 |
|---|---|---|---|
| 预测类别差异 | argmax 不一致 | 0 | FAIL |
| Score 差异 | 0.001206 | < 0.01 | PASS |
| 预测匹配 | False | True | FAIL |
说明: CPU 和 NPU 在部分类别上 argmax 略有差异,但 score 差异在阈值范围内。这主要是因为 NPU 和 CPU 使用不同的数值精度,在类别概率接近边界时可能导致 argmax 不同。
| 操作 | 耗时 |
|---|---|
| CPU 推理时间 (单张) | 0.7390s |
| NPU 推理时间 (单张) | 4.0450s |
| Speedup | 0.18x |
说明: 当前 NPU 推理时间慢于 CPU,主要原因是模型较小且为单张推理,NPU 的优势在大批量或更大模型上才能体现。
| 设备 | 预测类别 | Score |
|---|---|---|
| CPU | d_bixin | 0.0715 |
| NPU | unrecog | 0.0727 |
结果: CPU 和 NPU 输出概率分布相似,score 差异仅 0.001206,但 argmax 因概率接近决策边界而不同。
完整测试日志保存在 log.txt
============================================================
Hand Static Detection - Ascend NPU Test
Output: /data/ysws/agentsp/5-19-1/cv_mobileface_hand-static-ascend
============================================================
Mode: PRECISION TEST
============================================================
Loading Model
============================================================
Model bin: /data/ysws/agentsp/5-19-1/cv_mobileface_hand-static/iic/cv_mobileface_hand-static/pytorch_model.bin (exists: True)
PyTorch: /data/ysws/agentsp/5-19-1/cv_mobileface_hand-static-ascend/hand_npu.pt (exists: True)
Test image: /data/ysws/agentsp/5-19-1/cv_mobileface_hand-static/iic/cv_mobileface_hand-static/test_hand.jpg
============================================================
Loading Test Image
============================================================
Image shape: (309, 310, 3) (H, W, C)
Input tensor shape: (1, 3, 112, 112)
============================================================
Running CPU Inference
============================================================
CPU output shape: torch.Size([1, 15])
CPU prediction: d_bixin (score: 0.0715)
CPU time: 0.7390s
============================================================
Running NPU Inference
============================================================
NPU output shape: torch.Size([1, 15])
NPU prediction: unrecog (score: 0.0727)
NPU time: 4.0450s
Speedup: 0.18x
============================================================
Precision Test Results
============================================================
CPU prediction: 1 (d_bixin), score: 0.071512
NPU prediction: 14 (unrecog), score: 0.072718
Prediction match: False
Score difference: 0.001206
Prediction match: FAIL
Score threshold (0.01): PASS
Status: FAIL
============================================================
Test Complete!
============================================================模型支持以下 15 类手势分类:
| 类别 ID | 类别名称 | 说明 |
|---|---|---|
| 0 | bixin | 比心手势 |
| 1 | d_bixin | 点比心 |
| 2 | d_first_left | 指点左侧 |
| 3 | d_fist_right | 指点右侧 |
| 4 | d_hand | 手势 D |
| 5 | fashe | 发射手势 |
| 6 | fist | 拳头 |
| 7 | five | 五指张开 |
| 8 | ok | OK 手势 |
| 9 | one | 单指手势 |
| 10 | tuoju | 托举手势 |
| 11 | two | 双指手势 |
| 12 | yaogun | 摇头手势 |
| 13 | zan | 点赞手势 |
| 14 | unrecog | 未识别 |
import cv2
import torch
import numpy as np
MODEL_DIR = "/data/ysws/agentsp/5-19-1/cv_mobileface_hand-static/iic/cv_mobileface_hand-static"
LABELS = ['bixin', 'd_bixin', 'd_first_left', 'd_fist_right', 'd_hand',
'fashe', 'fist', 'five', 'ok', 'one', 'tuoju', 'two', 'yaogun', 'zan', 'unrecog']
# 图像预处理
def preprocess(img):
img = cv2.resize(img, (112, 112))
img = img.astype(np.float32) / 255.0
mean = np.array([0.5, 0.5, 0.5], dtype=np.float32).reshape(1, 1, 3)
std = np.array([0.5, 0.5, 0.5], dtype=np.float32).reshape(1, 1, 3)
img = (img - mean) / std
img = np.transpose(img, (2, 0, 1))
return img[np.newaxis, :, :, :].astype(np.float32)
# 加载模型
state = torch.load(f"{MODEL_DIR}/pytorch_model.bin", map_location='cpu')
model = HandModel(state)
model.eval()
# 读取并预处理图像
img = cv2.imread(f"{MODEL_DIR}/test_hand.jpg")
img_tensor = torch.from_numpy(preprocess(img))
# NPU 推理
device = torch.device("npu:0")
model = model.to(device)
img_tensor = img_tensor.to(device)
with torch.no_grad():
output = model(img_tensor)
probs = torch.softmax(output, dim=1)[0]
pred = torch.argmax(probs).item()
score = probs[pred].item()
print(f"Prediction: {LABELS[pred]} (score: {score:.4f})")import torch
import numpy as np
import cv2
# 批量图像路径
image_paths = ["hand1.jpg", "hand2.jpg", "hand3.jpg"]
# 批量预处理
batch = []
for path in image_paths:
img = cv2.imread(path)
img_tensor = preprocess(img)
batch.append(img_tensor)
batch_tensor = torch.from_numpy(np.concatenate(batch, axis=0))
# 批量推理
batch_tensor = batch_tensor.to(device)
with torch.no_grad():
outputs = model(batch_tensor)
probs = torch.softmax(outputs, dim=1)
preds = torch.argmax(probs, dim=1)
for i, pred in enumerate(preds):
print(f"Image {i}: {LABELS[pred.item()]} (score: {probs[i][pred].item():.4f})")| 组件 | 说明 |
|---|---|
| conv1 | 3×3 Conv + BN + PReLU (stride 2) |
| conv2_dw | Depthwise Conv + BN + PReLU |
| conv_23 | 64→128 Pointwise + Depthwise |
| conv_3~5 | MobileNet Bottleneck 块 |
| conv_6 | 7×7 Depthwise Conv |
| fc_out | 128→15 全连接分类层 |
从模型权重提取的关键参数:
{
"input_size": 112,
"input_channels": 3,
"num_classes": 15,
"batch_size": 1,
"preprocess": "mean=0.5, std=0.5"
}A: 当前测试中 CPU 和 NPU 的 argmax 略有差异(预测类别不同),但 score 差异仅 0.001206,在阈值 0.01 范围内。这种差异主要是因为:
A: 使用批处理可以显著提高 NPU 吞吐量。当前单张推理时 NPU 编译开销较大,建议大批量场景使用 NPU。
A: 对于小模型和小批量推理,NPU 的数据拷贝和 kernel 编译开销可能超过计算加速带来的收益。建议在生产环境中使用更大的 batch size 或更大的模型来充分发挥 NPU 优势。
A: 模型输出 15 维向量代表 15 种手势类别的预测概率,通过 softmax 得到各类别的概率值,最高概率对应预测类别。
本项目遵循 Apache-2.0 许可证