动手学深度学习V2每日笔记(权重衰退+Dropout)

news2024/11/17 4:47:46

本文主要参考沐神的视频教程 https://www.bilibili.com/video/BV1UK4y1o7dy/vd_source=c7bfc6ce0ea0cbe43aa288ba2713e56d
文档教程 https://zh-v2.d2l.ai/

本文的主要内容对沐神提供的代码中个人不太理解的内容进行笔记记录,内容不会特别严谨仅供参考。

1.函数目录

1.1 python

python位置
Lambda 函数3.1

1.2 torch

python位置
torch.utils.data.TensorDataset3.1
torch.optim.SGD3.6
torch.nn.MSELoss3.6
torch.Tensor.uniform_4.1
torch.nn.Dropout4.2

2. 权重衰退

控制模型的容量的主要方法:

  1. 模型参数比较少
  2. 每个参数值选择的范围比较小
    权重衰退就是控制参数值的大小。

2.1 使用均方范数作为硬性限制

  • 通过限制参数值的选择范围来控制模型容量
    m i n   l ( w , b ) s u b j e c t   t o   ∣ ∣ w ∣ ∣ 2 ≤ θ min\ l(w,b) \quad subject\ to\ ||w||^2≤\theta min l(w,b)subject to ∣∣w2θ
  • 通常不限制偏移b(限不限制都差不多)
  • 小的 θ \theta θ意味着更强的正则化
  • 正则化是用来防止模型过拟合而采取的手段

2.2 使用均方范数作为柔性限制

  • 对于每个 θ \theta θ,都可以找到 λ \lambda λ使得之前的目标函数等价于下面
    m i n   l ( w , b ) + λ 2 ∣ ∣ w ∣ ∣ 2 min\ l(w,b) + \frac{\lambda}{2}||w||^2 min l(w,b)+2λ∣∣w2
  • 超参数 λ \lambda λ控制了正则项的重要程度
  • λ = 0 : \lambda=0: λ=0:无作用
  • λ → + ∞ ,   w ∗ → 0 \lambda\to +\infty,\ w^*\to0 λ+, w0
    在这里插入图片描述

2.3 参数更新法则

  • 计算梯度
    d d w ( l ( w , b ) + λ 2 ∣ ∣ w ∣ ∣ 2 ) = d l ( w , b ) d w + λ w \frac{d}{dw}(l(w,b)+\frac{\lambda}{2}||w||^2)=\frac{dl(w,b)}{dw}+\lambda w dwd(l(w,b)+2λ∣∣w2)=dwdl(w,b)+λw
    w t + 1 = w t − η λ w t − η d l ( w , b ) d w w_{t+1}=w_t-\eta \lambda w_t-\eta \frac{dl(w,b)}{dw} wt+1=wtηλwtηdwdl(w,b)
  • 通常 η λ < 1 \eta \lambda<1 ηλ1,在深度学习中通常叫做权重衰退

3 代码实现

3.1 高维线性回归

3.1.1 Lambda 函数

Lambda 函数,也叫匿名函数,是 Python 中用于创建小型、临时函数的一种方法。Lambda 函数没有名字,是一次性使用的,通常用于简化代码。它们可以作为参数传递给其他函数,或在需要一个短小的函数时使用。

lambda arguments: expression
  • lambda 关键字用于定义匿名函数。
  • arguments 是输入参数,可以有多个,参数之间用逗号分隔。
  • expression 是一个单一的表达式,计算并返回结果。
# 定义一个 lambda 函数,计算两个数的和
sum = lambda x, y: x + y
print(sum(3, 5))  # 输出 8
  • 产生线性数据
#true_w.shape=[200,1]
def synthetic_data(true_w, true_b, n_train):
    """Generate y = Xw + b + noise."""
    X = torch.normal(0, 1, size=(n_train, len(true_w)))#X.shape=[20, 200]
    y = torch.matmul(X, true_w) + true_b
    y += torch.normal(0, 0.01, y.shape)
    return X, d2l.reshape(y, (-1, 1))

3.1.2 torch.utils.data.TensorDataset

torch.utils.data.TensorDataset 是 PyTorch 中的数据工具类,用于将多个张量包装成一个数据集对象。这个数据集对象可以与 DataLoader 一起使用,以方便地进行批量数据加载和迭代。
每个样本将通过沿第一个维度索引张量来检索。第一个维度索引是指在张量的第 0 维度上进行索引操作。

import torch
from torch.utils.data import TensorDataset, DataLoader
# 示例数据
x = torch.tensor([[1, 2], [3, 4], [5, 6]])
y = torch.tensor([1, 2, 3])

# 创建 TensorDataset
dataset = TensorDataset(x, y)
# 创建 DataLoader
dataloader = DataLoader(dataset, batch_size=2, shuffle=True)
# 迭代数据
for batch in dataloader:
    features, labels = batch
    print(features, labels)

