MNIST資料集分類
阿新 • • 發佈:2020-08-01
import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from torchvision import datasets, transforms import matplotlib.pyplot as plt import numpy # 一個函式,用來計算模型中有多少引數 def get_n_params(model): np=0 for p in list(model.parameters()): np += p.nelement() return np # 使用GPU訓練,可以在選單 "程式碼執行工具" -> "更改執行時型別" 裡進行設定 device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
1.載入資料 (MNIST)
torchvision.datasets.MNIST(root, train=True, transform=None, target_transform=None, download=False) input_size = 28*28 # MNIST上的影象尺寸是 28x28 output_size = 10 # 類別為 0 到 9 的數字,因此為十類 train_loader = torch.utils.data.DataLoader( datasets.MNIST('./data', train=True, download=True, transform=transforms.Compose( [transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))])), batch_size=64, shuffle=True) test_loader = torch.utils.data.DataLoader( datasets.MNIST('./data', train=False, transform=transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))])), batch_size=1000, shuffle=True) #顯示資料集中的部分影象 plt.figure(figsize=(8, 5)) for i in range(20): plt.subplot(4, 5, i + 1) image, _ = train_loader.dataset.__getitem__(i) plt.imshow(image.squeeze().numpy(),'gray') plt.axis('off');
2.建立網路
class FC2Layer(nn.Module): def __init__(self, input_size, n_hidden, output_size): super(FC2Layer, self).__init__() self.input_size = input_size # 這裡直接用 Sequential 就定義了網路,注意要和下面 CNN 的程式碼區分開 self.network = nn.Sequential( nn.Linear(input_size, n_hidden), nn.ReLU(), nn.Linear(n_hidden, n_hidden), nn.ReLU(), nn.Linear(n_hidden, output_size), nn.LogSoftmax(dim=1) ) def forward(self, x): x = x.view(-1, self.input_size) return self.network(x) class CNN(nn.Module): def __init__(self, input_size, n_feature, output_size): super(CNN, self).__init__() self.n_feature = n_feature self.conv1 = nn.Conv2d(in_channels=1, out_channels=n_feature, kernel_size=5) self.conv2 = nn.Conv2d(n_feature, n_feature, kernel_size=5) self.fc1 = nn.Linear(n_feature*4*4, 50) self.fc2 = nn.Linear(50, 10) # 下面的 forward 函式,定義了網路的結構,按照一定順序,把上面構建的一些結構組織起來 # 意思就是,conv1, conv2 等等的,可以多次重用 def forward(self, x, verbose=False): x = self.conv1(x) x = F.relu(x) x = F.max_pool2d(x, kernel_size=2) x = self.conv2(x) x = F.relu(x) x = F.max_pool2d(x, kernel_size=2) x = x.view(-1, self.n_feature*4*4) x = self.fc1(x) x = F.relu(x) x = self.fc2(x) x = F.log_softmax(x, dim=1) return x #定義訓練和測試函式 # 訓練函式 def train(model): model.train() for batch_idx, (data, target) in enumerate(train_loader): # 把資料送到GPU中 data, target = data.to(device), target.to(device) optimizer.zero_grad() output = model(data) loss = F.nll_loss(output, target) loss.backward() optimizer.step() if batch_idx % 100 == 0: print('Train: [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format( batch_idx * len(data), len(train_loader.dataset), 100. * batch_idx / len(train_loader), loss.item())) #測試函式 def test(model): model.eval() test_loss = 0 correct = 0 for data, target in test_loader: # 把資料送到GPU中 data, target = data.to(device), target.to(device) # 把資料送入模型,得到預測結果 output = model(data) # 計算本次batch的損失,並加到 test_loss 中 test_loss += F.nll_loss(output, target, reduction='sum').item() # get the index of the max log-probability,最後一層輸出10個數, # 值最大的那個即對應著分類結果,然後把分類結果儲存在 pred 裡 pred = output.data.max(1, keepdim=True)[1] # 將 pred 與 target 相比,得到正確預測結果的數量,並加到 correct 中 correct += pred.eq(target.data.view_as(pred)).cpu().sum().item() test_loss /= len(test_loader.dataset) accuracy = 100. * correct / len(test_loader.dataset) print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format( test_loss, correct, len(test_loader.dataset), accuracy))
- 在小型全連線網路上訓練(Fully-connected network)
n_hidden = 8 # number of hidden units
model_fnn = FC2Layer(input_size, n_hidden, output_size)
model_fnn.to(device)
optimizer = optim.SGD(model_fnn.parameters(), lr=0.01, momentum=0.5)
print('Number of parameters: {}'.format(get_n_params(model_fnn)))
train(model_fnn)
test(model_fnn)
4.在卷積神經網路上訓練
# Training settings
n_features = 6 # number of feature maps
model_cnn = CNN(input_size, n_features, output_size)
model_cnn.to(device)
optimizer = optim.SGD(model_cnn.parameters(), lr=0.01, momentum=0.5)
print('Number of parameters: {}'.format(get_n_params(model_cnn)))
train(model_cnn)
test(model_cnn)
5.打亂畫素順序再次在兩個網路上訓練與測試
perm = torch.randperm(784)
plt.figure(figsize=(8, 4))
for i in range(10):
image, _ = train_loader.dataset.__getitem__(i)
# permute pixels
image_perm = image.view(-1, 28*28).clone()
image_perm = image_perm[:, perm]
image_perm = image_perm.view(-1, 1, 28, 28)
plt.subplot(4, 5, i + 1)
plt.imshow(image.squeeze().numpy(), 'gray')
plt.axis('off')
plt.subplot(4, 5, i + 11)
plt.imshow(image_perm.squeeze().numpy(), 'gray')
plt.axis('off')
# 對每個 batch 裡的資料,打亂畫素順序的函式
def perm_pixel(data, perm):
# 轉化為二維矩陣
data_new = data.view(-1, 28*28)
# 打亂畫素順序
data_new = data_new[:, perm]
# 恢復為原來4維的 tensor
data_new = data_new.view(-1, 1, 28, 28)
return data_new
# 訓練函式
def train_perm(model, perm):
model.train()
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device)
# 畫素打亂順序
data = perm_pixel(data, perm)
optimizer.zero_grad()
output = model(data)
loss = F.nll_loss(output, target)
loss.backward()
optimizer.step()
if batch_idx % 100 == 0:
print('Train: [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx / len(train_loader), loss.item()))
# 測試函式
def test_perm(model, perm):
model.eval()
test_loss = 0
correct = 0
for data, target in test_loader:
data, target = data.to(device), target.to(device)
# 畫素打亂順序
data = perm_pixel(data, perm)
output = model(data)
test_loss += F.nll_loss(output, target, reduction='sum').item()
pred = output.data.max(1, keepdim=True)[1]
correct += pred.eq(target.data.view_as(pred)).cpu().sum().item()
test_loss /= len(test_loader.dataset)
accuracy = 100. * correct / len(test_loader.dataset)
print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
test_loss, correct, len(test_loader.dataset),
accuracy))
#在全連線網路上訓練與測試:
perm = torch.randperm(784)
n_hidden = 8 # number of hidden units
model_fnn = FC2Layer(input_size, n_hidden, output_size)
model_fnn.to(device)
optimizer = optim.SGD(model_fnn.parameters(), lr=0.01, momentum=0.5)
print('Number of parameters: {}'.format(get_n_params(model_fnn)))
train_perm(model_fnn, perm)
test_perm(model_fnn, perm)
#在卷積神經網路上訓練與測試
perm = torch.randperm(784)
n_features = 6 # number of feature maps
model_cnn = CNN(input_size, n_features, output_size)
model_cnn.to(device)
optimizer = optim.SGD(model_cnn.parameters(), lr=0.01, momentum=0.5)
print('Number of parameters: {}'.format(get_n_params(model_cnn)))
train_perm(model_cnn, perm)
test_perm(model_cnn, perm)