批量归一化(Batch Normalization)及其实现

批归一化(Batch Normalization)详解 批归一化(Batch Normalization)详解 文章目录批归一化(Batch Normalization)详解前言一、数据归一化二、BN解决的问题:Internal Covariate Shift三、BN如何做的数据归一化四、BN的本质总结 前言 批归一化简称BN,是由Google于2015年提出,这是一个深度神经网络训练的技巧,它不仅可以加快了模型的收敛速度,而且更重要的是在一定程度缓解了深层网络中“梯度弥散(特征分布较散)”的问题,从而使得训练深层网络模型更加容易和稳定。所以目前BN已经成为几 阅读详情

批量归一化(Batch Normalization)及其实现

在学习沐神的视频时,看到批量归一化这个视频时,有些难理解,故将这一课沐神将的内容加上自己的一些理解写成这篇笔记,原视频指路:批量归一化

批量归一化所考虑要解决的问题

模型在反向传播计算梯度时,由于使用的激活函数使得梯度基本上都比较小,再加上链式法则造成的梯度累乘,使得上层网络的梯度相较于底层网络大,在考虑学习率都相同时,顶层网络训练较快,底层网络训练较慢
但,由于底部变化之后,下一次正向计算时,当网络层数较多,较深时,底部网络对顶部网络的影响逐步累积,导致每一次训练完,下一次训练时顶层虽然训练较快,但由于底部网络的微小变化,导致顶层网络在每一次训练中拿到的数据和上一次的差异较大,相当于每一次都在重新学习各个特征,需要训练多次才能达到比较好的收敛效果,这样就导致整个网络的收敛变慢,学习率也不好调节,因为当学习率较大时,顶层网络训练过快无法收敛,学习率较小时底层网络出现梯度消失
因此,我们考虑能不能在底部学习训练时,尽量的去减小顶层的不断的重新学习训练,加快收敛速度

批量归一化解决问题的核心思想

内部协变量偏移(Internal Covariate Shift) :在训练时我们每次每层输入的数据由于经过了前面一层或多层的处理,分布差异(统计特性,比如均值、方差)较大,导致训练过程非常不稳定,尤其是当网络层数不断增加时,这种
效应不断加强
因此,批量归一化就考虑从分布差异入手解决问题,假设将每一层的输出都在整体上符合某一分布(主要用到的是正态分布),具体可以微调,那么在学习过程中的稳定性就能得到提高

批量归一化的具体实现

具体来说,批量归一化,就是将将训练中的每一个batch看作是一个批量,需要归一化的就是这一个小批量的均值和方差,用公式表达为:
均值: μ B = 1 ∣ B ∣ ∑ i ∈ B X i 方差: σ 2 = 1 ∣ B ∣ ∑ i ∈ B ( X i − μ B ) 2 + ϵ 均值:\mu_B = \frac{1}{|B|} \sum_{i \in B} X_i \\ 方差:\sigma^2 = \frac{1}{|B|} \sum_{i \in B}(X_i - \mu_B)^2 + \epsilon 均值:μB​=∣B∣1​i∈B∑​Xi​方差:σ2=∣B∣1​i∈B∑​(Xi​−μB​)2+ϵ
微调(最终传入下一层进行计算):
x i + 1 = γ x i − μ B σ B + β x_{i+1} = \gamma\frac{x_i - \mu_B}{\sigma_B} + \beta xi+1​=γσB​xi​−μB​​+β
其中, γ \gamma γ和 β \beta β是需要学习的值,来逼近最优解

对于全连接层来说,输入是一个二维的tensor,分为批量维和特征维,那么,对全连接层进行批量归一化,我们所要求的均值就是特征维的均值,也就是将批量压缩为一,可以想象为将全连接层从上到下压扁,求和成一层,保留特征维度,求出均值,具体例子为:
假设我们有如下输入:
[[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],]
进行批量归一化的第一步就是求和,得到:
[[4, 8,12,16]]
然后再求均值:
[[1, 2, 3, 4]]
对于卷积层来说,一般用于处理图片,输入是一个四维的tensor,分为批量,通道,宽,高,那么进行批量归一化,同样将批量压为一,但与全连接层不同的是,宽和高也同样压缩为1求平均,也就是说只保留通道维的维数,其余维度降为1维,整体维数保持不变,可以看作是将图片中的所有像素作为样本,将通道看作是全连接层中的特征,具体例子为:
一开始是一个3*3*3*3的四维向量(3批次,3通道,宽3,高3)

