李沐机器学习系列2--- mlp

1 Introduction

LP中有一个很强的假设,输入和输出是线性关系,这一般是不符合事实的。
通过几何的方式去对信息进行理解和压缩是比较高效的,MLP可以表示成下面的形式。
在这里插入图片描述

1.1 从线性到非线性

X ∈ R n × d X \in R^{n \times d} XRn×d表示输入层,有n个样本,d个特征。
H ∈ R n × h H \in R^{n\times h} HRn×h表述隐藏层的输出,有h个输出;
W ( 1 ) ∈ R d × h W^{(1)} \in R^{d\times h} W(1)Rd×h 表示隐藏层的权重, b ( 1 ) ∈ R 1 × h b^{(1)} \in R^{1 \times h} b(1)R1×h表示隐藏层的偏置
W ( 2 ) ∈ R h × q W^{(2)} \in R^{h\times q} W(2)Rh×q b ( 2 ) ∈ R 1 × q b^{(2)} \in R^{1\times q} b(2)R1×q分别是输出层的权重和偏置
H = X ∗ W ( 1 ) + b ( 1 ) O = H ∗ W ( 2 ) + b ( 2 ) \begin{aligned} H &= X * W^{(1)} + b^{(1)} \\ O & = H * W^{(2)}+b^{(2)} \end{aligned} HO=XW(1)+b(1)=HW(2)+b(2)
如果只是这样处理没有任何作用
O = X ∗ W 1 ∗ W 2 + b 1 ∗ W 2 + b 2 O = X*W_1*W_2+b_1*W_2+b_2 O=XW1W2+b1W2+b2
关键还是需要一个非线性的激活函数,有了激活函数多层感知机就不会退化了。
H = σ ( X ∗ W ( 1 ) + b ( 1 ) ) O = H ∗ W ( 2 ) + b ( 2 ) \begin{aligned} H &= \sigma (X * W^{(1)} + b^{(1)}) \\ O & = H * W^{(2)}+b^{(2)} \end{aligned} HO=σ(XW(1)+b(1))=HW(2)+b(2)

1.2 激活函数

  • RELU
    R E L U ( x ) = m a x ( 0 , x ) RELU(x) = max(0,x) RELU(x)=max(0,x)
y.backward(torch.ones_like(x), retain_graph=True)
d2l.plot(x.detach(), x.grad, 'x', 'grad of relu', figsize=(5, 2.5))

在这里插入图片描述
y是一个向量,所以要指定torch.ones_like(x), 因为y是一个向量,所以需要retain_graph,防止计算图被销毁。

y.backward(torch.ones_like(x), retain_graph=True) # 保留计算图
plt.plot(x.detach(), x.grad)  

在这里插入图片描述

  • sigmoid
    s i g m o i d ( x ) = 1 1 + e x p ( − x ) sigmoid(x)=\frac{1}{1+exp(-x)} sigmoid(x)=1+exp(x)1

在这里插入图片描述
导数是
在这里插入图片描述

  • tanh
    t a n h ( x ) = 1 − e x p ( − 2 x ) 1 + e x p ( − 2 x ) tanh(x)=\frac{1-exp(-2x)}{1+exp(-2x)} tanh(x)=1+exp(2x)1exp(2x)
    在0附近接近线性,
    在这里插入图片描述
    在这里插入图片描述

1.2 多层感知机

如果从零实现的话,需要自己定义个网络customNet

import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt

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

from torch import nn
from d2l import torch as d2l
batch_size = 256
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,))
])

train_iter = torchvision.datasets.FashionMNIST(
    root='./data',
    train=True,
    download=True,
    transform=transform)
test_iter = torchvision.datasets.FashionMNIST(
    root='./data',
    train=False,
    download=True,
    transform=transform)
train_loader = DataLoader(train_iter, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_iter, batch_size=batch_size, shuffle=False)


# Neural Network Class
class CustomNet(nn.Module):
    def __init__(self, num_inputs, num_hiddens, num_outputs):
        super(CustomNet, self).__init__()
        self.linear1 = nn.Linear(num_inputs, num_hiddens)
        self.linear2 = nn.Linear(num_hiddens, num_outputs)

    def forward(self, x):
        x = x.reshape((-1, num_inputs))
        H = torch.relu(self.linear1(x))
        return self.linear2(H)

