基于BERT预训练的中文命名实体识别TensorFlow实现

基于bert的命名实体识别任务(一) 自从bert提出后,nlp领域的预训练语言模型持续刷新各种任务榜单,各种预训练语言模型不断提出并更新迭代,最新的GPT3以千亿级的参数再次刷新了榜单任务。但是在工业界,bert的预训练+微调的任务模式还是在发挥一定的作用。因此本篇博客主要介绍在tf2.x的版本下使用bert模型进行命名实体识别任务。 bert模型的原理还是先简单介绍一下,主要从一下几个方面: 一、任务目标 bert的目标是学习大量的没有标注的语料数据,进而提取出语言模型,便于下游的微调任务。在训练的过程中主要有两个任务:其一是根据上下 阅读详情
AI摘要

本文介绍了一种结合BERT预训练模型与BiLSTM-CRF结构的中文命名实体识别方法,并提供了详细的训练流程及代码实现。

BERT-BiLSMT-CRF-NER

Tensorflow solution of NER task Using BiLSTM-CRF model with Google BERT Fine-tuning
GitHub: https://github.com/macanv/BERT-BiLSTM-CRF-NER
本文目录机构:

  1. 自己训练模型
  2. 说明
  3. 结果
  4. 使用自己的数据

2019.1.31更新,支持pip install package


现在可以使用下面的命令下载软件包了:

pip install bert-base==0.0.7 -i https://pypi.python.org/simple

或者使用基于源代码的安装:

git clone https://github.com/macanv/BERT-BiLSTM-CRF-NER
cd BERT-BiLSTM-CRF-NER/
python3 setup.py install

如果没啥问题,你将会看到这个:
安装成功
笔者在windows10/ Linux/ Mac OSX上都测试过,安装没有问题。

软件包现在支持的功能

  1. 命名实体识别的训练
  2. 命名实体识别的服务C/S
  3. 继承优秀开源软件:bert_as_service(hanxiao)的BERT所有服务
    4. 文本分类服务 (2019.2.19)

内容还会继续补充,同时欢迎大神们分享训练的模型或者新的方法或者数据(弱鸡的我并不会用在商业上,毕竟还是一个毕业即失业的渣渣~~)。

基于命名行训练命名实体识别模型:

安装完bert-base后,会生成两个基于命名行的工具,其中bert-base-ner-train支持命名实体识别模型的训练,你只需要指定训练数据的目录,BERT相关参数的目录即可。可以使用下面的命令查看帮助

bert-base-ner-train -help

在这里插入图片描述
训练的事例命名如下:

bert-base-ner-train \
    -data_dir {your dataset dir}\
    -output_dir {training output dir}\
    -init_checkpoint {Google BERT model dir}\
    -bert_config_file {bert_config.json under the Google BERT model dir} \
    -vocab_file {vocab.txt under the Google BERT model dir}
参数说明
  1. 其中data_dir是你的数据所在的目录,训练数据,验证数据和测试数据命名格式为:train.txt, dev.txt,test.txt,请按照这个格式命名文件,否则会报错。
    训练数据的格式如下:
    海 O
    钓 O
    比 O
    赛 O
    地 O
    点 O
    在 O
    厦 B-LOC
    门 I-LOC
    与 O
    金 B-LOC
    门 I-LOC
    之 O
    间 O
    的 O
    海 O
    域 O
    。 O
    

每行得第一个是字,第二个是它的标签,使用空格’ '分隔,请一定要使用空格。句与句之间使用空行划分。程序会自动读取你的数据。

  1. output_dir: 训练模型输出的文件路径,模型的checkpoint以及一些标签映射表都会存储在这里,这个路径在作为服务的时候,可以指定为-ner_model_dir
  2. init_checkpoint: 下载的谷歌BERT模型
  3. bert_config_file : 谷歌BERT模型下面的bert_config.json
  4. vocab_file: 谷歌BERT模型下面的vocab.txt

训练完成后,你可以在你指定的output_dir中查看训练结果。

将命名实体识别任务进行服务部署

