Caffe学习系列——4使用训练好的模型进行分类

Contents

本文主要介绍如何用训练好的模型进行分类,如何训练模型可以查看上一篇博文,本文用到的模型即上一篇博文训练好的模型。当然如果你还没有自己训练模型,也可以使用Caffe官网提供的 利用imagenet图片和caffenet模型训练好的一个caffemodel。
首先需要准备三个文件:

  1. Caffemodel文件
    可以直接在浏览器里输入地址下载,也可以运行脚本文件下载。下载地址为:http://dl.caffe.berkeleyvision.org/bvlc_reference_caffenet.caffemodel
    文件名称为:bvlc_reference_caffenet.caffemodel,文件大小为230M左右,为了代码的统一,将这个caffemodel文件下载到caffe根目录下的 models/bvlc_reference_caffenet/ 文件夹下面。也可以运行脚本文件进行下载:

    1
    # sudo ./scripts/download_model_binary.py models/bvlc_reference_caffenet
  2. 均值文件
    有了caffemodel文件,就需要对应的均值文件,在测试阶段,需要把测试数据减去均值。这个文件我们用脚本来下载,在caffe根目录下执行:

    1
    # sudo sh ./data/ilsvrc12/get_ilsvrc_aux.sh

执行并下载后,均值文件放在 data/ilsvrc12/ 文件夹里。用自己训练的模型的话,就需要相应的替换成自己数据集的均值文件。

  1. synset_words.txt文件
    在调用脚本文件下载均值的时候,这个文件也一并下载好了。里面放的是1000个类的名称。
  2. deploy.prototxt
    这是进行分类时的网络结构,需要与你训练时的网络结构文件大体一致,不同的是没有测试那层,若是用官网的caffenet网络以及他训练好的caffemodel,则该文件也在model/bvlc_reference_caffenet目录下。你可以参考里面的deploy.prototxt来修改自己的train_val.prototxt并重命名为deploy.prototxt

本文使用python方法来进行分类,python代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# -*- coding: utf-8 -*-
#加载必要的库
import numpy as np
import argparse
import sys,os,shutil
import caffe
#将结果输出到txt中
def writeouput(result,path):
if os.path.isfile(path):
f=open(path,'a')
f.write(result+'\n')
f.close()
else:
f=open(path,'w')
f.write(result+'\n')
f.close()
#定义输入的参数
def main(argv):
#设置caffe的根目录
caffe_root='/home/linbiyuan/caffe/'
sys.path.insert(0,caffe_root+'python')
os.chdir(caffe_root)
#定义输入参数,可设定默认参数
parser = argparse.ArgumentParser()
parser.add_argument(
"input_file",
help="Input image, directory, or npy."
)
parser.add_argument(
"output_file",
help="Output npy filename."
)
parser.add_argument(
"output_image_file",
help="Output npy filename."
)
#caffemodel等等也可以使用参数,这里为了简单故注释掉了
# # Optional arguments.
# parser.add_argument(
# "--model_def",
# default=os.path.join(caffe_root,"examples/wow_style/deploy.prototxt"),
# help="Model definition file."
# )
# parser.add_argument(
# "--pretrained_model",
# default=os.path.join(caffe_root,"examples/wow_style/wow_style3_iter_50000.caffemodel"),
# help="Trained model weights file."
# )
# parser.add_argument(
# "--mean_file",
# default=os.path.join(caffe_root,'python/caffe/imagenet/ilsvrc_2012_mean.npy'),
# help="Data set image mean of [Channels x Height x Width] dimensions " +
# "(numpy array). Set to '' for no mean subtraction."
# )
args=parser.parse_args()

caffe.set_mode_gpu()
#deploy.prototxt文件的位置
net_file=caffe_root+'examples/blog_img/deploy.prototxt'
#caffemodel文件的位置
caffe_model=caffe_root+'examples/blog_img/blogimg_type.caffemodel'
#定义net
net=caffe.Net(net_file,caffe_model,caffe.TEST)

#均值文件的位置
mean_file = caffe_root + 'python/caffe/imagenet/ilsvrc_2012_mean.npy'
transformer=caffe.io.Transformer({'data':net.blobs['data'].data.shape})
transformer.set_transpose('data',(2,0,1))
transformer.set_mean('data',np.load(mean_file).mean(1).mean(1))
transformer.set_raw_scale('data',255)
transformer.set_channel_swap('data',(2,1,0))

#读取图片
im=caffe.io.load_image(args.input_file)
net.blobs['data'].data[...]=transformer.preprocess('data',im)
#获得结果
out=net.forward()
#准确率最高的一个结果
output_prob=out['prob'][0]
#标签文件位置
labels_file=caffe_root+'examples/wow_style/synset_words.txt'
labels=np.loadtxt(labels_file,str,delimiter='\t')
#根据标签文件获得标签名字,否则输出的是标签的ID
labels_name = labels[output_prob.argmax()]
image_name=args.input_file.split('/')[-1]
#结果保存
writeouput(image_name+" "+labels_name,args.output_file)
#将得到分类结果的图片复制到相应类别的目录下,前提需要在该目录下建立各个类别的文件夹,看个人需求,可以注释掉这两行代码,
topath=args.output_image_file+labels_name+'/'+image_name
shutil.copy(args.input_file,topath)

# print 'output label:',labels_name
# return labels_name
if __name__ == '__main__':
main(sys.argv)

输出的结果是:
使用上一篇博文训练好的网络进行分类的结果还是不错,
分类的效果如下:




你也可以使用caffe开发团队编写了一个python版本的分类文件,路径为 python/classify.py
运行这个文件必需两个参数,一个输入图片文件,一个输出结果文件。而且运行必须在python目录下。假设当前目录是caffe根目录,则运行:

1
# cd python# sudo python classify.py ../examples/images/cat.jpg result.npy

分类的结果保存为当前目录下的result.npy文件里面,是看不见的。而且这个文件有错误,运行的时候,会提示Mean shape incompatible with input shape的错误。因此,要使用这个文件,我们还得进行修改:

  1. 修改均值计算
    定位到
    mean = np.load(args.mean_file)
    这一行,在下面加上一行:
    mean=mean.mean(1).mean(1)
    则可以解决报错的问题。
  2. 修改文件,使得结果显示在命令行下:
    定位到
    1
    2
    3
    4
    # Classify. 
    start = time.time()
    predictions = classifier.predict(inputs, not args.center_only)
    print("Done in %.2f s." % (time.time() - start))

这个地方,在后面加上几行,如下所示:

1
# Classify. start = time.time() predictions = classifier.predict(inputs, not args.center_only) print("Done in %.2f s." % (time.time() - start)) imagenet_labels_filename = '../data/ilsvrc12/synset_words.txt' labels = np.loadtxt(imagenet_labels_filename, str, delimiter='\t') top_k = predictions.flatten().argsort()[-1:-6:-1] for i in np.arange(top_k.size): print top_k[i], labels[top_k[i]]

就样就可以了。运行不会报错,而且结果会显示在命令行下面。

Contents