# Network Parameters
num_inputs, num_hiddens, num_outputs = 784, 256, 10
net = CustomNet(num_inputs, num_hiddens, num_outputs)

# Loss Function and Optimizer
loss = nn.CrossEntropyLoss(reduction='mean')
updater = optim.SGD(net.parameters(), lr=0.1)

# Training Loop
num_epochs = 10
for epoch in range(num_epochs):
    total_loss = 0
    for x, y in train_loader:
        output = net(x)
        l = loss(output, y)
        updater.zero_grad()
        l.backward()
        updater.step()
        total_loss += l.item()
    print(f'Epoch {epoch + 1}, Average Loss: {total_loss / len(train_loader)}')

# Test the model
def test_model(net, test_loader):
    net.eval()  # Set the model to evaluation mode
    test_correct = 0
    total = 0
    with torch.no_grad():
        for x, y in test_loader:
            output = net(x)
            _, predicted = torch.max(output, 1)
            total += y.size(0)
            test_correct += (predicted == y).sum().item()
    return test_correct / total

accuracy = test_model(net, test_loader)
print(f'Test Accuracy: {accuracy:.2f}')

# Visualize one example
test_images, test_labels = next(iter(test_loader))
image, label = test_images[0], test_labels[0]

net.eval()
with torch.no_grad():
    output = net(image.unsqueeze(0))
    _, prediction = torch.max(output, 1)
    prediction = prediction.item()

# Display the image
plt.imshow(image.squeeze(), cmap='gray')
plt.title(f'Predicted: {prediction}, Actual: {label}')
plt.show()    

使用pytorch自带的网络定义工具

# Network Parameters
num_inputs, num_hiddens, num_outputs = 784, 256, 10

# Define the network using nn.Sequential
net = nn.Sequential(
    nn.Flatten(),
    nn.Linear(num_inputs, num_hiddens),
    nn.ReLU(),
    nn.Linear(num_hiddens, num_outputs)
)

2 模型选择、欠拟合和过拟合

2.1 训练误差和泛化误差

2.1.1 统计学习理论

同名定理,训练误差收敛到泛化误差的速率。
独立同步分布假设,训练数据和测试数据都是从相同分布中独立提取出来。
有些假设符合独立同部分假设,人脸识别、语音识别和语言翻译任务;
有些假设不符合独立同分布,用大学生的人脸数据来检测养老院的老人。

2.1.2 模型复杂性

简单的模型和大量的数据,期待泛化误差和训练误差接近。需要更多训练迭代的模型比较复杂,较小训练迭代周期的不那么复杂。
影响泛化的因素:
1)可调参数的数量,模型往往更容易过拟合;
2)参数采用的值,权重的取值范围较大,更容易过拟合;
3)训练样本的数量;

2.1.3 验证集

需要通过验证集来进行模型筛选
训练和验证误差之间的泛化误差很小,欠拟合;
在这里插入图片描述

import math
import numpy as np
import torch
from torch import nn
from d2l import torch as d2l

max_degree = 20
n_train, n_test = 100, 100
true_w = np.zeros(max_degree)
true_w[0:4] = np.array([5, 1.2, -3.4, 5.6])

features = np.random.normal(size=(n_train + n_test, 1))
# print(features)
np.random.shuffle(features)
print(np.arange(max_degree).reshape(1, -1))
poly_features = np.power(features, np.arange(max_degree).reshape(1, -1))
print(poly_features)
for i in range(max_degree):
    poly_features[:, i] /= math.gamma(i + 1)

labels = np.dot(poly_features, true_w)
labels += np.random.normal(scale=0.1, size=labels.shape)

# 将pnumy array 转换成tensor
true_w, features, poly_features, labels = [torch.tensor(x, dtype=torch.float32)
                                          for x in [true_w, features, poly_features, labels]]
features[:2], poly_features[:2, :], labels[:2]

# 对模型进行训练
def evaluate_loss(net, data_iter, loss):
    metric = d2l.Accumulator(2)
    for x, y in data_iter:
        out = net(x)
        y = y.reshape(out.shape)
        l = loss(out, y)
        metric.add(l.sum(), l.numel())
    return metric[0]/metric[1]