作为服务的很多代码都来自优秀的开源项目: bert as service of hanxiao 但是我不知道这样改动是不是违反了某些许可规定,如果有违反,请马上告诉我,我将第一时间进行修改.而且服务端的代码很解耦,修改为另外一种任务的服务也是很简单的,例如文本分类,我将会不就提供这一功能,也欢迎愿意分享的童鞋分享模型或者代码。

作为服务的命名是:bert-base-serving-start,同样的,你可以先使用-help查看相关帮助

bert-base-serving-start -help

在这里插入图片描述
作为命名实体识别任务的服务,这两个目录是你必须指定的:ner_model_dir, bert_model_dir
然后你就可以使用下面的命令启动了:

bert-base-serving-start \
    -model_dir C:\workspace\python\BERT_Base\output\ner2 \
    -bert_model_dir F:\chinese_L-12_H-768_A-12
    -mode NER
参数解释

bert_model_dir: 谷歌BERT模型的解压路径,可以在这里下载 https://github.com/google-research/bert
model_dir: 训练好的NER模型或者文本分类模型的路径,对于上面的output_dir
model_pd_dir: 运行模型优化代码后, 经过模型压缩后的存储路径,例如运行上面的命令后改路径下会产生 ner_model.pb 这个二进制文件
mode:NER 或者是BERT这两个模式,类型是字符串,如果是NER,那么就会启动NER的服务,如果是BERT,那么具体参数将和[bert as service] 项目中得一样。

我提供了命名实体识别pb模型下载:https://pan.baidu.com/s/1m9VcueQ5gF-TJc00sFD88w, 提取码: guqq
文本分类模型:https://pan.baidu.com/s/1oFPsOUh1n5AM2HjDIo2XCw, 提取码: bbu8
文本分类使用的是bert中的demo:run_classxxx.py,在运行的时候使用Pickle序列化了label_list和id2label折两个变量。
将 ner_mode.pb/classification_model.pb 文件放到 model_pd_dir目录下,将命名识别的label_list.pkl和id2map.pkl不同的模型不同的文件夹,因为他们同名,但是内容不一样,需要区分开来
命名实体识别模型只支持人名,地名,住址机构名的识别,在我的测试数据上有95.6%的F1值(实体级别的得分)
文本分类模型数据来自清华大学的文本分类数据:http://thuctc.thunlp.org/ , 在测试数据上准确率为98%~99%的准确率
肥肠欢迎大家分享你们训练的更好的模型。

如果使用的下载的模型,你可以使用下面的命令启动,替换你自己的路径即可:

bert-base-serving-start -model_pd_dir /home/macan/ml/workspace/BERT_Base/output/predict_optimizer  \ 
	-bert_model_dir /home/macan/ml/data/chinese_L-12_H-768_A-12/ \
	-ner_model_dir /home/macan/ml/data/bert_ner \
	-num_worker 8 
	-mode NER

你将会看到下面的启动信息(启动log有点多,分两张图截):
在这里插入图片描述
在这里插入图片描述

在本地连接服务端进行命名实体识别的测试

你可以使用下面的代码进行服务的连接,在本地进行NER测试,客户端代码如下:

import time
from bert_base.client import BertClient
# 指定服务器的IP
with BertClient(ip='XXX,XXX,XXX,XXX', ner_model_dir=ner_model_dir, show_server_config=False, check_version=False, check_length=False, mode='NER') as bc:
    start_t = time.perf_counter()
    str = '1月24日,新华社对外发布了中央对雄安新区的指导意见,洋洋洒洒1.2万多字,17次提到北京,4次提到天津,信息量很大,其实也回答了人们关心的很多问题。'
    rst = bc.encode([str, str])  #测试同时输入两个句子,多个输入同理
    print('rst:', rst) 
    print(time.perf_counter() - start_t)

运行后,会输出下面的信息:
在这里插入图片描述

结果说明:

返回的结果就是序列标注的结果,再往后的工作就不准备再写了,因为后面的操作会涉及到一些策略问题,写的太多,影响代码的灵活,例如有童鞋在terminal_predict.py的代码上提了issue,无法应用到自己的数据中。这样看起来,也比较直观吧~~

到此,基于命令行的用法已经讲完,不明白的地方请评论或者在GitHub上提交issue,觉得有用,麻烦在GitHub上点个star吧~~

###########################################################################################

