深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)

文章目录

  • 背景
  • 物体识别简介
    • 自动驾驶
    • 淘宝京东使用物体识别技术
    • 公司业务需求
  • 深度学习简介
    • 深度学习的位置
    • 深度学习概念
    • 深度学习优势
  • 深度学习基础知识
    • 感知机
    • 激活函数
    • 多层感知机
    • 卷积神经网络
      • 卷积层
      • 池化层
    • 模型训练
      • 前向传播
      • 反向传播与参数优化
  • 深度学习服务端框架
    • tensorFlow
    • keras
    • pytorch
    • Caffe/Caffe2.0
  • caffe框架
    • 为何选择caffe
    • caffe环境搭建
    • caffe基础
      • 数据集
      • 模块概要图
      • solver(prototxt) 执行者配置
      • 神经网络可视化
      • caffe中的基础概念
        • blobs
        • layer 神经层
        • net 神经网络
        • forward/backward 前向传播/反向传播
    • caffe+mnist数据集+lenet
    • caffe+cifar10+caffenet
    • caffe+cifar10+mobilenet
    • caffe+voc2012+vgg(finetune)+ssd(物体检测模型)
  • 轻量级客户端框架-ncnn
    • ncnn简介
    • ncnn+caffe+mobilenet实战
      • ncnn环境搭建
      • 模型转化(caffe格式-> ncnn格式)
    • 源码解析
      • 文件目录
      • 执行流程
      • 重点代码
      • 效果展示
      • 其他工程的效果图
  • 相关学习资料
    • 教学视频
    • 开源项目
    • 参考博客

背景

产品以后的发展需要添加更多科技元素,如下:

  • 人脸识别
  • 物体识别
  • 场景识别

以下以物体识别为重点,使用到了深度学习技术,以下我们将逐一展开。
本次分享的重点是深度学习+caffe+ncnn,其余部分将简单的进行带过。
注:本文主要以有监督的学习为主(分类和回归问题),无监督学习不作为分享范围。

物体识别简介

物体识别(俗称Object detection),是近年来兴起的技术,这也是人工智能的首要目标之一。这是一种完全模拟人眼识别的技术,即使在物体旋转、变色、部分展示等的情况下,同样具备优秀的识别效果。
人工智能目标是:

  • 让机器看世界
  • 让机器听世界
  • 让机器独立思考
    深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第1张图片

自动驾驶

在驾驶领域中,引入物体识别技术将大大降低交通事故发生的概率。
深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第2张图片
深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第3张图片

淘宝京东使用物体识别技术

深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第4张图片

公司业务需求

近期产品提出物体识别的相应需求,能识别出家长和老师发送图片中的物体,来开展相应的业务。以下是一张海边游玩的照片。

深度学习简介

深度学习的位置

深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第5张图片
深度学习分别属于人工智能和机器学习的一部分。与深度学习相并行的另外一种机器学习方法,被称之为传统的机器学习(例如svm、逻辑回归)。

深度学习概念

人工神经网络是一个分层的有向图,第一层输入节点接受输入的信息,也称为输入层。来自这些点的数值按照它们输出的弧的权重(wn),进行线性加权(得到G),然后再做一次函数变化f(G),赋给第二层的节点Y。
第二层的节点照此将数值向后传递,直到第三层节点,如此一层层传递,直到最后一层,最后一层又被称为输出层。在模式分类时,一个模式(图像、语音、文字等)的特征值(比如坐标),从输入层开始,按照上面的规则和公式一层层向后传递。最后在输出层,哪个节点的数值最大,输入的模式就被分在了哪一类。
------------------引自《数学之美—Google大脑和人工神经网络》

深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第6张图片

深度学习优势

神经网络与传统的机器学习相比:

  • 能支持更复杂的分类边界
  • 非线性表征更加丰富
  • 准确率会随着数据集的增加而突破传统学习的瓶颈
  • 与svm相比,在大数据集上收敛的更快
  • 轻量级神经网络具备高性能的前向传播,方便部署到移动设备
    深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第7张图片

深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第8张图片

深度学习基础知识

参考:https://www.cnblogs.com/wj-1314/p/9754072.html