def train(train_features, test_features, train_labels, test_labels,
          num_epochs=400):
    loss = nn.MSELoss(reduction='none')
    input_shape = train_features.shape[-1]
    net = nn.Sequential(nn.Linear(input_shape, 1, bias=False))
    batch_size = min(10, train_labels.shape[0])
    train_iter = d2l.load_array((train_features, train_labels.reshape(-1, 1)),
                               batch_size)
    test_iter = d2l.load_array((test_features, test_labels.reshape(-1, 1)),
                              batch_size, is_train=False)
    trainer = torch.optim.SGD(net.parameters(), lr=0.01)
    animator = d2l.Animator(xlabel='epoch', ylabel='loss', yscale='log',
                           xlim=[1, num_epochs], ylim=[1e-3,1e2],
                           legend=['train', 'test'])
    for epoch in range(num_epochs):
        d2l.train_epoch_ch3(net, train_iter, loss, trainer)
        if epoch == 0  or (epoch + 1) % 20 == 0:
            animator.add(epoch + 1, (evaluate_loss(net, train_iter, loss),
                                    evaluate_loss(net, test_iter, loss)))
    
    print('weight:', net[0].weight.data.numpy())

train(poly_features[:n_train, :4], poly_features[n_train:, :4],
     labels[:n_train], labels[n_train:])

3 权重衰减

在基础loss的基础上,增加对大权重的惩罚。
在这里插入图片描述

只要修改一下loss function,

def l2_penalty(w):
    return torch.sum(w.pow(2)) / 2
# 对模型进行训练
def train(lambd):
    w, b = init_params()
    net, loss = lambda X: d2l.linreg(X, w, b), d2l.squared_loss
    num_epochs, lr = 100, 0.003
    animator = d2l.Animator(xlabel='epochs', ylabel='loss', yscale='log',
                            xlim=[5, num_epochs], legend=['train', 'test'])
    for epoch in range(num_epochs):
        for X, y in train_iter:
            # 增加了L2范数惩罚项,
            # 广播机制使l2_penalty(w)成为一个长度为batch_size的向量
            l = loss(net(X), y) + lambd * l2_penalty(w)
            l.sum().backward()
            d2l.sgd([w, b], lr, batch_size)
        if (epoch + 1) % 5 == 0:
            animator.add(epoch + 1, (d2l.evaluate_loss(net, train_iter, loss),
                                     d2l.evaluate_loss(net, test_iter, loss)))
    print('w的L2范数是:', torch.norm(w).item())

在pytorch上可以同步衰减权重和参数

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
    # 偏置参数没有衰减
    trainer = torch.optim.SGD([
        {"params":net[0].weight,'weight_decay': wd},
        {"params":net[0].bias}], lr=lr)
    animator = d2l.Animator(xlabel='epochs', ylabel='loss', yscale='log',
                            xlim=[5, num_epochs], legend=['train', 'test'])
    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()
        if (epoch + 1) % 5 == 0:
            animator.add(epoch + 1,
                         (d2l.evaluate_loss(net, train_iter, loss),
                          d2l.evaluate_loss(net, test_iter, loss)))
    print('w的L2范数:', net[0].weight.norm().item())

4 dropout

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/90703e065d4d4184b4ee1db336a369ae.png

随机去掉一些节点,
在这里插入图片描述
标准暂退法
在这里插入图片描述
这里因为dropout层的参数被mask了,输出为0,在反向传播的时候,更新的数值很小

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)
    
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.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))))
        # 只有在训练模型时才使用dropout
        if self.training == True:
            # 在第一个全连接层之后添加一个dropout层
            H1 = dropout_layer(H1, dropout1)
        H2 = self.relu(self.lin2(H1))
        if self.training == True:
            # 在第二个全连接层之后添加一个dropout层
            H2 = dropout_layer(H2, dropout2)
        out = self.lin3(H2)
        return out


net = Net(num_inputs, num_outputs, num_hiddens1, num_hiddens2)

在pytorch后面,添加一个mask的dropout层就可以实现

net = nn.Sequential(nn.Flatten(),
        nn.Linear(784, 256),
        nn.ReLU(),
        # 在第一个全连接层之后添加一个dropout层
        nn.Dropout(dropout1),
        nn.Linear(256, 256),
        nn.ReLU(),
        # 在第二个全连接层之后添加一个dropout层
        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);

5 参数初始化

5.1 梯度爆炸

