Caffe2 使用预训练模型进行预测

介绍

深度学习是当下主流的人工智能实现方法。互联网公司都在积极的拥抱AITensorflowCaffeCaffe2MXNetTorch各种框架百家争鸣,
作为Facebook粉今天要讲述的是2017年4月份发布的深度学习框架Caffe2。
并且这篇文章以 “使用预训练模型进行预判” 的角度进行描述。

几个问题

1. 为什么深度学习选择GPU?

简单来说GPU的硬件设计更适合密集型计算。
那么5000RMBi7 7700K5000RMBGTX 1080同样的价格为什么都说GPU比CPU快呢?原因有二:
GPU有多个内存单元,而GPU位宽为所有内存单元的和,这就保证了GTX 1080360GB/s的数据吞吐量。
GTX10802560个流处理器和独立的寄存器,可以独立计算这就保证了处理速度。
CPU是跑车,GPU时候卡车,如果拉大批货物的话,卡车当然是首选。

2. 为什么选择NVIDIA?

NVIDIA的标准库非常容易在CUDA中建立第一个深度学习库,并且NVIDIA在深度学习领域做了很多工作cuDNN加速库支持。
反观AMD的只有OpenCL并没有NVIDIA这样强大的标准库。

3. 手机使用什么?

大部分是用CPUGPU性能不如CPU(想象GPU本来要负责2K图形的渲染,已经很累了)
但是有些公司对GPUOpenCL进行优化,但是速度还是和CPU有一定差距。

手机CPU优化

1. NNPACK

NNPACK由facebook开发,是一个加速神经网络计算的加速包,NNPACK可以在多核CPU平台上提高卷积层计算性能。NNPACK采用的快速卷积算法是基于Fourier transform 和 Winograd transform算法。
Caffe2 NNPACK 的实现在IPhone 6s的设备上胜过苹果自己的MPSCNNConvolution(卷积)。

2. ARM neon

这是一个单指令,多数据的指令集(技术),可以一次将多个操作数打包到源寄存器。比如一个加法运算未优化前,一次只能从内存取一个操作数。很多音视频,多媒体处理项目都支持neon优化,比如FFmpeg。目前ARM主流CPU都支持,并且提供了指令集的C++接口。

Caffe2

Caffe之死

Caffe始于2013年。是第一个主流工业级深度学习工具,作者是贾扬清,一位看起来非常年轻的伯克利博士。Caffe由他和BAIRBVLC,开源社区共同贡献。也正是因为第一个,所以被后浪(TensorFlow)拍死到了沙滩上,此刻默哀三分钟(如果你还在用,就当我没说...)。Caffe有着优秀的卷积神经网络实现,并且速度一直得到大家的肯定,但是不支持集群,对循环神经网络和递归神经网络支持很差。就注定了被TensorFlow等其他框架蚕食。

新的Caffe2

2017年4月份Facebook发布了Caffe2,最大的特点是速度快和移动平台良好的支持,并提供了pyhtonC++语言接口。 与1.0的不同:

1. 支持大规模集群训练
2. 支持移动平台部署
3. 新硬件支持(除了`CUP`和`CUDA`之外还有新硬件)
4. flexibility for future directions such as quantized computation
5. stress tested by the vast scale of Facebook applications

应用

使用Caffe2在Mobile设备上进行实时“风格迁移”,在一些手机上能在50ms内完成AI处理(推断)。

Facebook实时风格迁移效果

1到2的迁移

image

Caffe2提供最小的处理单位是Operator,他可以表示一个数学函数,一个网络类型,一个激活函数等等,
Caffe2并且提供了400多个不同给开发者使用。

Operators Catalogue

发现之旅

1. 安装

sudo apt-get install g++
sudo apt-get install automake libtool
git clone --recursive https://github.com/caffe2/caffe2.git
cd caffe2 
./scripts/build_android.sh

或者./scripts/build_ios.sh

2. 数据结构

  • Blob:存储数据
  • Operator:输入blob,输出blob,定义了计算规则
  • Nets : 由多个operator组合实现
  • Workspace:可以理解成变量的空间,便于管理网络和变量

3. 加载预训练模型

下载模型

python -m caffe2.python.models.download -i squeezenet

在命令行中,使用一个caffe2中定义的下载模块去下载一个预训练好的模型。
当下载完成时,在caffe2/python/model底下有一个squeezenet文件,
文件夹底下有两个文件init_net.pb,predict_net.pb分别保存了权值和网络定义。

我们使用workspace来存放这个模型的网络定义和权重,并且把它们加载到blob、init_netpredict_net。我们需要使用一个workspace.Predictor来接收两个protobuf,然后剩下的就可以交给caffe2了。

