神经网络建模流程梳理

1. 导入所需要的库

2. 设置步长(学习率)lr,设置动量参数gamma,设置迭代次数epochs,设置批量大小

bs,如果后续需要,可以设置初始权重w_{0}

3. 导入数据,将数据切分成batchs

4. 定义神经网络架构

5. 定义损失函数L(w)

6. 定义优化算法(直接内置在训练函数中)

7. 开始在epoch和batch上循环,执行优化算法:

        7.1 调整数据结构,确定数据能够在神经网络、损失函数和优化算法中顺利运行

        7.2 完成向前传播,计算初始损失

        7.3 反向传播,获取梯度信息

        7.4 迭代当前权重

        7.5 清空本轮梯度

        7.6 完成模型进度与效果监控

8. 输出结果

导入所需要的库

import torch
from torch import nn       #构筑神经网络结构
from torch import optim    #优化算法模块
from torch.nn import functional as F    #神经网络的损失函数和激活函数
from torch.utils.data import DataLoader,TensorDataset      #神经网络的数据预处理
import torchvision           #导入计算机视觉相关的库
import torchvision.transforms as transforms

设置各种参数信息

lr = 0.5 #学习率,步长
gamma = 0.8   #动量参数
epochs = 5 迭代轮次
bs = 128   #每批量的数据量

导入数据集

mnist = torchvision.datasets.FashionMNIST(
    root = r"Lesson 11\MINST-FASHION数据集"    #你自己存放数据集的目录
    ,download = False
    ,train = True
    ,transform = transforms.ToTensor()     #将数据转化成tensor结构
)         #实例化数据

查看数据量:

len(mnist)
#返回60000

查看特征张量:

mnist.data

查看标签以及类别:

mnist.targets
#返回:tensor([9, 0, 0,  ..., 3, 0, 5])
mnist.classes
#返回:
['T-shirt/top',
 'Trouser',
 'Pullover',
 'Dress',
 'Coat',
 'Sandal',
 'Shirt',
 'Sneaker',
 'Bag',
 'Ankle boot']

查看图像模样:

import matplotlib.pyplot as plt
import numpy as np
import os
os.environ['KMP_DUPLICATE_LIB_OK']='True'
plt.imshow(mnist[0][0].view(28,28).numpy())   #左图
plt.imshow(mnist[1][0].view(28,28).numpy())   #右图

切割数据集操作:

batchdata = DataLoader(mnist
                        ,batch_size=bs
                        ,shuffle = True     #随机打乱数据
)#对mnist数据集进行分割,每个批次128个样本,共469个批次

查看数据集

for x,y in batchdata:
    print(x.shape)
    print(y.shape)
    break

第一行表示:每一个批量都是四维,大小是128个样本,每个样本的维度是[1,28,28],1是图像的通道数,值为1代表是灰度图像,[28,28]是图像的高度和宽度,即每个图像是28×28的像素尺寸。

第二行表示:批次中图像对应的标签张量,形状为一维张量,长度等于批次大小128,代表有128个标签。

len(batchdata)
#返回469,共469个批次,除最后一个批次外,都是128个样本

设置输入和输出:

#输入层维度
input_ = mnist.data[0].numel()  #计算第一个样本的总元素数量,即总像素数
input_
#返回784
#输出层维度
output_ = len(mnist.targets.unique())  #targets属性存储了所有样本的标签的张量格式
output_
#返回10

定义神经网络架构

class Model(nn.Module):
    def __init__(self,in_features = 10, out_features = 2):
        super().__init__()
        self.linear1 = nn.Linear(in_features,128,bias=False)
        self.output = nn.Linear(128,out_features,bias=False)

    def forward(self,x):
        x = x.view(-1,28*28)
        sigma1 = torch.relu(self.linear1(x))
        sigma2 = F.log_softmax(self.output(sigma1),dim=1)
        return sigma2

