How to graph tf.keras model in Tensorflow-2.0? - python-3.x

I upgraded to Tensorflow 2.0 and there is no tf.summary.FileWriter("tf_graphs", sess.graph). I was looking through some other StackOverflow questions on this and they said to use tf.compat.v1.summary etc. Surely there must be a way to graph and visualize a tf.keras model in Tensorflow version 2. What is it? I'm looking for a tensorboard output like the one below. Thank you!

You can visualize the graph of any tf.function decorated function, but first, you have to trace its execution.
Visualizing the graph of a Keras model means to visualize it's call method.
By default, this method is not tf.function decorated and therefore you have to wrap the model call in a function correctly decorated and execute it.
import tensorflow as tf
model = tf.keras.Sequential(
[
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(32, activation="relu"),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(10, activation="softmax"),
]
)
#tf.function
def traceme(x):
return model(x)
logdir = "log"
writer = tf.summary.create_file_writer(logdir)
tf.summary.trace_on(graph=True, profiler=True)
# Forward pass
traceme(tf.zeros((1, 28, 28, 1)))
with writer.as_default():
tf.summary.trace_export(name="model_trace", step=0, profiler_outdir=logdir)

According to the docs, you can use Tensorboard to visualise graphs once your model has been trained.
First, define your model and run it. Then, open Tensorboard and switch to the Graph tab.
Minimal Compilable Example
This example is taken from the docs. First, define your model and data.
# Relevant imports.
%load_ext tensorboard
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from datetime import datetime
from packaging import version
import tensorflow as tf
from tensorflow import keras
# Define the model.
model = keras.models.Sequential([
keras.layers.Flatten(input_shape=(28, 28)),
keras.layers.Dense(32, activation='relu'),
keras.layers.Dropout(0.2),
keras.layers.Dense(10, activation='softmax')
])
model.compile(
optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
(train_images, train_labels), _ = keras.datasets.fashion_mnist.load_data()
train_images = train_images / 255.0
Next, train your model. Here, you will need to define a callback for Tensorboard to use for visualising stats and graphs.
# Define the Keras TensorBoard callback.
logdir="logs/fit/" + datetime.now().strftime("%Y%m%d-%H%M%S")
tensorboard_callback = keras.callbacks.TensorBoard(log_dir=logdir)
# Train the model.
model.fit(
train_images,
train_labels,
batch_size=64,
epochs=5,
callbacks=[tensorboard_callback])
After training, in your notebook, run
%tensorboard --logdir logs
And switch to the Graph tab in the navbar:
You will see a graph that looks a lot like this:

Here is the solution for tf2.x with Graph visualization of subclassed model/layer
import tensorflow as tf
print("TensorFlow version:", tf.__version__)
from tensorflow.keras.layers import Dense, Flatten, Conv2D
from tensorflow.keras import Model,Input
class MyModel(Model):
def __init__(self, dim):
super(MyModel, self).__init__()
self.conv1 = Conv2D(16, 3, activation='relu')
self.conv2 = Conv2D(32, 3, activation='relu')
self.conv3 = Conv2D(8, 3, activation='relu')
self.flatten = Flatten()
self.d1 = Dense(128, activation='relu')
self.d2 = Dense(1)
def call(self, x):
x = self.conv1(x)
x = self.conv2(x)
x = self.conv3(x)
x = self.flatten(x)
x = self.d1(x)
return self.d2(x)
def build_graph(self):
x = Input(shape=(dim))
return Model(inputs=[x], outputs=self.call(x))
dim = (28, 28, 1)
# Create an instance of the model
model = MyModel((dim))
model.build((None, *dim))
model.build_graph().summary()
tf.keras.utils.plot_model(model.build_graph(), to_file="model.png",
expand_nested=True, show_shapes=True)
the output is
TensorFlow version: 2.5.0
Model: "model"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) [(None, 28, 28, 1)] 0
_________________________________________________________________
conv2d (Conv2D) (None, 26, 26, 16) 160
_________________________________________________________________
conv2d_1 (Conv2D) (None, 24, 24, 32) 4640
_________________________________________________________________
conv2d_2 (Conv2D) (None, 22, 22, 8) 2312
_________________________________________________________________
flatten (Flatten) (None, 3872) 0
_________________________________________________________________
dense (Dense) (None, 128) 495744
_________________________________________________________________
dense_1 (Dense) (None, 1) 129
=================================================================
Total params: 502,985
Trainable params: 502,985
Non-trainable params: 0
Here is also a graph visualization

