多层感知机实现

news2025/3/30 20:26:02

激活函数

非线性

ReLU函数

修正线性单元 rectified linear unit
relu(x)=max(0,x)
在这里插入图片描述
relu的导数:
在这里插入图片描述

sigmoid函数

s i g m o i d ( x ) = 1 1 + e − x sigmoid(x)=\frac{1}{1+e^{-x}} sigmoid(x)=1+ex1
是一个早期的激活函数
缺点是:

  1. 幂运算相对耗时,因此函数计算量较大
  2. 在反向传播时容易出现梯度消失的情况
  3. 收敛缓慢

在这里插入图片描述
导数是sigmoid(x)(1-sigmoid(x)):
在这里插入图片描述

Tanh 函数

双曲正切函数
t a n h ( x ) = 1 − e − 2 x 1 + e − 2 x tanh(x)=\frac{1-e^{-2x}}{1+e^{-2x}} tanh(x)=1+e2x1e2x
在这里插入图片描述
导数: 1 − t a n h 2 ( x ) 1-tanh^2(x) 1tanh2(x)
在这里插入图片描述
幂运算,同样存在计算量大的问题

阶跃函数

在这里插入图片描述

Leaky ReLU 函数 (LReLU)

在这里插入图片描述
如果在学习过程中,a 并不设定为一个常量,而是一个可通过反向传播算法学习的变量,则此时带泄露线性整流又被称为参数线性整流 (Parametric ReLU, PReLU)。

SoftPlus 函数

可以看成是 ReLU 函数的平滑版
在这里插入图片描述

多层感知机

multilayer perceptron
在这里插入图片描述

手写实现

import torch
from torch import nn
from torchvision import transforms
import torchvision
from torch.utils import data
import matplotlib.pyplot as plt

#加载fashion_mnist数据集
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)
    #print(len(mnist_train),len(mnist_test))
    return (data.DataLoader(mnist_train, batch_size, shuffle=True),
        data.DataLoader(mnist_test, batch_size, shuffle=False)) #windows下不能多进程,linux下可以

#批大小
batch_size = 256
#训练和测试的迭代器
train_iter, test_iter = load_data_fashion_mnist(batch_size)

num_inputs,num_outputs,num_hiddens=784,10,256

W1=nn.Parameter(torch.randn(num_inputs,num_hiddens,requires_grad=True)*0.01)
b1=nn.Parameter(torch.zeros(num_hiddens),requires_grad=True)
W2=nn.Parameter(torch.randn(num_hiddens,num_outputs,requires_grad=True)*0.01)
b2=nn.Parameter(torch.zeros(num_outputs),requires_grad=True)
params=[W1,b1,W2,b2]

def relu(x):
    a=torch.zeros_like(x)
    return torch.max(x,a)
def net(x):
    x=x.reshape(-1,num_inputs)
    h=relu(x@W1+b1)
    return (h@W2+b2)
loss=nn.CrossEntropyLoss(reduction='none')
num_epochs,lr=10,0.01
updater=torch.optim.SGD(params,lr=lr)
def set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend):
    """设置matplotlib的轴"""
    axes.set_xlabel(xlabel)
    axes.set_ylabel(ylabel)
    axes.set_xscale(xscale)
    axes.set_yscale(yscale)
    axes.set_xlim(xlim)
    axes.set_ylim(ylim)
    if legend:
        axes.legend(legend)
    axes.grid()
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 = []
        self.fig, self.axes = plt.subplots(nrows, ncols, figsize=figsize)
        if nrows * ncols == 1:
            self.axes = [self.axes, ]
        # 使⽤lambda函数捕获参数
        self.config_axes = lambda: set_axes(self.axes[0], xlabel, ylabel, xlim, ylim, xscale, yscale, legend)
        self.X, self.Y, self.fmts = None, None, fmts
    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)
        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)
        # 通过以下两行代码实现了在PyCharm中显示动图
        plt.draw()
        #plt.pause(interval=0.001)
        #display.clear_output(wait=True)