view(-1,28*28)将张量x重塑形状,需要对数据结构进行改变,-1作为占位符,自动计算该位置的维度是多少,这里-1将x第一维度设置为128,因为有128个样本,每个样本展平为长度784的一维向量。全连接神经网络的输入需要是一维特征向量,而不是多维图像张量。

F.log_softmax()功能是先对输入应用softmax激活(将原始分数转换为和为1的概率分布),再对结果取自然对数,相比直接用softmax后再取对数,可以避免数值下溢,更稳定。

dim=1是在类别维度上应用操作,对于多分类softmax函数取最后概率,dim一般必须存在且恒取1

定义训练函数(难点)

def fit(net,batchdata,lr=0.01,epochs=5,gamma=0.9):
    criterion = nn.NLLLoss()    #定义损失函数,与前面的log_softmax函数配套使用
    opt = optim.SGD(net.parameters(),lr = lr,momentum = gamma)   #定义优化算法小批量梯度下降



    correct = 0 #循环开始前,设定预测正确的样本量为0
    samples = 0 #循环开始前,一个样本都没有使用过,统计已经使用了多少样本,用来监测完成度
    for epoch in range(epochs):   #在每个轮次里循环,共epochs个轮次
        for batch_idx,(x,y) in enumerate(batchdata):  #enumerate同时获取批次索引(batch_idx)和批次数据(样本x,标签y),方便追踪当前处理到第几个批次,共batchdata个轮次
            y = y.view(x.shape[0])    #降维,把标签形状调整为一维的形状,x.shape[0]是当前批次样本的数量,除最后一个批次,一般为128
            sigma = net.forward(x)    #正向传播,输出模型的预测结果,对数概率分布
            loss = criterion(sigma,y) #返回当前批次的平均损失
            loss.backward()           #反向传播,获得梯度信息,梯度存储在.grad属性中
            opt.step()                #根据反向传播计算出的梯度,按照SGD的规则更新模型所有参数
            opt.zero_grad()           #清空梯度,pytorch默认累积梯度,不清空会叠加梯度导致错误

            yhat = torch.max(sigma,dim = 1)[1]   #yhat取值为每个样本被预测的标签值(0-9)
                #torch.max函数返回一个两个元素的元组(每个样本在类别维度上的最大值,最大值所在的索引)
                #[1]取元组的第二个元素,即每个样本被预测的类别标签,赋值给yhat,yhat[i]就是第i个样本被预测为的数字(0-9其中一个)
            correct += torch.sum(yhat == y)
                #yhat==y主元素比较yaht与y,预测正确结果为True,pytorch自动转换为整数1,预测错误为0
                #用来标记每个样本是否预测正确
                #torch.sum()对上述(0、1张量)求和,得到预测样本正确的总数
            samples = samples + x.shape[0]        #每训练一个batch的数据,模型见过的数据就会增加128
            


            if(batch_idx + 1) % 125 == 0 or batch_idx == len(batchdata) - 1:
                #打印条件:每处理125个批次打印一次,以及在当前轮次的最后一个批次强制打印
                print("Epoch{}:[{}/{}({:.0f}%)]  Loss:{:.6f},Accuracy:{:.3f}".foramt(
                epoch+1          #第几个轮次,epoch索引从0开始
                ,samples         #已经查看过的数据
                ,epochs * len(batchdata.dataset)     #整个训练模型一共需要查看多少数据
                ,100 * samples / (epochs * len(batchdata.dataset))  #训练进度百分比
                ,loss.data.item()   #当前批次的损失值,保留6位小数
                ,float(100 * correct / samples)    #到目前为止累积的准确率,3位小数
)
)

模型训练和评估

定义随机数种子
torch.manual_seed(1412)
net = Model(in_features = input_,out_features = output_)   #实例化网络
fit(net,batchdata,lr=lr,epochs=epochs,gamma=gamma)        #执行训练函数

结果:

准确率越来越低,本次设置的参数并不是很好的参数,需要调参,调参后续会学习。

使用课件所给最佳参数:

#最佳参数
lr=0.15
gamma=0
epochs= 10
bs=128

更多推荐