在这里插入图片描述

  • 加载数据
def load_array(data_arrays, batch_size, is_train=True):
    """Construct a PyTorch data iterator."""
    dataset = torch.utils.data.TensorDataset(*data_arrays)
    return torch.utils.data.DataLoader(dataset, batch_size, shuffle=is_train)
def synthetic_data(true_w, true_b, n_train):
    """Generate y = Xw + b + noise."""
    X = torch.normal(0, 1, size=(n_train, len(true_w)))#X.shape=[20, 200]
    y = torch.matmul(X, true_w) + true_b
    y += torch.normal(0, 0.01, y.shape)
    return X, d2l.reshape(y, (-1, 1))

def load_array(data_arrays, batch_size, is_train=True):
    """Construct a PyTorch data iterator."""
    dataset = torch.utils.data.TensorDataset(*data_arrays)
    return torch.utils.data.DataLoader(dataset, batch_size, shuffle=is_train)

n_train, n_test, num_inputs, batch_size = 20, 100, 200, 5
true_w, true_b = torch.ones((num_inputs, 1)) * 0.01, 0.05
#true_w.shape=[200,1]
train_data = synthetic_data(true_w, true_b, n_train)
train_iter = load_array(train_data, batch_size)
test_data = synthetic_data(true_w,true_b, n_test)
test_iter = load_array(test_data, batch_size)
X,y = next(iter(test_iter))
print(X.shape, y.shape)

3.2 初始化参数模型

def init_params():
    w = torch.normal(0, 1, size=(num_inputs, 1), requires_grad=True)
    b = torch.zeros(1, requires_grad=True)
    return [w, b]

3.3 定义 l 2 l_2 l2范数惩罚

实现这一惩罚最方便的方法是对所有项求平方后并将它们求和

# 定义L2范数惩罚
def l2_penalty(w):
    return torch.sum(w.pow(2))/2
a = torch.tensor([1, 2, 3])
print(l2_penalty(a)) #输出为tensor(7.)

3.4 训练

def train(lambd):
    w, b = init_params()
    net, loss = lambda X:linreg(X, w, b), d2l.squared_loss
    num_epochs, lr = 100, 0.003
    # 训练集损失列表
    train_loss_all = []
    # 验证集损失列表
    val_loss_all = []
    for epoch in range(num_epochs):
        for X,y in train_iter:
            l = loss(net(X), y) + lambd * l2_penalty(w)
            l.sum().backward()
            d2l.sgd([w, b], lr, batch_size)
        train_loss = d2l.evaluate_loss(net, train_iter, loss)
        val_loss = d2l.evaluate_loss(net, test_iter, loss)
        train_loss_all.append(train_loss)
        val_loss_all.append(val_loss)
    train_process = pd.DataFrame(data={"epoch": range(num_epochs),
                                       "train_loss_all": train_loss_all,
                                       "val_loss_all": val_loss_all,
                                       })
    return train_process

3.5 完整代码

import pandas as pd
import torch
import matplotlib.pyplot as plt
from torch import nn
from d2l import torch as d2l

def synthetic_data(true_w, true_b, n_train):
    """Generate y = Xw + b + noise."""
    X = torch.normal(0, 1, size=(n_train, len(true_w)))#X.shape=[20, 200]
    y = torch.matmul(X, true_w) + true_b
    y += torch.normal(0, 0.01, y.shape)
    return X, d2l.reshape(y, (-1, 1))

def load_array(data_arrays, batch_size, is_train=True):
    """Construct a PyTorch data iterator."""
    dataset = torch.utils.data.TensorDataset(*data_arrays)
    return torch.utils.data.DataLoader(dataset, batch_size, shuffle=is_train)

def matplot_acc_loss(train_process):
    # 显示每一次迭代后的训练集和验证集的损失函数和准确率
    plt.figure(figsize=(12, 4))
    plt.subplot(1, 1, 1)
    plt.plot(train_process['epoch'], train_process.train_loss_all, "ro-", label="Train loss")
    plt.plot(train_process['epoch'], train_process.val_loss_all, "bs-", label="Val loss")
    plt.legend()
    plt.xlabel("epoch")
    plt.ylabel("Loss")
    plt.show()

def linreg(X, w, b):
    """The linear regression model.

        Defined in :numref:`sec_utils`"""
    return torch.matmul(X, w)+b

