从零开始学caffe(九):在Windows下实现图像识别

本系列文章主要介绍了在win10系统下caffe的安装编译,运用CPU和GPU完成简单的小项目,文章之间具有一定延续性。

step1:准备数据集

数据集是进行深度学习的第一步,在这里我们从以下五个链接中下载所需要的数据集:
animal
flower
plane
house
guitar

我们在原先的models文件夹下新建文件夹my_models_recognition,用于存放本文在实现图像识别过程中的相关文件。我们之前下载的五个压缩包包含animal、flower、plane、house和guitar五个类别。我们首先需要将其分成训练集和测试集两个部分,在这里,我们采用手工的方法来制作数据集。

首先分别在train和test文件夹下新建五个类别的文件夹,用于存放每个类别的训练集和测试集。
在这里插入图片描述
在这里,我们设定训练集的数目为500,测试集的数目为300,我们将每个分类的前500章图片剪切到train文件夹的相应类别下,用于作为训练集,剪切300张图片到test的相应文件夹下作为测试集。至此,我们已经完成了数据集的准备工作。

step2:制作标签

我们以“文件路径+标签”的形式对每个图像进行命名,在这里,如果我们继续采用手工操作对图像标签进行制作,这个过程需要耗费大量的时间。为此,我们在jupyter 中运行下列程序来帮助我们完成标签制作。在运行程序之前先新建labels文件夹用于存放产生的标签。

import os 

#定义Caffe根目录
caffe_root = 'E:/caffe-windows/'

#制作训练标签数据
i = 0 #标签
with open(caffe_root + 'models/my_models_recognition/labels/train.txt','w') as train_txt: 
    for root,dirs,files in os.walk(caffe_root+'models/my_models_recognition/data/train/'): #遍历文件夹
        for dir in dirs:
            for root,dirs,files in os.walk(caffe_root+'models/my_models_recognition/data/train/'+str(dir)): #遍历每一个文件夹中的文件 
                for file in files:
                    image_file = str(dir) + '\\' + str(file)
                    label = image_file + ' ' + str(i) + '\n'       #文件路径+空格+标签编号+换行 
                    train_txt.writelines(label)                   #写入标签文件中
                i+=1 #编号加1


#制作测试标签数据
i=0 #标签
with open(caffe_root + 'models/my_models_recognition/labels/test.txt','w') as test_txt:
    for root,dirs,files in os.walk(caffe_root+'models/my_models_recognition/data/test/'): #遍历文件夹
        for dir in dirs:
            for root,dirs,files in os.walk(caffe_root+'models/my_models_recognition/data/test/'+str(dir)): #遍历每一个文件夹中的文件
                for file in files:
                    image_file = str(dir) + '\\' + str(file)
                    label = image_file + ' ' + str(i) + '\n'       #文件路径+空格+标签编号+换行 
                    test_txt.writelines(label)                   #写入标签文件中
                i+=1#编号加1
                
print "成功生成文件列表"

运行程序,输出“成功生成文件列表”,打开labels文件夹,就可以在里面分别找到train和test的标签文件。在这里插入图片描述
至此,我们也已经完成了标签的制作过程。

step3:数据转换

由于我们的数据集中图片是png的形式,我们需要将其转化为LMDB的格式,新建lmdb文件夹用于存放生成的lmdb文件。

和之前我们讲述的方法一样,在这里我们运用convert_imageset.exe来完成格式转化。运行批处理文件如下,对训练集的图像进行格式转换并打乱图片顺序:

%格式转换的可执行文件%
%重新设定图像大小%
%打乱图片%
%转换格式%
%图片路径%
%图片标签%
%lmdb文件的输出路径%

E:\caffe-windows\Build\x64\Release\convert_imageset.exe ^
--resize_height=256  --resize_width=256 ^
--shuffle ^
--backend="lmdb" ^
E:\caffe-windows\models\my_models_recognition\data\train\ ^
E:\caffe-windows\models\my_models_recognition\labels\train.txt ^
E:\caffe-windows\models\my_models_recognition\lmdb\train\
pause

同理,运行如下程序修改测试集中的图片格式。

%格式转换的可执行文件%
%重新设定图像大小%
%打乱图片%
%转换格式%
%图片路径%
%图片标签%
%lmdb文件的输出路径%

E:\caffe-windows\Build\x64\Release\convert_imageset.exe ^
--resize_height=256  --resize_width=256 ^
--shuffle ^
--backend="lmdb" ^
E:\caffe-windows\models\my_models_recognition\data\test\ ^
E:\caffe-windows\models\my_models_recognition\labels\test.txt ^
E:\caffe-windows\models\my_models_recognition\lmdb\test\
pause

在这里插入图片描述

step5:修改网络参数文件

