A hobby project inspired by torch
to learn how to design a deep learning framework.
This project also includes a DIY version of the torchdiy.transformers
package, similar to Hugging Face's transformers
.
To install the torchdiy
package, run the following command:
$ pip install torchdiy
To run the example on the MNIST dataset, execute the following command:
$ python mnist.py
from torchvision import datasets, transforms
import torchdiy as torch
nn = torch.nn
optim = torch.optim
DataLoader = torch.utils.data.DataLoader
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
test_dataset = datasets.MNIST(root='./data', train=False, download=True, transform=transform)
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)
class MLP(nn.Module):
def __init__(self):
super(MLP, self).__init__()
self.fc1 = nn.Linear(28 * 28, 512)
self.fc2 = nn.Linear(512, 256)
self.fc3 = nn.Linear(256, 10)
self.relu = nn.ReLU()
# self.dropout = nn.Dropout(0.5)
def forward(self, x):
x = x.view(-1, 28 * 28)
x = self.relu(self.fc1(x))
# x = self.dropout(x)
x = self.relu(self.fc2(x))
# x = self.dropout(x)
x = self.fc3(x)
return x
class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1)
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)
self.fc1 = nn.Linear(64 * 7 * 7, 128)
self.fc2 = nn.Linear(128, 10)
self.relu = nn.ReLU()
self.maxpool = nn.MaxPool2d(kernel_size=2, stride=2)
# self.dropout = nn.Dropout(0.5)
def forward(self, x):
x = self.relu(self.conv1(x))
x = self.maxpool(x)
x = self.relu(self.conv2(x))
x = self.maxpool(x)
x = x.view(-1, 64 * 7 * 7)
x = self.relu(self.fc1(x))
# x = self.dropout(x)
x = self.fc2(x)
return x
# model = CNN()
model = MLP()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
num_epochs = 3
for epoch in range(num_epochs):
model.train()
running_loss = 0.0
for i, (images, labels) in enumerate(train_loader):
optimizer.zero_grad()
outputs = model(images)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
if (i + 1) % 100 == 0:
print(f'Epoch [{epoch + 1}/{num_epochs}], Step [{i + 1}/{len(train_loader)}], Loss: {loss.item():.4f}')
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {running_loss / len(train_loader):.4f}')
model.eval()
correct = 0
total = 0
with torch.no_grad():
for images, labels in test_loader:
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f'Accuracy of the model on the 10000 test images: {100 * correct / total:.2f}%')
torch.save(model.state_dict(), 'mnist_cnn.pth')
model.load_state_dict(torch.load('mnist_cnn.pth'))
model.eval()
with torch.no_grad():
sample_image, true_label = test_dataset[0]
sample_image = sample_image.unsqueeze(0)
output = model(sample_image)
_, predicted = torch.max(output, 1)
print(f'Predicted: {predicted.item()}, True Label: {true_label}')
Output example:
$ python mnist.py
Epoch [1/3], Step [100/938], Loss: 0.1205
Epoch [1/3], Step [200/938], Loss: 0.1729
...
Accuracy of the model on the 10000 test images: 96.92%
Predicted: 7, True Label: 7