Softmax 回归 + 丧失函数 + 图片分类数据集

[复制链接]
发表于 昨天 20:28 | 显示全部楼层 |阅读模式
Softmax 回归


softmax 回归是呆板学习别的一个非常经典且告急的模子,是一个分类标题。
下面先表明一下分类和回归的区别:


简单来说,分类标题从回归的单输出酿成了多输出,输出的个数即是种别的个数。

现实上,对于分类来说,我们不关心它们之间现实的值,我们关心的是:模子是否对正确种别的置信度特别的大

固然上述没有要求                                        O                         i                                  O_i               Oi​ 是一个什么样的值,但是假如我们将值放在符合的区间,也会让后续的处置惩罚变得更加的简单,好比下面我们渴望模子的输出是一个概率:


上述要是你使用了                               o                      n                      e                      −                      h                      o                      t                          one-hot               one−hot 编码的话,只有当                               i                      =                      y                          i=y               i=y时,                                       y                         i                              =                      1                          y_i = 1               yi​=1,否则就是0。

丧失函数

丧失函数是用来衡量猜测值与真实值之间的区别,是呆板学习内里一个非常告急的概念。

1. L2 Loss(均方丧失)


蓝色的线表现                               y                      =                      0                          y=0               y=0 时变更我的 猜测值                                        y                         ′                                  y'               y′ 所天生的函数,可以看出来是一个二次函数。绿色是一个似然函数,似然函数取得最大值表明取该参数模子最公道。橙色的表现的是丧失函数的梯度,由于是一次函数,穿过原点。
由上述可以发现,当猜测值与真实值隔断比力远的时间,梯度比力的大,则对参数的更新是比力的多的,当越靠近原点的时间,梯度的绝对值就会越小,对参数的更新就会越来越小。但这大概并不是一件功德,由于在离原点越远的地方,我大概并不渴望须要那么大的梯度来更新我的参数。因此也可以思量下面的 L1 Loss
L1 Loss


固然也是可以提出新的丧失函数来连合上述两种丧失函数的优点。


上述丧失函数界说的优点就是:当猜测值与真实值差别比力大的时间,我可以以匀称的力度
往回拉。当两者越来越靠近时,我可以使得拉的力度越来越小,从而不会出现数值上的标题。
图片分类数据集

下面使用 Fashion-MNIST 数据集,展示对数据集的一样平常利用:
起首导入所需的库:
  1. %matplotlib inline
  2. import torch
  3. import torchvision
  4. from torch.utils import data
  5. from torchvision import transforms
  6. from d2l import torch as d2l
  7. d2l.use_svg_display()
  8. # 使用svg来显示图片
复制代码
接着我们可以通过框架中的内置函数将Fashion-MNIST数据集下载并读取到内存中
  1. # 通过ToTensor实例将图像数据从PIL类型变换成32位浮点数格式,
  2. # 并除以255使得所有像素的数值均在0~1之间
  3. trans = transforms.ToTensor() # 预处理,将图片转换成tensor
  4. mnist_train = torchvision.datasets.FashionMNIST(
  5.     root="../data", train=True, transform=trans, download=True)
  6. # transform=trans希望得到的是一个tensor而不是一张图片
  7. mnist_test = torchvision.datasets.FashionMNIST(
  8.     root="../data", train=False, transform=trans, download=True)
复制代码
Fashion-MNIST由10个种别的图像构成,每个种别由练习数据集(train dataset)中的6000张图像和测试数据集(test dataset)中的1000张图像构成。因此,练习集和测试集分别包罗60000和10000张图像。测试数据集不会用于练习,只用于评估模子性能

每个输入图像的高度和宽度均为28像素。
数据集由灰度图像构成,其通道数为1。
为了轻便起见,将高度                              h                          h               h像素、宽度                              w                          w               w像素图像的形状记为                              h                      ×                      w                          h \times w               h×w或(                              h                          h               h,                              w                          w               w)。

