主要参考(按顺序):
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是我自己创建的文件夹。
二、转换为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两个文本文件,里面就是图片的列表清单。
另外,也可以用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
what(): std::bad_alloc
已放弃 (核心已转储)
问题解决:我这边是由于前面create_lmdb.sh中路径填写错误,导致lbdb文件未正确生成。
数据集准备完毕。
四、创建模型并编写配置文件
模型用程序自带的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
训练过程出现一个错误~~继续解决
我首先尝试在train_val.prototxt中将batch_size设置为128,结果还是错,后来在solver.prototxt中设置solver_mode: CPU,然后程序跑成功,耗时三个多小时。
训练结束会生成xxx.caffemodel和xxx.solverstate分别存储训练过程的参数和中段的参数信息
六、利用生成的模型使用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
确实缺少版本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] #将该序号转换成对应的类别名称,并打印