Learning Imbalanced Datasets withLabel-Distribution-Aware Margin Loss

LMFLOSS:专治解决不平衡医学图像分类的新型混合损失函数 (附代码) 阅读详情

代码:GitHub - kaidic/LDAM-DRW: [NeurIPS 2019] Learning Imbalanced Datasets with Label-Distribution-Aware Margin Loss

Abstract

训练集类别机器不均衡,而测试的标准又要求对每一个类别都有很好的泛化能力,甚至,更关心少数类的表现,是 long tail 问题的本质矛盾。这篇文章提出了两个方法:1)label-distribution-aware margin(LDAM),最小化边缘泛化边界。2)一种简单但是有效的训练方式,先让模型学习初始的特征表示(initial stage),再进行re-weighting或者re-sampling。

Introduction

这几天有同学问我到底什么是long tail,我就说就是训练集不平衡但是测试集是平衡了,搞得别人一头雾水:这玩意有啥做的意义,咱们平时用的数据集不都是平衡的么?你还人为的造出来不平衡的训练集,没事找事...

啊这...

其实这个问题可以结合一下研究现状来回答,可以看到主要的贡献都是FAIR,SenseTime或者Google的,主要原因还是产业上会遇到这个问题。在实际收集数据的时候,人们不可能为了平衡数据集主动放弃大量的常见类,而只标注稀有类,这是不经济的。又或者,其实研究者对某些类的分类准确率(或者其他性能指标)不感兴趣,他们只关心特定的几类准确率。

举个例子,病灶检测。如果一个数据集中,95%是正常区域(多数类,head),剩下5%是5种不同的病灶,那么模型只预测为正常就可以达到95%的准确率,然而这是无用的,我们关心的是这5种病灶(稀有类,tail)的检出率。所以,此时tail类的准确率能否得到提升就是模型性能的关键。

当然,long tail和异常检测还是有不同的,以上例子只是为了说明long tail问题的一个意义所在。因为这篇文章是2019年CVPR的(现在CVPR2021都开始冲了,听说1w多篇,吐了),所以简介就不怎么说了,可以参考之前的文章。

Implementing this general idea requires a data-dependent or label-dependent regularizer while  l_{2} regularization depends only on the weight matrices

文章从正则化的角度考虑,认为l2正则不太行,提出了一个新的不但依赖于数据而且还和其label有关的正则方式。

Encouraging a large margin can be viewed as regularization, as standard generalization error bounds depend on the inverse of the minimum margin among all the examples.

核心思想是让少数类之间的margin尽可能地大。

我们以二分类为例,讲一讲margin对分类结果的直观影响:

假设一个二分类问题,一类是多数一类是少数,一个良好的分类器是找到一个分类边界,使得数据的分布被划分到两个域,从而实现完美的分类表现。一般的,margin定义为第i类中每个数据点到达分类边界的最小值。

一个不均衡的二分类例子

以上图为例,蓝点是多数类,绿点是少数类,两条线虚线分别是两个类中到边界的最小数据点,点虚线是理想的分类边界,位于两条线虚线的中间。对于一个分类器来说,位于分类边界(点虚线)左边的都是多数类,右边的都是少数类,两个类的margin都是相等的。

但是在不均衡分类问题中,模型对少数类的特征表示往往学习不够,容易过拟合从而导致少数类上很差的表现。所以考虑对少数类放低要求,从margin的角度来说,就是给予少数类更大的margin,从上图可以看出,实际的分类边界向多数类的线虚线偏移,从而对减轻少数类分类的难度。此时,两个类的margin不相等了,图中以\gamma _{1},\gamma _{2} 表示。

那么偏移多少合适呢?直观上想,偏移量应该是和每一类样本数量有关的一个值,具体的推导可以看下面的理论部分。

Related Work

  • Re-sampling
  • Re-weighting
  • Margin loss:

Hinge loss 通常用于获得“margin”的分类器,尤其是在SVM方法中。 最近,已经提出了大边距Softmax,Angular Softmax和加性余量Softmax,以最大程度地减少类内变化的预测和通过合并角度余量的概念来扩大类间余量。 与这些论文中与类别无关的margin相反,此文的方法尽力为少数群体提供更大的margin。

  • Label shift in domain adaptation