如果模型有L层,那么每层之间的参数进行更新的时候,梯度满足下面的关系。因为参数的grad有乘积关系,容易出现梯度爆炸和梯度消失。
在这里插入图片描述
sigmoid函数的梯度消失
当参数很大或者很小,gradient都很小,经过多次传递之后,直接梯度消失了
在这里插入图片描述

5.2 xavier 参数初始化

保证梯度的方差不变
在这里插入图片描述

在这里插入图片描述

6 分布和偏移

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深信服技术认证“SCCA-C”划重点:云计算关键技术

为帮助大家更加系统化地学习云计算知识&#xff0c;高效通过云计算工程师认证&#xff0c;深信服特推出“SCCA-C认证备考秘笈”&#xff0c;共十期内容。“考试重点”内容框架&#xff0c;帮助大家快速get重点知识。 划重点来啦 *点击图片放大展示 深信服云计算认证&#xff08…

神经网络:经典模型热门模型

在这里插入代码片【一】目标检测中IOU的相关概念与计算 IoU&#xff08;Intersection over Union&#xff09;即交并比&#xff0c;是目标检测任务中一个重要的模块&#xff0c;其是GT bbox与pred bbox交集的面积 / 二者并集的面积。 下面我们用坐标&#xff08;top&#xff0…

电动汽车BMS PCB制板的技术分析与可制造性设计

随着电动汽车行业的迅猛发展&#xff0c;各大厂商纷纷投入巨资进行技术研发和创新。电动汽车的核心之一在于其电池管理系统&#xff08;Battery Management System, BMS&#xff09;&#xff0c;而BMS的心脏则是其印刷电路板&#xff08;PCB&#xff09;。通过这篇文章探讨电动…

Application layer

title: 应用层 date: 2023-12-20 21:03:48 tags: 知识总结 categories: 计算机网络 应用层&#xff1a;负责最直观的应用请求的封装、发起 一、域名系统DNS 连接在互联网上的主机不仅有IP地址&#xff0c;还有便于用户记忆的主机名字。域名系统DNS能够把互联网上的主机的名字…

Idea启动运行“错误:java: 无效的源发行版: 13”,如何解决?

以上是以JDK1.8的项目作为举例&#xff0c;如果您用的是其他版本请选择对应的language level idea中项目的language level的含义 language level指的是编译项目代码所用的jdk版本。那么&#xff0c;从这个定义出发会有两个小问题。 ❶ 如果project sdk是jdk8&#xff0c;那么la…

卡尔曼滤波算法

卡尔曼滤波算法是一种经典的状态估计算法&#xff0c;它广泛应用于控制领域和信号处理领域。在电动汽车领域中&#xff0c;卡尔曼滤波算法也被广泛应用于电池管理系统中的电池状态估计。其中&#xff0c;电池的状态包括电池的剩余容量&#xff08;SOC&#xff09;、内阻、温度等…

openGauss学习笔记-185 openGauss 数据库运维-升级-提交升级/升级版本回退/异常处理

文章目录 openGauss学习笔记-185 openGauss 数据库运维-升级-提交升级/升级版本回退/异常处理185.1 提交升级操作步骤 185.2 升级版本回滚操作步骤 185.3 异常处理升级问题FAQ openGauss学习笔记-185 openGauss 数据库运维-升级-提交升级/升级版本回退/异常处理 185.1 提交升级…

Swift并发的结构化编程

并发&#xff08;concurrency&#xff09; 早期的计算机 CPU 都是单核的&#xff0c;操作系统为了达到同时完成多个任务的效果&#xff0c;会将 CPU 的执行时间分片&#xff0c;多个任务在同一个 CPU 核上按时间先后交替执行。由于 CPU 执行速度足够地快&#xff0c;给人的错觉…

基于Java+SpringBoot+vue+elementUI私人健身教练预约管理系统设计实现

