Reputation: 29
I want to write my own Keras layer which invokes a python function.
So I came across tf.py_func
which should actually do the job.
I tried the following: In the call-method of the MyLayer Class I wrapped my custom python function myFunc in tf.py_func
. So the call-method returns tf.py_func(myFunc, [input], tf.float32)
.
I get the following error message:
TypeError: unsupported operand type(s) for %=: 'int' and 'NoneType'
What's the correct way of calling a python function in a custom Keras layer? What am I doing wrong?
Upvotes: 2
Views: 2745
Reputation: 11
If you declare weights at def build(self, input_shape):, then you have to "use" all the weights after the tf.py_func call.
import tensorflow as tf
from keras import backend as K
from keras.engine.topology import Layer
class MultiplyLayer(Layer):
def __init__(self, **kwargs):
super(MultiplyLayer, self).__init__(**kwargs)
def build(self, input_shape):
self.filters = self.add_weight(name='Filters', shape=(1, input_shape[1]), initializer='uniform', trainable=True)
super(MultiplyLayer, self).build(input_shape) # Be sure to call this at the end
def call(self, x):
xw = x * self.filters
def my_func(x):
return 5 * x
X = tf.py_func(my_func, [xw], tf.float32)
return X + (self.filters - self.filters)
def compute_output_shape(self, input_shape):
return (input_shape)
def get_model():
model = Sequential()
model.add(MultiplyLayer(input_shape=(num_features,)))
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.25))
model.add(Dense(64, activation='relu'))
model.add(Dropout(0.4))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.optimizers.Adadelta(), metrics=['accuracy'])
return model
model = get_model()
model.summary()
model.fit(X_train, y_train_hot, batch_size=batch_size, epochs=epochs, verbose=verbose, validation_data=(X_test, y_test_hot))
Upvotes: 1
Reputation: 1
Wrap your function with Lambda
layer and call py_func
in your function.
def my_func(x):
return 5 * x
def my_lambda_func(x):
return py_func(my_func,[x],tf.float32)
x = Lambda(my_lambda_func)(x)
Upvotes: 0
Reputation: 1217
You just need to wrap you function with a Lambda layer. Here is an example:
def complex_tf_fn(x):
u, v = tf.nn.moments(x, axes=[1], keep_dims=True)
return (x - u) / tf.sqrt(v)
with tf.device('/cpu:0'):
model = tf.keras.Sequential([
tf.keras.layers.Lambda(complex_tf_fn, input_shape=[784]),
tf.keras.layers.Dense(1024, activation='relu'),
tf.keras.layers.Lambda(complex_tf_fn),
tf.keras.layers.Dense(10, activation='softmax')
])
Upvotes: 0
Reputation: 91
You'd have to show the code of your layer and the function you pass to pyfunc for us to understand the error. However, although it is possible to embed tf functions in custom Keras layers, the best option in this case is probably to use a Keras lambda layer : https://keras.io/layers/core/#lambda
This directly takes a python function as a parameter. Like tf.py_func, it expects a function that takes a numpy array as input and outputs a numpy array.
Upvotes: 1