torch.nn到底是什么?(精简版)

PyTorch 中神经网络库torch.nn的详细介绍 torch.nn是 PyTorch 深度学习框架中的一个核心模块,它为构建和训练神经网络提供了丰富的类库。通过torch.nn,开发者能够快速构建复杂的深度学习模型,并利用 PyTorch 动态计算图特性进行高效训练和推理。此外,该模块还与torch.optim配合,方便地进行权重优化;以及与DataLoader结合以组织和迭代训练数据。 阅读详情

此文为《torch.nn到底是什么?》的总结版。

首先创建基本的神经网络,然后逐步添加torch.nn,torch.optim,Dateset 和 DataLoader的功能,以显示每一部分的具体作用。

1、设置MNIST数据

使用经典的 MNIST 数据集,该数据集由手写数字(0-9)的黑白图像组成。

使用 pathlib 来处理路径(Python3标准库的一部分),用 requests 下载数据。

from pathlib import Path
import requests

DATA_PATH = Path("data")
PATH = DATA_PATH / "mnist"

PATH.mkdir(parents=True, exist_ok=True)

URL = "http://deeplearning.net/data/mnist/"
FILENAME = "mnist.pkl.gz"

if not (PATH / FILENAME).exists():
        content = requests.get(URL + FILENAME).content
        (PATH / FILENAME).open("wb").write(content)

该数据集的格式为NumPy array,使用 pickle 存储。

import pickle
import gzip

with gzip.open((PATH / FILENAME).as_posix(), "rb") as f:
        ((x_train, y_train), (x_valid, y_valid), _) = pickle.load(f, encoding="latin-1")

每个图片大小为28x28,并存储为长度为784(=28x28)的扁平行。

查看其中的一个图片:

from matplotlib import pyplot
import numpy as np

pyplot.imshow(x_train[0].reshape((28, 28)), cmap="gray")
print(x_train.shape)

输出为:
在这里插入图片描述

(50000, 784)

PyTorch使用 tensor 而不是 NumPy array,所以我们需要将其转换。

import torch

x_train, y_train, x_valid, y_valid = map(
    torch.tensor, (x_train, y_train, x_valid, y_valid)
)
n, c = x_train.shape
x_train, x_train.shape, y_train.min(), y_train.max()
print(x_train, y_train)
print(x_train.shape)
print(y_train.min(), y_train.max())

输出:

tensor([[0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.],
        ...,
        [0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.]]) tensor([5, 0, 4,  ..., 8, 4, 8])
torch.Size([50000, 784])
tensor(0) tensor(9)

2、从头构建神经网络(不使用 torch.nn)

首先只使用PyTorch tensor 操作创建一个模型。

#initializing the weights with Xavier initialisation (by multiplying with 1/sqrt(n)).

import math

weights = torch.randn(784, 10) / math.sqrt(784)
weights.requires_grad_()
bias = torch.zeros(10, requires_grad=True)

def log_softmax(x):
    return x - x.exp().sum(-1).log().unsqueeze(-1)

def model(xb):
    return log_softmax(xb @ weights + bias)

def nll(input, target):
    return -input[range(target.shape[0]), target].mean()

def accuracy(out, yb):
    preds = torch.argmax(out, dim=1)
    return (preds == yb).float().mean()
    
loss_func = nll

bs = 64  # batch size

xb = x_train[0:bs]  # a mini-batch from x
yb = y_train[0:bs]

preds = model(xb)  # predictions

print(preds[0], preds.shape)
print(loss_func(preds, yb))
print(accuracy(preds, yb))

输出:

tensor([-1.7022, -3.0342, -2.4138, -2.6452, -2.7764, -2.0892, -2.2945, -2.5480,
        -2.3732, -1.8915], grad_fn=<SelectBackward>) torch.Size([64, 10])

tensor(2.3783, grad_fn=<NegBackward>)
tensor(0.0938)

现在我们可以进行训练。对于每次迭代,将会做以下几件事:

  • 选择一批数据(mini-batch)
  • 使用模型进行预测
  • 计算损失
  • loss.backward() 更新模型的梯度,即权重和偏置
from IPython.core.debugger import set_trace

