Pagna401
Pagna401

Reputation: 29

Using python code with tf.py_func in custom Keras layer

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

Answers (4)

Meng Hui Tan
Meng Hui Tan

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

nairouz mrabah
nairouz mrabah

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

julhien
julhien

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

Related Questions