Batch 1
+---------+   +---------+   +---------+
|Channel 1|   |Channel 2|   |Channel 3|
+---------+   +---------+   +---------+
| 1  1  1 |   | 2  2  2 |   | 3  3  3 |
| 1  1  1 |   | 2  2  2 |   | 3  3  3 |
| 1  1  1 |   | 2  2  2 |   | 3  3  3 |
+---------+   +---------+   +---------+

Batch 2
+---------+   +---------+   +---------+
|Channel 1|   |Channel 2|   |Channel 3|
+---------+   +---------+   +---------+
| 4  4  4 |   | 5  5  5 |   | 6  6  6 |
| 4  4  4 |   | 5  5  5 |   | 6  6  6 |
| 4  4  4 |   | 5  5  5 |   | 6  6  6 |
+---------+   +---------+   +---------+

Batch 3
+---------+   +---------+   +---------+
|Channel 1|   |Channel 2|   |Channel 3|
+---------+   +---------+   +---------+
| 7  7  7 |   | 8  8  8 |   | 9  9  9 |
| 7  7  7 |   | 8  8  8 |   | 9  9  9 |
| 7  7  7 |   | 8  8  8 |   | 9  9  9 |
+---------+   +---------+   +---------+

批量归一化求和,取平均后:

Batch 1
+- -+   +- -+   +- -+
|C 1|   |C 2|   |C 3|
+- -+   +- -+   +- -+
| 4 |   | 5 |   | 6 |
+- -+   +- -+   +- -+

变成一个1*3*1*1的四维向量

在沐神的视频中讲到,批量归一化最初是认为可以减少内部协变量转移(就像前面所说),但后续的论文发现可能批量归一化更多的是通过在每一个小批量中加入噪音来控制模型整体的复杂度,因此没必要和丢弃法混合使用

下面是批量归一化具体的代码实现
(
使用pytorch框架,
但不使用pytorch框架中的nn.BatchNorm2d,如果需要使用,只需要在net中改一下就行,
和视频中使用相同的LeNet和fashionmnist,但不使用d2l
)

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

def batch_norm(X, gamma, beta, moving_mean, moving_var, eps, momentum):
    #这里我们添加了moving_mean和moving_var这两个变量来求出全部训练样本的整体mean和var
    #为的是在inference也就是之后的推理中使用
    if not torch.is_grad_enabled():
        X_hat = (X - moving_mean) / torch(moving_var + eps)
            #在推理中,就直接使用训练得到的moving_mean,moving_var
            #每次训练学习到的γ和β已经包含在其中
    else: 
        assert len(X.shape) in (2,4)
            #判断是否是全连接层或者是卷积层(这里只考虑这两种)
        if len(X.shape) == 2:#全连接层
            mean = X.mean(dim = 0)#dim = 0即前面提到的对批量求平均
            var = ((X - mean) ** 2).mean(dim = 0)#对批量求方差
        if len(X.shape) == 4:#卷积层
            mean = X.mean(dim = (0, 2, 3), keepdim=True)#只保留通道数
            var = ((X - mean) ** 2).mean(dim = (0, 2, 3), keepdim=True)
        X_hat = (X - mean) / torch.sqrt(var + eps)
        moving_mean = momentum * moving_mean + (1 - momentum) * mean#使用指数移动平均来逐渐逼近整体的平均和方差
        moving_var = momentum * moving_var + (1 - momentum) * var
    Y = gamma * X_hat + beta
    return Y, moving_mean.data, moving_var.data

