Skip to content

Instantly share code, notes, and snippets.

@mvoelk
Last active March 11, 2022 08:06
Show Gist options
  • Save mvoelk/ef4fc7fb905be7191cc2beb1421da37c to your computer and use it in GitHub Desktop.
Save mvoelk/ef4fc7fb905be7191cc2beb1421da37c to your computer and use it in GitHub Desktop.
Resnet-152 pre-trained model in TF Keras 2.x
# -*- coding: utf-8 -*-
import cv2
import numpy as np
from tensorflow.keras.layers import Input, Dense, Conv2D, MaxPool2D, AvgPool2D, Activation
from tensorflow.keras.layers import Layer, BatchNormalization, ZeroPadding2D, Flatten, add
from tensorflow.keras.optimizers import SGD
from tensorflow.keras.models import Model
from tensorflow.keras import initializers
from tensorflow.python.keras.layers import InputSpec
from tensorflow.keras import backend as K
import sys
sys.setrecursionlimit(3000)
class Scale(Layer):
'''Custom Layer for ResNet used for BatchNormalization.
Learns a set of weights and biases used for scaling the input data.
the output consists simply in an element-wise multiplication of the input
and a sum of a set of constants:
out = in * gamma + beta,
where 'gamma' and 'beta' are the weights and biases larned.
# Arguments
axis: integer, axis along which to normalize in mode 0. For instance,
if your input tensor has shape (samples, channels, rows, cols),
set axis to 1 to normalize per feature map (channels axis).
momentum: momentum in the computation of the
exponential average of the mean and standard deviation
of the data, for feature-wise normalization.
beta_init: name of initialization function for shift parameter
(see [initializers](../initializers.md)).
gamma_init: name of initialization function for scale parameter (see
[initializers](../initializers.md)).
'''
def __init__(self, axis=-1, momentum = 0.9, beta_init='zero', gamma_init='one', **kwargs):
self.momentum = momentum
self.axis = axis
self.beta_initializer = initializers.get(beta_init)
self.gamma_initializer = initializers.get(gamma_init)
super(Scale, self).__init__(**kwargs)
def build(self, input_shape):
self.input_spec = [InputSpec(shape=input_shape)]
shape = (int(input_shape[self.axis]),)
self.gamma = self.add_weight(
name='%s_gamma'%self.name,
shape=shape,
initializer=self.gamma_initializer,
trainable=True,
dtype=self.dtype)
self.beta = self.add_weight(
name='%s_beta'%self.name,
shape=shape,
initializer=self.beta_initializer,
trainable=True,
dtype=self.dtype)
self.built = True
def call(self, x, mask=None):
input_shape = self.input_spec[0].shape
broadcast_shape = [1] * len(input_shape)
broadcast_shape[self.axis] = input_shape[self.axis]
out = K.reshape(self.gamma, broadcast_shape) * x + K.reshape(self.beta, broadcast_shape)
return out
def get_config(self):
config = {"momentum": self.momentum, "axis": self.axis}
base_config = super(Scale, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
def identity_block(input_tensor, kernel_size, filters, stage, block):
'''The identity_block is the block that has no conv layer at shortcut
# Arguments
input_tensor: input tensor
kernel_size: defualt 3, the kernel size of middle conv layer at main path
filters: list of integers, the nb_filters of 3 conv layer at main path
stage: integer, current stage label, used for generating layer names
block: 'a','b'..., current block label, used for generating layer names
'''
eps = 1.1e-5
nb_filter1, nb_filter2, nb_filter3 = filters
conv_name_base = 'res' + str(stage) + block + '_branch'
bn_name_base = 'bn' + str(stage) + block + '_branch'
scale_name_base = 'scale' + str(stage) + block + '_branch'
x = Conv2D(nb_filter1, (1, 1), name=conv_name_base + '2a', use_bias=False)(input_tensor)
x = BatchNormalization(epsilon=eps, name=bn_name_base + '2a')(x)
x = Scale(name=scale_name_base + '2a')(x)
x = Activation('relu', name=conv_name_base + '2a_relu')(x)
x = ZeroPadding2D((1, 1), name=conv_name_base + '2b_zeropadding')(x)
x = Conv2D(nb_filter2, (kernel_size, kernel_size), name=conv_name_base + '2b', use_bias=False)(x)
x = BatchNormalization(epsilon=eps, name=bn_name_base + '2b')(x)
x = Scale(name=scale_name_base + '2b')(x)
x = Activation('relu', name=conv_name_base + '2b_relu')(x)
x = Conv2D(nb_filter3, (1, 1), name=conv_name_base + '2c', use_bias=False)(x)
x = BatchNormalization(epsilon=eps, name=bn_name_base + '2c')(x)
x = Scale(name=scale_name_base + '2c')(x)
x = add([x, input_tensor], name='res' + str(stage) + block)
x = Activation('relu', name='res' + str(stage) + block + '_relu')(x)
return x
def conv_block(input_tensor, kernel_size, filters, stage, block, strides=(2, 2)):
'''conv_block is the block that has a conv layer at shortcut
# Arguments
input_tensor: input tensor
kernel_size: defualt 3, the kernel size of middle conv layer at main path
filters: list of integers, the nb_filters of 3 conv layer at main path
stage: integer, current stage label, used for generating layer names
block: 'a','b'..., current block label, used for generating layer names
Note that from stage 3, the first conv layer at main path is with subsample=(2,2)
And the shortcut should have subsample=(2,2) as well
'''
eps = 1.1e-5
nb_filter1, nb_filter2, nb_filter3 = filters
conv_name_base = 'res' + str(stage) + block + '_branch'
bn_name_base = 'bn' + str(stage) + block + '_branch'
scale_name_base = 'scale' + str(stage) + block + '_branch'
x = Conv2D(nb_filter1, (1, 1), strides=strides, name=conv_name_base + '2a', use_bias=False)(input_tensor)
x = BatchNormalization(epsilon=eps, name=bn_name_base + '2a')(x)
x = Scale(name=scale_name_base + '2a')(x)
x = Activation('relu', name=conv_name_base + '2a_relu')(x)
x = ZeroPadding2D((1, 1), name=conv_name_base + '2b_zeropadding')(x)
x = Conv2D(nb_filter2, (kernel_size, kernel_size), name=conv_name_base + '2b', use_bias=False)(x)
x = BatchNormalization(epsilon=eps, name=bn_name_base + '2b')(x)
x = Scale(name=scale_name_base + '2b')(x)
x = Activation('relu', name=conv_name_base + '2b_relu')(x)
x = Conv2D(nb_filter3, (1, 1), name=conv_name_base + '2c', use_bias=False)(x)
x = BatchNormalization(epsilon=eps, name=bn_name_base + '2c')(x)
x = Scale(name=scale_name_base + '2c')(x)
shortcut = Conv2D(nb_filter3, (1, 1), strides=strides, name=conv_name_base + '1', use_bias=False)(input_tensor)
shortcut = BatchNormalization(epsilon=eps, name=bn_name_base + '1')(shortcut)
shortcut = Scale(name=scale_name_base + '1')(shortcut)
x = add([x, shortcut], name='res' + str(stage) + block)
x = Activation('relu', name='res' + str(stage) + block + '_relu')(x)
return x
def resnet152_model(input_shape=(224, 224, 3), weights_path=None):
'''Instantiate the ResNet152 architecture,
# Arguments
input_shape: shape of the model input
weights_path: path to pretrained weight file
# Returns
A Keras model instance.
'''
eps = 1.1e-5
img_input = Input(shape=input_shape, name='data')
x = ZeroPadding2D((3, 3), name='conv1_zeropadding')(img_input)
x = Conv2D(64, (7, 7), strides=(2, 2), name='conv1', use_bias=False)(x)
x = BatchNormalization(epsilon=eps, name='bn_conv1')(x)
x = Scale(name='scale_conv1')(x)
x = Activation('relu', name='conv1_relu')(x)
x = MaxPool2D((3, 3), strides=(2, 2), name='pool1')(x)
x = conv_block(x, 3, [64, 64, 256], stage=2, block='a', strides=(1, 1))
x = identity_block(x, 3, [64, 64, 256], stage=2, block='b')
x = identity_block(x, 3, [64, 64, 256], stage=2, block='c')
x = conv_block(x, 3, [128, 128, 512], stage=3, block='a')
for i in range(1,8):
x = identity_block(x, 3, [128, 128, 512], stage=3, block='b'+str(i))
x = conv_block(x, 3, [256, 256, 1024], stage=4, block='a')
for i in range(1,36):
x = identity_block(x, 3, [256, 256, 1024], stage=4, block='b'+str(i))
x = conv_block(x, 3, [512, 512, 2048], stage=5, block='a')
x = identity_block(x, 3, [512, 512, 2048], stage=5, block='b')
x = identity_block(x, 3, [512, 512, 2048], stage=5, block='c')
x_fc = AvgPool2D((7, 7), name='avg_pool')(x)
x_fc = Flatten()(x_fc)
x_fc = Dense(1000, activation='softmax', name='fc1000')(x_fc)
model = Model(img_input, x_fc)
# load weights
if weights_path:
model.load_weights(weights_path, by_name=True)
return model
if __name__ == '__main__':
input_shape = (224, 224, 3)
weights_path = 'resnet152_weights_tf.h5'
image_path = 'cat.jpg'
im = cv2.resize(cv2.imread(image_path), input_shape[0:2]).astype(np.float32)
# Remove train image mean
im -= [103.939, 116.779, 123.68]
# Insert a new dimension for the batch_size
im = np.expand_dims(im, axis=0)
# Test pretrained model
model = resnet152_model(input_shape, weights_path)
sgd = SGD(lr=1e-2, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=['accuracy'])
preds = model.predict(im)
print(np.argmax(preds))
@hbake001
Copy link

Hi

I got the following error while running the code

Using Theano backend.
Traceback (most recent call last):
  File "resnet152.py", line 249, in <module>
    score = model.evaluate(x_test, ((y_test)))
  File "c:\users\engadmin\anaconda3\lib\site-packages\keras\engine\training.py",
 line 1646, in evaluate
    batch_size=batch_size)
  File "c:\users\engadmin\anaconda3\lib\site-packages\keras\engine\training.py",
 line 1382, in _standardize_user_data
    exception_prefix='target')
  File "c:\users\engadmin\anaconda3\lib\site-packages\keras\engine\training.py",
 line 144, in _standardize_input_data
    str(array.shape))