不均衡学习有时候可以看做迁移学习或着Domain adaptation中的label shift问题。在label shift中,最大的困难在于检测和估计标签的偏移,并且在这之后,应用重新加权或重新采样恢复。在long tail问题中,标签偏移是已知的,那么能否基于此做出更好的re-weight或者re-sample优化?

  • Meta-learning

这个我的理解就是把一些超参(比如采样分布)也当作参数,用某些特定设计的loss在特定的epoch进行一定的更新。

Main Approach

假设一个模型为f,其在均衡数据集上的损失一般可以表示为:

其中,l和y是指输入x的预测标签和真实标签,这个公式的含义就是真实标签y的logit小于其他标签的logit的概率。

在一个样本(x,y)中,其真实标签 y=j ,则定义margin,:

这样,综合考虑数据集中所有y=j的样本(记作 S_{j} ),定义每一类的margin:


上述假设所有训练样本分类完全正确,这在训练集是可以做到的。至此,定义和之前的研究完全一致。

理论推导先不写,直接上结论:

最佳的trade off:

\gamma _{j} = \frac{C}{n_{j}^{1/4 }}

其中nj是对应类别j的数目,C是一个超参常数。

基于hinge loss,新的loss为:

其中: \Delta _{j} = \frac{C}{n_{j}^{1/4}}

对应到softmax:

可以看到不同的label对应的margin是不一样的,和他们类的数量有关,但是值得注意的是,只有y_true减去了margin。

这个方法虽然改了loss,但是loss还是可以做re-weight的。

Deferred Re-balancing Optimization Schedule

如图,从T0之后的epoch都对loss按照每一类的频率做reweight,easy,故略。

Experiment

19年的实验结果就不看了吧,不过这个实验里好几个数据都持续出现在2020年的研究工作中。

重点关注一下Cifar100(Res32&Imbalance Factor=100)的结果。

LDAM的代码

class LDAMLoss(nn.Module):
    
    def __init__(self, cls_num_list, max_m=0.5, weight=None, s=30):
        super(LDAMLoss, self).__init__()
        m_list = 1.0 / np.sqrt(np.sqrt(cls_num_list)) # nj的四次开方
        m_list = m_list * (max_m / np.max(m_list)) # 常系数 C
        m_list = torch.cuda.FloatTensor(m_list) # 转成 tensor
        self.m_list = m_list
        assert s > 0
        self.s = s # 这个参数的作用论文里提过么?
        self.weight = weight # 和频率相关的 re-weight

    def forward(self, x, target):
        index = torch.zeros_like(x, dtype=torch.uint8) # 和 x 维度一致全 0 的tensor
        index.scatter_(1, target.data.view(-1, 1), 1) # dim idx input
        index_float = index.type(torch.cuda.FloatTensor) # 转 tensor
        ''' 以上的idx指示的应该是一个batch的y_true '''
        batch_m = torch.matmul(self.m_list[None, :], index_float.transpose(0,1))
        batch_m = batch_m.view((-1, 1))
        x_m = x - batch_m # y 的 logit 减去 margin
        output = torch.where(index, x_m, x) # 按照修改位置合并
        return F.cross_entropy(self.s*output, target, weight=self.weight)

关于参数cls_num_list是什么,如何得到?

在train.py文件中,出现了cls_num_list,是从训练集中获取的

    cls_num_list = train_dataset.get_cls_num_list()

    print('cls num list:')

    print(cls_num_list)

    args.cls_num_list = cls_num_list

论文中有使用两个自制的不平衡数据集cifar-10和cifar-100,通过函数IMBALANCECIFAR获得的

    if args.dataset == 'cifar10':

        train_dataset = IMBALANCECIFAR10(root='./data', imb_type=args.imb_type, imb_factor=args.imb_factor, rand_number=args.rand_number, train=True, download=True, transform=transform_train)

        val_dataset = datasets.CIFAR10(root='./data', train=False, download=True, transform=transform_val)

    elif args.dataset == 'cifar100':

        train_dataset = IMBALANCECIFAR100(root='./data', imb_type=args.imb_type, imb_factor=args.imb_factor, rand_number=args.rand_number, train=True, download=True, transform=transform_train)