以下是基于源代码的训练和启动服务的教程

###########################################################################################

自己训练命名实体识别模型

使用谷歌的BERT模型在BLSTM-CRF模型上进行预训练用于中文命名实体识别的Tensorflow代码’

代码已经托管到GitHub 代码传送门 大家可以去clone 下来亲自体验一下!

git clone https://github.com/macanv/BERT-BiLSTM-CRF-NER

关于BERT的相关理论文章不是本文的主要目的,而且网上简介该部分的文章多如牛毛,大家自行去查看吧,本文着重讲解基于BERT用于中文命名实体的fine-tuning 过程。

1. 下载Google BERT 预训练模型:

下载
wget https://storage.googleapis.com/bert_models/2018_11_03/chinese_L-12_H-768_A-12.zip  
解压
unzip chinese_L-12_H-768_A-12.zip

2. 训练模型

下载了Google的BERT模型和我的GitHub代码后,就可以开始训练啦
训练之前先在项目目录中新建一个output文件夹,模型的输出,和结构都会保存在这个目录中

mkdir output

训练的时候需要一些参数,你可以使用命名行的形式进行模型参数指定,例如下面的方法:

  python3 bert_lstm_ner.py   \
                  --task_name="NER"  \ 
                  --do_train=True   \
                  --do_eval=True   \
                  --do_predict=True
                  --data_dir=NERdata   \
                  --vocab_file=checkpoint/vocab.txt  \ 
                  --bert_config_file=checkpoint/bert_config.json \  
                  --init_checkpoint=checkpoint/bert_model.ckpt   \
                  --max_seq_length=128   \
                  --train_batch_size=32   \
                  --learning_rate=2e-5   \
                  --num_train_epochs=3.0   \
                  --output_dir=./output/result_dir/ 

笔者比较菜,选择的是将默认参数写在代码中,开始训练的之前,只需要修改下面的代码即可,代码在bert_lstm_ner.py文件中

if os.name == 'nt': #windows path config
   bert_path = '{your BERT model path}'
   root_path = '{project path}'
else: # linux path config
   bert_path = '{your BERT model path}'
   root_path = '{project path}'

os.name=='nt’是表示识别到的系统是windows,其余的是Linux,这里只需要修改一个,如果你是windows训练修改os.name='nt’下面的路径就好了,Linux或者Mac修改else下面的两个路径。
两个路径说明:
bert_path: 就是在步骤1中下载解压的BERT模型的路径,复制绝对路径替换即可,例如我项目中所写的路径
root_path: 这个是项目的路径,也是一个绝对路径,即BERT-BiLSTM-CRF-NER的路径

修改好两个路径后,就可以开始训练了:

python3 bert_lstm_ner.py

说明:

模型代码主要在bert_lstm_ner.py中的create_model函数中
下面对该函数逻辑进行讲解:

  • 1使用bert模型对我们的输入进行represent
	#使我们的input_ids数据通过bert 网络结构
    model = modeling.BertModel(
        config=bert_config,
        is_training=is_training,
        input_ids=input_ids,
        input_mask=input_mask,
        token_type_ids=segment_ids,
        use_one_hot_embeddings=use_one_hot_embeddings
    )
    # 获取bert 模型最后一层
    embedding = model.get_sequence_output()

bert 的最后一层是所有transformer结果的最后一维,其是一个三维向量维度是:[batch_size, seq_length, embedding_size],可以类比的理解为我们使用tf.nn.embedding_lookup获取的结果。

  • 2 将embedding 作为LSTM结构的输入:
	# 加载BLSTM-CRF模型对象
    blstm_crf = BLSTM_CRF(embedded_chars=embedding, hidden_unit=FLAGS.lstm_size, cell_type=FLAGS.cell, num_layers=FLAGS.num_layers,
                          dropout_rate=FLAGS.droupout_rate, initializers=initializers, num_labels=num_labels,
                          seq_length=max_seq_length, labels=labels, lengths=lengths, is_training=is_training)
    # 获取添加我们自己网络结构后的结果,这些结果包括loss, logits, trans, pred_ids
    rst = blstm_crf.add_blstm_crf_layer(crf_only=True)

