28x28
像素点,可以用一个数组来描述,这个数组可以张成一个向量,长度为784,保证每张照片以相同方式展开。从这个角度看,就是784维向量空间的点,然后可以进行比较。import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
BATCH_SIZE = 523 # batch_size即每批训练的样本数量
epochs = 20 # 循环次数
DEVICE=torch.device("cuda" if torch.cuda.is_available() else "cpu") #判断是否能在GPU上进行运算
train_loader = torch.utils.data.DataLoader( # vision.utils : 用于把形似 (3 x H x W) 的张量保存到硬盘中,给一个mini-batch的图像可以产生一个图像格网。
datasets.MNIST('data', train=True, download=True,
transform=transforms.Compose([
transforms.ToTensor(), # 图像转化为Tensor
transforms.Normalize((0.1307,), (0.3081,)) # 标准化
])),
batch_size=BATCH_SIZE, shuffle=True) # shuffle() 方法将序列的所有元素随机排序
torchvision.dataset
作用是下载数据集,第一次调用时会自动从网上获取数据,
torch.utils.data.DataLoader()
利用下载的数据集来创建一个读取小批量数据样本的DataLoader实例
test_loader = torch.utils.data.DataLoader(
datasets.MNIST('data', train=False, transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])),
batch_size=BATCH_SIZE, shuffle=True) # shuffle() 方法将序列的所有元素随机排序
三个个卷积层
,以及两个全连接层
,在卷积层以及全连接层之间分别设置了激活函数
,池化函数
分别试验他们各自作用view()
函数,-1是根据输入数据自动设定class Net(nn.Module): # 继承model
def __init__(self):
super().__init__()
# 28x28
self.conv1=nn.Conv2d(1,12,5) # 12, 24x24
self.conv2=nn.Conv2d(12, 20,3) #20, 10x10
self.conv3=nn.Conv2d(20, 40,3) #20, 10x10
self.batchnorm2d = nn.BatchNorm2d(40)
self.fc1=nn.Linear(40*8*8, 500)
self.fc2=nn.Linear(500, 10)
def forward(self, x): #网络传播结构
in_size=x.size(0)# in_size 为 batch_size(一个batch中的Sample数)
# 卷积层 -> relu -> 最大池化
out = self.conv1(x) # 24
out = F.relu(out)
out = F.max_pool2d(out, 2, 2) # 12
out = self.conv2(out) # 10
out = F.relu(out)
out = self.conv3(out)
out = F.relu(out)
out = self.batchnorm2d(out)
out = out.view(in_size, -1) # view()函数作用是将一个多行的Tensor,拼接成行。
# 输出前的预处理
out = self.fc1(out)
out = F.relu(out)
out = self.fc2(out)
# softmax
out = F.log_softmax(out, dim=1)
# 返回值 out
return out
model = Net().to(DEVICE)
optimizer = optim.Adam(model.parameters())
torch.functional.nll_loss
,后面讨论环节也会分析不同loss函数的结果差异with torch.no_grad()
表示不反向求导。训练过程需要反向求导(去更新优化模型参数),测试过程不需要反向求导。简洁
方式将结果输出def train(model, device, train_loader, optimizer, epoch):
model.eval()
for epoch_i in range(epoch+1):
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data, target # CPU转GPU
optimizer.zero_grad() # 优化器清零
output = model(data) # 由model,计算输出值
loss = F.nll_loss(output, target) # 计算损失函数loss
loss.backward() # loss反向传播
optimizer.step() # 优化器优化
if(batch_idx+1)%30 == 0: # 输出结果
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch_i, batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx / len(train_loader), loss.item()))
def test(model, device, test_loader):
test_loss = 0 # 损失函数初始化为0
correct = 0 # correct 计数分类正确的数目
with torch.no_grad():
for data, target in test_loader: # 遍历所有的data和target
data, target = data.to(device), target.to(device) # CPU -> GPU
output = model(data) # output为预测值,由model计算出
test_loss += F.nll_loss(output, target, reduction='sum').item() ### 将一批的损失相加
pred = output.max(1, keepdim=True)[1] ### 找到概率最大的下标
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)))
train(model, DEVICE, train_loader, optimizer, epoch)
test(model, DEVICE, test_loader)
class Net(nn.Module): # 继承model
def __init__(self):
super().__init__()
# 28x28
self.conv1=nn.Conv2d(1,12,5)
self.conv2=nn.Conv2d(12, 20,3)
self.fc1=nn.Linear(20*10*10, 500)
self.fc2=nn.Linear(500, 10)
def forward(self, x): #网络传播结构
# 卷积层 -> relu -> 最大池化
out = self.conv1(x) # 24
out = F.relu(out)
out = F.max_pool2d(out, 2, 2) # 12
out = self.conv2(out) # 10
out = F.relu(out)
out = out.view(in_size=x.size(0), -1) # view()函数作用是将一个多行的Tensor,拼接成行。
# 输出前的预处理结束,提取完特征信息
out = self.fc1(out)
out = F.relu(out)
out = self.fc2(out)
# softmax
out = F.log_softmax(out, dim=1)
# 返回值 out
return out
Test set: Average loss: 0.0363, Accuracy: 9889/10000 (99%)
class Net(nn.Module): # 继承model
def __init__(self):
super().__init__()
# 28x28
self.conv1=nn.Conv2d(1,12,5) # 12, 24x24
self.conv2=nn.Conv2d(12, 20,3) #20, 10x10
self.conv3=nn.Conv2d(20, 40,3) #20, 10x10
self.batchnorm2d = nn.BatchNorm2d(40)
self.fc1=nn.Linear(40*8*8, 500)
self.fc2=nn.Linear(500, 10)
def forward(self, x): #网络传播结构
in_size=x.size(0)# in_size 为 batch_size(一个batch中的Sample数)
# 卷积层 -> relu -> 最大池化
out = self.conv1(x) # 24
out = F.relu(out)
out = F.max_pool2d(out, 2, 2) # 12
out = self.conv2(out) # 10
out = F.relu(out)
out = self.conv3(out)
out = F.relu(out)
out = self.batchnorm2d(out)
out = out.view(in_size, -1) # view()函数作用是将一个多行的Tensor,拼接成行。
# 输出前的预处理
out = self.fc1(out)
out = F.relu(out)
out = self.fc2(out)
# softmax
out = F.log_softmax(out, dim=1)
# 返回值 out
return out
Test set: Average loss: 0.0296, Accuracy: 9898/10000 (99%)
self.conv1=nn.Conv2d(1,10,5) # 改变输出通道10,11,12,13,14
self.conv2=nn.Conv2d(10, 20,3) #对应上一层输出通道
self.fc1=nn.Linear(20*10*10, 500)
self.fc2=nn.Linear(500, 10)
sigmoid()
都改成使用F.relu
(和nn.relu产不多),AlexNet相对于LeNet有一改变就是使用了relu函数,使用了relu克服sigmoid在反向求导时,导数不可算的情况过拟合
。池化层的存在,会不断提取一定范围内最强烈的特征,并且缩小张量的大小,使得大范围内的特征组合也能够捕捉到,pooling的结果是使得特征减少,参数减少,但pooling的目的并不仅在于此。pooling目的是为了保持某种不变性(旋转、平移、伸缩等),常用的有mean-pooling,max-pooling和Stochastic-pooling三种,该文建立的网络中采取的是最大池化
减小第一种误差
,更多的保留图像的背景信息;减小第二种误差
,更多的保留纹理信息;介于两者之间
,通过对像素点按照数值大小赋予概率,再按照概率进行亚采样,在平均意义上,与mean-pooling近似,在局部意义上,则服从max-pooling的准则。torch.functional.null_loss
,