接着界说两个可视化数据集的函数
Fashion-MNIST中包罗的10个种别,分别为t-shirt(T恤)、trouser(裤子)、pullover(套衫)、dress(连衣裙)、coat(外套)、sandal(凉鞋)、shirt(衬衫)、sneaker(运动鞋)、bag(包)和ankle boot(短靴)。
以下函数用于在数字标签索引及其文本名称之间举行转换。
  1. def get_fashion_mnist_labels(labels):  #@save
  2.     """返回Fashion-MNIST数据集的文本标签"""
  3.     text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat',
  4.                    'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']
  5.     return [text_labels[int(i)] for i in labels]
  6.    
  7. def show_images(imgs, num_rows, num_cols, titles=None, scale=1.5):  #@save
  8.     """绘制图像列表"""
  9.     figsize = (num_cols * scale, num_rows * scale)
  10.     _, axes = d2l.plt.subplots(num_rows, num_cols, figsize=figsize)
  11.     axes = axes.flatten()
  12.     for i, (ax, img) in enumerate(zip(axes, imgs)):
  13.         if torch.is_tensor(img):
  14.             # 图片张量
  15.             ax.imshow(img.numpy())
  16.         else:
  17.             # PIL图片
  18.             ax.imshow(img)
  19.         ax.axes.get_xaxis().set_visible(False)
  20.         ax.axes.get_yaxis().set_visible(False)
  21.         if titles:
  22.             ax.set_title(titles[i])
  23.     return axes
复制代码
以下展示练习数据会合前几个样本的图像及其相应的标签。

为了使我们在读取练习集和测试集时更轻易,我们使用内置的数据迭代器,而不是从零开始创建。
在每次迭代中,数据加载器每次都会读取一小批量数据,巨细为batch_size
通过内置数据迭代器,我们可以随机打乱了全部样本,从而无私看法读取小批量。
  1. batch_size = 256
  2. def get_dataloader_workers():  #@save
  3.     """使用4个进程来读取数据"""
  4.     return 4
  5. train_iter = data.DataLoader(mnist_train, batch_size, shuffle=True,
  6.                              num_workers=get_dataloader_workers())
  7. timer = d2l.Timer() # 用来测试速度
  8. for X, y in train_iter:
  9.     continue
  10. f'{timer.stop():.2f} sec'
复制代码

在模子练习之前,一样平常都是须要测试数据读取的速率,数据读取的速率须要比模子的练习速率更快才好。
基于上述内容,现在我们界说load_data_fashion_mnist函数,用于获取和读取Fashion-MNIST数据集。这个函数返回练习集验证集的数据迭代器。别的,这个函数还担当一个可选参数resize,用来将图像巨细调解为另一种形状。
  1. def load_data_fashion_mnist(batch_size, resize=None):  #@save
  2.     """下载Fashion-MNIST数据集,然后将其加载到内存中"""
  3.     trans = [transforms.ToTensor()]
  4.     if resize:
  5.         trans.insert(0, transforms.Resize(resize))
  6.     trans = transforms.Compose(trans)
  7.     mnist_train = torchvision.datasets.FashionMNIST(
  8.         root="../data", train=True, transform=trans, download=True)
  9.     mnist_test = torchvision.datasets.FashionMNIST(
  10.         root="../data", train=False, transform=trans, download=True)
  11.     return (data.DataLoader(mnist_train, batch_size, shuffle=True,
  12.                             num_workers=get_dataloader_workers()),
  13.             data.DataLoader(mnist_test, batch_size, shuffle=False,
  14.                             num_workers=get_dataloader_workers()))
复制代码

Softmax 回归从0开始实现

  1. import torch
  2. from IPython import display
  3. from d2l import torch as d2l
  4. batch_size = 256 # 每次随机读取256张图片
  5. train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size) # 前面实现过
复制代码
由于图像是12828的,但是对于softmax来说,输入的须要是一个向量。(但是这种利用会丧失很多空间信息,卷积部分办理。)因此我们将展平每个图像,把它们看作长度为784的向量。数据集有十个种别,因此网络输出维度就是10。
  1. num_inputs = 784 # 将空间拉长,28*28拉成784的一个向量
  2. num_outputs = 10
  3. W = torch.normal(0, 0.01, size=(num_inputs, num_outputs), requires_grad=True)
  4. # 行数为输入的个数,列数等于输出的个数
  5. b = torch.zeros(num_outputs, requires_grad=True)
  6. # 对每一个输出,都需要有一个偏移