感知机

可以简单的理解为是线性分类。假设训练数据集是线性可分的,感知机学习的目标是求得一个能够将训练数据集正实例点和负实例点完全正确分开的分离超平面。
深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第9张图片
感知机重点包含以下两点:

  • 线性加权
  • 依靠损失函数进行权重优化

数学公式略,将在其他博文中进行阐述。

感知机的缺陷:只支持线性分类,对于简单的异或问题也不能进行分类。以下是异或问题中最简单的情况,可以看到无论哪一条直线都不能进行完美的分割。
深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第10张图片

激活函数

针对于感知机不能表达非线性的问题,激活函数诞生了。

在人工神经网络中,规定神经元函数只能对输入变量(指向他的节点的值)线性组合后的结果进行一次非线性变换。
这次非线性变化成为“激活函数”
----《数学之美》

为了神经网络的通用性,每一层的非线性变化都选择同一类函数。
激活函数包括:

  • relu
  • sigmoid
  • tanh
  • 等等

激活函数参考博客:https://blog.csdn.net/tyhj_sf/article/details/79932893
深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第11张图片

多层感知机

多层感知机(MLP,Multilayer Perceptron)也叫人工神经网络(ANN,Artificial Neural Network),除了输入输出层,它中间可以有多个隐层,最简单的MLP只含一个隐层,即三层的结构
深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第12张图片

  • 输入层,输入特征数据等加工或者没有加工过的原始数据
  • 隐含层,隐含层可以很多,resnet有128层的,就是说的隐含层
  • 输出层,输出最后的计算结果,很多神经网络里面都把输出层定义为概率值

多层感知机等同于全连接层,信息每向下传递一个神经元,都会产生n*n的计算量(计算量会随着输入的维度增大而变得非常恐怖)

卷积神经网络

卷积神经网络是近年发展起来的,并引起广泛重视的一种高效识别方法,20世纪60年代,Hubel和Wiesel在研究猫脑皮层中用于局部敏感和方向选择的神经元时发现其独特的网络结构可以有效地降低反馈神经网络的复杂性,继而提出了卷积神经网络(Convolutional Neural Networks-简称CNN)

参考资料:https://www.cnblogs.com/wj-1314/p/9754072.html

卷积的原理与人眼观察事物极其相似,过程都是边缘 -> 局部 -> 整体。卷积神经网络的核心就是使用多个局部特征来影响分类结果。
深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第13张图片
全连接的计算量非常大。而且是以整体来计算,没有进行有效的特征提取,即使权重最终达到了收敛效果,也不能很好的进行预测。
卷积神经网络则不同,每次卷积完毕后,传入下一层的数据大大降低了维度,而且经过卷积,获得了众多局部特征,后面的层对这些特征数据进行训练,将变得既简单又高效。

卷积层

简单来说,卷积层用于特征提取。
深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第14张图片
根据卷积核的滑动,获取到一个新的特征数据(Convolved Feature)。这个特征数据不是那么直观,来看一下实物的效果。

针对于不同的通道(rgb)进行卷积后,会得到边缘轮廓的图。

池化层

池化层用于降低参数,而降低参数的方法当然是删除参数,保留最有效的参数。

一般我们有最大池化和平均池化。

  • 最大池化是现在使用最多的,可以突出局部特征
  • 平均池化则考虑了所有参数,而计算出了平均值

需要注意的是,池化层一般放在卷积层后面。所以池化层池化的是卷积层的输出。

模型训练

本博客重点关注有监督的训练。在训练之前需要有一批标注好的数据,即训练数据。为了能在训练过程中动态的观测模型的准确率,同样也需要一批标注数据(推荐为训练数据/测试数据比例为4/1)

前向传播

深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第15张图片
前向传播,即训练数据在神经网络里从输入层到输出层的方向传播一次,最终得到输出层的输出结果,即在每个分类的概率值。

反向传播与参数优化

