caffe +ubuntu16.04基于CaffeNet网络框架训练图片进行分类

主要参考(按顺序):
http://www.cnblogs.com/denny402/p/5083300.html
http://www.cnblogs.com/denny402/p/5082341.html
http://www.cnblogs.com/denny402/p/5083300.html
https://www.cnblogs.com/denny402/p/5685909.html

其它:
https://blog.csdn.net/u010682375/article/details/77777827
https://blog.csdn.net/where_is_my_keyboard/article/details/79882466

一、准备数据
数据下载地址:
(1).可以去imagenet的官网:http://www.image-net.org/download-images,下载imagenet图片来训练。

(2).使用Corel数据集:https://blog.csdn.net/garfielder007/article/details/51483759

我在corel中下载图片,并选取了500张图片,其中400张作为训练集,100张作为测试集,图片序号是200 - 699。图片放在caffe/examples/myfile/images下的train文件夹(400张)和test文件夹(100),其中myfile是我自己创建的文件夹。

caffe +ubuntu16.04基于CaffeNet网络框架训练图片进行分类_第1张图片

二、转换为lmdb格式
首先,制作图片列表清单:
cd到caffe目录下,执行以下命令,在myfile文件夹中添加create_filelist.sh文件

# sudo vi examples/myfile/create_filelist.sh

并在其中加入以下代码:

create_filelist.sh

#!/usr/bin/env sh
DATA=examples/myfile/images
MY=examples/myfile

echo "Create train.txt..."
rm -rf $MY/train.txt
for i in 2 3 4 5 6
do
find $DATA/train -name $i*.jpg | cut -d '/' -f4-5 | sed "s/$/ $i/">>$MY/train.txt
done
echo "Create test.txt..."
rm -rf $MY/test.txt
for i in 2 3 4 5 6
do
find $DATA/test -name $i*.jpg | cut -d '/' -f4-5 | sed "s/$/ $i/">>$MY/test.txt
done
echo "All done"

然后,运行此脚本

# sudo sh examples/myfile/create_filelist.sh

成功的话,就会在examples/myfile/ 文件夹下生成train.txt和test.txt两个文本文件,里面就是图片的列表清单。
caffe +ubuntu16.04基于CaffeNet网络框架训练图片进行分类_第2张图片
caffe +ubuntu16.04基于CaffeNet网络框架训练图片进行分类_第3张图片

另外,也可以用python来制作列表清单:

# -*- coding: utf-8 -*-

import os
data_path='examples/myfile/images/'
my='examples/myfile/'
classes=[3,4,5,6,7]

def gen_txt(phase):
    f=open(my+phase+'.txt','w')
    for c in classes:
        folder=str(c)
        images=os.listdir(data_path+phase+'/'+folder)
        for img in images:
            f.write(folder+'/'+img+' '+folder+'\n')
gen_txt('train')
gen_txt('test')

在caffe根目录下执行:

sudo python examples/myfile/create_filelist.py

然后,再编写一个脚本文件,调用convert_imageset命令来转换数据格式

# sudo vi examples/myfile/create_lmdb.sh

加入以下代码:

create_lmdb.sh

#!/usr/bin/env sh
MY=examples/myfile

echo "Create train lmdb.."
rm -rf $MY/img_train_lmdb
build/tools/convert_imageset \
--shuffle \
--resize_height=256 \
--resize_width=256 \
/home/cyj/caffe/examples/myfile/images/ \
$MY/train.txt \
$MY/img_train_lmdb

echo "Create test lmdb.."
rm -rf $MY/img_test_lmdb
build/tools/convert_imageset \
--shuffle \
--resize_width=256 \
--resize_height=256 \
/home/cyj/caffe/examples/myfile/images/ \
$MY/test.txt \
$MY/img_test_lmdb

echo "All Done.."

在caffe目录下,运行:

sudo sh examples/myfile/create_lmdb.sh

成功后,在myfile中得到img_test_lmdb和img_train_lmdb目录,分别用于保存图片转换后的lmdb文件,检查一下其文件大小是否为0字节,是的话代表出错,要重新执行前面的步骤。

三、计算均值并保存

图片减去均值再训练,会提高训练速度和精度。因此,一般都会有这个操作。

caffe中使用的均值数据格式是binaryproto, 作者为我们提供了一个计算均值的文件compute_image_mean.cpp,放在caffe根目录下的tools文件夹里面。编译后的可执行体放在 build/tools/ 下面,我们直接调用就可以了