这里有几点需要说明:

  1. 因为BERT里面已经存在双向编码,所以LSTM并不是必须的,可以将BERT最后一层的结构直接扔给CRF进行解码。所以在代码中通过在add_blstm_crf_layer函数中的crf_only参数进行控制我们训练的时候使用的是那种网络结构用于最后的fine-tuning.通过两种结构的训练结果对比,其实他们的最后结果相差不大,可以说基本是一样的,足见transformer的强大。
  2. crf_only=True 是我们fine-tuning 只使用CRF进行解码,不再使用传统经典的BLSTM-CRF,False表示使用blstm-crf这样的网络结构。
  3. 但是我在试验中发现,只使用CRF的训练时间要比BLSTM-CRF结构的时间要长,这一点我百思不得其解,按理加了BLSTM网络的参数会更多,如果有大佬发现这是个错的观察或者有合理的解释,麻烦不吝赐教。

实验结果

  • 1 基于label计算出来的指标:
In dev data set:

在这里插入图片描述

In test data set

在这里插入图片描述

  • 2 在很多地方命名实体的结果使用基于实体级别的评测更为合理,下面是实体级别的评测结果。
    在这里插入图片描述

评测脚本使用的是conlleval.pl, conlleval.py

提供我训练的模型下载:

my model can download from baidu cloud:
链接:https://pan.baidu.com/s/1GfDFleCcTv5393ufBYdgqQ 提取码:4cus

  • 3 在线预测
    当你的模型训练完后,可以使用下面的脚本加载模型,进行在线预测
python3 terminal_predict.py

在这里插入图片描述

使用自己的数据:

BERT的大腿简直太粗了,效果很好有木有,看到这样的效果,是不是很想再自己的数据上进行测试一番呢? 其实改的地方很少,只需要修改bert_lstm_ner.py文件中的几行代码就好啦:

    1. get_labels 函数
    def get_labels(self):
        return ["O", "B-PER", "I-PER", "B-ORG", "I-ORG", "B-LOC", "I-LOC", "X", "[CLS]", "[SEP]"]

这里是我数据中所有的标签,其中"X", “[CLS]”, “[SEP]” 是附加的, “[CLS]”, "[SEP]"是句子的开始和结束标志,X是wordpice产生的东西,中文中目前还没有遇到过,可以不用管,大家要改的话,就改前面的标签就好啦。
例如你想加一个时间类型的实体,就加 “B-TIME”, “I-TIME”
如果你想应用于分词中,那就没有-XXX了。就是B,I这些,简而言之,就是你的序列标注数据中的第二列的标签的set集合。
你也可以把get_labels函数写成这样一劳永逸,但是要注意在测试集或者验证机中出现的OOLabel哦:

    def get_labels(self):
        # 通过读取train文件获取标签的方法会出现一定的风险。
        if os.path.exists(os.path.join(FLAGS.output_dir, 'label_list.pkl')):
            with codecs.open(os.path.join(FLAGS.output_dir, 'label_list.pkl'), 'rb') as rf:
                self.labels = pickle.load(rf)
        else:
            if len(self.labels) > 0:
                self.labels = self.labels.union(set(["X", "[CLS]", "[SEP]"]))
                with codecs.open(os.path.join(FLAGS.output_dir, 'label_list.pkl'), 'wb') as rf:
                    pickle.dump(self.labels, rf)
            else:
                self.labels = ["O", 'B-TIM', 'I-TIM', "B-PER", "I-PER", "B-ORG", "I-ORG", "B-LOC", "I-LOC", "X", "[CLS]", "[SEP]"]
        return self.labels

参考:

BERT+CRF实现中文命名实体识别(TensorFlow) 本篇解读了基于BERT+CRF做中文NER这篇文章中的代码,在该篇作者的GitHub上可以下载源码:源代码。这段代码对BERT模型的实现较为简洁,删掉了谷歌源代码中我们可能用不到的部分,保留了核心部分。对于那些想要快速上手BERT的同学是非常好的学习机会,在看懂这个之后再去学习谷歌的源代码会更加轻松。 BERT-CRF模型 之前有写过BERT模型和CRF模型的详解,建议往下看之前一定要了解这两个模型的原理:结合原理和代码来理解bert模型、结合原理与代码理解BiLSTM-CRF模型(pytorch)。B 阅读详情