#精度计算函数
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: 
    """在n个变量上累加"""
    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): 
    """训练模型⼀个迭代周期(定义⻅第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):
            # 使⽤PyTorch内置的优化器和损失函数
            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): #@save
    """训练模型(定义⻅第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_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

train_ch3(net,train_iter,test_iter,loss,num_epochs,updater)
plt.show()


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())
        else:
            # PIL图⽚
            ax.imshow(img)
            ax.axes.get_xaxis().set_visible(False)
            ax.axes.get_yaxis().set_visible(False)
        if titles:
            ax.set_title(titles[i])
    plt.show()
    return axes
def predict_ch3(net, test_iter, n=6):
    """预测标签(定义⻅第3章)"""
    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])

predict_ch3(net, test_iter)

结果:
在这里插入图片描述
在这里插入图片描述

调库实现

import torch
from torch import nn
from torchvision import transforms
import torchvision
from torch.utils import data
import matplotlib.pyplot as plt

net=nn.Sequential(nn.Flatten(),
                  nn.Linear(784,256),
                  nn.ReLU(),
                  nn.Linear(256,10)                 
                  )
def init_weights(m):
    if type(m)==nn.Linear:
        nn.init.normal_(m.weight,std=0.01)
net.apply(init_weights)
batch_size,lr,num_epochs=256,0.1,10
loss=nn.CrossEntropyLoss(reduction='none')
trainer=torch.optim.SGD(net.parameters(),lr=lr)
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)
    #print(len(mnist_train),len(mnist_test))
    return (data.DataLoader(mnist_train, batch_size, shuffle=True),
        data.DataLoader(mnist_test, batch_size, shuffle=False)) #windows下不能多进程,linux下可以
train_iter, test_iter = load_data_fashion_mnist(batch_size)
def set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend):
    """设置matplotlib的轴"""
    axes.set_xlabel(xlabel)
    axes.set_ylabel(ylabel)
    axes.set_xscale(xscale)
    axes.set_yscale(yscale)
    axes.set_xlim(xlim)
    axes.set_ylim(ylim)
    if legend:
        axes.legend(legend)
    axes.grid()
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 = []
        self.fig, self.axes = plt.subplots(nrows, ncols, figsize=figsize)
        if nrows * ncols == 1:
            self.axes = [self.axes, ]
        # 使⽤lambda函数捕获参数
        self.config_axes = lambda: set_axes(self.axes[0], xlabel, ylabel, xlim, ylim, xscale, yscale, legend)
        self.X, self.Y, self.fmts = None, None, fmts
    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)
        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)
        # 通过以下两行代码实现了在PyCharm中显示动图
        plt.draw()
        #plt.pause(interval=0.001)
        #display.clear_output(wait=True)
