Caffe通过Boost中的Boost.Python模块来支持使用Python定义Layer:
- 使用C++增加新的Layer繁琐、耗时而且很容易出错
- 开发速度与执行速度之间的trade-off
编译同时支持Python Layer的Caffe,方便更改使用。如果想要使用应进行以下配置:
如果是首次编译,修改Caffe根目录下的Makefile.cinfig,uncomment
WITH_PYTHON_LAYER:=1
python层的主要标志是:
python层具体格式以及参数可以参照。
添加python层
1.应该修改prototxt文件:
layer{
type:"Python"
name:"mylayer"
bottom:"norm1"
top:"mylayer"
python_param{
#python文件名
module:"mylayer"
#函数名
layer:"mylayer"
}
}
2.这里创建一个什么都不做的python层,仅仅把前一层的数据传给下一层。
在自己项目的目录下编写自己的python函数:
#!/usr/bin/env python
import sys
import caffe
class mylayer(caffe.Layer):
#什么都不做
def setup(self,bottom,top):
pass
#对输出数据进行形状变换,使输出数据和输入形状相同
def reshape(self,bottom,top):
top[0].reshape(*bottom[0].data.shape)
def forward(self,bottom,top):
#top[0].data[...]=bottom[0].data
#把输入数据赋值给输出
top[0].data[...]=bottom[0].data[:]
def backward(self,top,propagate_down,bottom):
for i in range(len(propagate_down)):
if not propagate_down[i]:
continue
#bottom[i].diff[...]=top[i].diff
#把高层的梯度赋值给底层,注意此处为反向传播
bottom[i].diff[...]=top[i].diff[:]
添加python的Loss层
1.修改.prototxt文件:
在文件的最后添加此层,注意删除原有的loss层,注意此层的输入。
layer{
type:"Python"
name:"loss"
top:"loss"
bottom:"fc9"
bottom:"label"
python_param{
module:"myloss"
layer:"myloss"
}
#set loss weight,so caffe know this is loss layer
loss_weight:1
}
2.添加python文件,位置同上:
import caffe
import numpy as np
class EuclideanLossLayer(caffe.Layer):
def setup(self, bottom, top):
# top是最后的loss值, bottom 中有两个值,一个网络的输出, 一个是label。
# check input pair
if len(bottom) != 2:
raise Exception("Need two inputs to compute distance.")
def reshape(self, bottom, top):
'''
在reshape中确定输出的形状,即top的形状。
所以,最后一定是top[i].reshape(形状),i是对应的输出编号,这里只有一个输出。
'''
# check input dimensions match
if bottom[0].count != bottom[1].count:
raise Exception("Inputs must have the same dimension.")
# difference is shape of inputs
self.diff = np.zeros_like(bottom[0].data, dtype=np.float32)
# loss output is scalar
top[0].reshape(1)
def forward(self, bottom, top):
'''
forward函数中最后的结果要放入top[i].data[...]中,
其中i就是第几个top,因为有些层会有多个输出的。
'''
self.diff[...] = bottom[0].data - bottom[1].data
#这里定义了平方损失函数
top[0].data[...] = np.sum(self.diff**2) / bottom[0].num / 2.
def backward(self, top, propagate_down, bottom):
'''
backward函数中,是对输入这一层的数据求梯度,
而不是输出这一层的数据。即是对bottom求梯度,
不是对top求梯度,所以这样写:
bottom[i].diff[...]=得到的梯度
'''
for i in range(2):
if not propagate_down[i]:
continue
if i == 0:
sign = 1
else:
sign = -1
#注意此处为反向传播的梯度计算,计算了loss函数的导数
bottom[i].diff[...] = sign * self.diff / bottom[i].num
最后,我们可以通过代码验证网络是否符合要求:
#!/usr/bin/env python
import sys
#这里在其他人的工程下建立自己的工程,所以指定了caffe位置
#如果直接在caffe下建立的工程,配好环境,应该不需要
caffe_root = 'path/to/caffe/'
sys.path.insert(0, caffe_root + 'python')
import caffe
#使用导入的caffe包
#设置使用GPU
caffe.set_device(0)
caffe.set_mode_gpu()
print("==============================")
#指定网络文件
net=caffe.Net("add_python_layer.prototxt",caffe.TEST)
#对文件进行前向传播
net.forward()