对官方例程中所用到的Python接口的用法做一个归纳,方便查询(并不是所有,只是例程中出现过的)。
import sys # 用于管理sys.path,也就是python的搜索路径,如:sys.path.append()或者.insert()都是达到临时添加的效果,不过.insert()可以设置优先级(列表的前后位置)
import os # 用于路径目录方面的操作,如os.path.isfile(),os.chdir()改变当前工作目录
import os.path as osp # 简写模式
import tempfile # 管理临时文件
import pandas as pd # 用于数据分析,如pd.read_hdf(),pd.DataFrame(),pd.Series()
import numpy as np
import matplotlib.pyplot as plt # 绘图,常见参数设置有'figure.figsize'、'image.cmap'
from pylab import * # 结合pylot和numpy到单个命名空间,这对于交互式工作很方便,但是对于编程,建议将命名空间保持独立,也就是上面两行。
import caffe # 常用于加载已有网络模型
from caffe import layers as L, params as P # 用于访问和设置各种层类型
from caffe.proto import caffe_pb2 # 用于定义求解器
# 使用CPU模式
caffe.set_mode_cpu()
# 使用GPU模式
caffe.set_device(0) # 用于指定GPU设备
caffe.set_mode_gpu()
caffe.set_random_seed() # 固定随机种子用于复现
net = caffe.Net(model_def, # 定义模型架构的prototxt文件
model_weights, # 训练好的权重参数
caffe.TEST) # 使用模型的TEST模式
solver = caffe.SGDSolver('solver.prototxt') # 仅用于加载SGD求解器
solver = caffe.get_solver(solver_config_path) # 允许加载其他求解器类型
solver.net.copy_from(weights) # 从指定文件中加载权重
solver.test_nets[0].share_with(solver.net) # 共享权重
分为四步:实例化转换对象、设置转换参数、加载图像、调用对象转换格式
# 实例化
transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape})
# 设置转换参数
transformer.set_transpose('data', (2,0,1)) # 维度转换,如HxWxC to CxHxW
transformer.set_mean('data', mu) # 每个通道减去数据集的均值
transformer.set_raw_scale('data', 255) # 图像预处理时用在减去均值之前的缩放系数,如[0, 1]缩放到[0, 255]
transformer.set_input_scale('data', 0.017) # 图像预处理时用在减去均值之后的缩放系数
transformer.set_channel_swap('data', (2,1,0)) # 交换通道,如 RGB to BGR
# 加载输入图像
image = caffe.io.load_image('img_path') # 加载进来的图像像素值在[0,1]区间,RGB or grayscale
# 调用对象转换格式 resize->transpose->channel_swap->raw_scale->mean->input_scale
transformed_image = transformer.preprocess('data', image)
# 调用对象逆向转回格式 与上面预处理的操作顺序相反
image = transformer.deprocess('data', net.blobs['data'].data[0])
import caffe
import numpy as np
import sys
blob = caffe.proto.caffe_pb2.BlobProto()
data = open( sys.argv[1] , 'rb' ).read()
blob.ParseFromString(data)
arr = np.array( caffe.io.blobproto_to_array(blob) )
out = arr[0]
np.save( 'mean.npy' , out )
n = caffe.NetSpec() # 实例化网络模型
# 构建网络
n.data, n.label = L.Data(batch_size=batch_size, backend=P.Data.LMDB, source=lmdb,
n.data, n.label = L.HDF5Data(batch_size=batch_size, source=hdf5, ntop=2)
n.data, n.label = L.ImageData(
transform_param=dict(mirror='',crop_size,mean_file/mean_value,shuffle,scale),
source=list_path,
batch_size=50, new_height=256, new_width=256, ntop=2,root_folder='')
n.data = L.DummyData(shape=dict(dim=[1, 3, 227, 227])) # 虚拟数据层,常用于调试阶段
# 使用自定义的Python层
n.data, n.label = L.Python(module = 'layers_class_name', # 该Python层的类名
ntop = 2, # 顶层数量
param_str=str(layer_params)) # 层参数
n.conv = L.Convolution(bottom, kernel_size=ks, stride=stride,
num_output=nout, pad=pad, group=group,
param=param, weight_filler=weight_filler,
n.pool = L.Pooling(bottom, pool=P.Pooling.MAX, kernel_size=ks, stride=stride)
......
n.fc = L.InnerProduct(bottom, num_output=nout, param=param,
weight_filler=weight_filler,
bias_filler=bias_filler)
n.relu = L.ReLU(bottom, in_place=True)
n.drop = L.Dropout(bottom, in_place=True)
n.norm = L.LRN(bottom, local_size=5, alpha=1e-4, beta=0.75)
n.loss = L.SoftmaxWithLoss(bottom, n.label) # 多类别损失
n.loss = L.SigmoidCrossEntropyLoss(n.score, n.label) # 用于多标签损失
n.acc = L.Accuracy(bottom, n.label)
n.probs = L.Softmax(bottom)
n.__setattr__(new_name, old_layer_name) # 用于改名
# 发布为prototxt格式
n.to_proto() # 注:写入文件时要使用str()
from caffe.proto import caffe_pb2
s = caffe_pb2.SolverParameter()
# 为重现试验设置随机种子
# 控制训练过程的随机
s.random_seed = 0xCAFFE
s.train_net = train_net_path # 指定网络训练配置文件的位置
s.test_net.append(test_net_path) # 指定网络测试配置文件的位置,可以添加多个测试网络
s.test_interval = 500 # 每训练500迭代,测试一次
s.test_iter.append(100) # 每次测试时都要测试100个batch取平均
s.iter_size = 1 # 处理batch_size*iter_size个数据后,更新一次参数
s.max_iter = 10000 # 最大迭代次数
# 编辑这里来尝试不同的求解器
# 求解器类型包括 "SGD", "Adam", "Nesterov" 等
s.type = "SGD"
# 设置基础学习率
s.base_lr = 0.01
# 设置momentum来加速学习,通过将当前和之前的updates进行加权平均
s.momentum = 0.9
# 设置权重衰减系数来正则化避免过拟合
s.weight_decay = 5e-4
# 设置`lr_policy`来定义学习率在训练期间如何变化。
s.lr_policy = 'inv'
s.gamma = 0.0001
s.power = 0.75
# 保持学习率不变(与自适应方法相对立)
# s.lr_policy = 'fixed'
# 每迭代stepsize次,学习率乘以gamma
s.lr_policy = 'step'
s.gamma = 0.1
s.stepsize = 20000
# 每迭代1000次显示当前训练损失和精度
s.display = 1000
# 每5K次迭代保存一次快照
s.snapshot = 5000
s.snapshot_prefix = 'mnist/custom_net'
# 设置在CPU还是GPU上训练
s.solver_mode = caffe_pb2.SolverParameter.GPU 或 caffe_pb2.SolverParameter.CPU
各层的输入/输出数据均存储在
net.blobs['layer_name']
中,一个blob存储了两块数据‘data’
和‘diff’
,分别代表普通数据和梯度。
# 每层的blobs形如
net.blobs['layer_name'](N, # 一个batch的大小,每层都一样
C, # 通道数,取决于卷积核数目(数据层取决于输入)
H, W) # 图像的高宽,根据公式计算
# 迭代打印出各层输出的shape
for layer_name, blob in net.blobs.iteritems():
print layer_name + '\t' + str(blob.data.shape)
各层的权重/偏置均存储在
net.params['layer_name']
,net.params['layer_name'][0]
为权重,net.params['layer_name'][1]
为偏置
# 各层的params形如
net.params['layer_name'][0](output_channels, # 输出通道数
input_channels, # 输入通道数
filter_height, filter_width) # 卷积核高宽
net.params['layer_name'][1](output_channels,) # 输出通道数
# 迭代打印出各层参数的shape
for layer_name, param in net.params.iteritems():
print layer_name + '\t' + str(param[0].data.shape), str(param[1].data.shape)
net.name # 网络的名称
下面列举出一些读/写数据的examples,各操作存在共性
# reshape
net.blobs['data'].reshape(n, c, h, w)
# 访问各层数据
net.blobs['data'].data[...] = transformed_image # 给输入数据层赋值
net.blobs['data'].data.copy() # copy数据
feat = net.blobs['conv1'].data[0, :36] # 取conv1层batch中的第1张图所对应的前36个通道
output_prob = output['prob'][0] # 读取一个batch中第一幅图的最后输出层'prob'的概率
net.blobs['conv'].data.min(), net.blobs['conv'].data.max() # 取大,取小
filters = net.params['conv1'][0].data # 读取卷积核权重数据
# 迭代打印出各层输出的shape
[(k, v.data.shape) for k, v in solver.net.blobs.items()]
# 迭代打印出各层参数的shape
[(k, v[0].data.shape) for k, v in solver.net.params.items()]
solver.net.blobs['label'].data[:10] # 取训练网络‘label’层前10个数据
solver.test_nets[0].blobs['data'].data[:8, 0] # 取测试网络‘data’层一个batch的前8个数据,第一个通道
solver.test_nets[0].blobs['data'].num # 获取数据个数(这里为batch_size)
solver.net.params['conv1'][0].diff[:, 0] # 取conv1层权重的梯度
solver.net.params['conv1'][0].data.copy() # 数据深拷贝
solver.net.layers[0]
solver.iter # 迭代次数
output = net.forward() # 做一次前向传播
net.forward(start='conv1') # 拿上一个batch做一次前向传播(不加载新的batch)
output = net.forward_all(data=data) # 批量前向传播,一次装载所有数据
net.save('weights_name.caffemodel')
solver.net.forward() # 训练网络,做一次前向传播
solver.net.backward() # 训练网络,做一次反向传播
solver.test_nets[0].forward() # 测试网络(可能会多于一个)
solver.test_nets[0].forward(start='conv1') # 拿上一个batch测试网络(不加载新的batch)
solver.step(1) # 对一个batch的数据迭代一次,包括forward、backward、update
solver.solve() # 根据solver文件中最大迭代次数的限制,训练完整的model
solver.net.save(weights_name) # 保存权重参数