使用卷积神经网络进行图片分类 4

利用训练好的模型开发图片分类程序

一、实验介绍

1.1 实验内容

snapshot目录下已经有我们训练好的模型的参数,为了利用我们的卷积神经网络模型和这些参数去对图像进行分类,我们这次实验就来编写代码实现一个图片分类程序。

1.2 实验知识点

  • caffe python api

1.3 实验环境

  • python 2.7
  • opencv 2.4.11
  • caffe 1.0.0

二、实验步骤

2.1 准备deploy.prototxt

在第二次实验中,我们编写了network.prototxt用于进行模型的训练,当模型训练完成需要使用模型进行实际的分类时,就不能再继续用network.prototxt来定义我们的网络结构了。因为此时我们不需要区分TRAINTEST这两种phase, 同时我们模型的需要输出对每种类别的概率预测,而不是损失函数值,并且我们也不需要准确率层了。  

但是我们的网络结构是不会变的,所以我们可以直接在network.prototxt的基础上进行修改。首先我们需要去掉一个数据层,并且将include{phase:TRAIN/TEST}参数删掉,然后我们需要删掉Accuracy层和SoftmaxWithLoss层,最后需要添加一个概率预测层prob,其定义如下:

layer{
    name: "prob"
    type: "Softmax"
    bottom: "ip2"
    bottom: "label"
    top: "prob"
}

我们之前说过,通常都会将Softmax层作为模型对概率的预测输出,所以这里的type参数为Softmax。  

完整的deploy.prototxt文件可以通过以下命令获取:

wget http://labfile.oss.aliyuncs.com/courses/820/deploy.tar.gz
tar zxvf deploy.tar.gz

注意里面还包含了我们接下来会介绍的classifier.py文件

2.2 转换平均值文件

在前面获取训练数据时,我们使用compute_image_mean命令计算出了平均值文件train.binaryproto, 在我们将要实现的python程序中,也必须对图片减去均值,为了让python能够读取平均值文件,我们先将train.binaryproto转换成npy文件,以下的脚本实现了这个转换,你可以把这个脚本保存下来以备以后使用。创建bin2npy.py文件,编写如下代码:

#!/usr/bin/env python
import sys
sys.path.append('/opt/caffe/python')
import numpy as np
import sys, caffe

if len(sys.argv) != 3:
    print "Usage: python bin2npy.py mean.binaryproto mean.npy"
    sys.exit()

blob = caffe.proto.caffe_pb2.BlobProto()
bin_mean = open(sys.argv[1], 'rb').read()
blob.ParseFromString(bin_mean)
arr = np.array(caffe.io.blobproto_to_array(blob))
npy_mean = arr[0]
print 'channel:', len(npy_mean), 'row:', len(npy_mean[0]), 'col:', len(npy_mean[0][0])
np.save(sys.argv[2], npy_mean)

在terminal运行如下命令进行转换:

python bin2npy.py train.binaryproto train.npy

就将均值文件转换成了python可以直接读取的npy格式。

2.3 caffe python api

caffe本身是用C++CUDA编写的,但它提供了pythonMATLAB编程借接口。本次实验我们就是使用python编程接口来编写图片分类程序。本次实验只会用到很少的几个api,更多功能强大的api你可以查看caffe官网的教程。这里创建classifier.py文件,编写如下代码:

# Created by wz on 17-5-12.
# encoding=utf-8
import sys

sys.path.append('/opt/caffe/python')  # 先将pycaffe 路径加入环境变量中
import caffe, cv2, numpy as np


class Classfier:  # 将模型封装入一个分类器类中
    def __init__(self, deploy, model, mu):
        self.net = caffe.Net(deploy, model, caffe.TEST)  # 初始化网络结构及其中的参数
        self.mu = mu

    def classify(self, img):
        img = (img - self.mu) * 0.00390625  # 减去均值后再进行缩放
        self.net.blobs['data'].data[...] = img  # 将图片数据送入data层的blobs
        out = self.net.forward()['prob']  # 执行前向计算,并得到最后prob层的输出结果
        return out


def main():
    mean_file = 'train.npy'
    mean = np.load(mean_file)  # 加载均值文件
    classifier = Classfier('deploy.prototxt', 'snapshot/alpha_iter_10000.caffemodel', mean)  # 创建我们的分类器
    with open('test.txt') as f:  # 读取测试集中的图片
        l = f.readlines()
    for i in l:
        print i
        name, label = i.split(' ')
        img = cv2.imread(name)  # 读取图片
        img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        prob = classifier.classify(img)  # 使用分类器分类,得到概率
        print prob  # 输出概率值
        print chr(np.argmax(prob) + 65)  # 输出概率最大值对应的英文字母
        if np.argmax(prob) == int(label):
            cv2.imshow('img', img)  # 输出原始图片
            cv2.waitKey()  # 等待按键


if __name__ == '__main__':
    main()

首先我们要将pycaffe的目录添加进环境变量PATH中,不然import caffe会报错。
可以看到,我们将caffe模型封装进一个Classifier类,注意在Classifier.classify()函数中,对输入图片的预处理要与训练模型时的预处理完全一样,不然识别准确率可能很低。

main函数中,我们对test.txt里的的每一张图片都调用模型去识别,在terminal输出预测的概率和预测概率最大的字母,同时显示出原图片,这样你可以直观的感受模型的准确率如何。注意一张图片显示出来后,需要按一下键盘才能显示下一张图片:

三、实验总结

至此,本课程就结束了。虽然我们做的项目十分简单,但相信你也已经体会到了caffe深度学习框架的强大。而且我们第一次利用训练好的模型开发出了一个直观的图片分类程序,这个程序再一次让我们感受到了深度学习的神奇。

如果你在学习的过程中受到了许多挫折,没有获得理想的学习效果,也不要灰心,这正能体现出深度学习的价值。如果人人都能轻易学会,那还有什么特意花时间去学习的必要呢?如果你对深度学习仍然怀有兴趣,请回过头去再看看没有理解的部分。或者如果你觉得本课程的文档写的不够好,也可以再去查阅相关的资料,随着深度学习的影响力逐渐扩大,一定会有越来越多优质的中文资料出现。

本次实验,我们学习了:

  • caffe提供的python api可以使我们方便地通过python去调用caffe中的一些功能

四、课后作业

  1. 请你修改我们的classifier.py文件,使这个程序不再逐个显示出test.txt里的文件,而是遍历其中的每一个图片,并计算出模型在测试集上的准确率。
  2. [选做]caffe的python api还可以用来构建网络并进行训练,请你自行查阅资料,不使用network.prototxtsolver.prototxt文件而直接通过python程序进行模型的构建和训练。

你可能感兴趣的:(实验楼课程)