pytorch / pages /1_TensorIntro.py
eaglelandsonce's picture
Update pages/1_TensorIntro.py
a761b67 verified
raw
history blame
11.2 kB
import streamlit as st
import torch
import io
import sys
# Function to execute the input code and capture print statements
def execute_code(code):
# Redirect stdout to capture print statements
old_stdout = sys.stdout
sys.stdout = mystdout = io.StringIO()
global_vars = {"torch": torch}
local_vars = {}
try:
exec(code, global_vars, local_vars)
output = mystdout.getvalue()
except Exception as e:
output = str(e)
finally:
# Reset redirect.
sys.stdout = old_stdout
return output, local_vars
# Dictionary with exercise details
exercises = {
"Exercise 1: Create and Manipulate Tensors": {
"description": "Tensors are the core data structure in PyTorch, similar to arrays in NumPy but with additional capabilities for GPU acceleration. This exercise introduces how to create tensors from various data sources such as lists and NumPy arrays. It also covers basic tensor operations like addition, subtraction, and element-wise multiplication, which are fundamental for manipulating data in PyTorch.",
"code": '''import torch
import numpy as np
# Creating tensors from Python lists
# This creates a 1D tensor from the list [1, 2, 3]
tensor_from_list = torch.tensor([1, 2, 3])
print("Tensor from list:", tensor_from_list)
# Creating tensors from NumPy arrays
# This converts a NumPy array to a tensor
numpy_array = np.array([4, 5, 6])
tensor_from_numpy = torch.tensor(numpy_array)
print("Tensor from NumPy array:", tensor_from_numpy)
# Performing basic tensor operations
tensor1 = torch.tensor([1, 2, 3])
tensor2 = torch.tensor([4, 5, 6])
# Addition
addition = tensor1 + tensor2
print("Addition:", addition)
# Subtraction
subtraction = tensor1 - tensor2
print("Subtraction:", subtraction)
# Element-wise multiplication
elementwise_multiplication = tensor1 * tensor2
print("Element-wise Multiplication:", elementwise_multiplication)
'''
},
"Exercise 2: Tensor Indexing and Slicing": {
"description": "Indexing and slicing allow you to access and manipulate specific elements and sub-tensors. This is crucial for tasks such as data preprocessing and manipulation in machine learning workflows. This exercise demonstrates how to index and slice tensors to extract and modify elements efficiently.",
"code": '''import torch
# Creating a 2D tensor (matrix)
tensor = torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# Indexing elements
# Accessing the element at the 2nd row and 3rd column (indexing starts at 0)
element = tensor[1, 2]
print("Element at index [1, 2]:", element)
# Slicing sub-tensors
# Extracting the entire second row
row = tensor[1, :]
print("Second row:", row)
# Extracting the entire third column
column = tensor[:, 2]
print("Third column:", column)
# Modifying elements
# Changing the first element of the tensor to 10
tensor[0, 0] = 10
print("Modified tensor:", tensor)
'''
},
"Exercise 3: Reshaping and Transposing Tensors": {
"description": "Reshaping and transposing tensors are common operations in machine learning workflows, especially when preparing data for model training. This exercise covers how to reshape tensors using view, squeeze, and unsqueeze, as well as how to transpose tensors.",
"code": '''import torch
# Creating a 2D tensor
tensor = torch.tensor([[1, 2, 3], [4, 5, 6]])
# Reshaping a tensor
reshaped_tensor = tensor.view(3, 2)
print("Reshaped tensor:", reshaped_tensor)
# Squeezing a tensor (removing dimensions of size 1)
squeezed_tensor = torch.tensor([[1], [2], [3]]).squeeze()
print("Squeezed tensor:", squeezed_tensor)
# Unsqueezing a tensor (adding dimensions of size 1)
unsqueezed_tensor = squeezed_tensor.unsqueeze(1)
print("Unsqueezed tensor:", unsqueezed_tensor)
# Transposing a tensor
transposed_tensor = tensor.t()
print("Transposed tensor:", transposed_tensor)
'''
},
"Exercise 4: Tensor Operations for Deep Learning": {
"description": "Deep learning requires various tensor operations such as matrix multiplication and element-wise operations. This exercise demonstrates how to perform matrix multiplication, calculate the dot product, and transpose tensors, which are essential for building neural networks.",
"code": '''import torch
# Creating tensors for matrix multiplication
a = torch.tensor([[1, 2], [3, 4]])
b = torch.tensor([[5, 6], [7, 8]])
# Matrix multiplication
matrix_multiplication = torch.matmul(a, b)
print("Matrix multiplication result:", matrix_multiplication)
# Transposing a tensor
transposed_a = a.t()
print("Transposed tensor:", transposed_a)
# Calculating the dot product
dot_product = torch.dot(torch.tensor([1, 2]), torch.tensor([3, 4]))
print("Dot product result:", dot_product)
'''
},
"Exercise 5: Tensors and Gradients": {
"description": "Gradients are essential for optimizing neural networks during training. This exercise introduces the autograd feature in PyTorch, showing how to compute gradients using backpropagation.",
"code": '''import torch
# Creating a tensor with gradient tracking enabled
x = torch.tensor([2.0, 3.0], requires_grad=True)
# Performing operations on the tensor
y = x * 2
z = y.mean()
# Backpropagation to compute gradients
z.backward()
# Printing the gradients
print("Gradients of x:", x.grad)
# Disabling gradient tracking
with torch.no_grad():
y = x * 2
print("Result with no gradient tracking:", y)
'''
},
"Exercise 6: Practical Tensor Exercises - Custom Layers": {
"description": "Implementing custom layers and activation functions is crucial for creating neural networks tailored to specific tasks. This exercise guides you through creating a simple linear layer and a ReLU activation function.",
"code": '''import torch
# Implementing a custom linear layer
class LinearLayer:
def __init__(self, input_dim, output_dim):
self.weights = torch.randn(input_dim, output_dim, requires_grad=True)
self.bias = torch.randn(output_dim, requires_grad=True)
def forward(self, x):
return torch.matmul(x, self.weights) + self.bias
# Creating an instance of the custom linear layer
layer = LinearLayer(2, 1)
# Passing a tensor through the layer
input_tensor = torch.tensor([[1.0, 2.0]])
output_tensor = layer.forward(input_tensor)
print("Output of the custom linear layer:", output_tensor)
# Implementing a custom ReLU activation function
def relu(x):
return torch.max(torch.tensor(0.0), x)
# Applying the ReLU activation function
relu_output = relu(torch.tensor([-1.0, 2.0, -0.5, 3.0]))
print("Output of the custom ReLU function:", relu_output)
'''
},
"Exercise 7: Data Normalization with Tensors": {
"description": "Data normalization is a key preprocessing step in machine learning. This exercise demonstrates how to normalize data using Min-Max normalization, which scales the data to a specific range.",
"code": '''import torch
# Function for Min-Max normalization
def min_max_normalize(tensor):
min_val = tensor.min()
max_val = tensor.max()
return (tensor - min_val) / (max_val - min_val)
# Creating a tensor with sample data
data = torch.tensor([10, 20, 30, 40, 50])
# Applying Min-Max normalization
normalized_data = min_max_normalize(data)
print("Normalized data:", normalized_data)
'''
},
"Final Project: Image Classification with a Simple CNN": {
"description": "In this project, you will build and train a simple Convolutional Neural Network (CNN) for image classification using the CIFAR-10 dataset. This involves loading the dataset, defining the CNN model, and training the model to classify images into one of the 10 classes.",
"code": '''import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
# Define the transformation for the dataset
transform = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5))])
# Load the CIFAR-10 dataset
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=32, shuffle=True, num_workers=2)
testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=32, shuffle=False, num_workers=2)
# Define the CNN model
class SimpleCNN(nn.Module):
def __init__(self):
super(SimpleCNN, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = self.pool(nn.functional.relu(self.conv1(x)))
x = self.pool(nn.functional.relu(self.conv2(x)))
x = x.view(-1, 16 * 5 * 5)
x = nn.functional.relu(self.fc1(x))
x = nn.functional.relu(self.fc2(x))
x = self.fc3(x)
return x
# Instantiate the model, loss function, and optimizer
net = SimpleCNN()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
# Training loop
for epoch in range(5): # loop over the dataset multiple times
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
inputs, labels = data
optimizer.zero_grad()
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
if i % 200 == 199: # print every 200 mini-batches
print(f'[{epoch + 1}, {i + 1}] loss: {running_loss / 200:.3f}')
running_loss = 0.0
print('Finished Training')
# Save the trained model
torch.save(net.state_dict(), 'simple_cnn.pth')
# Testing the model
correct = 0
total = 0
with torch.no_grad():
for data in testloader:
images, labels = data
outputs = net(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f'Accuracy of the network on the 10000 test images: {100 * correct / total}%')
'''
},
}
st.title('PyTorch Code Runner')
# Side menu for exercises
exercise_choice = st.sidebar.radio("Choose an exercise", list(exercises.keys()))
# Display the chosen exercise description
st.subheader(exercise_choice)
st.write(exercises[exercise_choice]["description"])
# Text area for inputting the PyTorch code
code_input = st.text_area("Enter your PyTorch code here", height=300, value=exercises[exercise_choice]["code"])
# Button to execute the code
if st.button("Run Code"):
# Prepend the import statement
code_to_run = "import torch\n" + code_input
# Execute the code and capture the output
output, variables = execute_code(code_to_run)
# Display the output
st.subheader('Output')
st.text(output)
# Display returned variables
if variables:
st.subheader('Variables')
for key, value in variables.items():
st.text(f"{key}: {value}")