class BatchNorm(nn.Module):#定义一个类来做初始化
    def __init__(self, num_features, num_dims):
        super().__init__()
        if num_dims == 2:
            shape = (1, num_features)
        else: shape = (1, num_features, 1, 1)
        self.gamma = nn.Parameter(torch.ones(shape))#gamma初始化为1,肯定不能初始化为0
        self.beta = nn.Parameter(torch.zeros(shape))#beta初始化为0
        self.moving_mean = torch.zeros(shape)
        self.moving_var = torch.ones(shape)#初始整体样本化均值为0,方差为1

    def forward(self, X):
        if self.moving_mean.device != X.device:
            self.moving_mean = self.moving_mean.to(X.device)
            self.moving_var = self.moving_var.to(X.device)
        Y, self.moving_mean, self.moving_var = batch_norm(X, self.gamma, self.beta, self.moving_mean, self.moving_var,
                                                        eps=1e-5, momentum=0.9)
        return Y

net = nn.Sequential(
    nn.Conv2d(1, 6, kernel_size=5),
    BatchNorm(6, num_dims = 4),
    nn.Sigmoid(),
    nn.MaxPool2d(kernel_size=2, stride=2),

    nn.Conv2d(6, 16, kernel_size=5),
    BatchNorm(16, num_dims=4),
    nn.Sigmoid(),
    nn.MaxPool2d(kernel_size=2, stride=2),

    nn.Flatten(),
    nn.Linear(16 * 4 * 4, 120),
    BatchNorm(120, num_dims=2),
    nn.Sigmoid(),

    nn.Linear(120, 84),
    BatchNorm(84,num_dims=2),
    nn.Sigmoid(),
    nn.Linear(84, 10)
)

#下载数据集,创建dataloader
lr, num_epochs, batch_size = 1.0, 10, 256
trans = transforms.ToTensor()
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)
train_iter = DataLoader(mnist_train, batch_size, shuffle=True, num_workers=4)
test_iter = DataLoader(mnist_test, batch_size, shuffle=False, num_workers=4)

#开始训练
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
loss = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(net.parameters(), lr=lr)
net.to(device)
for epoch in range(num_epochs):
    net.train() 
    train_loss_sum, train_acc_sum, n = 0.0, 0.0, 0
    for X, y in train_iter:
        X, y = X.to(device), y.to(device)
        y_hat = net(X)
        l = loss(y_hat, y)
        optimizer.zero_grad() # 梯度清零
        l.backward()          # 计算梯度
        optimizer.step()      # 更新参数
        train_loss_sum += l.cpu().item()
        train_acc_sum += (y_hat.argmax(dim=1) == y).sum().cpu().item()
        n += y.shape[0]
    train_loss = train_loss_sum / n
    train_acc = train_acc_sum / n

    #测试
    net.eval()
    test_acc_sum, n_test = 0.0, 0
    with torch.no_grad(): # 在评估时,我们不需要计算梯度
        for X, y in test_iter:
            X, y = X.to(device), y.to(device)
            test_acc_sum += (net(X).argmax(dim=1) == y).sum().cpu().item()
            n_test += y.shape[0]
    
    test_acc = test_acc_sum / n_test
    
    print(f'Epoch {epoch + 1}/{num_epochs}, Train Loss: {train_loss:.4f}, Train Acc: {train_acc:.4f}, Test Acc: {test_acc:.4f}')

最终的训练结果:

Epoch 1/10, Train Loss: 0.0011, Train Acc: 0.8976, Test Acc: 0.8319
Epoch 2/10, Train Loss: 0.0010, Train Acc: 0.9052, Test Acc: 0.7687
Epoch 3/10, Train Loss: 0.0010, Train Acc: 0.9096, Test Acc: 0.8097
Epoch 4/10, Train Loss: 0.0009, Train Acc: 0.9137, Test Acc: 0.8688
Epoch 5/10, Train Loss: 0.0009, Train Acc: 0.9154, Test Acc: 0.8454
Epoch 6/10, Train Loss: 0.0009, Train Acc: 0.9166, Test Acc: 0.8377
Epoch 7/10, Train Loss: 0.0008, Train Acc: 0.9203, Test Acc: 0.8365
Epoch 8/10, Train Loss: 0.0008, Train Acc: 0.9234, Test Acc: 0.7488
Epoch 9/10, Train Loss: 0.0008, Train Acc: 0.9234, Test Acc: 0.8821
Epoch 10/10, Train Loss: 0.0008, Train Acc: 0.9264, Test Acc: 0.8768