Here's what is working for me at the moment (TF 2.0.0), based on the tf.keras.callbacks.TensorBoard code:
# After model has been compiled
from tensorflow.python.ops import summary_ops_v2
from tensorflow.python.keras.backend import get_graph
tb_path = '/tmp/tensorboard/'
tb_writer = tf.summary.create_file_writer(tb_path)
with tb_writer.as_default():
if not model.run_eagerly:
summary_ops_v2.graph(get_graph(), step=0)

Another option is to use this website: https://lutzroeder.github.io/netron/
which generate a graph with a .h5 or .tflite file.
The github repo it's based on may be found here:
https://github.com/lutzroeder/netron

Related

Keras: Custom loss function: Dimension Issue (None, None)

I am constructing a neural network with Keras. And I need to define a simple custom loss function. However, I met dimension problem of y_True in creating a custom loss function.
I inserted print function in loss function to verify the dimension of y_true (target variable). It shows that dimension of y_true is (none, none), but it should be (none, 10). The dimension of y_pred is (none, 10).
Anyone can point out where is the mistake? Thanks a lot.
from keras.datasets import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
from keras import models
from keras import layers
network = models.Sequential()
network.add(layers.Dense(512, activation='relu', input_shape=(28 * 28,)))
network.add(layers.Dense(10, activation='softmax'))
def customLoss(yTrue,yPred):
print(yTrue)
print(yPred)
print(K.int_shape(yTrue))
return K.dot(yTrue, yPred) # K.mean(K.dot(yTrue,yPred), axis=-1)
network.compile(optimizer='rmsprop',
loss=customLoss,
metrics=['accuracy']) # loss='categorical_crossentropy',
train_images = train_images.reshape((60000, 28 * 28))
train_images = train_images.astype('float32') / 255
test_images = test_images.reshape((10000, 28 * 28))
test_images = test_images.astype('float32') / 255
from keras.utils import to_categorical
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)
network.fit(train_images, train_labels, epochs=5, batch_size=128)

ValueError while performing 'binary-crossentropy' ==> array shapes not matching

