Using an Embedding layer in the Keras functional API - python-3.x

Doing basic things with the Keras Functional API seems to produce errors. For example, the following fails:
from keras.layers import InputLayer, Embedding
input = InputLayer(name="input", input_shape=(1, ))
embedding = Embedding(10000, 64)(input)
This produces the error:
AttributeError: 'str' object has no attribute 'base_dtype'
I can then "cheat" by using the input_length argument but this then fails when I try to concatenate two such embeddings:
from keras.layers import InputLayer, Embedding, Concatenate
embedding1 = Embedding(10000, 64, input_length=1)
embedding2 = Embedding(10000, 64, input_length=1)
concat = Concatenate()([embedding1 , embedding2])
This gives the error:
TypeError: 'NoneType' object is not subscriptable
Same error when I use "concatenate" (lower case) instead (some sources seem to say that this should be used instead if using the functional API).
What am I doing wrong?
I am on tensorflow version 2.3.1, keras version 2.4.3, python version 3.6.7

I strongly suggest to use tf.keras and not keras.
It doesn't work because InputLayer is an instance of keras.Layer, whereas keras.layers.Input is an instance of Tensor. The argument to layer.__call__() should be Tensor and not keras.Layer.
import tensorflow as tf
inputs = tf.keras.layers.Input((1,))
print(type(inputs)) # <class 'tensorflow.python.framework.ops.Tensor'>
input_layer = tf.keras.layers.InputLayer(input_shape=(1,))
print(type(input_layer)) # <class 'tensorflow.python.keras.engine.input_layer.InputLayer'>
You use InputLayer with Sequential API. When you use functional API you should use tf.keras.layers.Input() instead:
import tensorflow as tf
inputs = tf.keras.layers.Input((1, ), name="input", )
embedding = tf.keras.layers.Embedding(10000, 64)(inputs)
Same with the second example:
import tensorflow as tf
inputs = tf.keras.layers.Input((1, ), name="input", )
embedding1 = tf.keras.layers.Embedding(10000, 64)(inputs)
embedding2 = tf.keras.layers.Embedding(10000, 64)(inputs)
concat = tf.keras.layers.Concatenate()([embedding1, embedding2])

Related

Pytorch to ONNX conversion error DeeplabV3

