在snapshot
目录下已经有我们训练好的模型的参数,为了利用我们的卷积神经网络模型和这些参数去对图像进行分类,我们这次实验就来编写代码实现一个图片分类程序。
在第二次实验中,我们编写了network.prototxt
用于进行模型的训练,当模型训练完成需要使用模型进行实际的分类时,就不能再继续用network.prototxt
来定义我们的网络结构了。因为此时我们不需要区分TRAIN
和TEST
这两种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
文件
在前面获取训练数据时,我们使用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
格式。
caffe
本身是用C++
和CUDA
编写的,但它提供了python
和MATLAB
编程借接口。本次实验我们就是使用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
深度学习框架的强大。而且我们第一次利用训练好的模型开发出了一个直观的图片分类程序,这个程序再一次让我们感受到了深度学习的神奇。
如果你在学习的过程中受到了许多挫折,没有获得理想的学习效果,也不要灰心,这正能体现出深度学习的价值。如果人人都能轻易学会,那还有什么特意花时间去学习的必要呢?如果你对深度学习仍然怀有兴趣,请回过头去再看看没有理解的部分。或者如果你觉得本课程的文档写的不够好,也可以再去查阅相关的资料,随着深度学习的影响力逐渐扩大,一定会有越来越多优质的中文资料出现。
本次实验,我们学习了:
test.txt
里的文件,而是遍历其中的每一个图片,并计算出模型在测试集上的准确率。network.prototxt
和solver.prototxt
文件而直接通过python
程序进行模型的构建和训练。