引言
记录学习官网的例程中的一些重要语句,遇到的问题等,内容分散,建议顺序查看。
主要是调用Caffe的Python接口
源文件就在{caffe_root}/examples中,安装sudo pip install jupyter
打开即可运行,初学者最好是放在它指定的目录,如,否则要改很多路径。
注:eaxmples是用jupyter notebook写的,部分Cell中出现了一些特殊的用法:
1. 感叹号‘!’:用于执行系统命令,如 !pwd
2. 百分号‘%’:用法太多,如 %matplotlib inline 显示绘图窗口 详见Jupyter Notebook Viewer
目录
- 引言
- 目录
- 用Python接口学习LeNet
- 1. 创建网络
- 2. 加载和检查求解器
- 2.1. 选择训练设备,加载求解器
- 2.2. 检查网络的中间输出和参数的维度
- 2.3. 运行一次train & test 来检查是否正常
- 2.4. 用一个小技巧来平铺前八张图片
- 3. 迭代求解器
- 4. 写一个常规训练循环
- 5. 架构实验和优化
- 用Python接口学习LeNet
- 上一篇:Caffe实战之Python接口系列(一)Classification_Visualization
- 下一篇:Caffe实战之Python接口系列(三)Fine-tuning a Pretrained Network
用Python接口学习LeNet
1. 创建网络
from caffe import layers as L, params as Pdef lenet(lmdb, batch_size):# our version of LeNet: a series of linear and simple nonlinear transformations 定义两个参数,支持train和test net设置不同的值n = caffe.NetSpec()n.data, n.label = L.Data(batch_size=batch_size, backend=P.Data.LMDB, source=lmdb,transform_param=dict(scale=1./255), ntop=2)n.conv1 = L.Convolution(n.data, kernel_size=5, num_output=20, weight_filler=dict(type='xavier'))n.pool1 = L.Pooling(n.conv1, kernel_size=2, stride=2, pool=P.Pooling.MAX)n.conv2 = L.Convolution(n.pool1, kernel_size=5, num_output=50, weight_filler=dict(type='xavier'))n.pool2 = L.Pooling(n.conv2, kernel_size=2, stride=2, pool=P.Pooling.MAX)n.fc1 = L.InnerProduct(n.pool2, num_output=500, weight_filler=dict(type='xavier'))n.relu1 = L.ReLU(n.fc1, in_place=True)n.score = L.InnerProduct(n.relu1, num_output=10, weight_filler=dict(type='xavier'))n.loss = L.SoftmaxWithLoss(n.score, n.label)return n.to_proto()
# 调用上面的函数,将网络定义写入文件
with open('mnist/lenet_auto_train.prototxt', 'w') as f:f.write(str(lenet('mnist/mnist_train_lmdb', 64))) with open('mnist/lenet_auto_test.prototxt', 'w') as f:f.write(str(lenet('mnist/mnist_test_lmdb', 100)))
2. 加载和检查求解器
2.1. 选择训练设备,加载求解器
caffe.set_device(0)
caffe.set_mode_gpu()### load the solver and create train and test nets
solver = None # ignore this workaround for lmdb data (can't instantiate two solvers on the same data)
solver = caffe.SGDSolver('mnist/lenet_auto_solver.prototxt')
2.2. 检查网络的中间输出和参数的维度
# each output is (batch size, feature dim, spatial dim)
[(k, v.data.shape) for k, v in solver.net.blobs.items()]# just print the weight sizes (we'll omit the biases)
[(k, v[0].data.shape) for k, v in solver.net.params.items()]
2.3. 运行一次train & test 来检查是否正常
solver.net.forward() # train net
solver.test_nets[0].forward() # test net (there can be more than one)
2.4. 用一个小技巧来平铺前八张图片
# we use a little trick to tile the first eight images
imshow(solver.net.blobs['data'].data[:10, 0].transpose(1, 0, 2).reshape(28, 10*28), cmap='gray'); axis('off')
print 'train labels:', solver.net.blobs['label'].data[:10]
# 测试网络的图片
imshow(solver.test_nets[0].blobs['data'].data[:8, 0].transpose(1, 0, 2).reshape(28, 8*28), cmap='gray'); axis('off')
print 'test labels:', solver.test_nets[0].blobs['label'].data[:8]
3. 迭代求解器
- 迭代一次(一个minibatch):
solver.step(1)
可视化conv1层20个5x5的卷积核:
imshow(solver.net.params['conv1'][0].diff[:, 0].reshape(4, 5, 5, 5).transpose(0, 2, 1, 3).reshape(4*5, 5*5), cmap='gray'); axis('off')
4. 写一个常规训练循环
- 记录日志
- 迭代一段时间保存一次快照,在solver.prototxt中设置
设置多长间隔测试一次
niter = 200 test_interval = 25# losses will also be stored in the logtrain_loss = zeros(niter) test_acc = zeros(int(np.ceil(niter / test_interval))) output = zeros((niter, 8, 10))# the main solver loopfor it in range(niter):solver.step(1) # SGD by Caffe# store the train losstrain_loss[it] = solver.net.blobs['loss'].data# store the output on the first test batch# (start the forward pass at conv1 to avoid loading new data)solver.test_nets[0].forward(start='conv1') # 测试刚刚训练的那组数据output[it] = solver.test_nets[0].blobs['score'].data[:8]# run a full test every so often# (Caffe can also do this for us and write to a log, but we show here# how to do it directly in Python, where more complicated things are easier.)if it % test_interval == 0:print 'Iteration', it, 'testing...'correct = 0for test_it in range(100):solver.test_nets[0].forward()correct += sum(solver.test_nets[0].blobs['score'].data.argmax(1)== solver.test_nets[0].blobs['label'].data)test_acc[it // test_interval] = correct / 1e4
注:solver.step(1)包括了三个阶段-forward,backward,update
画出训练损失和测试精度
_, ax1 = subplots() ax2 = ax1.twinx() ax1.plot(arange(niter), train_loss) ax2.plot(test_interval * arange(len(test_acc)), test_acc, 'r') ax1.set_xlabel('iteration') ax1.set_ylabel('train loss') ax2.set_ylabel('test accuracy') ax2.set_title('Test Accuracy: {:.2f}'.format(test_acc[-1]))
查看预测分数的演化
将每次迭代保存的训练batch中的前八张图片的分数打印出来,X轴为迭代次数,Y轴为对应标签。for i in range(8): figure(figsize=(2, 2)) imshow(solver.test_nets[0].blobs['data'].data[i, 0], cmap='gray') figure(figsize=(10, 2)) imshow(output[:50, i].T, interpolation='nearest', cmap='gray') xlabel('iteration') ylabel('label')
前面是原始的输出分数,还可以画出经过softmax计算的概率向量,如下:
for i in range(8): figure(figsize=(2, 2)) imshow(solver.test_nets[0].blobs['data'].data[i, 0], cmap='gray') figure(figsize=(10, 2)) imshow(exp(output[:50, i].T) / exp(output[:50, i].T).sum(0), interpolation='nearest', cmap='gray') xlabel('iteration') ylabel('label')
5. 架构实验和优化
- 定义新的架构用于对比
- 微调基础学习率 base_lr
- 将求解器类型从 SGD 切换到自适应方法,如 AdaDelta or Adam
其中网络的配置和上面没有太大差别,下面介绍求解器的定义。
### define solver
from caffe.proto import caffe_pb2
s = caffe_pb2.SolverParameter()# Set a seed for reproducible experiments:
# this controls for randomization in training.
s.random_seed = 0xCAFFE# Specify locations of the train and (maybe) test networks.
s.train_net = train_net_path
s.test_net.append(test_net_path)
s.test_interval = 500 # Test after every 500 training iterations.
s.test_iter.append(100) # Test on 100 batches each time we test.s.max_iter = 10000 # no. of times to update the net (training iterations)# EDIT HERE to try different solvers
# solver types include "SGD", "Adam", and "Nesterov" among others.
s.type = "SGD"# Set the initial learning rate for SGD.
s.base_lr = 0.01 # EDIT HERE to try different learning rates
# Set momentum to accelerate learning by
# taking weighted average of current and previous updates.
s.momentum = 0.9
# Set weight decay to regularize and prevent overfitting
s.weight_decay = 5e-4# Set `lr_policy` to define how the learning rate changes during training.
# This is the same policy as our default LeNet.
s.lr_policy = 'inv'
s.gamma = 0.0001
s.power = 0.75
# EDIT HERE to try the fixed rate (and compare with adaptive solvers)
# `fixed` is the simplest policy that keeps the learning rate constant.
# s.lr_policy = 'fixed'# Display the current training loss and accuracy every 1000 iterations.
s.display = 1000# Snapshots are files used to store networks we've trained.
# We'll snapshot every 5K iterations -- twice during training.
s.snapshot = 5000
s.snapshot_prefix = 'mnist/custom_net'# Train on the GPU
s.solver_mode = caffe_pb2.SolverParameter.GPU# Write the solver to a temporary file and return its filename.
with open(solver_config_path, 'w') as f:f.write(str(s))### load the solver and create train and test nets
solver = None # ignore this workaround for lmdb data (can't instantiate two solvers on the same data)
solver = caffe.get_solver(solver_config_path)