# train_dataset

        val_dataset = datasets.CIFAR100(root='./data', train=False, download=True, transform=transform_val)

    else:

        warnings.warn('Dataset is not listed')

        return

作者通过INBALANCE函数来获取不平衡数据集

    def get_img_num_per_cls(self, cls_num, imb_type, imb_factor):
        img_max = len(self.data) / cls_num
        img_num_per_cls = []
        if imb_type == 'exp':
            for cls_idx in range(cls_num):
                num = img_max * (imb_factor**(cls_idx / (cls_num - 1.0)))
                img_num_per_cls.append(int(num))
        elif imb_type == 'step':
            for cls_idx in range(cls_num // 2):
                img_num_per_cls.append(int(img_max))
            for cls_idx in range(cls_num // 2):
                img_num_per_cls.append(int(img_max * imb_factor))
        else:
            img_num_per_cls.extend([int(img_max)] * cls_num)
        return img_num_per_cls


        

其中,get_img_num_per_cls函数是为了获取每一类图像的样本数量。首先,函数会根据类别数量和数据集总数计算出每个类别应该有的最大图片数量。然后,根据imb_type参数的不同,使用不同的算法来计算每个类别的具体图片数量。如果imb_type是’exp’,则使用指数衰减的方式计算;如果imb_type是’step’,则使用阶梯式计算;如果imb_type既不是’exp’也不是’step’,则所有类别使用相同数量的图片。

    def gen_imbalanced_data(self, img_num_per_cls):
        new_data = []
        new_targets = []
        targets_np = np.array(self.targets, dtype=np.int64)
        classes = np.unique(targets_np)
        # np.random.shuffle(classes)
        self.num_per_cls_dict = dict()
        for the_class, the_img_num in zip(classes, img_num_per_cls):
            self.num_per_cls_dict[the_class] = the_img_num
            idx = np.where(targets_np == the_class)[0]
            np.random.shuffle(idx)
            selec_idx = idx[:the_img_num]
            new_data.append(self.data[selec_idx, ...])
            new_targets.extend([the_class, ] * the_img_num)
        new_data = np.vstack(new_data)
        self.data = new_data
        self.targets = new_targets

gen_imbalanced_data函数是一个用于生成不平衡数据集的方法。它接受一个参数img_num_per_cls,该参数是一个列表,指定每个类别需要生成的图像数量。该方法首先将目标标签转换成numpy数组,并提取出所有不重复的类别。接着,对每一个类别,根据img_num_per_cls中指定的数量随机选择对应的样本,并将这些样本添加到新的数据集中。最后,将新的数据集和标签更新到原始数据集中。

    def get_cls_num_list(self):
        cls_num_list = []
        for i in range(self.cls_num):
            cls_num_list.append(self.num_per_cls_dict[i])
        return cls_num_list

get_cls_num_list函数通过遍历获取每一类图像的数量。在函数内部,它通过循环遍历self.cls_num,并将self.num_per_cls_dict中每个类别的数量添加到cls_num_list中。

参考资料:

 知乎:LDAM loss

论文阅读Learning Imbalanced Datasets with Label-Distribution-Aware Margin Loss

不平衡数据集处理方式总结 假设我们有。 阅读详情

相关推荐

动手深度学习笔记(二十三)4.9. 环境和分布偏移

动手深度学习笔记(二十三)4.9. 环境和分布偏移4. 多层感知机4.9. 环境和分布偏移4.9.1. 分布偏移的类型4.9.1.1. 协变量偏移 4. 多层感知机 4.9. 环境和分布偏移 前面我们学习了许多机器学习的实际应用,将模型拟合各种数据集。 然而,我们从来没有想过数据最初从哪里来?以及我们计划最终如何处理模型的输出? 通常情况下,开发人员会拥有一些数据且急于开发模型,而不关注这些基本问题。 许多失败的机器学习部署(即实际应用)都可以追究到这种方式。 有时,根据测试集的精度衡量,模型表现得非常出色

juluwangriyue的博客 1063

论文阅读Learning Imbalanced Datasets with Label-Distribution-Aware Margin Loss

Abstract 当训练数据集存在严重的类不平衡时,深度学习算法的表现可能会很差,但测试标准需要对不太频繁的类进行良好的泛化。 我们设计了两种新的方法来提高这种情况下的性能。首先,我们提出了一个理论上的标签分布感知边际损失(LDAM),其动机是最小化基于边际的泛化边界。在训练过程中,这种损失取代了标准的交叉熵目标,并可以应用于先前的训练策略,如重加权或重采样类不平衡。其次,我们提出了一个简单而有效的训练计划,将重新加权推迟到初始阶段之后,允许模型学习初始表示,同时避免了与重新加权或重新抽样相关的一些复杂性。

qq_40310050的博客 5827

LDAM-DRW:[NeurIPS 2019]通过标签分配感知的保证金损失学习不平衡的数据集

通过标签分配感知的保证金损失学习不平衡的数据集 曹凯迪,魏琳,阿德里安·盖顿,尼科斯·阿雷奇加,马腾宇 这是LDAM-DRW在PyTorch中的集中的正式实现。 相依性 该代码是使用以下库构建的: 1.2 数据集 不平衡的 。 原始数据将被下载和转换imbalancec_cifar.py 。 本文还报告了Tiny ImageNet和iNaturalist 2018的结果。我们稍后将更新这些数据集的代码。 训练 我们通过此仓库提供了一些培训示例: 训练ERM基准以比率为100的长尾不平衡 python cifar_train.py --gpu 0 --imb_type exp --imb_factor 0.01 --loss_type CE --train_rule None 在比率为100的长尾不平衡中训练LDAM损失和DRW训练 python cifar_train.py --

【论文学习3】LDAM:Learning Imbalanced Datasets with Label-Distribution-Aware Margin Loss

训练数据集出现严重的类不平衡问题会导致在实际应用中缺乏泛化性。该文设置了两种解决的算法:1)基于标签分布的边界损失(Label-distribution-aware margin, LDAM);2) 延迟重新加权(Defers re-weighting, DRW),既让模型学习初始特征表示,再进行re-weighting或re-sampling。