n_train, n_test, num_inputs, batch_size = 20, 100, 200, 5
true_w, true_b = torch.ones((num_inputs, 1)) * 0.01, 0.05
#true_w.shape=[200,1]
train_data = synthetic_data(true_w, true_b, n_train)
train_iter = load_array(train_data, batch_size)
test_data = synthetic_data(true_w,true_b, n_test)
test_iter = load_array(test_data, batch_size)
X,y = next(iter(test_iter))
print(X.shape, y.shape)
# 初始化参数模型
def init_params():
    w = torch.normal(0, 1, size=(num_inputs, 1), requires_grad=True)
    b = torch.zeros(1, requires_grad=True)
    return [w, b]
# 定义L2范数惩罚
def l2_penalty(w):
    return torch.sum(w.pow(2))/2
# a = torch.tensor([1, 2, 3])
# print(l2_penalty(a))
# 训练
def train(lambd):
    w, b = init_params()
    net, loss = lambda X:linreg(X, w, b), d2l.squared_loss
    num_epochs, lr = 100, 0.003
    # 训练集损失列表
    train_loss_all = []
    # 验证集损失列表
    val_loss_all = []
    for epoch in range(num_epochs):
        for X,y in train_iter:
            l = loss(net(X), y) + lambd * l2_penalty(w)
            l.sum().backward()
            d2l.sgd([w, b], lr, batch_size)
        train_loss = d2l.evaluate_loss(net, train_iter, loss)
        val_loss = d2l.evaluate_loss(net, test_iter, loss)
        train_loss_all.append(train_loss)
        val_loss_all.append(val_loss)
    train_process = pd.DataFrame(data={"epoch": range(num_epochs),
                                       "train_loss_all": train_loss_all,
                                       "val_loss_all": val_loss_all,
                                       })
    return train_process

train_process = train(3)
matplot_acc_loss(train_process)

3.6 简洁实现

3.6.1 torch.optim.SGD

torch.optim.SGD 是 PyTorch 提供的标准随机梯度下降优化器(Stochastic Gradient Descent)。它适用于大多数深度学习模型的优化过程,可以通过添加动量、权重衰减(L2正则化)和 Nesterov 加速梯度来增强其性能。

torch.optim.SGD(params, lr=<required parameter>, momentum=0, dampening=0, weight_decay=0, nesterov=False)
  • 参数说明
  • params:待优化的模型参数,一般通过 model.parameters() 传递。
  • lr (float):学习率,是控制参数更新步伐的关键超参数。
  • momentum (float, 可选):动量因子,用于加速收敛并减少振荡(默认:0)。
  • dampening (float, 可选):动量抑制因子,用于控制动量的累积(默认:0)。
  • weight_decay (float, 可选):权重衰减(L2正则化)因子,用于防止过拟合(默认:0)。
  • nesterov (bool, 可选):是否使用 Nesterov 加速梯度(默认:False)。

3.6.2 torch.nn.MSELoss

nn.MSELoss 是 PyTorch 中的一个损失函数类,用于计算均方误差(Mean Squared Error, MSE)。该损失函数通常用于回归任务中,评估预测值与实际值之间的差异。通过设置 reduction 参数,可以控制损失值的计算方式。

torch.nn.MSELoss(size_average=None, reduce=None, reduction='mean')
  • 参数说明
  • reduction (string, 可选):指定损失值的聚合方式。可以取以下值:
  • ‘none’:不进行任何聚合,返回每个样本的损失值。
  • ‘mean’:返回所有样本损失值的平均值(默认)。
  • ‘sum’:返回所有样本损失值的总和。
import torch
import torch.nn as nn

# 定义均方误差损失函数,不进行聚合
loss_fn = nn.MSELoss(reduction='none')

# 假设有一些预测值和目标值
predictions = torch.tensor([[2.5, 0.0], [1.5, -0.5], [3.0, 2.0]], requires_grad=True)
targets = torch.tensor([[3.0, -0.5], [1.0, 0.0], [2.0, 2.0]])

# 计算损失值
loss = loss_fn(predictions, targets)

print(loss)  # 打印每个样本的损失值

# 如果需要,可以手动计算损失值的平均值或总和
mean_loss = loss.mean()
sum_loss = loss.sum()

print(mean_loss)  # 打印损失值的平均值
print(sum_loss)   # 打印损失值的总和

在这里插入图片描述

def train_concise(wd):
    net = nn.Sequential(nn.Linear(num_inputs, 1))
    for param in net.parameters():
        param.data.normal_()
    loss = nn.MSELoss(reduction='none')
    num_epochs, lr = 100, 0.003
    # 将 weight_decay 应用于 net[0].weight,而不应用于 net[0].bias。
    trainer = torch.optim.SGD([{"params": net[0].weight, "weight_decay":wd},
                               {"params": net[0].bias}], lr=lr)
    train_loss_all = []
    val_loss_all = []
    for epoch in range(num_epochs):
        for X,y in train_iter:
            trainer.zero_grad()
            l = loss(net(X), y)
            l.mean().backward()
            trainer.step()
        train_loss = d2l.evaluate_loss(net, train_iter, loss)
        val_loss = d2l.evaluate_loss(net, test_iter, loss)
        train_loss_all.append(train_loss)
        val_loss_all.append(val_loss)
    train_process = pd.DataFrame(data={'epoch':range(num_epochs),
                                       "train_loss_all":train_loss_all,
                                       "val_loss_all":val_loss_all})
    return train_process

