keras-team / keras-applications

Reference implementations of popular deep learning models.
Other
2k stars 913 forks source link

Keras Lambda making a custom simple layer, tuple TypeError #125

Open BobZiyangDing opened 5 years ago

BobZiyangDing commented 5 years ago

Here's the task: I've got 2 Keras layers, encode_p_neck & encode_g_neck. They are of the same dimension. I want to calculate the distance between these 2 vectors, and if the distance is greater than a threshold, then I predict this pair of 2 vectors as negative. If the distance is smaller than a threshold, then I predict this pair of 2 vectors as positive. At last, I want to calculate AUC and output this prediction. The responsible code is as follows:

distance = Subtract()([encode_p_neck, encode_g_neck])

def getOutput(X):
    distance = tf.norm(X, axis = 1)
    output = K.cast(tf.less_equal(distance, threshold), tf.float32)
    return output

output = Lambda(getOutput)(distance)

because the output for Keras model has to be a layer, so I did this. But error shows:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-197-18acac9c7a3b> in <module>
     74     return output
     75 
---> 76 output = Lambda(getOutput)(distance)
     77 
     78 

~\AppData\Local\Continuum\anaconda3\lib\site-packages\tensorflow\python\keras\engine\base_layer.py in __call__(self, inputs, *args, **kwargs)
    661               kwargs.pop('training')
    662             inputs, outputs = self._set_connectivity_metadata_(
--> 663                 inputs, outputs, args, kwargs)
    664           self._handle_activity_regularization(inputs, outputs)
    665           self._set_mask_metadata(inputs, outputs, previous_mask)

~\AppData\Local\Continuum\anaconda3\lib\site-packages\tensorflow\python\keras\engine\base_layer.py in _set_connectivity_metadata_(self, inputs, outputs, args, kwargs)
   1706     kwargs.pop('mask', None)  # `mask` should not be serialized.
   1707     self._add_inbound_node(
-> 1708         input_tensors=inputs, output_tensors=outputs, arguments=kwargs)
   1709     return inputs, outputs
   1710 

~\AppData\Local\Continuum\anaconda3\lib\site-packages\tensorflow\python\keras\engine\base_layer.py in _add_inbound_node(self, input_tensors, output_tensors, arguments)
   1793     """
   1794     inbound_layers = nest.map_structure(lambda t: t._keras_history.layer,
-> 1795                                         input_tensors)
   1796     node_indices = nest.map_structure(lambda t: t._keras_history.node_index,
   1797                                       input_tensors)

~\AppData\Local\Continuum\anaconda3\lib\site-packages\tensorflow\python\util\nest.py in map_structure(func, *structure, **kwargs)
    513 
    514   return pack_sequence_as(
--> 515       structure[0], [func(*x) for x in entries],
    516       expand_composites=expand_composites)
    517 

~\AppData\Local\Continuum\anaconda3\lib\site-packages\tensorflow\python\util\nest.py in <listcomp>(.0)
    513 
    514   return pack_sequence_as(
--> 515       structure[0], [func(*x) for x in entries],
    516       expand_composites=expand_composites)
    517 

~\AppData\Local\Continuum\anaconda3\lib\site-packages\tensorflow\python\keras\engine\base_layer.py in <lambda>(t)
   1792             `call` method of the layer at the call that created the node.
   1793     """
-> 1794     inbound_layers = nest.map_structure(lambda t: t._keras_history.layer,
   1795                                         input_tensors)
   1796     node_indices = nest.map_structure(lambda t: t._keras_history.node_index,

AttributeError: 'tuple' object has no attribute 'layer'

Why? How to fix this?

2sang commented 5 years ago
import tensorflow as tf
from keras.models import Model
from keras.layers import Subtract, Lambda, Dense, Input, Flatten
from keras import backend as K
from keras.datasets import mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

x_train = x_train.reshape((-1, 784))
x_test = x_test.reshape((-1, 784))

inputs = Input(shape=(784,))
x1 = Dense(64, activation='relu')(inputs)
x2 = Dense(64, activation='relu')(x1)
predictions = Dense(10, activation='softmax')(x2)

model = Model(inputs=inputs, outputs=predictions)
model.compile(optimizer='rmsprop',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.fit(x_train, y_train) 

## And yours
threshold = 30
distance = Subtract()([x1, x2])

def getOutput(X):
    distance = tf.norm(X, axis = 1)
    output = K.cast(tf.less_equal(distance, threshold), tf.float32)
    return output

output = Lambda(getOutput)(distance)
model_i = Model(inputs=inputs, outputs=output)
predicted_i = model_i.predict(x_test)

import numpy as np
print(np.unique(predicted_i, return_counts=True))
# And this gives following:
>>> (array([0., 1.], dtype=float32), array([   4, 9996]))

I couldn't reproduce your error, it worked just fine as you intended. And by the way, this kind of question is better to be asked in Stackoverflow I guess, since it seems like it's not an issue or a bug of the project. :)