Je1zvz的博客 4418

数据不均衡问题经典文献《Learning from Imbalanced Data》

数据不平衡是指在数据集中,一类(或多类)样本特别多而另一类(或多类)样本特别少。这种问题广泛存在于金融欺诈、医学检测、网络入侵等场景中。

DANN实战:用Python手把手教你实现对抗迁移学习(附完整代码)

本文通过Python实战教程,手把手教你实现DANN对抗迁移学习模型,以解决领域偏移问题。文章详细解析了领域对抗神经网络的核心机制,包括梯度反转层和领域判别器的构建,并提供了从数据准备、模型搭建到训练评估的完整代码,帮助开发者快速掌握这一强大的无监督领域自适应技术。

net55的博客 317

不平衡之钥: 重加权法知几何

重加权,也称为代价敏感学习,通过调整训练期间不同类别的损失值来对类别进行重新平衡,近期的研究提出了各种代价敏感学习方法来处理类别不平衡问题,包括类别级重加权和类别级re-margining,大家熟知的Focal loss、动态权重等都属于重加权方法。...

公众号/知乎: AI算法札记,欢迎关注交流 2577

基于STM32的智慧农业大棚监测与控制系统设计与实现

摘要:本文设计了一种基于STM32F103C8T6单片机的智慧农业大棚监测与控制系统,集成多参数环境监测、智能控制和远程管理功能。系统可实时采集光照、CO2、温湿度和土壤湿度等参数,通过OLED显示并采用双模式控制机制:自动模式下根据阈值调节设备,手动模式下支持APP或按键控制。通过ESP8266模块接入机智云平台实现数据云存储和远程控制。测试表明系统具有高精度(温度±0.5℃、CO2±50ppm)、快速响应(<2s)和稳定运行(30天无故障)等特点,有效解决了传统大棚调控不及时等问题。创新点包括多参

