如何基于飞桨打造智能眼镜视觉辅助系统
目前中国视障人士数量多达700万,占全世界视障人士总数的18%。此外,全国还有约1200万弱视人群,两者总和约占全国总人口的1.5%。严重的视觉障碍给他们日常生活带来了巨大困难。
视障人群需要专人陪同,或借助辅助工具例如导盲杖、导盲犬等才能正常生活。这些传统解决方案,始终存在普及率低、成本高以及使用困难等问题。如何有效助力视障人士日常生活与出行,改善他们的生活质量,是当下全社会亟待解决的问题。
幸运的是,当前广泛使用的手机芯片,不仅具备高效能、超低功耗、开发设计弹性,也满足特殊行业应用的定制系统整合设计需求,因此非常适合用来开发智能出行类产品应用。例如,手机搭配百度端侧推理引擎 Paddle Lite,不仅能够加速设备开发,同时能提供设备持续维护、优化的设计弹性,加上目前手机完善的生态链和自身高可靠度表现,可大大降低智能眼镜设备开发过程的风险。
此外,通过设计出合理的并行运算机制,可以对人工智能算法进一步优化,特别是那些利用深度学习技术进行训练或推理的场合。百度飞桨支持并行计算,可以很容易设计出符合要求的系统结构;其丰富的程序资源和硬件支持,可以满足更广泛的市场需求。
因此,我们基于人工智能技术,开发出一套视觉辅助智能眼镜系统。该系统首先通过百度深度学习平台飞桨进行大规模日常生活环境图像的训练,形成服务于视障人士生活与出行的深度神经网络。接着配合智能眼镜,采用安卓智能手机作为运算核心,使用 Paddle Lite 作为智能手机上的人工智能图像推理平台,并导入前述网络配置参数,从而在智能眼镜系统中实现对视障人士的生活和出行提供辅助。
用户佩戴上眼镜后,语音告诉眼镜相应的指令,例如,进行物体寻找,通过交互模块,手机端首先会处理用户的语音信号,并执行相应的指令;与此同时,智能眼镜通过眼镜镜架处的摄像头捕捉周围的环境,通过通信模块传入手机端,手机采用飞桨生成的深度卷积神经网络 SSD 作为核心算法单元完成画面中的物体检测与识别。获得结果以后,将结果通过交互模块再反馈给用户。
如何实现智能眼镜系统
本系统基于深度学习技术中的深度卷积神经网络(Deep Convolution Neural Network),以目前通用的日常生活环境图像为训练数据集,开发出一套应用于视障人士的智能服务导航系统。本系统的软件核心算法通过飞桨进行卷积神经网络搭建,硬件部分采用安卓智能手机以及配有摄像头的眼镜,利用 Paddle Lite 进行安卓手机端的开发,完成了如下两方面的设计工作:
飞桨深度学习算法设计,即通过飞桨生成用于辅助视障人士日常生活和出行的深度神经网络。
安卓程序开发,即读取摄像头图像,使用 Paddle Lite 在智能手机上进行神经网络推理等功能开发,最后进行系统测试。
数据图像训练样本
如下图图4所示,系统中用于训练的样本选用平时常用的生活用品,如水杯,瓶子,自行车,汽车等20类图片,其中包含9963张标注过的图片,由训练集、测试集、验证集三部分组成,共标注出24640个物体。
对于非视觉障碍的人而言,从图中可以直观地分类出这些内容。图像经过初步的预处理,根据数据集中提供的标记信息,传入深度卷积神经网络进行训练。
系统实现
整个系统由三个交互的主题构成:眼镜、手机以及用户,而在具体实现过程中,我们将系统分为如下几个部分:
通信模块。负责连接眼镜上的摄像头进行传输,将视频数据传给手机端。
分析模块。是最为核心的部分,包含 SSD 深度神经网络,用于完成物体检测与识别。
交互模块。完成实时播报和语音交互。
分析模块的 SSD 算法的特点在于 SingleShot,也就是说只要观察一次图片,就能够进行目标检测和识别,因此算法的效率非常高。SSD 网络属于典型的回归目标检测算法,具体分为四个步骤:
通过深度神经网络提取整个图片的特征。
对于不同尺度的深度特征图设计不同大小的特征抓取盒。
通过提取这些特征抓取盒对应的深度特征图的特征进行目标识别。
在这些识别的结果中通过非极大值抑制选择最佳的目标识别结果。
这里的多个特征抓取盒就是多尺度的,换言之,SSD 算法的核心思想就是从深度神经网络的不同层来提取特征,并分别利用这些特征进行回归预测。
本系统中,涉及到的 SSD 算法的代码部分如下所示:
def ssd_net(self, scale=1.0):
# 300x300
tmp = self.conv_bn(self.img, 3, int(32 * scale), 2, 1)
# 150x150
tmp = self.depthwise_separable(tmp, 32, 64, 32, 1, scale)
tmp = self.depthwise_separable(tmp, 64, 128, 64, 2, scale)
# 75x75
tmp = self.depthwise_separable(tmp, 128, 128, 128, 1, scale)
tmp = self.depthwise_separable(tmp, 128, 256, 128, 2, scale)
# 38x38
tmp = self.depthwise_separable(tmp, 256, 256, 256, 1, scale)
tmp = self.depthwise_separable(tmp, 256, 512, 256, 2, scale)
# 19x19
for i in range(5):
tmp = self.depthwise_separable(tmp, 512, 512, 512, 1, scale)
module11 = tmp
tmp = self.depthwise_separable(tmp, 512, 1024, 512, 2, scale)
# 10x10
module13 = self.depthwise_separable(tmp, 1024, 1024, 1024, 1, scale)
module14 = self.extra_block(module13, 256, 512, 1, 2)
# 5x5
module15 = self.extra_block(module14, 128, 256, 1, 2)
# 3x3
module16 = self.extra_block(module15, 128, 256, 1, 2)
# 2x2
module17 = self.extra_block(module16, 64, 128, 1, 2)
mbox_locs, mbox_confs, box, box_var = fluid.layers.multi_box_head(
inputs=[
module11, module13, module14, module15, module16, module17
],
image=self.img,
num_classes=self.num_classes,
min_ratio=20,
max_ratio=90,
min_sizes=[60.0, 105.0, 150.0, 195.0, 240.0, 285.0],
max_sizes=[[], 150.0, 195.0, 240.0, 285.0, 300.0],
aspect_ratios=[[2.], [2., 3.], [2., 3.], [2., 3.], [2., 3.],
[2., 3.]],
base_size=self.img_shape[2],
offset=0.5,
flip=True)
return mbox_locs, mbox_confs, box, box_var
在输出层,将 softmax 作为分类输出函数,损失函数使用交叉熵(cross_entropy)函数,采用在均方根传递算法(RMSprop)上改进的适合比较大规模的适合训练大数据集的阶梯阶梯型的学习率算法,通过反向传播来不断更新模型中的参数,从而使得损失函数逐渐减小来不断优化模型。
SSD 网络训练
1. 数据准备
▲ 图6 SSD 网络训练损失与训练迭代次数之间的关系
MobileNet 模型链接
https://github.com/PaddlePaddle/models/tree/release/1.7/PaddleCV/image_classification
飞桨模型库链接:
https://github.com/PaddlePaddle/models
3. 模型评估
· 系统性能评估
▲ 表1 模型性能比较
不同网络的资源消耗不同,取得的识别结果也不尽相同。考虑到智能手机的资源情况,我们选择 MobileNet-SSD 作为核心,其在性能和资源消耗上可以取得很好的平衡。
/opt \
--model_dir=<model_param_dir> \
--model_file=<model_path> \
--param_file=<param_path> \
--optimize_out_type=(protobuf|naive_buffer) \
--optimize_out=<output_optimize_model_dir> \
--valid_targets=(arm|opencl|x86|npu|xpu) \
--prefer_int8_kernel=(true|false) \
--record_tailoring_info =(true|false)
导入 baidu.paddle.liteJava 库。
利用 config.setModelFromFile 从路径中读取移动端的神经网络模型,然后将 config 设置为预测模型 predictor 的参数。
把一维 float 数组格式的输入 input 送入预测模型 predictor 中。
执行 predictor.run 运行神经网络进行预测。
最后,将 predictor 的输出 output 以一维 float 数组格式取出。
// 导入Java API
import com.baidu.paddle.lite.MobileConfig;
import com.baidu.paddle.lite.Tensor;
import com.baidu.paddle.lite.PaddlePredictor;
import com.baidu.paddle.lite.PowerMode;
// 1. 写入配置:设置MobileConfig
MobileConfig config = new MobileConfig();
config.setModelFromFile(<modelPath>); // 设置Paddle Lite模型路径
config.setPowerMode(PowerMode.LITE_POWER_NO_BIND); // 设置CPU运行模式
config.setThreads(4); // 设置工作线程数
// 2. 创建 PaddlePredictor
PaddlePredictor predictor = PaddlePredictor.createPaddlePredictor(config);
// 3. 设置输入数据
long[] dims = {100, 100};
float[] inputBuffer = new float[10000];
for (int i = 0; i < 10000; ++i) {
inputBuffer[i] = i;
}
Tensor input = predictor.getInput(0);
input.resize(dims);
input.setData(inputBuffer);
// 4. 执行预测
predictor.run();
// 5. 获取输出数据
Tensor result = predictor.getOutput(0);
float[] output = result.getFloatData();
for (int i = 0; i < 1000; ++i) {
System.out.println(output[i]);
}
▲ 图8 测试人物识别(远处场景)
▲ 图9 眼镜对于物体的检测识别结果
更多的实际演示效果可以登录链接参看本系统测试版本的视频:
https://www.bilibili.com/video/av56580392/
https://github.com/PaddlePaddle/Paddle-Lite