#精度计算函数
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: 
    """在n个变量上累加"""
    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): 
    """训练模型⼀个迭代周期(定义⻅第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):
            # 使⽤PyTorch内置的优化器和损失函数
            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): #@save
    """训练模型(定义⻅第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_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

train_ch3(net,train_iter,test_iter,loss,num_epochs,trainer)
plt.show()

在这里插入图片描述

欠拟合和过拟合

影响模型泛化的因素:

  1. 参数的数量,越多越容易过拟合
  2. 参数的取值,取值范围越大,越容易过拟合
  3. 训练样本的数量,越少越容易过拟合

欠拟合:泛化能力差,训练样本集准确率低,测试样本集准确率低。
过拟合:泛化能力差,训练样本集准确率高,测试样本集准确率低。
合适的拟合程度:泛化能力强,训练样本集准确率高,测试样本集准确率高

欠拟合原因:

  • 训练样本数量少
  • 模型复杂度过低
  • 参数还未收敛就停止循环

欠拟合的解决办法:

  • 增加样本数量
  • 增加模型参数,提高模型复杂度
  • 增加循环次数
  • 查看是否是学习率过高导致模型无法收敛

防止过拟合的方法:

  • 增加训练集的样本数
  • 交叉验证
  • 数据增强
  • 早停法
  • 降低模型复杂度
  • Dropout(随机丢弃)
  • 正则化regularization(在loss里加入惩罚项)

权重衰减 weight_decay是正则化技术之一,即L2正则化

L2范数惩罚项指的是模型权重参数每个元素的平方和与一个正的常数的乘积。
L ( w , b ) + λ 2 ∣ ∣ w ∣ ∣ 2 L(w,b)+\frac{\lambda}{2}||w||^2 L(w,b)+2λ∣∣w2

L2正则化线性模型构成岭回归算法,L1构成套索回归算法。


def l2_penalty(w):
    return (w**2).sum() / 2
l = loss(net(X, w, b), y) + lambd * l2_penalty(w)

暂退法dropout

手动实现

import torch
from torch import nn
from torchvision import transforms
import torchvision
from torch.utils import data
import matplotlib.pyplot as plt

num_inputs,num_outputs,num_hiddens1,num_hiddens2=784,10,256,256
dropout1,dropout2=0.2,0.5
def dropout_layer(x,dropout):
    assert 0<=dropout<=1
    if dropout==1:
        return torch.zeros_like(x)
    if dropout==0:
        return x
    mask=(torch.rand(x.shape)>dropout).float()
    return mask*x/(1.0-dropout)

class Net(nn.Module):
    def __init__(self,num_inputs,num_outputs,num_hiddens1,num_hiddens2,is_training=True):
        super(Net,self).__init__()
        self.num_inputs=num_inputs
        self.training=is_training
        self.lin1=nn.Linear(num_inputs,num_hiddens1)
        self.lin2=nn.Linear(num_hiddens1,num_hiddens2)
        self.lin3=nn.Linear(num_hiddens2,num_outputs)
        self.relu=nn.ReLU()
    def forward(self,x):
        h1=self.relu(self.lin1(x.reshape((-1,self.num_inputs))))
        if self.training==True:
            h1=dropout_layer(h1,dropout1)
        h2=self.relu(self.lin2(h1))
        if self.training==True:
            h2=dropout_layer(h2,dropout2)
        out=self.lin3(h2)
        return out
    
net=Net(num_inputs,num_outputs,num_hiddens1,num_hiddens2)

num_epochs,lr,batch_size=10,0.5,256
loss=nn.CrossEntropyLoss(reduction='none')

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)
    #print(len(mnist_train),len(mnist_test))
    return (data.DataLoader(mnist_train, batch_size, shuffle=True),
        data.DataLoader(mnist_test, batch_size, shuffle=False)) #windows下不能多进程,linux下可以
train_iter, test_iter = load_data_fashion_mnist(batch_size)

trainer=torch.optim.SGD(net.parameters(),lr=lr)

def set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend):
    """设置matplotlib的轴"""
    axes.set_xlabel(xlabel)
    axes.set_ylabel(ylabel)
    axes.set_xscale(xscale)
    axes.set_yscale(yscale)
    axes.set_xlim(xlim)
    axes.set_ylim(ylim)
    if legend:
        axes.legend(legend)
    axes.grid()
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 = []
        self.fig, self.axes = plt.subplots(nrows, ncols, figsize=figsize)
        if nrows * ncols == 1:
            self.axes = [self.axes, ]
        # 使⽤lambda函数捕获参数
        self.config_axes = lambda: set_axes(self.axes[0], xlabel, ylabel, xlim, ylim, xscale, yscale, legend)
        self.X, self.Y, self.fmts = None, None, fmts
    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)
        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)
        # 通过以下两行代码实现了在PyCharm中显示动图
        plt.draw()
        #plt.pause(interval=0.001)
        #display.clear_output(wait=True)
