这是使用spyder运行的代码,用的是anaconda环境,pytorch框架(数据集那些都已经在盘里面):
# 引入Pytorch,在Python中使用torch表示 import torch # 从torch中引入网络层 from torch import nn # 从torch中引入优化器(求解器) from torch import optim # 引入torchvision处理常用的数据集 from torchvision import datasets, transforms # 引入可视化工具visdom import visdom import numpy as np #################### ## 第1步 加载数据集 ## #################### # load dataset 加载数据集 # torch提供的数据加载函数 # 加载 datasets.MNIST 这个数据集 # 数据集存放路径为''D:/kaikeba___/data'(按照自己存放的路径,若路径下没有数据集,download=True会自动下载)' # train=True,是否开展训练:是 # 图片变换,transforms是torchvision提供的图片处理函数,包括放大,扰动等。此处要变换图片大小.Resize();改变图片数据格式为矢量.ToTensor(),因为图片加载后是标量numpy # 如果没有这个数据集,就载这个数据集download=True # batch_size可以理解为多线程,即一次加载128张图片 # shuffle=True,随机化,将图片打散 train_loader = torch.utils.data.DataLoader(datasets.MNIST('F:/ppppp/data', train=True, transform=transforms.Compose([ transforms.Resize( 28, 28), transforms.ToTensor(), ]), download=True), batch_size=128, shuffle=True ) # 将上面的train_loader复制粘贴下来,作为测试集test_loader。但也要做一些修改。 # 区分数据集是用于训练还是测试,从train = True/False可以判断 test_loader = torch.utils.data.DataLoader(datasets.MNIST('F:/ppppp/data', train=False, transform=transforms.Compose([ transforms.Resize( 28, 28), transforms.ToTensor(), ]), download=True), batch_size=128, shuffle=True ) # 为训练添加环境变量,之后程序产生的所有数据都会出现在这个环境变量中,visdom就可以监听数据实现可视化 # 而且在visdom中还可以按照环境变量名选择性监听,便于分类管理 viz = visdom.Visdom(env='mnist_train') ##################### ## 第2步 新建网络模型 ## (可以随时更改网络) ##################### # LeNet-5是一种用于手写体字符识别的非常高效的卷积神经网络。此处使用super()函数继承父类Lenet5 # 定义类Lenet5,Lenet5只需要定义好初始化__init__和foward函数 class Lenet5(nn.Module): def __init__(self): super(Lenet5, self).__init__() # 通过Squential构造网络模型:将网络层和激活函数结合起来,输出激活后的网络节点 self.model = nn.Sequential( # 第一层使用全连接层Linear,全连接层的输入与输出都是二维张量,一般形状为[batch_size, size],此处为[b, 784] nn.Linear(28 * 28, 512), # 每一层节点的输入与上层输出都具备某种函数关系,这里的ReLU()函数就是定义这个函数形式,称为“激活函数” nn.ReLU(), # 第二层 nn.Linear(512, 256), nn.ReLU(), # 第三层,输出为10个节点,对应0~9这10个数 nn.Linear(256, 10), # 每张图片经过运算后,最后一层10个节点的数值或大或小,此时再连接一个把一个Softmax层,将数值归一化为(0,1)之间且和为1的值 # nn.Softmax() # 查文档发现,CrossEntropyLoss()中已经包含Softmax()函数,所以此处无需重复使用,否则会导致算法不收敛 ) # forward定义程序怎样前向计算:上面定义了网络的结构,这里定义这个结构的使用方式 def forward(self, x): # 变换数据的维度:[b, 1, 28, 28] => [b, 784] x = x.view(x.size(0), 28 * 28) # [b,784] => [b,10] pred = self.model(x) return pred #################### ## 第3步 撰写主函数 ## #################### def main(): # 设置计算设备为GPU,如果不做此修改,默认的计算设备为CPU,速度会很慢。使用GPU加速的前提是先安装好GPU驱动,CUDA,Anoconda device = torch.device('cpu') # x:images,[128,1,28,28],图片有128张,每张尺寸都是28x28,由于是黑白二值化图片,所以色彩维度为1。如果是彩色RGB图片,这里就是3。 # label:图片标签,就是每张图片到底是什么数字,都以标签的形式赋予其属性 x, label = iter(train_loader).next() print(x.shape, label.shape) # print('x:', x) # print('label:', label) # 定义一个评价函数criteon,它是损失函数定义的拟合结果和真实结果之间的差异,作为优化的目标 criteon = nn.CrossEntropyLoss().to(device) model = Lenet5().to(device) # 定义一个优化器SGD(Stochastic Gradient Descent 随机梯度下降法) optimizer = optim.SGD(model.parameters(), lr=1e-3) # 0.001 # 全局运行步数 global_step = 0 # 创建线图初始点。loss是差值图,acc是精度图 viz.line(np.array([0]), np.array([0]), win='loss', opts=dict(title='loss')) viz.line(np.array([0]), np.array([0]), win='acc', opts=dict(title='acc')) # 数据集跑100遍 for epoch in range(100): # enumerate函数用于在循环中得到计数,利用它可以同时获得索引、步数和值 # x是每张图片的数据,label是图片的标签属性 for step, (x, label) in enumerate(train_loader): x, label = x.to(device), label.to(device) # 将x值送到模型中,[b, 1, 28, 28] => [b, 10] pred = model(x) # pred是一张图片分别为0~9的概率,形式为[0.1, 0.8, 0.05, ......] # 我们希望预测值pred与这张图片的标签label越接近越好,此处使用loss变量得到二者的相差量 loss = criteon(pred, label) # 先将梯度值清零 optimizer.zero_grad() # 相差量loss使用backward计算出梯度gradient loss.backward() # 使用梯度值gradient更新模型参数,或者说函数各系数的权重 # a = a - lr * grad_a optimizer.step() # 更新全局步数 global_step += 1 if global_step % 20 == 0: # 数据变化,点与点用线line连接 viz.line(np.array([loss.item()]),np.array([global_step]), win='loss', update='append') # 为测试添加可视化显示代码 # images是显示参与测试的图片 # 前两个值是纵,横坐标 # nrow一行显示数量,win窗口名字,opts指定参数,title标题 viz.images(x, nrow=16, win='input', opts=dict(title='input x')) # 使用测试集测试训练精度 if epoch % 5 == 0: # 定义变量,total_correct是预测对的次数,total_num是预测的次数 total_correct = 0 total_num = 0 for x, label in test_loader: x, label = x.to(device), label.to(device) # pred 是模型输出结果,[b, 1, 28, 28] => [b, 10] pred = model(x) # 从pred中取出概率最大值的位置,比如[b, 10]这是个数中概率最大值在第0号位置,那这张图片是手写0的概率相应也是最大,此时返回0 # argmax()函数就是返回概率最大值的位置。dim表示计算的维度 pred = pred.argmax(dim=1) # 将预测的结果pred与正确值label做eq比较操作,相等则返回1,不等则返回0。同时以此更新预测对的次数total_correct # eq返回的是Byte类型,这里转换为float类型 # 图片是成批预测,每一批都有预测对的(返回1),也有预测错的(返回0),一批一个数组,此处将数组中预测返回值相加(sum()),得到一批中预测对的次数 # item()将Tensor张量类型转化为标量类型 # 转化路径:[b] => [b] => [b] => scalar => numpy scalar total_correct += torch.eq(pred, label).float().sum().item() # x的大小就是预测的次数 total_num += x.size(0) # 计算预测准确度acc,也称为精度 acc = total_correct / total_num # 打印训练周期数epoch,预测差值loss,精度acc # loss是矢量tensor()形式,使用tensor().item()可将矢量转换为numpy标量 print(epoch, loss.item(), acc) # 精度可视化显示 viz.line(np.array([acc]), np.array([global_step]), win='acc', update='append') # 再加载一次测试集,用于可视化输出每次预测的结果 x, label = iter(test_loader).next() x, label = x.to(device), label.to(device) pred = model(x).argmax(dim=1) viz.images(x, nrow=16, win='test_x', opts=dict(title='test_x')) # 可视化显示预测 viz.text(str(pred.detach().cpu().numpy()), win='predicted label', opts=dict(title='predicted label')) # 可视化显示真实值 viz.text(str(label.detach().cpu().numpy()), win='groundtruth label', opts=dict(title='groundtruth label')) # Python不同于C/C++,程序执行并不需要主程序main(),而是文件自上而下的执行。 # 但很多Python程序中都有if __name__ == "__main__" # 这段代码的主要作用主要是让该python文件既可以独立运行,也可以当做模块导入到其他文件。 # 当导入到其他的脚本文件的时候,此时__name__的名字其实是导入模块的名字,不是’__main__’, main代码里面的就不执行了。 if __name__ == "__main__": main()只要运行就会报错,一直提示目标计算机积极拒绝: 在网上找了很多种方法,一直调试不成功,不知道是自己主机的网络设置问题还是其他问题