三、MTCNN + MobileFaceNet 部署到 K210 的完整步骤
1. 模型准备与优化
(1) MTCNN 模型适配 KPU
- 步骤 1:获取 TensorFlow 版 MTCNN
BASH
git clone https://github.com/ipazc/mtcnn
# 提取 PNet/RNet/ONet 的 .pb 模型
python mtcnn/export_models.py
- 步骤 2:转换为 TFLite 格式
PYTHON
import tensorflow as tf
# 转换 PNet
converter = tf.lite.TFLiteConverter.from_saved_model("mtcnn/pnet/")
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_pnet = converter.convert()
open("pnet.tflite", "wb").write(tflite_pnet)
- 固定输入尺寸(如
320x240
),删除动态ResizeBilinear
层。 - 确保所有卷积层满足 KPU 限制(
kernel=1x1/3x3
,stride=1/2
)。
- 固定输入尺寸(如
(2) MobileFaceNet 量化校准
- 步骤 1:导出 Keras 模型为 TFLite
PYTHON
model = keras.models.load_model("mobilefacenet.h5")
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = calibration_data_gen # 提供 100 张校准图片
tflite_model = converter.convert()
open("mobilefacenet_int8.tflite", "wb").write(tflite_model) - 步骤 2:验证量化精度损失
使用 LFW 数据集测试量化后模型,确保准确率下降不超过 2%。
2. 使用 nncase 编译为 K210 模型
BASH
# 编译 PNet
ncc -i tflite -o k210model --dataset calibration_images/ --postprocess 0to1 pnet.tflite pnet.kmodel
# 编译 MobileFaceNet
ncc -i tflite -o k210model --dataset faces_emore/ --weights-bits 8 mobilefacenet_int8.tflite mobilefacenet.kmodel
3. K210 端部署代码
PYTHON
# K210 MicroPython 代码(精简版)
import sensor, image, time
from nncase import runtime
# 初始化摄像头
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA) # 320x240
# 加载模型
pnet = runtime.Kpu()
pnet.load_kmodel('/sd/pnet.kmodel')
mobilefacenet = runtime.Kpu()
mobilefacenet.load_kmodel('/sd/mobilefacenet.kmodel')
while True:
img = sensor.snapshot()
# PNet 检测
pnet_input = img.resize(160, 120).pix_to_ai()
pnet.run(pnet_input)
boxes = pnet.get_outputs()[0] # 解析输出边界框
for box in boxes:
# 裁剪人脸并缩放到 112x112
face = img.crop(box).resize(112, 112)
face_ai = face.pix_to_ai()
# MobileFaceNet 提取特征
mobilefacenet.run(face_ai)
embedding = mobilefacenet.get_outputs()[0]
# 比对数据库(需提前存储注册特征)
min_dist = 1.0
for db_emb in database:
dist = sum((embedding[i] - db_emb[i])**2 for i in range(128))**0.5
if dist < min_dist:
min_dist = dist
if min_dist < 0.5: # 阈值根据场景调整
img.draw_rectangle(box, color=(0, 255, 0))
4. KPU 适配关键操作
- 内存优化:
- 使用
runtime.Kpu.alloc_input()
和runtime.Kpu.alloc_output()
复用内存缓冲区。 - 限制并发模型数量(K210 内存仅 6MB,同时加载多个模型需分时加载)。
- 使用
- 算子替换:
- 将 MobileFaceNet 中的
GlobalAveragePooling2D
替换为AveragePooling2D(pool_size=(7,7))
。 - 确保所有
Conv2D
的padding
为same
且输入尺寸为偶数。
- 将 MobileFaceNet 中的
四、YOLOv3-Tiny + ArcFace 部署到 K210 的完整步骤
1. 模型训练与优化
(1) YOLOv3-Tiny 适配 KPU
- 步骤 1:训练 TensorFlow 版 YOLOv3-Tiny
BASH
git clone https://github.com/zzh8829/yolov3-tf2
python train.py --model yolov3-tiny --dataset widerface/ --weights yolov3-tiny.conv.15 - 步骤 2:简化模型结构
- 删除
ResizeNearestNeighbor
上采样层,改用Conv2DTranspose
(需 KPU 支持)。 - 限制输入尺寸为
320x240
(K210 最大支持分辨率)。
- 删除
(2) ArcFace 特征提取模型量化
- 步骤 1:转换 PyTorch 模型为 ONNX
PYTHON
import torch
from models.arcface import ArcFacemodel = ArcFace(pretrained=True)
dummy_input = torch.randn(1, 3, 112, 112)
torch.onnx.export(model, dummy_input, "arcface.onnx", opset_version=11)
- 步骤 2:ONNX 转 TFLite
BASH
pip install onnx-tf
onnx-tf convert -i arcface.onnx -o arcface_tf
tflite_convert --saved_model_dir arcface_tf --output_file arcface.tflite
2. nncase 编译与优化
BASH
# 编译 YOLOv3-Tiny
ncc -i tflite -o k210model --dataset calibration_images/ yolov3-tiny.tflite yolov3-tiny.kmodel
# 编译 ArcFace
ncc -i tflite -o k210model --postprocess n1to1 --weights-bits 8 arcface.tflite arcface.kmodel
3. K210 端部署代码
PYTHON
# K210 MicroPython 代码(关键逻辑)
import nncase, sensor, image
# 初始化模型
yolo = nncase.RuntimeKpu()
yolo.load_kmodel('/sd/yolov3-tiny.kmodel')
arcface = nncase.RuntimeKpu()
arcface.load_kmodel('/sd/arcface.kmodel')
while True:
img = sensor.snapshot().resize(320, 240)
# YOLO 推理
yolo_input = img.pix_to_ai()
yolo.run(yolo_input)
dets = parse_yolo_output(yolo.get_outputs()) # 自定义解析函数
for det in dets:
face = img.crop(det['bbox']).resize(112, 112)
# ArcFace 特征提取
face_ai = face.pix_to_ai().transpose([2, 0, 1]) # HWC→CHW
arcface.run(face_ai)
embedding = arcface.get_outputs()[0]
# 特征比对(Faiss 需预编译为 K210 兼容格式)
match_id = faiss_search(embedding, database)
if match_id != -1:
img.draw_string(10, 10, f"ID: {match_id}", color=(255, 0, 0))
显示全部 (27)
4. KPU 适配关键操作
- YOLOv3-Tiny 优化:
- 替换
LeakyReLU
为ReLU
(KPU 不支持 LeakyReLU 硬件加速)。 - 确保所有
Conv2D
的stride=1/2
,输入尺寸为偶数。
- 替换
- ArcFace 调整:
- 使用
--postprocess n1to1
参数匹配模型输入归一化范围([-1,1])。 - 将
Bottleneck
结构中的Flatten
替换为GlobalAveragePooling2D
。
- 使用
五、总结与建议
- 路径选择:将
nncase
工具链放在无空格路径(如/opt/nncase
),并确保bin
加入 PATH。 - 模型设计铁律:
- 输入尺寸 ≤ 320x240,输出 ≥ 4x4。
- 仅使用 KPU 支持的算子(如 Conv3x3/1x1、ReLU)。
- 性能压榨技巧:
- 使用
ncc
的--weights-bits 8
和--channelwise-output
降低内存占用。 - 启用
nncase.RuntimeTensor
内存池复用,减少碎片
- 使用