Как имитировать максимальное поведение пула Caffe в Keras / Tensorflow? - PullRequest
0 голосов
/ 28 января 2019

Если у меня есть MaxPooling2D слой с pool_size=(2,2), strides=(2,2) в Керасе.Применительно к 3x3 входной карте объектов это приведет к 1x1 пространственному выходному размеру.Та же операция в Caffe (pool: MAX; kernel_size: 2; stride: 2) приведет к выводу размером 2x2.

Хорошо известно, что Caffe и Tensorflow / Keras ведут себя по-разному при применении максимального пула .

Существует обходной путь для двумерной свертки: чтобы избежать асимметричного заполнения Conv2D в TensorFlow , можно добавить к нему явное заполнение нулями и изменить тип заполнения с same to valid

Есть ли подобный обходной путь для изменения поведения MaxPooling2D в Keras таким образом, чтобы оно работало подобно Caffe?Точнее, я ищу обертку вокруг MaxPooling2D, которая будет равна максимальному объему 2D 2x2 в Caffe.

Может быть, дополнить ввод MaxPooling2D одним пикселем влево и вверх?

Я использую tf.keras от TensorFlow.

1 Ответ

0 голосов
/ 28 января 2019

Хорошо, я нашел ответ, позвольте мне сохранить его здесь.Нужно заполнить ввод снизу / справа нулями.Вот рабочий минимальный пример:

import os
import math
import numpy as np

import tensorflow as tf
from tensorflow.python.keras.models import Model
from tensorflow.python.keras.layers import Input, MaxPool2D
from tensorflow.python.keras import backend as K

import caffe
from caffe.model_libs import P
from caffe import layers as L
from caffe.proto import caffe_pb2


def MaxPooling2DWrapper(pool_size=(2, 2), strides=None, padding='valid', data_format=None, **kwargs):

    def padded_pooling(inputs):
        _, h, w, _ = K.int_shape(inputs)
        interm_input = inputs
        if h % 2 != 0 or w % 2 != 0:
            interm_input = tf.keras.layers.Lambda(lambda x: tf.pad(inputs, [[0, 0], [0, 1], [0, 1], [0, 0]]),
                                                  name='input_pad')(inputs)
        return MaxPool2D(pool_size, strides, padding, data_format, **kwargs)(interm_input)

    return padded_pooling


def build_caffe_model(h, w):
    caffe_spec = caffe.NetSpec()

    pool_config = {                                                                                                                                                                                                                                                   
        'pool': P.Pooling.MAX,                                                                                                                                                                                                                                        
        'kernel_size': 2,                                                                                                                                                                                                                                             
        'stride': 2                                                                                                                                                                                                                                                   
    }                                                                                                                                                                                                                                                                 

    caffe_spec['input'] = L.Input(shape=caffe_pb2.BlobShape(dim=(1, 1, h, w)))                                                                                                                                                                                        
    caffe_spec['max_pool'] = L.Pooling(caffe_spec['input'], **pool_config)                                                                                                                                                                                            

    proto = str(caffe_spec.to_proto())                                                                                                                                                                                                                                
    with open('deploy.prototxt', 'w') as f:                                                                                                                                                                                                                           
        f.write(proto)                                                                                                                                                                                                                                                
    net = caffe.Net('deploy.prototxt', caffe.TEST)                                                                                                                                                                                                                    

    return net                                                                                                                                                                                                                                                        


def build_keras_model(h, w):                                                                                                                                                                                                                                          
    inputs = Input(shape=(h, w, 1))                                                                                                                                                                                                                                   

    maxpool = MaxPooling2DWrapper()(inputs)                                                                                                                                                                                                                           
    return Model(inputs, maxpool)                                                                                                                                                                                                                                     


def main():                                                                                                                                                                                                                                                           
    caffe.set_mode_cpu()                                                                                                                                                                                                                                              
    os.environ['GLOG_minloglevel'] = '2'                                                                                                                                                                                                                              
    h = 3                                                                                                                                                                                                                                                             
    w = 3                                                                                                                                                                                                                                                             
    size_input = h * w                                                                                                                                                                                                                                                

    caffe_net = build_caffe_model(h, w)                                                                                                                                                                                                                               
    keras_model = build_keras_model(h, w)                                                                                                                                                                                                                             
    keras_model.summary()                                                                                                                                                                                                                                             

    keras_out = keras_model.predict(np.arange(size_input).reshape(1, h, w, 1))
    caffe_net.blobs['input'].data[...] = np.arange(size_input).reshape(1, 1, h, w)
    caffe_out = caffe_net.forward()['max_pool']

    print('Input:')
    print(np.arange(size_input).reshape(h, w))

    print('Caffe result:')
    print(np.squeeze(caffe_out))

    print('Keras result:')
    print(np.squeeze(keras_out))


if __name__ == '__main__':
    main()

Оболочка будет добавлять отступ только при необходимости.Выход этого кода:

Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         (None, 3, 3, 1)           0         
_________________________________________________________________
input_pad (Lambda)           (None, 4, 4, 1)           0         
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 2, 2, 1)           0         
=================================================================


Input:
[[0 1 2]
 [3 4 5]
 [6 7 8]]
Caffe result:
[[4. 5.]
 [7. 8.]]
Keras result:
[[4. 5.]
 [7. 8.]]
...