4. 丢弃法

一个好的模型需要对输入数据的扰动鲁棒

  • 使用有噪音的数据等价于Tikhonov正则
  • 丢弃法:在层之间加入噪声
    无偏差的加入噪声
  • 对x加入噪声得到x’,我们希望
    E [ x ′ ] = x E[x']=x E[x]=x
  • 丢弃法对每个元素进行如下扰动:
    x i ′ = { 0   w i t h   p r o b a b l i t y   p x i 1 − p   o t h e r i s e x'_i=\left\{ \begin{array}{c} 0 \ with\ probablity\ p \\ \frac{x_i}{1-p} \ otherise \\ \end{array} \right. xi={0 with probablity p1pxi otherise
    通常将丢弃法作用在隐藏全连接层的输出上
    在这里插入图片描述
  • 丢弃法将一些输出项随机置0来控制模型复杂度
  • 常作用在多层感知机的隐藏层输出上
  • 丢弃概率是控制模型复杂度的超参数

4.1 dropout实现

4.1.1 torch.Tensor.uniform_()

torch.Tensor.uniform_() 是一个用于填充张量的内置方法。它将张量的元素用来自均匀分布的随机数替换。通常用于初始化模型参数。

uniform_(from=0, to=1) → Tensor

参数

  • from:均匀分布的下界(默认值为0)。
  • to:均匀分布的上界(默认值为1)。
import torch

# 创建一个形状为(3, 3)的张量
tensor = torch.empty(3, 3)

# 使用uniform_方法将张量的元素初始化为均匀分布[0, 1)范围内的随机数
tensor.uniform_(0, 1)
print(tensor)

# 使用uniform_方法将张量的元素初始化为均匀分布[-1, 1)范围内的随机数
tensor.uniform_(-1, 1)
print(tensor)

在这里插入图片描述

def dropout_layer(X, dropout):
    assert 0 <= dropout <= 1
    if dropout == 0:
        return torch.zeros_like(X)
    if dropout == 1:
        return X
    mask = (torch.Tensor(X.shape).uniform_(0, 1) > dropout).float()
    return mask * X / (1.0 - dropout)
x = torch.arange(16, dtype=torch.float32).reshape((2,8))
print(x)
print(dropout_layer(x, 0))
print(dropout_layer(x, 0.5))
print(dropout_layer(x, 1.0))

4.2 定义模型

4.2.1 nn.Dropout

nn.Dropout 是 PyTorch 中的一种正则化技术,用于防止神经网络中的过拟合。它通过在训练过程中随机将一部分神经元的输出设为 0 来实现这一点。这种做法可以迫使网络的其余部分学习更稳健的特征,因为它不能依赖于某些特定的神经元。

import torch.nn as nn
dropout = nn.Dropout(p=0.5)
  • p:指定每个神经元在训练时被丢弃的概率。取值范围是 [0, 1),通常设为 0.5。
    训练和评估模式
    Dropout 层在训练和评估(推理)模式下表现不同:

训练模式:在训练模式下,Dropout 会按照指定的概率 p 随机丢弃神经元的输出。
评估模式:在评估模式下,Dropout 不会丢弃任何神经元的输出。即使在训练过程中应Dropout,在评估时网络的所有神经元都会参与计算。
可以通过 model.train() 和 model.eval() 来切换这两种模式。

net = nn.Sequential(nn.Flatten(),
        nn.Linear(784, 256),
        nn.ReLU(),
        # 在第一个全连接层之后添加一个dropout层
        nn.Dropout(0.5),
        nn.Linear(256, 256),
        nn.ReLU(),
        # 在第二个全连接层之后添加一个dropout层
        nn.Dropout(0.2),
        nn.Linear(256, 10))
num_inputs, num_outputs, num_hiddens1, num_hiddens2 = 28*28, 10, 256, 256
dropout1, dropout2 = 0.2, 0.5
class Net(nn.Module):
    def __init__(self, num_inputs, num_outputs, num_hiddens1, num_hiddens2, is_training = True):
        super(Net, self).__init__()
        self.training = is_training
        self.h1 = nn.Linear(num_inputs, num_hiddens1)
        self.h2 = nn.Linear(num_hiddens1, num_hiddens2)
        self.h3 = nn.Linear(num_hiddens2, num_outputs)
        self.Relu = nn.ReLU()

    def forward(self, x):
        x = x.view(-1, num_inputs)  # 将输入形状调整为 [batch_size, num_inputs]
        H1 = self.Relu(self.h1(x))
        if self.training == True:
            H1 = dropout_layer(H1, dropout1)
        H2 = self.Relu(self.h2(H1))
        if self.training == True:
            H2 = dropout_layer(H2, dropout2)
        out = self.h3(H2)
        return out

net = Net(num_inputs, num_outputs, num_hiddens1, num_hiddens2)
x = torch.rand(size=(1,28*28),dtype=torch.float32)
def print_layer_outputs(net, x):
    for name, layer in net.named_children():
        x = layer(x)
        print(f"{name} output shape: {x.shape}")

print_layer_outputs(net, x)

4.3 训练和测试

def train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer):
    argmax = lambda x, *args, **kwargs: x.argmax(*args, **kwargs)
    astype = lambda x, *args, **kwargs: x.type(*args, **kwargs) #转换数据类型
    reduce_sum = lambda x, *args, **kwargs: x.sum(*args, **kwargs) #求和
    # 对n个变量求和
    class Accumulator:
        """For accumulating sums over `n` variables."""
        def __init__(self, n):
            """Defined in :numref:`sec_utils`"""
            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 accuracy(y_hat, y):
        """Compute the number of correct predictions.
        Defined in :numref:`sec_utils`"""
        if len(y_hat.shape) > 1 and y_hat.shape[1] > 1:
            y_hat = argmax(y_hat, axis=1)
        cmp = astype(y_hat, y.dtype) == y
        return float(reduce_sum(astype(cmp, y.dtype)))
    # 单轮训练
    def train_epoch(net, train_iter, loss, trainer):
        if isinstance(net, nn.Module):
            net.train()
        metric_train = Accumulator(3)
        for X, y in train_iter:
            y_hat = net(X)
            l = loss(y_hat, y)
            if isinstance(trainer, torch.optim.Optimizer):
                trainer.zero_grad()
                l.mean().backward()
                trainer.step()
            else:
                l.sum().backward()
                trainer(X.shape[0])
            metric_train.add(float(l.sum()), accuracy(y_hat, y), y.numel())
        #返回训练损失和训练精度
        return metric_train[0]/metric_train[2], metric_train[1]/metric_train[2]
    # 用于计算验证集上的准确率
    def evalution_loss_accuracy(net, loss, data_iter):
        if isinstance(net, torch.nn.Module):
            net.eval()
        meteric = Accumulator(3)
        with torch.no_grad():
            for X, y in data_iter:
                l = loss(net(X), y)
                meteric.add(float(l.sum()), accuracy(net(X), y), y.numel())
        return meteric[0]/meteric[2], meteric[1]/meteric[2],
    # 训练集损失列表
    train_loss_all = []
    # 验证集损失列表
    val_loss_all = []
    # 训练集准确度列表
    train_acc_all = []
    # 验证集准确度列表
    val_acc_all = []
    for epoch in range(num_epochs):
        print("Epoch {}/{}".format(epoch, num_epochs - 1))
        print("-" * 10)
        train_metrics = train_epoch(net, train_iter, loss, trainer)
        print("{} train loss:{:.4f} train acc: {:.4f}".format(epoch, train_metrics[0], train_metrics[1]))
        # print(train_metrics)
        test_metrics = evalution_loss_accuracy(net, loss, test_iter)
        print("{} train loss:{:.4f} train acc: {:.4f}".format(epoch, test_metrics[0], test_metrics[1]))
        train_loss_all.append(train_metrics[0])
        train_acc_all.append(train_metrics[1])
        val_loss_all.append(test_metrics[0])
        val_acc_all.append(test_metrics[1])
    train_process = pd.DataFrame(data={"epoch": range(num_epochs),
                                       "train_loss_all": train_loss_all,
                                       "val_loss_all": val_loss_all,
                                       "train_acc_all": train_acc_all,
                                       "val_acc_all": val_acc_all
                                       })
    return train_process

def matplot_acc_loss(train_process):
    # 显示每一次迭代后的训练集和验证集的损失函数和准确率
    plt.figure(figsize=(12, 4))
    plt.subplot(1, 2, 1)
    plt.plot(train_process['epoch'], train_process.train_loss_all, "ro-", label="Train loss")
    plt.plot(train_process['epoch'], train_process.val_loss_all, "bs-", label="Val loss")
    plt.legend()
    plt.xlabel("epoch")
    plt.ylabel("Loss")
    plt.subplot(1, 2, 2)
    plt.plot(train_process['epoch'], train_process.train_acc_all, "ro-", label="Train acc")
    plt.plot(train_process['epoch'], train_process.val_acc_all, "bs-", label="Val acc")
    plt.xlabel("epoch")
    plt.ylabel("acc")
    plt.legend()
    plt.show()

4.4 完整代码

import pandas as pd
import torch
import matplotlib.pyplot as plt
from torch import nn
from d2l import torch as d2l

def dropout_layer(X, dropout):
    assert 0 <= dropout <= 1
    if dropout == 0:
        return torch.zeros_like(X)
    if dropout == 1:
        return X
    mask = (torch.Tensor(X.shape).uniform_(0, 1) > dropout).float()
    return mask * X / (1.0 - dropout)
x = torch.arange(16, dtype=torch.float32).reshape((2,8))
# print(x)
# print(dropout_layer(x, 0))
# print(dropout_layer(x, 0.5))
# print(dropout_layer(x, 1.0))

num_inputs, num_outputs, num_hiddens1, num_hiddens2 = 28*28, 10, 256, 256
dropout1, dropout2 = 0.2, 0.5
class Net(nn.Module):
    def __init__(self, num_inputs, num_outputs, num_hiddens1, num_hiddens2, is_training = True):
        super(Net, self).__init__()
        self.training = is_training
        self.h1 = nn.Linear(num_inputs, num_hiddens1)
        self.h2 = nn.Linear(num_hiddens1, num_hiddens2)
        self.h3 = nn.Linear(num_hiddens2, num_outputs)
        self.Relu = nn.ReLU()

    def forward(self, x):
        x = x.view(-1, num_inputs)  # 将输入形状调整为 [batch_size, num_inputs]
        H1 = self.Relu(self.h1(x))
        if self.training == True:
            H1 = dropout_layer(H1, dropout1)
        H2 = self.Relu(self.h2(H1))
        if self.training == True:
            H2 = dropout_layer(H2, dropout2)
        out = self.h3(H2)
        return out
# x = torch.rand(size=(1,28*28),dtype=torch.float32)
# def print_layer_outputs(net, x):
#     for name, layer in net.named_children():
#         x = layer(x)
#         print(f"{name} output shape: {x.shape}")
#
# print_layer_outputs(net, x)
def train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer):
    argmax = lambda x, *args, **kwargs: x.argmax(*args, **kwargs)
    astype = lambda x, *args, **kwargs: x.type(*args, **kwargs) #转换数据类型
    reduce_sum = lambda x, *args, **kwargs: x.sum(*args, **kwargs) #求和
    # 对n个变量求和
    class Accumulator:
        """For accumulating sums over `n` variables."""
        def __init__(self, n):
            """Defined in :numref:`sec_utils`"""
            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 accuracy(y_hat, y):
        """Compute the number of correct predictions.
        Defined in :numref:`sec_utils`"""
        if len(y_hat.shape) > 1 and y_hat.shape[1] > 1:
            y_hat = argmax(y_hat, axis=1)
        cmp = astype(y_hat, y.dtype) == y
        return float(reduce_sum(astype(cmp, y.dtype)))
    # 单轮训练
    def train_epoch(net, train_iter, loss, trainer):
        if isinstance(net, nn.Module):
            net.train()
        metric_train = Accumulator(3)
        for X, y in train_iter:
            y_hat = net(X)
            l = loss(y_hat, y)
            if isinstance(trainer, torch.optim.Optimizer):
                trainer.zero_grad()
                l.mean().backward()
                trainer.step()
            else:
                l.sum().backward()
                trainer(X.shape[0])
            metric_train.add(float(l.sum()), accuracy(y_hat, y), y.numel())
        #返回训练损失和训练精度
        return metric_train[0]/metric_train[2], metric_train[1]/metric_train[2]
    # 用于计算验证集上的准确率
    def evalution_loss_accuracy(net, loss, data_iter):
        if isinstance(net, torch.nn.Module):
            net.eval()
        meteric = Accumulator(3)
        with torch.no_grad():
            for X, y in data_iter:
                l = loss(net(X), y)
                meteric.add(float(l.sum()), accuracy(net(X), y), y.numel())
        return meteric[0]/meteric[2], meteric[1]/meteric[2]
    # 训练集损失列表
    train_loss_all = []
    # 验证集损失列表
    val_loss_all = []
    # 训练集准确度列表
    train_acc_all = []
    # 验证集准确度列表
    val_acc_all = []
    for epoch in range(num_epochs):
        print("Epoch {}/{}".format(epoch, num_epochs - 1))
        print("-" * 10)
        train_metrics = train_epoch(net, train_iter, loss, trainer)
        print("{} train loss:{:.4f} train acc: {:.4f}".format(epoch, train_metrics[0], train_metrics[1]))
        # print(train_metrics)
        test_metrics = evalution_loss_accuracy(net, loss, test_iter)
        print("{} train loss:{:.4f} train acc: {:.4f}".format(epoch, test_metrics[0], test_metrics[1]))
        train_loss_all.append(train_metrics[0])
        train_acc_all.append(train_metrics[1])
        val_loss_all.append(test_metrics[0])
        val_acc_all.append(test_metrics[1])
    train_process = pd.DataFrame(data={"epoch": range(num_epochs),
                                       "train_loss_all": train_loss_all,
                                       "val_loss_all": val_loss_all,
                                       "train_acc_all": train_acc_all,
                                       "val_acc_all": val_acc_all
                                       })
    return train_process