在之前的文章中,我们使用过Googlenet,Googlenet适用于分类多,数据量大的情况,当数据集太小的时候容易出现过拟合现象(如本文只采用500个数据集),因此在这里我们使用caffenet来完成图像的分类。
在这里插入图片描述
把上述文件复制到my_models_recognition中,然后编辑网络参数文件
在这里,我们没有使用均值文件,因此将下列代码注释掉

# transform_param {
# mirror: true
# crop_size: 227
# mean_file: "data/ilsvrc12/imagenet_mean.binaryproto"
# }
# mean pixel / channel-wise mean instead of mean image

同理,还有下列代码:

#  transform_param {
#    mirror: false
#    crop_size: 227
#    mean_file: "data/ilsvrc12/imagenet_mean.binaryproto"
#  }
# mean pixel / channel-wise mean instead of mean image

将第25行batch size改为100
将293和333行num_output改为512
373行中,因为这里我们只有五个类别,所以只需要5个输出即可,将1000改为5

step6:修改超参数文件

对超参数文件中的路径进行修改,最大迭代次数改为3000.,每500次迭代输出一次model,并新建文件夹model,用于存放训练得到的模型

net: "E:/caffe-windows/models/my_models_recognition/train_val.prototxt"
test_iter: 30
test_interval: 200
base_lr: 0.01
lr_policy: "step"
gamma: 0.1
stepsize: 1000
display: 50
max_iter: 3000
momentum: 0.9
weight_decay: 0.0005
snapshot: 500
snapshot_prefix: "E:/caffe-windows/models/my_models_recognition/model/"
solver_mode: GPU

step7:准备标签

新建label文件,在里面放置物体的类别
在这里插入图片描述

step8:修改deploy Prototxt文件

虽然在之前我们已经修改了网络结构文件,但是在测试过程中我们使用的是deploy Prototxt文件,因此我们对其进行同样的修改:

181行和157行输出改为512,第205行改为5.

step9:模型运行

运行批处理文件如下:

%train训练数据%
%超参数文件%

E:\caffe-windows\Build\x64\Release\caffe.exe train ^
-solver=E:/caffe-windows/models/my_models_recognition/solver.prototxt ^
pause

在这里插入图片描述
(第一次进行训练的时候是设置没5次迭代输出一次结构,第二次训练改为500次训练输出一次结构,因此前面有那些第五次第十次之类,忽略即可)

step10:准备测试图片

新建image文件夹,将我们要测试的图片放置在其中:
在这里插入图片描述

step11:模型测试

在jupyter中运行如下代码:

import caffe
import numpy as np
import matplotlib.pyplot as plt
import os
import PIL
from PIL import Image
import sys

#定义Caffe根目录
caffe_root = 'E:/caffe-windows/'
#网络结构描述文件
deploy_file = caffe_root+'models/my_models_recognition/deploy.prototxt'
#训练好的模型
model_file = caffe_root+'models/my_models_recognition/model/_iter_3000.caffemodel'

#gpu模式
#caffe.set_device(0)
caffe.set_mode_cpu()

#定义网络模型
net = caffe.Classifier(deploy_file, #调用deploy文件
                       model_file,  #调用模型文件
                       channel_swap=(2,1,0),  #caffe中图片是BGR格式,而原始格式是RGB,所以要转化
                       raw_scale=255,         #python中将图片存储为[0, 1],而caffe中将图片存储为[0, 255],所以需要一个转换
                       image_dims=(227, 227)) #输入模型的图片要是227*227的图片


#分类标签文件
imagenet_labels_filename = caffe_root +'models/my_models_recognition/labels/label.txt'
#载入分类标签文件
labels = np.loadtxt(imagenet_labels_filename, str)

#对目标路径中的图像,遍历并分类
for root,dirs,files in os.walk(caffe_root+'models/my_models_recognition/image/'):
    for file in files:
        #加载要分类的图片
        image_file = os.path.join(root,file)
        input_image = caffe.io.load_image(image_file)

        #打印图片路径及名称
        image_path = os.path.join(root,file)
        print(image_path)
        
        #显示图片
        img=Image.open(image_path)
        plt.imshow(img)
        plt.axis('off')
        plt.show()
        
        #预测图片类别
        prediction = net.predict([input_image])
        print 'predicted class:',prediction[0].argmax()

        # 输出概率最大的前5个预测结果
        top_k = prediction[0].argsort()[::-1]
        for node_id in top_k:     
            #获取分类名称
            human_string = labels[node_id]
            #获取该分类的置信度
            score = prediction[0][node_id]
            print('%s (score = %.5f)' % (human_string, score))

运行代码即可输出分类结果,我们发现模型的识别准确率非常高
在这里插入图片描述