No se puede replicar una architecture CNN matconvnet en Keras

Tengo la siguiente architecture de una neural network convolucional en matconvnet que utilizo para entrenar con mis propios datos:

function net = cnn_mnist_init(varargin) % CNN_MNIST_LENET Initialize a CNN similar for MNIST opts.batchNormalization = false ; opts.networkType = 'simplenn' ; opts = vl_argparse(opts, varargin) ; f= 0.0125 ; net.layers = {} ; net.layers{end+1} = struct('name','conv1',... 'type', 'conv', ... 'weights', {{f*randn(3,3,1,64, 'single'), zeros(1, 64, 'single')}}, ... 'stride', 1, ... 'pad', 0,... 'learningRate', [1 2]) ; net.layers{end+1} = struct('name','pool1',... 'type', 'pool', ... 'method', 'max', ... 'pool', [3 3], ... 'stride', 1, ... 'pad', 0); net.layers{end+1} = struct('name','conv2',... 'type', 'conv', ... 'weights', {{f*randn(5,5,64,128, 'single'),zeros(1,128,'single')}}, ... 'stride', 1, ... 'pad', 0,... 'learningRate', [1 2]) ; net.layers{end+1} = struct('name','pool2',... 'type', 'pool', ... 'method', 'max', ... 'pool', [2 2], ... 'stride', 2, ... 'pad', 0) ; net.layers{end+1} = struct('name','conv3',... 'type', 'conv', ... 'weights', {{f*randn(3,3,128,256, 'single'),zeros(1,256,'single')}}, ... 'stride', 1, ... 'pad', 0,... 'learningRate', [1 2]) ; net.layers{end+1} = struct('name','pool3',... 'type', 'pool', ... 'method', 'max', ... 'pool', [3 3], ... 'stride', 1, ... 'pad', 0) ; net.layers{end+1} = struct('name','conv4',... 'type', 'conv', ... 'weights', {{f*randn(5,5,256,512, 'single'),zeros(1,512,'single')}}, ... 'stride', 1, ... 'pad', 0,... 'learningRate', [1 2]) ; net.layers{end+1} = struct('name','pool4',... 'type', 'pool', ... 'method', 'max', ... 'pool', [2 2], ... 'stride', 1, ... 'pad', 0) ; net.layers{end+1} = struct('name','ip1',... 'type', 'conv', ... 'weights', {{f*randn(1,1,256,256, 'single'), zeros(1,256,'single')}}, ... 'stride', 1, ... 'pad', 0,... 'learningRate', [1 2]) ; net.layers{end+1} = struct('name','relu',... 'type', 'relu'); net.layers{end+1} = struct('name','classifier',... 'type', 'conv', ... 'weights', {{f*randn(1,1,256,2, 'single'), zeros(1,2,'single')}}, ... 'stride', 1, ... 'pad', 0,... 'learningRate', [1 2]) ; net.layers{end+1} = struct('name','loss',... 'type', 'softmaxloss') ; % optionally switch to batch normalization if opts.batchNormalization net = insertBnorm(net, 1) ; net = insertBnorm(net, 4) ; net = insertBnorm(net, 7) ; net = insertBnorm(net, 10) ; net = insertBnorm(net, 13) ; end % Meta parameters net.meta.inputSize = [28 28 1] ; net.meta.trainOpts.learningRate = [0.01*ones(1,10) 0.001*ones(1,10) 0.0001*ones(1,10)]; disp(net.meta.trainOpts.learningRate); pause; net.meta.trainOpts.numEpochs = length(net.meta.trainOpts.learningRate) ; net.meta.trainOpts.batchSize = 256 ; net.meta.trainOpts.momentum = 0.9 ; net.meta.trainOpts.weightDecay = 0.0005 ; % -------------------------------------------------------------------- function net = insertBnorm(net, l) % -------------------------------------------------------------------- assert(isfield(net.layers{l}, 'weights')); ndim = size(net.layers{l}.weights{1}, 4); layer = struct('type', 'bnorm', ... 'weights', {{ones(ndim, 1, 'single'), zeros(ndim, 1, 'single')}}, ... 'learningRate', [1 1], ... 'weightDecay', [0 0]) ; net.layers{l}.biases = [] ; net.layers = horzcat(net.layers(1:l), layer, net.layers(l+1:end)) ; 

Lo que quiero hacer es construir la misma architecture en Keras, eso es lo que intenté hasta ahora:

 model = Sequential() model.add(Conv2D(64, (3, 3), strides=1, input_shape=input_shape)) model.add(MaxPooling2D(pool_size=(3, 3), strides=1)) model.add(Conv2D(128, (5, 5), strides=1)) model.add(MaxPooling2D(pool_size=(2, 2), strides=2)) model.add(Conv2D(256, (3, 3), strides=1)) model.add(MaxPooling2D(pool_size=(3, 3), strides=1)) model.add(Conv2D(512, (5, 5), strides=1)) model.add(MaxPooling2D(pool_size=(2, 2), strides=1)) model.add(Conv2D(256, (1, 1))) convout1=Activation('relu') model.add(convout1) model.add(Flatten()) model.add(Dense(num_classes, activation='softmax')) opt = keras.optimizers.rmsprop(lr=0.0001, decay=0.0005) model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['binary_accuracy']) 

Sin embargo, cuando ejecuto la red matconvnet, tengo una precisión del 87% y si ejecuto la versión keras, tengo una precisión del 77%. Si se supone que son la misma red y los datos son los mismos, ¿dónde está la diferencia? ¿Qué está mal en mi architecture Keras?

En su versión MatConvNet, usa SGD con impulso.

En Keras, usas rmsprop.

Con una regla de aprendizaje diferente debes probar diferentes tasas de aprendizaje. También a veces el impulso es útil cuando se entrena una CNN.

¿Podrías probar el impulso SGD + en Keras y decirme qué pasa?

Otra cosa que podría ser diferente es la inicialización. por ejemplo, en MatConvNet se usa la inicialización gaussiana con f = 0.0125 como la desviación estándar. En Keras no estoy seguro de la inicialización por defecto.

En general, si no utiliza la normalización por lotes, la red es propensa a muchos problemas numéricos. Si utiliza la normalización por lotes en ambas redes, apuesto a que los resultados serían similares. ¿Hay alguna razón por la que no quiera usar la normalización por lotes?