lr = 0.5  # learning rate
epochs = 2  # how many epochs to train for

for epoch in range(epochs):
    for i in range((n - 1) // bs + 1):
       #set_trace()
        start_i = i * bs
        end_i = start_i + bs
        xb = x_train[start_i:end_i]
        yb = y_train[start_i:end_i]
        pred = model(xb)
        loss = loss_func(pred, yb)

        loss.backward()
        with torch.no_grad():
            weights -= weights.grad * lr
            bias -= bias.grad * lr
            weights.grad.zero_()
            bias.grad.zero_()

print(loss_func(model(xb), yb), accuracy(model(xb), yb))

输出:

tensor(0.0806, grad_fn=<NegBackward>) tensor(1.)

3、使用 torch.nn.functional

如果使用了负对数似然损失函数和 log softnax 激活函数,那么Pytorch提供的F.cross_entropy 结合了两者。所以我们甚至可以从我们的模型中移除激活函数。

import torch.nn.functional as F

loss_func = F.cross_entropy

def model(xb):
    return xb @ weights + bias

注意,在 model 函数中我们不再需要调用 log_softmax。让我们确认一下,损失和精确度与前边计算的一样:

print(loss_func(model(xb), yb), accuracy(model(xb), yb))

输出:

tensor(0.0806, grad_fn=<NllLossBackward>) tensor(1.)

4、使用 nn.Module 重构

继承 nn.Module(它本身是一个类并且能够跟踪状态)建立子类,并实例化模型:

from torch import nn

class Mnist_Logistic(nn.Module):
    def __init__(self):
        super().__init__()
        self.weights = nn.Parameter(torch.randn(784, 10) / math.sqrt(784))
        self.bias = nn.Parameter(torch.zeros(10))

    def forward(self, xb):
        return xb @ self.weights + self.bias
        
model = Mnist_Logistic()

print(loss_func(model(xb), yb))

输出:

tensor(2.3558, grad_fn=<NllLossBackward>)

将训练循环包装到一个 fit 函数中,以便我们以后运行。

def fit():
    for epoch in range(epochs):
        for i in range((n - 1) // bs + 1):
            start_i = i * bs
            end_i = start_i + bs
            xb = x_train[start_i:end_i]
            yb = y_train[start_i:end_i]
            pred = model(xb)
            loss = loss_func(pred, yb)

            loss.backward()
            with torch.no_grad():
                for p in model.parameters():
                    p -= p.grad * lr
                model.zero_grad()

fit()

print(loss_func(model(xb), yb))

输出:

tensor(0.0826, grad_fn=<NllLossBackward>)

5、使用 nn.Linear 重构

使用PyTorch 的 nn.Linear 类建立一个线性层,以替代手动定义和初始化 self.weights 和 self.bias、计算 xb @ self.weights + self.bias 等工作。

class Mnist_Logistic(nn.Module):
    def __init__(self):
        super().__init__()
        self.lin = nn.Linear(784, 10)

    def forward(self, xb):
        return self.lin(xb)

model = Mnist_Logistic()
print(loss_func(model(xb), yb))

输出:

tensor(2.3156, grad_fn=<NllLossBackward>)

我们仍然能够像之前那样使用 fit 方法

fit()

print(loss_func(model(xb), yb))

输出:

tensor(0.0809, grad_fn=<NllLossBackward>)

6、使用 optim 重构

定义一个函数来创建模型和优化器,以便将来可以重用它。

from torch import optim

def get_model():
    model = Mnist_Logistic()
    return model, optim.SGD(model.parameters(), lr=lr)

model, opt = get_model()
print(loss_func(model(xb), yb))

for epoch in range(epochs):
    for i in range((n - 1) // bs + 1):
        start_i = i * bs
        end_i = start_i + bs
        xb = x_train[start_i:end_i]
        yb = y_train[start_i:end_i]
        pred = model(xb)
        loss = loss_func(pred, yb)

        loss.backward()
        opt.step()
        opt.zero_grad()

print(loss_func(model(xb), yb))

输出:

tensor(2.2861, grad_fn=<NllLossBackward>)
tensor(0.0815, grad_fn=<NllLossBackward>)

7、使用 Dataset 重构

from torch.utils.data import TensorDataset

train_ds = TensorDataset(x_train, y_train)
model, opt = get_model()

for epoch in range(epochs):
    for i in range((n - 1) // bs + 1):
        xb, yb = train_ds[i * bs: i * bs + bs]
        pred = model(xb)
        loss = loss_func(pred, yb)

        loss.backward()
        opt.step()
        opt.zero_grad()

print(loss_func(model(xb), yb))

输出:

tensor(0.0800, grad_fn=<NllLossBackward>)

8、使用 DataLoader 重构

from torch.utils.data import DataLoader

train_ds = TensorDataset(x_train, y_train)
train_dl = DataLoader(train_ds, batch_size=bs)

for epoch in range(epochs):
    for xb, yb in train_dl:
        pred = model(xb)
        loss = loss_func(pred, yb)

        loss.backward()
        opt.step()
        opt.zero_grad()

print(loss_func(model(xb), yb))

输出:

tensor(0.0821, grad_fn=<NllLossBackward>)

9、增加验证

train_ds = TensorDataset(x_train, y_train)
train_dl = DataLoader(train_ds, batch_size=bs, shuffle=True)

valid_ds = TensorDataset(x_valid, y_valid)
valid_dl = DataLoader(valid_ds, batch_size=bs * 2)

我们将在每个epoch结束时计算和打印验证损失。(注意,我们总是在训练之前调用model.train(),在推理之前调用 model.eval(),因为这些由诸如 nn.BatchNorm2d 和nn.Dropout 等层使用,以确保这些不同阶段的适当行为。)

model, opt = get_model()

for epoch in range(epochs):
    model.train()
    for xb, yb in train_dl:
        pred = model(xb)
        loss = loss_func(pred, yb)

        loss.backward()
        opt.step()
        opt.zero_grad()

    model.eval()
    with torch.no_grad():
        valid_loss = sum(loss_func(model(xb), yb) for xb, yb in valid_dl)

    print(epoch, valid_loss / len(valid_dl))

输出:

0 tensor(0.2981)
1 tensor(0.3033)

10、创建 fit() 和 get_data()

loss_batch 函数计算每个批次的损失。

def loss_batch(model, loss_func, xb, yb, opt=None):
    loss = loss_func(model(xb), yb)

    if opt is not None:
        loss.backward()
        opt.step()
        opt.zero_grad()

    return loss.item(), len(xb)

fit 运行必要的操作来训练我们的模型并计算每个epoch的训练和验证损失。

import numpy as np

def fit(epochs, model, loss_func, opt, train_dl, valid_dl):
    for epoch in range(epochs):
        model.train()
        for xb, yb in train_dl:
            loss_batch(model, loss_func, xb, yb, opt)

        model.eval()
        with torch.no_grad():
            losses, nums = zip(
                *[loss_batch(model, loss_func, xb, yb) for xb, yb in valid_dl]
            )
        val_loss = np.sum(np.multiply(losses, nums)) / np.sum(nums)

        print(epoch, val_loss)

get_data 为训练集合验证集返回 DataLoader。

def get_data(train_ds, valid_ds, bs):
    return (
        DataLoader(train_ds, batch_size=bs, shuffle=True),
        DataLoader(valid_ds, batch_size=bs * 2),
    )

现在,我们获取 DataLoader 和拟合模型的整个过程可以在3行代码中运行:

train_dl, valid_dl = get_data(train_ds, valid_ds, bs)
model, opt = get_model()
fit(epochs, model, loss_func, opt, train_dl, valid_dl)

输出:

0 0.3055081913471222
1 0.31777948439121245

11、总结

我们现在有一个通用数据流水线和训练循环,你可以使用它来训练多种类型PyTorch模型。 各部分的功能总结如下:

  • torch.nn
    • Module:创建一个可调用的对象,其行为类似于一个函数,但也可以包含状态(例如神经网络层权重)。 它知道它包含哪些参数,并且可以将所有梯度归零,循环遍历它们更新权重等。
    • Parameter:tensor 的包装器(wrapper),它告诉 Module 它具有在反向传播期间需要更新的权重。 只更新具有 requires_grad 属性的 tensor。
    • functional:一个模块(通常按惯例导入到F命名空间中),它包含激活函数,损失函数等,以及非状态(non-stateful)版本的层,如卷积层和线性层。
  • torch.optim:包含 SGD 等优化器,可在后向传播步骤中更新 Parameter 的权重。
  • Dataset:带有 __len__ 和 __getitem__ 的对象的抽象接口,包括 PyTorch 提供的类,如TensorDataset。
  • DataLoader:获取任何 Dataset 并创建一个返回批量数据的迭代器。
torch.nn torch.nn是 PyTorch 提供的一个模块化工具集,专为构建和训练神经网络设计。模块化:通过nn.Module基类,用户可以像搭积木一样组合各种层、激活函数和损失函数,构建复杂模型。动态计算图:PyTorch 的动态计算图(eager execution)允许在运行时定义和修改网络结构,适合研究和快速原型开发。灵活性与控制力:用户可以轻松自定义层、损失函数或前向传播逻辑,同时保留对底层张量操作的访问权限。易用性。 阅读详情

相关推荐

Pytorch torch.nn库以及nn与nn.functional有什么区别?

Pytorch torch.nn库以及nn与nn.functional有什么区别?

算法工程师 1084

pytorch深度学习框架—torch.nn模块(一)

torch.nn模块中包括了pytorch中已经准备好的层,方便使用者调用构建的网络。包括了卷积层,池化层,激活函数层,循环层,全连接层。

xiaoxu的博客 4864

Pytorch中torch.nn.conv2d和torch.nn.functional.conv2d的区别

你是否和我有同样疑惑,pytorch中怎么会有卷积、激活、池化等操作,虽然不在同一个包下面,那他们的区别究竟是什么,今天我们就来捋一捋这个问题。 区别一 正如我们知道的这些看似相同的卷积、激活、池化等操作,分别在不同的包下面—— torch.nn.xxx 和 torch.nn.functional.xxx包,那么他的作用和完成的方式以及调用的方式当然也不一样。 首先我们来看一下pytorch中文文档 ![在这里插入图片描述](https://img-blog.csdnimg.cn/202011161909

weixin_45561795的博客 3405

PyTorch基础:神经网络工具箱torch.nn(nn.Module类)

perception.py import torch from torch import nn #首先建立一个全连接的子module,继承nn.Module class Linear(nn.Module): def __init__(self, in_dim, out_dim): super(Linear, self).__init__() #调用nn.Module的构造函数 #使用nn.Parameter来构造需要学习的参数 self.w

weixin_42782833的博客 7319

常用torch.nn

常用基础pytorch知识

m0_37737957的博客 1684

从CMT2300A实战出发:Sub1G射频匹配电路设计要点与315MHz应用详解

本文从CMT2300A芯片实战出发,详细解析Sub1G射频匹配电路设计要点,特别针对315MHz应用场景。内容涵盖频段划分逻辑、调制方式选择、晶体振荡器设计等基础认知,以及315MHz匹配电路物料选型、巴伦网络处理等实战技巧,并分享PCB布局防干扰设计和实测验证方法,助力开发者优化射频通信性能。

weixin_29238147的博客 162

torch.nn到底是什么?

PyTorch提供了设计优雅的模块和类:torch.nn,torch.optim,Dateset和DataLoader,以帮助你创建和训练神经网络。为了充分利用它们的功能并且为你的问题定制它们,你需要正真理解它们在做什么。为了逐渐理解,我们首先在MNIST数据集上训练基本的神经网络,而不使用这些模块的任何特征。最初只会使用最基本的PyTorch tensor功能。然后,我们逐步添加来自torch....

Spring_24的博客 2万+

深入解析安卓/Linux固件:从DTB到DTS的反编译实战

本文详细介绍了如何从安卓/Linux设备固件中提取并反编译DTB文件,将其转换为可读的DTS源码。通过实战步骤,包括拆解boot.img、处理resource.img以及使用dtc工具,帮助开发者深入理解设备硬件配置,为固件定制、驱动调试和系统移植提供关键支持。

weixin_29274337的博客 339

深入理解 TORCH.NN

原文地址:WHAT IS TORCH.NN REALLY? 本人英语学渣,如有错误请及时指出以便更正 pytorch提供了许多优雅的类和模块帮助我们构建与训练网络,比如 torch.nn, torch.optim,Dataset等。为了充分利用这些模块的功能,灵活操作它们解决各种不同的问题,我们需要更好地理解当我们调用这些模块时它们到底干了些什么,为此,我们首先不调用这些模块实现MNIST手写字...

我的学习笔记 3万+

王爽《汇编语言》课程设计2(不涉及软盘版本)

assume cs:code,ds:data,ss:stack stack segment db 128 dup (0) stack ends data segment db 256 dup (0) data ends code segment start: mov ax,stack mov ss,ax mov sp,128 ...

weixin_41944412的博客 1178

U-net复现pytorch版本 以及制作自己的数据集并训练

GitHub链接: https://github.com/milesial/Pytorch-UNet 论文链接:

candice5566的博客 3万+

Pytorch笔记 之 torch.nn 模块简介

参考翻译 [What is torch.nn really?](https://pytorch.org/tutorials/beginner/nn_tutorial.html) 主要是对 PyTorch 框架的各模块进行简要介绍 一定程度上是 PyTorch 的入门笔记 假设已经对神经网络相关基础知识有了一定了解 (或实现过机器学习梯度下降相关代码)

子耶 6万+

Ansys Lumerical 启动时出现 Error: Could not connect to Ansys license server specified at 1055@ 的一种解决办法

考虑到 2020 版的时候是直接在全局变量里指定具体地址,但是 2024 版本是写成 1055@localhost ,并且之后在站里搜相关 Ansys 的问题都指向 1055 端口被占用,虽然问题不一样,但是本着死马当活马医,就按照。我最近在跑超透镜结构,听说2024版本现在有GPU加速可以用,就把Lumerical从2020升到2024版本,结果发现一开头的破解办法完全不一样了。一开始安装的时候以为2020没有删干净,导致2024版的安装一直锁着目标地址,解决办法参考。的办法来操作,在关闭了。

qq_51404184的博客 5752

torch.nn.Parameter理解

Pytorch官网对torch.nn.Parameter()的解释: torch.nn.Parameter是继承自torch.Tensor的子类,其主要作用是作为nn.Module中的参数使用。它与torch.Tensor的区别就是nn.Parameter会自动被认为是module的可训练参数,即加入到parameter()这个迭代器中去;而module中非nn.Parameter()得普通te...

Stoneplay 4万+

在虚拟机上搭建FTP服务器

chroot_list_file=/etc/vsftpd/chroot_list # 对chroot_list下用户限制。[root@localhost ~]# vim /etc/vsftpd/vsftpd.conf #打开配置文件。# 指定用户的shell: -s /usr/bin/nologin。# 在配置文件中找到以下几行代码, 去掉注释(去掉 "#"号)# 指定用户主目录:/data/ftp/ftpuser -M。(2)修改配置文件,路径/etc/vsftpd/ 下的文件。

weixin_70753380的博客 3209

YOLO11涨点优化:训练技巧 | 使用标签平滑(Label Smoothing)配合余弦退火学习率,防止过拟合,稳步提点

摘要: YOLO11凭借动态卷积核调度、自适应特征融合等创新成为2026年目标检测主流,但面临训练集过拟合问题。文章聚焦两种零推理开销的正则化技巧:标签平滑(Label Smoothing)和余弦退火学习率(Cosine Annealing LR)。标签平滑通过软化硬标签(如将[1,0]改为[0.9,0.1])防止模型过度自信,代码中通过label_smoothing=0.1一键启用;余弦退火则以平滑的余弦曲线调整学习率(cos_lr=True),避免阶梯衰减的震荡。两者组合可显著缩小YOLO11训练与验证

2601_95807009的博客 45

torch.nn.MaxPool1d各参数分析

对torch.nn.MaxPool1d各参数(kernel_size、stride、ceil_mode、dilation、padding)的小白文分析:含官方定义和初步翻译、用代码测试并画图举例讲解各参数的作用。 另外讨论了torch.nn.MaxPool1d与torch.max的区别。

yingluo54的博客 3万+

多源异构数据融合(Kaggle+Google Trends联合分析)

本文详细介绍了如何利用Python实现多源异构数据融合,以Kaggle电商销售数据与Google Trends搜索指数为例,展示了数据清洗、预处理、时间对齐、数据合并、相关性分析、回归建模和可视化全过程。数据预处理与内存优化通过分块加载、数据类型转换和缺失值处理,有效降低了大规模数据在内存中的占用,并确保数据质量。时间对齐与数据融合策略采用重采样与内连接方法对齐不同数据源的时间维度,实现了高质量数据的融合,为后续联合分析奠定基础。模型构建与分析。

闲人编程的博客 1015

torch.nn 与 torch.nn.functional的区别?如何选择?

前言: 在ptorch中,torch.nn和torch.nn.functional模块下包含了许多功能相同、用法相似的方法,比如: 1. torch.nn.Softmax(dim=1)(x) 和torch.nn.functional.softmax(x, dim=1):实现了对x在行维度上进行softmax, 2.torch.nn.Conv2d(3, 6, 5)(x) 和 torch.nn.functional.conv2d(x, weight=torch.rand(6, 3, 5, 5)):实现..

PanYHHH的博客 3265

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Pytorch系列1: torch.nn.Sequential()讲解

torch.nn.Sequential是一个Sequential容器,模块将按照构造函数中传递的顺序添加到模块中。通俗的话说,就是根据自己的需求,把不同的函数组合成一个(小的)模块使用或者把组合的模块添加到自己的网络中。主要有两种使用方法: # 第一种方法 conv_module = nn.Sequential( nn.Conv2d(1,20,5), n...

xddwz的博客 2万+

PyTorch中 torch.nn与torch.nn.functional的区别

torch.nn pytorch中文文档:torch.nn 在__init__()函数里定义,定义的是一个类: torch.nn.functional pytorch中文文档:torch.nn.functional 在__forward()__函数里定义,定义的是一个函数: 两者的区别: nn中是定义的类,以class xx来定义的,可以提取变化的学习参数。nn.functional...

zbzcDZF的博客 6038

torch.nn模块

本文就根据官网文档整理一下torch.nn模块 TORCH.NN非常重要,也是以后用pytorch搭建神经网络的关键模块。所以值得认真学习。 TORCH.NN 第一个关键类: CLASS torch.nn.Parameter A kind of Tensor that is to be considered a module parameter. Parameters are Tensor s...

青山 7162

torch.nn 与 torch.nn.functional的区别?

可以在其基础上定义出自己想要的功能参考博文:【pytorch】torch.nn 与 torch.nn.functional 的区别_torch.nn和torch.nn.function的区别-优快云博客文章浏览阅读554次。今天在看pytorch的代码时,看到了torch.nn 和 torch.nn.functional,然后查了两个模块的官方doc,也没有看明白有啥区别,然后就查了一下资料,这里记录一下,方便以后查阅。_torch.nn和torch.nn.function的区别。

weixin_56054625的博客 1283

nn.Module、nn.Sequential和torch.nn.parameter学习笔记

nn.Module、nn.Sequential和torch.nn.parameter是利用pytorch构建神经网络最重要的三个函数。搞清他们的具体用法是学习pytorch的必经之路。 目录nn.Modulenn.Sequentialtorch.nn.Parameter nn.Module nn.Module中,自定义层的步骤: 1.自定义一个Module的子类,实现两个基本的函数: (1)构造 init 函数 (2)层的逻辑运算函数,即正向传播的函数 2.在构造 init 函数中实现层的参数定义。 比如L

tangbiubiu的博客 3901

Pythorch torch.nn 与 torch.nn.functional的区别

我们知道在torch.nn和torch.nn.functional中有许多类似的激活函数或者损失函数,例如: torch.nn.ReLU 和 torch.nn.functional.relu torch.nn.MSEloss 和 torch.nn.functional.mse_loss 那么他们有什么区别呢? 1.在定义函数层(继承nn.Module)时,init函数中应该用torch.nn,...

xiaohuihui1994的博客 4456
上一篇: torch.nn到底是什么?
下一篇: 神经网络
Spring_24
博客等级 码龄12年 46粉丝 41原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值