相关推荐

BERT的demo运行

BERT的demo运行概述实际操作1.环境2.下载bert源码和demo源码3.下载预训练模型4.下载训练数据:5. run demo:6.总结: 概述 自从google发布了《Pre-training of Deep Bidirectional Transformers for Language Understanding》,一举刷新多项NLP领域记录后。BERT模型可谓红遍NLP领域,许多人都...

weixin_43948816的博客 1万+

BERT-BiLSTM-CRF基于BERT预训练的中文命名实体识别TensorFlow实现

向AI转型的程序员都关注了这个号????????????机器学习AI算法工程 公众号:datayxTensorflow solution of NER task Using BiL...

datayx的文章 1万+

利用BERT进行命名实体识别(NER)

命名实体识别 (Named Entity Recognition, NER) 是自然语言处理 (Natural Language Processing, NLP) 中的一项基础任务,旨在识别文本中代表命名实体的词语或词语序列,并将其分类到预定义的类别,例如人名、地名、机构名、时间、日期等。NER 是许多 NLP 应用的重要组成部分,例如信息提取、问答系统、机器翻译和文本摘要等。传统的 NER 方法通常依赖于手工设计的特征和领域特定的规则,这些方法需要大量的专家知识,并且难以推广到新的领域或语言。

AI天才研究院 3862

用BERT做命名实体识别任务