用数据语言来表达:假设C为一个成本函数(Cost Function),它表示根据人工神经网络的输出值(分类结果概率)和实际训练数据中的输出值之间的差距。现在,训练人工神经网络的问题就变成了一个最优化的问题,说的通俗点就是数学中的“找最大(最小)值”的问题。解决最优化为题的常用方法是梯度下降法(Gradient Descent)
深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第16张图片
注:这里存在一个局部最优解的问题,不过已经被证明:在深度神经网络中,即使收敛过程进入了局部最优,最终结果也与全局最优没有明显差异。

深度学习服务端框架

深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第17张图片

tensorFlow

2015年11月谷歌(Google)出品,基于Python和C++编写。GitHub上最热,谷歌搜索最多,使用人数最多(笔者也是其中之一),大多数网上招聘工作描述中也提到了它。由于Google在深度学习领域的巨大影响力和强大的推广能力,TensorFlow一经推出就获得了极大的关注,并迅速成为如今用户最多的深度学习框架。2019年3月已发布最新的TensorFlow2.0 版本。

官方网站:https://www.tensorflow.org/
优点:

  • 自带tensorboard可视化工具,能够让用户实时监控观察训练过程深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第18张图片
  • 拥有大量的开发者,有详细的说明文档、可查询资料多
  • 支持多GPU、分布式训练,跨平台运行能力强
  • 具备不局限于深度学习的多种用途,还有支持强化学习和其他算法的工具

缺点:

  • 频繁变动的接口。TensorFlow的接口一直处于快速迭代之中,并且没有很好地考虑向后兼容性,这导致现在许多开源代码已经无法在新版的TensorFlow上运行,同时也间接导致了许多基于TensorFlow的第三方框架出现BUG
  • 接口设计过于晦涩难懂,在设计TensorFlow时,创造了图、会话、命名空间、PlaceHolder等诸多抽象概念,对初学者来说较难上手
  • 运行明显比其他框架速度慢

keras

Keras 于2015年3月首次发布,拥有“为人类而不是机器设计的API”,得到Google的支持。它是一个用于快速构建深度学习原型的高层神经网络库,由纯Python编写而成,以TensorFlow,CNTK,Theano和MXNet为底层引擎,提供简单易用的API接口,能够极大地减少一般应用下用户的工作量。
如果你是深度学习的初学者,想要快速入门,建议从Keras开始。
官方网站:https://keras.io

优点:

  • 更简洁,更简单的API
  • 丰富的教程和可重复使用的代码
  • 更多的部署选项(直接并且通过TensorFlow后端),更简单的模型导出

缺点:

  • 过度封装导致丧失灵活性,导致用户在新增操作或是获取底层的数据信息时过于困难
  • 初学者容易依赖于 Keras 的易使用性而忽略底层原理

pytorch

PyTorch于2016年10月发布,是一款专注于直接处理数组表达式的低级API。 前身是 Torch(一个基于 Lua 语言的深度学习库)。Facebook 人工智能研究院对PyTorch提供了强力支持。 PyTorch 支持动态计算图,为更具数学倾向的用户提供了更低层次的方法和更多的灵活性,目前许多新发表的论文都采用PyTorch作为论文实现的工具,成为学术研究的首选解决方案。

如果你是一名科研工作者,倾向于理解你的模型真正在做什么,那么就考虑选择PyTorch。

官方网站:https://pytorch.org/

Caffe/Caffe2.0

Caffe的全称是Convolutional Architecture for Fast Feature Embedding,它是一个清晰、高效的深度学习框架,于2013年底由加州大学伯克利分校开发,核心语言是C++。它支持命令行、Python和MATLAB接口。Caffe的一个重要特色是可以在不编写代码的情况下训练和部署模型。

具体介绍见下文。

caffe框架

为何选择caffe

我们暂时先选择caffe框架作为分享目标,原因如下:

  • 与ncnn的兼容性好(最重点)
  • 不需要写代码就可以实现训练(可以作为深度学习的突破口)
  • 支持python接口,可以丰富编程化实现
  • 丰富的demo实现等

caffe环境搭建

推荐ubuntu系统,参考博客:https://blog.csdn.net/wangjie5540/article/details/97786182
mac系统也可搭建,参考博客:https://blog.csdn.net/wangjie5540/article/details/99571832