和不使用批量归一化相比较准确率差别不大,但速度提升了好几倍

Batch Normalization 批量归一化 【全方位解释】 批量归一化(Batch Normalization),由Google于2015年提出,是近年来深度学习(DL)领域最重要的进步之一。该方法依靠两次连续的线性变换,希望转化后的数值满足一定的特性(分布),不仅可以加快了模型的收敛速度,也一定程度缓解了特征分布较散的问题,使深度神经网络(DNN)训练更快、更稳定。 阅读详情

相关推荐

批量归一化(Batch Normalization)是什么?

批量归一化(Batch Normalization,BN)通过标准化每一层的输入,缓解了训练过程中的协方差偏移,能够加速深度神经网络的训练,提高网络的稳定性和泛化能力。它不仅能解决梯度消失和梯度爆炸的问题,还具有一定的正则化效果。尽管在某些情况下可能引入计算开销,批量归一化仍然是目前深度学习中最常用且有效的技术之一。

wq6qeg88的博客 1532

批量归一化(Batch Normalization)

对输入数据进行标准化处理的原因? 使输入数据各个特征的分布相近: 神经网络学习的本质就是学习数据的分布,如果训练数据与测试数据的分布不同,那么网络的泛化能力也大大降低; 在使用小批量数据对神经网络进行训练时,若每批训练数据的分布各不相同,网络在每次迭代都去学习适应不同的分布,这会大大降低网络的训练速度; 为什么要使用批量归一化? 使用浅层模型时,随着模型训练的进行,当每层中参数更新时,靠近...

Yasin的博客 4万+

加速模型收敛神器——归一化(normalization)

进入到深度学习阶段,优化任务是一个非凸优化问题。模型收敛的稳定和速度是算法工程师不得不考虑的问题。归一化自提出后,就是该领域神器。本文将从归一化的思想,介绍常见的几种归一化,探究生效原理三部分来展开,最后是个人使用心得

qq_20879591的博客 4160

批量归一化(BATCH NORM)

批量归一化的理解

2202_75851137的博客 2703

pytorch- 批量归一化

批量归一化(BatchNormalization) 对输入的标准化(浅层模型) 处理后的任意一个特征在数据集中所有样本上的均值为0、标准差为1。 标准化处理输入数据使各个特征的分布相近 批量归一化(深度模型) 利用小批量上的均值和标准差,不断调整神经网络中间输出,从而使整个神经网络在各层的中间输出的数值更稳定。 1.对全连接层做批量归一化 位置:全连接层中的仿射变换和激活函数之间。 全连接: x=...

weixin_42479155的博客 2610

车辆TBOX科普 第64次 TBOX系统集成测试与文档编写

汽车电子开发中,TBOX作为核心网关面临独特挑战:需处理多网络接口、满足严苛安全标准并确保10年以上可靠性。项目文档是开发流程的核心资产,必须与编码同步更新,构建从需求到测试的完整闭环。系统集成测试需分层进行,结合硬件在环测试和自动化工具,并严格管理缺陷。文档与测试深度协同,通过追溯矩阵确保每个需求都被覆盖验证。最终交付不仅是软件包,更是一套包含完整验证报告的信任体系。这种严谨的工程纪律,是将代码转化为车规级可靠产品的关键保障。

IT深耕十余载,大道之简 1317

【从零开始学习深度学习】30. 神经网络中批量归一化层(batch normalization)的作用及其Pytorch实现

【从零开始学习深度学习】30. 神经网络中批量归一化层(batch normalization)的作用及其Pytorch实现

阿旭的博客 2922

STM32F103C8T6的PC13-15引脚配置避坑指南:为什么你的IO口不工作?