命名实体识别NER任务是NLP的一个常见任务,它是Named Entity Recognization的简称。简单地说,就是识别一个句子中的各种 名称实体。诸如:人名,地名,机构 等。例如对于下面这句话:小明对小红说:"你听说过安利吗?"它的NER抽取结果如下:[{'entity':'person', 'word':'小明', 'start':0, 'end':2}, {'e...

Python_Ai_Road的博客 3440

Bert基础(十八)--Bert实战:NER命名实体识别

命名实体识别(NER)是自然语言处理(NLP)中的一项关键技术,它的目标是从文本中识别出具有特定意义或指代性强的实体,并对这些实体进行分类。这些实体通常包括人名、地名、组织机构名、日期、时间、专有名词等。NER在许多实际应用中都非常重要,如信息提取、文本挖掘、机器翻译、自动摘要等。实体的边界识别:这部分任务是要确定文本中实体的起始和结束位置,即在文本中准确地定位出实体的边界。确定实体的类型:在识别出实体的边界之后,还需要确定每个实体的具体类型,如人名、地名、机构名等。例如,在处理文本。

Andy_shenzl的博客 3361

TensorFlow实现中文命名实体识别项目实战

TensorFlow是由Google开发的开源机器学习库,它为从研究到生产提供了广泛的工具、库和社区资源。TensorFlow使用数据流图表示算法,而数据流图的节点代表数学运算,边代表数据流动。这种设计允许它进行高效的自动微分计算,非常适合实现复杂的深度学习模型。TensorFlow的设计目标之一是易于扩展。它支持多种语言,并且可以部署在不同的硬件平台上。TensorFlow还包含了一个强大的可视化工具TensorBoard,它可以展示图形化的训练结果,帮助开发者更好地理解模型的性能和结构。

weixin_42583683的博客 1040

中文命名实体识别的实战代码

基于BERT预训练的中文命名实体识别TensorFlow实现 https://blog.youkuaiyun.com/macanv/article/details/85684284 https://github.com/wusaisa/BERT-BiLSTM-CRF-NER

升级迭代 3691

Python-用谷歌BERT模型在BLSTMCRF模型上进行预训练用于中文命名实体识别的Tensorflow代码

Tensorflow solution of NER task Using BiLSTM-CRF model with Google BERT Fine-tuning

命名实体识别-跑代码实录

跑代码实录命名实体识别实践与探索 命名实体识别实践与探索 下载 BERT_CHINESE 预训练的 ckpt 模型,然后解压到 bert_model 目录下 环境:Python3, Tensorflow1.12 2.1 创建conda环境 conda create -n ner python=3 2.2 进入ner环境 conda activate ner 2.3 安装tensorflow conda install tensorflow=1.12 2.4 运行log ...

hongguoya的博客 1523

轴承故障诊断——领域知识

幅域分析、频域分析及轴承方面的领域知识

qq_58516607的博客 3531

统一大型语言模型和知识图谱:路线图

大型语言模型(LLM),如ChatGPT和GPT4,由于其涌现能力和泛化性,正在自然语言处理和人工智能领域掀起新的浪潮。然而,LLM是黑箱模型,通常无法捕捉和获取事实知识。相反,知识图谱(KGs),例如维基百科和华普,是显式存储丰富事实知识的结构化知识模型。KGs可以通过为推理和可解释性提供外部知识来增强LLM。同时,KGs很难从本质上构建和演化,这对KGs中现有的生成新事实和表示未知知识的方法提出了挑战。因此,将LLM和KGs统一在一起并同时利用它们的优势是相辅相成的。

qq_32907491的博客 2841

TensorFlow在中文NLP领域的最新应用与实战解析

在训练或微调生成模型时,需要采用自回归的方式,并关注解码策略,如贪心搜索、束搜索(Beam Search)、Top-k采样和核采样(Top-p采样),以在生成文本的准确性和多样性之间取得平衡。微调是指在特定任务的数据集上,以较小的学习率继续训练预训练模型的所有或部分参数。TensorFlow在这一领域同样提供了支持,我们可以利用Keras Functional API灵活地构建多输入模型,将文本特征(通过预训练NLP模型提取)与图像特征(通过预训练CNN模型如ResNet提取)进行融合,共同完成下游任务。

sogaoli的博客 583

UMI刷盘机器人代码实战:从SLAM到Diffusion Policy的完整部署流程

本文详细解析了UMI(Universal Manipulation Interface)刷盘机器人从数据准备到真实部署的完整实战流程。通过SLAM处理视频数据生成三维轨迹,并训练Diffusion Policy模型,最终将策略部署到UR5机械臂与WSG50夹爪上,实现从模仿学习到物理执行的闭环。

weixin_29042035的博客 460

用于文本的TensorFlow:使用TensorFlow的BERT

本指南探讨了 BERT 及其使用 TensorFlow 的各种应用,包括文本分类、命名实体识别 (NER) 和语言翻译。(NER) 是自然语言处理 (NLP) 的一个子领域,涉及识别文本中的实体并将其分类为预定义的类别,例如人名、组织、位置、日期等。使用 BERT 进行语言翻译并不是最常见或直接的方法,因为 BERT 主要设计用于句子分类、命名实体识别和类似任务等任务,而不是语言翻译等序列到序列任务。BERT 使用 WordPiece 标记化,将单词分割成更小的子词,使模型能够处理词汇表之外的单词。

新华编程特战队 1929

论文分享 - OctoMap八叉树建图原理

论文:OctoMap:An Efficient Probabilistic 3D Mapping Framework Based on Octrees。

一只废佐_的博客 2537

PINN——加入物理约束的神经网络

【摘要】 基于物理信息的神经网络(Physics-informed Neural Network, 简称PINN),是一类用于解决有监督学习任务的神经网络,它不仅能够像传统神经网络一样学习到训练数据样本的分布规律,而且能够学习到数学方程描述的物理定律。与纯数据驱动的神经网络学习相比,PINN在训练过程中施加了物理信息约束,因而能用更少的数据样本学习到更具泛化能力的模型。本文主要解析这种神经网络以...

qq_39444290的博客 4581

BERT入门(tensorflow)

在家无聊,Chatgpt最近蛮火的,便开始学习了一下NLP,接触到了BERT。这篇博客将讲一讲我从零到跑通中文文本相似度计算的过程。只是想使用BERT的话直接跳转到五对于BERT的原理,其他博主已经做了许多介绍,并且十分详尽。在这里略述一些作为入门BERT是一种预训练语言模型(pre-trained language model, PLM),其全称是Bidirectional Encoder Representations from Transformers。

梓川枫的博客 2559

在Rviz仿真环境中搭建传送带

<geometry><material>

qq_58268456的博客 934
上一篇: hadoop2.7编译以及部署时遇到的坑
下一篇: Windows下PySpark 环境搭建篇以及词频统计(1)
Macanv
博客等级 码龄14年 407粉丝 65原创
评论 467
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值