caffe使用了众多的依赖库,再加上caffe年久失修,出现编译兼容问题也不奇怪。推荐大家在ubuntu上进行编译,可以驱动gpu,mac的最新14.14不支持n卡,据说需要降到14.13才可以。

caffe基础

针对于神经网络的模型,caffe设计了对应的概念。并且使用caffe来训练模型的过程非常简单,甚至都不用写一行代码,仅仅改改配置文件也同样能直接开始训练(当然,用python去写训练过程的话,会更加的灵活)。

数据集

  • 原始数据,本文主要针对的是图片数据,可能有不同的格式(image格式、bytes格式、lmdb格式等)
  • 标注数据,监督学习,必须进行标注

caffe倾向于先把数据集转化成lmdb或者hdf5格式,然后输入神经网络进行训练。

模块概要图

深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第19张图片
概要:

  • 使用数据构建脚本,构建训练数据和测试数据
  • caffe train命令加载solver的prototxt配置
  • solver配置加载神经网络配置
  • 神经网络对接训练数据和测试数据
  • 成千上万次迭代,最终按照solver中的配置策略,周期性生成权重模型文件

solver(prototxt) 执行者配置

超参数配置文件。
超参数的概念如下:

在机器学习的上下文中,超参数是在开始学习过程之前设置值的参数,而不是通过训练得到的参数数据。通常情况下,需要对超参数进行优化,给学习机选择一组最优超参数,以提高学习的性能和效果

神经网络可视化

http://ethereon.github.io/netscope/#/editor
下面是对lenet的可视化,可以清楚的看到lenet的全貌。

  • mnist数据输入
  • conv1,第一次卷积层
  • pool1,第一池化层
  • conv2,第二次卷积层
  • pool2,第二次池化层
  • ip1,全连接层(即多层感知机)
  • relu1,激活层
  • ip2,全连接层
  • loss,损失层(同时激发bn反向传播操作)
    深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第20张图片

caffe中的基础概念

blobs

  • 对待处理数据带一层封装用于在Caffe中通信传递
  • 也为CPU和GPU间提供同步能力
  • 数学上,是一个N维的C风格的存储数组

总的来说,Caffe使用Blob来交流数据,其是Caffe中标准的数组与统一的内存接口,它是多功能的,在不同的应用场景具有不同的含义,如可以是:batches of images, model parameters, and derivatives for optimization等
作者:沤江一流
链接:https://www.jianshu.com/p/0ac09c3ffec0

layer 神经层

layer是caffe神经网络的基本组成单元。layer包括不同的种类:

  • Data,也就是blob的层
  • Convolution,卷积层
  • Pooling,池化层
  • InnerProduct,全连接
  • SoftmaxWithLoss,激活函数+loss层

不同的层次对应了神经网络中的不通过概念。另外,每种类型的层在caffe的源码中有特定的实现,之后会在其他博客中展开讨论,这里不再赘述。

net 神经网络

net是指神经网络定义,可以认为是layer的总和。在python版本编程中会出现net的概念。

forward/backward 前向传播/反向传播

forward和backward在python编程版本中会出现,手动执行会触发一次前向传播或反向传播(python实现的caffe训练最终的本质是在循环中每次手动触发forward函数,重点看一下本博客的caffe+mnist的python实现注释版)。

caffe+mnist数据集+lenet

参考博客:https://blog.csdn.net/wangjie5540/article/details/98615226
python实现mnist(注释版):https://gitee.com/simple_projects/caffe_learning/blob/master/01-learning-lenet-mine.ipynb

caffe+cifar10+caffenet

非常类似mnist数据集,参考:https://blog.csdn.net/wangjie5540/article/details/98615226

caffe+cifar10+mobilenet

参考:https://github.com/shicai/MobileNet-Caffe.git
shicai的mobilenet提供了预训练模型,可以直接进行数据预测。
深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第21张图片
大家肯定想,预训练模型没什么意思,要自己训练才来实际。
参考:https://blog.csdn.net/lwplwf/article/details/82415525,可以使用cifar10进行模型训练。
(ps,作者用cpu训练了几天,最终迭代了19w次,最终准确率在70%,没有达到很好的收敛效果。之后准备好gpu的机器,还会再次训练,以观后效)

