还没有仔细分析各个接口的方法,只给出了示例
思考:python书写网络层,如何用C++来跑网络呢?
自定义网络层
卷积层是对数据进行卷积操作,如果我不想进行卷积运算,而是简单的像素加减,可以通过python自定义网络层来实现。
python用来写网络C++用来跑网络
准备工作
- step1 修改caffe/Makefile.config文件,且取消注销代码:with_python_layer :=1
- step2 重新编译caffe
cd caffe
make clean
make all -j8
make pycaffe
- step3 修改网络层的参数type设置成python,python_param{},下述代码给予对比
# 使用python
layer {
type: 'Python'
name: 'loss'
top: 'loss'
bottom: 'ipx'
bottom: 'ipy'
python_param {
# the module name -- usually the filename -- that needs to be in $PYTHONPATH
module: 'pyloss'
# the layer name -- the class name in the module
# 这个参数的名字需要和接下来自定义层的类名相同
layer: 'MyLayer'
}
# set loss weight so Caffe knows this is a loss layer.
# since PythonLayer inherits directly from Layer, this isn't automatically
# known to Caffe
loss_weight: 1
}
# 不用python
layer {
name: "conv1"
type: "Convolution"
bottom: "data"
top: "conv1"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
convolution_param {
num_output: 20
kernel_size: 5
stride: 1
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
使用python自定义层与调用
这里在ubuntu18中使用pycharm
自定义层
import sys
caffe_root = "/home/tyd/caffe/"
sys.path.insert(0, caffe_root+'python')
import caffe
import numpy as np
import yaml #这个库就是把我们的参数做一个传递 这个库linux下一直在
import cv2
# MyLayer和上边的代码中的python_param{layer:MyLayer}是对应的
class MyLayer(caffe.Layer): #千万注意,这里看一下下图, 这里是个继承关系
#这里的四个函数不是随便定义的,而是caffe给出来规则
def setup(self, bottom, top): #做一下准备工作
self.num = yaml.load(self.param_str)['num']
print("Parament num: ", self.num)
def reshape(self, bottom, top): #对你的数据做一些维度的变化
pass #这里不执行任何操作, pass就是字面意思,跳过
# 因为我们自己写的层, 所以我们要把前向传播和反向传播定义好
# 这里举个例子, 因为是自定义所以*度比较大, 我们这里先实现一个特征图每个元素都加21, 如下图的param_str:"num:21"
# 在前向传播的时候让特征图上的所有值都加上21
# 这里的top就是prototxt文件中的输出意思, bottom就是输入的意思
# 这里的top[0]就是第0个输出
def forward(self, bottom, top):
top[0].reshape(*bottom[0].shape)
print bottom[0].data.shape
print bottom[0].data
top[0].data[...] = bottom[0].data + self.num #输出的数据= 输入数据+自己定义的21
print top[0].data[...] # ...就是全部的意思
def backward(self, top, propagate_down, bottom):
pass #这里选择不做反向传播
生成.prototxt网络配置文件
如果你的网络层很多,几十层,难道你要每次都手写一个layer{}吗? 或者不断的复制粘贴吗
太麻烦了, 用代码把配置文件生成出来
import sys
caffe_root='/home/tyd/caffe/'
sys.path.insert(0,caffe_root+'python')
from caffe import layers as L
from caffe import params as P
import caffe
def lenet(lmdb,batch_size):
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_filter=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_filter=dict(type='xavier'))
# pooling层需要说明是均值还是max
n.pool2 = L.Pooling(n.conv2, kernel_size=2, stride=2, pool=P.Pooling.MAX)
n.ip1 = L.InnerProduct(n.pool2, num_output=500, weight_filter=dict(type='xavier'))
n.relu1 = L.ReLU(n.ip1, in_place=True)
n.ip2 = L.InnerProduct(n.relu1, num_output=10, weight_filter=dict(type='xavier'))
n.loss = L.SoftmaxWithLoss(n.ip2, n.label)
return n.to_proto()
# .to_proto()应该是方法函数
with open('lenet_auto_train.prototxt', 'w') as f:
f.write(str(lenet('examples/mnist/mnist_train_lmdb', 64)))
with open('lenet_auto_test.prototxt', 'w') as f:
f.write(str(lenet('examples/mnist/mnist_test_lmdb', 100)))
使用自定义层
# 接下来告诉你如何使用我们定义的这个python层
# 加载自定义的网络层
net = caffe.Net("conv.prototxt", caffe.TEST)
# 图片预处理
# 加载一张图片并转换成numpy格式
im = np.array(cv2.imread("timg.jpeg"))
# 图片是[width, height, channels]3个维度
# conv.prototxt配置文件是[batch, channels, width,height]4个维度
# 通过np.newaxis自动在axis=0处增加一个维度
im_input = im(np.newaxis, :, :]
# 这里的im_input.shape=(1, width, height, channels)
print im_input.shape
# 这里还需要修改每个维度的位置,通过transpose()直接对位调整就行了
im_input2 = im_input.transpose((0,3,1,2))
print im_input2.shape
# 接下来需要修改prototxt文件最前几行中的dim值,改成我们修改好的维度值
net.blobs['data'].reshape(*im_input2.shape)
# 把图片的数据放进去
net.blobs['data'].data[...] = im_input2
#执行forward方法
net.forward()
绘制loss函数曲线
把loss函数曲线画出来,或者accuracy rate曲线也画出来
import numpy as np
import matplotlib.pyplot as plt
import sys, os
caffe_root = '/home/tyd/caffe/'
sys.path.insert(0, caffe_root+'python')
import caffe
# caffe.set_device(0)
caffe.set_mode_cpu()
solver = caffe.SGDSolver('/home/tyd/caffe/examples/mnist/lenet_solver.prototxt')
niter = 1000
test_interval =200
train_loss = np.zeros(niter)
test_acc = np.zeros(int(np.ceil(niter / test_interval)))
for it in range(niter):
solver.step(1)
train_loss[it] = solver.net.blobs['loss'].data