I got an error when implementing Residual Network in Keras. Below is the code that gives me error (the error comes from the first line of the final step in the function definition):
Load packages:
import numpy as np
from keras import layers
from keras.layers import Input, Add, Concatenate, Dense, Activation, ZeroPadding2D, BatchNormalization, Flatten, Conv2D, AveragePooling2D, MaxPooling2D, GlobalMaxPooling2D
from keras.models import Model, load_model
from keras.preprocessing import image
from keras.utils import layer_utils
from keras.utils.data_utils import get_file
from keras.applications.imagenet_utils import preprocess_input
import pydot
from IPython.display import SVG
from keras.utils.vis_utils import model_to_dot
from keras.utils import plot_model
from resnets_utils import *
from keras.initializers import glorot_uniform
import scipy.misc
from matplotlib.pyplot import imshow
%matplotlib inline
import keras.backend as K
K.set_image_data_format('channels_last')
K.set_learning_phase(1)
Define the function: (it's the first line of the "final step" that gives me the error)
def identity_block(X, f, filters, stage, block):
"""
Implementation of the identity block as defined in Figure 4
Arguments:
X -- input tensor of shape (m, n_H_prev, n_W_prev, n_C_prev)
f -- integer, specifying the shape of the middle CONV's window for the main path
filters -- python list of integers, defining the number of filters in the CONV layers of the main path
stage -- integer, used to name the layers, depending on their position in the network
block -- string/character, used to name the layers, depending on their position in the network
Returns:
X -- output of the identity block, tensor of shape (n_H, n_W, n_C)
"""
# defining name basis
conv_name_base = 'res' + str(stage) + block + '_branch'
bn_name_base = 'bn' + str(stage) + block + '_branch'
# Save the input value. You'll need this later to add back to the main path.
X_shortcut = X
# First component of main path
X = Conv2D(filters = F1, kernel_size = (1, 1), strides = (1,1), padding = 'valid', name = conv_name_base + '2a', kernel_initializer = glorot_uniform(seed=0))(X)
X = BatchNormalization(axis = 3, name = bn_name_base + '2a')(X)
X = Activation('relu')(X)
# Second component of main path
X = Conv2D(filters=F2, kernel_size=(f,f),strides=(1,1),padding='same',name=conv_name_base+'2b',kernel_initializer=glorot_uniform(seed=0))(X)
X = BatchNormalization(axis=3,name=bn_name_base+'2b')(X)
X = Activation('relu')(X)
# Third component of main path
X = Conv2D(filters=F3,kernel_size=(1,1),strides=(1,1),padding='valid',name=conv_name_base+'2c',kernel_initializer=glorot_uniform(seed=0))(X)
print(f'before BatchNormalization: X={X}');X = BatchNormalization(axis=3,name=bn_name_base+'2c');print(f'after BatchNormalization: X={X}');
# Final step: Add shortcut value to main path, and pass it through a RELU activation
X = Add()([X_shortcut,X])
X = Activation('relu')(X)
### END CODE HERE ###
return X
Call/test the above function:
tf.reset_default_graph()
with tf.Session() as test:
np.random.seed(1)
A_prev = tf.placeholder("float", [3, 4, 4, 6])
X = np.random.randn(3, 4, 4, 6)
A = identity_block(A_prev, f = 2, filters = [2, 4, 6], stage = 1, block = 'a')
test.run(tf.global_variables_initializer())
out = test.run([A], feed_dict={A_prev: X, K.learning_phase(): 0})
print("out = " + str(out[0][1][1][0]))
Below is the print message and error message:
before BatchNormalization: X=Tensor("res1a_branch2c/BiasAdd:0", shape=(3, 4, 4, 6), dtype=float32)
after BatchNormalization: X= <keras.layers.normalization.BatchNormalization object at 0x7f169c6d9668>
ValueError: Unexpectedly found an instance of type `<class 'keras.layers.normalization.BatchNormalization'>`. Expected a symbolic tensor instance.
Below is the complete log (in case you need it)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
/opt/conda/lib/python3.6/site-packages/keras/engine/topology.py in assert_input_compatibility(self, inputs)
424 try:
--> 425 K.is_keras_tensor(x)
426 except ValueError:
/opt/conda/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py in is_keras_tensor(x)
399 tf.SparseTensor)):
--> 400 raise ValueError('Unexpectedly found an instance of type `' + str(type(x)) + '`. '
401 'Expected a symbolic tensor instance.')
ValueError: Unexpectedly found an instance of type `<class 'keras.layers.normalization.BatchNormalization'>`. Expected a symbolic tensor instance.
During handling of the above exception, another exception occurred:
ValueError Traceback (most recent call last)
<ipython-input-6-b3d1050f50dc> in <module>()
5 A_prev = tf.placeholder("float", [3, 4, 4, 6])
6 X = np.random.randn(3, 4, 4, 6)
----> 7 A = identity_block(A_prev, f = 2, filters = [2, 4, 6], stage = 1, block = 'a')
8 test.run(tf.global_variables_initializer())
9 out = test.run([A], feed_dict={A_prev: X, K.learning_phase(): 0})
<ipython-input-5-013941ce79d6> in identity_block(X, f, filters, stage, block)
43
44 # Final step: Add shortcut value to main path, and pass it through a RELU activation (≈2 lines)
---> 45 X = Add()([X_shortcut,X])
46 X = Activation('relu')(X)
47
/opt/conda/lib/python3.6/site-packages/keras/engine/topology.py in __call__(self, inputs, **kwargs)
556 # Raise exceptions in case the input is not compatible
557 # with the input_spec specified in the layer constructor.
--> 558 self.assert_input_compatibility(inputs)
559
560 # Collect input shapes to build layer.
/opt/conda/lib/python3.6/site-packages/keras/engine/topology.py in assert_input_compatibility(self, inputs)
429 'Received type: ' +
430 str(type(x)) + '. Full input: ' +
--> 431 str(inputs) + '. All inputs to the layer '
432 'should be tensors.')
433
ValueError: Layer add_1 was called with an input that isn't a symbolic tensor. Received type: <class 'keras.layers.normalization.BatchNormalization'>. Full input: [<tf.Tensor 'Placeholder:0' shape=(3, 4, 4, 6) dtype=float32>, <keras.layers.normalization.BatchNormalization object at 0x7f169c6d9668>]. All inputs to the layer should be tensors.
I guess that I missed something in the final step of the function definition, but I have no idea why I got the error. Could any Keras expert here help me out?
Always remember to pass tensors into layers:
print(f'before BatchNormalization: X={X}');
#X = BatchNormalization(axis=3,name=bn_name_base+'2c') # <--- INCORRECT
X = BatchNormalization(axis=3,name=bn_name_base+'2c')(X) # <--- CORRECT
print(f'after BatchNormalization: X={X}');
The difference between 'CORRECT' and 'INCORRECT' is, latter yields a layer - whereas former evaluates that layer into a tensor when fed with X
.
Furthermore, your identity_block()
lacks a return, which will throw another error; add:
return X
. Lastly, F1, F2, F3
are neither defined within the function nor passed as arguments - which you may not see as an error since they were defined outside the function - e.g. in your local namespace.