#深度学习技术之CAFFE模型转Tensorflow模型
####背景
最近笔者在工作时遇到一个问题,需要使用已经训练好的CAFFE模型,但是由于CAFFE这个项目已经很旧了,在服务器上未能正确安装,所以只能通过其他途径来使用该模型。一个直观的想法就是将这个CAFFE模型转换为TF模型,索性在gituhb上面发现了这个项目https://github.com/ethereon/caffe-tensorflow。然而这个项目也是两年前的项目,更是基于python2环境,所以想要在python3环境下跑通模型转换流程有许多坑。下面分别介绍怎么解决。
####填坑
#####1、转换过程的坑
首先获得模型的结构,执行命令
python3 ./convert.py ../open_nsfw/nsfw_model/deploy.prototxt --code-output-path=mynet.py
这里会报错误
File "/usr/local/lib/python3.6/site-packages/google/protobuf/descriptor.py", line 829, in __new__
return _message.default_pool.AddSerializedFile(serialized_pb)
网上查到的资料显示python2和python3之间的问题,较难解决,一个简单的解决方式是在python2环境下完成转换。
执行命令以下命令可以得到模型的结构
python2 ./convert.py ../open_nsfw/nsfw_model/deploy.prototxt --code-output-path=mynet.py
再获得模型的权重,执行命令,会报错误
File "/Users/wangshuai/Documents/code/caffe-tensorflow/kaffe/transformers.py", line 246, in __call__
variance *= scaling_factor
ValueError: non-broadcastable output operand with shape (64,) doesn't match the broadcast shape (1,1,1,64)
在GITHUB上面可以看到也有同学遇到类似错误,见https://github.com/ethereon/caffe-tensorflow/issues/146,解决方法是更改此处的scaling_factor维度,直接取scaling_factor的值,问题解决。
variance \*= scaling_factor[0,0,0,0]
#####2、使用过程的坑
首先加载模型,因为在python3下面部分API更改,所以需要修改./tensorflow/network.py文件,具体包括:
if data.shape != var.shape:
# print(type(var), var, var.shape)
# print(type(data), data, data.shape)
data = data.reshape(var.shape)
kernel = self.make_var('weights', shape=[k_h, k_w, int(c_i) / group, c_o])
change if isinstance(fed_layer, basestring): to if isinstance(fed_layer, str)
avg_pool(7, 7, 2, 2, padding='VALID', name='pool')# modify from stride 1 to stride 2 to fix shape bug
####3、运行
由于yahoo开源的NSFW写死了预处理,所以在送入模型前需要进行预处理。
def get_img_with_req(url):
try:
response = requests.get(url)
img = Image.open(BytesIO(response.content))
except:
raise Exception("get image failed! %s" % url)
return img
def img_pre_process_with_url(urls):
a = get_img_with_req(urls)
img = img_to_array(a.resize((256, 256), Image.NEAREST))
img -= [104, 117, 123]
np.swapaxes(img, 0, 2)
return img
if __name__ == '__main__':
url = "http://p.88rt.org/pic88/2018/0416/276.jpg"
url2 = "http://t2.hddhhn.com/uploads/tu/201609/192/1.jpg"
url3 = "http://p.88rt.org/pic88/2018/0226/282.jpg"
url4 = "http://p.88rt.org/pic88/2018/0224/200.jpg"
url5 = "http://p.88rt.org/pic88/2018/0224/194.jpg"
# Import the converted model's class
input_x = tf.placeholder(tf.float32,
shape=(None, 256, 256, 3))
net = ResNet_50_1by2_nsfw({'data': input_x })
img_seg=[url, url2, url3, url4, url5]
imgs=[img_pre_process_with_url(ele) for ele in img_seg]
with tf.Session() as sesh:
# Load the data
net.load('mynet.npy', sesh, ignore_missing=False)
# Forward pass
# https://github.com/tensorflow/tensorflow/issues/3378
output = sesh.run(net.get_output(), feed_dict={
input_x:
np.array(imgs, ndmin=4).astype('float32')})
print(type(output))
print(list(output))
print(output[0, 0])
print(output[0, 1])
pass
####4、结果
获得结果,成功。
[array([0.3077783 , 0.69222164], dtype=float32), array([0.8333309 , 0.16666912], dtype=float32), array([0.6487526 , 0.35124734], dtype=float32), array([0.05181765, 0.94818234], dtype=float32), array([0.3710381 , 0.62896186], dtype=float32)]
0.3077783
0.69222164