PyTorch实现Logistic regression
import torch
import torch.nn as nn
import torchvision
import torch.nn.functional as F
import numpy as np
from torchvision.datasets import MNIST
import matplotlib.pyplot as plt
import torchvision.transforms as transforms
from torch.utils.data.sampler import SubsetRandomSampler
from torch.utils.data.dataloader import DataLoader
#Download training dataset
dataset = MNIST(root='data/', download=True)
test_dataset = MNIST(root='data/', train=False)
#Check the data
image, label = dataset[0]
plt.imshow(image, cmap='gray')
print('Label:', label)
#MNIST dataset (images and labels)
dataset = MNIST(root='data/',
train=True,
transform=transforms.ToTensor())
img_tensor, label = dataset[0]
print(img_tensor.shape, label)
#Plot the image by passing in the 28x28 matrix
plt.imshow(img_tensor[0,10:15,10:15], cmap='gray');
#Training and Validation Datasets
def split_indices(n, val_pct):
# Determine size of validation set
n_val = int(val_pct*n)
# Create random permutation of 0 to n-1
idxs = np.random.permutation(n)
# Pick first n_val indices for validation set
return idxs[n_val:], idxs[:n_val]
train_indices, val_indices = split_indices(len(dataset), val_pct=0.2)
print(len(train_indices), len(val_indices))
print('Sample val indices: ', val_indices[:20])
batch_size=100
#Training sampler and data loader
train_sampler = SubsetRandomSampler(train_indices)
train_loader = DataLoader(dataset,
batch_size,
sampler=train_sampler)
#Validation sampler and data loader
val_sampler = SubsetRandomSampler(val_indices)
val_loader = DataLoader(dataset,
batch_size,
sampler=val_sampler)
for batch in val_loader:
inputs, targets = batch
print(inputs.shape)
print(targets.shape)
break
input_size = 28*28
num_classes = 10
#Logistic regression model
model = nn.Linear(input_size, num_classes)
print(model.weight.shape)
model.weight
print(model.bias.shape)
model.bias
for batch in train_loader:
images, labels = batch
images = images.reshape(100, 784)
print('input shape:', images.shape)
outputs = model(images)
#outputs = images @ model.weight.t() + model.bias
break
print('output shape:', outputs.shape)
class MnistModel(nn.Module):
def __init__(self):
super().__init__()
self.linear = nn.Linear(input_size, num_classes)
def forward(self, xb):
xb = xb.reshape(-1, 784)
out = self.linear(xb)
return out
model = MnistModel()
print(model.linear.weight.shape, model.linear.bias.shape)
list(model.parameters())
for images, labels in train_loader:
print('input shape:', images.shape)
outputs = model(images)
break
print('outputs.shape : ', outputs.shape)
print('Sample outputs :\n', outputs[:2].data)
#Apply softmax for each output row
probs = F.softmax(outputs, dim=1)
#Look at sample probabilities
print("Sample probabilities:\n", probs[:2].data)
#Add up the probabilities of an output row
print("Sum: ", torch.sum(probs[0]).item())
max_probs, preds = torch.max(probs, dim=1)
print(preds)
def accuracy(l1, l2):
return torch.sum(l1 == l2).item() / len(l1)
print(accuracy(preds, labels))
loss_fn = F.cross_entropy
#Loss for current batch of data
loss = loss_fn(outputs, labels)
print(loss)
learning_rate = 0.001
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
def loss_batch(model, loss_func, xb, yb, opt=None, metric=None):
#Calculate loss
preds = model(xb)
loss = loss_func(preds, yb)
if opt is not None:
#Compute gradients
loss.backward()
#Update parameters
opt.step()
#Reset gradients
opt.zero_grad()
metric_result = None
if metric is not None:
#Compute the metric
metric_result = metric(preds, yb)
return loss.item(), len(xb), metric_result
def evaluate(model, loss_fn, valid_dl, metric=None):
with torch.no_grad():
#Pass each batch through the model
results = [loss_batch(model, loss_fn, xb, yb, metric=metric)
for xb,yb in valid_dl]
#Separate losses, counts and metrics
losses, nums, metrics = zip(*results)
#Total size of the dataset
total = np.sum(nums)
#Avg. loss across batches
avg_loss = np.sum(np.multiply(losses, nums)) / total
avg_metric = None
if metric is not None:
#Avg. of metric across batches
avg_metric = np.sum(np.multiply(metrics, nums)) / total
return avg_loss, total, avg_metric
def accuracy(outputs, labels):
_, preds = torch.max(outputs, dim=1)
return torch.sum(preds == labels).item() / len(preds)
val_loss, total, val_acc = evaluate(model, loss_fn, val_loader, metric=accuracy)
print('Loss: {:.4f}, Accuracy: {:.4f}'.format(val_loss, val_acc))
def fit(epochs, model, loss_fn, opt, train_dl, valid_dl, metric=None):
for epoch in range(epochs):
#Training
for xb,yb in train_dl:
loss,_,_ = loss_batch(model, loss_fn, xb, yb, opt)
#Evaluation
result = evaluate(model, loss_fn, valid_dl, metric)
val_loss, total, val_metric = result
#Print progress
if metric is None:
print('Epoch [{}/{}], Loss: {:.4f}'
.format(epoch+1, epochs, val_loss))
else:
print('Epoch [{}/{}], Loss: {:.4f}, {}: {:.4f}'
.format(epoch+1, epochs, val_loss, metric.__name__, val_metric))
# Redifine model and optimizer
model = MnistModel()
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
fit(5, model, F.cross_entropy, optimizer,
train_loader, val_loader, accuracy)
输出
Epoch [1/5], Loss: 1.8719, accuracy: 0.6530
Epoch [2/5], Loss: 1.5743, accuracy: 0.7440
Epoch [3/5], Loss: 1.3650, accuracy: 0.7756
Epoch [4/5], Loss: 1.2146, accuracy: 0.7938
Epoch [5/5], Loss: 1.1031, accuracy: 0.8053