深度学习技术之CAFFE模型转Tensorflow模型

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xuanyuansen/article/details/83028913

#深度学习技术之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文件,具体包括:

  • 1、Line65:data_dict[op_name].items()
  • 2、Line66:shape不相等的情况。
                        if data.shape != var.shape:
                            # print(type(var), var, var.shape)
                            # print(type(data), data, data.shape)
                            data = data.reshape(var.shape)
  • 3、Int兼容性问题:
 kernel = self.make_var('weights', shape=[k_h, k_w, int(c_i) / group, c_o])
  • 4、String兼容性问题:
change if isinstance(fed_layer, basestring): to if isinstance(fed_layer, str)
  • 5、最诡异的问题是最后输出层的结构与权重结构不一致,所以需要需改模型结构,文件倒数第三行:
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

猜你喜欢

转载自blog.csdn.net/xuanyuansen/article/details/83028913