sudo build/tools/compute_image_mean examples/myfile/img_train_lmdb examples/myfile/mean.binaryproto

我这边出现错误:
caffe +ubuntu16.04基于CaffeNet网络框架训练图片进行分类_第4张图片

what(): std::bad_alloc
已放弃 (核心已转储)

问题解决:我这边是由于前面create_lmdb.sh中路径填写错误,导致lbdb文件未正确生成。

改正后,成功生成文件mean.binaryproto:
caffe +ubuntu16.04基于CaffeNet网络框架训练图片进行分类_第5张图片

数据集准备完毕。

四、创建模型并编写配置文件
模型用程序自带的caffenet模型,位置在 models/bvlc_reference_caffenet/文件夹下, 将需要的两个配置文件,复制到myfile文件夹内

sudo cp models/bvlc_reference_caffenet/solver.prototxt examples/myfile/
sudo cp models/bvlc_reference_caffenet/train_val.prototxt examples/myfile/

修改其中的solver.prototxt

sudo vi examples/myfile/solver.prototxt

solver.prototxt

net: "examples/myfile/train_val.prototxt"
test_iter: 2
test_interval: 50
base_lr: 0.001
lr_policy: "step"
gamma: 0.1
stepsize: 100
display: 20
max_iter: 500
momentum: 0.9
weight_decay: 0.005
solver_mode: GPU

100个测试数据,batch_size为50,因此test_iter设置为2,就能全cover了。在训练过程中,调整学习率,逐步变小。
修改solver.prototxt,设置snapshot和snapshot_prefix,snapshot用于设置训练多少次后进行保存,默认为0,不保存。snapshot_prefix设置保存路径。

修改train_val.prototxt,只需要修改两个阶段的data层就可以了,其它可以不用管。

sudo vi examples/myfile/train_val.prototxt

train_val.prototxt的修改部分:

name: "CaffeNet"
layer {
  name: "data"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TRAIN
  }
  transform_param {
    mirror: true
    crop_size: 227
    mean_file: "examples/myfile/mean.binaryproto"
  }
  data_param {
    source: "examples/myfile/img_train_lmdb"
    batch_size: 256
    backend: LMDB
  }
}
layer {
  name: "data"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TEST
  }
  transform_param {
    mirror: false
    crop_size: 227
    mean_file: "examples/myfile/mean.binaryproto"
  }
  data_param {
    source: "examples/myfile/img_test_lmdb"
    batch_size: 50
    backend: LMDB
  }
}

实际上就是修改两个data layer的mean_file和source这两个地方,其它都没有变化 。

配置完毕。

五、训练和测试

执行:

sudo build/tools/caffe train -solver examples/myfile/solver.prototxt

训练过程出现一个错误~~继续解决

caffe +ubuntu16.04基于CaffeNet网络框架训练图片进行分类_第6张图片

我首先尝试在train_val.prototxt中将batch_size设置为128,结果还是错,后来在solver.prototxt中设置solver_mode: CPU,然后程序跑成功,耗时三个多小时。

caffe +ubuntu16.04基于CaffeNet网络框架训练图片进行分类_第7张图片

训练结束会生成xxx.caffemodel和xxx.solverstate分别存储训练过程的参数和中段的参数信息

caffe +ubuntu16.04基于CaffeNet网络框架训练图片进行分类_第8张图片

六、利用生成的模型使用python接口测试自己的数据

1.首先将待预测的图片准备好,我这边将图片放到myfile目录下。然后,编写脚本将二进制文件mean.binaryproto转换成python可以识别的mean.npy文件(均值文件)

to_mean_npy.py

import caffe
import numpy as np

MEAN_PROTO_PATH = 'imagenet_mean.binaryproto'            
MEAN_NPY_PATH = 'mean.npy'                        

blob = caffe.proto.caffe_pb2.BlobProto()        
data = open(MEAN_PROTO_PATH, 'rb' ).read()         
blob.ParseFromString(data)                      

array = np.array(caffe.io.blobproto_to_array(blob))
mean_npy = array[0]                            
np.save(MEAN_NPY_PATH ,mean_npy)

这边出现一个错误:

