I'm working with the Titanic data set from the TensorFlow API.
I don't know how to make the features tensors model friendly.
Here's the best I got, but it's for one tensor at a time. How do I make it so it can handle all tensors in the features item?
import tensorflow as tf
import tensorflow_datasets as tfds
from tensorflow.keras.optimizers import Adam
data = tfds.load("titanic",split='train', as_supervised=True).map(lambda x,y: (x,y)).prefetch(1)
for i in data.batch(1309):
xx1 = i[0]['age']
xx2 = i[0]['fare']
yyy = tf.convert_to_tensor(tf.one_hot(i[1],2))
model = tf.keras.models.Sequential([tf.keras.layers.Dense(1),
tf.keras.layers.Dense(13, activation='relu'),
tf.keras.layers.Dense(2, activation='softmax')])
model.compile(
optimizer=Adam(learning_rate=0.01),
loss='categorical_crossentropy',
metrics=['accuracy']
)
model.fit(xx1,yyy,epochs=30)
How do I concat the age and fare tensors so that they're in one data set?
I tried concat and stack to no avail.
This should be accomplishable with using tf.stack. As the input is already using the dataset API, I've refactored some code to leverage the dataset features for mapping the input format to the goal format that you have described. For convenience, here is a colab notebook with the example: https://colab.research.google.com/drive/1dHNe9rYaJSgqbj_QtQ1aJL_7WgKnLKsU?usp=sharing
# Nothing novel here
import tensorflow as tf
import tensorflow_datasets as tfds
from tensorflow.keras.optimizers import Adam
data = tfds.load("titanic",split='train', as_supervised=True).map(lambda x,y: (x,y)).prefetch(1)
Basic demo of intended data restructuring
Take 1 item from the dataset and convert it to a tensor that includes both of the goal datapoints using tf.stack
for item in data.take(1):
age = item[0]['age']
fare = item[0]['fare']
output = tf.stack([age, fare], axis=0)
print(output)
Output: tf.Tensor([30. 13.], shape=(2,), dtype=float32)
Within the output we can see a single tensor with two values embedded as expected.
Usage as a TensorFlow Dataset
Tensorflow datasets can be provided directly for training, we can easily create a function which will map from the input data format to the goal format described in the problem. The below function will accomplish this, using the sample code from above.
# Input data and associated label
def transform_data(item, label):
# Extract values
age = item['age']
fare = item['fare']
# Create output tensor
output = tf.stack([age, fare], axis=0)
return output, label
# Create a training dataset from the base dataset - for each batch map the input format to the goal format by passing the mapping function
train_dataset = data.map(transform_data).batch(1200)
# Model - I made some minor changes to get it to run cleaner
model = tf.keras.models.Sequential([
tf.keras.layers.Dense(2),
tf.keras.layers.Dense(13, activation='relu'),
# As we have only two labels, this is really a binary problem, so I've created a single output neuron activated by sigmoid
tf.keras.layers.Dense(1,activation='sigmoid')
])
# Compiled with binary_crossentropy to complement the binary classification
model.compile(optimizer=Adam(learning_rate=0.01),loss='binary_crossentropy', metrics=['accuracy'])
model.fit(train_dataset,epochs=30)
Output:
Epoch 1/30
2/2 [==============================] - 0s 16ms/step - loss: 11.7881 - accuracy: 0.4385
Epoch 2/30
2/2 [==============================] - 0s 7ms/step - loss: 10.2350 - accuracy: 0.4270
...
Related
I am predicting house prices using Deep Learning with Tensorflow 2 libraries.
I have data for 3 attributes (baths, bedrooms, area), and image of each house as my dataset. (nearly 2000 samples)
I am building 3 Deep Learning models:
Regression model (model_reg): using 3 attributes -- worked fine
CNN model (img_model) using images -- worked fine
Combining above two models (model_combined) -- erroring out
Regressoin model:
I built a Deep Neural Network (DNN) model uisng Tensorflow2.0 with 3 attributes as features and prices as labels.
I could fit the DNN and could predict the house prices.
Note: I used tf.data.Dataset combining X_train, y_train while building this model.
model_reg.fit(X_reg_train_dataset, batch_size=BATCH_SIZE, epochs=EPOCHS,
callbacks=[stop_callback], verbose=1)
63/63 [==============================] - 0s 2ms/step - loss: 0.3993 - mae: 0.4256 - mse: 0.3993
CNN Model:
Next, I build other CNN using house image as features and price as labels.
This too worked fine and I could predict the house prices.
Note: I used ImageDataGenerator from tensorflow.keras.preprocessing to build the generator.
hist = img_model.fit(
train_images_generator,
steps_per_epoch = train_images_generator.samples // BATCH_SIZE ,
validation_data = test_images_generator,
validation_steps = test_images_generator.samples // BATCH_SIZE,
epochs = EPOCHS,
callbacks=[stop_callback], verbose=1)
49/49 [==============================] - 59s 1s/step - loss: 1741.6321 - mae: 20.8221 - mse: 1741.6321 - val_loss: 755833241600.0000 - val_mae: 768718.3125 - val_mse: 755833241600.0000
Lastly, I merged these 2 models appropriately using Concatenate() layer.
Now I have 2 inputs that need to pass to the model.
Hence I defined a model using Functional API's with 2 inputs.
model_combined = Model(inputs=[input_layer_reg, img_input_layer], outputs=[output_layer_combined])
optimizer = tf.keras.optimizers.Adam(0.01)
model_combined.compile(loss='mae', optimizer=optimizer, metrics=['mae', 'mse'])
Till this point it worked fine and the generated model looks fine.
It's going error while trying to train it using fit:
model_combined.fit([X_reg_train_dataset, train_images_generator], epochs=EPOCHS,
callbacks=[stop_callback], verbose=1,
batch_size=BATCH_SIZE )
ValueError: Failed to find data adapter that can handle input:
(<class 'list'> containing values of types {"<class 'tensorflow.python.keras.preprocessing.image.DataFrameIterator'>",
"<class 'tensorflow.python.data.ops.dataset_ops.BatchDataset'>"}),
<class 'NoneType'>
Question: How to pass 2 inputs: tf.data.Dataset and ImageDataGenerator to Tensorflow model?
model_combined.fit(ta,
steps_per_epoch = train_images_generator.samples // train_images_generator.batch_size,
validation_data = test_images_generator,
validation_steps = test_images_generator.samples // test_images_generator.batch_size,
epochs = 5,
callbacks=[stop_callback], verbose=1)
Epoch 1/5
36/49 [=====================>........] - ETA: 20s - loss: 0.4512 - mae: 0.4512 - mse: 0.5005
I had to write a custom generator and a dataset on top of that to make it work
ta = tf.data.Dataset.from_generator(train_image_dataset_generator,
output_signature=(
(tf.TensorSpec(shape=(None, 5,), dtype=tf.float64),
tf.TensorSpec(shape=(None, None, None, None), dtype=tf.float64)),
(tf.TensorSpec(shape=(None,), dtype=tf.float64),
tf.TensorSpec(shape=(None,), dtype=tf.float64)),
)).repeat()
def train_image_dataset_generator():
data_X_reg = enumerate(X_reg_train_dataset)
a_tuple = next(data_X_reg)
b_tuple = train_images_generator.next()
I have a keras model and want to save it as a tensorflow graph. Is there a difference between tf.saved_model.save(model, path_to_dir) and tf.keras.model.save.
In both of these, I want to save in a tensorflow saved format and will not be using h5 format. I understand tf.saved_model.save is more generic but if I am using a keras model are these two different in anyways.
In general cases, there should not be any difference. To give a concrete answer, we can save the entire tf. keras model - one is TensorFlow SavedModel and another one is .h5 format.
As you said, you have a keras model and wanted to save its graph. You can do this either
Model.save or
tf.keras.models.save_model
(1)
Model.save(
filepath,
overwrite=True,
include_optimizer=True,
save_format=None,
signatures=None,
options=None,
save_traces=True,
)
(2)
tf.keras.models.save_model(
model,
filepath,
overwrite=True,
include_optimizer=True,
save_format=None,
signatures=None,
options=None,
save_traces=True,
)
(3)
# tf.saved_model.save(model, path_to_dir)
tf.saved_model.save(model,
export_dir,
signatures,
options)
As you can see, all of them take the same argument too. I would recommend choosing (1) or (2), easy to follow. Here is an example, I've trained a function model on the CIFAR data set and saved the model as follows with (1) and (2) approaches.
func_model.fit(x_train, y_train, batch_size=128, epochs=2, verbose = 1)
1s/step - loss: 2.7365 - categorical_accuracy: 0.1088
1s/step - loss: 1.8353 - categorical_accuracy: 0.3905
# with (1)
func_model.save('/content/1/',
save_format='tf', save_traces=False)
INFO:tensorflow:Assets written to: /content/1/assets
INFO:tensorflow:Assets written to: /content/1/assets
# with (2)
tf.keras.models.save_model(func_model, '/content/2/',
save_format='tf', save_traces=False)
INFO:tensorflow:Assets written to: /content/2/assets
INFO:tensorflow:Assets written to: /content/2/assets
Load and re-train them
from tensorflow.keras.models import load_model
x = load_model('.//1/')
y = load_model('.//2/')
x.fit(x_train, y_train, batch_size=128, epochs=1, verbose = 1)
1s/step - loss: 1.0963 - categorical_accuracy: 0.6780
y.fit(x_train, y_train, batch_size=128, epochs=1, verbose = 1)
1s/step - loss: 1.0963 - categorical_accuracy: 0.6780
Also note that there is a parameter called save_traces, and by default, it sets as True. I set it False as I don't want to. Newly added, according to doc:
save_traces: (only applies to SavedModel format) When enabled, the SavedModel will store the function traces for each layer. This can be disabled so that only the configs of each layer are stored. Defaults to True. Disabling this will decrease serialization time and reduce file size, but it requires that all custom layers/models implement a get_config() method.
Also FYI, as you save the entire model, I like to remind you to use the custom_object parameter while loading the model if you've custom layer-like stuff.
new_moedl = keras.models.load_model(
"my_model", custom_objects={"CustomModel": CustomModel}
)
Would you mind checking this:
enter link description here
Scroll down to the answer by #WGierke don't forget to upvote if it helpsed, you will get the code and load your Model normally.
Code Sample:
import tensorflow as tf
import tensorflow_hub as hub
m = tf.keras.Sequential([hub.KerasLayer("saved_model", trainable=True),
tf.keras.layers.Dense(10, activation='softmax')
])
m.build([None, 224, 224, 3])
m.summary()
It works fine with me.
I am trying to store numpy arrays in a Tensorflow dataset. The model fits correctly when using the numpy arrays as train and test data but not when I store the numpy arrays in a single Tensorflow dataset. The problem is with the dimensions of the dataset. Something is wrong even though shapes seem OK at first sight.
After trying multiple things to reshape my Tensorflow dataset, I am still unable to get it working. My code is the following:
train_x.shape
Out[54]: (7200, 40)
train_y.shape
Out[55]: (7200,)
dataset = tf.data.Dataset.from_tensor_slices((x,y))
print(dataset)
Out[56]: <TensorSliceDataset shapes: ((40,), ()), types: (tf.int32, tf.int32)>
model.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy')
history = model.fit(dataset, epochs=EPOCHS, batch_size=256)
sparse_softmax_cross_entropy_with_logits
logits.get_shape()))
ValueError: Shape mismatch: The shape of labels (received (1,)) should equal the shape of logits except for the last dimension (received (40, 1351)).
I have seen this answer but I am sure it doesn't apply here. I must use sparse_categorical_crossentropy. I am inspiring myself from this example where I want to store the train and test data in a Tensorflow dataset. I also want to store the arrays in a dataset as I will have to use it later.
You can't use batch_size with model.fit() when using a tf.data.Dataset. Instead use tf.data.Dataset.batch(). You'll have to change your code as follows for it to work.
import numpy as np
import tensorflow as tf
# Some toy data
train_x = np.random.normal(size=(7200, 40))
train_y = np.random.choice([0,1,2], size=(7200))
dataset = tf.data.Dataset.from_tensor_slices((train_x,train_y))
dataset = dataset.batch(256)
#### - Define your model here - ####
model.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy')
history = model.fit(dataset, epochs=EPOCHS)
I am working on an autoencoder in Keras that contains some dropout layers. To evaluate bias and variance, I'd like to compare the losses of training and test data. However, since dropout is used during training, the losses cannot be compared. (See here for an explanation of why the training data results can be worse than test data results.)
In order to get training data losses that are not influenced by the dropout, I wrote a callback to validate some additional data set (in this case, it would be the training data again).
The strange thing is that I ALWAYS get the same results as for the validation data. Here's a minimal example:
from pprint import pprint
import keras
import numpy as np
import pandas as pd
from numpy.random import seed as np_seed
from tensorflow.random import set_seed as tf_seed
np_seed(1)
tf_seed(2)
# Generation of data sets for training and testing. Random data is only used to showcase the problem.
df_train = pd.DataFrame(data=np.random.random((1000, 10))) # This will be used for training
df_test_1 = pd.DataFrame(data=np.random.random((1000, 10))) # This will be used as validation data set directly
df_test_2 = pd.DataFrame(data=np.random.random((1000, 10))) # This will be used within the callback
np_seed(1)
tf_seed(2)
model = keras.models.Sequential(
[
keras.Input(shape=(10, )),
keras.layers.Dropout(rate=0.01),
keras.layers.Dense(5, activation='relu'),
keras.layers.Dropout(rate=0.01),
keras.layers.Dense(10, activation='linear'),
]
)
model.compile(
loss='mean_squared_error',
optimizer=keras.optimizers.Adam(),
)
class CustomDataValidation(keras.callbacks.Callback):
def __init__(self, x=None, y=None):
self.x = x
self.y = y
def on_epoch_end(self, epoch, logs=None):
result = self.model.evaluate(x=self.x, y=self.y, return_dict=True)
for loss_name, loss_value in result.items():
logs["custom_" + loss_name] = loss_value
cdv = CustomDataValidation(df_test_2, df_test_2)
hist = model.fit(df_train, df_train, validation_data=(df_test_1, df_test_1), epochs=2, validation_split=0.1, callbacks=[cdv])
pprint(hist.history)
The output is
Epoch 1/2
4/4 [==============================] - 0s 1ms/step - loss: 0.7625
29/29 [==============================] - 0s 5ms/step - loss: 0.9666 - val_loss: 0.7625
Epoch 2/2
4/4 [==============================] - 0s 1ms/step - loss: 0.5331
29/29 [==============================] - 0s 2ms/step - loss: 0.6638 - val_loss: 0.5331
{'custom_loss': [0.7624925374984741, 0.5331208109855652],
'loss': [0.9665887951850891, 0.6637843251228333],
'val_loss': [0.7624925374984741, 0.5331208109855652]}
'custom_loss' and 'val_loss' are equal although they should be based on totally different data sets.
The question is therefore: How can I evaluate the model performance on custom data within a callback?
Edit: Since I did not yet got an answer on stackoverflow, I created an issue at tensorflow's git repo. Also, there's now a notebook available that shows the problem.
It seems that this is a bug in tensorflow versions 2.3.x (tested with 2.3.0 and 2.3.1). In versions 2.4.0-rc0 and 2.2.1, the loss outputs of loss and custom_loss differ, which is the expected behavior:
{'custom_loss': [0.7694963216781616, 0.541864812374115],
'loss': [0.9665887951850891, 0.6637843251228333],
'val_loss': [0.7624925374984741, 0.5331208109855652]}
from sklearn.preprocessing import LabelBinarizer
from sklearn.metrics import classification_report
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
os.environ['TF_FORCE_GPU_ALLOW_GROWTH'] = 'true'
from tensorflow.keras.optimizers import SGD
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
from tensorflow.keras.datasets import cifar10
print("[INFO] loading CIFAR-10 data")
((trainX, trainY), (testX, testY)) = cifar10.load_data()
trainX = trainX.astype("float") / 255.0
testX = testX.astype("float") / 255.0
print("trainX: {}, testX ={}".format(trainX.shape,testX.shape))
lb=LabelBinarizer()
# convert the labels from integers to vectors
trainY = lb.fit_transform(trainY)
testY = lb.transform(testY)
labelNames = ["airplane", "automobile", "bird", "cat", "deer",
"dog", "frog", "horse", "ship", "truck"]
print("[INFO] compiling model")
opt=SGD(lr=0.01, decay=0.01/40, momentum=0.9, nesterov=True)
model= MiniVGGNet.build(width=32,height=32,depth=3, classes=10)
model.compile(loss="categorical_crossentropy",
optimizer=opt,metrics=["accuracy"])
#train the network
print("[INFO] training network..")
H=model.fit(trainX, trainY, validation_data=(testX, testY),
batch_size=64, epochs=40, verbose=1)
The output is:
[INFO] loading CIFAR-10 data
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
170500096/170498071 [==============================] - 4s 0us/step
trainX: (50000, 32, 32, 3), testX =(10000, 32, 32, 3)
[INFO] compiling model
[INFO] training network..
Epoch 1/40
782/782 [==============================] - 10s 12ms/step - loss: 1.6249 - accuracy: 0.4555 - val_loss: 1.3396 - val_accuracy: 0.5357
Epoch 2/40
782/782 [==============================] - 9s 12ms/step - loss: 1.1462
When I download the data from the website above, I get the correct cifar data but when I run my model, I can see it only takes 782 images.
I have worked on other models as well but same result.
This only happens in google colab and not in my local pc. What am I missing?
Both the training and testing sets are working perfectly fine. Train set has 50000 images and the test set has 10000. So, there is no problem in the code that you posted. Consider adding rest of the code that you used to train the model. You can check the shape of your sets by executing.
from tensorflow.keras.datasets import cifar10
(train_X, train_y), (test_X, test_y) = cifar10.load_data()
train_X = train_X.astype("float") / 255.0
test_X = test_X.astype("float") / 255.0
print(f"train_X: {train_X.shape}, test_X = {test_X.shape}")
Update:
Tested this in MyBinder, my local Juyter Notebook and Colab and got to this conclusion:
MyBinder and local Notebook didn't separate CIFAR training set into mini-batches or just showed total number individual data-points in training set. So, they show showed that 50000 steps were necessary at each epoch.
On contrary, Google Colab has mini-batched the CIFAR dataset into 64 mini-batches and has trained the model. So the total steps at each epoch is 5000/64 which is equal to 782.
Hope this cleared your confusion. It was just that Colab displayed total mini-batches, whereas Jupyter Notebook showed total invidual number of entities in the set.
PS: You might want to add missing bracket at the end of line 34 in the code that you shared here.