3254968421的博客 485

损失函数学习

解决one-stage目标检测中正负样本不平衡什么是正负样本不平衡?为什么是解决一阶段目标检测器,那为什么二阶段不用解决呢?其中m为正样本个数,n为负样本个数,N为样本总数,m+n=N当样本分布失衡时,在损失函数L的分布也会发生倾斜,如m

weixin_46042803的博客 1001

python发送邮件的时候出现 error (535, b‘5.7.3 Authentication unsuccessful‘) 解决方法

出现该Bug的原因主要是 账号密码无法登录,但原先使用该代码测试qq或者163的时候是可以通过的!问题在于各个公司邮件所处理的代码方式不一样

码农研究僧的博客 3503

rk3568 适配以太网(mac 2 mac)

MDIO(Management Data Input/Output)是一种管理数据输入/输出协议,用于在以太网交换机和PHY(物理层收发器)之间进行通信。在Android中,MDIO总线用于控制网络接口的PHY芯片,例如通过MDIO总线访问PHY芯片的寄存器。这些寄存器包含了一些关于网络连接状态、链路速度和其他计算机网络相关信息的数据。MDIO总线通常由网络接口控制器(NIC)使用,以便在OS中管理PHY芯片。在Android设备上,MDIO总线通常由内核驱动程序管理,并且可以通过 /sys/bus/mdi

weixin_35723192的博客 2454

论文笔记:ALA loss:Adaptive Logit Adjustment Loss for Long-Tailed Visual Recognition

Adaptive Logit Adjustment Loss for Long-Tailed Visual Recognition

m0_57459724的博客 1476

OpenClaw插件配置错误修复完全指南

插件文件名是插件目录结构正确package.json配置正确OpenClaw的插件系统还在快速迭代,偶尔会遇到这种配置问题。看错误信息检查配置文件检查实际文件对比差异修复问题大部分问题都能解决。查看官方文档:https://openclaw.ai/docs提Issue:https://github.com/openclaw/openclaw/issues加入Discord社区求助快速修复命令汇总。

Maynor的博客 4096

【深度学习】日常笔记14

在这个网络中,每一层的隐藏变量h(l)通过变换函数fl(h(l-1))得到,其中l表示层数,h(l-1)表示上一层的隐藏变量。在深层网络中,我们有一系列的变换函数f(l),其中每个函数都作用在前一层的隐藏变量h(l-1)上,以产生当前层的隐藏变量h(l)。· ∂W(l)h(l) 表示将所有∂h(L-1) h(L),∂h(l)h(l+1),∂W(l)h(l)这些项依次相乘。②初始化权重的对称性:如果网络的初始权重具有某种对称性,比如在对称的权重矩阵中,不同的神经元连接具有相同的权重值。

努力学习的DS 852

5-EP4CE10F17C8-引脚配置

EP4CE10F17C8-引脚配置

weixin_44479192的博客 720

NVIDIA Isaac GR00T N1.5 人形机器人强化学习入门教程(四)Lerobot、宇树 G1 等不同形态机器人微调教程

本笔记本是一份关于如何在新的数据集上对GR00T-N1预训练模型进行微调的教程。

2506_90492529的博客 1667

04.9. 环境和分布偏移

在构建模型时,我们必须考虑到这种可能性,并继续监控实时系统,并对我们的模型和环境以意想不到的方式纠缠在一起的可能性持开放态度。统计学家称之为协变量偏移(covariate shift), 因为这个问题是由于协变量(特征)分布的变化而产生的。虽然有时我们可以在不引用因果关系的情况下对分布偏移进行推断, 但在我们认为导致的情况下,协变量偏移是一种自然假设。在相应的假设条件下,可以在测试时检测并纠正协变量偏移和标签偏移。机器学习的许多应用中都存在类似的问题: 通过将基于模型的决策引入环境,可能会破坏模型。

weixin_45063703的博客 1551

第一节:从Chat_Bot 到 AI_Agent——一个范式转换

