caffe是C++语言写的,可能很多人不太熟悉,因此想用更简单的脚本语言来实现。caffe提供matlab接口和python接口,这两种语言就非常简单,而且非常容易进行可视化,使得学习更加快速,理解更加深入。
以上这些操作都是训练之前的预处理操作,不管是用什么接口,都要用到。
首先,我们需要掌握的,就是如何写配置文件,通过下面的代码来学习:
#!/usr/bin/env python
# encoding: utf-8
'''
@author: lele Ye
@contact: 1750112338@qq.com
@software: pycharm 2018.2
@file: 01LMDB和配置生成网络文件.py
@time: 2018/10/12 19:27
@desc:
'''
from caffe import layers as L, params as P, to_proto
import os
path = '/home/yeler082/caffe_learning/data/' # 保存数据和配置文件的路径
train_lmdb = path + 'train_db' # 训练数据LMDB文件的位置
val_lmdb = path + 'val_db' # 验证数据LMDB文件的位置
mean_file = path + 'mean.binaryproto' # 均值文件的位置
train_proto = path + 'train.prototxt' # 生成的训练配置文件保存的位置
val_proto = path + 'val.prototxt' # 生成的验证配置文件保存的位置
# 编写一个函数,用于生成网络
def create_net(lmdb, batch_size, include_acc=False):
# 创建第一层:数据层。向上传递两类数据:图片数据和对应的标签
data, label = L.Data(source=lmdb, backend=P.Data.LMDB, batch_size=batch_size, ntop=2,
transform_param=dict(crop_size=40, mean_file=mean_file, mirror=True))
# 创建第二屋:卷积层
conv1 = L.Convolution(data, kernel_size=5, stride=1, num_output=16, pad=2, weight_filler=dict(type='xavier'))
# 创建激活函数层
relu1 = L.ReLU(conv1, in_place=True)
# 创建池化层
pool1 = L.Pooling(relu1, pool=P.Pooling.MAX, kernel_size=3, stride=2)
conv2 = L.Convolution(pool1, kernel_size=3, stride=1, num_output=32, pad=1, weight_filler=dict(type='xavier'))
relu2 = L.ReLU(conv2, in_place=True)
pool2 = L.Pooling(relu2, pool=P.Pooling.MAX, kernel_size=3, stride=2)
# 创建一个全连接层
fc3 = L.InnerProduct(pool2, num_output=1024, weight_filler=dict(type='xavier'))
relu3 = L.ReLU(fc3, in_place=True)
# 创建一个dropout层
drop3 = L.Dropout(relu3, in_place=True)
fc4 = L.InnerProduct(drop3, num_output=10, weight_filler=dict(type='xavier'))
# 创建一个softmax层
loss = L.SoftmaxWithLoss(fc4, label)
if include_acc: # 在训练阶段,不需要accuracy层,但是在验证阶段,是需要的
acc = L.Accuracy(fc4, label)
return to_proto(loss, acc)
else:
return to_proto(loss)
def write_net():
if not os.path.exists(path):
os.mkdir(path)
# 将以上的设置写入到prototxt文件
with open(train_proto, 'w') as f:
f.write(str(create_net(train_lmdb, batch_size=64)))
# 写入配置文件
with open(val_proto, 'w') as f:
f.write(str(create_net(val_lmdb, batch_size=32, include_acc=True)))
if __name__ == '__main__':
write_net()
print ("generate the prototxt in "+path)
通过上面这个文件的执行,我们就会得到两个配置文件:train.prototxt和val.prototxt,分别用于训练阶段和验证阶段。
这种方式生成配置文件,必须有个前提,就是要先把原始图片转换成LMDB文件才行。如果我们已经把原始图片做成了一个列表清单(txt文件,一行一张图片),则可以不用LMDB格式作为输入数据,可以用ImageData作为数据源输入,代码如下:
#!/usr/bin/env python
# encoding: utf-8
'''
@author: lele Ye
@contact: 1750112338@qq.com
@software: pycharm 2018.2
@file: 02txt和配置生成网络文件.py
@time: 2018/10/12 19:41
@desc:
'''
from caffe import layers as L, params as P, to_proto
import os
path = '/home/yeler082/caffe_learning/data/'
train_list = path + 'train.txt'
val_list = path + 'val.txt'
train_proto = path + 'train_02.prototxt'
val_proto = path + 'val_02.prototxt'
def create_net(img_list, batch_size, include_acc=False):
data, label = L.ImageData(source=img_list, batch_size=batch_size, new_width=48, new_height=48, ntop=2,
transform_param=dict(crop_size=40, mirror=True))
conv1 = L.Convolution(data, kernel_size=5, stride=1, num_output=16, pad=2, weight_filler=dict(type='xavier'))
relu1 = L.ReLU(conv1, in_place=True)
pool1 = L.Pooling(relu1, pool=P.Pooling.MAX, kernel_size=3, stride=2)
conv2 = L.Convolution(pool1, kernel_size=53, stride=1, num_output=32, pad=1, weight_filler=dict(type='xavier'))
relu2 = L.ReLU(conv2, in_place=True)
pool2 = L.Pooling(relu2, pool=P.Pooling.MAX, kernel_size=3, stride=2)
conv3 = L.Convolution(pool2, kernel_size=53, stride=1, num_output=32, pad=1, weight_filler=dict(type='xavier'))
relu3 = L.ReLU(conv3, in_place=True)
pool3 = L.Pooling(relu3, pool=P.Pooling.MAX, kernel_size=3, stride=2)
fc4 = L.InnerProduct(pool3, num_output=1024, weight_filler=dict(type='xavier'))
relu4 = L.ReLU(fc4, in_place=True)
drop4 = L.Dropout(relu4, in_place=True)
fc5 = L.InnerProduct(drop4, num_output=7, weight_filler=dict(type='xavier'))
loss = L.SoftmaxWithLoss(fc5, label)
if include_acc:
acc = L.Accuracy(fc5, label)
return to_proto(loss, acc)
else:
return to_proto(loss)
def write_net():
if not os.path.exists(path):
os.mkdir(path)
#
with open(train_proto, 'w') as f:
f.write(str(create_net(train_list, batch_size=64)))
#
with open(val_proto, 'w') as f:
f.write(str(create_net(val_list, batch_size=32, include_acc=True)))
if __name__ == '__main__':
write_net()
print ("generate the prototxt in "+path)
这是利用第二种方法生成的训练配置文件。
即第一层由原来的Data类型,变成了ImageData类型,不需要LMDB文件和均值文件,但需要一个txt文件 。