本文详细解析了STM32F103C8T6的PC13-15引脚作为普通IO口不工作的原因及解决方案。这三个引脚默认关联侵入检测和低速外部时钟等特殊功能,需先禁用TAMPER和LSE,并开启AFIO时钟,才能正确配置为普通GPIO。文章提供了标准外设库和HAL库的配置步骤、常见问题排查方法及硬件设计注意事项。

weixin_29169899的博客 521

caffe中BatchNorm层和Scale层实现批量归一化(batch-normalization)注意事项

caffe中实现批量归一化(batch-normalization)需要借助两个层:BatchNorm 和 Scale BatchNorm实现的是归一化 Scale实现的是平移和缩放 在实现的时候要注意的是由于Scale需要实现平移功能,所以要把bias_term项设为true 另外,实现BatchNorm的时候需要注意一下参数use_global_stats,在训练的时候设为false,...

weixin_NineDays66 1844

Windows 10/11下彻底卸载Chrome的终极指南(附一键清理注册表脚本)

本文提供了一份在Windows 10/11系统中彻底卸载Google Chrome浏览器的终极指南。针对标准卸载后用户数据与注册表项残留的问题,文章详细介绍了从应用程序层、用户数据层到系统集成层的三层深度清理方法,并重点提供了安全高效的注册表清理脚本,确保浏览器所有痕迹被完全移除,解决重装冲突并释放磁盘空间。

elastic6hunter的博客 781

【Cadence 17.4实战】----- 基于MySQL与ODBC的企业级CIS数据库配置全攻略

本文详细介绍了如何在Cadence 17.4中配置基于MySQL与ODBC的企业级CIS数据库,提升硬件设计团队的元器件管理效率。通过实战案例和避坑指南,帮助读者掌握数据库部署、ODBC驱动配置及CIS参数映射等关键技巧,实现设计数据的实时同步与高效管理。

weixin_30591551的博客 327

批量归一化(Batch Normalization)原理与PyTorch实现

批量归一化(Batch Normalization)是加速深度神经网络训练的常用技术。本文通过Fashion-MNIST数据集,演示如何从零实现批量归一化,并对比PyTorch内置API的简洁实现方式。

m0_74824642的博客 752

IEEE ACCESS Please note that all author names should be listed in English.(所有作者名需用英文名列出)

很奇怪哈,我明明手稿和提交页面作者都是用的英文,但是为什么还是会提示我没用英文呢?后来给编辑发消息,回的很快,他给我发了一个截图,确实是出现中文,但是我还是不知道为啥会出现中文。直到晚上回寝室洗澡的时候忽然想起来了是不是orcid的原因,因为它会强制作者绑定一个orcid账号,而我的orcid账号的名字刚好是中文的。当然这个只是我的一个猜想,但是我觉得可能性很大。我的第二篇论文已经投稿了快三个月了,效果非常的不好,所以我打算转投IEEE ACCESS了,希望这里可以给我一点好的建议。

kuyecsl的博客 3309

批量归一化:Batch Normalization层 原理+Pytorch实现

一、BN层概念明晰 BN层存在的意义:让较深的神经网络的训练变得更加容易。 BN层的工作内容:利用小批量数据样本的均值和标准差,不断调整神经网络中间输出,使整个神经网络在各层的中间输出的数值更加稳定。 BN层注意事项:训练模式和预测模式计算结果不同。 训练模式下:数据是成批的,可以进行批内求均值、求方差,进而得到归一化结果,最后乘以拉伸参数(scale—)和偏移参数(shift—)得...

小小顺利的博客 4425

脑机接口(BCI)从原理到开发实战 10|脑控外设:用脑电波控制机械臂/游戏

摘要: 脑机接口(BCI)的“最后一公里”是将分类结果转化为实际动作的关键环节。本文介绍如何通过指令映射、硬件通信和执行反馈实现脑控外设,包括离散/连续控制策略、防抖处理及串口/蓝牙通信方法。通过两个实战案例(运动想象控制机械臂抓取、P300/SSVEP控制游戏)和完整项目(OpenBCI控制小车),演示了从分类标签到设备动作的完整流程,重点涵盖指令生成算法(多数投票)、Python与Arduino的串口通信集成,为BCI系统落地提供实用解决方案。(149字)