基于JavaSpringBootvueelementUI私人健身教练预约管理系统设计实现 欢迎点赞 收藏 ⭐留言 文末获取源码联系方式 文章目录 基于JavaSpringBootvueelementUI私人健身教练预约管理系统设计实现一、前言介绍&#xff1a;二、系统设计&#xff1a;2.1 性能需求分析2.2 B/S架构&…

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK实现相机掉线自动重连(C#)

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK实现相机掉线自动重连&#xff08;C#&#xff09; Baumer工业相机Baumer工业相机的掉线自动重连的技术背景通过PnP事件函数检查Baumer工业相机是否掉线在NEOAPI SDK里实现相机掉线重连方法&#xff1a;工业相机掉线重连测试演示图…

Python武器库开发-武器库篇之代理池配置(四十)

武器库篇之代理池配置(四十) 我们在渗透的过程中&#xff0c;是必须要挂代理的&#xff0c;相信为何要挂代理的原因&#xff0c;各位也是非常的明白的&#xff0c;这里就不多讲了。关于如何挂代理和购买代理大家可以去看内网隧道代理技术&#xff08;十&#xff09;之公网资产…

优雅地展示20w单细胞热图|非Doheatmap 超大数据集 细胞数太多

单细胞超大数据集的热图怎么画&#xff1f;昨天刚做完展示20万单细胞的热图要这么画吗&#xff1f; 今天就有人发消息问我为啥他画出来的热图有问题。 问题起源 昨天分享完 20万单细胞的热图要这么画吗&#xff1f;&#xff0c;就有人问为啥他的数据会出错。我们先来看下他的…

CMU15-445-Spring-2023-Project #0 - C++ Primer

前置任务。 Task #1 - Copy-On-Write Trie Copy-on-write (COW) Trie 在进行修改时&#xff0c;不会立即复制整个数据结构。相反&#xff0c;它会在需要修改的节点被多个引用的时候才进行复制。当要对某个节点进行写操作&#xff08;添加子节点或者继续向下insert&#xff09…

FLASH 闪存-stm32入门

本节我们学习的内容是 STM32 的 FLASH&#xff0c;闪存。 当然闪存是一个通用的名词&#xff0c;表示的是一种非易失性&#xff0c;也就是掉电不丢失的存储器。比如&#xff0c;我们之前学习 SPI 的时候&#xff0c;用的 W25Q64 芯片&#xff0c;就是一种闪存存储器芯片。 而…

【QML】与 C++ 混合编程:互相调用函数

文章目录 qml 调用 C 函数案例 a&#xff1a;Q_INVOKABLE 标记 C 函数 视图设置进 qml 属性案例 b&#xff1a;qml 通过发送信号的方式&#xff0c;调用 Qt 槽函数 C调用qml函数 qml 调用 C 函数 qml 要使用 C 的函数有两个方法&#xff1a; 一种是&#xff0c;用 Q_INVOKABLE…

守护进程“独辟蹊径”

守护进程“独辟蹊径” 一、前言二、实际运用2.1 知识介绍2.2 单机库场景应用2.2.1 配置dmwatcher.ini2.2.2 注册后台守护服务2.2.3 配置dmmal.ini2.2.4 配置归档和守护OGUID2.2.5 开启mal2.2.6 启动守护2.2.7 测试dmserver异常退出 三、总结 DM技术交流QQ群&#xff1a;9401242…

数据结构—环形缓冲区

写在前面&#xff0c;2023年11月开始进入岗位&#xff0c;工作岗位是嵌入式软件工程师。2024年是上班的第一年的&#xff0c;希望今年收获满满&#xff0c;增长见闻。 数据结构—环形缓冲区 为什么要使用环形数组&#xff0c;环形数组比起原来的常规数组的优势是什么&#xf…

Windows 10系统用Xlight FTP搭建SFTP服务器

步骤&#xff1a; 1.安装SFTP服务器 刚开始我使用的是freeSSHd&#xff0c;后面发现由于公司网络原因&#xff0c;打不开这个软件&#xff0c;改成了使用Xlight FTP&#xff0c; 官网下载链接&#xff1a;Xlight FTP 服务器 - 下载免费的windows FTP 服务器 Xlight FTP有30…

LocalSend 开源跨平台的局域网文件互传工具

如果您需要在多平台设备之间进行文件传输&#xff0c;例如从Windows电脑到安卓手机&#xff0c;或者从安卓手机到macOS&#xff0c;通常会使用聊天工具或者U盘进行传输。为了简化这一过程&#xff0c;推荐使用一款全平台支持的文件共享传输工具&#xff1a;LocalSend。 LocalS…

Qt通过pos()获取坐标信息

背景&#xff1a;这是一个QWidget窗体&#xff0c;里面是各种布局的组合&#xff0c;一层套一层。 我希望得到绿色部分的坐标信息(x,y) QPoint get_pos(QWidget* w, QWidget* parent) {if ((QWidget*)w->parent() parent) {return w->pos();}else {QPoint pos(w->po…