赞
踩
目录
使用MindSpore实现一个基于RNN网络的情感分类模型
1、从 https://mindspore-website.obs.myhuaweicloud.com/notebook/datasets/aclImdb_v1.tar.gz 下载数据集。注意,可用tqdm
库对下载百分比进行可视化、用IO的方式可安全地下载临时文件,而后保存至指定的路径并返回。如下,是下载的数据集展示。
2、将IMDB数据集加载至内存并构造为迭代对象后,使用 mindspore.dataset
提供的Generatordataset
接口加载数据集迭代对象,并进行下一步的数据处理,例子如下,其中 IMDBData 类是 IMDB 数据集加载器,imdb_train
是构建的一个
对象。Generatordataset
- import mindspore.dataset as ds
-
- def load_imdb(imdb_path):
- imdb_train = ds.GeneratorDataset(
- IMDBData(imdb_path, "train"),
- column_names=["text", "label"],
- shuffle=True,
- num_samples=10000)
- imdb_test = ds.GeneratorDataset(
- IMDBData(imdb_path, "test"),
- column_names=["text", "label"],
- shuffle=False)
- return imdb_train, imdb_test
-
- imdb_train, imdb_test = load_imdb(imdb_path)
Glove( Global Vectors for Word Representation ) 词向量作为Embedding,是一种无监督学习算法。从 'https://mindspore-website.obs.myhuaweicloud.com/notebook/datasets/glove.6B.zip' 下载数据集。如下图所示。
预训练词向量是对输入单词的数值化表示,通过nn.Embedding
层,采用查表的方式,输入单词对应词表中的index,获得对应的表达向量。
由于数据集中可能存在词表没有覆盖的单词,因此需要加入<unk>
标记符;同时由于输入长度的不一致,在打包为一个batch时需要将短的文本进行填充,因此需要加入<pad>
标记符。 完成后的词表长度为原词表长度+2。mindspore.dataset.text.Vocab 用于创建用于训练NLP模型的Vocab,Vocab是数据集中可能出现的所有Token的集合,保存了各Token与其ID之间的映射关系,其中的函数 from_list(word_list, special_tokens=None, special_first=True) 从给定Token列表创建Vocab, special_tokens 表示追加到Vocab中的Token列表;tokens_to_ids(tokens) 查找指定Token对应的ID。
示例代码如下,根据输出,对应的词表大小 400002 ,向量长度为100。
- import zipfile
- import numpy as np
-
- def load_glove(glove_path):
- glove_100d_path = os.path.join(cache_dir, 'glove.6B.100d.txt')
- if not os.path.exists(glove_100d_path):
- glove_zip = zipfile.ZipFile(glove_path)
- glove_zip.extractall(cache_dir)
-
- embeddings = []
- tokens = []
- with open(glove_100d_path, encoding='utf-8') as gf:
- for glove in gf:
- word, embedding = glove.split(maxsplit=1)
- tokens.append(word)
- embeddings.append(np.fromstring(embedding, dtype=np.float32, sep=' '))
- # 添加 <unk>, <pad> 两个特殊占位符对应的embedding
- embeddings.append(np.random.rand(100))
- embeddings.append(np.zeros((100,), np.float32))
-
- vocab = ds.text.Vocab.from_list(tokens, special_tokens=["<unk>", "<pad>"], special_first=False)
- embeddings = np.array(embeddings).astype(np.float32)
- return vocab, embeddings
-
- glove_path = download('glove.6B.zip', 'https://mindspore-website.obs.myhuaweicloud.com/notebook/datasets/glove.6B.zip')
- vocab, embeddings = load_glove(glove_path) #
-
- print(len(vocab.vocab())) # 400002
- print(np.shape(embeddings)) ## (400002, 100) 比原始文件多两行
-
- idx = vocab.tokens_to_ids('the')
- embedding = embeddings[idx]
- print(f"idx={idx}, embedding={embedding}")

