欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

实践介绍深度学习和Caffe与Python

程序员文章站 2022-03-30 19:25:12
...

实践介绍深度学习和Caffe与Python

作者:

Adil Moujahid

译者:

gashero

日期:

2016-10-28

地址:

http://adilmoujahid.com/posts/2016/06/introduction-deep-learning-python-caffe/

标题原文:

A Practical Introduction to Deep Learning with Caffe and Python

目录

  • 1   问题定义
  • 2   分类:使用传统机器学习vs深度学习
  • 3   深度学习快速教程
    • 3.1   人工神经网络ANN
      • 3.1.1   人工神经网络vs生物神经网络
      • 3.1.2   前馈神经网络
      • 3.1.3   激活函数
      • 3.1.4   训练ANN
    • 3.2   卷积神经网络(CNN或ConvNet)
      • 3.2.1   卷积层
      • 3.2.2   汇集层
      • 3.2.3   CNN架构
  • 4   使用CNN构建猫狗分类器
    • 4.1   获取猫狗数据
    • 4.2   机器设置
    • 4.3   Caffe概览
    • 4.4   数据准备
    • 4.5   模型定义
    • 4.6   Solver定义
    • 4.7   模型训练
      • 4.7.1   绘制学习曲线
    • 4.8   在新数据上的预测
  • 5   使用Transfer Learning构建猫狗分类器
    • 5.1   什么是Transfer Learning
    • 5.2   使用Transfer Learning训练猫狗分类器
      • 5.2.1   下载bvlc_reference_caffenet模型
      • 5.2.2   模型定义
      • 5.2.3   Solver定义
      • 5.2.4   通过传输学习训练模型
      • 5.2.5   绘制学习曲线
      • 5.2.6   在新数据上的预测
  • 6   总结

深度学习是机器学习的大趋势。在计算机视觉、自动语音识别、自然语言处理上有很多成功案例。