ValueError: Error when checking target: expected fc1000 to have shape (None, 10)
 but got array with shape (10000, 1)

(C:\Users\engadmin\Anaconda3) C:\Users\engadmin\.spyder-py3>
(C:\Users\engadmin\Anaconda3) C:\Users\engadmin\.spyder-py3>
(C:\Users\engadmin\Anaconda3) C:\Users\engadmin\.spyder-py3>python resnet152.py
Using Theano backend.
Traceback (most recent call last):
  File "c:\users\engadmin\anaconda3\lib\site-packages\theano\compile\function_mo
dule.py", line 884, in __call__
    self.fn() if output_subset is None else\
ValueError: Input dimension mis-match. (input[0].shape[1] = 10, input[1].shape[1
] = 1000)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "resnet152.py", line 249, in <module>
    score = model.evaluate(x_test, (np_utils.to_categorical(y_test)))
  File "c:\users\engadmin\anaconda3\lib\site-packages\keras\engine\training.py",
 line 1657, in evaluate
    steps=steps)
  File "c:\users\engadmin\anaconda3\lib\site-packages\keras\engine\training.py",
 line 1339, in _test_loop
    batch_outs = f(ins_batch)
  File "c:\users\engadmin\anaconda3\lib\site-packages\keras\backend\theano_backe