注:cifar10的数据集进行模型训练的时候,出现mean的概念(即均值,rgb每个通道上的像素的平均值)。这样做的目的是让个像素的值以0为对称点进行均匀分布,训练过程更容易收敛。有两种获取均值的方法:

  • 以数据集为目标,把每个通道上的像素值全部加和,然后求平均(caffe的cifar10就是使用的这种方法)
  • 直接使用均值(128,128,128),简单暴力。(mobilenet+ssd的训练过程中就是这么做的,最终也能收敛)

以上两种方法,暂时没有证实哪个效果最好。

caffe+voc2012+vgg(finetune)+ssd(物体检测模型)

参考:https://github.com/weiliu89/caffe.git
voc的数据集需要在外网下载,时间要好久好久。。我已经把这些数据都下载完毕,上传到云盘。以下是下载地址:https://download.csdn.net/download/wangjie5540/11598810
由于本次是迁移训练,预训练模型是vggnet,还需要下载vggnet,地址是:https://download.csdn.net/download/wangjie5540/11603902

注:博主用cpu训练跑了两天,还没有跑到第一次的快照地点。如果想自己训练的话,就选gpu的机器吧。

轻量级客户端框架-ncnn

ncnn简介

git地址:https://github.com/Tencent/ncnn
ncnn 是一个为手机端极致优化的高性能神经网络前向计算框架。ncnn 从设计之初深刻考虑手机端的部署和使用。无第三方依赖,跨平台,手机端 cpu 的速度快于目前所有已知的开源框架。基于 ncnn,开发者能够将深度学习算法轻松移植到手机端高效执行,开发出人工智能 APP,将 AI 带到你的指尖。ncnn 目前已在腾讯多款应用中使用,如 QQ,Qzone,微信,天天P图等。

支持大部分常用的 CNN 网络

  • Classical CNN: VGG AlexNet GoogleNet Inception …
  • Practical CNN: ResNet DenseNet SENet FPN …
  • Light-weight CNN: SqueezeNet MobileNetV1/V2/V3 ShuffleNetV1/V2 MNasNet …
  • Detection: MTCNN facedetection …
  • Detection: VGG-SSD MobileNet-SSD SqueezeNet-SSD MobileNetV2-SSDLite …
  • Detection: Faster-RCNN R-FCN …
  • Detection: YOLOV2 YOLOV3 MobileNet-YOLOV3 …
  • Segmentation: FCN PSPNet UNet …

ncnn+caffe+mobilenet实战

ncnn环境搭建

先下载release版本的ncnn,我这里现在ncnn-20190611

$ cd 
$ mkdir -p build-android-armv7
$ cd build-android-armv7

$ cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
    -DANDROID_ABI="armeabi-v7a" -DANDROID_ARM_NEON=ON \
    -DANDROID_PLATFORM=android-14 ..

# if you want to enable vulkan, platform api version >= android-24 is needed
$ cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
    -DANDROID_ABI="armeabi-v7a" -DANDROID_ARM_NEON=ON \
    -DANDROID_PLATFORM=android-24 -DNCNN_VULKAN=ON ..

$ make -j4
$ make install

pick build-android-armv7/install folder for further jni usage

编译完成后,生成以下文件
深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第22张图片
支持库和头文件供android的arm-v7a使用

模型转化(caffe格式-> ncnn格式)

首先需要编译caffe的环境。
参考:
https://blog.csdn.net/wangjie5540/article/details/97786182
https://blog.csdn.net/wangjie5540/article/details/99571832

源码解析

文件目录