代码运行结果例子。
<pad>
补齐,超出的进行截断。mindspore.dataset.text.Lookup(vocab, unknown_token=None, data_type=mstype.int32)
接口,将前文构造的词表加载,并指定 unknown_token
。dataset.transforms.PadEnd(pad_shape, pad_value=None)
接口,此接口定义最大长度和补齐值(pad_value
),这里取最大长度为500,填充值对应词表中 <pad>
的 index id。label
数据转为float32格式。最后,通过 batch(batch_size, drop_remainder=False, num_parallel_workers=None, **kwargs)
接口指定数据集的 batch 大小,,并设置是否丢弃无法被batch size整除的剩余数据。
代码例子
- import mindspore as ms
-
- # 根据词表,将分词标记(token)映射到其索引值(id)。
- lookup_op = ds.text.Lookup(
- vocab, # 词表对象,用于存储分词和索引的映射。
- unknown_token='<unk>' # 备用词汇,用于要查找的单词不在词汇表时进行替换。 如果单词不在词汇表中,则查找结果将替换为 unknown_token 的值。 如果单词不在词汇表中,且未指定 unknown_token ,将抛出运行时错误。默认值: None ,不指定该参数。
- )
-
- # 对输入Tensor进行填充,要求 pad_shape 与输入Tensor的维度保持一致。
- pad_op = ds.transforms.PadEnd(
- [500], ## 指定填充的shape。设置为较小的维数时该维度的元素将被截断。
- pad_value=vocab.tokens_to_ids('<pad>') ## 用于填充的值。默认 None ,表示不指定填充值。 当指定为默认值,输入Tensor为数值型时默认填充 0 ,输入Tensor为字符型时填充空字符串。
- )
-
- type_cast_op = ds.transforms.TypeCast(ms.float32)
-
-
- imdb_train = imdb_train.map(operations=[lookup_op, pad_op], input_columns=['text'])
- imdb_train = imdb_train.map(operations=[type_cast_op], input_columns=['label'])
-
- imdb_test = imdb_test.map(operations=[lookup_op, pad_op], input_columns=['text'])
- imdb_test = imdb_test.map(operations=[type_cast_op], input_columns=['label'])
-
-
- imdb_train, imdb_valid = imdb_train.split([0.7, 0.3])
- imdb_train = imdb_train.batch(64, drop_remainder=True)
- imdb_valid = imdb_valid.batch(64, drop_remainder=True)

nn.Embedding
层加载Glove词向量,RNN 层做特征提取,nn.Dense 层
将特征转化为与分类数量相同的size,用于后续进行模型优化训练。用于存储词向量并使用索引进行检索,根据输入Tensor中的id,从 embedding_table 中查询对应的 embedding 向量。当输入为id组成的序列时,输出为对应embedding向量构成的矩阵。当 use_one_hot 等于True时,x的类型必须是mindpore.int32。
vocab_size (int) - 词典的大小。如上文,对应的词表大小 400002 。
embedding_size (int) - 每个嵌入向量的大小。如上文,向量长度为100。
use_one_hot (bool) - 指定是否使用one-hot形式。默认值: False
。
embedding_table (Union[Tensor, str, Initializer, numbers.Number]) - embedding_table的初始化方法。当指定为字符串,字符串取值请参见类 mindspore.common.initializer 。默认值: "normal"
。
dtype (mindspore.dtype) - x的数据类型。默认值: mstype.float32
。
padding_idx (int, None) - 将 padding_idx 对应索引所输出的嵌入向量用零填充。默认值: None
。该功能已停用。
循环神经网络(Recurrent Neural Network, RNN)是一类以序列(sequence)数据为输入,在序列的演进方向进行递归(recursion)且所有节点(循环单元)按链式连接的神经网络。
RNN的结构拆解:
RNN单个Cell的结构简单,因此也造成了梯度消失(Gradient Vanishing)问题,具体表现为RNN网络在序列较长时,在序列尾部已经基本丢失了序列首部的信息。为了克服这一问题,LSTM(Long short-term memory)被提出,通过门控机制(Gating Mechanism)来控制信息流在每个循环步中的留存和丢弃。选择LSTM变种而不是经典的RNN做特征提取,来规避梯度消失问题,可以获得更好的模型效果。
mindspore.nn.LSTM(*args, **kwargs)
长短期记忆(LSTM)网络,根据输入序列和给定的初始状态计算输出序列和最终状态。在LSTM模型中,有两条管道连接两个连续的Cell,一条是Cell状态管道,另一条是隐藏状态管道。将两个连续的时间节点表示为 t−1 和 t。指定在 t 时刻输入 , t-1 时刻的隐藏状态
和Cell状态
。
t 时刻的Cell状态 和隐藏状态
使用门控机制计算得到。
输入门 计算出候选值。遗忘门
决定是否让
学到的信息通过或部分通过。
输出门 决定哪些信息输出。
候选Cell状态 是用当前输入计算的。
最后,使用遗忘门、输入门、输出门计算得到当前时刻的Cell状态 和隐藏状态
。
如下公式,
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。