Initial commit
This commit is contained in:
commit
8542a1f9ef
59 files changed
+73464
No files matched your search
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,150 @@
|
||||
import torch
|
||||
|
||||
import torch.nn as nn
|
||||
import torch.nn.functional as F
|
||||
|
||||
import torch.optim as optim
|
||||
|
||||
import torchvision
|
||||
import torchvision.transforms as transforms
|
||||
|
||||
|
||||
class FFNet(nn.Module):
|
||||
"""
|
||||
Feedforward neural network, virtual base class
|
||||
"""
|
||||
def __init__(self):
|
||||
super(FFNet, self).__init__()
|
||||
self.dnn_model = self.build_model()
|
||||
|
||||
def build_model(self):
|
||||
""" build specific model """
|
||||
raise NotImplementedError
|
||||
|
||||
def forward(self, x):
|
||||
""" feed data forward and return result """
|
||||
raise NotImplementedError
|
||||
|
||||
def train_model(self, trainloader, testloader, loss_fn, optimizer, num_epochs):
|
||||
"""Train a model."""
|
||||
|
||||
def train_epoch(model, dataloader, loss_fn, optimizer):
|
||||
"""Train a single epoch"""
|
||||
num_data = len(dataloader.dataset)
|
||||
# Set the model to training mode
|
||||
model.train()
|
||||
for batch, (X, y) in enumerate(dataloader):
|
||||
# Compute prediction error
|
||||
pred = model(X)
|
||||
loss = loss_fn(pred, y)
|
||||
|
||||
# Backpropagation
|
||||
optimizer.zero_grad()
|
||||
loss.backward()
|
||||
optimizer.step()
|
||||
|
||||
if batch % 100 == 0:
|
||||
loss, current = loss.item(), batch * len(X)
|
||||
print(f"loss: {loss:>7f} [{current:>5d}/{num_data:>5d}]")
|
||||
|
||||
def test_epoch(model, dataloader, loss_fn):
|
||||
"""Test a single epoch"""
|
||||
num_data = len(dataloader.dataset)
|
||||
num_batches = len(dataloader)
|
||||
# Set the model to evaluate mode
|
||||
model.eval()
|
||||
test_loss, correct = 0, 0
|
||||
with torch.no_grad():
|
||||
for X, y in dataloader:
|
||||
pred = model(X)
|
||||
test_loss += loss_fn(pred, y).item()
|
||||
correct += (pred.argmax(1) == y).type(torch.float).sum().item()
|
||||
test_loss /= num_batches
|
||||
correct /= num_data
|
||||
print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")
|
||||
|
||||
for epoch in range(num_epochs):
|
||||
print(f"Epoch {epoch+1}\n-------------------------------")
|
||||
train_epoch(self, trainloader, loss_fn, optimizer)
|
||||
test_epoch(self, testloader, loss_fn)
|
||||
print("Done!")
|
||||
|
||||
def make_predict(self, images):
|
||||
""" predict labels for images """
|
||||
self.eval()
|
||||
with torch.no_grad():
|
||||
outputs = self(images)
|
||||
_, predicted = torch.max(outputs.data, 1) # (max, max_indices)
|
||||
return predicted
|
||||
|
||||
def evaluate_model(self, testloader, n):
|
||||
""" evaluation: return accuracy """
|
||||
correct = 0
|
||||
for inputs, labels in testloader:
|
||||
pred = self.make_predict(inputs)
|
||||
correct += (pred == labels).sum()
|
||||
return 100 * correct / n
|
||||
|
||||
def predict_one(self, x):
|
||||
self.eval()
|
||||
with torch.no_grad():
|
||||
outputs = self(x)
|
||||
predicted = outputs[0].argmax(0)
|
||||
return predicted
|
||||
|
||||
|
||||
class LeNet(FFNet):
|
||||
def __init__(self):
|
||||
super(LeNet, self).__init__()
|
||||
|
||||
def build_model(self):
|
||||
""" build specific model """
|
||||
raise NotImplementedError
|
||||
|
||||
def forward(self, x):
|
||||
""" feed data forward and return result """
|
||||
return self.dnn_model(x)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# load train and test set
|
||||
trainset = torchvision.datasets.MNIST(
|
||||
'../data', train=True, download=True, transform=transforms.ToTensor())
|
||||
testset = torchvision.datasets.MNIST(
|
||||
'../data', train=False, download=True, transform=transforms.ToTensor())
|
||||
print(f'Train #: {len(trainset)}; Test #: {len(testset)}')
|
||||
# data iterator
|
||||
dataiter = iter(torch.utils.data.DataLoader(trainset, batch_size=8, shuffle=False))
|
||||
images, labels = next(dataiter)
|
||||
print(f'Labels: {labels}; Batch shape: {images.size()}')
|
||||
|
||||
# construct model
|
||||
model = LeNet()
|
||||
print(model)
|
||||
|
||||
# data loader: easier iteration
|
||||
BATCH_SIZE = 256
|
||||
NUM_WORKERS = 4
|
||||
trainloader = torch.utils.data.DataLoader(
|
||||
trainset, batch_size=BATCH_SIZE, shuffle=True, num_workers=NUM_WORKERS)
|
||||
testloader = torch.utils.data.DataLoader(
|
||||
testset, batch_size=BATCH_SIZE, shuffle=False, num_workers=NUM_WORKERS)
|
||||
|
||||
# train the model
|
||||
LR = 0.1
|
||||
loss_fn = nn.CrossEntropyLoss() # cross entropy
|
||||
optimizer = torch.optim.SGD(model.parameters(), lr=LR) # SGD
|
||||
NUM_EPOCH = 5
|
||||
model.train_model(trainloader, testloader, loss_fn, optimizer, NUM_EPOCH)
|
||||
|
||||
# check prediction accuracy
|
||||
print(f'Labels : {labels}')
|
||||
print(f'Prediction: {model.make_predict(images)}')
|
||||
print(f'Accuracy: {model.evaluate_model(testloader, len(testset)):.2f}')
|
||||
|
||||
# application: predict hand-written digit
|
||||
from PIL import Image
|
||||
image = Image.open('number6c.png')
|
||||
image = transforms.ToTensor()(image).unsqueeze(0)
|
||||
print(f'loaded image shape: {image.size()}')
|
||||
print(f'Predicted: "{model.predict_one(image)}", Actual: "{6}"')
|
||||
@@ -0,0 +1,64 @@
|
||||
Train #: 60000; Test #: 10000
|
||||
Labels: tensor([5, 0, 4, 1, 9, 2, 1, 3]); Batch shape: torch.Size([8, 1, 28, 28])
|
||||
LeNet(
|
||||
(dnn_model): Sequential(
|
||||
(0): Conv2d(1, 32, kernel_size=(5, 5), stride=(1, 1))
|
||||
(1): ReLU()
|
||||
(2): Conv2d(32, 32, kernel_size=(5, 5), stride=(1, 1))
|
||||
(3): ReLU()
|
||||
(4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
|
||||
(5): Conv2d(32, 64, kernel_size=(5, 5), stride=(1, 1))
|
||||
(6): ReLU()
|
||||
(7): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
|
||||
(8): Flatten(start_dim=1, end_dim=-1)
|
||||
(9): Linear(in_features=576, out_features=256, bias=True)
|
||||
(10): ReLU()
|
||||
(11): Linear(in_features=256, out_features=10, bias=True)
|
||||
)
|
||||
)
|
||||
Epoch 1
|
||||
-------------------------------
|
||||
loss: 2.299683 [ 0/60000]
|
||||
loss: 0.348185 [25600/60000]
|
||||
loss: 0.239826 [51200/60000]
|
||||
Test Error:
|
||||
Accuracy: 95.7%, Avg loss: 0.133152
|
||||
|
||||
Epoch 2
|
||||
-------------------------------
|
||||
loss: 0.220472 [ 0/60000]
|
||||
loss: 0.056995 [25600/60000]
|
||||
loss: 0.078447 [51200/60000]
|
||||
Test Error:
|
||||
Accuracy: 90.3%, Avg loss: 0.284392
|
||||
|
||||
Epoch 3
|
||||
-------------------------------
|
||||
loss: 0.255085 [ 0/60000]
|
||||
loss: 0.071809 [25600/60000]
|
||||
loss: 0.080565 [51200/60000]
|
||||
Test Error:
|
||||
Accuracy: 98.2%, Avg loss: 0.056539
|
||||
|
||||
Epoch 4
|
||||
-------------------------------
|
||||
loss: 0.074963 [ 0/60000]
|
||||
loss: 0.053749 [25600/60000]
|
||||
loss: 0.042180 [51200/60000]
|
||||
Test Error:
|
||||
Accuracy: 98.3%, Avg loss: 0.048151
|
||||
|
||||
Epoch 5
|
||||
-------------------------------
|
||||
loss: 0.018707 [ 0/60000]
|
||||
loss: 0.047416 [25600/60000]
|
||||
loss: 0.022978 [51200/60000]
|
||||
Test Error:
|
||||
Accuracy: 98.6%, Avg loss: 0.041758
|
||||
|
||||
Done!
|
||||
Labels : tensor([5, 0, 4, 1, 9, 2, 1, 3])
|
||||
Prediction: tensor([5, 0, 4, 1, 9, 2, 1, 3])
|
||||
Accuracy: 98.60
|
||||
loaded image shape: torch.Size([1, 1, 28, 28])
|
||||
Predicted: "0", Actual: "6"
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 176 B |
Binary file not shown.
|
After Width: | Height: | Size: 169 B |
Reference in new issue
Block a user