def matplot_acc_loss(train_process):
    # 显示每一次迭代后的训练集和验证集的损失函数和准确率
    plt.figure(figsize=(12, 4))
    plt.subplot(1, 2, 1)
    plt.plot(train_process['epoch'], train_process.train_loss_all, "ro-", label="Train loss")
    plt.plot(train_process['epoch'], train_process.val_loss_all, "bs-", label="Val loss")
    plt.legend()
    plt.xlabel("epoch")
    plt.ylabel("Loss")
    plt.subplot(1, 2, 2)
    plt.plot(train_process['epoch'], train_process.train_acc_all, "ro-", label="Train acc")
    plt.plot(train_process['epoch'], train_process.val_acc_all, "bs-", label="Val acc")
    plt.xlabel("epoch")
    plt.ylabel("acc")
    plt.legend()
    plt.show()

if __name__ == '__main__':
    net = Net(num_inputs, num_outputs, num_hiddens1, num_hiddens2)
    num_eporch, lr, batch_size = 10, 0.5, 256
    train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size=batch_size)
    loss = nn.CrossEntropyLoss(reduction='none')
    trainer = torch.optim.SGD(net.parameters(), lr)
    train_process = train_ch3(net, train_iter, test_iter, loss, num_eporch, trainer)
    matplot_acc_loss(train_process)

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

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