├── README.md
├── app
│   ├── build.gradle // android工程配置
│   ├── proguard-rules.pro // 混淆配置
│   └── src
│       ├── androidTest
│       │   └── java
│       │       └── com
│       │           └── ztjy
│       │               └── ncnndemo
│       │                   └── ExampleInstrumentedTest.java
│       ├── main
│       │   ├── AndroidManifest.xml
│       │   ├── assets
│       │   │   ├── mobilenet_v2.bin // mobilenet权重文件
│       │   │   ├── mobilenet_v2.param.bin // 神经网络参数文件
│       │   │   └── synset.txt // 分类索引文件
│       │   ├── cpp
│       │   │   ├── CMakeLists.txt
│       │   │   ├── include // ncnn的头文件
│       │   │   │   ├── allocator.h
│       │   │   │   ├── benchmark.h
│       │   │   │   ├── blob.h
│       │   │   │   ├── caffe.pb.h
│       │   │   │   ├── command.h
│       │   │   │   ├── cpu.h
│       │   │   │   ├── gpu.h
│       │   │   │   ├── layer.h
│       │   │   │   ├── layer_type.h
│       │   │   │   ├── layer_type_enum.h
│       │   │   │   ├── mat.h
│       │   │   │   ├── mobilenet_v2.id.h
│       │   │   │   ├── mobilenet_v2.mem.h
│       │   │   │   ├── modelbin.h
│       │   │   │   ├── net.h
│       │   │   │   ├── opencv.h
│       │   │   │   ├── option.h
│       │   │   │   ├── paramdict.h
│       │   │   │   ├── pipeline.h
│       │   │   │   └── platform.h
│       │   │   ├── jniLibs
│       │   │   │   └── armeabi-v7a
│       │   │   │       └── libncnn.a // ncnn静态库
│       │   │   └── native-lib.cpp
│       │   ├── java
│       │   │   └── com
│       │   │       └── ztjy
│       │   │           └── ncnndemo
│       │   │               ├── MainActivity.java // 主窗体
│       │   │               ├── NcnnJni.java // jni交互文件
│       │   │               └── PhotoUtil.java // 图片工具文类(从相册中取文件)
│       │   └── res
│       │       ├── drawable
│       │       │   └── ic_launcher_background.xml
│       │       ├── drawable-v24
│       │       │   └── ic_launcher_foreground.xml
│       │       ├── layout
│       │       │   └── activity_main.xml
│       │       ├── mipmap-anydpi-v26
│       │       │   ├── ic_launcher.xml
│       │       │   └── ic_launcher_round.xml
│       │       ├── mipmap-hdpi
│       │       │   ├── ic_launcher.png
│       │       │   └── ic_launcher_round.png
│       │       ├── mipmap-mdpi
│       │       │   ├── ic_launcher.png
│       │       │   └── ic_launcher_round.png
│       │       ├── mipmap-xhdpi
│       │       │   ├── ic_launcher.png
│       │       │   └── ic_launcher_round.png
│       │       ├── mipmap-xxhdpi
│       │       │   ├── ic_launcher.png
│       │       │   └── ic_launcher_round.png
│       │       ├── mipmap-xxxhdpi
│       │       │   ├── ic_launcher.png
│       │       │   └── ic_launcher_round.png
│       │       └── values
│       │           ├── colors.xml
│       │           ├── strings.xml
│       │           └── styles.xml
│       └── test
│           └── java
│               └── com
│                   └── ztjy
│                       └── ncnndemo
│                           └── ExampleUnitTest.java
├── build.gradle
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle

执行流程

https://www.processon.com/view/link/5d5cfe08e4b08b95b82695bb
深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第23张图片

重点代码

java层代码

//  predict image
    private void predict_image(String image_path) {
     
        // picture to float array
        Bitmap bmp = PhotoUtil.getScaleBitmap(image_path);
        Bitmap rgba = bmp.copy(Bitmap.Config.ARGB_8888, true);

        // resize to 227x227
        Bitmap input_bmp = Bitmap.createScaledBitmap(rgba, ddims[2], ddims[3], false);
        try {
     
            // Data format conversion takes too long
            // Log.d("inputData", Arrays.toString(inputData));
            long start = System.currentTimeMillis();
            // get predict result(调用jni层代码,进行预测)
            float[] result = squeezencnn.detect(input_bmp);
            long end = System.currentTimeMillis();
            Log.d(TAG, "origin predict result:" + Arrays.toString(result));
            long time = end - start;
            Log.d(TAG, String.valueOf(result.length));
            // show predict result and time
            int r = get_max_result(result);
            Log.d(TAG, r + "");
            Log.d(TAG, resultLabel.toString());
            Log.d(TAG, resultLabel.get(r));
            Log.d(TAG, result[r] + "");
            Log.d(TAG, time + "");

            String show_text = "result:" + r + ",name:" + resultLabel.get(r) + "\nprobability:" + result[r] + "\ntime:" + time + "ms";
            Log.d(TAG, show_text);
            result_text.setText(show_text);
        } catch (Exception e) {
     
            e.printStackTrace();
        }
    }