步骤(Python描述)

  1. 读入protobuf文件
 with open("init_net.pb") as f:
     init_net = f.read()
 with open("predict_net.pb") as f:
     predict_net = f.read()
  1. 使用workspace中的Predictor来加载从protobuf中取到的blobs
 p = workspace.Predictor(init_net, predict_net)
  1. 运行网络,得到结果:
 results = p.run([img])

需要注意的这里的img是预处理过的图像。

4. AICamera

这里看一下Caffe2提供的Android平台Demo,因为是Android,只能使用C++语言进行操作。
AICamera Demo主要是使用CNN预训练好的SqueezeNet模型对Camera实时捕捉的画面中的物体进行分类。

代码很简单,涉及到一个JavaClassifyCamera和一个C++native-lib.cpp文件。

ClassifyCamera Class

public native void initCaffe2(AssetManager mgr);

public native String classificationFromCaffe2(int h, int w, byte[] Y, byte[] U, byte[] V,
                                              int rowStride, int pixelStride, boolean r_hwc);

这个类继承自Activity并提供了两个Native方法:一个负责预训练库的初始化,一个负责将图像数据做为输入进行预判。主要功能使用三面三步进行概括:

  1. 在页面onCreate的时候调用initCaffe2方法初始化库、摄像头、View
  2. 摄像头通过TextureView进行预览(Camera关联TextureViewsurface,使用OpenGL接口进行加速预览)。
  3. 在摄像头实时数据回调接口中,调用classificationFromCaffe2方法对捕捉的图像进行分类预判,并将返回结果显示到界面上。

现在你只要知道ClassifyCamera类大概的用途就行了,这不是重点,下面我们看native-lib.cpp文件。

native-lib.cpp

这个文件主要对模型库进行加载和预判,按从Activity调用的顺序可以分为下列步骤:

  • 初始化方法
    1. Java_facebook_f8demo_ClassifyCamera_initCaffe2这接口在页面创建的时候被调用了,它调用loadToNetDef,从asset目录加载squeeze_init_net.pb模型权重文件,squeeze_predict_net.pb模型网络结构文件。
    2. 并把他们赋值给caffe2::NetDef _initNet, _predictNet,最终放到Blob_predictor = new caffe2::Predictor(_initNet, _predictNet);
  • 对输入进行预判方法
    1. Java_facebook_f8demo_ClassifyCamera_classificationFromCaffe2这个方法对采集的数据进行预处理(模型训练和预判都需要对数据进行预处理)首先将摄像头采集的YUV数据转换为BGR数据并使用均值(网络训练时数据集图像的均值)对预处理图像进行均值化处理,处理结果保存在input_data[MAX_DATA_SIZE]数组中。
    2. 图像预处理完成之后使用caffe2::TensorCPU input创建输入源对象,并将图像数据进行关联memcpy(input.mutable_data<float>(), input_data, IMG_H * IMG_W * IMG_C * sizeof(float));
    3. 调用_predictor->run,给样本输入,得到分类输出output_vec
      caffe2::Predictor::TensorVector input_vec{&input};
      caffe2::Predictor::TensorVector output_vec;
      _predictor->run(input_vec, &output_vec);
    4. 最终处理输出结果output_vec,根据预判准确率对结果进行排序,通过imagenet_classes[max_index[j]]从模型训练时的结果集取分类信息。

    训练方法分为有监督学习和无监督学习,有监督学习指训练集有样本输入和对应的结果输出,
    如要预判某程序员的工资,那么有监督学习数据集的输入是年龄,职级,公司等特征,结果是对应准确薪资。

模型训练

这里使用CNNModelHelper帮助我们用最少的代码创建一个全连接的神经网络。

# Create the input data
data = np.random.rand(16, 100).astype(np.float32)

# Create labels for the data as integers [0, 9].
label = (np.random.rand(16) * 10).astype(np.int32)

workspace.FeedBlob("data", data)
workspace.FeedBlob("label", label)

# Create model using a model helper
m = cnn.CNNModelHelper(name="my first net")
fc_1 = m.FC("data", "fc1", dim_in=100, dim_out=10)
pred = m.Sigmoid(fc_1, "pred")
[softmax, loss] = m.SoftmaxWithLoss([pred, "label"], ["softmax", "loss"])

输出

name: "my first net"
op {
  input: "data"
  input: "fc1_w"
  input: "fc1_b"
  output: "fc1"
  name: ""
  type: "FC"
}
op {
  input: "fc1"
  output: "pred"
  name: ""
  type: "Sigmoid"
}
op {
  input: "pred"
  input: "label"
  output: "softmax"
  output: "loss"
  name: ""
  type: "SoftmaxWithLoss"
}
external_input: "data"
external_input: "fc1_w"
external_input: "fc1_b"

关于Operator,Nets更详细的操作和训练网络创建方式请参考官方文档
Basics of Caffe2 - Workspaces, Operators, and Nets
部分的描述。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

返回主页看更多
狠狠的抽打博主 支付宝 扫一扫