import numpy as np
import pandas as pdPytorch vs Tensorflow - CNN
Choosing Pytorch vs Tensorflow, which should you use? Which is better and what are the differences between these two frameworks both made for deep learning. Well in this series I am going to compare them side by side so you could see the differences and simliarities clearly, in code with crips examples.
Also, when I switched from Tensorflow to pytorch, I just wished I had a “Rosetta Stone” to translate between frameworks, which I hope this series will be for you. A nice overview that practitioners to leverage the strengths of both libraries.
In this notebook
In the first notebook of this series, I will start with the basics by creating a simple Convolutional Neural Network (CNN) in both PyTorch and TensorFlow. We will train this so called CNN on the MNIST dataset, which consists of handwritten digit images, to illustrate fundamental concepts and workflows in each framework. This foundational exercise will set the stage for more complex models and comparisons in subsequent notebooks.
For both PyTorch and TensorFlow, the steps for training a model are essentially the same:
- Importing the necessary libraries.
- Defining the model parameters and hyperparameters.
- Loading the dataset.
- Preprocessing the data to make it suitable for training.
- Initializing the model architecture.
- Training the model using the defined parameters and dataset.
These steps form the core workflow in building and training deep learning models, regardless of the framework used.
import plotly.graph_objects as go
from plotly.subplots import make_subplots
# Plotting the training metrics with Plotly
def plot_tensorflow_training_results(history):
fig = make_subplots(rows=1, cols=2, subplot_titles=("Loss Over Epochs", "Accuracy Over Epochs"))
# Loss plot
fig.add_trace(go.Scatter(x=list(range(len(history.history['loss']))),
y=history.history['loss'],
mode='lines',
name='Training Loss'),
row=1, col=1)
fig.add_trace(go.Scatter(x=list(range(len(history.history['val_loss']))),
y=history.history['val_loss'],
mode='lines',
name='Validation Loss'),
row=1, col=1)
# Accuracy plot
fig.add_trace(go.Scatter(x=list(range(len(history.history['accuracy']))),
y=history.history['accuracy'],
mode='lines',
name='Training Accuracy'),
row=1, col=2)
fig.add_trace(go.Scatter(x=list(range(len(history.history['val_accuracy']))),
y=history.history['val_accuracy'],
mode='lines',
name='Validation Accuracy'),
row=1, col=2)
# Updating layout
fig.update_layout(title='Training Metrics',
xaxis_title='Epoch',
yaxis_title='Value',
showlegend=True)
# Update xaxis labels
fig.update_xaxes(title_text='Epoch', row=1, col=1)
fig.update_xaxes(title_text='Epoch', row=1, col=2)
# Update yaxis labels
fig.update_yaxes(title_text='Loss', row=1, col=1)
fig.update_yaxes(title_text='Accuracy', row=1, col=2)
fig.show()
import plotly.graph_objects as go
from plotly.subplots import make_subplots
def plot_pytorch_training_results(n_epochs, train_losses, test_losses, train_accuracies, test_accuracies):
# Plotting the training metrics with Plotly
fig = make_subplots(rows=1, cols=2, subplot_titles=("Loss Over Epochs", "Accuracy Over Epochs"))
# Loss plot
fig.add_trace(go.Scatter(x=list(range(n_epochs)), y=train_losses, mode='lines', name='Training Loss'), row=1, col=1)
fig.add_trace(go.Scatter(x=list(range(n_epochs)), y=test_losses, mode='lines', name='Validation Loss'), row=1, col=1)
# Accuracy plot
fig.add_trace(go.Scatter(x=list(range(n_epochs)), y=train_accuracies, mode='lines', name='Training Accuracy'), row=1, col=2)
fig.add_trace(go.Scatter(x=list(range(n_epochs)), y=test_accuracies, mode='lines', name='Validation Accuracy'), row=1, col=2)
# Updating layout
fig.update_layout(title='Training Metrics', xaxis_title='Epoch', yaxis_title='Value', showlegend=True)
# Update xaxis labels
fig.update_xaxes(title_text='Epoch', row=1, col=1)
fig.update_xaxes(title_text='Epoch', row=1, col=2)
# Update yaxis labels
fig.update_yaxes(title_text='Loss', row=1, col=1)
fig.update_yaxes(title_text='Accuracy', row=1, col=2)
fig.show()pixel_columns = [f"pixel{i}" for i in range(784)]
all_df = pd.read_csv("/kaggle/input/digit-recognizer/train.csv")
indices = np.arange(len(all_df))
np.random.shuffle(indices)
# Split the indices into 80% train and 20% validation
trn_len = int(0.8 * len(all_df))
trn_ind = indices[:trn_len]
val_ind = indices[trn_len:]
trn_df = all_df.iloc[trn_ind]
val_df = all_df.iloc[val_ind]
x_trn = trn_df[pixel_columns].values
y_trn = trn_df["label"].values
x_val = val_df[pixel_columns].values
y_val = val_df["label"].values
tst_df = pd.read_csv("/kaggle/input/digit-recognizer/test.csv")
x_tst = tst_df[pixel_columns].values#1. Importing the necessary libraries.
import tensorflow as tf
import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.losses import CategoricalCrossentropy
from tensorflow.keras.datasets import mnist
# 2. Defining the model parameters and hyperparameters.
kernels_layer_1 = 32
kernels_layer_2 = 64
n_classes = 10
n_epochs = 10
batch_size = 32
img_size = 28
img_size_flattened = img_size * img_size
learning_rate = 0.001
n_classes = 10
x_trn = x_trn/255.0
x_val = x_val/255.0
x_tst = x_tst/255.0
x_trn = x_trn.reshape(-1, img_size, img_size, 1)
x_val = x_val.reshape(-1, img_size, img_size, 1)
x_tst = x_tst.reshape(-1, img_size, img_size, 1)
y_trn_encoded = np.zeros(shape=(y_trn.shape[0], n_classes), dtype=int)
y_val_encoded = np.zeros(shape=(y_val.shape[0], n_classes), dtype=int)
y_trn_encoded[np.linspace(0, len(y_trn)-1, len(y_trn)).astype(int), y_trn]=1
y_val_encoded[np.linspace(0, len(y_val)-1, len(y_val)).astype(int), y_val]=1
# 5. Initializing the model architecture.
model = Sequential([
tf.keras.layers.Conv2D(kernels_layer_1, kernel_size=(3, 3), activation="relu"),
tf.keras.layers.MaxPooling2D(pool_size=(2, 2)),
tf.keras.layers.Conv2D(kernels_layer_2, kernel_size=(3, 3), activation="relu"),
tf.keras.layers.MaxPooling2D(pool_size=(2, 2)),
tf.keras.layers.Flatten(),
tf.keras.layers.Dropout(0.5),
tf.keras.layers.Dense(units=n_classes, activation="softmax")
])
model.compile(
optimizer=tf.keras.optimizers.Adam(learning_rate=learning_rate), loss=CategoricalCrossentropy(),
metrics=["accuracy"])
# 6. Training the model using the defined parameters and dataset.
callback = model.fit(
x=x_trn,
y=y_trn_encoded,
validation_data=(x_val, y_val_encoded),
batch_size=batch_size,
epochs=n_epochs)Epoch 1/10 1050/1050 ━━━━━━━━━━━━━━━━━━━━ 13s 12ms/step - accuracy: 0.8149 - loss: 0.5747 - val_accuracy: 0.9730 - val_loss: 0.0848 Epoch 2/10 1050/1050 ━━━━━━━━━━━━━━━━━━━━ 12s 11ms/step - accuracy: 0.9675 - loss: 0.1046 - val_accuracy: 0.9807 - val_loss: 0.0645 Epoch 3/10 1050/1050 ━━━━━━━━━━━━━━━━━━━━ 11s 11ms/step - accuracy: 0.9768 - loss: 0.0739 - val_accuracy: 0.9833 - val_loss: 0.0514 Epoch 4/10 1050/1050 ━━━━━━━━━━━━━━━━━━━━ 20s 11ms/step - accuracy: 0.9802 - loss: 0.0623 - val_accuracy: 0.9869 - val_loss: 0.0425 Epoch 5/10 1050/1050 ━━━━━━━━━━━━━━━━━━━━ 11s 11ms/step - accuracy: 0.9819 - loss: 0.0545 - val_accuracy: 0.9888 - val_loss: 0.0373 Epoch 6/10 1050/1050 ━━━━━━━━━━━━━━━━━━━━ 12s 11ms/step - accuracy: 0.9832 - loss: 0.0496 - val_accuracy: 0.9870 - val_loss: 0.0421 Epoch 7/10 1050/1050 ━━━━━━━━━━━━━━━━━━━━ 12s 11ms/step - accuracy: 0.9845 - loss: 0.0467 - val_accuracy: 0.9896 - val_loss: 0.0347 Epoch 8/10 1050/1050 ━━━━━━━━━━━━━━━━━━━━ 12s 11ms/step - accuracy: 0.9848 - loss: 0.0438 - val_accuracy: 0.9892 - val_loss: 0.0362 Epoch 9/10 1050/1050 ━━━━━━━━━━━━━━━━━━━━ 21s 12ms/step - accuracy: 0.9871 - loss: 0.0378 - val_accuracy: 0.9907 - val_loss: 0.0318 Epoch 10/10 1050/1050 ━━━━━━━━━━━━━━━━━━━━ 12s 12ms/step - accuracy: 0.9886 - loss: 0.0352 - val_accuracy: 0.9882 - val_loss: 0.0399
plot_tensorflow_training_results(history=callback)y_prd = model.predict(x_tst)
y_prd_labels = np.argmax(y_prd, axis=1)875/875 ━━━━━━━━━━━━━━━━━━━━ 4s 4ms/step
tst_df["Label"] = y_prd_labels
tst_df = tst_df.reset_index(names="ImageId")
tst_df["ImageId"] += 1
tst_df[["ImageId", "Label"]].to_csv("tensorflow-prediction.csv", index=False, header=True)# 1. Importing the necessary libraries.
import os
import torch
import torchvision
import torch.nn.functional as F
from tqdm import tqdm
import torch.nn as nn
import matplotlib.pyplot as plt
import plotly.graph_objects as go
from plotly.subplots import make_subplots
class NumpyDataset(torch.utils.data.Dataset):
def __init__(self, data, labels=None, train=True):
self.data = torch.from_numpy(data).float()
if train:
self.labels = torch.from_numpy(labels).long()
self.train = train
def __len__(self):
return len(self.data)
def __getitem__(self, idx):
sample = self.data[idx]
if self.train:
return sample, self.labels[idx]
return sample
x_trn = np.expand_dims(np.squeeze(x_trn, axis=-1), axis=1)
x_val = np.expand_dims(np.squeeze(x_val, axis=-1), axis=1)
x_tst = np.expand_dims(np.squeeze(x_tst, axis=-1), axis=1)
# 3. Loading the dataset.
mnist_dataset_trn = NumpyDataset(data=x_trn, labels=y_trn, train=True)
mnist_dataset_val = NumpyDataset(data=x_val, labels=y_val, train=True)
mnist_dataset_tst = NumpyDataset(data=x_tst, labels=None, train=False)
# 4. Preprocessing the data to make it suitable for training.
trn_loader = torch.utils.data.DataLoader(
dataset=mnist_dataset_trn,
batch_size=batch_size,
shuffle=True)
val_loader = torch.utils.data.DataLoader(
dataset=mnist_dataset_val,
batch_size=batch_size,
shuffle=True)
tst_loader = torch.utils.data.DataLoader(
dataset=mnist_dataset_tst,
batch_size=batch_size,
shuffle=False)
# 5. Initializing the model architecture.
class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.conv1 = nn.Conv2d(1, kernels_layer_1, kernel_size=3)
self.conv2 = nn.Conv2d(kernels_layer_1, kernels_layer_2, kernel_size=3)
self.fc = nn.Linear(5*5*64, n_classes)
def forward(self, x):
x = F.relu(F.max_pool2d(self.conv1(x), 2))
x = F.relu(F.max_pool2d(self.conv2(x), 2))
x = x.view(-1,5*5*64 )
return F.softmax(self.fc(x), dim=1)
model = CNN()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
loss_function = nn.CrossEntropyLoss()
# Tracking metrics
train_losses = []
test_losses = []
train_accuracies = []
test_accuracies = []
# 6. Training the model using the defined parameters and dataset.
for epoch in range(n_epochs):
model.train()
running_loss = 0
correct_train = 0
total_train = 0
for batch_idx, (x_trn_batch, y_trn_batch) in tqdm(enumerate(trn_loader)):
optimizer.zero_grad()
y_pred_batch = model(x_trn_batch)
loss = loss_function(y_pred_batch, y_trn_batch)
loss.backward()
optimizer.step()
running_loss += loss.item()
_, predicted = torch.max(y_pred_batch, 1)
correct_train += (predicted == y_trn_batch).sum().item()
total_train += y_trn_batch.size(0)
train_losses.append(running_loss / len(trn_loader))
train_accuracies.append(correct_train / len(x_trn))
model.eval()
test_loss = 0
correct_test = 0
total_test = 0
with torch.no_grad():
for x_val_batch, y_val_batch in val_loader:
y_pred_batch = model(x_val_batch)
loss = loss_function(y_pred_batch, y_val_batch)
test_loss += loss.item()
_, predicted = torch.max(y_pred_batch, 1)
correct_test += (predicted == y_val_batch).sum().item()
total_test += y_val_batch.size(0)
test_losses.append(test_loss / len(val_loader))
test_accuracies.append(correct_test / len(x_val))
print(f'Epoch {epoch+1}/{n_epochs}, Train Loss: {train_losses[-1]:.4f}, Train Accuracy: {train_accuracies[-1]:.4f}, Test Loss: {test_losses[-1]:.4f}, Test Accuracy: {test_accuracies[-1]:.4f}')
plot_pytorch_training_results(n_epochs, train_losses, test_losses, train_accuracies, test_accuracies)1050it [00:12, 85.69it/s]
Epoch 1/10, Train Loss: 1.5524, Train Accuracy: 0.9181, Test Loss: 1.4922, Test Accuracy: 0.9714
1050it [00:11, 89.86it/s]
Epoch 2/10, Train Loss: 1.4903, Train Accuracy: 0.9727, Test Loss: 1.4898, Test Accuracy: 0.9738
1050it [00:11, 87.88it/s]
Epoch 3/10, Train Loss: 1.4841, Train Accuracy: 0.9784, Test Loss: 1.4847, Test Accuracy: 0.9774
1050it [00:11, 91.19it/s]
Epoch 4/10, Train Loss: 1.4805, Train Accuracy: 0.9818, Test Loss: 1.4800, Test Accuracy: 0.9818
1050it [00:11, 89.92it/s]
Epoch 5/10, Train Loss: 1.4769, Train Accuracy: 0.9849, Test Loss: 1.4786, Test Accuracy: 0.9832
1050it [00:11, 88.57it/s]
Epoch 6/10, Train Loss: 1.4750, Train Accuracy: 0.9865, Test Loss: 1.4764, Test Accuracy: 0.9858
1050it [00:11, 92.62it/s]
Epoch 7/10, Train Loss: 1.4737, Train Accuracy: 0.9880, Test Loss: 1.4780, Test Accuracy: 0.9842
1050it [00:11, 89.66it/s]
Epoch 8/10, Train Loss: 1.4725, Train Accuracy: 0.9890, Test Loss: 1.4770, Test Accuracy: 0.9851
1050it [00:11, 91.02it/s]
Epoch 9/10, Train Loss: 1.4711, Train Accuracy: 0.9905, Test Loss: 1.4758, Test Accuracy: 0.9861
1050it [00:11, 88.03it/s]
Epoch 10/10, Train Loss: 1.4700, Train Accuracy: 0.9915, Test Loss: 1.4758, Test Accuracy: 0.9852
y_pred_tot = []
with torch.no_grad():
for x_tst_batch in tst_loader:
y_pred_batch = model(x_val_batch)
_, pred = torch.max(y_pred_batch, 1)
y_pred_tot += list(pred.numpy())tst_df["Label"] = y_prd_labels
tst_df[["ImageId", "Label"]].to_csv("pytorch-prediction.csv", index=False, header=True)