本文的目的是给你个上手简介。基于构建一个猫狗图片分类,使用深度学习算法,叫做卷积神经网络CNN和Kaggle数据集( https://www.kaggle.com/c/dogs-vs-cats )。

本文分为两个部分。第一部分是代码概念,第二部分是上手入门。

在第4节上手入门,我们会构建一个猫狗图片分类器使用一个CNN。在第二部分(第5节),我们会用更高级的技术来训练CNN,叫做Transfer Learning。我们会使用一些Python代码和流行的开源深度学习框架Caffe来构建分类器。我们的分类器会实现97%的准确度。

本文末尾,你会理解CNN的原理,并熟悉构建这些网络的步骤。

本文的代码在 https://github.com/adilmoujahid/deeplearning-cats-dogs-tutorial

1   问题定义

本入门使用Kaggle的数据集。包含了25000张图片,有猫和狗。

目标是构建机器学习算法来检测新的图片。

机器学习中,这类问题叫 分类(classification)

2   分类:使用传统机器学习vs深度学习

机器学习来进行分类有两个阶段:

  1. 训练阶段:训练一个机器学习算法,使用有对应标签的数据集
  2. 预测阶段:使用训练过的模型来预测(predict)新图片的标签

图片分类的训练阶段有两个主要步骤:

  1. 特征提取(Feature Extraction):使用领域知识来提取新的特征,用于机器学习算法,HoG和SIFT是图片分类的例子
  2. 模型训练:使用干净的数据集,包括图片的特征和对应的标签来训练机器学习模型

在预测阶段,我们使用相同的特征提取器来处理新图片,并传入这些特征到训练过的机器学习算法来预测标签。

 

传统机器学习和深度学习算法的区别是特征工程(Feature Engineering)。传统机器学习算法,需要手工设计特征。相对的在深度学习中,特征的设计由算法自动完成。特征工程很困难,消耗时间和领域知识。深度学习的优势是无需特征工程就能做到更好的准确率。

 

3   深度学习快速教程

深度学习是很多处理层构成的人工神经网络(ANN=Artificial Neural Networks)。ANN存在了几十年,但是对训练深度架构的ANN是从Geoffrey Hinton开始的,在2000年中期。除了算法创新,GPU的强大计算能力和大量的数据集都帮助了深度学习的迅速成长。

3.1   人工神经网络ANN

ANN是一系列模仿生物神经网络的模型。

3.1.1   人工神经网络vs生物神经网络

生物神经网络是大脑的核心。一个神经元(neuron)由细胞体、树突(dendrite)、轴突(axon)构成。会处理和传输信息到其他神经元,通过发射电信号。每个神经元从树突接受输入信号并通过轴突产生输出信号。轴突的分支输出,通过突触(synapse)连接到其他神经元的树突。

一个神经元工作的基本模型:每个突触有个强度,是可以被学习和控制的。树突将输入信号带入神经元做求和,如果求和结果高于一定的阈值,神经元就被点亮,通过轴突发送脉冲出去。

人工神经元受到了生物神经元的启发,尝试模拟模型来解释如上计算模式。一个人工神经元拥有数量有限的输入,且没有输入都有一个权重,以及一个激活函数(也叫传输函数)。神经元的输出是激活函数应用了输入权重再求和的结果。人工神经元回想连接,构成了ANN。

 

3.1.2   前馈神经网络

前馈神经网络是ANN最简单的形式。

这个网络由3种类型的层:输入层、隐藏层、输出层。这些网络中,数据从输入层通过隐藏层到达输出层。

下面的例子是全连接前馈神经网络(Fully-Connected FeedForward Neural Network)的例子,有两个隐藏层。全连接意味着每个结点都连接到下一层的所有结点。

注意:隐藏层的数量以及大小是仅有的*参数。更大和更深的隐藏层,理论上就可以得到更加复杂的模式。

 

3.1.3   激活函数

激活函数将输入权重的和转换为人工神经元。这些函数应该是非线性的,来编码复杂的数据模式。最流行的激活函数是Sigmoid、Tanh和ReLU。ReLU是深度学习中最流行的激活函数。

 

3.1.4   训练ANN

训练阶段就是学习网络的权重,我们需要两个元素来训练一个ANN:

  1. 训练数据:训练数据由图片和对应的标签组成
  2. 损失函数:测量预测准确率

一旦我们有了这两个,训练ANN使用的算法叫 backpropagation(反向传播) ,和梯度下降(gradient descent)或者是他的导数。反向传播的细节,推荐 https://mattmazur.com/2015/03/17/a-step-by-step-backpropagation-example/

3.2   卷积神经网络(CNN或ConvNet)

CNN是一种特殊类型的前馈网络。这些模型设计用于模拟视觉皮层(visual cortex)。CNN在视觉识别任务中的效果很好。CNN拥有一些特殊的层叫做卷积层(Convolutional Layer)和汇集层(Pooling Layer),允许网络编码图像属性。

 

3.2.1   卷积层

这个层由一系列可学习的图片空间过滤器组成,计算输入图像和过滤器的点积。过滤器应该扩展为全深度的输入图像。例如,如果我们想要使用5x5大小的过滤器到32x32的彩色图像,那么过滤器应该拥有深度3(5x5x3)来覆盖所有3个颜色通道。这些过滤器会在看到特定图像结构时激活。

 

3.2.2   汇集层

汇集(Pooling)是一种非线性降采样(down-sampling)。汇集层的目标是逐步降低网络计算参数的空间大小,也有避免过拟合(overfitting)。有多种方法实现汇集,但max pooling最常用。汇集通常使用2x2过滤器,通过一个最大2步到每个深度切片。一个汇集层的大小为2x2包含2个缩小输入图像到1/4的原始大小。

 

如上max pooling示例将每个角落中最大的数字作为结果。

3.2.3   CNN架构

最简单的CNN架构,拥有一个输入层(图像),跟着一系列的卷积层和汇集层,最后以全连接层结束。卷积层通常跟着一层ReLU激活函数。

卷积、汇集、ReLU层作为可学习的特征提取器,而全连接层作为机器学习的分类器。此外,靠前的层编码通用的图像模式,后面的层编码图像模式的细节。

注意,不是所有的卷积层和全连接层都拥有权重。这些权重在训练阶段是可学习的。

 

4   使用CNN构建猫狗分类器

本章使用CNN实现一个猫狗分类器。我们会使用Kaggle的数据集。要实现CNN,我们将会使用Caffe框架和一些Python代码。

4.1   获取猫狗数据

要获取数据,需要从 https://www.kaggle.com/c/dogs-vs-cats/data 下载两个数据集, train.ziptest1.zip 。前者是训练数据,后者是未标注的测试数据。我们还可以上传我们的预测结果到Kaggle来获得预测模型的分数。

4.2   机器设置

要训练一个CNN,我们需要有强大GPU的电脑。

本文档里,作者使用了AWS EC2的g2.2xlarge实例。这个实例有高性能的nVidia GPU,有1536个CUDA核心和4GB显存,15GB内存和8个CPU核心。机器的价格是$0.65/h。

如果你对AWS不熟悉,这里有设置的文档 http://cs231n.github.io/aws-tutorial/

注意:文章推荐的AMI已经失效,所以作者准备了一个AMI(ami-64d31209),包含了所有必要的软件。也创建了新的指南 https://github.com/adilmoujahid/deeplearning-cats-dogs-tutorial/blob/master/aws-ec2-setup.md 用以安装Caffe和 Anaconda 到AWS EC2和Ubuntu机器。

在设置AWS实例后,我们连接和clone代码,包含Python代码和Caffe配置。从你的终端执行:

git clone https://github.com/adilmoujahid/deeplearning-cats-dogs-tutorial.git

然后,创建一个input目录用于存储训练和测试数据:

cd deeplearning-cats-dogs-tutorial

mkdir input

4.3   Caffe概览

Caffe是BVLC=Berkeley Vision and Learning Center开发的框架,以C++编写,有Python和Matlab绑定。

使用Caffe训练CNN有4个步骤:

  1. 数据准备:清理图片并存储到Caffe可用的格式,我们使用Python会处理图片预处理和存储
  2. 模型定义:选择CNN架构并定义其参数到配置文件.prototxt
  3. Solver定义:Solver对应的是模型优化器,我们定义Solver参数到.prototxt
  4. 模型训练:用Caffe的命令训练一个模型,训练后,我们会得到模型.caffemodel

在训练阶段后,我们使用.caffemodel模型来预测新的数据。我们用Python搞定。

4.4   数据准备

先拷贝 train.ziptest1.zip 到AWS EC2实例的input目录。可以用scp命令,然后解压:

unzip ~/deeplearning-cats-dogs-tutorial/input/train.zip

unzip ~/deeplearning-cats-dogs-tutorial/input/test1.zip

rm ~/deeplearning-cats-dogs-tutorial/input/*.zip

然后运行 create_lmdb.py

cd ~/deeplearning-cats-dogs-tutorial/code

python create_lmdb.py

create_lmdb.py 会做如下事情:

  1. 运行直方图均衡化(histogram equalization)到所有训练图片,这会调整图片的对比度
  2. 调整图片大小到227x227格式
  3. 分割训练数据为两部分:一部分(5/6的图片)用于训练,另一部分(1/6)用于验证,验证集用于计算模型的准确度
  4. 存储训练和验证数据到2个LMDB数据库, train_lmdb 用于训练, validation_lmdb 用于模型验证

如下是代码重要部分:

def transform_img(img, img_width=IMAGE_WIDTH, img_height=IMAGE_HEIGHT):

 

    #Histogram Equalization

    img[:, :, 0] = cv2.equalizeHist(img[:, :, 0])

    img[:, :, 1] = cv2.equalizeHist(img[:, :, 1])

    img[:, :, 2] = cv2.equalizeHist(img[:, :, 2])

 

    #Image Resizing

    img = cv2.resize(img, (img_width, img_height), interpolation = cv2.INTER_CUBIC)

 

    return img

transform_img() 接受彩色图像输入,做直方图均衡化3个颜色通道,并调整图像大小。

 

def make_datum(img, label):

 

    return caffe_pb2.Datum(

        channels=3,

        width=IMAGE_WIDTH,

        height=IMAGE_HEIGHT,

        label=label,

        data=np.rollaxis(img, 2).tostring())

make_datum() 接受图像和标签输入,并返回 Datum 对象包含了图像机器标签。

in_db = lmdb.open(train_lmdb, map_size=int(1e12))

with in_db.begin(write=True) as in_txn:

    for in_idx, img_path in enumerate(train_data):

        if in_idx %  6 == 0:

            continue

        img = cv2.imread(img_path, cv2.IMREAD_COLOR)

        img = transform_img(img, img_width=IMAGE_WIDTH, img_height=IMAGE_HEIGHT)

        if 'cat' in img_path:

            label = 0

        else:

            label = 1

        datum = make_datum(img, label)

        in_txn.put('{:0>5d}'.format(in_idx), datum.SerializeToString())

        print '{:0>5d}'.format(in_idx) + ':' + img_path

in_db.close()

如上代码接受训练图片,转换和存储到 train_lmdb 。用于验证和存储的代码差不多,就不写了。

生成训练数据的平均图像:

我们执行如下命令来生成训练数据的平均图像。我们让输入图像减去平均图像后来确保每个特征像素都是0均值(zero mean)的。这是有监督机器学习的常用预处理步骤:

/home/ubuntu/caffe/build/tools/compute_image_mean \

    -backend=lmdb /home/ubuntu/deeplearning-cats-dogs-tutorial/input/train_lmdb \

    /home/ubuntu/deeplearning-cats-dogs-tutorial/input/mean.binaryproto

4.5   模型定义

在确定了CNN架构后,我们需要在.prototxt文件train_val中定义其参数。Caffe自带了流行的CNN模型,例如Alexnet和GoogleNet。本文中我们使用 bvlc_reference_caffenet 模型,属于AlexNet的修改。在复制 train_val 后我们命名为 caffenet_train_val_1.prototxt 。如果你想克隆本文的代码,你应该用相同的名字 deeplearning-cats-dogs-tutorial/caffe_models/caffe_model_1/

我们需要修改原始的 bvlc_reference_caffenet 的prototxt文件:

  1. 改变输入数据路径和平均图像:24、40、50行
  2. 改变输出数量从1000到2:373行,就是输出有几个类

我们可以打印出架构,通过如下命令。模型架构图像会存储在 deeplearning-cats-dogs-tutorial/caffe_models/caffe_model_1/caffe_model_1.png

python /home/ubuntu/caffe/python/draw_net.py \

    /home/ubuntu/deeplearning-cats-dogs-tutorial/caffe_models/caffe_model_1/caffenet_train_val_1.prototxt \

    /home/ubuntu/deeplearning-cats-dogs-tutorial/caffe_models/caffe_model_1/caffe_model_1.png

4.6   Solver定义

Solver是模型优化的主管。我们定义Solver参数在一个.prototxt文件中。你可以在 deeplearning-cats-dogs-tutorial/caffe_models/caffe_model_1/solver_1.prototxt

Solver会在每1000次迭代就使用验证集计算模型精度。优化流程会运行最大40000次迭代,并每5000次迭代生成一个快照模型。

base_lrlr_policygammamomentumweight_decay 是超参数(hyperparameter),我们需要调整以便获得模型更好的收敛(convergence)。

作者选择了 lr_policystepsize: 2500base_lr: 0.001gamma: 0.1 。在这个配置下,我们开始的学习率为0.001,然后调低学习率通过系数10,在每2500次迭代。

还有其他的优化策略。对细节的解释,建议 http://caffe.berkeleyvision.org/tutorial/solver.html

4.7   模型训练

在定义好模型和Sovler后,通过如下命令开始训练:

/home/ubuntu/caffe/build/tools/caffe train \

    --solver /home/ubuntu/deeplearning-cats-dogs-tutorial/caffe_models/caffe_model_1/solver_1.prototxt 2>&1 \

    | tee /home/ubuntu/deeplearning-cats-dogs-tutorial/caffe_models/caffe_model_1/model_1_train.log

训练产生的日志会存放到 deeplearning-cats-dogs-tutorial/caffe_models/caffe_model_1/model_1_train.log

在训练时,我们需要监控损失(loss)和模型精度。可以在任何时候停止这个过程,通过Ctrl+C。Caffe会在训练模型每5000个迭代时产生一个快照,并存储到 caffe_model_1 目录。

快照拥有.caffemodel扩展名。例如10000次迭代的快照叫做 caffe_model_1_iter_10000.caffemodel

4.7.1   绘制学习曲线

学习曲线是显示训练和测试损失的功能。对于训练/验证损失和精度很有用。

我们可以通过学习曲线来了解模型和验证何时到达90%,以及在3000次迭代后就不再改进了:

python /home/ubuntu/deeplearning-cats-dogs-tutorial/caffe_models/code/plot_learning_curve.py \

    /home/ubuntu/deeplearning-cats-dogs-tutorial/caffe_models/caffe_models/caffe_model_1/model_1_train.log \

    /home/ubuntu/deeplearning-cats-dogs-tutorial/caffe_models/caffe_models/caffe_model_1/caffe_model_1_learning_curve.png

 

4.8   在新数据上的预测

现在我们拥有了训练过的模型,我们可以用它来预测新的数据(从test1而来)。 deeplearning-cats-dogs-tutorial/code/make_predictions_1.py 就是预测代码。需要4个文件来运行:

  1. 测试图片:使用test1图片
  2. 平均图片:如上4.4节得到的
  3. 模型结构图: deeplearning-cats-dogs-tutorial/caffe_models/caffe_model_1/caffenet_deploy_1.prototxt 结构类似于 caffenet_train_va1_1.prototxt ,但是有少量修改,需要删除数据层,添加输入层并改变最后一层从SoftmaxWithLost为Softmax
  4. 训练模型权重:这个文件是训练阶段计算得到的,使用 caffe_model_1_iter_10000.caffemodel

要运行这个Python代码,我们需要执行如下命令。预测会存储到 deeplearning-cats-dogs-tutorial/caffe_models/caffe_model_1/submission_mode_1.csv

cd /home/ubuntu/deeplearning-cats-dogs-tutorial/code

python make_predictions_1.py

如下解释重要的代码部分:

#Read mean image

mean_blob = caffe_pb2.BlobProto()

with open('/home/ubuntu/deeplearning-cats-dogs-tutorial/input/mean.binaryproto') as f:

    mean_blob.ParseFromString(f.read())

mean_array = np.asarray(mean_blob.data, dtype=np.float32).reshape(

    (mean_blob.channels, mean_blob.height, mean_blob.width))

 

 

#Read model architecture and trained model's weights

net = caffe.Net('/home/ubuntu/deeplearning-cats-dogs-tutorial/caffe_models/caffe_model_1/caffenet_deploy_1.prototxt',

                '/home/ubuntu/deeplearning-cats-dogs-tutorial/caffe_models/caffe_model_1/caffe_model_1_iter_10000.caffemodel',

                caffe.TEST)

 

#Define image transformers

transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape})

transformer.set_mean('data', mean_array)

transformer.set_transpose('data', (2,0,1))

如上代码存储平均图像为 mean_array ,通过读取部署文件和训练模型定义模型叫做 net ,然后定义变换,应用到测试图像。

img = cv2.imread(img_path, cv2.IMREAD_COLOR)

img = transform_img(img, img_width=IMAGE_WIDTH, img_height=IMAGE_HEIGHT)

 

net.blobs['data'].data[...] = transformer.preprocess('data', img)

out = net.forward()

pred_probas = out['prob']

print pred_probas.argmax()

如上代码读取图像,应用与训练阶段相似的图像处理步骤,计算每个类的概率并打印最大概率的类,0=猫,1=狗。

之后提交预测结果到Kaggle,给出精度为0.89691。

5   使用Transfer Learning构建猫狗分类器

本节使用一个强大而实用的技术叫做Transfer Learning来构建我们的猫狗分类器。

5.1   什么是Transfer Learning

CNN需要大量的数据集和大量的计算时间来训练。一些网络可能需要2-3周,以及多个GPU来训练。传输学习则是解决这两个问题的办法。与其从头训练网络,传输学习使用已经训练的模型和不同的数据集,并适应更多要解决的问题。

传输学习的两个策略:

  1. 把训练出的模型作为特征提取器:在这个策略里,我们是你出最后的全连接层,冻结剩余层的权重,并训练在剩余层的输出上做分类器
  2. Fine-Tune训练过的模型:继续调优训练过的模型到新的数据集,持续做反向传播,我们可以同时在整个网络做调优或者冻结一部分的层

传输学习的细节解释,参见 http://cs231n.github.io/transfer-learning/

5.2   使用Transfer Learning训练猫狗分类器

Caffe自带了版本库给研究者和机器学习实践者来共享训练过的模型,叫做 Model Zoo: https://github.com/BVLC/caffe/wiki/Model-Zoo

我们可以使用传输学习,将训练过的 bvlc_reference_caffenet 作为起点来构建我们的猫狗分类器。这个模型是在ImageNet上训练过的。

我们使用调优策略来训练模型。

5.2.1   下载bvlc_reference_caffenet模型

cd /home/ubuntu/caffe/models/bvlc_reference_caffenet

wget http://dl.caffe.berkeleyvision.org/bvlc_reference_caffenet.caffemodel

5.2.2   模型定义

模型定义和Sovler配置文件存储在 deeplearning-cats-dogs-tutorial/caffe_models/caffe_model_2 中。我们需要gaiiban原始的 bvlc_reference_caffenet 模型配置文件。

  1. 改变输入数据路径和平均图像:24、40、51行
  2. 改变最后全连接层从fc8到fc8-cats-dogs:360、363、387、397行
  3. 改变输出数量:从1000到2,373行

现在我们保持层的名字不变,并传入训练过的模型权重到Caffe,就会选择从训练过的模型载入权重。如果我们想要冻结层,就需要设置他的 lr_mult 参数为0。

模型配置的 caffe_train_val_2.prototxt 就不粘贴了,400行呢。文件中 lr_mult 有多处,取值是1和2,没见到0。

5.2.3   Solver定义

使用一个相似的Sovler:

net: "/home/ubuntu/cats-dogs-tutorial/caffe_models/caffe_model_2/caffenet_train_val_2.prototxt"

test_iter: 1000

test_interval: 1000

base_lr: 0.001

lr_policy: "step"

gamma: 0.1

stepsize: 2500

display: 50

max_iter: 40000

momentum: 0.9

weight_decay: 0.0005

snapshot: 5000

snapshot_prefix: "/home/ubuntu/cats-dogs-tutorial/caffe_models/caffe_model_2/caffe_model_2"

solver_mode: GPU

5.2.4   通过传输学习训练模型

定义好模型和Solver后,可以开始训练。注意我们传递训练过的模型权重作为 --weights 参数:

/home/ubuntu/caffe/build/tools/caffe train \

    --solver=/home/ubuntu/deeplearning-cats-dogs-tutorial/caffe_models/caffe_model_2/solver_2.prototxt \

    --weights /home/ubuntu/caffe/models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel 2>&1 \

    | tee /home/ubuntu/deeplearning-cats-dogs-tutorial/caffe_models/caffe_model_2/model_2_train.log

5.2.5   绘制学习曲线

类似于之前的章节,我们绘制学习曲线。可以看到在1000次迭代后,模型的精度就达到了97%。这展示了传输学习的力量。我们可以在更小的迭代就获得类似的准确率:

python /home/ubuntu/deeplearning-cats-dogs-tutorial/code/plot_learning_curve.py \

    /home/ubuntu/deeplearning-cats-dogs-tutorial/caffe_models/caffe_model_2/model_2_train.log \

    /home/ubuntu/deeplearning-cats-dogs-tutorial/caffe_models/caffe_model_2/caffe_model_2_learning_curve.png

5.2.6   在新数据上的预测

之前做过,预测并上传到Kaggle来获得模型精度。预测的代码在 deeplearning-cats-dogs-tutorial/code/make_predictions_2.py

模型的精度达到了0.97154,比之前从头训练的还好。

6   总结

本文覆盖了深度学习和CNN的核心概念。也学习了如何使用Caffe和Python来从头构建CNN,以及使用Transfer Learning。如果想要了解更多,强烈推荐Stanford的CNN视觉识别:http://cs231n.github.io/

上一篇: 2020年笔记统计

下一篇: test图片