I'm trying to convert a Pytorch model to ONNX usin this code:
import onnx
import torch
import onnxruntime
import numpy as np
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
batch_size = 1
model = torch.jit.load('../saved_weights/model.pt')
x = torch.randn(1, 3, 224, 224, requires_grad=True)
x = x.to(device)
torch_out = model(x)
torch_out = torch_out['out']
torch.onnx.export(model, x, "../saved_weights/model.onnx",
export_params=True,
opset_version=12,
do_constant_folding=True,
input_names=['input'],
output_names=['out'],
dynamic_axes={ 'input': {0 : 'batch_size'},
'output': {0 : 'batch_size'}})
However I'm getting the following error:
raise errors.UnsupportedOperatorError(
torch.onnx.errors.UnsupportedOperatorError: Exporting the operator
'aten::dict' to ONNX opset version 12 is not supported.
I'm not sure why, but could it be that the model output is in the form of a dictionary?
Referring Pytorch doc, you can try:
Change the model to not use that operator (here, dictionary).
Create a symbolic function to convert the operator and register it as a custom symbolic function.
Contribute to PyTorch to add the same symbolic function to torch.onnx itself.
My recommendation is to change the output type to a tensor.
Also, you can visit here and check supported operators.
Solution: I had to save the model using model.save instead of a scripted model:
model_scripted = torch.jit.script(model) # Export to TorchScript
model_scripted.save('model_scripted.pt') # Save

NameError: name 'Model is not defined'-how to resolve this?

I am trying to classify 2 categories with transfer learning. After preprocessing my data I want to apply 'InceptionResNetV2'. Where I want to remove the last layer of this Keras application and want to add a layer.
The following script I wrote to do this:
irv2 = tf.keras.applications.inception_resnet_v2.InceptionResNetV2()
irv2.summary()
x = irv2.layers[-1].output
x = Dropout(0.25)(x)
predictions = Dense(2, activation='softmax')(x)
model = Model(inputs=mobile.input, outputs=predictions)
Then an error occurred:
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-40-911de74d9eaf> in <module>()
5 predictions = Dense(2, activation='softmax')(x)
6
----> 7 model = Model(inputs=mobile.input, outputs=predictions)
NameError: name 'Model' is not defined
If is there another way to remove the last layer and add a new layer(predictions = Dense(2, activation='softmax')) please let me know.
This is my full code.
You can use this code snippet to define your transfer learning model.
Here, we are using weights trained on imagenet datsaset and are ignoring the final layer (the 1000 neuron layer that was used to train 1000 classes in imagenet dataset) and adding our custom layers. In this example we are adding a GAP layer followed by a dense layer for binary classification.
from tensorflow import keras
input_layer = keras.layers.Input(shape=(224, 224, 3))
irv2 = keras.applications.Xception(weights='imagenet',include_top=False,input_tensor = input_layer)
global_avg = keras.layers.GlobalAveragePooling2D()(irv2.output)
dense_1 = keras.layers.Dense(1,activation = 'sigmoid')(global_avg)
model = keras.Model(inputs=irv2.inputs,outputs=dense_1)
model.summary()
The error you faced could possibly be due to the import changes between tf 1.x and tf 2.x
Try out any one of the below import methods depending on your tensorflow version. It should fix the error.
from tensorflow.keras.models import Model
or
from tensorflow.keras import Model
And also make sure you either import everything from tensorflow or from keras. Using the functions which are imported from either of the libraries in the same script would cause incompatibility errors.
-1 will give you the last Dense layer, but what you really what it a layer above that which is -2
Input should be the inception model input layer
import tensorflow as tf
from tensorflow.keras.layers import Dense
from keras.models import Model
irv2 = tf.keras.applications.inception_resnet_v2.InceptionResNetV2()
predictions = Dense(2, activation='softmax')(irv2.layers[-2].output)
model = Model(inputs=irv2.input, outputs=predictions)
model.summary()

Why is keras tokenizer applying lowercase() to it's own tokens?

I am running my first cnn text-classifier using the IMDB dataset with the in-built
tf.keras.datasets.imdb.load_data()
I understand the AttributeError: 'int' object has no attribute 'lower' error indicates that a lowercase function is being applied to int objects (seems to be from the tokenizer). However, I don't know why it is throwing this in this case as I am loading it directly though the in-built tf.keras.datasets.imdb.load_data().
I am not experienced with using embedding in text-classification.
The code excluding the CNN model is:
import tensorflow as tf
from keras.preprocessing import sequence
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation
from keras.layers import Embedding, LSTM
from keras.layers import Conv1D, Flatten, MaxPooling1D
from keras.datasets import imdb
import wandb
from wandb.keras import WandbCallback
import numpy as np
from keras.preprocessing import text
import imdb
wandb.init(mode="disabled") # disabled for debugging
config = wandb.config
# set parameters:
config.vocab_size = 1000
config.maxlen = 1000
config.batch_size = 32
config.embedding_dims = 10
config.filters = 16
config.kernel_size = 3
config.hidden_dims = 250
config.epochs = 10
(X_train, y_train), (X_test, y_test) = tf.keras.datasets.imdb.load_data()
tokenizer = text.Tokenizer(num_words=config.vocab_size)
tokenizer.fit_on_texts(X_train)
X_train = tokenizer.texts_to_matrix(X_train)
X_test = tokenizer.texts_to_matrix(X_test)
X_train = sequence.pad_sequences(X_train, maxlen=config.maxlen)
X_test = sequence.pad_sequences(X_test, maxlen=config.maxlen)
Line 34 referred to in the error is tokenizer = text.Tokenizer(num_words=config.vocab_size)
The exact error thrown (includes Deprecation warnings) is:
C:\Users\Keegan\anaconda3\envs\oldK\lib\site-
packages\tensorflow_core\python\keras\datasets\imdb.py:129:
VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-
or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If
you meant to do this, you must specify 'dtype=object' when creating the ndarray.
x_train, y_train = np.array(xs[:idx]), np.array(labels[:idx])
C:\Users\Keegan\anaconda3\envs\oldK\lib\site-
packages\tensorflow_core\python\keras\datasets\imdb.py:130: VisibleDeprecationWarning: Creating
an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or
ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must
specify 'dtype=object' when creating the ndarray.
x_test, y_test = np.array(xs[idx:]), np.array(labels[idx:])
Traceback (most recent call last):
File "imdb-cnn.py", line 34, in <module>
tokenizer.fit_on_texts(X_train)
File "C:\Users\Keegan\anaconda3\envs\oldK\lib\site-packages\keras_preprocessing\text.py",
line 217, in fit_on_texts
text = [text_elem.lower() for text_elem in text]
File "C:\Users\Keegan\anaconda3\envs\oldK\lib\site-packages\keras_preprocessing\text.py", line 217, in <listcomp>
text = [text_elem.lower() for text_elem in text]
AttributeError: 'int' object has no attribute 'lower'
The Anaconda venv has Python 3.7.1, Tensorflow 2.1.0 and Keras 2.3.1
The Keras tokenizer has an attribute lower which can be set either to True or False.
I guess the reason why the pre-packaged IMDB data is by default lower-cased is that the dataset is pretty small. If you did not lower-case it the capitalized and lower-cased words would get different embeddings, but the capitalized forms probably are not frequently enough in the training data to train the embeddings appropriately. This of course changes, once you use pre-trained embeddings or pre-trained contextualized models such as BERT which were pre-trained on large data.

"RuntimeError: PyTorch convert function for op 'pythonop' not implemented" AND "Python builtin is currently not supported in Torchscript"

Newbie question. I've been trying to convert this PyTorch model into CoreML model. I've followed the guide here but couldn't make it work. I tried tracing and scripting but faced errors which hint that there might be an operation not supported in TorchScript:
Error on torch.jit.trace: RuntimeError: PyTorch convert function for op 'pythonop' not implemented
Error on torch.jit.script: RuntimeError: Python builtin <built-in method apply of FunctionMeta object at 0x7fa37e2ad600> is currently not supported in Torchscript
I suspect that it just might not be possible to convert any PyTorch model into CoreML one. Is this the case? Can I somehow overcome the errors without diving deep into PyTorch operations and layers?
My python script just in case (model is loaded locally):
import warnings
import torch
import torch.nn as nn
import coremltools as ct
from efficientnet_pytorch import EfficientNet
from torchvision import datasets, models, transforms
from PIL import Image
# Simple loading the model
# model = torch.load('food308_efnetb2_91.31.pth', map_location=torch.device('cpu'))
# ends up with RuntimeError("Could not get name of python class object")
# Load the model
model = EfficientNet.from_pretrained('efficientnet-b2')
num_ftrs = model._fc.in_features
model._fc = nn.Linear(num_ftrs, 308)
prev_state = torch.load('food308_efnetb2_91.31.pth', map_location=torch.device('cpu'))
model.load_state_dict(prev_state)
model.eval()
# Model tracing
example_input = torch.rand(1, 3, 224, 224)
traced_model = torch.jit.trace(model, example_input)
mlmodel = ct.convert(
traced_model,
inputs=[ct.TensorType(name="input", shape=(1, 3, 64, 64))],
)
# Model scripting
scripted_model = torch.jit.script(model)
mlmodel2 = ct.convert(
scripted_model,
inputs=[ct.TensorType(name="input", shape=(1, 3, 64, 64))],
)

Calling K.eval() on input_tensor inside keras custom loss function?

I'm trying to convert the input tensor to a numpy array inside a custom keras loss function, after following the instructions here.
The above code runs on my machine with no errors. Now, I want to extract a numpy array with values from the input tensor. However, I get the following error:
"tensorflow.python.framework.errors_impl.InvalidArgumentError: You
must feed a value for placeholder tensor 'input_1' with dtype float
[[Node: input_1 = Placeholderdtype=DT_FLOAT, shape=[],
_device="/job:localhost/replica:0/task:0/cpu:0"]]"
I need to convert to a numpy array because I have other keras models that must operate on the input - I haven't shown those lines below in joint_loss, but even the code sample below doesn't run at all.
import numpy as np
from keras.models import Model, Sequential
from keras.layers import Dense, Activation, Input
import keras.backend as K
def joint_loss_wrapper(x):
def joint_loss(y_true, y_pred):
x_val = K.eval(x)
return y_true - y_pred
return joint_loss
input_tensor = Input(shape=(6,))
hidden1 = Dense(30, activation='relu')(input_tensor)
hidden2 = Dense(40, activation='sigmoid')(hidden1)
out = Dense(1, activation='sigmoid')(hidden2)
model = Model(input_tensor, out)
model.compile(loss=joint_loss_wrapper(input_tensor), optimizer='adam')
I figured it out!
What you want to do is use the Functional API for Keras.
Then your submodels outputs as tensors can be obtained as y_pred_submodel = submodel(x).
This is similar to how a Keras layer operates on a tensor.
Manipulate only tensors within the loss function. That should work fine.

Resources