#精度计算函数
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: 
    """在n个变量上累加"""
    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): 
    """训练模型⼀个迭代周期(定义⻅第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):
            # 使⽤PyTorch内置的优化器和损失函数
            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): #@save
    """训练模型(定义⻅第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_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

train_ch3(net,train_iter,test_iter,loss,num_epochs,trainer)
plt.show()

在这里插入图片描述
调库实现

import torch
from torch import nn
from torchvision import transforms
import torchvision
from torch.utils import data
import matplotlib.pyplot as plt
dropout1,dropout2=0.2,0.5
net=nn.Sequential(nn.Flatten(),
                  nn.Linear(784,256),
                  nn.ReLU(),
                  nn.Dropout(dropout1),
                  nn.Linear(256,256),
                  nn.ReLU(),
                  nn.Dropout(dropout2),
                  nn.Linear(256,10)
)
def init_weights(m):
    if type(m)==nn.Linear:
        nn.init.normal_(m.weight,std=0.01)
net.apply(init_weights)

num_epochs,lr,batch_size=10,0.5,256
loss=nn.CrossEntropyLoss(reduction='none')

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)
    #print(len(mnist_train),len(mnist_test))
    return (data.DataLoader(mnist_train, batch_size, shuffle=True),
        data.DataLoader(mnist_test, batch_size, shuffle=False)) #windows下不能多进程,linux下可以
train_iter, test_iter = load_data_fashion_mnist(batch_size)

trainer=torch.optim.SGD(net.parameters(),lr=lr)

def set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend):
    """设置matplotlib的轴"""
    axes.set_xlabel(xlabel)
    axes.set_ylabel(ylabel)
    axes.set_xscale(xscale)
    axes.set_yscale(yscale)
    axes.set_xlim(xlim)
    axes.set_ylim(ylim)
    if legend:
        axes.legend(legend)
    axes.grid()
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 = []
        self.fig, self.axes = plt.subplots(nrows, ncols, figsize=figsize)
        if nrows * ncols == 1:
            self.axes = [self.axes, ]
        # 使⽤lambda函数捕获参数
        self.config_axes = lambda: set_axes(self.axes[0], xlabel, ylabel, xlim, ylim, xscale, yscale, legend)
        self.X, self.Y, self.fmts = None, None, fmts
    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)
        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)
        # 通过以下两行代码实现了在PyCharm中显示动图
        plt.draw()
        #plt.pause(interval=0.001)
        #display.clear_output(wait=True)
