1、 在WIN10编译GPU版本的caffe
详见本人其他博客【Caffe-GPU】Caffe+Python3+CUDA8+CUDNN5+win10+VS2015+Mnist 配置
2、 caffe编译所得
如果在第一步中正常编译了caffe,将在 caffe/build/tools/Release 等目录下生成很多有用工具,如图所示,
其中,caffe.exe用于训练,compute_image_mean.exe用于计算数据集的均值,convert_imageset.exe用于将图片数据集转换成lmdb等格式。
3、数据集准备
例如,为了识别数字0-9及大写字母A-Z,一共36类,先在 caffe/examples 目录下创建char文件夹,并在char目录下创建 dataset-09AZ 文件夹,并在 dataset-09AZ 文件夹下分别创建train、val文件夹,train用于存放训练集,val用于存放测试集,然后在train、val中创建0-35共36个文件夹,分别代表36种类别,在每个文件夹中放入对应类别的图片,注意的是,这里文件夹名称全部为数字,0中放入0的图片,1中放入1的图片,10中放入A的图片,以此类推。
4、生成图片列表文件
利用以下python脚本生成训练样本和测试样本的图片列表,执行前将 root_data_path 改为train、val文件夹的上级目录,即 dataset-09AZ。
# -*- coding: utf-8 -*-
import os
#数据集根目录所在路径
root_data_path = r"D:\caffe-gpu\caffe-windows\examples\char_wt\dataset-09AZ"
#输出的TXT文件路径
traintxt_path = root_data_path + "\\" + "train.txt"
valtxt_path = root_data_path + "\\" + "val.txt"
#如果存在之前生成的TXT文件,先把它们删除
if os.path.exists(traintxt_path):
os.remove(traintxt_path)
if os.path.exists(valtxt_path):
os.remove(valtxt_path)
#返回数据集文件夹下的子文件夹
filenames = os.listdir(root_data_path) #["train", "val"]
#打开要存储的TXT文件
file_train = open(traintxt_path, "w")
file_val = open(valtxt_path, "w")
if len(filenames) > 0:
for fn in filenames:
#数据集根目录下的子文件夹路径,train和val的绝对路径
full_filename = os.path.join(root_data_path, fn)
#print(full_filename)
#print(fn)
# 判断是训练集文件夹,还是验证集文件夹
if fn == "train":
#找出训练集文件夹下的子文件夹名字,是每个类别的文件夹,0表示狗,1表示猫
file = os.listdir(full_filename) #["0", "1"]
for name in file:
#获得train文件夹下的子文件夹“0”和“1”的绝对路径
temp = os.path.join(full_filename, name)
for img in os.listdir(temp): #分别遍历两个文件夹["0", "1"]下的所有图像
#将图像的信息写入到train.txt文件
file_train.write(root_data_path + "\\"+name + "\\" + img + " " + name + "\n")
elif fn == "val": #当进入到val文件夹后
#找出训练集文件夹下的子文件夹名字,是每个类别的文件夹,0表示狗,1表示猫
file = os.listdir(full_filename) #["0", "1"]
#print(file)
for name in file:
#获得train文件夹下的子文件夹“0”和“1”的绝对路径
temp = os.path.join(full_filename, name)
for img in os.listdir(temp): #分别遍历两个文件夹["0", "1"]下的所有图像
#将图像的信息写入到train.txt文件
file_val.write(root_data_path + "\\"+ name + "\\" + img + " " + name + "\n")
else:
print("存在train val以外的文件")
else:
print("该文件夹下不存在子文件夹")
file_train.close()
file_val.close()
执行完后,将在dataset-09AZ目录下生成train.txt、val.txt文件,
分别列出了训练集和测试集的图片路径及其类别标号,注意,此时列出的是路径是绝对路径,需要利用notepad的替换功能将其改为相对路径,如
5、转换为LMDB格式
创建create_train_lmdb.bat脚本,输入以下内容,其中convert_imageset_filepath是第2步中编译生成的convert_imageset.exe所在路径,trainset_path是训练集train所在路径,trainset_filelist是train.txt所在路径,同理,修改相应内容,创建create_val_lmdb.bat脚本,然后分别双击执行脚本,将生成train和val数据集的LMDB文件
6、计算均值文件
得到LMDB文件后,就可以计算训练集和测试集的均值了,设置均值能够加快训练速度,
创建Get-train-Meanfile.bat文件,输入以下内容
其中compute_mean_filepath就是上述第2步中编译生成的compute_image_mean.exe所在的路径,lmdb_path是上述第5步生成的lmdb文件的路径,meanfile_path用于指定需要生成的meanfile的名称及路径,按照相同的方法,可以分别生成train和val对应的均值文件
在生成完成时,在命令窗口还会分别得到三个通道的均值,如
在配置train_val.prototxt文件时,可以指定生成的均值文件,也可以直接设置各通道的均值。
7、配置train_val.prototxt文件
利caffe进行训练时,需要用到三个文件,分别是
train_val.prototxt 用于训练,定义了网络结构
solver.prototxt 用于训练,设置训练过程中的各种超参数
deploy.prototxt 用于部署,由train_val.prototxt修改而来
对于train_val.prototxt文件的配置,主要修改以下几个地方:
1)、分别设置train和val的均值或均值文件所在路径
2)、分别设置train和val的LMDB文件路径
3)、根据硬件能力设置batch_size
4)、根据实际情况,更改输出的类别数目,如果从头开始训练只需将 num_output 数目改为数据集的类别数目即可,如果是在已有模型上进行fine-tuning,则还需相应地更改最后一层的名称以其之后的相关输入输出的层名称。如下图所示,数据集类别为36,因此将num_output改为36,如果进行fine-tuning,还需将所有的 conv10 改为 conv10-char。注意,在部署时的 deploy.ptototxt 文件中也须进行相应的同步修改。
8、配置solver.prototxt文件
该文件主要用于设置训练时使用的一些超参数
其中,
- net 指定上一步中配置好的train_val.prototxt的路径
- test_iter 测试时需要迭代的次数,其值为测试集数据量除以测试阶段的batch_size
- test_interval 测试间隔,多久执行一次测试,通常在训练集全部迭代完一次后进行测试,其值为训练集数据量除以训练阶段的batch_size,取整数
- base_lr 基础学习率
- lr_policy 学习率变化规律
- power momentum stepsize 根据学习率变化规律来指定
- display 在终端显示的间隔
- max_iter 最大迭代次数
- weight_decay 权重衰减
- snapshot 快照,多久保存一次模型
- snapshot_prefix 模型保存的路径和前缀
- solver_mode 是否采用GPU
9、创建训练脚本
在caffe主目录创建训练脚本train.bat,输入以下内容
其中caffe.exe是编译生成的工具,–solver是上一步中配置的solver.prototxt路径,如果是fine-tuing,还需进一步指定–weights内容,即预训练模型路径,–gpu指定使用的gpu编号,最后的2>&1| tee train_caffenet_v1.1_063036.txt用于保存训练时的log,便于后续生成loss曲线。创建完成后,双击train.bat即可开始训练,训练时将按照solver.prototxt中snapshot_prefix指定的路径生成相应的caffemodel文件。
10、模型测试
在模型生成后,需要对模型进行测试。移动到caffe/python目录,在该目录创建test文件夹,并将所有需要测试的图片放入该文件夹,每张图片的命名以其类别开始,如
然后在python文件夹中创建classify.py文件,输入以下内容,并按照实际情况分别指定
caffe_root 、deploy、caffe_model、labels_filename、mean_file、dir路径,然后执行即可输出准确率
#!/usr/bin/env python
import numpy as np
import os
import sys
import argparse
import glob
import time
import caffe
caffe_root = 'D:/caffe-gpu-python3-unsamplelayer/caffe-windows/python' # 指定 caffe 的路径
sys.path.insert(0,caffe_root+'python')
caffe.set_mode_gpu()
deploy = 'caffenet/deploy.prototxt' ##
caffe_model = 'caffenet/caffenet-nft-063036__iter_2000.caffemodel' ##
labels_filename = 'caffenet/labels-char-36.txt'
mean_file = 'mean-0630363.npy' # 由 imagenet_mean.binaryproto 转换来
dir='test/'
ok_num = 0
ng_num = 0
ng_imgname = []
ng_imgname_label = []
#预读待分类的图片
filelist=[]
filenames=os.listdir(dir) #返回指定目录下的所有文件和目录名
for fn in filenames:
fullfilename=os.path.join(dir,fn) #os.path.join--拼接路径
filelist.append(fullfilename) #filelist里存储每个图片的路径
net = caffe.Net(deploy, caffe_model, caffe.TEST)
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))
#加载图片
for i in range(0,len(filelist)):
img=filelist[i] #获取当前图片的路径
print(filenames[i]) #打印当前图片的名称
#t_label = filenames[i].split('_')[0] #truelable
t_label = filenames[i][0] #truelable
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['prob'].data[0].flatten() #取出最后一层(prob)属于某个类标的概率值,'prob'为最后一层的名称
#print prob
index1=prob.argsort()[-1] #获取最大概率值对应的index
#index2=prob.argsort()[-2] #获取第二大概率值对应的index
#index3=prob.argsort()[-3] #获取第三大概率值对应的index
#index4=prob.argsort()[-4] #获取第四大概率值对应的index
print(t_label)
print(labels[index1],'--',prob[index1]) #输出label--prob
#print(labels[index2],'--',prob[index2])
#print(labels[index3],'--',prob[index3])
#print(labels[index4],'--',prob[index4])
if t_label == labels[index1] :
print("OK")
ok_num=ok_num+1
else:
print("NG")
ng_imgname.append(filenames[i])
ng_imgname_label.append(labels[index1])
ng_num=ng_num+1
print("total : %d"% len(filelist) )
print("ok_num : %d"% ok_num )
print("ng_num : %d"% ng_num )
p = ok_num / len(filelist)
print("预测正确率为:%f"%p)
for i in range(0,len(ng_imgname)):
print(ng_imgname[i])
print(ng_imgname_label[i])
值得注意的是,上述脚本中mean_file为npy格式的,需要利用以下文件将binaryproto转换为npy格式
import caffe
import numpy as np
# 待转换的pb格式图像均值文件路径
MEAN_PROTO_PATH = 'char_0630363_train_mean.binaryproto'
# 转换后的numpy格式图像均值文件路径
MEAN_NPY_PATH = 'mean-0630363.npy'
# 创建protobuf blob
blob = caffe.proto.caffe_pb2.BlobProto()
# 读入mean.binaryproto文件内容
data = open(MEAN_PROTO_PATH, 'rb' ).read()
# 解析文件内容到blob
blob.ParseFromString(data)
# 将blob中的均值转换成numpy格式,array的shape (mean_number,channel, hight, width)
array = np.array(caffe.io.blobproto_to_array(blob))
# 一个array中可以有多组均值存在,故需要通过下标选择其中一组均值
mean_npy = array[0]
np.save(MEAN_NPY_PATH ,mean_npy)
https://www.cnblogs.com/denny402/p/5083300.html
https://www.cnblogs.com/louyihang-loves-baiyan/p/5038758.html