使用BERT进行文本分类

基于BERT做中文文本分类(情感分析) Bert: BERT是一种预训练语言表示的方法,这意味着我们在大型文本语料库(例如Wikipedia)上训练通用的“语言理解”模型,然后将该模型用于我们关心的下游NLP任务,BERT优于之前的方法,因为它是第一个用于预训练NLP的无监督,深度双向系统。 相关论文: 《Attention Is All You Need》 《BERT:Pre-training of Deep Bidirect... 阅读详情

a1bdee5d0531017b62484b534620e1bc.png

本范例我们微调transformers中的BERT来处理文本情感分类任务。

我们的数据集是美团外卖的用户评论数据集。

模型目标是把评论分成好评(标签为1)和差评(标签为0)。

#安装库
#!pip install datasets 
#!pip install transformers[torch]
#!pip install torchkeras

公众号算法美食屋后台回复关键词 torchkeras, 获取本文源代码和waimai评论数据集。

一,准备数据

准备数据阶段主要需要用到的是datasets.Dataset 和transformers.AutoTokenizer。

1,数据加载

HuggingFace的datasets库提供了类似TensorFlow中的tf.data.Dataset的功能。

import numpy as np 
import pandas as pd 

import torch 
from torch.utils.data import DataLoader 

import datasets
df = pd.read_csv("data/waimai_10k.csv")
ds = datasets.Dataset.from_pandas(df) 
ds = ds.shuffle(42) #打乱顺序
ds = ds.rename_columns({"review":"text","label":"labels"})
ds[0]
{'labels': 0, 'text': '晚了半小时,七元套餐饮料就给的罐装的可乐,真是可以'}
ds[0:4]["text"]
['晚了半小时,七元套餐饮料就给的罐装的可乐,真是可以',
 '很好喝!天天都喝~~',
 '东西很少,像半分每次都是这样失望',
 '配送比较慢(不是高峰时间点的结果1个多小时才送到);菜品备注了“老人吃请少油少盐”,结果还是很咸很油,哎…失望']

2,文本分词

transformers库使用tokenizer进行文本分词。

from transformers import AutoTokenizer #BertTokenizer
tokenizer = AutoTokenizer.from_pretrained('bert-base-chinese') #需要和模型一致
print(tokenizer)
BertTokenizerFast(name_or_path='bert-base-chinese', vocab_size=21128, model_max_length=512, is_fast=True, padding_side='right', truncation_side='right', special_tokens={'unk_token': '[UNK]', 'sep_token': '[SEP]', 'pad_token': '[PAD]', 'cls_token': '[CLS]', 'mask_token': '[MASK]'}, clean_up_tokenization_spaces=True)
#tokenizer可以使用 __call__,encode,encode_plus,batch_encode_plus等方法编码
#可以使用decode,batch_decode等方法进行解码
text_codes = tokenizer(text = '晚了半小时,七元套餐饮料就给的罐装的可乐,真是可以',
                       text_pair = None,
                       max_length = 100, #为空则默认为模型最大长度,如BERT是512,GPT是1024
                       truncation = True,
                       padding= 'do_not_pad') #可选'longest','max_length','do_not_pad'