ImportError: /home/cyj/anaconda2/bin/../lib/libstdc++.so.6: version
`GLIBCXX_3.4.21’ not found

原因是没有找到GLBCXX 3.4.21

所以查询以下当前版本号:

$ strings /home/kzl/anaconda2/bin/../lib/libstdc++.so.6 | grep GLIBCXX

caffe +ubuntu16.04基于CaffeNet网络框架训练图片进行分类_第9张图片

确实缺少版本GLBCXX 3.4.21

解决办法:https://blog.csdn.net/CYJ2014go/article/details/80736767

执行成功后,在同目录下出现mean.npy文件

2.编写labels.txt文件

labels.txt

buldings
dinosaur
elephant
flower
horse

它是一个类别名称映射文件,共5行,每行一个类别名称

3.利用python脚本生成deploy.prototxt文件

deploy.py

# -*- coding: utf-8 -*-

from caffe import layers as L,params as P,to_proto
root='/home/cyj/'
deploy=root+'caffe/examples/myfile/deploy.prototxt'    #文件保存路径

def create_deploy():
    #少了第一层,data层
    conv1=L.Convolution(bottom='data', kernel_size=5, stride=1,num_output=20, pad=0,weight_filler=dict(type='xavier'))
    pool1=L.Pooling(conv1, pool=P.Pooling.MAX, kernel_size=2, stride=2)
    conv2=L.Convolution(pool1, kernel_size=5, stride=1,num_output=50, pad=0,weight_filler=dict(type='xavier'))
    pool2=L.Pooling(conv2, pool=P.Pooling.MAX, kernel_size=2, stride=2)
    fc3=L.InnerProduct(pool2, num_output=500,weight_filler=dict(type='xavier'))
    relu3=L.ReLU(fc3, in_place=True)
    fc4 = L.InnerProduct(relu3, num_output=10,weight_filler=dict(type='xavier'))
    #最后没有accuracy层,但有一个Softmax层
    prob=L.Softmax(fc4)
    return to_proto(prob)
def write_deploy(): 
    with open(deploy, 'w') as f:
        f.write('name:"Lenet"\n')
        f.write('input:"data"\n')
        f.write('input_dim:1\n')
        f.write('input_dim:3\n')
        f.write('input_dim:28\n')
        f.write('input_dim:28\n')
        f.write(str(create_deploy()))
if __name__ == '__main__':
    write_deploy()

4.编写python接口执行类别预测

py-myclassify-1.py

#coding=utf-8

import caffe
import numpy as np
root='/home/cyj/'   #根目录
deploy=root + 'caffe/examples/myfile/deploy.prototxt'    #deploy文件
caffe_model=root + 'caffe/examples/myfile/caffenet_train_iter_500.caffemodel'   #训练好的 caffemodel
img=root+'caffe/examples/myfile/4.jpg'    #随机找的一张待测图片
labels_filename = root + 'caffe/examples/myfile/labels.txt'  #类别名称文件,将数字标签转换回类别名称
mean_file = root + 'caffe/examples/myfile/mean.npy'     #均值文件

net = caffe.Net(deploy,caffe_model,caffe.TEST)   #加载model和network

#图片预处理设置
transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape})  #设定图片的shape格式(1,3,28,28)
transformer.set_transpose('data', (2,0,1))    #改变维度的顺序,由原始图片(28,28,3)变为(3,28,28)
transformer.set_mean('data', np.load(mean_file).mean(1).mean(1))    #减去均值,前面训练模型时没有减均值,这儿就不用
transformer.set_raw_scale('data', 255)    # 缩放到【0,255】之间
transformer.set_channel_swap('data', (2,1,0))   #交换通道,将图片由RGB变为BGR

im=caffe.io.load_image(img)                   #加载图片
net.blobs['data'].data[...] = transformer.preprocess('data',im)      #执行上面设置的图片预处理操作,并将图片载入到blob中

#执行测试
out = net.forward()

labels = np.loadtxt(labels_filename, str, delimiter='\t')   #读取类别名称文件
prob= net.blobs['Softmax1'].data[0].flatten() #取出最后一层(Softmax)属于某个类别的概率值,并打印
print prob
order=prob.argsort()[-1]  #将概率值排序,取出最大值所在的序号 
print 'the class is:',labels[order]   #将该序号转换成对应的类别名称,并打印

测试图片为
caffe +ubuntu16.04基于CaffeNet网络框架训练图片进行分类_第10张图片

结果为
caffe +ubuntu16.04基于CaffeNet网络框架训练图片进行分类_第11张图片

你可能感兴趣的:(深度学习)