#精度计算函数
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: 
    """在n个变量上累加"""
    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): 
    """训练模型⼀个迭代周期(定义⻅第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):
            # 使⽤PyTorch内置的优化器和损失函数
            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): #@save
    """训练模型(定义⻅第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_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

train_ch3(net,train_iter,test_iter,loss,num_epochs,trainer)
plt.show()

在这里插入图片描述

梯度消失

gradient vanishing =梯度弥散=参数更新过小,每次基本不会移动
sigmoid会导致这个问题

梯度爆炸

初始化设置不合理,没有机会让梯度下降优化器收敛,解决方法:参数初始化
初始化可以是正态分布,或者框架的默认初始化方法。
或Xavier初始化方法:从均值为0,方差为 2 n i n + n o u t \frac{2}{n_{in}+n_{out}} nin+nout2的高斯分布里抽样权重,或从同方差的均匀分布里抽样(均匀分布U(-a,a)的方差是a^2/3),这个初始化方法很常用。

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

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

相关文章

Linux笔记---动静态库(使用篇)

目录 1. 库的概念 2. 静态库&#xff08;Static Libraries&#xff09; 2.1 静态库的制作 2.2 静态库的使用 2.2.1 显式指定库文件及头文件路径 2.2.2 将库文件安装到系统目录 2.2.3 将头文件安装到系统目录 3. 动态库 3.1 动态库的制作 3.2 动态库的使用 3.2.1 显式…

手机销售终端MPR+LTC项目项目总体方案P183(183页PPT)(文末有下载方式)

资料解读&#xff1a;手机销售终端 MPRLTC 项目项目总体方案 详细资料请看本解读文章的最后内容。在当今竞争激烈的市场环境下&#xff0c;企业的销售模式和流程对于其发展起着至关重要的作用。华为终端正处于销售模式转型的关键时期&#xff0c;波士顿 - 华为销售终端 MPRLTC …

【Python LeetCode Patterns】刷力扣,15 个学习模式总结

1. 前缀和&#xff08;Prefix Sum&#xff09;—— 查询子数组中元素和303. 区域和检索 - 数组不可变304. 二维区域和检索 - 矩阵不可变 2. 双指针&#xff08;Two Pointers&#xff09;—— 移向彼此或远离彼此3. 滑动窗口&#xff08;Sliding Window&#xff09;—— 找到满足…

蓝桥杯单片机刷题——串口发送显示

设计要求 通过串口接收字符控制数码管的显示&#xff0c;PC端发送字符A&#xff0c;数码管显示A&#xff0c;发送其它非法字符时&#xff0c;数码管显示E。 数码管显示格式如下&#xff1a; 备注&#xff1a; 单片机IRC振荡器频率设置为12MHz。 串口通信波特率&#xff1a;…

探索抓包利器ProxyPin,实现手机APP请求抓包,支持https请求

以下是ProxyPin的简单介绍&#xff1a; - ProxyPin是一个开源免费HTTP(S)流量捕获神器&#xff0c;支持 Windows、Mac、Android、IOS、Linux 全平台系统- 可以使用它来拦截、检查并重写HTTP(S)流量&#xff0c;支持捕获各种应用的网络请求。ProxyPin基于Flutter开发&#xff0…

文献学习:单细胞+临床+模型构建 | 一篇Molecular Cancer文献如何完整解读CDK4/6i耐药机制

&#x1f44b; 欢迎关注我的生信学习专栏~ 如果觉得文章有帮助&#xff0c;别忘了点赞、关注、评论&#xff01; &#x1f4cc;一、研究背景&#xff1a;CDK4/6i 是不是“万无一失”&#xff1f; HR/HER2- 是最常见的乳腺癌亚型&#xff0c;占比超过70%。近年来&#xff0c;随…

网盘解析工具更新,解决了一些bug

解析工具v1.2.1版本更新&#xff0c;本次是小版本更新&#xff0c;修复了一些bug。 之前小伙伴反应的网盘进入文件后不能返回上一级&#xff0c;现在这个bug修复了&#xff0c;已经可以点击了。 点击资源后会回到资源那一级目录&#xff0c;操作上是方便了不少。 增加了检查自…

5种生成模型(VAE、GAN、AR、Flow 和 Diffusion)的对比梳理 + 易懂讲解 + 代码实现

目录 1 变分自编码器&#xff08;VAE&#xff09;​ 1.1 概念 1.2 训练损失 1.3 VAE 的实现 2 生成对抗网络&#xff08;GAN&#xff09;​ 2.1 概念 2.2 训练损失 a. 判别器的损失函数 b. 生成器的损失函数 c. 对抗训练的动态过程 2.3 GAN 的实现 3 自回归模型&am…

计算机期刊推荐 | 计算机-人工智能、信息系统、理论和算法、软件工程、网络系统、图形学和多媒体, 工程技术-制造, 数学-数学跨学科应用

Computers, Materials & Continua 学科领域&#xff1a; 计算机-人工智能、信息系统、理论和算法、软件工程、网络系统、图形学和多媒体, 工程技术-制造, 数学-数学跨学科应用 期刊类型&#xff1a; SCI/SSCI/AHCI 收录数据库&#xff1a; SCI(SCIE),EI,Scopus,知网(CNK…

【教学类-58-14】黑白三角拼图12——单页1页图。参考图1页6张(黑白、彩色)、板式(无圆点、黑圆点、白圆点)、宫格2-10、张数6张,适合集体操作)

背景需求&#xff1a; 基于以下两个代码&#xff0c;设计一个单页1页黑白三角、彩色三角&#xff08;包含黑点、白点、无点&#xff09;的代码。 【教学类-58-12】黑白三角拼图10&#xff08;N张参考图1张操作卡多张彩色白块&#xff0c;适合个别化&#xff09;-CSDN博客文章…

