赞
踩
import random import torch import matplotlib_inline from matplotlib import pyplot as plt import torchvision import torchvision.transforms as transforms import torchvision.datasets import sys from collections import OrderedDict # --------------------------------------------------------------------------------------------- # 图表展示 def use_svg_display(): # 用矢量图表示 matplotlib_inline.backend_inline.set_matplotlib_formats('svg') def set_figsize(figsize=(3.5, 2.5)): use_svg_display() # 设置图的尺寸 plt.rcParams['figure.figsize'] = figsize # --------------------------------------------------------------------------------------------- # 读取数据 # 获取总的样本数量,然后打乱顺序,用batch-size获取每一部分索引去索引对应样本中的数据,使用yield返回 ''' 函数详解: torch.linspace(start, end, steps, dtype) → Tensor 从start开始到end结束,生成steps个数据点,数据类型为dtype torch.index_select(input, dim, index) 索引张量中的子集 ** input:需要进行索引操作的输入张量 dim:张量维度 0,1 index:索引号,是张量类型 ** yield: 使用yield的函数返回迭代器对象,每次使用时会保存变量信息,使用next()或者使用for可以循环访问迭代器中的内容 ''' def data_iter(batch_size, features, labels): num_examples = len(features) # features nxm indices = list(range(num_examples)) # 借助range生成索引序列 random.shuffle(indices) # 把list列表中的值打乱顺序 for i in range(0, num_examples, batch_size): j = torch.LongTensor(indices[i:min(i + batch_size, num_examples)]) # 这里的i是对标乱序表中的下标索引号 yield features.index_select(0, j), labels.index_select(0, j) # 0维度,有1000个样本,j就是他们的下标 # --------------------------------------------------------------------------------------------- # 定义模型 def linreg(X, w, b): return torch.mm(X, w) + b # 传进来的参数和样本特征都符合矩阵形式 w,b都是列矩阵 X:1000x2 w:2x1 b:1x1 # 这里使用了广播 # --------------------------------------------------------------------------------------------- # 定义损失函数 def square_loss(y_hat, y): # 保证y_hat和y同型,pytorch中的MSELoss没有除以2的操作 return (y_hat - y.view(y_hat.size())) ** 2 / 2 # 这里是多个样本的预测值和实际值之间的差值,返回nxm大小的张量 # 这里的得到的也是一个小批量的样本的损失张量 # --------------------------------------------------------------------------------------------- # 定义优化算法 # 这里使用的是sgd算法,使用小批量梯度和(参数求导后的和:梯度会自动累加,不用自己加和梯度)除以小批量样本个数来求小批量平均值 def sgd(params, lr, batch_size): for param in params: param.data -= lr * param.grad / batch_size # 这里更改param时使用的是param.data,这样就不会影响反向梯度 # 这里的param指的是w1,w2,b # 这里应该是小批量中的每个loss运行完,得到小批量每个样本的梯度然后pytorch自动进行了梯度累加,之后一个小批量得到一个累加和后的 # 梯度w1,w2,b # --------------------------------------------------------------------------------------------- ''' FashionMNIST 数据集 ''' # ----------------------------------------------------------将数值标签转换成文本标签 def get_fashion_mnist_labels(labels): text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat', 'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot'] return [text_labels[int(i)] for i in labels] # -----------------------------------------------------在一行里画出多张图像和对应标签的函数 def show_fashion_mnist(images, labels): use_svg_display() # 这里的_表示忽略(不使用)的变量 _, figs = plt.subplots(1, len(images), figsize=(12, 12)) # 设置一行 len(images)个数量,每个figsize大小的画布 # figs 返回的是一个画布对象,这个对象有imshow,set_tittle,axes_get_xasis().set_visible, # axes.get_yaxis().set_visible()这几种函数调用方式,用来给figs里面添加图像 for f, img, lbl, in zip(figs, images, labels): # 这个画布对象循环往里面添加图像信息 f.imshow(img.view((28, 28)).numpy()) # img承接图像信息,将tensor转化为numpy 这里参数为数组元素 f.set_title(lbl) f.axes.get_xaxis().set_visible(False) f.axes.get_yaxis().set_visible(False) plt.savefig("路径") # ----------------------------------------------------------------获取并读取FashionMNIST数据集函数,返回小批量train,test def load_data_fashion_mnist(batch_size): mnist_train = torchvision.datasets.FashionMNIST(root='路径', train=True, download=True, transform=transforms.ToTensor()) mnist_test = torchvision.datasets.FashionMNIST(root='路径', train=False, download=True, transform=transforms.ToTensor()) ''' 上面的mnist_train,mnist_test都是torch.utils.data.Dataset的子类,所以可以使用len()获取数据集的大小 训练集和测试集中的每个类别的图像数分别是6000,1000,两个数据集分别有10个类别 ''' # mnist是torch.utils.data.dataset的子类,因此可以将其传入torch.utils.data.DataLoader来创建一个DataLoader实例来读取数据 # 在实践中,数据读取一般是训练的性能瓶颈,特别是模型较简单或者计算硬件性能比较高的时候 # DataLoader一个很有用的功能就是允许多进程来加速读取 使用num_works来设置4个进程读取数据 if sys.platform.startswith('win'): num_workers = 0 else: num_workers = 4 train_iter = torch.utils.data.DataLoader(mnist_train, batch_size=batch_size, shuffle=True, num_workers=num_workers) test_iter = torch.utils.data.DataLoader(mnist_test, batch_size=batch_size, shuffle=False, num_workers=num_workers) return train_iter, test_iter # -------------------------------------------------------------查看mnist前10个图像和标签 def check_mnist(): mnist_train = torchvision.datasets.FashionMNIST(root='路径', train=True, download=True, transform=transforms.ToTensor()) mnist_test = torchvision.datasets.FashionMNIST(root='路径', train=False, download=True, transform=transforms.ToTensor()) X, y = [], [] for i in range(10): X.append(mnist_train[i][0]) # 循环获取图像张量矩阵 y.append(mnist_train[i][1]) # 循环获取图像对应数值标签 show_fashion_mnist(X, get_fashion_mnist_labels(y)) # feature, label = mnist_train[0] # print(feature.shape, label) CxHxW # feature对应高和宽均为28像素的图像,因为使用了transforms.ToTensor(),所以每个像素的数值对应于【0.0,1.0】的32位浮点数 # C 是通道数,RGB,灰色图像,通道数为1,H,W分别为高,宽 # mnist_train[0] 是一个元祖,它包含两部分,图像数据结构和图像标签值,图像的数据结构是1x28x28结构,是一个浮点数矩阵,代表一个图像 # -------------------------------------------------------------------------评价模型net在数据集data_iter上的准确率 def evaluate_accuracy(test_iter, net): acc_sum, n, x = 0.0, 0, 0.0 for X, y in test_iter: # 返回一个批量的数据元组迭代对象 if isinstance(net, torch.nn.Module): net.eval() # 评估模式,这会关闭dropout acc_sum += (net(X).argmax(dim=1) == y).float().sum().item() # 将net模型的预测y与标签y进行了准确率比较 net.train() # 改回训练模式 else: # 自定义模型 if ('is_training' in net.__code__.co_varnames): # 就是说如果net函数的参数中如果有is_training这个参数 # 将is_training 设置为False acc_sum += (net(X, is_training=False).argmax(dim=1) == y).float().sum().item() else: acc_sum += (net(X).argmax(dim=1) == y).float().sum().item() n += y.shape[0] # 累加获得样本个数 x = acc_sum / n return x # -------------------------------------------------------------------------训练模型函数 def train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, params=None, lr=None, optimizer=None): for epochs in range(num_epochs): # 循环周期 train_l_sum, train_acc_sum, n = 0.0, 0.0, 0 # 预先定义 训练损失,训练精度,批量个数 for X, y in train_iter: # 批量更新 y_hat = net(X) l = loss(y_hat, y).sum() # 损失计算 # 梯度清零 if optimizer is not None: optimizer.zero_grad() elif params is not None and params[0].grad is not None: # 权重存在并且权重的梯度存在 for param in params: param.grad.data.zero_() l.backward() # 反向传播 # 梯度更新操作 if optimizer is None: sgd(params, lr, batch_size) # 调用sgd进行梯度下降操作 else: optimizer.step() # softmax回归的简洁实现将要用到 train_l_sum += l.item() # 损失累加 train_acc_sum += (y_hat.argmax(dim=1) == y).sum().item() # (y_hat.argmax(dim=1) == y) # 取出y_hat每一行中最大的概率索引和y比较,结果为tensor,元素值为0/1 n += y.shape[0] # 计算一个批量中标签的个数 test_acc = evaluate_accuracy(test_iter, net) # 一个循环之后进行测试集的准确度计算 print(f'epoch %d,loss %.4f,train_acc %.3f,test_acc %.3f' % (epochs + 1, train_l_sum / n, train_acc_sum / n, test_acc)) # x = torch.tensor([[0.1, 0.4, 0.2], [1, 0.06, 0.5]]) # print((x.argmax(dim=1)==torch.tensor([[1,1]])).float()) # -------------------------------------------------------------------------x的形状转换功能函数 class FlattenLayer(torch.nn.Module): def __init__(self): super(FlattenLayer, self).__init__() # 初始化函数,自动调用forward函数 def forward(self, x): # x shape: (batch,*,*,....) return x.view(x.shape[0], -1) # 转换成(batch_size,特征数)形状 # 这样就方便定义模型 net = torch.nn.Sequential( # FlattenLayer() # torch.nn.Linear(num_inputs,num_outputs) OrderedDict([ ('flatten', FlattenLayer()), ('linear', torch.nn.Linear(2, 3)) ]) ) ''' -------------------------------------------------------------------作图函数 ''' def semilogy(x_vals, y_vals, xlabel, ylabel, label, x2_vals=None, y2_vals=None, legend=None): plt.xlabel(xlabel) plt.ylabel(ylabel) plt.semilogy(x_vals, y_vals) # y轴使用对数尺度 if x2_vals and y2_vals: plt.semilogy(x2_vals, y2_vals, linestyle=':') plt.legend(legend) plt.savefig("路径" + label + "模拟.png")
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。