复制代码
下面界说 softmax 利用:
实现softmax由三个步调构成:

  • 对每个项求幂(使用exp);
  • 对每一行求和(小批量中每个样本是一行),得到每个样本的规范化常数;
  • 将每一行除以其规范化常数,确保结果的和为1。
表达式如下:
                                              s                            o                            f                            t                            m                            a                            x                                  (                         X                                   )                                       i                               j                                            =                                              exp                               ⁡                               (                                           X                                               i                                     j                                                      )                                                             ∑                                  k                                          exp                               ⁡                               (                                           X                                               i                                     k                                                      )                                            .                               \mathrm{softmax}(\mathbf{X})_{ij} = \frac{\exp(\mathbf{X}_{ij})}{\sum_k \exp(\mathbf{X}_{ik})}.                   softmax(X)ij​=∑k​exp(Xik​)exp(Xij​)​.分母或规范化常数,偶然也称为配分函数(其对数称为对数-配分函数)。该名称来自统计物理学中一个模仿粒子群分布的方程。
  1. def softmax(X):
  2.     X_exp = torch.exp(X) # 对X中的每个元素作指数运算
  3.     partition = X_exp.sum(1, keepdim=True) # 按照每一行进行求和
  4.     return X_exp / partition  # 这里应用了广播机制
复制代码

界说softmax利用后,可以实现softmax回归模子
下面的代码界说了输入怎样通过网络映射到输出。
留意,将数据转到达模子之前,我们使用reshape函数将每张原始图像展平为向量。
  1. def net(X):
  2.     return softmax(torch.matmul(X.reshape((-1, W.shape[0])), W) + b)
复制代码
起首回首一下交错熵:
交错熵接纳真实标签的猜测概率的负对数似然。这里我们倒霉用Python的for循环迭代猜测(这通常是低效的),而是通过一个运算符选择全部元素。
下面,**创建一个数据样本y_hat,此中包罗2个样本在3个种别的猜测概率,以及它们对应的标签y。**有了y,我们知道在第一个样本中,第一类是正确的猜测;而在第二个样本中,第三类是正确的猜测。然后(使用y作为y_hat中概率的索引),我们选择第一个样本中第一个类的概率和第二个样本中第三个类的概率。
  1. y = torch.tensor([0, 2]) # 表示两个样本的真实标签分别为0、2
  2. y_hat = torch.tensor([[0.1, 0.3, 0.6], [0.3, 0.2, 0.5]])
  3. y_hat[[0, 1], y]
  4. # 对第0个样本,拿出y[0]对应的那个元素,对第一个样本,拿出y[1]对应的那个元素
  5. # [0, 1] 是一个索引列表,表示要选取 y_hat 中的第一行和第二行。
复制代码

基于上述,我们下面来实现交错熵丧失函数:
  1. # 了解交叉熵公式和代码上述原理,一行代码即可完成。
  2. def cross_entropy(y_hat, y):
  3.     return - torch.log(y_hat[range(len(y_hat)), y])
  4. cross_entropy(y_hat, y)
复制代码

由于上述是分类标题,因此须要将猜测种别与真实                               y                          y               y 元素举行比力:
  1. def accuracy(y_hat, y):  #@save
  2.     """计算预测正确的数量"""
  3.     # 要是 y_hat 是一个二维矩阵且列数也大于1
  4.     if len(y_hat.shape) > 1 and y_hat.shape[1] > 1:
  5.         y_hat = y_hat.argmax(axis=1) # 按每一行来存最大值的下标
  6.     cmp = y_hat.type(y.dtype) == y  # 将 y_hat 转换为 y 的数据类型,然后作比较
  7.     return float(cmp.type(y.dtype).sum()) # 返回预测正确的样本数
复制代码
我们将继续使用之前界说的变量y_hat和y分别作为猜测的概率分布和标签。可以看到,第一个样本的猜测种别是2(该行的最大元素为0.6,索引为2),这与现实标签0不同等。第二个样本的猜测种别是2(该行的最大元素为0.5,索引为2),这与现实标签2同等。因此,这两个样本的分类精度率为0.5。

同样,对于恣意数据迭代器data_iter可访问的数据集,可以评估在恣意模子net的精度
  1. def evaluate_accuracy(net, data_iter):  #@save
  2.     """计算在指定数据集上模型的精度"""
  3.     if isinstance(net, torch.nn.Module):
  4.         net.eval()  # 将模型设置为评估模式
  5.     metric = Accumulator(2)  # 正确预测数、预测总数
  6.     with torch.no_grad():
  7.         for X, y in data_iter:
  8.             metric.add(accuracy(net(X), y), y.numel())
  9.     return metric[0] / metric[1]
复制代码
这里界说一个实用步伐类Accumulator,用于对多个变量举行累加。在上面的evaluate_accuracy函数中,我们在(Accumulator实例中创建了2个变量,分别用于存储正确猜测的数目和猜测的总数目)。当我们遍历数据集时,两者都将随着时间的推移而累加。
  1. class Accumulator:  #@save
  2.     """在n个变量上累加"""
  3.     def __init__(self, n):
  4.         self.data = [0.0] * n
  5.     def add(self, *args):
  6.         self.data = [a + float(b) for a, b in zip(self.data, args)]
  7.     def reset(self):
  8.         self.data = [0.0] * len(self.data)
  9.     def __getitem__(self, idx):
  10.         return self.data[idx]
复制代码

下面就可以举行 softmax 的回归练习了:
  1. def train_epoch_ch3(net, train_iter, loss, updater):  #@save
  2.     """训练模型一个迭代周期(定义见第3章)"""
  3.     # 将模型设置为训练模式
  4.     if isinstance(net, torch.nn.Module):
  5.         net.train()
  6.     # 训练损失总和、训练准确度总和、样本数
  7.     metric = Accumulator(3)
  8.     for X, y in train_iter:
  9.         # 计算梯度并更新参数
  10.         y_hat = net(X)
  11.         l = loss(y_hat, y)
  12.         if isinstance(updater, torch.optim.Optimizer):
  13.             # 使用PyTorch内置的优化器和损失函数
  14.             updater.zero_grad()
  15.             l.mean().backward()
  16.             updater.step()
  17.         else:
  18.             # 使用定制的优化器和损失函数
  19.             l.sum().backward()
  20.             updater(X.shape[0])
  21.         metric.add(float(l.sum()), accuracy(y_hat, y), y.numel())
  22.     # 返回训练损失和训练精度
  23.     return metric[0] / metric[2], metric[1] / metric[2]
复制代码
在展示练习函数的实现之前,我们[界说一个在动画中绘制数据的实用步伐类]Animator
  1. class Animator:  #@save
  2.     """在动画中绘制数据"""
  3.     def __init__(self, xlabel=None, ylabel=None, legend=None, xlim=None,
  4.                  ylim=None, xscale='linear', yscale='linear',
  5.                  fmts=('-', 'm--', 'g-.', 'r:'), nrows=1, ncols=1,
  6.                  figsize=(3.5, 2.5)):
  7.         # 增量地绘制多条线
  8.         if legend is None:
  9.             legend = []
  10.         d2l.use_svg_display()
  11.         self.fig, self.axes = d2l.plt.subplots(nrows, ncols, figsize=figsize)
  12.         if nrows * ncols == 1:
  13.             self.axes = [self.axes, ]
  14.         # 使用lambda函数捕获参数
  15.         self.config_axes = lambda: d2l.set_axes(
  16.             self.axes[0], xlabel, ylabel, xlim, ylim, xscale, yscale, legend)
  17.         self.X, self.Y, self.fmts = None, None, fmts
  18.     def add(self, x, y):
  19.         # 向图表中添加多个数据点
  20.         if not hasattr(y, "__len__"):
  21.             y = [y]
  22.         n = len(y)
  23.         if not hasattr(x, "__len__"):
  24.             x = [x] * n
  25.         if not self.X:
  26.             self.X = [[] for _ in range(n)]
  27.         if not self.Y:
  28.             self.Y = [[] for _ in range(n)]
  29.         for i, (a, b) in enumerate(zip(x, y)):
  30.             if a is not None and b is not None:
  31.                 self.X[i].append(a)
  32.                 self.Y[i].append(b)
  33.         self.axes[0].cla()
  34.         for x, y, fmt in zip(self.X, self.Y, self.fmts):
  35.             self.axes[0].plot(x, y, fmt)
  36.         self.config_axes()
  37.         display.display(self.fig)
  38.         display.clear_output(wait=True)
复制代码
下面开始练习:
  1. def train_ch3(net, train_iter, test_iter, loss, num_epochs, updater):  #@save
  2.     """训练模型(定义见第3章)"""
  3.     animator = Animator(xlabel='epoch', xlim=[1, num_epochs], ylim=[0.3, 0.9],
  4.                         legend=['train loss', 'train acc', 'test acc'])
  5.     for epoch in range(num_epochs):
  6.         train_metrics = train_epoch_ch3(net, train_iter, loss, updater)
  7.         test_acc = evaluate_accuracy(net, test_iter)
  8.         animator.add(epoch + 1, train_metrics + (test_acc,))
  9.     train_loss, train_acc = train_metrics
  10.     assert train_loss < 0.5, train_loss
  11.     assert train_acc <= 1 and train_acc > 0.7, train_acc
  12.     assert test_acc <= 1 and test_acc > 0.7, test_acc
复制代码
[小批量随机梯度降落来优化模子的丧失函数],设置学习率为0.1
  1. lr = 0.1
  2. def updater(batch_size):
  3.     return d2l.sgd([W, b], lr, batch_size)
复制代码

对图像举行猜测:
  1. def predict_ch3(net, test_iter, n=6):  #@save
  2.     """预测标签"""
  3.     for X, y in test_iter:
  4.         break
  5.     trues = d2l.get_fashion_mnist_labels(y)
  6.     preds = d2l.get_fashion_mnist_labels(net(X).argmax(axis=1))
  7.     titles = [true +'\n' + pred for true, pred in zip(trues, preds)]
  8.     d2l.show_images(
  9.         X[0:n].reshape((n, 28, 28)), 1, n, titles=titles[0:n])
  10. predict_ch3(net, test_iter)
复制代码

Softmax 回归的轻便实现

通过深度学习框架的高级API也能更方便地实现softmax回归模子:
  1. import torch
  2. from torch import nn
  3. from d2l import torch as d2l
  4. batch_size = 256
  5. train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
复制代码
Softmax 回归的输出层是一个全毗连层
  1. # PyTorch不会隐式地调整输入的形状。因此,
  2. # 我们在线性层前定义了展平层(flatten),来调整网络输入的形状
  3. net = nn.Sequential(nn.Flatten(), nn.Linear(784, 10))
  4. def init_weights(m):
  5.     if type(m) == nn.Linear:
  6.         nn.init.normal_(m.weight, std=0.01)
  7. net.apply(init_weights);
复制代码
在交错熵丧失函数中转达未规范化的猜测,并同时盘算softmax及其对数
  1. loss = nn.CrossEntropyLoss(reduction='none')# 不进行任何减少操作,返回每个样本的损失值。
复制代码
使用学习率为0.1的小批量随机梯度降落作为优化算法
  1. trainer = torch.optim.SGD(net.parameters(), lr=0.1)
复制代码
练习,重用之前编写的函数:

QA思考

Q1:softlabel练习战略。
上述被称为软标签,旨在通过使用非硬性(即不是0或1的绝对分类结果)的目的标签来进步模子的泛化本领和鲁棒性。
传统的分类任务中,目的标签通常是one-hot编码的情势,即对于每个样本,正确的种别标志为1,其他种别标志为0。但是现实上对于边界值是很难到达的,好比对于softmax函数而言:
                                    softmax                         (                                   z                            i                                  )                         =                                              e                                           z                                  i                                                                        ∑                                               j                                     =                                     1                                              n                                                      e                                               z                                     j                                                                         \text{softmax}(z_i) = \frac{e^{z_i}}{\sum_{j=1}^{n} e^{z_j}}                   softmax(zi​)=∑j=1n​ezj​ezi​​
