Tensorflow
Install
Docker
https://www.tensorflow.org/install
https://www.tensorflow.org/install/gpu
$ docker pull tensorflow/tensorflow:latest-gpu-jupyter # still need NVIDIA drivers
$ docker run -it -p 8888:8888 tensorflow/tensorflow:latest-gpu-jupyter
Conda (CPU)
name: tf
channels:
- conda-forge
- nodefaults
dependencies:
- python=3.9
- graphviz
- h5py
- ipykernel
- ipywidgets
- matplotlib
- pydot
- pyyaml
- tqdm
- pip
- pip:
- tensorflow
- tensorflow-datasets
- git+https://github.com/tensorflow/examples.git
Test CPU install
import tensorflow as tf
tf.config.list_physical_devices()
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
model = tf.keras.models.Sequential(
[
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(128, activation="relu"),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(10),
]
)
loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
model.compile(optimizer="adam", loss=loss, metrics=["accuracy"])
model.fit(x_train, y_train, epochs=5)
loss, acc = model.evaluate(x_test, y_test, verbose=2)
Conda (GPU)
name: tf-gpu
channels:
- conda-forge
- nodefaults
dependencies:
- python=3.9
- tensorflow-gpu
Test GPU Install
import tensorflow as tf
print("Num GPUs Available: ", len(tf.config.list_physical_devices('GPU')))
tf.debugging.set_log_device_placement(True)
Imports
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import models
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Dropout, Flatten, Dense
from tensorflow.keras import utils
from tensorflow.keras import optimizers
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import tensorflow_probability as tfp
# Set random seed for reproducibility
tf.random.set_seed(42)
IO, Math and initialization
https://github.com/mrdbourke/tensorflow-deep-learning/blob/main/00_tensorflow_fundamentals.ipynb
a = tf.constant(7)
a = tf.constant(numpy_arr)
a = tf.Variable(tf.cast([1, 2, 3], dtype=tf.float32)
tf.random.uniform(shape=[50])
a.ndim
tf.reduce_min(([1, 2, 3]) # np.min
tf.random.Generator.from_seed(42).normal(shape=(3, 2))
Probability
import tensorflow_probability as tfp
tfp.stats.variance(E)
math
tf.math.reduce_std
Multi-Classification problem
Data Preparation
Put numpy array into Tensorflow object
# Set data types for float features
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
# Set data types for categorical labels
y_train = utils.to_categorical(y_train)
y_test = utils.to_categorical(y_test)
Setup model
model = Sequential()
model.add(Dense(10, input_dim=len(features), activation='relu'))
model.add(Dense(10, input_dim=10, activation='relu'))
model.add(Dense(len(classes), input_dim=10, activation='softmax'))
print(model.summary())
#hyper-parameters for optimizer
learning_rate = 0.001
opt = optimizers.Adam(lr=learning_rate)
model.compile(loss='categorical_crossentropy',
optimizer=opt,
metrics=['accuracy'])
Run
# Train the model over 50 epochs using 10-observation batches and using the test holdout dataset for validation
num_epochs = 50
history = model.fit(x_train, y_train, epochs=num_epochs, batch_size=10, validation_data=(x_test, y_test))
Plot
epoch_nums = range(1,num_epochs+1)
training_loss = history.history["loss"]
validation_loss = history.history["val_loss"]
plt.plot(epoch_nums, training_loss)
plt.plot(epoch_nums, validation_loss)
plt.xlabel('epoch')
plt.ylabel('loss')
plt.legend(['training', 'validation'], loc='upper right')
plt.show()
See confusion matrix
import numpy as np
from sklearn.metrics import confusion_matrix
import matplotlib.pyplot as plt
%matplotlib inline
class_probabilities = model.predict(x_test)
predictions = np.argmax(class_probabilities, axis=1)
true_labels = np.argmax(y_test, axis=1)
# Plot the confusion matrix
cm = confusion_matrix(true_labels, predictions)
plt.imshow(cm, interpolation="nearest", cmap=plt.cm.Blues)
plt.colorbar()
tick_marks = np.arange(len(penguin_classes))
plt.xticks(tick_marks, classes, rotation=85)
plt.yticks(tick_marks, classes)
plt.xlabel("Actual Class")
plt.ylabel("Predicted Class")
plt.show()
Save model
modelFileName = 'models/penguin-classifier.h5'
model.save(modelFileName)
del model
Predict
model = models.load_model(modelFileName) # loads the saved model
x_new = np.array([[50.4, 15.3, 20, 50]])
print ('New sample: {}'.format(x_new))
class_probabilities = model.predict(x_new)
predictions = np.argmax(class_probabilities, axis=1)
print(classes[predictions[0]])
CNN
Load the data
data_folder = 'path'
img_size = (128, 128)
batch_size = 30
print("Getting Data...")
datagen = ImageDataGenerator(rescale=1./255, # normalize pixel values
validation_split=0.3) # hold back 30% of the images for validation
print("Preparing training dataset...")
train_generator = datagen.flow_from_directory(
data_folder,
target_size=img_size,
batch_size=batch_size,
class_mode='categorical',
subset='training') # set as training data
print("Preparing validation dataset...")
validation_generator = datagen.flow_from_directory(
data_folder,
target_size=img_size,
batch_size=batch_size,
class_mode='categorical',
subset='validation') # set as validation data
classnames = list(train_generator.class_indices.keys())
print("class names: ", classnames)
Setup model
# Define the model as a sequence of layers
model = Sequential()
# The input layer accepts an image and applies a convolution
# that uses 32 filters, a kernal size of 6x6 and a rectified linear unit activation function
model.add(Conv2D(32, (6, 6), input_shape=train_generator.image_shape, activation='relu'))
# Next we'll add a max pooling layer with a 2x2 patch
model.add(MaxPooling2D(pool_size=(2, 2)))
# We can add as many layers as we think necessary - here we'll add another convolution, max pooling, and dropout layer
model.add(Conv2D(32, (6, 6), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
# And another set
model.add(Conv2D(32, (6, 6), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
# A dropout layer randomly drops some nodes to reduce inter-dependencies (which can cause over-fitting)
model.add(Dropout(0.2))
# Now we'll flatten the feature maps and generate an output layer with a predicted probability for each class
model.add(Flatten())
model.add(Dense(train_generator.num_classes, activation='sigmoid'))
# With the layers defined, we can now compile the model for categorical (multi-class) classification
model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
print(model.summary())
Train model
# Train the model over 5 epochs using 30-image batches and using the validation holdout dataset for validation
num_epochs = 5
history = model.fit(
train_generator,
steps_per_epoch = train_generator.samples // batch_size,
validation_data = validation_generator,
validation_steps = validation_generator.samples // batch_size,
epochs = num_epochs)
Predict
# Function to create a random image (of a square, circle, or triangle)
def create_image (size, shape):
from random import randint
import numpy as np
from PIL import Image, ImageDraw
xy1 = randint(10,40)
xy2 = randint(60,100)
col = (randint(0,200), randint(0,200), randint(0,200))
img = Image.new("RGB", size, (255, 255, 255))
draw = ImageDraw.Draw(img)
if shape == 'circle':
draw.ellipse([(xy1, xy1), (xy2, xy2)], fill=col)
elif shape == 'triangle':
draw.polygon([(xy1, xy1), (xy2, xy2), (xy2, xy1)], fill=col)
else: # square
draw.rectangle([(xy1, xy1), (xy2, xy2)], fill=col)
del draw
return np.array(img)
# Save the trained model
modelFileName = 'models/classifier.h5'
model.save(modelFileName)
del model # deletes the existing model variable
# Create a random test image
classnames = os.listdir(os.path.join('data', 'shapes'))
classnames.sort()
img = create_image ((128,128), classnames[randint(0, len(classnames)-1)])
plt.axis('off')
plt.imshow(img)
# The model expects a batch of images as input, so we'll create an array of 1 image
imgfeatures = img.reshape(1, img.shape[0], img.shape[1], img.shape[2])
# We need to format the input to match the training data
# The generator loaded the values as floating point numbers
# and normalized the pixel values, so...
imgfeatures = imgfeatures.astype('float32')
imgfeatures /= 255
# Use the classifier to predict the class
model = models.load_model(modelFileName) # loads the saved model
class_probabilities = model.predict(imgfeatures)
# Find the class predictions with the highest predicted probability
class_idx = np.argmax(class_probabilities, axis=1)
print (classnames[int(class_idx[0])])
Image segmentation using U-net
https://www.tensorflow.org/tutorials/images/segmentation
Data generation from xarray objects
class DataGenerator(keras.utils.Sequence):
def __init__(
self,
ds,
var_list=["t2m_norm"],
target="target",
batch_size=100,
shuffle=False,
mean=False,
std=False,
class_weights=None,
):
"""
Template from https://stanford.edu/~shervine/blog/keras-how-to-generate-data-on-the-fly
Args:
ds: Dataset containing all variables
var_lst: List of the form ['var1', 'var2']
target: Name of target value
batch_size: Batch size
shuffle: bool. If True, data is shuffled.
mean: If None, compute mean from data.
std: If None, compute standard deviation from data.
"""
self.ds = ds
self.var_list = var_list
self.batch_size = batch_size
self.shuffle = shuffle
self.class_weights = class_weights
self.data = (
ds[var_list]
.to_array(dim="feature")
.transpose("time", "latitude", "longitude", "feature")
)
self.n_samples = self.data.shape[0]
self.target = ds[target].transpose("time", "latitude", "longitude")
self.on_epoch_end()
def __len__(self):
"Denotes the number of batches per epoch"
return int(np.ceil(self.n_samples / self.batch_size))
def __getitem__(self, i):
"Generate one batch of data"
idxs = self.idxs[i * self.batch_size : (i + 1) * self.batch_size]
X = self.data.isel(time=idxs).values
y = self.target.isel(time=idxs).values
if self.class_weights is not None:
sample_weights = tf.gather(self.class_weights, indices=tf.cast(y, tf.int32))
return X, y, sample_weights
else:
return X, y
def on_epoch_end(self):
"Updates indexes after each epoch"
self.idxs = np.arange(self.n_samples)
if self.shuffle == True:
np.random.shuffle(self.idxs)
model
def get_model(height, width, num_features, num_classes):
inputs = keras.Input(shape=(height, width, num_features))
### [First half of the network: downsampling inputs] ###
# Entry block
x = layers.Conv2D(32, 3, strides=2, padding="same")(inputs)
x = layers.BatchNormalization()(x)
x = layers.Activation("relu")(x)
previous_block_activation = x # Set aside residual
# Scale up blocks
# Blocks 1, 2, 3 are identical apart from the feature depth.
for filters in [64, 128, 256]:
x = layers.Activation("relu")(x)
x = layers.SeparableConv2D(filters, 3, padding="same")(x)
x = layers.BatchNormalization()(x)
x = layers.Activation("relu")(x)
x = layers.SeparableConv2D(filters, 3, padding="same")(x)
x = layers.BatchNormalization()(x)
x = layers.MaxPooling2D(3, strides=2, padding="same")(x)
# Project residual
residual = layers.Conv2D(filters, 1, strides=2, padding="same")(
previous_block_activation
)
x = layers.add([x, residual]) # Add back residual
previous_block_activation = x # Set aside next residual
### [Second half of the network: upsampling inputs] ###
for filters in [256, 128, 64, 32]:
x = layers.Activation("relu")(x)
x = layers.Conv2DTranspose(filters, 3, padding="same")(x)
x = layers.BatchNormalization()(x)
x = layers.Activation("relu")(x)
x = layers.Conv2DTranspose(filters, 3, padding="same")(x)
x = layers.BatchNormalization()(x)
x = layers.UpSampling2D(2)(x)
# Project residual
residual = layers.UpSampling2D(2)(previous_block_activation)
residual = layers.Conv2D(filters, 1, padding="same")(residual)
x = layers.add([x, residual]) # Add back residual
previous_block_activation = x # Set aside next residual
# Add a per-pixel classification layer
x = layers.Conv2D(num_classes, 3, activation="softmax", padding="same")(x)
# Crop to match input sizes (if shapes mis-match)
outputs = layers.Cropping2D(cropping=((4, 4), (2, 2)))(x)
# Define the model
model = keras.Model(inputs, outputs)
return model
model = get_model(height, width, num_features, num_classes)
model.compile(
optimizer="rmsprop",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"],
)
model.summary()
Model training and plotting
epochs = 250
model_history = model.fit(
dg_train, epochs=epochs, validation_data=dg_valid, callbacks=[DisplayCallback()]
)
Model evaluation
loss = model_history.history["loss"]
val_loss = model_history.history["val_loss"]
plt.figure()
plt.plot(model_history.epoch, loss, "r", label="Training loss")
plt.plot(model_history.epoch, val_loss, "bo", label="Validation loss")
plt.title("Training and Validation Loss")
plt.xlabel("Epoch")
plt.ylabel("Loss Value")
plt.legend()
plt.show()
loss = model_history.history["accuracy"]
val_loss = model_history.history["val_accuracy"]
plt.figure()
plt.plot(model_history.epoch, loss, "r", label="Training accuracy")
plt.plot(model_history.epoch, val_loss, "bo", label="Validation accuracy")
plt.title("Training and Validation accuracy")
plt.xlabel("Epoch")
plt.ylabel("Accuracy")
plt.legend()
plt.show()
plot_y_and_y_pred(y, prob_to_class(model.predict(dg_train)), epoch)
Metrics
m = tf.keras.metrics.IoU(num_classes=5, target_class_ids=[0, 1, 2, 3, 4])
m.update_state(preds_multiclass_yp, true_y)
m.result().numpy()
Callbacks
Plotting and saving images
from IPython.display import clear_output
def plot_y_and_y_pred(y, y_pred, epoch, i=0, save_plots=False, save_every_epoch=10):
da = xr.concat([xr.DataArray(y[i, :, :]), xr.DataArray(y_pred[i, :, :])], "y")
da.plot(
cmap=cmap,
norm=norm,
add_colorbar=False,
col="y",
size=6,
)
if save_plots:
if epoch % save_every_epoch == 0:
plt.savefig("plots/epoch_" + str(epoch).zfill(4))
plt.pause(0.05)
def show_predictions(epoch):
plot_y_and_y_pred(y, prob_to_class(model.predict(X)), epoch)
class DisplayCallback(tf.keras.callbacks.Callback):
def on_epoch_end(self, epoch, logs=None):
clear_output(wait=True)
show_predictions(epoch)
print("\nSample Prediction after epoch {}\n".format(epoch + 1))
callbacks=[DisplayCallback()]
Model saving
import os
from datetime import datetime
run = datetime.now().isoformat()
checkpoint_path = "training_" + run_cp.ckpt"
checkpoint_dir = os.path.dirname(checkpoint_path)
checkpoint_callback = tf.keras.callbacks.ModelCheckpoint(
filepath=checkpoint_path,
verbose=1,
save_weights_only=True,
save_freq=5 * batch_size,
)
checkpoint_callback = tf.keras.callbacks.ModelCheckpoint(
filepath="my_model.h5",
save_best_only=True,
)
callbacks=[checkpoint_callback]
latest = tf.train.latest_checkpoint(checkpoint_dir)