到目前为止,我们就下载好了MNIST数据集:
(1)train_dataset:训练集,共10000个数据样本;
(2)test_dataset:测试集,共10000个数据样本;
前5000个样本为验证集,后5000个为测试集,
import torch
import torch.nn as nn
import torch.nn.functional as F
# torchvision 包收录了若干重要的公开数据集、网络模型和计算机视觉中的常用图像变换
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np
# 超参数设置(即全局数据,参数:可变,用于训练中的权重)
num_epochs = 5 # 全数据集为5
num_classes = 10 # 总共分为10个类
batch_size = 64 # 批处理大小为64个样本
image_size = 28 # 图像的总尺寸28*28
learning_rate = 0.0001 # 学习率为0.001
# 下载训练集
train_dataset = torchvision.datasets.MNIST(root= './data',train=True,transform=transforms.ToTensor(),download=True)
# 下载测试集
test_dataset = torchvision.datasets.MNIST(root='./data',train=False,transform=transforms.ToTensor(),download=True)
# 训练数据集的加载器,自动将数据分割成batch,顺序随机打乱
train_loader = torch.utils.data.DataLoader(dataset=train_dataset,batch_size=batch_size,shuffle=True)
"""
接下来把测试数据中的前5000个样本作为验证集,后5000个样本作为测试集
"""
indices = range(len(test_dataset))
indices_val = indices[:5000] # indices_val = 0:4999
indices_test = indices[5000:] # indices_test = 5000:9999
# 通过下标对验证集和测试集进行采样
sampler_val = torch.utils.data.sampler.SubsetRandomSampler(indices_val)
sampler_test = torch.utils.data.sampler.SubsetRandomSampler(indices_test)
# 根据采样器来定义加载器,然后加载数据
# 根据采样的验证集sample_val 加载验证集
validation_loader = torch.utils.data.DataLoader(dataset =test_dataset,batch_size = batch_size,sampler = sampler_val)
# 根据采样的测试集sample_test 加载测试集
test_loader = torch.utils.data.DataLoader(dataset=test_dataset,batch_size=batch_size,sampler = sampler_test)
#从数据集中读入一张图片,并绘制出来
idx = 8000
#dataset支持下标索引,其中提取出来的每一个元素为features,target格式,即属性和标签。[0]表示索引features
muteimg = train_dataset[idx][0].numpy()
#由于一般的图像包含rgb三个通道,而MINST数据集的图像都是灰度的,只有一个通道。因此,我们忽略通道,把图像看作一个灰度矩阵。
#用imshow画图,会将灰度矩阵自动展现为彩色,不同灰度对应不同颜色:从黄到紫
plt.imshow(muteimg[0,...])
print('标签是:',train_dataset[idx][1])
目前,我们把训练集:train_loader,验证集:validataion_loader、测试集:test_loader都加载到了内存中;
(1)卷积层 (可以不止一个)
(2)池化层
(3)全连接层
1)一个权重,【3】 :能够扩大差异,使得差异更明显
2)两个权重,【1,0.3】左边仍旧保留,因为权重值高;右边因为略低的权重,有些丢失。
1)特定信息过滤器
权值矩阵在图像里表现的像一个从原始图像矩阵中提取特定信息的过滤器。
2)矩阵用途
一个权值组合可能用来提取边缘(edge)信息,另一个可能是用来提取一个特定颜色,下一个就可能就是对不需要的噪点进行模糊化。
3)权值矩阵学习方法:
A 先对权值进行学习,然后损失函数可以被最小化,类似于多层感知机(MLP)。
B 因此需要通过对参数进行学习来从原始图像中提取信息,从而来帮助网络进行正确的预测。
C 当我们有多个卷积层的时候,初始层往往提取较多的一般特征,随着网络结构变得更深,权值矩阵提取的特征越来越复杂,并且越来越适用于眼前的问题。
1)步长小,能够共享更多像素点
1)我们可以看见在我们给图像填加一层 0 边界后,图像的原始形状是如何被保持的。
2)由于输出图像和输入图像是大小相同的,所以这被称为 same padding。
same padding(意味着我们仅考虑输入图像的有效像素)。
3)中间的 4*4 像素是相同的。这里我们已经利用边界保留了更多信息,并且也已经保留了图像的原大小。
4)小技巧:
卷积核:3 * 3 padding = 1
卷积核:5 * 5 padding = 2 可以使得图像保持原来大小
import torch.nn as nn
conv1 = nn.Conv2d()
conv2 = nn.Conv2d()
最大池化层
pool = nn.MaxPool2d()
线性池化层
fc1 = nn.Linear()
fc2 = nn.Linear()
fc3 = nn.Linear()```
思考:
Conv1d:自然语言处理
Conv2d:图像处理
图像处理:X,Y,RGB(3) 3通道,X,Y负责定位;建立在二维平面上的3维特征
那么对于输入的股票数据呢?X是时间;建立在一维坐标轴上的多维特征;
#定义两个卷积层的厚度(feature map的数量)
depth = [4, 8]
class ConvNet(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(1,4,5,padding=2) # 1 input channel, 4 output channels, 5x5 square convolution kernel
self.pool = nn.MaxPool2d(2, 2) #定义一个Pooling层
self.conv2 = nn.Conv2d(depth[0],depth[1],5, padding = 2) #第二层卷积:4input channel, 8 output channels, 5x5 square convolution kernel
self.fc1 = nn.Linear( depth[1] * image_size // 4 * image_size // 4 , 512) #线性连接层的输入尺寸为最后一层立方体的平铺,输出层512个节点
self.fc2 = nn.Linear(512, num_classes) #最后一层线性分类单元,输入为512,输出为要做分类的类别数
def forward(self, x):
# x尺寸:(batch_size, image_channels, image_width, image_height)
x = F.relu(self.conv1(x)) #第一层卷积的激活函数用ReLu
x = self.pool(x) #第二层pooling,将片变小
#x的尺寸:(batch_size, depth[0], image_width/2, image_height/2)
x = F.relu(self.conv2(x)) #第三层卷积,输入输出通道分别为depth[0]=4, depth[1]=8
x = self.pool(x) #第四层pooling,将图片缩小到原大小的1/4
#x的尺寸:(batch_size, depth[1], image_width/4, image_height/4)
# view函数将张量x变形成一维的向量形式,总特征数batch_size * (image_size//4)^2*depth[1]不改变,为接下来的全连接作准备。
x = x.view(-1, image_size // 4 * image_size // 4 * depth[1])
#x的尺寸:(batch_size, depth[1]*image_width/4*image_height/4)
x = F.relu(self.fc1(x)) #第五层为全链接,ReLu激活函数
#x的尺寸:(batch_size, 512)
x = F.dropout(x, training=self.training) #以默认为0.5的概率对这一层进行dropout操作,为了防止过拟合
x = self.fc2(x)
#x的尺寸:(batch_size, num_classes)
x = F.log_softmax(x, dim = 0) #输出层为log_softmax,即概率对数值log(p(x))。采用log_softmax可以使得后面的交叉熵计算更快
return x
def retrieve_features(self, x):
#该函数专门用于提取卷积神经网络的特征图的功能,返回feature_map1, feature_map2为前两层卷积层的特征图
feature_map1 = F.relu(self.conv1(x)) #完成第一层卷积
x = self.pool(feature_map1) # 完成第一层pooling
print('type(feature_map1)=',feature_map1)
feature_map2 = F.relu(self.conv2(x)) #第二层卷积,两层特征图都存储到了feature_map1, feature_map2中
return (feature_map1, feature_map2)
"""计算预测正确率的函数,其中predictions是模型给出的一组预测结果,batch_size行num_classes列的矩阵,labels是数据之中的正确答案"""
def accuracy(predictions, labels):
# torch.max的输出:out (tuple, optional维度) – the result tuple of two output tensors (max, max_indices)
pred = torch.max(predictions.data, 1)[1] # 对于任意一行(一个样本)的输出值的第1个维度,求最大,得到每一行的最大元素的下标
right_num = pred.eq(labels.data.view_as(pred)).sum() #将下标与labels中包含的类别进行比较,并累计得到比较正确的数量
return right_num, len(labels) #返回正确的数量和这一次一共比较了多少元素
"""计算预测正确率的函数,其中predictions是模型给出的一组预测结果,batch_size行num_classes列的矩阵,labels是数据之中的正确答案"""
def accuracy(predictions, labels):
# torch.max的输出:out (tuple, optional维度) – the result tuple of two output tensors (max, max_indices)
pred = torch.max(predictions.data, 1)[1] # 对于任意一行(一个样本)的输出值的第1个维度,求最大,得到每一行的最大元素的下标
right_num = pred.eq(labels.data.view_as(pred)).sum() #将下标与labels中包含的类别进行比较,并累计得到比较正确的数量
return right_num, len(labels) #返回正确的数量和这一次一共比较了多少元素
net = ConvNet()
criterion = nn.CrossEntropyLoss() #Loss函数的定义,交叉熵
optimizer = torch.optim.SGD(net.parameters(), lr=0.001, momentum=0.9) #定义优化器,普通的随机梯度下降算法
record = [] #记录准确率等数值的list
weights = [] #每若干步就记录一次卷积核
for epoch in range(num_epochs):
train_accuracy = [] #记录训练数据集准确率的容器
# 一次迭代一个batch的 data 和 target
for batch_id, (data,target) in enumerate(train_loader):
net.train() # 给网络模型做标记,标志说模型正在训练集上训练,这种区分主要是为了打开关闭net的training标志,从而决定是否运行dropout
output = net(data) #forward
loss = criterion(output, target)
optimizer.zero_grad()
loss.backward()
optimizer.step()
accuracies = accuracy(output, target)
train_accuracy.append(accuracies)
if batch_id%100 ==0: #每间隔100个batch执行一次打印等操作
net.eval() # 给网络模型做标记,将模型转换为测试模式。
val_accuracy = [] #记录校验数据集准确率的容器
for (data, target) in validation_loader: #计算校验集上面的准确度
output = net(data) #完成一次前馈计算过程,得到目前训练得到的模型net在校验数据集上的表现
accuracies = accuracy(output, target) #计算准确率所需数值,返回正确的数值为(正确样例数,总样本数)
val_accuracy.append(accuracies)
# 分别计算在已经计算过的训练集,以及全部校验集上模型的分类准确率
#train_r为一个二元组,分别记录目前 已经经历过的所有 训练集中分类正确的数量和该集合中总的样本数,
train_r = (sum([tup[0] for tup in train_accuracy]), sum([tup[1] for tup in train_accuracy]))
#val_r为一个二元组,分别记录校验集中分类正确的数量和该集合中总的样本数
val_r = (sum([tup[0] for tup in val_accuracy]), sum([tup[1] for tup in val_accuracy]))
#打印准确率等数值,其中正确率为本训练周期Epoch开始后到目前batch的正确率的平均值
print('Epoch [{}/{}] [{}/{} ({:.0f}%)]\tLoss: {:.6f}\t训练正确率: {:.2f}%\t校验正确率: {:.2f}%'.format(
epoch+1,num_epochs, batch_id * batch_size, len(train_loader.dataset),
100. * batch_id / len(train_loader), loss.item(),
100. * train_r[0] / train_r[1],
100. * val_r[0] / val_r[1]))
runfile('H:/PyTorch/third.py', wdir='H:/PyTorch')
Epoch [1/5] [0/60000 (0%)] Loss: 2.306378 训练正确率: 7.81% 校验正确率: 9.36%
Epoch [1/5] [6400/60000 (11%)] Loss: 2.300146 训练正确率: 11.31% 校验正确率: 19.66%
Epoch [1/5] [12800/60000 (21%)] Loss: 2.288543 训练正确率: 13.09% 校验正确率: 34.32%
Epoch [1/5] [19200/60000 (32%)] Loss: 2.281700 训练正确率: 15.63% 校验正确率: 46.72%
Epoch [1/5] [25600/60000 (43%)] Loss: 2.241495 训练正确率: 18.23% 校验正确率: 55.34%
Epoch [1/5] [32000/60000 (53%)] Loss: 2.075073 训练正确率: 21.54% 校验正确率: 58.20%
Epoch [1/5] [38400/60000 (64%)] Loss: 1.332497 训练正确率: 25.47% 校验正确率: 67.48%
Epoch [1/5] [44800/60000 (75%)] Loss: 1.240580 训练正确率: 30.79% 校验正确率: 72.86%
Epoch [1/5] [51200/60000 (85%)] Loss: 0.692732 训练正确率: 35.94% 校验正确率: 78.48%
Epoch [1/5] [57600/60000 (96%)] Loss: 0.681386 训练正确率: 40.42% 校验正确率: 80.82%
Epoch [2/5] [0/60000 (0%)] Loss: 0.595346 训练正确率: 78.12% 校验正确率: 81.04%
Epoch [2/5] [6400/60000 (11%)] Loss: 0.473438 训练正确率: 79.21% 校验正确率: 82.86%
Epoch [2/5] [12800/60000 (21%)] Loss: 0.469020 训练正确率: 80.09% 校验正确率: 84.18%
Epoch [2/5] [19200/60000 (32%)] Loss: 0.482854 训练正确率: 81.05% 校验正确率: 84.90%
Epoch [2/5] [25600/60000 (43%)] Loss: 0.582667 训练正确率: 81.57% 校验正确率: 85.98%
Epoch [2/5] [32000/60000 (53%)] Loss: 0.465008 训练正确率: 82.28% 校验正确率: 86.84%
Epoch [2/5] [38400/60000 (64%)] Loss: 0.256229 训练正确率: 82.73% 校验正确率: 87.60%
Epoch [2/5] [44800/60000 (75%)] Loss: 0.383545 训练正确率: 83.40% 校验正确率: 88.04%
Epoch [2/5] [51200/60000 (85%)] Loss: 0.283119 训练正确率: 83.83% 校验正确率: 89.38%
Epoch [2/5] [57600/60000 (96%)] Loss: 0.403816 训练正确率: 84.30% 校验正确率: 89.72%
Epoch [3/5] [0/60000 (0%)] Loss: 0.384087 训练正确率: 90.62% 校验正确率: 89.68%
Epoch [3/5] [6400/60000 (11%)] Loss: 0.294257 训练正确率: 88.20% 校验正确率: 90.48%
Epoch [3/5] [12800/60000 (21%)] Loss: 0.520744 训练正确率: 88.75% 校验正确率: 90.84%
Epoch [3/5] [19200/60000 (32%)] Loss: 0.187293 训练正确率: 89.21% 校验正确率: 91.70%
Epoch [3/5] [25600/60000 (43%)] Loss: 0.149348 训练正确率: 89.35% 校验正确率: 91.64%
Epoch [3/5] [32000/60000 (53%)] Loss: 0.177097 训练正确率: 89.63% 校验正确率: 91.52%
Epoch [3/5] [38400/60000 (64%)] Loss: 0.283381 训练正确率: 89.85% 校验正确率: 92.32%
Epoch [3/5] [44800/60000 (75%)] Loss: 0.221938 训练正确率: 90.11% 校验正确率: 92.42%
Epoch [3/5] [51200/60000 (85%)] Loss: 0.168308 训练正确率: 90.35% 校验正确率: 93.24%
Epoch [3/5] [57600/60000 (96%)] Loss: 0.329505 训练正确率: 90.54% 校验正确率: 93.10%
Epoch [4/5] [0/60000 (0%)] Loss: 0.188860 训练正确率: 93.75% 校验正确率: 93.12%
Epoch [4/5] [6400/60000 (11%)] Loss: 0.150691 训练正确率: 92.30% 校验正确率: 93.04%
Epoch [4/5] [12800/60000 (21%)] Loss: 0.384889 训练正确率: 92.67% 校验正确率: 93.38%
Epoch [4/5] [19200/60000 (32%)] Loss: 0.117718 训练正确率: 92.86% 校验正确率: 93.68%
Epoch [4/5] [25600/60000 (43%)] Loss: 0.162536 训练正确率: 92.83% 校验正确率: 93.70%
Epoch [4/5] [32000/60000 (53%)] Loss: 0.140568 训练正确率: 92.98% 校验正确率: 94.08%
Epoch [4/5] [38400/60000 (64%)] Loss: 0.088605 训练正确率: 92.99% 校验正确率: 94.06%
Epoch [4/5] [44800/60000 (75%)] Loss: 0.287696 训练正确率: 93.13% 校验正确率: 94.14%
Epoch [4/5] [51200/60000 (85%)] Loss: 0.159704 训练正确率: 93.14% 校验正确率: 94.50%
Epoch [4/5] [57600/60000 (96%)] Loss: 0.298342 训练正确率: 93.20% 校验正确率: 94.58%
Epoch [5/5] [0/60000 (0%)] Loss: 0.061918 训练正确率: 98.44% 校验正确率: 94.26%
Epoch [5/5] [6400/60000 (11%)] Loss: 0.230948 训练正确率: 94.35% 校验正确率: 94.72%
Epoch [5/5] [12800/60000 (21%)] Loss: 0.057776 训练正确率: 94.08% 校验正确率: 94.74%
Epoch [5/5] [19200/60000 (32%)] Loss: 0.166323 训练正确率: 94.08% 校验正确率: 94.76%
Epoch [5/5] [25600/60000 (43%)] Loss: 0.310377 训练正确率: 94.10% 校验正确率: 94.84%
Epoch [5/5] [32000/60000 (53%)] Loss: 0.246734 训练正确率: 94.24% 校验正确率: 94.92%
Epoch [5/5] [38400/60000 (64%)] Loss: 0.085995 训练正确率: 94.30% 校验正确率: 94.56%
Epoch [5/5] [44800/60000 (75%)] Loss: 0.109112 训练正确率: 94.32% 校验正确率: 94.92%
Epoch [5/5] [51200/60000 (85%)] Loss: 0.112068 训练正确率: 94.36% 校验正确率: 95.22%
Epoch [5/5] [57600/60000 (96%)] Loss: 0.131915 训练正确率: 94.37% 校验正确率: 95.40%
(1)选取适中的batch_size,当然可以,这就是批梯度下降法(Mini-batches Learning)。因为如果数据集足够充分,那么用一半(甚至少得多)的数据训练算出来的梯度与用全部数据训练出来的梯度是几乎一样的。
(2)作用:用来解决数据量比较小,而准确率需要比较高的情形
(1)元素为【features,target】格式,即属性和标签,[0]表示属性features,[1]表示标签
idx=0 # 下标0,第0张图片
muteimg = train_dataset[idx][0].numpy # 第0张图片的第一个元素:属性,进行格式转换,便于输出图形
plt.imshow(muteing[0,...])
print('标签是:',train_dataset[idx][1]) # 第0张图片的第二个元素:标签
(1)# 训练数据集的加载器,自动将数据分割成batch,顺序随机打乱
train_loader =
torch.utils.data.DataLoader(dataset=train_dataset,
batch_size=batch_size,shuffle=True)
(1)在实际应用中,数据并不一定是循规蹈矩的序惯访问,而需要随机打乱顺序来访问,或需要随机加权访问,
因此,按某种特定的规则来读取数据,就是采样操作,需要定义采样器:Sampler。
(2)另外,数据也可能并不是一个一个读取的,而需要一批一批的读取,即需要批量采样操作,定义批量采样器:BatchSampler。
(3) BatchSample = Sample +Batch_Size (相当于基址+偏移量)
(4)原来随机一次性读取一个Sample,后面随机一次性读取Batch_Size个Sample。
(1)Conv2d(1,4,5,padding=2)
input channel = 1;输入的数据通道数是1,灰度图像,
output channel = 4,输出的数据通道数是4,即深度为4,等于4个卷积核。
square convulution kernel = 5;卷积矩阵=5*5;
padding = 2;外层填充两层0;
(2)
(1) PyTorch1.0 在MNIST数据集上实现卷积神经网络
(2)谈谈深度学习中的 Batch_Size
(3)Pytorch数据读取详解
1. 关于三通道彩色图像的存储方式理解
# 超参数设置
image_size = 28
batch_size = 64 # 将 batch_size = 640 训练速度急剧下降
num_classes = 10
depth = [4,8]
class ConvNet(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(1,4,5,padding=2) # 1 input channel, 4 output channels,5*5 square convolution kernel
# 1个输入通道 4个输出通道 5-5的平方卷积核
# 1 是因为灰度为 1 5*5的卷积核 配上padding = 2,图像大小不变
# 第一层卷积的结果 :
# 原先总特征数:batch_size * depth = 1 *image_weight * image_height
# 即 64 * 1 * 28 * 28
# 第一层卷积后:batch_size * depth = 4 * image_weight * image_height
# 即 64 * 4 * 28 * 28 总特征数变成了原来的4倍
self.pool = nn.MaxPool2d(2,2) # 定义一个Pooling层 14*14*4
# 第二层池化的结果:
# 第二层池化:batch_size * depth = 4 * image_weight / 2 * image_height /2
# 即:64 * 1 * 28 * 28 总特征数保持不变
self.conv2 = nn.Conv2d(depth[0],depth[1],5,padding=2) # 第二层卷积:4 input channel,8 output channels, 5*5 squares convolution kernel
# 第三层卷积结果:
# batch_size * depth[1] = 8 * image_weight/2 * image_height/2 为原来总特征数的两倍
# 这里似乎只考虑了深度,没有考虑图片大小? 14*14*8
self.fc1 = nn.Linear(depth[1]*image_size//4*image_size//4,512) # 线性连接层的输入尺寸为最后一层立方体的平铺,输出层为512个节点
# 8*8*8=512 立方体平铺成512个节点,然后512分类成num_classes
self.fc2 = nn.Linear(512,num_classes) # 最后一层线性分类单元,输入为512,输出为要做分类的类别数
# 最后一层要回归到分类树当中,是因为有两个卷积层,所以要有两个激活函数吗?
"""
若要保持总特征数不变,是否应该使得depth[1] = 16 呢?
在fc1当中,如果最后输出的立方体的总特征数并不等于512,这个数字是怎么得来的呢?
"""
beta 1.0 # 1.0 版本
epochs = 5 # 总训练批次
batch_size = 64 #
> https://blog.csdn.net/qq_36589234/article/details/89259744
beta 2.0 # 2.0 版本
epochs = 20 # 总训练批次
batch_size = 512 # 大概需要2G显存
>https://blog.csdn.net/wsp_1138886114/article/details/86633056
>>>seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
>>> list(enumerate(seasons, start=1)) # 下标从 1 开始
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
beta 1 # 版本1
self.fc1 = nn.Linear()
self.fc2 = nn.Linear()
beata 2 # 版本2
self.fc1 = nn.Linear()
self.fc2 = nn.Linear()