相关文章

百某应JS逆向

https://ying.baichuan-ai.com/ 目录 一、发起提问 二、观察发现有两个加密参数&#xff1a;X-Bc-Sig和X-Bc-Ts ​三、观察JS调用栈 四、从JS中搜索 X-Bc-Sig和X-Bc-Ts 五、断点并分析参数的生成方式 六、分析入参 七、发现关键的o方法调用了一个i()方法 八、验证结果 …

sqlilabs解题方法

Lass1 查询id为1的用户名和密码 查询id为2的用户名和密码 没有回显&#xff0c;不含id-1的行 判断字段数&#xff0c;字段数为3 查询数据库用户名&#xff0c;和数据库名 查询时id必须超出数据库以外&#xff0c;一般用-1 用户名&#xff1a;user() 数据库名&#xff1a;databa…

VulnHub:colddbox easy

靶机下载地址 信息收集 主机发现 攻击机网段192.168.31.0/24&#xff0c;扫描同网段存活主机。 nmap 192.168.31.0/24 -Pn -T4 发现靶机&#xff0c;IP为192.168.31.176。 端口扫描 扫描靶机开放端口。 nmap 192.168.31.176 -A -p- -T4 开放了80,4512端口&#xff0c;注…

[H并查集] lc100347. 判断矩形的两个角落是否可达(并查集+高质量+周赛408_4)