nd.py", line 1222, in __call__
    return self.function(*inputs)
  File "c:\users\engadmin\anaconda3\lib\site-packages\theano\compile\function_mo
dule.py", line 898, in __call__
    storage_map=getattr(self.fn, 'storage_map', None))
  File "c:\users\engadmin\anaconda3\lib\site-packages\theano\gof\link.py", line
325, in raise_with_op
    reraise(exc_type, exc_value, exc_trace)
  File "c:\users\engadmin\anaconda3\lib\site-packages\six.py", line 685, in rera
ise
    raise value.with_traceback(tb)
  File "c:\users\engadmin\anaconda3\lib\site-packages\theano\compile\function_mo
dule.py", line 884, in __call__
    self.fn() if output_subset is None else\
ValueError: Input dimension mis-match. (input[0].shape[1] = 10, input[1].shape[1
] = 1000)
Apply node that caused the error: Elemwise{Composite{(i0 * log(clip((i1 / i2), i
3, i4)))}}[(0, 1)](/fc1000_target, SoftmaxWithBias.0, InplaceDimShuffle{0,x}.0,
TensorConstant{(1, 1) of 1e-07}, TensorConstant{(1, 1) of 1.0})
Toposort index: 6318
Inputs types: [TensorType(float32, matrix), TensorType(float32, matrix), TensorT
ype(float32, col), TensorType(float32, (True, True)), TensorType(float32, (True,
 True))]
Inputs shapes: [(32, 10), (32, 1000), (32, 1), (1, 1), (1, 1)]
Inputs strides: [(40, 4), (4000, 4), (4, 4), (4, 4), (4, 4)]
Inputs values: ['not shown', 'not shown', 'not shown', array([[  1.00000001e-07]
], dtype=float32), array([[ 0.99999988]], dtype=float32)]
Outputs clients: [[Sum{axis=[1], acc_dtype=float64}(Elemwise{Composite{(i0 * log
(clip((i1 / i2), i3, i4)))}}[(0, 1)].0)]]

HINT: Re-running with most Theano optimization disabled could give you a back-tr
ace of when this node was created. This can be done with by setting the Theano f
lag 'optimizer=fast_compile'. If that does not work, Theano optimizations can be
 disabled with 'optimizer=None'.
HINT: Use the Theano flag 'exception_verbosity=high' for a debugprint and storag
e map footprint of this apply node.

@mvoelk
Copy link
Author

mvoelk commented Jan 19, 2018

