学习记录 —— pytorch example for MNIST
代码来自:mnist
from __future__ import print_function
import argparse
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets,transforms
class Net(nn.Module):
def __init__(self):
super(Net,self).__init__()
self.conv1 = nn.Conv2d(1, 10, kernel_size=5)
self.conv2 = nn.Conv2d(10, 20, kernel_size=5)
self.conv2_drop = nn.Dropout2d()
self.fc1 = nn.Linear(320, 50)
self.fc2 = nn.Linear(50, 10)
def forward(self, x):
x = F.relu(F.max_pool2d(self.conv1(x), 2))
x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))
x = x.view(-1, 320)
x = F.relu(self.fc1(x))
x = F.dropout(x, training=self.training)
x = self.fc2(x)
return F.log_softmax(x, dim=1)
导入包,pytorch的一些函数功能见:pytorch中文文档
定义Net类,定义初始化。在定义一个类的时候
def __init__(self):
是必须的,其中对于 self 的理解,这里说的比较详细:self
这里有个 super()
super(Net,self).__init__()
非常好用的继承。
接下来就是对于
self.conv1 = nn.Conv2d(1, 10, kernel_size=5)
nn.Conv2d()及参数的理解:
在这里,2维卷积和tf里的思路是一样的,tf 2维卷积有个文章理解的比较详细:Conv2d
pytorch有一篇文章:Conv2d
有个
x.view(-1, 320)
后面还有一个
target.view_as(pred)
与reshape操作是一样的,将其变换成为指定的形状。
def train(args, model, device, train_loader, optimizer, epoch):
model.train() # When using PyTorch for training and testing, be sure to specify the train/eval for the instantiated model.
for batch_idx, (data, target) in enumerate(train_loader):
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 % args.log_interval == 0:
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss:{:.6f}'.format(
epoch, batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx / len(train_loader), loss.item()))
def test(args, model, device, test_loader):
model.eval()
test_loss = 0
correct = 0
with torch.no_grad():
for data, target in test_loader:
data, target = data.to(device), target.to(device)
output = model(data)
test_loss += F.nll_loss(output, target, reduction='sum').item() #sum up batch loss
pred = output.max(1,keepdim=True)[1]# get the index of the max log-probability
correct += pred.eq(target.view_as(pred)).sum().item()
test_loss /= len(test_loader.dataset)
print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
test_loss, correct, len(test_loader.dataset),
100. * correct / len(test_loader.dataset)))
optimizer.zero_grad() 是指将梯度清零
optimizer.step()是指更新全部的参数
其中在定义train()\test()时,要特别注意,使用PyTorch进行训练和测试时一定注意要把实例化的model指定train/eval
model.train()/model.eval()
对于在搭建网络中的问题,会看到在搭网络的时候需要搭一个 forward()前传,但是反传就不需要再搭了,直接使用即可。这是因为
在pytorch中只需要定义
forward
函数即可, 反向传播backward
的部分在你使用autograd
时会自动生成.在
forward
函数中可以对Tensor进行任何操作.一个模块可学习的参数都在
net.parameters
中
理解 backward()
我用的笔记本跑的,将batch_size调整到了4,原先是64,结果如图:
MNIIST识别效果非常好,因为minist几乎是线性可分的。
来自科大佬举例:
K:只是说几乎线性可分,我打个比方,我甚至可以用某个点有没有黑色来区分某两类,
S:但是线性可分 对于10类图片来说, 我怎么能可视化的理解呢
K:线性可分意味着一个超平面能把它分开,可视化嘛,也许可以降到三维来可视化
S:一个超平面分开10类吗还是 一个分开两类 要好几个分开10类
K:一个分开两类~
S:我其实是想知道 他为啥好分
K:几乎线性,我的意思是超平面也会分错,所以SVM才会有个惩罚系数
欸。。。 所以为什么好分呢