文章目录 1. 题目来源2. 题目解析 1. 题目来源 链接&#xff1a;100347. 判断矩形的两个角落是否可达 参考&#xff1a; 灵神视频题解&#xff1a;筛质数 巧妙枚举 并查集【力扣周赛 408】 这一期周赛很不错。 2. 题目解析 十分不错的题目哈&#xff0c;关键是题意的转换…

哈希 Hash(闭散列、开散列介绍及其实现)

目录 unordered 系列关联式容器unordered_mapunordered_map 的介绍unordered_map 的接口说明构造函数容量函数迭代器元素访问查询操作修改操作桶操作 unordered_setunordered_set 的介绍unordered_set 的接口说明构造函数容量函数迭代器查询操作修改操作桶操作 底层结构哈希概念…

Catalyst优化器:让你的Spark SQL查询提速10倍

目录 1 逻辑优化阶段 2.1 逻辑计划解析 2.2 逻辑计划优化 2.2.1 Catalys的优化过程 2.2.2 Cache Manager优化 2 物理优化阶段 2.1 优化 Spark Plan 2.1.1 Catalyst 的 Join 策略 2.1.2 如何决定选择哪一种 Join 策略 2.2 Physical Plan 2.2.1 EnsureRequirements 规则 3 相关文…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第五十七章 Linux中断实验

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

python 裁剪图片

情况&#xff1a; 有时候看视频&#xff0c;看到一个漂亮的妹子&#xff0c;按下 Alt PrintScreen 进行截图之后&#xff0c;会把整个屏幕都截图。 需要适当剪裁一下。 每次打开 PS &#xff0c; 也太慢了。 所以写个代码&#xff0c; 快速处理。 效果对比&#xff1a; 原始…

