mindNLP
API reference
另一个API reference,这个全
介绍这是什么
MindNLP是基于MindSpore的开源NLP库。这个是个package,类似于huggingface的transformer库,有 250+ 预训练模型支持类似 huggingface transformers 的 API。您可以通过以下代码片段轻松使用,这样可以直接使用已经定义好的模型并且还有模型的权重:支持的模型
1 2 3 import mindnlp.transformers import AutoModel model = AutoModel.from_pretrained('bert-base-cased')
全面的数据处理:将多个经典的 NLP 数据集打包成友好的模块,以便于使用,例如 Multi30k、SQuAD、CoNLL 等。
友好的 NLP 模型工具集:MindNLP 提供了各种可配置的组件。使用 MindNLP 自定义模型很友好。
易于使用的引擎:MindNLP 简化了 MindSpore 中复杂的训练过程。它支持 Trainer 和 Evaluator 接口,可轻松训练和评估模型。
全平台支持:全面支持昇腾 910 系列、昇腾 310B (Orange Pi)、GPU 和 CPU。(注意:目前 Orange Pi 上唯一可用的 AI 开发套件。
分布式并行推理:对超过 10B 参数的模型提供多设备、多进程并行推理支持。
量化算法支持:SmoothQuant 可用于 Orange Pi;GPU 支持类似 bitsandbytes 的 int8 量化。
Sentence Transformer 支持:实现高效的 RAG(检索增强生成)开发。
动态图性能优化:在 Ascend 硬件上实现动态图的 PyTorch+GPU 级推理速度(在 85 毫秒/令牌下测试 Llama 性能)。
真正的静态和动态图统一:使用 mindspore.jit 单行切换到图形模式,完全兼容 Hugging Face 代码风格,既易于使用,又能快速提升性能。在Ascend硬件上测试的Llama性能达到了2倍的动态图速度(45ms/token),与其他MindSpore基于静态图的套件一致。
广泛的 LLM 应用程序更新:包括文本信息提取、聊天机器人、语音识别、ChatPDF、音乐生成、代码生成、语音克隆等。随着模型支持的增加,更多令人兴奋的应用程序等待开发!
安装
1 2 3 4 5 6 7 8 9 10 11 # whl的下载位置: https://repo.mindspore.cn/mindspore-lab/mindnlp/newest/any/ # 直接pip就可以安装 pip install mindnlp # source安装 pip install git+https://github.com/mindspore-lab/mindnlp.git # or git clone https://github.com/mindspore-lab/mindnlp.git cd mindnlp bash scripts/build_and_reinstall.sh # 版本要求:python >=3.9, <=3.11 mingspore >=2.2.x
补充知识
分词器,词表,预训练的词向量模型
1 2 3 4 5 6 7 # 使用分词器分词 tokens = tokenizer.tokenize("Hello, how are you?") print(tokens) # 输出: ['hello', ',', 'how', 'are', 'you', '?'] # 使用词表映射到索引 indices = vocab(tokens) print(indices) # 输出: [2, 3, 4, 5, 6, 7]
分词器tokenizer
分词器的主要任务是将文本分割成基本单元(如单词、子词或字符),并将这些单元转换为模型可以理解的数值形式(如索引)。常见的分词器包括:
空格分词器 :按空格分割文本。
BPE(Byte Pair Encoding)分词器 :将文本分割成子词单元。
WordPiece 分词器 :BERT 等模型使用的分词器。
SentencePiece 分词器 :支持无空格语言的分词器。
分词器的处理流程:
分词 :将文本分割成基本单元(如单词或子词)。
转换为索引 :将分词结果映射到词表中的索引。
添加特殊标记 :如 [CLS]
、[SEP]
、[PAD]
等。
填充或截断 :将序列长度统一为固定长度。
词表(Vocab)的作用
词表是词汇到索引的映射表。它的作用是将分词后的文本转换为数值形式,以便模型能够处理。词表通常包括:
词汇表 :所有可能的词汇或子词。
特殊标记 :如 <unk>
(未知词)、<pad>
(填充标记)等。
索引映射 :将每个词汇映射到一个唯一的索引。
glove预训练词向量
GloVe(Global Vectors for Word Representation) 是一种预训练的词向量模型,它通过全局词共现统计来学习词汇的分布式表示。主要作用是为词汇提供语义丰富的向量表示,从而增强模型对文本的理解能力。是一种嵌入层embedding。
(1)语义表示 GloVe 词向量捕捉了词汇之间的语义关系。例如,king - man + woman ≈ queen
,这种关系在向量空间中可以通过向量加减来表示。
(2)降维 将高维的离散词汇表示(如 one-hot 编码)转换为低维的连续向量表示。例如,一个词汇可以用一个 100 维的向量表示,而不是一个数万维的 one-hot 向量。
(3)初始化嵌入层 在训练 NLP 模型时,GloVe 词向量可以作为嵌入层(Embedding Layer)的初始化参数,从而加速模型收敛并提升性能。
(4)解决稀疏性问题 传统的 one-hot 编码会导致数据稀疏性问题,而 GloVe 词向量是稠密的,能够更好地表示词汇。
1 2 3 4 5 6 7 8 9 10 11 from torchtext.vocab import GloVe # 加载预训练的 GloVe 词向量(6B 表示训练语料为 60 亿词,100 表示向量维度) glove = GloVe(name='6B', dim=100) # 查看词汇表大小 print(len(glove.itos)) # 输出: 400000(GloVe 6B 包含 40 万个词汇) # 获取单词 "king" 的词向量 king_vector = glove['king'] print(king_vector.shape) # 输出: torch.Size([100])
词表和glove预训练词向量不是一个东西
虽然 GloVe 预训练词向量 和 词表(Vocab) 都涉及将词汇转换为向量或索引。
大多数深度学习模型(如 LSTM、Transformer)的输入是索引序列,而不是直接输入向量序列。词表将文本转换为索引序列,而 GloVe 词向量用于将索引映射为向量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 # 将文本转换为索引 text = "hello NLP" indices = vocab(text.split()) print(indices) # 输出: [2, 4] # 加载 GloVe 词向量 glove = GloVe(name='6B', dim=100) # 创建嵌入层,并使用 GloVe 词向量初始化 embedding_layer = nn.Embedding.from_pretrained(glove.vectors, freeze=False) # 将索引转换为 GloVe 向量 input_indices = torch.LongTensor(indices) embedded_vectors = embedding_layer(input_indices) print(embedded_vectors.shape) # 输出: torch.Size([2, 100])
学习使用
官方参考文件
另一个官方参考文件
使用模型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 import math from mindspore import nn from mindspore import ops from mindspore.common.initializer import Uniform, HeUniform from mindnlp.modules import Glove from mindnlp.modules import RNNEncoder # 使用 Seq2vecModel 进行模型构建。模块 Seq2vecModel 的功能是提取输入序列数据的语义特征并计算得到结果向量。这一模块由 encoder 和 head 两部分组成,其中 encoder 将输入句子映射为语义向量,而 head 对 encoder 的输出进行进一步计算得到最终的结果。 # 使用MindNLP提供的 RNNEncoder 作为模型的 encoder ,并使用自定义的模块作为模型的 head 。 # 定义一个head class Head(nn.Cell): """ Head for Sentiment Classification model """ def __init__(self, hidden_dim, output_dim, dropout): super().__init__() weight_init = HeUniform(math.sqrt(5)) bias_init = Uniform(1 / math.sqrt(hidden_dim * 2)) self.fc = nn.Dense(hidden_dim * 2, output_dim, weight_init=weight_init, bias_init=bias_init) self.sigmoid = nn.Sigmoid() self.dropout = nn.Dropout(1 - dropout) def construct(self, context): context = ops.concat((context[-2, :, :], context[-1, :, :]), axis=1) context = self.dropout(context) return self.sigmoid(self.fc(context)) # 使用encoder hidden_size = 256 output_size = 1 num_layers = 2 bidirectional = True drop = 0.5 lr = 0.001 embedding, vocab = Glove.from_pretrained('6B', 100, special_tokens=["<unk>", "<pad>"], dropout=drop) lstm_layer = nn.LSTM(100, hidden_size, num_layers=num_layers, batch_first=True, dropout=drop, bidirectional=bidirectional) sentiment_encoder = RNNEncoder(embedding, lstm_layer) sentiment_head = Head(hidden_size, output_size, drop) # 把这两个传进去生成model net = SentimentClassification(sentiment_encoder, sentiment_head)
使用数据集
通过对应接口加载
1 2 3 4 5 6 7 8 9 10 11 12 13 from mindnlp.dataset import Multi30k multi30k_train, multi30k_valid, multi30k_test = Multi30k("./dataset") multi30k_train = Multi30k(root="./dataset", split='train') 通过注释或者网站对应的接口 文档 查看参数列表以及返回值等信息: # 参数: # root (str) - 存放数据集的目录。默认:”~/.mindnlp”。 # split (str|Tuple[str]) - 要返回的数据集分块。默认:(‘train’, ‘valid’, ‘test’). # language_pair (Tuple[str]) - 包含源语言和目标语言的元组。默认:(‘de’, ‘en’). # proxies (dict) - 定义代理的字典,例如:{“https”: “https://127.0.0.1:7890”}. # 返回: # datasets_list (list) - 加载完成的数据集分块列表。如果只加载了一个数据集分块, 如:’trian’,那么就只返回这个数据集分块,而不是一个列表。
通过对应接口load预处理
可以在 mindnlp.dataset
下找到对应数据集接口,名称为数据集名称加下划线以及 Process
,其中的 vocab
为如上生成的词表:
1 2 3 4 5 6 7 8 9 10 11 from mindnlp.dataset import Multi30k_Process train_dataset = Multi30k_Process(train_dataset, vocab=vocab) # 通过注释或者网站对应的接口 [文档](https://mindnlp.cqu.ai/zh_CN/latest/api/dataset/machine_translation.html#module-mindnlp.dataset.machine_translation.multi30k) 查看参数列表以及返回值等信息: # 参数: # - **dataset** (*GeneratorDataset*) - Multi30k数据集。 # - **vocab** (*Vocab*) - 词表对象,用于存储分词和索引的映射。默认为空。如果为空,一个新的词表对象将会被创建。 # - **batch_size** (*int*) - 指定每个批处理数据包含的数据条目。默认值:64。 # - **max_len** (*int*) - 句子的最大长度。默认值:500。 # - **drop_remainder** (*bool*) - 当最后一批数据包含的数据条目小于batch_size时,是否丢弃该批次,而不将其传递到下一个操作。默认值:False,不丢弃 # 返回: # - **dataset** (MapDataset) - 预处理操作后返回的数据集。
1 2 3 4 5 6 7 8 9 10 11 12 # 处理和划分数据,针对语音数据集还需要分词器和词汇表 # 调用来自 Glove 的函数 from_pretrained() ,获取嵌入和词汇表 from mindnlp.modules import Glove embedding, vocab = Glove.from_pretrained('6B', 100, special_tokens=["<unk>", "<pad>"], dropout=drop) # 实例化类 BasicTokenizer 来初始化分词器: from mindnlp.dataset.transforms import BasicTokenizer tokenizer = BasicTokenizer(True) 将获取到的训练集、分词器和词汇表等传入方法 process() ,应用该方法获取处理过的训练集: from mindnlp.dataset import process imdb_train = process('imdb', imdb_train, tokenizer=tokenizer, vocab=vocab, bucket_boundaries=[400, 500], max_len=600, drop_remainder=True) # 使用方法 split() 来划分处理后的训练集,从而获取新的训练集和验证集 imdb_train, imdb_valid = imdb_train.split([0.7, 0.3])
通过统一接口加载
通过一个统一的 load
接口进行加载,第一个参数为数据集的名称字符串,用以指定数据集:
1 2 3 from mindnlp.dataset import load multi30k_train, multi30k_valid, multi30k_test = load('multi30k') multi30k_train, multi30k_valid, multi30k_test = load('multi30k', root="./dataset") # 其他参数可以通过查询接口继续添加
通过统一接口process预处理
对于不同领域中的不同数据集,有不同的处理流程,mindnlp提供了数据集的特定处理函数帮助我们快速处理数据。和前面的加载方法一样,这里同样有两种方法调用该处理函数。以 Multi30k
数据集为例:
1 2 3 from mindnlp.dataset import process multi30k_train, multi30k_valid, multi30k_test = load('multi30k') dataset_train = process('Multi30k', multi30k_train, vocab = vocab)
数据集变换处理
数据集变换处理中最重要的操作是 map
操作,可以针对数据集指定列(column)添加数据变换(Transforms),将数据变换应用于该列数据的每个元素,并返回包含变换后元素的新数据集。这里使用 BasicTokenizer
对数据集的两列进行分词,并使用 from_dataset
生成词表:
1 2 3 4 5 6 7 8 9 from mindnlp.dataset.transforms import BasicTokenizer tokenizer = BasicTokenizer(True) dataset_train= dataset_train.map([tokenizer], 'en') dataset_train= dataset_train.map([tokenizer], 'de') en_vocab = text.Vocab.from_dataset(dataset_train, 'en', special_tokens=['<pad>', '<unk>'], special_first= True) de_vocab = text.Vocab.from_dataset(dataset_train, 'de', special_tokens=['<pad>', '<unk>'], special_first= True) vocab = {'en':en_vocab, 'de':de_vocab}
用Trainer进行训练
定义loss和优化器
1 2 3 4 # 使用MindSpore提供的 `mindspore.nn.BCELoss` 来定义一个损失函数: loss = nn.BCELoss(reduction='mean') # 然后,调用 `mindspore.nn.Adam` ,并传入模型的可训练参数,从而定义运行模型所需要的优化器: optimizer = nn.Adam(net.trainable_params(), learning_rate=lr)
定义回调函数
1 2 3 4 5 6 7 8 9 from mindnlp.engine.callbacks.timer_callback import TimerCallback from mindnlp.engine.callbacks.earlystop_callback import EarlyStopCallback from mindnlp.engine.callbacks.best_model_callback import BestModelCallback # 首先需要初始化回调函数对应的类 timer_callback_epochs = TimerCallback(print_steps=2) # 用于计时的回调函数 earlystop_callback = EarlyStopCallback(patience=2) # 用于早停的回调函数 bestmodel_callback = BestModelCallback(save_path='save/callback/best_model', auto_load=True) # BestModelCallback 用于保存和加载最好的模型使用 CheckpointCallback 来保存checkpoint # 声明一个由我们事先初始化的回调函数组成的列表 callbacks = [timer_callback_epochs, earlystop_callback, bestmodel_callback]
也可自定义Callback,继承自mindnlp.abc.callback。Callback中所有的类方法都会在Trainer的训练中在特定的阶段调用。如train_begin()会在训练开始时被调用,epoch_end()会在每个epoch结束时调用。具体有哪些类方法,参见Callback文档。这里,MyCallback在每个epoch结束时调用epoch_end(),输出当前epoch结束时的loss均值。
定义评价指标
MindNLP中有很多 Metric
可以用于模型评估: Accuracy
, BleuScore
, ConfusionMatrix
, Distinct
, EmScore
, F1Score
, MatthewsCorrelation
, PearsonCorrelation
, Perplexity
, Precision
, Recall
, RougeL
, RougeN
, SpearmanCorrelation
。使用一个或多个评价指标来评估模型是有必要的。我们选择 Accuracy
作为模型的评价指标:
1 2 from mindnlp.engine.metrics import Accuracy metric = Accuracy()
也可以通过继承基类Metric自己定义
特别快的使用trainer,不需要多余写东西
1 2 3 4 5 6 7 8 9 10 11 12 13 from mindnlp.engine.trainer import Trainer trainer = Trainer(network=net, train_dataset=imdb_train, eval_dataset=imdb_valid, metrics=metric,epochs=5, loss_fn=loss, optimizer=optimizer, callbacks=callbacks) # network:训练的网络。 # train_dataset:用于训练模型的数据集。 # eval_dataset:用于评估模型的数据集。 # metrics:用于评估模型的评价指标。 # epochs:训练数据的总迭代次数。 # loss_fn:损失函数。 # optimizer:用于更新训练参数的优化器。 # callbacks:训练时执行的额外操作。 trainer.run(tgt_columns="label", jit=False)
组件
modules
用于构建神经网络模型,可以和 MindSpore 一起使用。 modules
具有三大功能模块:Embedding, Encoder-Decoder 和 Attention
Embedding
embedding直译是嵌入式、嵌入层 。本质上是一种词嵌入技术,能够将一个单词或短语表示为低维向量.mindnlp提供了一个快速通过预训练glove,fasttext,word2vec词向量简单构造embedding的方法
embedding的发展和常用embedding
embedding基本概念
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import numpy as np from mindspore import Tensor from mindspore.dataset.text.utils import Vocab from mindnlp.modules.embeddings.glove_embedding import Glove # 这个是自己定义的,需要字典和对应的向量,然后可以传入这两个参数创建一个自定义的glove # Define your own vocab vocab = Vocab.from_list(['default', 'one', 'two', 'three']) # Define your own embedding table init_embed = Tensor(np.zeros((4, 4)).astype(np.float32)) # Create your own embedding object glove_embed = Glove(vocab, init_embed) # 直接用他定义好的,pretrained的 # You can also use pre-trained word vectors glove_embed_pretrained, _ = Glove.from_pretrained() # 这个Embedding怎么反向通过向量输出文字 # The index to query for ids = Tensor([1, 2, 3]) # Computed by the built embedding output = glove_embed(ids)
Encoder-Decoder
Encoder-Decoder是一个模型架构,是一类算法统称。在这个框架下可以使用不同的算法来解决不同的人物。Encoder将输入序列转化为语义向量,Decoder根据Encoder的输出生成目标译文。MindNLP.modules.encoder 和 MindNLP.modules.decoder ,MindNLP中包含的Encoder-Decoder模块如下表所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 from mindspore import nn from mindnlp.abc import Seq2seqModel from mindnlp.modules import RNNEncoder, RNNDecoder class MachineTranslation(Seq2seqModel): def __init__(self, encoder, decoder): super().__init__(encoder, decoder) self.encoder = encoder self.decoder = decoder def construct(self, en, de): encoder_out = self.encoder(en) decoder_out = self.decoder(de, encoder_out=encoder_out) output = decoder_out[0] return output.swapaxes(1,2) enc_emb_dim = 256 dec_emb_dim = 256 enc_hid_dim = 512 dec_hid_dim = 512 enc_dropout = 0.5 dec_dropout = 0.5 # encoder en_embedding = nn.Embedding(input_dim, enc_emb_dim) en_rnn = nn.RNN(enc_emb_dim, hidden_size=enc_hid_dim, num_layers=2, has_bias=True,batch_first=True, dropout=enc_dropout, bidirectional=False) rnn_encoder = RNNEncoder(en_embedding, en_rnn) # decoder de_embedding = nn.Embedding(output_dim, dec_emb_dim) input_feed_size = 0 if enc_hid_dim == 0 else dec_hid_dim rnns = [ nn.RNNCell( input_size=dec_emb_dim + input_feed_size if layer == 0 else dec_hid_dim, hidden_size=dec_hid_dim ) for layer in range(2) ] rnn_decoder = RNNDecoder(de_embedding, rnns, dropout_in=enc_dropout, dropout_out = dec_dropout,attention=True, encoder_output_units=enc_hid_dim)
Attention
目前,MindNlp已经实现了8种注意力机制。 MindNLP.modules.attentions .
1 2 3 4 5 6 7 8 9 10 11 import mindspore from mindspore import Tensor from mindspore.text.modules.attentions import ScaledDotAttention model = ScaledDotAttention(dropout=0.9) # You can customize the query, key, vlaue vector q = Tensor(np.ones((2, 32, 512)), mindspore.float32) k = Tensor(np.ones((2, 20, 512)), mindspore.float32) v = Tensor(np.ones((2, 20, 400)), mindspore.float32) output, att = model(q, k, v) # output shape is (2, 1024, 512) # att shape is (2, 1024, 32)
示例四个
文本分类
序列翻译
机器学习
回答问题