小明的博客 763

工业级C#+YOLOv8缺陷检测系统:准确率98.5%、延迟<50ms的完整实现

本文分享了基于C#和YOLOv8的工业级表面缺陷检测系统实现方案。针对汽车零部件冲压件检测需求(60件/分钟,准确率>98%,延迟<100ms),作者对比了多种技术方案后选择了C#+YOLOv8+ONNX Runtime的组合,最终实现98.5%准确率和42ms延迟。 系统采用分层模块化架构,包含硬件层、采集层、推理层、业务层和控制层。核心优势包括:1)C#在工业环境下的稳定性和集成便利性;2)YOLOv8对复杂缺陷的泛化能力;3)ONNX Runtime GPU加速提升性能。文章详细介绍了硬件

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1138

Group Normalization

Group Normalization 一. 论文简介 主要做的贡献如下(可能之前有人已提出): 类似BN的一种归一化,使用group进行归一化 二. 模块详解 2.1 BN的做法 设 \(X\) 为输入的 \(batch\) 数据,\(\mu_B、\sigma_B\) 为当前 \(batch\) 的均值和方差,\(running\_u、runnnig\_\sigma\) 为滑动平均(...

寂寞的小乞丐 337

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

tensorflow实现batch normalization

撰写时间:2017.08.31 撰写内容:使用tensorflow实现batch normalization 写在开头:batch normalization不是很难的内容,但是如果不自己通过一些低级的API实现总会觉得有些细节很难触碰到,所以下面的内容就是如何使用tensorflow实现batch normalization。文章分为两部分: 1.实现过程中使用的API,务必在实现之前了解这

selous的专栏 5428

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

batch normalization阅读及tensorflow实现

1,核心观点 一个预测函数的输入应是同一分布,而在训练过程中由于前面网络的不断变化导致后面的网络的输入距离波动,因此后面网络的输入分布也变化。利用类似图像白化的方法处理任意一层网络的输入。 2,数学计算流程 https://blog.youkuaiyun.com/weixin_42398658/article/details/84560411 写的比较清晰,其他的数学符合表达有歧义。 计算的解...

qq_276982536的博客 186

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

批量归一化层BatchNorm

批量归一化BatchNorm

SisterRu的博客 2486

批量归一化(PyTorch)

批量归一化BatchNormalization是什么,PyTorch从零实现以及调用API实现。

不想随波逐流的大学生一枚,我们每个人都在努力奔跑 2289

Layer Normalization

论文: Jimmy Lei Ba, Jamie Ryan Kiros, Geoffrey E. Hinton. Layer Normalization. arXiv:1607.06450 Batch normalization 对每个channel或者hidden unit,求输入(mini-)batch上所有样本在这个channel上的均值和标准差。之后根据每个channel上的均值和...

便纵有千种风情 1257

33李沐动手学深度学习v2/批量归一化 mini-batch normalization

32李沐动手学深度学习v2/批量归一化 mini-batch normalization

求道问术 1039

批量归一化 BN(Batch Normalization) (减少重复学习 - 加速损失收敛) + 代码实现 ——笔记2.15《动手学深度学习》

批量归一化固定小批量中的均值和方差,然后学习出适合的偏移和缩放; 可以加速收敛速度(比如以前学习率是0.01,现在用了批量归一化后,可以调到0.1) 不会出现之前:学习率太大的话,上面 (靠近损失的梯度) 会炸掉; 不会出现之前:学习率太小的话,下面 (靠近数据的模型参数) 会学不动; 每一个层的输出都通过均值方差放在一起了,上下层的分布都差不多是正态分布; 但一般不改变模型精度

科研汪小陈的主页:https://chensuzeyu.github.io 3310
上一篇: C语言乘除原理
下一篇: Z-Score公式特性证明
Delores_Lin
博客等级 码龄2年 27粉丝 8原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值