#input_ids是编码后的数字,token_type_ids表示来自第1个句子还是第2个句子
#attention_mask在padding的位置是0其它位置是1
print(text_codes)
{'input_ids': [101, 3241, 749, 1288, 2207, 3198, 8024, 673, 1039, 1947, 7623, 7650, 3160, 2218, 5314, 4638, 5380, 6163, 4638, 1377, 727, 8024, 4696, 3221, 1377, 809, 102], 'token_type_ids': [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], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
tokenizer.decode(text_codes["input_ids"][0])
'[CLS]'
tokenizer.batch_decode(text_codes["input_ids"])
['[CLS]',
 '晚',
 '了',
 '半',
 '小',
 '时',
 ',',
 '七',
 '元',
 '套',
 '餐',
 '饮',
 '料',
 '就',
 '给',
 '的',
 '罐',
 '装',
 '的',
 '可',
 '乐',
 ',',
 '真',
 '是',
 '可',
 '以',
 '[SEP]']
tokens = tokenizer.tokenize(ds['text'][0])
print("tokens=",tokens)
ids = tokenizer.convert_tokens_to_ids(tokens)
print("ids = ",ids)
tokens= ['晚', '了', '半', '小', '时', ',', '七', '元', '套', '餐', '饮', '料', '就', '给', '的', '罐', '装', '的', '可', '乐', ',', '真', '是', '可', '以']
ids =  [3241, 749, 1288, 2207, 3198, 8024, 673, 1039, 1947, 7623, 7650, 3160, 2218, 5314, 4638, 5380, 6163, 4638, 1377, 727, 8024, 4696, 3221, 1377, 809]

3,传入DataLoader

ds_encoded = ds.map(lambda example:tokenizer(example["text"],
                    max_length=50,truncation=True,padding='max_length'),
                    batched=True,
                    batch_size=20,
                    num_proc=2) #支持批处理和多进程map
#转换成pytorch中的tensor 
ds_encoded.set_format(type="torch",columns = ["input_ids",'attention_mask','token_type_ids','labels'])
#ds_encoded.reset_format() 
ds_encoded[0]
#分割成训练集和测试集
ds_train_val,ds_test = ds_encoded.train_test_split(test_size=0.2).values()
ds_train,ds_val = ds_train_val.train_test_split(test_size=0.2).values()
#在collate_fn中可以做动态批处理(dynamic batching)

def collate_fn(examples):
    return tokenizer.pad(examples) #return_tensors='pt'

#以下方式等价
#from transformers import DataCollatorWithPadding
#collate_fn = DataCollatorWithPadding(tokenizer=tokenizer)

dl_train = torch.utils.data.DataLoader(ds_train, batch_size=16, collate_fn = collate_fn)
dl_val = torch.utils.data.DataLoader(ds_val, batch_size=16,  collate_fn = collate_fn)
dl_test = torch.utils.data.DataLoader(ds_test, batch_size=16,  collate_fn = collate_fn)
for batch in dl_train:
    break

二,定义模型

一个完整的模型(Model)包括模型架构(Architecture)和模型权重(Checkpoints/Weights)。

transformers提供了3种指定模型架构的方法。

  • 第1种是指定模型架构(如: from transformers import BertModel)

  • 第2种是自动推断模型架构(如: from transformers import AutoModel)

  • 第3种是自动推断模型架构并自动添加Head (如: from transformers import AutoModelForSequenceClassification )

第1种方案和第2种方案用户可以灵活地根据自己要做的任务设计Head,并且需要对基础模型有一定的了解。

此处我们使用第3种方案。

from transformers import AutoModelForSequenceClassification 

#加载模型 (会添加针对特定任务类型的Head)
model = AutoModelForSequenceClassification.from_pretrained('bert-base-chinese',num_labels=2)
dict(model.named_children()).keys()
dict_keys(['bert', 'dropout', 'classifier'])

我们可以用一个batch的数据去试算一下

output = model(**batch)
output.loss
tensor(0.6762, grad_fn=<NllLossBackward0>)

三,训练模型

下面使用我们的梦中情炉 torchkeras 来实现最优雅的微调训练循环。🤗🤗

from torchkeras import KerasModel 

#我们需要修改StepRunner以适应transformers的数据集格式

class StepRunner:
    def __init__(self, net, loss_fn, accelerator, stage = "train", metrics_dict = None, 
                 optimizer = None, lr_scheduler = None
                 ):
        self.net,self.loss_fn,self.metrics_dict,self.stage = net,loss_fn,metrics_dict,stage
        self.optimizer,self.lr_scheduler = optimizer,lr_scheduler
        self.accelerator = accelerator
        if self.stage=='train':
            self.net.train() 
        else:
            self.net.eval()
    
    def __call__(self, batch):
        
        out = self.net(**batch)
        
        #loss
        loss= out.loss
        
        #preds
        preds =(out.logits).argmax(axis=1) 
    
        #backward()
        if self.optimizer is not None and self.stage=="train":
            self.accelerator.backward(loss)
            self.optimizer.step()
            if self.lr_scheduler is not None:
                self.lr_scheduler.step()
            self.optimizer.zero_grad()
        
        all_loss = self.accelerator.gather(loss).sum()
        
        labels = batch['labels']
        acc = (preds==labels).sum()/((labels>-1).sum())
        
        all_acc = self.accelerator.gather(acc).mean()
        
        #losses
        step_losses = {self.stage+"_loss":all_loss.item(), self.stage+'_acc':all_acc.item()}
        
        #metrics
        step_metrics = {}
        
        if self.stage=="train":
            if self.optimizer is not None:
                step_metrics['lr'] = self.optimizer.state_dict()['param_groups'][0]['lr']
            else:
                step_metrics['lr'] = 0.0
        return step_losses,step_metrics
    
KerasModel.StepRunner = StepRunner
optimizer = torch.optim.AdamW(model.parameters(), lr=3e-5)

keras_model = KerasModel(model,
                   loss_fn=None,
                   optimizer = optimizer
                   )
keras_model.fit(
    train_data = dl_train,
    val_data= dl_val,
    ckpt_path='bert_waimai.pt',
    epochs=100,
    patience=10,
    monitor="val_acc", 
    mode="max",
    plot = True,
    wandb = False,
    quiet = True
)

d121f802b2db56ebc991f5f7a7e70bd7.png

此处准确率不是很高,可能冻结BERT除head之外的部分的参数进行训练效果会更好一些,感兴趣的小伙伴可以尝试。

四,评估模型

可以使用huggingFace的evaluate库来进行模型评估。

通过evaluate的load方法可以加载一些常用的评估指标。

可以用add_batch逐批次地往这些评估指标上添加数据,最后用compute计算评估结果。

!pip install evaluate
import evaluate
metric = evaluate.load("accuracy")
model.eval()
dl_test = keras_model.accelerator.prepare(dl_test)
for batch in dl_test:
    with torch.no_grad():
        outputs = model(**batch)

    logits = outputs.logits
    predictions = torch.argmax(logits, dim=-1)
    metric.add_batch(predictions=predictions, references=batch["labels"])

metric.compute()
{'accuracy': 0.9128440366972477}

五,使用模型

texts = ["味道还不错,下次再来","这他妈也太难吃了吧","感觉不是很新鲜","还行我家狗狗很爱吃"]
batch = tokenizer(texts,padding=True,return_tensors="pt")
batch = {k:v.to(keras_model.accelerator.device) for k,v in batch.items()}
from torch import nn 
logits = model(**batch).logits 
scores = nn.Softmax(dim=-1)(logits)[:,-1]
print(scores)
#可以看到得分与人的预期是高度一致的
tensor([0.9510, 0.0133, 0.1020, 0.6223], device='cuda:0',
       grad_fn=<SelectBackward0>)

也可以用pipeline把tokenizer和model组装在一起

from transformers import pipeline
classifier = pipeline(task="text-classification",tokenizer = tokenizer,model=model.cpu())
classifier("挺好吃的哦")
[{'label': 'LABEL_1', 'score': 0.9468138813972473}]

六,保存模型

保存model和tokenizer之后,我们可以用一个pipeline加载,并进行批量预测。

model.config.id2label = {0:"差评",1:"好评"}
model.save_pretrained("waimai_10k_bert")
tokenizer.save_pretrained("waimai_10k_bert")
('waimai_10k_bert/tokenizer_config.json',
 'waimai_10k_bert/special_tokens_map.json',
 'waimai_10k_bert/vocab.txt',
 'waimai_10k_bert/added_tokens.json',
 'waimai_10k_bert/tokenizer.json')
from transformers import pipeline 
classifier = pipeline("text-classification",model="waimai_10k_bert")
classifier(["味道还不错,下次再来","我去,吃了我吐了三天"])
[{'label': '好评', 'score': 0.950958251953125},
 {'label': '差评', 'score': 0.9617311954498291}]

更多有趣范例,公众号算法美食屋后台回复关键词:torchkeras,可在torchkeras仓库获取范例源码。

如果你喜欢torchkeras,记得给吃货一颗星星⭐️哦~~😋😋

06935dd7ca03441a2f15df5cdd975299.png

171890a96a068b13ec2828ec8988eaf4.png

【深度学习】基于BERT的文本情感分类模型---应用(附源代码+数据集+预训练模型) 文本情感分类(Text Sentiment Classification)是一种自然语言处理(NLP)任务,其目标是确定给定文本的情感倾向。情感分类正面情感(Positive Sentiment)文本表达了积极的情绪或观点,例如快乐、满意、赞扬等。负面情感(Negative Sentiment)文本表达了消极的情绪或观点,例如愤怒、不满、批评等。中性情感(Neutral Sentiment)文本既不表达强烈的正面情绪,也不表达强烈的负面情绪,通常是客观陈述。其他情感类别(Optional) 阅读详情

相关推荐

BERT文本分类使用指南

本文档介绍了如何使用BERT实现多类别文本分类任务,适合稍微了解BERT和文本分类的同学参考。 (一) 下载 首先,在github上clone谷歌的BERT项目,或者直接下载。项目地址 然后,下载中文预训练模型,地址 (二) 环境准备 tensorflow &gt;= 1.11.0 注意: 在GPU上运行Tensorflow,需要CUDA版本和Tensorflow版本的对应。比如Tensorfl...

乖兔子的专栏 2万+

NLP系列(2)文本分类(Bert)pytorch

对于 Bert 模型来说,用于文本分类是最常见的,并且准确率也很高。本文将会对Bert 模型用于文本分类来做详细的介绍。

牧子川的博客 1万+

【NLP】使用 BERT 和 PyTorch Lightning 进行多标签文本分类

了解如何为多标签文本分类(标记)准备带有恶意评论的数据集。我们将使用 PyTorch Lightning 微调 BERT 并评估模型。多标签文本分类(或标记文本)是您在执行 NLP 时会遇到的最常见任务之一。现代基于 Transformer 的模型(如 BERT)利用对大量文本数据的预训练,可以更快地进行微调,使用更少的资源并且在较小的(更)数据集上更准确。我们的模型对有害文本检测有用吗?数据我们的数据集包含潜在的攻击性(有毒)评论,来自。我们有文字(评论)和六种不同的毒性标签。

sikh_0529的博客 4621

12-NLP之Bert实现文本分类

NLP之Bert实现文本分类

weixin_46713695的博客 3305

TensorFlow 2.0实现BERT文本分类模型:使用预训练的BERT模型进行文本分类任务

2018年是NLP技术爆炸式发展的年代,自然语言处理(NLP)成为人工智能领域的一大热点。人们为了解决信息提取、文本处理、文本理解等诸多NLP任务而不断投入研发新的工具与技术。其中最火的当属预训练的BERT(Bidirectional Encoder Representations from Transformers)模型,它可以学习到大量的文本语义信息并用于许多NLP任务中,比如文本分类、文本匹配、序列标注等。

AI天才研究院 2683

人工智能入门实战:使用BERT模型进行文本分类

1.背景介绍 人工智能(Artificial Intelligence, AI)是一门研究如何让计算机模拟人类智能的学科。在过去的几年里,人工智能技术发展迅速,已经成为了许多行业的核心技术。文本分类是人工智能领域中一个重要的任务,它涉及到将文本数据划分为不同的类别。随着深度学习技术的发展,文本分类的准确性得到了显著提高。 在本文中,我们将

AI天才研究院 651

使用BERT预训练模型+微调进行文本分类

本文记录使用BERT预训练模型,修改最顶层softmax层,微调几个epoch,进行文本分类任务。 BERT源码 首先BERT源码来自谷歌官方tensorflow版:https://github.com/google-research/bert 注意,这是tensorflow 1.x 版本的。 BERT预训练模型 预训练模型采用哈工大讯飞联合实验室推出的WWM(Whole...

weixin_30836759的博客 4566

基于BERT的文本分类: 使用BERT进行句子级文本分类

文本分类是自然语言处理领域中的一个重要任务,它涉及将文本分为不同的预定义类别。BERT模型是通过对大规模的无监督文本进行预训练而得到的。BERT的输入是一段文本,它会经过一个词嵌入层将每个词转换为向量表示,然后将这些向量输入到多层的Transformer编码器中进行处理。首先,我们对数据集进行了预处理,将文本转换为BERT模型所期望的输入格式。然后,我们加载了预训练的BERT模型,并对其进行微调以适应特定的文本分类任务。数据集应该包含两列:一列是文本内容,另一列是对应的类别标签。

EbCoder的博客 345

基于Huggingface使用BERT进行文本分类的fine-tuning

随着BERT大火之后,很多BERT的变种,这里借用Huggingface工具来简单实现一个文本分类,从而进一步通过Huggingface来认识BERT的工程上的实现方法。 1、loaddata train_df = pd.read_csv('../data/train.tsv',delimiter='t',names=['text','label']) print(train_df.shape) train_df.head() sentences = list(train_...

写代码,是犯罪. 找bug,是破案- -.. 2757

玩转Zabbix智能告警:降噪、排班、认领、升级、IM协同

集成Zabbix告警到FlashDuty,获得告警降噪、智能排班、IM协同等能力

n9ecommunity的博客 1046

Power BI----各类切片器的使用

首先介绍切片器的最基础的创建和效果演示,紧跟着介绍切片器在多页中的同步和本身与报表的联动,再然后介绍关于切片器属性的设置,使得交互更加美观,最后介绍几种很好看的第三方的切片器样式和自己构建的可折叠的切片器.........

Itsme_MrJJ的博客 2万+

Bert实战:使用Bert实现文本分类。

1、简介 最近使用Bert实现了文本分类,模型使用的是bert的base版本。本文记录一下实现过程。 数据集:cnews,包含三个文件,分别是cnews.train.txt、cnews.test.txt、cnews.val.txt。类别包含10类,分别是:体育、娱乐、家居、房产、教育、时尚、时政、游戏、科技、财经。 代码参考:https://github.com/BeHappyForMe/Multi_Model_Classification,对代码的一些部分作了修改和注解。关注公众号“AI小浩”,回复“be

AI浩 2万+

360加固DEX解密与ELF修复技术解析

本文深入解析360加固的DEX解密与ELF修复技术,详细介绍了其多层保护机制、Java层入口分析、Native层加载流程及反调试绕过技巧。通过RC4和zlib解密技术,结合Frida工具实现内存Dump和ELF文件修复,为逆向工程师提供实用解决方案。

weixin_29327525的博客 513

bert使用做文本分类_使用BERT进行深度学习的多类文本分类

bert使用做文本分类Most of the researchers submit their research papers to academic conference because its a faster way of making the results available. Finding and selecting a suitable conference has always ...

weixin_26752765的博客 1695

从Verilog到GDS:手把手教你搞定Calibre LVS物理验证(附常见报错解决)

本文详细介绍了从Verilog到GDS的Calibre LVS物理验证全流程,包括工具链配置、RTL到SPICE网表转换、LVS运行配置及高级技巧。重点解析了常见报错如网络不匹配、器件不匹配和电源引脚缺失的解决方案,帮助工程师高效完成芯片物理验证,确保设计正确性。

culing2941的博客 508

Kubernetes+EdgeX:构建企业级AI边缘推理平台

设备:工业摄像头(RTSP协议,输出1920x1080视频流);AI模型:YOLOv8训练的轴承裂纹检测模型(识别“裂纹”“正常”两种类型);目标:摄像头采集图像→EdgeX传输数据→K8s推理服务检测→结果反馈到报警器(HTTP协议)。Kubernetes+EdgeX的组合,为企业构建AI边缘推理平台提供了标准化、可扩展标准化:K8s的容器编排和EdgeX的设备管理,都是行业标准,避免“重复造轮子”;可扩展:支持从单边缘节点到 thousands of nodes 的规模,满足企业的增长需求;

AI算力网络与通信的博客 1344

AI:使用pytorch通过BERT模型进行文本分类

BERT 是一个强大的语言模型,至少有两个原因:它使用从 BooksCorpus (有 8 亿字)和 Wikipedia(有 25 亿字)中提取的未标记数据进行预训练。它是通过利用编码器堆栈的双向特性进行预训练的。这意味着 BERT 不仅从左到右,而且从右到左从单词序列中学习信息。BERT 模型需要一系列 tokens (words) 作为输入。在每个token序列中,BERT 期望输入有两个特殊标记:[CLS] :这是每个sequence的第一个token,代表分类token。

GIS摆渡人 739

【推荐100个unity插件】Animator 的替代品?—— Animancer Pro插件的使用介绍

Animancer与Unity Animator对比及使用指南 摘要: 本文对比了Animancer与Unity官方Animator的核心差异,分析了Animancer的优势特点。Animancer采用代码驱动模式,相比Animator的状态机系统更灵活高效,支持实时调试、动态混合和深度逻辑集成。文章详细介绍了Animancer的快速使用方法,包括动画播放、切换和触发机制,并区分了免费版与专业版的功能差异。适合需要高效动画开发、复杂交互逻辑的中小项目,为开发者提供了一种现代化的动画解决方案。

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 2435

pytorch bert文本分类_机器学习中使用BERT强大的转换器进行多标签文本分类

在本文中,我们将重点介绍BERT在机器学习中对于多标签文本分类问题中的应用。传统的分类任务假定每个文档只分配给一个类,即标签。这被称为多类分类,或者如果类的数量是2,则是二元分类。另一方面,多标签分类假设文档可以同时和独立地分配给多个标签或类。多标签分类具有许多现实世界的应用,例如分类业务或为电影分配多个类型。在客户服务领域,此技术可用于识别客户电子邮件的多个意图。我们将使用Kaggle的Toxi...

weixin_39926016的博客 876

基于STM32设计的水下水质检测装置(微信小程序)(205)

本项目设计了一款基于STM32微控制器为核心的水下水质检测设备,该设备具有高度集成化、智能化的特点,能够实时监测水深、温度、浊度及溶解性总固体(TDS)等关键水质参数,并通过4G网络将数据上传至腾讯云IOT物联网平台,实现远程监控和数据分析。同时,为了便于操作和移动观测,还配套开发了微信小程序,用户可通过微信小程序实时查看并控制设备的各项功能,如调整下潜深度等。

1252

第一章 EB安装

1.DemoWorkspace 是基于EB当前组件配置下的例程,包含了启动文件和中断服务函数以及组件demo。2.Mclsar 下存放的是EB的插件包和静态MCAL的驱动文件。

舊梦的博客 1964

使用 BERT 进行文本分类的简单代码示例

好的,这是一个使用 BERT 进行文本分类的简单代码示例: 首先,导入所需的库: import tensorflow as tf import tensorflow_hub as hub from tensorflow.keras import layers 然后,加载 BERT 预训练模型: bert_model = "https://tfhub.dev/google/bert_uncase...

weixin_35749440的博客 593

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

手把手教你使用 BERT 进行文本分类——代码逐行注释讲解

BERT(Bidirectional Encoder Representations from Transformers,全称“基于双向编码器表示的变换器”)是 Google 开发的一种强大的自然语言处理(NLP)模型,基于 Transformer 的深度神经网络架构。

python1234_的博客 6533

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

使用huggingface的Transformer库进行BERT文本分类代码

本文通过huggingface的Transform类进行BERT的文本分类代码训练与验证,数据集采用网上整理包括正向和负向评论的携程网数据,包括数据的加载、创建数据集、划分训练集和验证集、创建模型和优化器、包括训练与验证、模型的训练、模型的预测

python1222_的博客 1334

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

上一篇: YOLOv8 训练自己的数据集
下一篇: 使用SwinTransformer进行图片分类
算法美食屋
博客等级 码龄9年 2万+粉丝 154原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值