I am trying to convert a caffe model to keras, I have successfully been able to use both MMdnn and even caffe-tensorflow. The output I have are .npy
files and .pb
files. I have not had much luck with the .pb
files, so I stuck to .npy
files which contain the weights and biases. I have reconstructed an mAlexNet network as follows:
import tensorflow as tf from tensorflow import keras from keras.layers import Conv2D, MaxPool2D, Dropout, Dense, Flatten def define_malexnet(): input = keras.Input(shape=(224, 224, 3), name='data') x = Conv2D(16, kernel_size=(11,11), strides=(4,4), activation='relu', name='conv1')(input) x = MaxPool2D(pool_size=(3,3), strides=(2,2), padding='same', name='pool1')(x) x = Conv2D(20, kernel_size=(5,5), strides=(1,1), activation='relu', name='conv2')(x) x = MaxPool2D(pool_size=(3,3), strides=(2,2), name='pool2')(x) x = Conv2D(30, kernel_size=(3,3), strides=(1,1), activation='relu', name='conv3')(x) x = MaxPool2D(pool_size=(3,3), strides=(2,2), name='pool3')(x) x = Flatten()(x) x = Dense(48, activation='relu', name='fc4')(x) output = Dense(2, activation='softmax', name='fc5')(x) occupancy_model = keras.Model(input, output, name='occupancy_malexnet') occupancy_model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) return occupancy_model
Then I try to load the weights using this code snippet:
import numpy as np weights_data = np.load('weights.npy', allow_pickle=True).item() model = define_malexnet() for layer in model.layers: if layer.name in weights_data.keys(): layer_weights = weights_data[layer.name] layer.set_weights((layer_weights['weights'], layer_weights['bias']))
During this process I get an error:
ValueError: Layer conv1 weight shape (16,) is not compatible with provided weight shape (1, 1, 1, 16).
Now as I understand this is because of the different backends and how they initialize weights, but I have not found a way to solve this problem. My question is, how do I tweak the weights loaded from the file to fit my keras model? Link to weights.npy
file https://drive.google.com/file/d/1QKzY-WxiUnf9VnlhWQS38DE3uF5I_qTl/view?usp=sharing.
Advertisement
Answer
The problem is the bias
vector. It is shaped as a 4D tensor but Keras assumes it is a 1D tensor. Just flatten the bias vector:
import numpy as np weights_data = np.load('weights.npy', allow_pickle=True).item() model = define_malexnet() for layer in model.layers: if layer.name in weights_data.keys(): layer_weights = weights_data[layer.name] layer.set_weights((layer_weights['weights'], layer_weights['bias'].flatten()))
As a sanity check, once I create your model I will access the conv1
weights and your corresponding weights you cached then compare them both:
In [22]: weights1 = model.layers[1].weights[0].numpy() In [23]: weights2 = weights_data['conv1']['weights'] In [24]: np.allclose(weights1, weights2) Out[24]: True
The same for the biases:
In [25]: bias1 = model.layers[1].weights[1].numpy() In [26]: bias2 = weights_data['conv1']['bias'] In [27]: np.allclose(bias1, bias2) Out[27]: True
Notice that I didn’t have to flatten the biases from your cached results because np.allclose
flattens singleton dimensions internally.