I am having many troubles trying to start training my model (a DCGAN). It is giving me the error:
'tuple' object has no attribute 'layer'
I read that this could be due to having both the TensorFlow version 1.14.0 and the Keras version 2.2 or higher. I tried to fix this by downgrading the Keras version to the 2.1.5, but I'm still having the same problem.
from google.colab import drive
drive.mount('/mntDrive')
import os,sys #os es para gestionar directorios (trabajar con archivos); sys es para trabajar con variables del sistema
# numpy
import numpy as np
# data processing, CSV file I/O (e.g. pd.read_csv)
import pandas as pd
from sklearn.model_selection import train_test_split
# Charts
import matplotlib.pyplot as plt
from matplotlib.pyplot import imread
#process
from tqdm import tqdm
# Image IO
from PIL import Image
import skimage.io
import skimage.transform
from skimage.transform import resize
# Deep learning
import tensorflow as tf
from tensorflow.keras import layers
from keras import optimizers
from keras.models import Sequential, Model
from keras.layers.advanced_activations import LeakyReLU
from keras.layers import Dense, Conv2D, Flatten, MaxPool2D, Dropout, Input
from keras.callbacks import ModelCheckpoint
from keras.preprocessing.image import ImageDataGenerator
from keras.optimizers import Adam
from keras import initializers
from __future__ import absolute_import, division, print_function, unicode_literals
# To make sure that we can reproduce the experiment and get the same results
np.random.seed(21)
# The dimension of our random noise vector.
random_dim = 100
from skimage.color import rgb2gray
import scipy.ndimage
import scipy.misc
import re
images = []
for root, dirnames, filenames in os.walk("/mntDrive/My Drive/Colab Notebooks/cubism"):
for filename in filenames:
if re.search("\.(jpg|jpeg|png)$", filename):
filepath = os.path.join(root, filename)
image = plt.imread(filepath, )
image = (image.astype(np.float32) - 127.5)/127.5
image_resized = resize(image, (112, 112))
images.append(image_resized)
images = np.array(images)
print('Original image shape: {}'.format(images.shape))
im_gray = rgb2gray(images)
print('New image shape: {}'.format(im_gray.shape))
images_resized = im_gray.reshape(320,12544)
def get_optimizer():
optimizer=tf.keras.optimizers.Adam(0.001)
return optimizer
def make_generator_model(optimizer):
generator = tf.keras.Sequential()
generator.add(layers.Dense(7*7*256, use_bias=False, input_shape=(random_dim,)))
generator.add(layers.BatchNormalization())
generator.add(layers.LeakyReLU())
generator.add(layers.Reshape((7, 7, 256)))
assert generator.output_shape == (None, 7, 7, 256) # Note: None is the batch size
generator.add(layers.Conv2DTranspose(128, (5, 5), strides=(2, 2), padding='same', use_bias=False))
assert generator.output_shape == (None, 14, 14, 128)
generator.add(layers.BatchNormalization())
generator.add(layers.LeakyReLU())
generator.add(layers.Conv2DTranspose(64, (5, 5), strides=(2, 2), padding='same', use_bias=False))
assert generator.output_shape == (None, 28, 28, 64)
generator.add(layers.BatchNormalization())
generator.add(layers.LeakyReLU())
generator.add(layers.Conv2DTranspose(32, (5, 5), strides=(2, 2), padding='same', use_bias=False))
assert generator.output_shape == (None, 56, 56, 32)
generator.add(layers.BatchNormalization())
generator.add(layers.LeakyReLU())
generator.add(layers.Conv2DTranspose(1, (5, 5), strides=(2, 2), padding='same', use_bias=False, activation='tanh'))
assert generator.output_shape == (None, 112, 112, 1)
generator.compile(loss='binary_crossentropy', optimizer=tf.keras.optimizers.Adam(0.001))
return generator
def make_discriminator_model(optimizer):
discriminator = tf.keras.Sequential()
discriminator.add(layers.Conv2D(64, (5, 5), strides=(2, 2), padding='same', input_shape=[112, 112, 1]))
discriminator.add(layers.LeakyReLU())
discriminator.add(layers.Dropout(0.3))
discriminator.add(layers.Conv2D(128, (5, 5), strides=(2, 2), padding='same'))
discriminator.add(layers.LeakyReLU())
discriminator.add(layers.Dropout(0.3))
discriminator.add(layers.Conv2D(256, (5, 5), strides=(2, 2), padding='same'))
discriminator.add(layers.LeakyReLU())
discriminator.add(layers.Dropout(0.3))
discriminator.add(layers.Flatten())
discriminator.add(layers.Dense(1, activation='sigmoid' ))
discriminator.compile(loss='binary_crossentropy', optimizer=tf.keras.optimizers.Adam(0.001))
return discriminator
def get_gan_network(discriminator, random_dim, generator, optimizer):
# We initially set trainable to False since we only want to train either the
# generator or discriminator at a time
discriminator.trainable = False
# gan input (noise) will be 100-dimensional vectors
gan_input = Input(shape=(random_dim,))
# the output of the generator (an image)
x = generator(gan_input)
# get the output of the discriminator (probability if the image is real or not)
gan_output = discriminator(x)
gan = Model(inputs=gan_input, outputs=gan_output)
gan.compile(loss='binary_crossentropy', optimizer=tf.keras.optimizers.Adam(0.001))
return gan
def plot_generated_images(epoch, generator, examples=64, dim=(10, 10), figsize=(100, 100)):
noise = np.random.normal(0, 1, size=[examples, random_dim]) #mean, std deviation, size
generated_images = generator.predict(noise)
generated_images = generated_images.reshape(examples, 112, 112)
plt.figure(figsize=figsize)
for i in range(generated_images.shape[0]):
plt.subplot(dim[0], dim[1], i+1)
plt.imshow(generated_images[i], interpolation='nearest', cmap='gray_r')
plt.axis('off')
plt.tight_layout()
plt.savefig('dcgan_generated_Originals_2_epoch_%d.png' % epoch)
#you can create a function which will save your generated images every 20 epochs
# Create a wall of generated MNIST images
def train(epochs=15000, batch_size=80):
# Get the training and testing data
images_resized
# Split the training data into batches of size 80
batch_count = images_resized.shape[0] // batch_size
# Build our GAN network
optimizer=get_optimizer()
generator = make_generator_model(optimizer)
discriminator = make_discriminator_model(optimizer)
gan = get_gan_network(discriminator, random_dim, generator, optimizer)
for e in range(1, epochs+1):
print ('-'*15, 'Epoch %d' % e, '-'*15)
for _ in tqdm(range(batch_count)):
# Get a random set of input noise and images
noise = np.random.normal(0, 1, size=[batch_size, random_dim])
image_batch = images_resized[np.random.randint(0, images_resized.shape[0], size=batch_size)]
# Generate fake MNIST images
generated_images = generator.predict(noise)
X = np.concatenate([image_batch, generated_images]) #128x4096 --- 'a' x 4096
# Labels for generated and real data
y_dis = np.zeros(2*batch_size)
y_dis[:batch_size] = 0.9 # One-sided label smoothing. Se refiere a que la mitad de y_dis seran 0.9 (reales) y la otra mitad seran 0 (falsos)
# Train discriminator
discriminator.trainable = True
discriminator.train_on_batch(X, y_dis) #Se entrena el Discriminador con dos vectores: X(tiene un batch(128) imagenes reales y un batch de imagenes generadas); y_dis(tiene un batch de 128 0.9(serian las reales) y otro batch de 128 ceros(serian las generadas). De esta manera, el algoritmo generador, aunque las genere bien, va a seguir optimizandose el numero de epochs que haga falta(seguimos en la fase de entrenamiento), ya que sus imagenes son continuamente rechazadas, comparandose con las reales y sacando continuamente diferencias. )
#Entra X(imagenes reales, imagenes generadas)--->y_dis(0.9 , 0)
#train_on_batch(x,y)---> realiza una actualizacion del gradiente en un batch----> x=array de training data (si el modelo tiene varias entradas pueden ser varios); y= array de target data (si el modelo tiene varias salidas pueden ser varios)
# Train generator
noise = np.random.normal(0, 1, size=[batch_size, random_dim])
y_gen = np.ones(batch_size)
discriminator.trainable = False
gan.train_on_batch(noise, y_gen) #Entra noise(pixeles desordenados)---->y_gen(todo son 1)
if e == 1 or e % 50 == 0:
plot_generated_images(e, generator)
if __name__ == '__main__':
train(30000, 80)
This is the output:
Drive already mounted at /mntDrive; to attempt to forcibly remount, call drive.mount("/mntDrive", force_remount=True).
Original image shape: (320, 112, 112, 3)
New image shape: (320, 112, 112)
WARNING:tensorflow:From /usr/local/lib/python3.6/dist-packages/tensorflow/python/ops/init_ops.py:1251: calling VarianceScaling.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Call initializer instance with the dtype argument instead of passing it to the constructor
WARNING:tensorflow:From /usr/local/lib/python3.6/dist-packages/tensorflow/python/ops/nn_impl.py:180: add_dispatch_support.<locals>.wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.where in 2.0, which has the same broadcast rule as np.where
WARNING:tensorflow:From /usr/local/lib/python3.6/dist-packages/keras/backend/tensorflow_backend.py:68: The name tf.get_default_graph is deprecated. Please use tf.compat.v1.get_default_graph instead.
WARNING:tensorflow:From /usr/local/lib/python3.6/dist-packages/keras/backend/tensorflow_backend.py:507: The name tf.placeholder is deprecated. Please use tf.compat.v1.placeholder instead.
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-18-6e3c9ece87ff> in <module>()
196
197 if __name__ == '__main__':
--> 198 train(30000, 80)
11 frames
<ipython-input-18-6e3c9ece87ff> in train(epochs, batch_size)
161 generator = make_generator_model(optimizer)
162 discriminator = make_discriminator_model(optimizer)
--> 163 gan = get_gan_network(discriminator, random_dim, generator, optimizer)
164
165 for e in range(1, epochs+1):
<ipython-input-18-6e3c9ece87ff> in get_gan_network(discriminator, random_dim, generator, optimizer)
128 gan_input = Input(shape=(random_dim,))
129 # the output of the generator (an image)
--> 130 x = generator(gan_input)
131 # get the output of the discriminator (probability if the image is real or not)
132 gan_output = discriminator(x)
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/base_layer.py in __call__(self, inputs, *args, **kwargs)
632 outputs = base_layer_utils.mark_as_return(outputs, acd)
633 else:
--> 634 outputs = call_fn(inputs, *args, **kwargs)
635
636 except TypeError as e:
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/sequential.py in call(self, inputs, training, mask)
245 if not self.built:
246 self._init_graph_network(self.inputs, self.outputs, name=self.name)
--> 247 return super(Sequential, self).call(inputs, training=training, mask=mask)
248
249 outputs = inputs # handle the corner case where self.layers is empty
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/network.py in call(self, inputs, training, mask)
749 ' implement a `call` method.')
750
--> 751 return self._run_internal_graph(inputs, training=training, mask=mask)
752
753 def compute_output_shape(self, input_shape):
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/network.py in _run_internal_graph(self, inputs, training, mask)
891
892 # Compute outputs.
--> 893 output_tensors = layer(computed_tensors, **kwargs)
894
895 # Update tensor_dict.
/usr/local/lib/python3.6/dist-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)
/usr/local/lib/python3.6/dist-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
/usr/local/lib/python3.6/dist-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)
/usr/local/lib/python3.6/dist-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
/usr/local/lib/python3.6/dist-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
/usr/local/lib/python3.6/dist-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'
AttributeError: 'tuple' object has no attribute 'layer'
You have imported layers from tensorflow.keras while other functions you have imported from keras. You can either import your layers from keras or try importing other functions from tensorflow.keras which might work.
I am only new in Python and deep learning. But I wanted to share this, as it helped me with a similar error. Maybe, in the importing section, try:
import tensorflow.keras
For all the rest you have to import from keras, keep the tensorflow. in front. And type it as a whole when using anything from keras later. Eg:
model.add(tensorflow.keras.layers.Conv2D())
Then you will not need: import tensorflow as tf
The tuple probably refers to your input_shape. What I mention above solved my problem.
I cannot answer why exactly this happens, though.
Ran into this issue when using GPU/TPU on Colab and trying to use Tensorflow v1.14 by installing it using pip. The docs advise against installing tensorflow using pip on GPU/TPU, instead they recommend to use %tensorflow_version 1.x
. Setting it as this, fixed my problem.
Docs: https://colab.research.google.com/notebooks/tensorflow_version.ipynb
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With