I was using tensorflow + keras while trying to implement a "Text classification" model to classify different types of movie reviews. I am running into a error which tells that the shapes aren't equal.
Because I am not sure where the error might be hidden, I can't produce a reprex example as i am not certain how to isolate the problem. It may be worth your time if the line with variable(x_val) is there as there may be a problem with the partitioning.
note this is not the final code. as I had already encountered an error at this point, i stopped writing it.
from __future__ import absolute_import, division, print_function
import numpy as np
import tensorflow as tf
from tensorflow import keras
imdb = keras.datasets.imdb
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)
#print ("The length if training data: "len(train_data[0]), "And labels: "len(test_data[0]))
word_index = imdb.get_word_index()
word_index = {k: (v+3) for k,v in word_index.items()}
word_index["<PAD>"] = 0
word_index["<START>"] = 1
word_index["<UNKNOWN>"] = 2
word_index["<END>"] = 3
reverse_word_index = dict([(value, key) for (key, value) in word_index.items() ])
def decode_review(text):
return (' '.join([reverse_word_index.get(i , "?") for i in text ]))
print (decode_review(train_data[0]))
train_data = keras.preprocessing.sequence.pad_sequences(train_data,
value=word_index["<PAD>"],
padding="post",
maxlen=256)
test_data = keras.preprocessing.sequence.pad_sequences(test_data,
value=word_index["<PAD>"],
padding="post",
maxlen=256)
#print ('train length :' ,len(train_data[0]), 'test length: ', len(train_data[1]))
vocab_size = 10000
model = keras.Sequential()
model.add(keras.layers.Embedding(vocab_size , 16))
model.add(keras.layers.GlobalAveragePooling1D())
model.add(keras.layers.Dense(16, activation=tf.nn.relu))
model.add(keras.layers.Dense(16, activation=tf.nn.sigmoid))
print ("the model summary is :======>>" , model.summary())
model.compile(optimizer="adam" , loss="binary_crossentropy", metrics=["acc"])
x_val = train_data[:10000]
partial_x_train = train_data[10000:]
y_val = train_labels[:10000]
partial_y_train = train_labels[10000:]
history = model.fit(partial_x_train , partial_y_train , epochs=40 , batch_size=512,
validation_data=(x_val, y_val), verbose=1)
This is the error message I was getting:-----
Model: "sequential_1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding_1 (Embedding) (None, None, 16) 160000
_________________________________________________________________
global_average_pooling1d_1 ( (None, 16) 0
_________________________________________________________________
dense_2 (Dense) (None, 16) 272
_________________________________________________________________
dense_3 (Dense) (None, 16) 272
=================================================================
Total params: 160,544
Trainable params: 160,544
Non-trainable params: 0
_________________________________________________________________
the model summary is :======>> None
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
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-18-02082e1f39d4> in <module>()
57
58 history = model.fit(partial_x_train , partial_y_train , epochs=40 , batch_size=512,
---> 59 validation_data=(x_val, y_val), verbose=1)
ValueError: A target array with shape (15000, 1) was passed for an output of shape (None, 16) while using as loss `binary_crossentropy`. This loss expects targets to have the same shape as the output.
You need to update the final/output layer of your model. Since it's a binary classification problem, the output Dense layer should have one node like follows:
model.add(keras.layers.Dense(1, activation=tf.nn.sigmoid))
You may want to check out this tutorial on text classification using IMDB dataset.

issue while using LSTM in functional mode

When creating a LSTM layer using the functional moded below error is thrown
ValueError: Input 0 is incompatible with layer lstm_1: expected ndim=3, found ndim=2
Code to reproduce the issue
import keras
from keras.layers import Input, LSTM, Dense
from keras.models import Model
import numpy as np
def build_lstm(lstm_input, hidden_dim=256):
out = LSTM(hidden_dim, input_shape=(1, 129))(lstm_input)
return out
def test_lstm():
lstm_input = Input(shape=(129, ), name='lstm_input')
out = build_lstm(lstm_input)
predictions = Dense(256, activation='softmax')(out)
model = Model(inputs=lstm_input, outputs=predictions)
model.compile(loss='categorical_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
model.summary()
return
Error Log
(NPI_Arch_Keras) C:\workspaces\NPL\project\NPI_Arch_Keras\npi>python npi_lstm_test.py
Using TensorFlow backend.
Traceback (most recent call last):
File "npi_lstm_test.py", line 35, in <module>
test_lstm()
File "npi_lstm_test.py", line 21, in test_lstm
out = build_lstm(lstm_input)
File "npi_lstm_test.py", line 15, in build_lstm
out = LSTM(hidden_dim, input_shape=(1, 129))(lstm_input)
File "C:\MyProgramFiles\Anaconda3\envs\NPI_Arch_Keras\lib\site-packages\keras\layers\recurrent.py", line 532, in __call__
return super(RNN, self).__call__(inputs, **kwargs)
File "C:\MyProgramFiles\Anaconda3\envs\NPI_Arch_Keras\lib\site-packages\keras\engine\base_layer.py", line 414, in __call__
self.assert_input_compatibility(inputs)
File "C:\MyProgramFiles\Anaconda3\envs\NPI_Arch_Keras\lib\site-packages\keras\engine\base_layer.py", line 311, in assert_input_compatibility
str(K.ndim(x)))
ValueError: Input 0 is incompatible with layer lstm_1: expected ndim=3, found ndim=2
The below version of the code which uses the Sequential model runs successfully
import keras
from keras.models import Sequential
from keras.layers import LSTM, Dense
import numpy as np
def build_lstm(hidden_dim=256, input_shape=None):
model = Sequential()
model.add(LSTM(hidden_dim, return_sequences=True, input_shape=input_shape))
model.add(LSTM(hidden_dim))
return model
def test_lstm():
model = Sequential()
model.add(build_lstm(input_shape=(1, 129)))
model.add(Dense(256, activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
model.summary()
return
Success log
(NPI_Arch_Keras) C:\workspaces\NPL\project\NPI_Arch_Keras\npi>python npi_lstm_working.py
Using TensorFlow backend.
WARNING:tensorflow:From C:\MyProgramFiles\Anaconda3\envs\NPI_Arch_Keras\lib\site-packages\tensorflow\python\framework\op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.
Instructions for updating:
Colocations handled automatically by placer.
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
sequential_2 (Sequential) (None, 256) 920576
_________________________________________________________________
dense_1 (Dense) (None, 256) 65792
=================================================================
Total params: 986,368
Trainable params: 986,368
Non-trainable params: 0
_________________________________________________________________
This code should work in the functional model:
in = Input(shape=(1, 129))
lstm_1 = LSTM(256, return_sequences=True)(in)
lstm_2 = LSTM(256)(lstm_1)
out = Dense(256)(lstm_2)
model = Model(in, out)

Training issue in keras

I am trying to train my lstm model for sentiment analysis but the program doesnt proceed at all after displaying the following output:
F:\Softwares\Anaconda\lib\site-packages\h5py\__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.
from ._conv import register_converters as _register_converters
Using TensorFlow backend.
Extracting features & training batches
Training...
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding_1 (Embedding) (None, 134, 70) 42481880
_________________________________________________________________
dropout_1 (Dropout) (None, 134, 70) 0
_________________________________________________________________
lstm_1 (LSTM) (None, 128) 101888
_________________________________________________________________
dense_1 (Dense) (None, 64) 8256
_________________________________________________________________
dropout_2 (Dropout) (None, 64) 0
_________________________________________________________________
activation_1 (Activation) (None, 64) 0
_________________________________________________________________
dense_2 (Dense) (None, 1) 65
_________________________________________________________________
activation_2 (Activation) (None, 1) 0
=================================================================
Total params: 42,592,089
Trainable params: 42,592,089
Non-trainable params: 0
_________________________________________________________________
None
Train on 360000 samples, validate on 90000 samples
Epoch 1/8
2018-12-08 15:56:04.680836: I T:\src\github\tensorflow\tensorflow\core\platform\cpu_feature_guard.cc:140] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2
The code below has some commented out since it was used to save some textual data on disk beforehand. Now, the code only trains the lstm model using that training and testing textual data. It is given below:
import pandas as pd
import Preprocessing as pre
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.utils import shuffle
import pickle
import numpy as np
import sys
from keras.models import Sequential, load_model
from keras.layers import Dense, Dropout, Activation
from keras.layers import Embedding
from keras.callbacks import ModelCheckpoint, ReduceLROnPlateau
from keras.layers import LSTM
from keras.preprocessing.sequence import pad_sequences
from keras.models import model_from_json
from keras.preprocessing.text import Tokenizer
import os
# fileDir = os.path.dirname(os.path.realpath('__file__'))
# df = pd.read_csv(os.path.join(fileDir, '../Dataset/tweets.csv'),header=None,encoding = "ISO-8859-1")
# df=shuffle(df)
# length=df.size
#
# train=[]
# test=[]
# Y=[]
# Y2=[]
#
# count=450000
# for a in range(450000): #loading data
# b=pre.preprocess_tweet(df[1][a])
# label=int(df[0][a])
# train.append(b)
# Y.append(label)
# count-=1
# print("Loading training data...", count)
#
# with open('training_data(latest).obj', 'wb') as fp:
# pickle.dump(train, fp)
# with open('training_labels(latest).obj', 'wb') as fp:
# pickle.dump(Y, fp)
with open ('training_data(latest).obj', 'rb') as fp:
train = pickle.load(fp)
with open ('training_labels(latest).obj', 'rb') as fp:
Y = pickle.load(fp)
# count=156884
# for a in range(450000,606884): #loading testin data
# b = pre.preprocess_tweet(df[1][a])
# label=int(df[0][a])
# test.append(b)
# Y2.append(label)
# count-=1
# print("Loading testing data...", count)
#
# with open('testing_data(latest).obj', 'wb') as fp:
# pickle.dump(test, fp)
# with open('testing_labels(latest).obj', 'wb') as fp:
# pickle.dump(Y2, fp)
with open ('testing_data(latest).obj', 'rb') as fp:
test = pickle.load(fp)
with open ('testing_labels(latest).obj', 'rb') as fp:
Y2 = pickle.load(fp)
# vectorizer = CountVectorizer(analyzer = "word",tokenizer = None, preprocessor = None, stop_words = None, max_features = 2000)
# # # fit_transform() does two functions: First, it fits the model
# # # and learns the vocabulary; second, it transforms our training data
# # # into feature vectors. The input to fit_transform should be a list of
# # # strings.
#
# train = vectorizer.fit_transform(train)
# test = vectorizer.transform(test)
tokenizer = Tokenizer(split=' ')
tokenizer.fit_on_texts(train)
train = tokenizer.texts_to_sequences(train)
max_words = 134
train = pad_sequences(train, maxlen=max_words)
tokenizer.fit_on_texts(test)
test = tokenizer.texts_to_sequences(test)
test = pad_sequences(test, maxlen=max_words)
print('Extracting features & training batches')
print("Training...")
embedding_size=32
model = Sequential()
model.add(Embedding(606884, 70, input_length=134))
model.add(Dropout(0.4))
model.add(LSTM(128))
model.add(Dense(64))
model.add(Dropout(0.5))
model.add(Activation('relu'))
model.add(Dense(1))
model.add(Activation('sigmoid'))
print(model.summary())
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
batch_size = 100
num_epochs = 8
model.fit(train, np.array(Y), batch_size=batch_size, epochs=num_epochs ,validation_split=0.2,shuffle=True,verbose=2)
# Save the weights
model.save_weights('LSTM_model_weights_updated.h5')
# Save the model architecture
with open('LSTM_model_updated.json', 'w') as f:
f.write(model.to_json())
# #
# Model reconstruction from JSON file
# with open(os.path.join(fileDir, '../Dataset/LSTM_model.json'), 'r') as f:
# model = model_from_json(f.read())
#
# # Load weights into the new model
# model.load_weights(os.path.join(fileDir, '../Dataset/LSTM_model_weights.h5'))
# model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
scores = model.evaluate(test, np.array(Y2))
print('Evaluation Test accuracy:', scores[1])
count=0
sum=0
#
#
b=model.predict(test)
for a in b:
print(count)
if a<0.5:
sum = sum + abs(Y2[count] - 0) # error finding
else:
sum=sum+ abs(Y2[count]-1) #error finding
count+=1
acc=100-((sum/156884)*100)
print ("Accuracy=",acc,"count",count)
Total params: 42,592,089
Trainable params: 42,592,089
Non-trainable params: 0
Your model has more than 42 million trainable parameters which is too much for your machine's configuration (CPU, RAM, etc.), thus it can't handle it. What are the options?
Use smaller model
Use a better more powerful computer (with GPU of course)
Consider using an online cloud solution like crestle or paperspace

In Keras, how to get the layer name associated with a "Model" object contained in my model?

I built a Sequential model with the VGG16 network at the initial base, for example:
from keras.applications import VGG16
conv_base = VGG16(weights='imagenet',
# do not include the top, fully-connected Dense layers
include_top=False,
input_shape=(150, 150, 3))
from keras import models
from keras import layers
model = models.Sequential()
model.add(conv_base)
model.add(layers.Flatten())
model.add(layers.Dense(256, activation='relu'))
# the 3 corresponds to the three output classes
model.add(layers.Dense(3, activation='sigmoid'))
My model looks like this:
model.summary()
Layer (type) Output Shape Param #
=================================================================
vgg16 (Model) (None, 4, 4, 512) 14714688
_________________________________________________________________
flatten_1 (Flatten) (None, 8192) 0
_________________________________________________________________
dense_7 (Dense) (None, 256) 2097408
_________________________________________________________________
dense_8 (Dense) (None, 3) 771
=================================================================
Total params: 16,812,867
Trainable params: 16,812,867
Non-trainable params: 0
_________________________________________________________________
Now, I want to get the layer names associated with the vgg16 Model portion of my network. I.e. something like:
layer_name = 'block3_conv1'
filter_index = 0
layer_output = model.get_layer(layer_name).output
loss = K.mean(layer_output[:, :, :, filter_index])
However, since the vgg16 convolutional is shown as a Model and it's layers are not being exposed, I get the error:
ValueError: No such layer: block3_conv1
How do I do this?
The key is to first do .get_layer on the Model object, then do another .get_layer on that specifying the specific vgg16 layer, THEN do .output:
layer_output = model.get_layer('vgg16').get_layer('block3_conv1').output
To get the name of the layer from the VGG16 instance use the following code.
for layer in conv_base.layers:
print(layer.name)
the name should be the same inside your model. to show this you could do the following.
print([layer.name for layer in model.get_layer('vgg16').layers])
like Ryan showed us. to call the vgg16 layer you must call it from the model first using the get_layer method.
One can simply store the name of layers in the list for further usage
layer_names=[layer.name for layer in base_model.layers]
This worked for me :)
for idx in range(len(model.layers)):
print(model.get_layer(index = idx).name)
Use the layer's summary:
model.get_layer('vgg16').summary()

Resources