jni层代码

// public native String Detect(Bitmap bitmap);
JNIEXPORT jfloatArray JNICALL
Java_com_ztjy_ncnndemo_NcnnJni_detect(JNIEnv *env, jobject thiz, jobject bitmap) {
     
    // ncnn from bitmap
    ncnn::Mat in;
    {
     
        AndroidBitmapInfo info;
        // 获取位图信息
        AndroidBitmap_getInfo(env, bitmap, &info);
        // 获取位图宽高
        int width = info.width;
        int height = info.height;
        // demo只支持rgba格式的图片
        if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888)
            return NULL;

        void *indata;
        AndroidBitmap_lockPixels(env, bitmap, &indata);
        // 把像素转换成data,并指定通道顺序
        in = ncnn::Mat::from_pixels((const unsigned char *) indata, ncnn::Mat::PIXEL_RGBA2BGR,
                                    width, height);

        AndroidBitmap_unlockPixels(env, bitmap);
    }

    // ncnn_net
    // 
    std::vector<float> cls_scores;
    {
     
        // 减去均值和乘上比例(来源与caffe神经网络的配置文件,即prototxt文件)
        const float mean_vals[3] = {
     103.94f, 116.78f, 123.68f};
        const float scale[3] = {
     0.017f, 0.017f, 0.017f};
		// 设置均值与标准化参数
        in.substract_mean_normalize(mean_vals, scale);
		// 创建ncnn前向传播的结果提取器
        ncnn::Extractor ex = ncnn_net.create_extractor();
        // 如果不加密使用ex.input("data", in);
        ex.input(mobilenet_v2_param_id::BLOB_data, in);

        ncnn::Mat out;
        // 如果不加密是使用ex.extract("prob", out);
        ex.extract(mobilenet_v2_param_id::BLOB_prob, out);

        int output_size = out.w;
        jfloat *output[output_size];
        for (int j = 0; j < out.w; j++) {
     
            output[j] = &out[j];
        }
		// 获取结果预测结果,并返回给android层
        jfloatArray jOutputData = env->NewFloatArray(output_size);
        if (jOutputData == nullptr) return nullptr;
        env->SetFloatArrayRegion(jOutputData, 0, output_size,
                                 reinterpret_cast<const jfloat *>(*output));  // copy

        return jOutputData;
    }
}

效果展示

caffe+mobilenet分类
深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第24张图片

其他工程的效果图

https://github.com/chehongshu/ncnnforandroid_objectiondetection_Mobilenetssd.git
ncnn+mobilenet-ssd
深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第25张图片
深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第26张图片
深度学习-服务端训练+android客户端物体识别实战(caffe+mobilenet+ncnn+android)_第27张图片

相关学习资料

教学视频

唐宇迪-深度学习Caffe框架入门视频课程:https://edu.csdn.net/course/detail/3506
会写代码的好厨师-Caffe实战入门:https://www.imooc.com/learn/1040

开源项目

caffe官网:https://github.com/BVLC/caffe
ncnn:https://github.com/Tencent/ncnn.git
ncnn+mobilenet-ssd:https://github.com/chehongshu/ncnnforandroid_objectiondetection_Mobilenetssd
shicai_mobilenet:https://github.com/shicai/MobileNet-Caffe.git
weiliu89:https://github.com/weiliu89/caffe.git(需要check_out到ssd分支)

参考博客

在Android手机上使用腾讯的ncnn实现图像分类:
https://blog.csdn.net/qq_33200967/article/details/82421089

你可能感兴趣的:(机器学习,#,caffe,深度学习,caffe,ncnn,实战)