@hbake001 Could you fix it? I only used tensorflow backend...

@edgarckd
Copy link

edgarckd commented Oct 9, 2019

Hi

I got the following error while running the code

File "C:\Users\Harrison\Anaconda3\lib\site-packages\tensorflow\python\pywrap_tensorflow.py", line 74, in
raise ImportError( msg )

ImportError: Traceback (most recent call last):
File "C:\Users\Harrison\Anaconda3\lib\site-packages\tensorflow\python\pywrap_tensorflow.py", line 58, in
from tensorflow.python.pywrap_tensorflow_internal import *
File "C:\Users\Harrison\Anaconda3\lib\site-packages\tensorflow\python\pywrap_tensorflow_internal.py", line 28, in
_pywrap_tensorflow_internal = swig_import_helper()
File "C:\Users\Harrison\Anaconda3\lib\site-packages\tensorflow\python\pywrap_tensorflow_internal.py", line 24, in swig_import_helper
_mod = imp.load_module('_pywrap_tensorflow_internal', fp, pathname, description)
File "C:\Users\Harrison\Anaconda3\lib\imp.py", line 243, in load_module
return load_dynamic(name, filename, file)
File "C:\Users\Harrison\Anaconda3\lib\imp.py", line 343, in load_dynamic
return _load(spec)
ImportError: DLL load failed: No se puede encontrar el módulo especificado.

Failed to load the native TensorFlow runtime.

friend please, how can I fix it?

@mikechen66
Copy link

mikechen66 commented Oct 6, 2020

I has the following error. It seems that it has the mismatch after your adding the scale class. Without the scale class, the original official restnet by Francois Chollet script runs well.

Traceback (most recent call last):
File "/home/mike/miniconda3/lib/python3.7/site-packages/tensorflow/python/framework/ops.py", line 1654, in _create_c_op
c_op = pywrap_tf_session.TF_FinishOperation(op_desc)
tensorflow.python.framework.errors_impl.InvalidArgumentError: Negative dimension size caused by subtracting 3 from 2 for '{{node pool1/MaxPool}} = MaxPoolT=DT_FLOAT, data_format="NHWC", ksize=[1, 3, 3, 1], padding="VALID", strides=[1, 2, 2, 1]' with input shapes: [?,2,112,64].

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "resnet152_keras.py", line 245, in
model = resnet152_model(weights_path=WEIGHTS_PATH)
File "resnet152_keras.py", line 187, in resnet152_model
x = MaxPooling2D((3, 3), strides=(2, 2), name='pool1')(x)
File "/home/mike/miniconda3/lib/python3.7/site-packages/tensorflow/python/keras/engine/base_layer.py", line 922, in call
outputs = call_fn(cast_inputs, *args, **kwargs)
File "/home/mike/miniconda3/lib/python3.7/site-packages/tensorflow/python/keras/layers/pooling.py", line 296, in call
data_format=conv_utils.convert_data_format(self.data_format, 4))
File "/home/mike/miniconda3/lib/python3.7/site-packages/tensorflow/python/ops/nn_ops.py", line 3929, in max_pool
name=name)
File "/home/mike/miniconda3/lib/python3.7/site-packages/tensorflow/python/ops/gen_nn_ops.py", line 5236, in max_pool
data_format=data_format, name=name)
File "/home/mike/miniconda3/lib/python3.7/site-packages/tensorflow/python/framework/op_def_library.py", line 744, in _apply_op_helper
attrs=attr_protos, op_def=op_def)
File "/home/mike/miniconda3/lib/python3.7/site-packages/tensorflow/python/framework/func_graph.py", line 595, in _create_op_internal
compute_device)
File "/home/mike/miniconda3/lib/python3.7/site-packages/tensorflow/python/framework/ops.py", line 3327, in _create_op_internal
op_def=op_def)
File "/home/mike/miniconda3/lib/python3.7/site-packages/tensorflow/python/framework/ops.py", line 1817, in init
control_input_ops, op_def)
File "/home/mike/miniconda3/lib/python3.7/site-packages/tensorflow/python/framework/ops.py", line 1657, in _create_c_op
raise ValueError(str(e))
ValueError: Negative dimension size caused by subtracting 3 from 2 for '{{node pool1/MaxPool}} = MaxPoolT=DT_FLOAT, data_format="NHWC", ksize=[1, 3, 3, 1], padding="VALID", strides=[1, 2, 2, 1]' with input shapes: [?,2,112,64].

@mvoelk
Copy link
Author

mvoelk commented Oct 6, 2020

I updated the code to TF Keras 2.4.0 and removed the Theano support.

@mvoelk
Copy link
Author

mvoelk commented Oct 6, 2020

Code is bases on https://gist.github.com/flyyufelix/7e2eafb149f72f4d38dd661882c554a6. You can find the weights there...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment