李沐动手深度学习(pycharm中运行笔记)——09.softmax回归+图像分类数据集+从零实现+简洁实现

09.softmax回归+图像分类数据集+从零实现+简洁实现(与课程对应)

目录

 一、softmax回归

 1、回归 vs 分类

2、经典分类数据集: 

3、从回归到分类——均方损失

4、从回归到多类分类——无校验比例

 5、从回归到多类分类——校验比例

 6、softmax和交叉熵损失

7、总结

二、损失函数

1、均方损失函数 L2 loss

2、绝对值损失函数L1 loss

3、Huber‘s 鲁棒损失

三、图片分类数据集

四、从零实现

五、简洁实现 


 一、softmax回归

 1、回归 vs 分类

回归估计一个连续值:例如房子卖的价格

  • 单连续数值输出
  • 自然区间R
  • 跟真实值的区别作为损失

分类预测一个离散类别:例如一个图片里面是猫还是狗

  • 通常多个输出
  • 输出 i 是预测为第 i 类的置信度。

2、经典分类数据集: 

MNIST 数据集 :一个非常经典的数据集,用于识别手写数字 0 到 9,是一个十类分类问题。

 

ImageNet 数据集 :深度学习中特别经典的数据集,有 100 万张图片,每一张图片是一个自然物体,属于 1000 类自然物体之一,其中包含大概 100 种不同的狗 ,该问题为 1000 类的分类问题。

3、从回归到分类——均方损失

  • 类别编码 :
    • 编码原因 :类别常为字符串,不是数值,需进行编码处理。
    • 编码方式 :若有 n 个类别,采用一位有效编码。标号是长为 n 的向量 Y1、Y2 … YN ,若真实类别是第 i 个,则 Yi 等于 1,其他元素全部为 0 。

  • 模型训练与预测 :
    • 训练方法 :编码后可用回归问题的均方损失进行训练,无需改动。
    • 预测方式 :训练出模型后,做预测时选取使置信度值最大化的 i,即通过 argmax o i 得到预测标号 yhat 。

4、从回归到多类分类——无校验比例

  • Softmax 回归的问题及目标
    • 关注置信度 :在分类中,更关心对正确类别的置信度要足够大,而非实际值。
    • 目标函数改进 :希望正确类别 y 的置信度 oy 远大于其他非正确类的 oi,数学表示为 oy - oi 大于某阈值 Delta,以此拉开正确类与其他类的距离(最大值作为预测、需要更置信的识别正确类)。

 5、从回归到多类分类——校验比例

  • 输出处理的想法
    • 输出值区间调整 :将输出值放到合适区间能让后续处理更简单,比如希望输出是概率。
    • 引入 Softmax 操作 :对输出向量 o 应用 Softmax 操作得到 y hat 向量,其元素非负且和为 1,满足概率属性。
    • Softmax 具体计算 :y hat 的第 i 个元素等于 o 的第 i 个元素做指数后,除以所有 o 元素做指数的和,这样 y hat 就可作为概率。

 6、softmax和交叉熵损失

  • 交叉熵基本概念
    • 衡量概率区别:使用交叉熵(cross entropy)衡量两个概率的区别,将其作为损失来比较预测概率和真实概率。
    • 离散概率公式:假设有两个离散概率 p 和 q,有 n 个元素,交叉熵公式为对每个元素 i,负的 pi 乘以 log qi 然后求和。

  • 在分类问题中的损失计算
    • 损失公式:对于真实标号 y 和预测标号 y hat,损失 l (y, y hat) 等于对所有 i 类别求和,负的 yi 乘以 log yi hat 。
    • 简化计算:由于 y 中只有一个元素为 1 其余为 0,求和可简化为负的对真实类别 y 的预测值 y hat 求 log 。

  • 与梯度的关系
    • 梯度计算:损失的梯度是真实概率和预测概率的区别,如损失对 DOI 求导等于 Softmax 的第二个元素减去真实类别 y。
    • 梯度下降作用:梯度下降时不断减去真实和预测概率的区别,使预测的 Softmax 值和真实的 y 更相近 。

7、总结

  • Softmax回归是一个多类分类模型
  • 使用Softmax操作子得到每个类的预测置信度
  • 使用交叉熵来衡量预测和标号的区别

二、损失函数

损失函数用于衡量预测值和真实值间的区别,在机器学习里是重要概念。简单介绍三个常用的损失函数。

1、均方损失函数 L2 loss

  • 定义 :均方损失又叫 L2 loss,定义为真实值 y 减去预测值 y',做平方再除以 2,这样求导数时 2 和 1/2 抵消变为 1。
  • 特性可视化 :用三条曲线可视化其特性,蓝色曲线表示 y = 0 时变换预测值 y' 的函数,是二次函数且为偶函数;橙色线表示损失函数的梯度,是穿过原点的一次函数。
  • 参数更新 :梯度决定参数更新方式,预测值 y' 与真实值 y 距离远时梯度大,参数更新多;靠近时梯度绝对值变小,参数更新幅度变小。

 

2、绝对值损失函数L1 loss

  • L1 损失函数定义
    • 公式形式:L1 损失函数定义为预测值减去真实值的绝对值,反过来也一样,即 | 预测值 - 真实值 |。
  • 函数曲线情况
    • 曲线呈现:蓝色线是损失函数曲线,当 y = 0 时的样子;绿色线是似然函数曲线,在原点处有一个很尖的点。
  • L1 损失函数导数
    • 大于 0 时导数:当 y' 大于 0 时,导数为常数 1。
    • 小于 0 时导数:当 y' 小于 0 时,导数为常数 -1。
    • 特殊点情况:由于绝对值函数在 0 点处不可导,其 subgradients(次梯度)可以在 -1 和 1 之间 。
  • L1 损失函数特性
    • 距离远时特点:当预测值跟真实值隔得比较远时,不管距离多远,梯度永远是常数,这带来稳定性好处,权重更新不会特别大。
    • 距离近时劣势:在零点处不可导,且在零点处有从 -1 到 1 之间的剧烈变化,这种不平滑性导致在预测值和真实值靠得比较近,即优化末期时可能变得不稳定 。

3、Huber‘s 鲁棒损失

  • Harbor 鲁棒损失函数定义
    • 差值较大情况:当预测值和真实值差的绝对值大于 1 时,损失函数是绝对值误差(y 减去 y 一撇的绝对值)并减去 LNG,使曲线能连起来。
    • 差值较近情况:当预测值和真实值差的绝对值小于等于 1 时,损失函数是平方误差。
  • Harbor 鲁棒损失函数曲线特点
    • 蓝色曲线:在正 1 负 1 之间是平滑二次函数曲线,之外是另一条曲线。
    • 绿色线(Sech 函数):类似高斯分布,在原点处不像绝对值误差那样尖锐。
  • Harbor 鲁棒损失函数导数特点
    • 差值较大时:当 y 撇大于 1 或者小于 -1 时,导数是常数。
    • 差值较小时:当 y 撇在 -1 到 1 之间时,导数是渐变过程。
    • 导数好处:预测值和真实值差得远时,梯度用均匀力度往回拉;靠近时,梯度绝对值变小,保证优化平滑,避免数值问题。

三、图片分类数据集

MNIST数据集是图像分类中广泛使用的数据集之一,但作为基准数据集过于简单,使用类似但更复杂的Fashion-MNIST数据集。

1、导入库

import torch
import torchvision
from torch.utils import data
from torchvision import transforms
from d2l import torch as d2l

2、 通过框架中的内置函数,将Fashion-MNIST数据集下载并读取到内存中

# 通过ToTensor实例将图像数据从PIL类型变换成32位浮点数格式;并除以255使得所有像素的数值均在0到1之间
trans = transforms.ToTensor()  # 预处理,用于将图片转为tensor
mnist_train = torchvision.datasets.FashionMNIST(root="../data", train=True, transform=trans, download=True)  # 在torchvision.datasets找到FashionMNIST数据集,参数:root="../data"下载目录, train=True下载训练数据集, transform=trans图片转为pytorch的tensor, download=True下载
mnist_test = torchvision.datasets.FashionMNIST(root="../data", train=False, transform=trans, download=True)
print("len(mnist_train):", len(mnist_train), "\nlen(mnist_test):", len(mnist_test))
print("mnist_train[0][0].shape,训练集中第一张图片的形状:", mnist_train[0][0].shape, "\nmnist_train[0][1],训练集中第一张图片的标签:", mnist_train[0][1])  # mnist_train[0][0]是图片、mnist_train[0][1]是标签

3、 两个可视化数据集的函数,来画一下数据集

def get_fashion_mnist_labels(labels):"""返回Fashion-MNIST数据集的文本标签"""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 = d2l.plt.subplots(num_rows, num_cols, figsize=figsize)  # 使用subplots创建子图axes = axes.flatten()for i, (ax, img) in enumerate(zip(axes, imgs)):if torch.is_tensor(img):ax.imshow(img.numpy())  # 图片张量else:ax.imshow(img)  # PIL图片ax.axes.get_xaxis().set_visible(False)ax.axes.get_yaxis().set_visible(False)if titles:ax.set_title(titles[i])return axesX, y = next(iter(data.DataLoader(mnist_train, batch_size=18)))  # 加载批量图片
show_images(X.reshape(18, 28, 28), 2, 9, titles=get_fashion_mnist_labels(y))  # 显示图片并添加标签
d2l.plt.show()  # 图片在线展示

4、 读取一小批量数据,大小batch_size

batch_size = 256
def get_dataloader_workers():"""使用4个进程来读取的数据"""return 0  # 写几就是几个进程train_iter = data.DataLoader(mnist_train, batch_size, shuffle=True, num_workers=get_dataloader_workers())
timer = d2l.Timer()
for X, y in train_iter:continue
print(f'{timer.stop():.2f} sec')

5、 整合所有组件

# 4、整合所有组件
def load_data_fashion_mnist(batch_size, resize=None):"""下载Fashion-MNIST数据集,然后将其加载到内存中"""trans = [transforms.ToTensor()]if resize:trans.insert(0, transforms.Resize(resize))trans = transforms.Compose(trans)mnist_train = torchvision.datasets.FashionMNIST(root="../data", train=True, transform=trans, download=True)mnist_test = torchvision.datasets.FashionMNIST(root="../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()))
# 测试整和组件功能
train_iter, test_iter = load_data_fashion_mnist(32, resize=64)
for X, y in train_iter:print(X.shape, X.dtype, y.shape, y.dtype)break

完整代码:

import torch
import torchvision
from torch.utils import data
from torchvision import transforms
from d2l import torch as d2l# 1、通过框架中的内置函数,将Fashion-MNIST数据集下载并读取到内存中
# 通过ToTensor实例将图像数据从PIL类型变换成32位浮点数格式;并除以255使得所有像素的数值均在0到1之间
trans = transforms.ToTensor()  # 预处理,用于将图片转为tensor
mnist_train = torchvision.datasets.FashionMNIST(root="../data", train=True, transform=trans, download=True)  # 在torchvision.datasets找到FashionMNIST数据集,参数:root="../data"下载目录, train=True下载训练数据集, transform=trans图片转为pytorch的tensor, download=True下载
mnist_test = torchvision.datasets.FashionMNIST(root="../data", train=False, transform=trans, download=True)
print("len(mnist_train):", len(mnist_train), "\nlen(mnist_test):", len(mnist_test))
print("mnist_train[0][0].shape,训练集中第一张图片的形状:", mnist_train[0][0].shape, "\nmnist_train[0][1],训练集中第一张图片的标签:", mnist_train[0][1])  # mnist_train[0][0]是图片、mnist_train[0][1]是标签# 2、两个可视化数据集的函数,来画一下数据集
def get_fashion_mnist_labels(labels):"""返回Fashion-MNIST数据集的文本标签"""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 = d2l.plt.subplots(num_rows, num_cols, figsize=figsize)  # 使用subplots创建子图axes = axes.flatten()for i, (ax, img) in enumerate(zip(axes, imgs)):if torch.is_tensor(img):ax.imshow(img.numpy())  # 图片张量else:ax.imshow(img)  # PIL图片ax.axes.get_xaxis().set_visible(False)ax.axes.get_yaxis().set_visible(False)if titles:ax.set_title(titles[i])return axesX, y = next(iter(data.DataLoader(mnist_train, batch_size=18)))  # 加载批量图片
show_images(X.reshape(18, 28, 28), 2, 9, titles=get_fashion_mnist_labels(y))  # 显示图片并添加标签
# d2l.plt.show()  # 图片在线展示# 3、读取一小批量数据,大小batch_size
batch_size = 256
def get_dataloader_workers():"""使用4个进程来读取的数据"""return 0  # 写几就是几个进程train_iter = data.DataLoader(mnist_train, batch_size, shuffle=True, num_workers=get_dataloader_workers())
timer = d2l.Timer()
for X, y in train_iter:continue
print(f'{timer.stop():.2f} sec')'''
# 4、整合所有组件
def load_data_fashion_mnist(batch_size, resize=None):"""下载Fashion-MNIST数据集,然后将其加载到内存中"""trans = [transforms.ToTensor()]if resize:trans.insert(0, transforms.Resize(resize))trans = transforms.Compose(trans)mnist_train = torchvision.datasets.FashionMNIST(root="../data", train=True, transform=trans, download=True)mnist_test = torchvision.datasets.FashionMNIST(root="../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()))
# 测试整和组件功能
train_iter, test_iter = load_data_fashion_mnist(32, resize=64)
for X, y in train_iter:print(X.shape, X.dtype, y.shape, y.dtype)break
'''

四、从零实现

1、导入库

import torch
from IPython import display
from d2l import torch as d2l

2、数据集

batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)  # 每次读取256张图片,返回训练集、测试集的迭代器:train_iter, test_iter# 将展平每个图像1x28x28=784,将它们视为长度为784的向量(因为对于softmax回归来讲,输入需要是一个向量)。因为我们的数据集有10个类别,所以网络输出维度为10
num_inputs = 784
num_outputs = 10

3、参数初始化

W = torch.normal(0, 0.01, size=(num_inputs, num_outputs), requires_grad=True)  # 均值为0,方差为0.01初始化W权重
b = torch.zeros(num_outputs, requires_grad=True)  # 全0初始化

4、实现softmax

# 实现softmax
def softmax(X):X_exp = torch.exp(X)  # 对每一个元素做指数运算partition = X_exp.sum(1, keepdim=True)  # 按照维度为1来求和,对每一行求和;按行求和并保持维度不变,还是2维矩阵return X_exp / partition  # 这里应用了广播机制,# 实现softmax回归模型
def net(X):return softmax(torch.matmul(X.reshape((-1, W.shape[0])), W) + b)  # 对X reshape使其能够与W做内积

 5、实现交叉熵损失函数

# 实现交叉熵损失函数
def cross_entropy(y_hat, y):return - torch.log(y_hat[range(len(y_hat)), y])

6、 将预测类别与真实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)  # argmax返回每行最大值的索引cmp = y_hat.type(y.dtype) == y  # cmp为01向量,表示y_hat和y相同索引的个数return float(cmp.type(y.dtype).sum())  # 返回cmp中所有相同索引的和

7、 评估任意模型net的精度

# 我们可以评估任意模型net的精度
def evaluate_accuracy(net, data_iter):"""计算在指定数据集上模型的精度"""if isinstance(net, torch.nn.Module):net.eval()  # eval()停用dropout和batchnormmetric = 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]# Accumulator实例中创建了2个变量, 分别用于存储正确预测的数量和预测的总数量
class Accumulator:"""在n个变量上累加"""def __init__(self, n):self.data = [0.0] * ndef 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]

8、Softmax回归的训练

# Softmax回归的训练
def train_epoch_ch3(net, train_iter, loss, updater):"""训练模型一个迭代周期(定义见第3章)"""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.sum().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]# 定义一个在动画中绘制数据的实用程序类
class Animator:"""在动画中绘制数据"""def __init__(self, xlabel=None, ylabel=None, legend=None, xlim=None,ylim=None, xscale='linear', yscale='linear',fmts=('-', 'm--', 'g-.', 'r:'), nrows=1, ncols=1,figsize=(3.5, 2.5)):if legend is None:legend = []d2l.use_svg_display()self.fig, self.axes = d2l.plt.subplots(nrows, ncols, figsize=figsize)if nrows * ncols == 1:self.axes = [self.axes, ]self.config_axes = lambda: d2l.set_axes(self.axes[0], xlabel, ylabel, xlim, ylim, xscale, yscale, legend)self.X, self.Y, self.fmts = None, None, fmtsdef add(self, x, y):if not hasattr(y, "__len__"):y = [y]n = len(y)if not hasattr(x, "__len__"):x = [x] * nif 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)self.axes[0].cla()for x, y, fmt in zip(self.X, self.Y, self.fmts):self.axes[0].plot(x, y, fmt)self.config_axes()display.display(self.fig)display.clear_output(wait=True)# 训练函数
def train_ch3(net, train_iter, test_iter, loss, num_epochs, updater):"""训练模型(定义见第3章)"""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_metricsassert train_loss < 0.5, train_lossassert train_acc <= 1 and train_acc > 0.7, train_accassert test_acc <= 1 and test_acc > 0.7, test_acc# 小批量随机梯度下降来优化模型的损失函数
lr = 0.1
def updater(batch_size):return d2l.sgd([W, b], lr, batch_size)# 训练模型10个迭代周期
num_epochs = 10
train_ch3(net, train_iter, test_iter, cross_entropy, num_epochs, updater) # 调用前面的函数
d2l.plt.show()

 9、对图像进行分类预测

# 对图像进行分类预测
def predict_ch3(net, test_iter, n=6):"""预测标签(定义见第3章)"""for X, y in test_iter:breaktrues = d2l.get_fashion_mnist_labels(y)preds = d2l.get_fashion_mnist_labels(net(X).argmax(axis=1))titles = [true +'\n' + pred for true, pred in zip(trues, preds)]d2l.show_images(X[0:n].reshape((n, 28, 28)), 1, n, titles=titles[0:n])predict_ch3(net, test_iter)
d2l.plt.show()

完整代码:

import torch
from IPython import display
from d2l import torch as d2l# softmax回归的从零开始实现
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)  # 每次读取256张图片,返回训练集、测试集的迭代器:train_iter, test_iter# 将展平每个图像1x28x28=784,将它们视为长度为784的向量(因为对于softmax回归来讲,输入需要是一个向量)。因为我们的数据集有10个类别,所以网络输出维度为10
num_inputs = 784
num_outputs = 10
W = torch.normal(0, 0.01, size=(num_inputs, num_outputs), requires_grad=True)  # 均值为0,方差为0.01初始化W权重
b = torch.zeros(num_outputs, requires_grad=True)  # 全0初始化# 实现softmax
def softmax(X):X_exp = torch.exp(X)  # 对每一个元素做指数运算partition = X_exp.sum(1, keepdim=True)  # 按照维度为1来求和,对每一行求和;按行求和并保持维度不变,还是2维矩阵return X_exp / partition  # 这里应用了广播机制,# 实现softmax回归模型
def net(X):return softmax(torch.matmul(X.reshape((-1, W.shape[0])), W) + b)  # 对X reshape使其能够与W做内积# 实现交叉熵损失函数
def cross_entropy(y_hat, y):return - torch.log(y_hat[range(len(y_hat)), y])# 将预测类别与真实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)  # argmax返回每行最大值的索引cmp = y_hat.type(y.dtype) == y  # cmp为01向量,表示y_hat和y相同索引的个数return float(cmp.type(y.dtype).sum())  # 返回cmp中所有相同索引的和# 我们可以评估在任意模型net的精度
def evaluate_accuracy(net, data_iter):"""计算在指定数据集上模型的精度"""if isinstance(net, torch.nn.Module):net.eval()  # eval()停用dropout和batchnormmetric = 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]# Accumulator实例中创建了2个变量, 分别用于存储正确预测的数量和预测的总数量
class Accumulator:"""在n个变量上累加"""def __init__(self, n):self.data = [0.0] * ndef 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]# Softmax回归的训练
def train_epoch_ch3(net, train_iter, loss, updater):"""训练模型一个迭代周期(定义见第3章)"""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.sum().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]# 定义一个在动画中绘制数据的实用程序类
class Animator:"""在动画中绘制数据"""def __init__(self, xlabel=None, ylabel=None, legend=None, xlim=None,ylim=None, xscale='linear', yscale='linear',fmts=('-', 'm--', 'g-.', 'r:'), nrows=1, ncols=1,figsize=(3.5, 2.5)):if legend is None:legend = []d2l.use_svg_display()self.fig, self.axes = d2l.plt.subplots(nrows, ncols, figsize=figsize)if nrows * ncols == 1:self.axes = [self.axes, ]self.config_axes = lambda: d2l.set_axes(self.axes[0], xlabel, ylabel, xlim, ylim, xscale, yscale, legend)self.X, self.Y, self.fmts = None, None, fmtsdef add(self, x, y):if not hasattr(y, "__len__"):y = [y]n = len(y)if not hasattr(x, "__len__"):x = [x] * nif 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)self.axes[0].cla()for x, y, fmt in zip(self.X, self.Y, self.fmts):self.axes[0].plot(x, y, fmt)self.config_axes()display.display(self.fig)display.clear_output(wait=True)# 训练函数
def train_ch3(net, train_iter, test_iter, loss, num_epochs, updater):"""训练模型(定义见第3章)"""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_metricsassert train_loss < 0.5, train_lossassert train_acc <= 1 and train_acc > 0.7, train_accassert test_acc <= 1 and test_acc > 0.7, test_acc# 小批量随机梯度下降来优化模型的损失函数
lr = 0.1
def updater(batch_size):return d2l.sgd([W, b], lr, batch_size)# 训练模型10个迭代周期
num_epochs = 10
train_ch3(net, train_iter, test_iter, cross_entropy, num_epochs, updater) # 调用前面的函数
d2l.plt.show()# 对图像进行分类预测
def predict_ch3(net, test_iter, n=6):"""预测标签(定义见第3章)"""for X, y in test_iter:breaktrues = d2l.get_fashion_mnist_labels(y)preds = d2l.get_fashion_mnist_labels(net(X).argmax(axis=1))titles = [true +'\n' + pred for true, pred in zip(trues, preds)]d2l.show_images(X[0:n].reshape((n, 28, 28)), 1, n, titles=titles[0:n])predict_ch3(net, test_iter)
d2l.plt.show()

五、简洁实现 

1、导入库

import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2l
from torch import nn

2、 人造数据集,使用线性模型参数 w = [2, -3.4]T、b = 4.2;得到features, labels

# 1、人造数据集,使用线性模型参数 w = [2, -3.4]T、b = 4.2;得到features, labels
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = d2l.synthetic_data(true_w, true_b, 1000)def load_array(data_arrays, batch_size, is_train=True):"""构造一个Pytorch数据迭代"""dataset = data.TensorDataset(*data_arrays)  # 得到数据集,*表示接受任意多个参数并将其放在一个元组中,拆包return data.DataLoader(dataset, batch_size, shuffle=is_train)  # 加载数据集,shuffle表示是否随机打乱batch_size = 10
data_iter = load_array(data_arrays=(features, labels), batch_size=batch_size)  # 把features, labels做成一个list传入到data.TensorDataset,得到数据集datasetprint(next(iter(data_iter)))

3、 模型定义;'nn'是神经网络的缩写

# 2、模型定义;'nn'是神经网络的缩写
# (1)使用框架的预定义好的层
net = nn.Sequential(nn.Linear(2, 1))  # 指定输入维度为2,输出维度为1# (2)初始化模型参数
net[0].weight.data.normal_(0, 0.01)  # 就是对w初始化化为均值为0,方差为0.01的正态分布
net[0].bias.data.fill_(0)  # 就是对b初始化为0

4、 计算均方误差使用的是MSELoss类,也称为 平方范数

# 3、计算均方误差使用的是MSELoss类,也称为 平方范数
loss = nn.MSELoss()

5、 实例化SGD实例,优化器

# 4、实例化SGD实例,优化器
trainer = torch.optim.SGD(net.parameters(), lr=0.03)  # 传入参数、学习率

6、 训练过程

# 5、训练过程
# (1)超参数设置
num_epochs = 3  # 整个数据扫三遍
# (2)训练的实现大同小异,一般就是两层for循环:第一层是每一次对数据扫一遍;第二层是对于每一次拿出一个批量大小的X、y
for epoch in range(num_epochs):for X, y in data_iter:l = loss(net(X), y)  # 把 X 放到模型里面做预测(net本身自己带了模型参数,所以不需要w、b再传入了);把 预测的y 与 真实的y 做损失;得到的损失就是 一个批量大小的向量trainer.zero_grad()  # 优化器梯度清0l.backward()  # 求梯度,此处不用求sum,因为已经自动求完sum了trainer.step()  # 调用step()函数,进行一次模型参数的更新# 对数据扫完一边之后,评价一下进度,此时是不需要梯度的,l = loss(net(features), labels)print(f"epoch {epoch + 1}, loss {l:f}") # 打印评估的结果

完整代码:

import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2l
from torch import nn# 线性回归的简洁实现(使用深度学习框架提供的计算);包括数据流水线、模型、损失函数和小批量随机梯度下降优化器
# 1、人造数据集,使用线性模型参数 w = [2, -3.4]T、b = 4.2;得到features, labels
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = d2l.synthetic_data(true_w, true_b, 1000)def load_array(data_arrays, batch_size, is_train=True):"""构造一个Pytorch数据迭代"""dataset = data.TensorDataset(*data_arrays)  # 得到数据集,*表示接受任意多个参数并将其放在一个元组中,拆包return data.DataLoader(dataset, batch_size, shuffle=is_train)  # 加载数据集,shuffle表示是否随机打乱batch_size = 10
data_iter = load_array(data_arrays=(features, labels), batch_size=batch_size)  # 把features, labels做成一个list传入到data.TensorDataset,得到数据集datasetprint(next(iter(data_iter)))# 2、模型定义;'nn'是神经网络的缩写
# (1)使用框架的预定义好的层
net = nn.Sequential(nn.Linear(2, 1))  # 指定输入维度为2,输出维度为1# (2)初始化模型参数
net[0].weight.data.normal_(0, 0.01)  # 就是对w初始化化为均值为0,方差为0.01的正态分布
net[0].bias.data.fill_(0)  # 就是对b初始化为0# 3、计算均方误差使用的是MSELoss类,也称为 平方范数
loss = nn.MSELoss()# 4、实例化SGD实例,优化器
trainer = torch.optim.SGD(net.parameters(), lr=0.03)  # 传入参数、学习率# 5、训练过程
# (1)超参数设置
num_epochs = 3  # 整个数据扫三遍
# (2)训练的实现大同小异,一般就是两层for循环:第一层是每一次对数据扫一遍;第二层是对于每一次拿出一个批量大小的X、y
for epoch in range(num_epochs):for X, y in data_iter:l = loss(net(X), y)  # 把 X 放到模型里面做预测(net本身自己带了模型参数,所以不需要w、b再传入了);把 预测的y 与 真实的y 做损失;得到的损失就是 一个批量大小的向量trainer.zero_grad()  # 优化器梯度清0l.backward()  # 求梯度,此处不用求sum,因为已经自动求完sum了trainer.step()  # 调用step()函数,进行一次模型参数的更新# 对数据扫完一边之后,评价一下进度,此时是不需要梯度的,l = loss(net(features), labels)print(f"epoch {epoch + 1}, loss {l:f}") # 打印评估的结果

如果此文章对您有所帮助,那就请点个赞吧,收藏+关注 那就更棒啦,十分感谢!!! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/80544.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++八股——内存分配

文章目录 1. 虚拟内存空间2. malloc和free3. new和delete4. 内存池 1. 虚拟内存空间 程序进程的虚拟内存空间是操作系统为每个进程提供的独立、连续的逻辑地址空间&#xff0c;与物理内存解耦。其核心目的是隔离进程、简化内存管理&#xff0c;并提供灵活的内存访问控制。 &am…

【Linux基础】网络相关命令

目录 netstat命令 1.1 命令介绍 1.2 命令格式 1.3 常用选项 1.4 常用命令实例 1.4.1 显示所有TCP连接 1.4.2 查看路由表 1.4.3 实时监控网络接口流量 1.4.4 查看监听中的端口以及关联进程 ping命令 2.1 命令介绍 2.2 命令格式 2.3 常用选项 2.4 常用示例 ifconfi…

adb 实用命令汇总

版权归作者所有&#xff0c;如有转发&#xff0c;请注明文章出处&#xff1a;https://cyrus-studio.github.io/blog/ 基础adb命令 # 重启adb adb kill-server# 查看已连接的设备 adb devices# 进入命令行 adb shell# 使用 -s 参数来指定设备 adb -s <设备序列号> shell…

C#管道通讯及传输信息丢失的原因

以下是C#管道通讯客户端/服务端共用类 namespace PipeCommunication { /// <summary> /// 管道信息回调通知 /// </summary> /// <param name"msg"></param> public delegate void PipeMessageEventHandler(string msg…

MixTeX - 支持CPU推理的多模态LaTeX OCR

文章目录 一、项目概览相关资源核心特性技术特点 二、安装三、使用说明环境要求 四、版本更新五、当前限制 一、项目概览 MixTeX是一款创新的多模态LaTeX识别小程序&#xff0c;支持本地离线环境下的高效CPU推理。 无论是LaTeX公式、表格还是混合文本&#xff0c;MixTeX都能轻…

简单 Linux 字符设备驱动程序

注&#xff1a;本文为 “Linux 字符设备驱动” 相关文章合辑。 英文引文&#xff0c;机翻未校。 中文引文&#xff0c;略作重排。 未整理去重&#xff0c;如有内容异常&#xff0c;请看原文。 Simple Linux character device driver 简单 Linux 字符设备驱动程序 Oleg Kutko…

NX949NX952美光科技闪存NX961NX964

NX949NX952美光科技闪存NX961NX964 在半导体存储领域&#xff0c;美光科技始终扮演着技术引领者的角色。其NX系列闪存产品线凭借卓越的性能与创新设计&#xff0c;成为数据中心、人工智能、高端消费电子等场景的核心组件。本文将围绕NX949、NX952、NX961及NX964四款代表性产品…

协议路由与路由协议

协议路由”和“路由协议”听起来相似&#xff0c;但其实是两个完全不同的网络概念。下面我来分别解释&#xff1a; 一、协议路由&#xff08;Policy-Based Routing&#xff0c;PBR&#xff09; ✅ 定义&#xff1a; 协议路由是指 根据预设策略&#xff08;策略路由&#xff0…

Linux510 ssh服务 ssh连接

arning: Permanently added ‘11.1.1.100’ (ECDSA) to the list of known hosts. rooot11.1.1.100’s password: Permission denied, please try again. rooot11.1.1.100’s password: Permission denied, please try again 还没生效 登不上了 失效了 sshcaozx26成功登录 …

金融学知识笔记

金融学知识笔记 一、引言 金融学它结合了数学、概率论、统计学、经济学和计算机科学等多学科的知识&#xff0c;用于解决金融领域中的各种问题&#xff0c;如金融衍生品定价、投资组合优化、风险管理和固定收益证券分析等。通过对金融学的学习&#xff0c;我们可以更好地理解…

AB测试面试题

AB测试面试题 常考AB测试问答题(1)AB测试的优缺点是什么?(2)AB测试的一般流程/介绍一下日常工作中你是如何做A/B实验的?(3)第一类错误 vs 第二类错误 vs 你怎么理解AB测试中的第一、二类错误?(4)统计显著=实际显著?(5)AB测试效果统计上不显著?(6)实验组优于对…

USR-M100采集数据并提交MQTT服务器

本文为记录备忘&#xff0c;不做过多解释。 模块自身带有2路数字量输入&#xff0c;2路模拟量输入&#xff0c;2路485接口 数字量接报警输入&#xff0c;模拟量接压力传感器&#xff0c;液位传感器&#xff0c;485接口分别接流量计&#xff0c;温湿度传感器。 正确接线&…

Octave 绘图快速入门指南

目录 1. 基本的 2D 绘图 2. 自定义图形样式 3. 绘制散点图 4. 绘制柱状图 5. 绘制直方图 6. 3D 绘图 6.6.1 3D 曲面图 6.6.2 3D 散点图 7. 绘制极坐标 8. 多子图绘制 总结 Octave 是一个类似于 MATLAB 的开源数学软件&#xff0c;广泛用于数值计算和数据分析。它提供…

RabbitMQ--基础篇

RabbitMQ 简介&#xff1a;RabbitMQ 是一种开源的消息队列中间件&#xff0c;你可以把它想象成一个高效的“邮局”。它专门负责在不同应用程序之间传递消息&#xff0c;让系统各部分能松耦合地协作 优势&#xff1a; 异步处理&#xff1a;比如用户注册后&#xff0c;主程序将发…

【MySQL】事务(重点)

目录 一、什么是事务&#xff1a; 二、事务的前置知识了解 引擎是否支持事务 事务的提交方式 事务操作的前置准备&#xff1a; 三、事务回滚&#xff1a; 四、事务崩溃&#xff1a; 原子性&#xff1a; 持久性&#xff1a; 五、自动提交和手动提交&#xff1a; 六、…

C++STL——stack,queue

stack与queue 前言容器适配器deque 前言 本篇主要讲解stack与queue的底层&#xff0c;但并不会进行实现&#xff0c;stack的接口 queue的接口 &#xff0c;关于stack与queue的接口在这里不做讲解&#xff0c;因为通过前面的对STL的学习&#xff0c;这些接口都是大同小异的。 …

STM32智能手表:基于FreeRTOS

引言 随着物联网和可穿戴设备的快速发展&#xff0c;智能手表作为典型代表&#xff0c;集成了传感器数据采集、实时显示、无线通信等多项功能。本文将深入剖析一个基于STM32和FreeRTOS的智能手表项目&#xff0c;从硬件架构到软件设计&#xff0c;逐步讲解如何构建一个完整的嵌…

leetcode504.七进制数

标签&#xff1a;进制转换 机试真题 给定一个整数 num&#xff0c;将其转化为 7 进制&#xff0c;并以字符串形式输出。 示例 1: 输入: num 100 输出: "202" 示例 2: 输入: num -7 输出: "-10" 思路&#xff1a;求n进制就是循环取余数&#xff0c;…

中国古代史2

夏朝&#xff08;公元前2070-公元前1600年&#xff09; 1.禹建立了我国历史上第一个奴隶制国家–夏朝&#xff0c;定都阳城。禹传启&#xff0c;世袭制代替禅让制。 2.夏代都城&#xff1a;二里头遗址位于今河南洛阳偃师二里头村。发现了大型绿松石龙形器&#xff0c;被命名为…

死锁的形成

死锁的形成 背景学习资源死锁的本质 背景 面试可能会被问到. 学习资源 一个案例: https://www.bilibili.com/video/BV1pz421Y7kM 死锁的本质 互相持有对方的资源. 存在资源竞争都没有释放. 可能出现死锁. insert into demo_user (no, name) values (6, ‘test1’) on dupl…