要想使其输出为 1 ,则须要某一个                                        z                         i                                  z_i               zi​ ,趋近于无穷才行。
而softlabel则允许这些标签值位于(0, 1)之间,而且全部种别的概率之和通常为1。这意味着纵然是错误的种别也大概被赋予肯定的概率,从而向模子转达“某种水平上的正确”。好比我可以以为0.9 就是正确,0.1 就是不正确。
Q2 : softmax 回归和 logistic 回归的接洽。
可以以为logistic是softmax的特例,也就是logistic是一个两分类的标题,只须要输出一个种别的概率                               P                          P               P 即可,剩下的直接                               1                      −                      P                          1-P               1−P 即可。但是在现实的分类标题中,两分类的标题很少。
Q3 : 在 Accuracy函数中为啥不把除以 len(y) 做完呢?
在 Accuracy 函数中,不能直接除以 len(y),由于末了一个 batch 的样本数目大概会少于设定的 batch size。为了确保正确率盘算的正确性,应该根据当前 batch 现实包罗的样本数目举行归一化,而不是固定地使用完备的 batch size。
增补:
思量到李沐老师的视线中使用到了d2l,且是在jupyter上面举行实现的,但是我现在不想用d2l,以及须要再Pycharm上面编写,于是我根据上述代码编写了下面的代码,结果也能很好的复现李沐老师代码的结果。
  1. import torchimport torchvisionfrom torchvision import transformsfrom torch.utils import dataimport matplotlib.pyplot as pltclass Animator:    def __init__(self, xlabel=None, ylabel=None, legend=None, xlim=None,                 ylim=None, xscale='linear', yscale='linear',                 fmts=('-', 'm--', 'g-.', 'r:'), figsize=(3.5, 2.5)):        if legend is None:            legend = []        self.xlabel = xlabel        self.ylabel = ylabel        self.legend = legend        self.xlim = xlim        self.ylim = ylim        self.xscale = xscale        self.yscale = yscale        self.fmts = fmts        self.figsize = figsize        self.X, self.Y = [], []    def add(self, x, y):        if not hasattr(y, "__len__"):            y = [y]        n = len(y)        if not hasattr(x, "__len__"):            x = [x] * n        if not self.X:            self.X = [[] for _ in range(n)]        if not self.Y:            self.Y = [[] for _ in range(n)]        for i, (a, b) in enumerate(zip(x, y)):            if a is not None and b is not None:                self.X[i].append(a)                self.Y[i].append(b)    def show(self):        plt.figure(figsize=self.figsize)        for x_data, y_data, fmt in zip(self.X, self.Y, self.fmts):            plt.plot(x_data, y_data, fmt)        plt.xlabel(self.xlabel)        plt.ylabel(self.ylabel)        if self.legend:            plt.legend(self.legend)        if self.xlim:            plt.xlim(self.xlim)        if self.ylim:            plt.ylim(self.ylim)        plt.xscale(self.xscale)        plt.yscale(self.yscale)        plt.grid()        plt.show()def get_dataloader_workers():    return 0  # 禁用多历程加载def load_data_fashion_mnist(batch_size, resize=None):    trans = [transforms.ToTensor()]    if resize:        trans.insert(0, transforms.Resize(resize))    trans = transforms.Compose(trans)    mnist_train = torchvision.datasets.FashionMNIST("./data", train=True, transform=trans, download=True)    mnist_test = torchvision.datasets.FashionMNIST("./data", train=False, transform=trans, download=True)    return (        data.DataLoader(mnist_train, batch_size, shuffle=True, num_workers=get_dataloader_workers()),        data.DataLoader(mnist_test, batch_size, shuffle=False, num_workers=get_dataloader_workers())    )# softmax 实现def softmax(X):    X_exp = torch.exp(X)    partition = X_exp.sum(1, keepdim=True)    return X_exp / partition# 回归模子def net(X):
  2.     return softmax(torch.matmul(X.reshape((-1, W.shape[0])), W) + b)
  3. # 交错熵丧失函数def cross_entropy(y_hat, y):    return -torch.log(y_hat[range(len(y_hat)), y])# 猜测正确的数目def accuracy(y_hat, y):    if len(y_hat.shape) > 1 and y_hat.shape[1] > 1:        y_hat = y_hat.argmax(axis=1)    cmp = y_hat.type(y.dtype) == y    return float(cmp.type(y.dtype).sum())class Accumulator:    def __init__(self, n):        self.data = [0.0] * n    def add(self, *args):        self.data = [a + float(b) for a, b in zip(self.data, args)]    def reset(self):        self.data = [0.0] * len(self.data)    def __getitem__(self, idx):        return self.data[idx]def evaluate_accuracy(net, data_iter):    if isinstance(net, torch.nn.Module):        net.eval()    metric = Accumulator(2)    with torch.no_grad():        for X, y in data_iter:            metric.add(accuracy(net(X), y), y.numel())    return metric[0] / metric[1]def train_epoch_ch3(net, train_iter, loss, updater):    if isinstance(net, torch.nn.Module):        net.train()    metric = Accumulator(3)    for X, y in train_iter:        y_hat = net(X)        l = loss(y_hat, y)        if isinstance(updater, torch.optim.Optimizer):            updater.zero_grad()            l.mean().backward()            updater.step()        else:            l.sum().backward()            updater(X.shape[0])        metric.add(float(l.sum()), accuracy(y_hat, y), y.numel())    return metric[0] / metric[2], metric[1] / metric[2]def train_ch3(net, train_iter, test_iter, loss, num_epochs, updater):    animator = Animator(xlabel='epoch', xlim=[1, num_epochs], ylim=[0.3, 0.9],                        legend=['train loss', 'train acc', 'test acc'])    for epoch in range(num_epochs):        train_metrics = train_epoch_ch3(net, train_iter, loss, updater)        test_acc = evaluate_accuracy(net, test_iter)        animator.add(epoch + 1, train_metrics + (test_acc,))    train_loss, train_acc = train_metrics    assert train_loss < 0.5, train_loss    assert train_acc <= 1 and train_acc > 0.7, train_acc    assert test_acc <= 1 and test_acc > 0.7, test_acc    animator.show()  # 展示终极结果图def sgd(params, lr, batch_size):    with torch.no_grad():        for param in params:            param -= lr * param.grad / batch_size            param.grad.zero_()def updater(batch_size):    return sgd([W, b], lr, batch_size)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_images(imgs, num_rows, num_cols, titles=None, scale=1.5):    figsize = (num_cols * scale, num_rows * scale)    _, axes = plt.subplots(num_rows, num_cols, figsize=figsize)    axes = axes.flatten()    for i, (ax, img) in enumerate(zip(axes, imgs)):        if torch.is_tensor(img):            ax.imshow(img.numpy(), cmap='gray')        else:            ax.imshow(img, cmap='gray')        ax.axes.get_xaxis().set_visible(False)        ax.axes.get_yaxis().set_visible(False)        if titles:            ax.set_title(titles[i])    plt.show()def predict_ch3(net, test_iter, n=6):    for X, y in test_iter:        break    trues = get_fashion_mnist_labels(y)    preds = get_fashion_mnist_labels(net(X).argmax(axis=1))    titles = [true + '\n' + pred for true, pred in zip(trues, preds)]    show_images(X[0:n].reshape((n, 28, 28)), 1, n, titles=titles[0:n])if __name__ == "__main__":    # 界说超参数    batch_size = 256    num_epochs = 10    lr = 0.1    # 加载数据    train_iter, test_iter = load_data_fashion_mnist(batch_size)    # 初始化模子参数    num_inputs = 784    num_outputs = 10    W = torch.normal(0, 0.1, size=(num_inputs, num_outputs), requires_grad=True)    b = torch.zeros(num_outputs, requires_grad=True)    # 练习模子    train_ch3(net, train_iter, test_iter, cross_entropy, num_epochs, updater)    # 测试模子并表现猜测结果    predict_ch3(net, test_iter)
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

×
登录参与点评抽奖,加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表