个人定制化形象生成,FaceChain最新模型部署

FaceChain是阿里巴巴达摩院推出的一个开源的人物写真和个人数字形象的AI生成框架。 FaceChain利用了Stable Diffusion模型的文生图功能&#xff0c;并结合人像风格化LoRA模型训练及人脸相关感知理解模型&#xff0c;将输入的图片进行训练后推理输出生成个人写真图像。 FaceCh…

【redis】对hash类型和list类型的常用命令,应用场景,内部编码的总结

˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如…

初识c++:vector全方面讲解及其代码模拟实现

本节大纲&#xff1a; vector全方面讲解及其代码模拟实现 1.学习vector方法 2.vector的使用 2.1 vector的定义 2.2 vector iterator 的使用 2.3 vector 空间增长问题 2.4 vector 增删查改 2.5 vector 迭代器失效问题&#xff08;重点&#xff09; 3.vector 深度刨析 4…

【Vulnhub系列】Vulnhub_Raven2靶场渗透(原创)

【Vulnhub系列靶场】Vulnhub_Raven2 渗透 原文转载已经过授权 原文链接&#xff1a;Lusen的小窝 - 学无止尽&#xff0c;不进则退 (lusensec.github.io) 一、环境准备 从网盘下载该靶机&#xff0c;在vm中选择【打开】 然后设置好存储路径&#xff0c;开机后检查靶机的网络连…

主宰生物进化的 “魔咒” —— 制约生物在特殊环境下进化方式的线索

一些神秘的法则制约着生物在特殊环境下的进化方式。它们还为动物将如何适应气候变暖提供了线索。 一些奇特的进化现象 一艘装满大象和老鼠的 “诺亚方舟” 搁浅在一座偏远的小岛上。动物们都幸存下来并繁衍后代。但是&#xff0c;随着世代相传&#xff0c;奇怪的事情发生了&a…

【Matlab】快速傅里叶变换fft代码(单边谱)

单边谱&#xff0c;横纵坐标还原代码 参考链接 主代码 function main() clc clear close all %% %仿真时间 dt0.01; t_end10; timedt:dt:t_end;%注意&#xff0c;length(time)会对fft结果的精度有影响 %对应振幅&#xff0c;频率&#xff1a;10、5、2Hz Z20*sin(2*pi*20*time…

使用abpcli创建项目时提示数据库迁移失败

问题描述 使用abpcli创建项目时提示数据库迁移失败&#xff01; 解决方案&#xff1a; 1、检查数据库连接字符串 {"ConnectionStrings": {"Default": "serverlocalhost;port3306;databaseAcmeBookStore;userroot;passwordyour_password;"} }2、…

盗梦空间续集(InceptionNeXt):使用Inception优化加速ConvNeXt实现ImageNet-1K的最佳精度

Abstract 灵感来自ViT的长距离建模能力&#xff0c;大核卷积最近被广泛研究和采用&#xff0c;以扩大感受野并提高模型性能&#xff0c;例如显著的工作ConvNeXt采用77深度卷积。虽然这种深度算子只消耗少量的FLOPs&#xff0c;但由于高内存访问成本&#xff0c;它在强大计算设…

环境配置—批量删除时提示/usr/bin/rm: Argument list too long问题

文章目录 1. 背景介绍2. 问题原因3. 解决方案3.1 分批删除文件3.2 使用 find 命令直接删除3.3 增加系统参数限制3.4 使用循环删除 4. 结论 1. 背景介绍 在Linux系统中&#xff0c;rm 命令是删除文件和目录的常用工具。然而&#xff0c;当需要删除大量文件时&#xff0c;可能会…

【CPS出版】2024年智能计算与数据分析国际学术会议(ICDA 2024,9月6日-8)

为探讨数据科学和计算智能领域的关键问题&#xff0c;促进相关交流&#xff0c;2024年智能计算与数据分析国际学术会议&#xff08;ICDA 2024)将于2024年9月6日-8日在中国青岛召开。 本届会议拟邀请数据分析和计算智能领域的顶级专家、学者和产业界优秀人才&#xff0c;围绕当前…

党员管理系统2024(代码+论文+ppt)

下载在最后 技术栈: ssmmysql 展示: 下载地址: CSDN现在上传有问题,有兴趣的朋友先收藏.正常了贴上下载地址 备注:

Hive环境搭建(Mysql数据库)

【实验目的】 1) 了解hive的作用 2) 熟练hive的配置过程&#xff08;Mysql数据库&#xff09; 【实验原理】 Hive工具中默认使用的是derby数据库&#xff0c;该数据库使用简单&#xff0c;操作灵活&#xff0c;但是存在一定的局限性&#xff0c;hive支持使用第三方数据库&…