本文系统剖析了工业级AI代理系统ClaudeCode的设计原理与工程实践。通过对比ChatBot与Agent的三个本质差异:自主循环决策vs单轮应答、环境交互vs纯文本I/O、持久状态管理vs无状态对话,揭示了构建生产级Agent系统的关键挑战。文章详细解析了ClaudeCode的五层架构设计、1800+文件组成的运行时系统,包括工具调度、权限管理、状态持久化等核心机制,并阐述了从简单API调用到完整Agent系统的演进路径。

2201_75869398的博客 68

【无标题】

具体来说,在条件分布对齐后,利用源域标签分布和目标域标签分布,在训练阶段和推理阶段调整分类器的预测。源域的标签分布很容易就可以得到,作者通过模型的预测和源域像素级分布先验来估计目标域的标签分布。label shift:源域与目标域的标签分布不一致,比如一些类在源域中出现的很频繁,但是在目标域中出现的很少,这样就导致了分类器对于一些类的分类结果更加偏向于源域。首先要解决条件分布对齐的问题,在条件分布对齐的基础上,进行分类器纠正,分类器纠正需要得到目标域的标签分布,作者在3.4介绍了得到目标域标签分布的方法。

m0_46598543的博客 548

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

论文笔记:Optimal Transport for Conditional Domain Matching and Label shift

本文研究无监督迁移学习,也就是说在目标域中y的标签是缺失。最泛化的情况是同时存在label shift和class-conditional shift。 label shift: $p_S(y=j) $p_

时间的玫瑰的博客 1031

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

NeurIPS 2020 | 数据类别不平衡/长尾分布?不妨利用半监督或自监督学习

作者:Yuzhe Yang链接:https://zhuanlan.zhihu.com/p/259710601本文转载自知乎,作者已授权,未经许可请勿二次转载来给大家介绍一下我们的最新工作...

深度学习与计算机视觉 1262

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Loss损失函数及代码详解

最近在做语义分割相关的工作,看到两篇博文介绍的不错,放在这里学习,也供需要的朋友参考。 1.语义分割的各种loss详解与实现 https://blog.youkuaiyun.com/wangdongwei0/article/details/84576044 2.损失函数loss总结 https://blog.youkuaiyun.com/qq_14845119/article/details/80787753 ...

qq_32863339的博客 3885

cifar10数据集和mnist数据集的读取以及可视化

记录一下cifar10和mnist的读取方式,了解数据格式内容

weixin_47289438的博客 2458

年龄回归问题论文阅读

摘要: 当训练数据集存在严重的类不平衡时,深度学习算法的表现可能会很差,但测试标准需要对不太频繁的类进行良好的泛化。我们设计了两种新的方法来提高这种情况下的性能。首先,我们提出了一个理论上的标签分布感知边际损失(LDAM),其动机是最小化基于边际的泛化边界。在训练过程中,这种损失取代了标准的交叉熵目标,并可以应用于先前的训练策略,如重加权或重采样类不平衡。其次,我们提出了一个简单而有效的训练计划,将重新加权推迟到初始阶段之后,允许模型学习初始表示,同时避免了与重新加权或重新抽样相关的一些复杂性。我们在几个基

qq_43349542的博客 1006

域适应(DA)---域泛化(DG)

集成学习卷积神经网络通过激活与标签相关的显性特征来进行图像分类。当训练和测试数据处于类似的分布时,它们的主导功能类似,导致不错的测试性能。尽管如此,在用不同的分布测

专业主义 1万+

Label-Distribution-Aware Margin Loss原理解析:LDAM数学公式与代码实现

Label-Distribution-Aware Margin Loss(LDAM)是NeurIPS 2019提出的解决类别不平衡问题的创新损失函数,通过动态调整类别边界来提升长尾数据的分类性能。本文将深入解析LDAM的数学原理与PyTorch实现细节,帮助开发者快速掌握这一高效算法。 ## 什么是LDAM Loss? 在图像分类等任务中,训练数据常存在严重的类别不平衡问题(如1:100的样本

gitblog_01062的博客 1076
上一篇: 多尺度特征融合笔记
下一篇: BiFPN---加权双向特征金字塔网络(附代码)
无妄无望
博客等级 码龄7年 1901粉丝 215原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值