C++项目:高并发内存池_下

目录 8. thread cache回收内存 9. central cache回收内存 10. page cache回收内存 11. 大于256KB的内存申请和释放 11.1 申请 11.2 释放 12. 使用定长内存池脱离使用new 13. 释放对象时优化成不传对象大小 14. 多线程环境下对比malloc测试 15. 调试和复杂问题的调试技…

消息队列性能比拼: Kafka vs RabbitMQ

本内容是对知名性能评测博主 Anton Putra Kafka vs RabbitMQ Performance 内容的翻译与整理, 有适当删减, 相关数据和结论以原作结论为准。 简介 在本视频中&#xff0c;我们将首先比较 Apache Kafka 和传统的 RabbitMQ。然后&#xff0c;在第二轮测试中&#xff0c;会将 Kaf…

AP 场景架构设计(一) :OceanBase 读写分离策略解析

说明&#xff1a;本文内容对应的是 OceanBase 社区版&#xff0c;架构部分不涉及企业版的仲裁副本功能。OceanBase社区版和企业版的能力区别详见&#xff1a; 官网链接。 概述​ 当两种类型的业务共同运行在同一个数据库集群上时&#xff0c;这对数据库的配置等条件提出了较高…

Java 大视界 -- Java 大数据在智能金融区块链跨境支付与结算中的应用(154)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

手把手教你在linux服务器部署deepseek,打造专属自己的数据库知识库

第一步&#xff1a;安装Ollama 打开官方网址&#xff1a;https://ollama.com/download/linux 下载Ollama linux版本 复制命令到linux操作系统执行 [rootpostgresql ~]# curl -fsSL https://ollama.com/install.sh | sh在Service中增加下面两行 [rootlocalhost ~]# vi /etc/…

C++ 继承:面向对象编程的核心概念(一)

文章目录 引言1. 继承的基本知识1.1 继承的关键词的区别1.2 继承类模版 2. 基类和派生类间的转换3. 继承中的作用域4. 派生类的默认成员函数4.1 默认成员函数的规则4.2 自己实现成员函数4.3 实现一个不能被继承的基类&#xff08;基本不用&#xff09; 引言 在C中&#xff0c;…

蓝桥杯 临时抱佛脚 之 二分答案法与相关题目

二分答案法&#xff08;利用二分法查找区间的左右端点&#xff09; &#xff08;1&#xff09;估计 最终答案可能得范围 是什么 &#xff08;2&#xff09;分析 问题的答案 和 给定条件 之间的单调性&#xff0c;大部分时候只需要用到 自然智慧 &#xff08;3&#xff09;建…

【算法day22】两数相除——给你两个整数,被除数 dividend 和除数 divisor。将两数相除,要求 不使用 乘法、除法和取余运算。

29. 两数相除 给你两个整数&#xff0c;被除数 dividend 和除数 divisor。将两数相除&#xff0c;要求 不使用 乘法、除法和取余运算。 整数除法应该向零截断&#xff0c;也就是截去&#xff08;truncate&#xff09;其小数部分。例如&#xff0c;8.345 将被截断为 8 &#x…

关于服务器只能访问localhost:8111地址,局域网不能访问的问题

一、问题来源&#xff1a; 服务器是使用的阿里云的服务器&#xff0c;服务器端的8111端口没有设置任何别的限制&#xff0c;但是在阿里云服务器端并没有设置相应的tcp连接8111端口。 二、解决办法&#xff1a; 1、使用阿里云初始化好的端口&#xff1b;2、配置新的阿里云端口…

基于ADMM无穷范数检测算法的MIMO通信系统信号检测MATLAB仿真,对比ML,MMSE,ZF以及LAMA

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 ADMM算法 4.2 最大似然ML检测算法 4.3 最小均方误差&#xff08;MMSE&#xff09;检测算法 4.4 迫零&#xff08;ZF&#xff09;检测算法 4.5 OCD_MMSE 检测算法 4.6 LAMA检测算法 …