深度学习---从入门到放弃(九)RNN入门

深度学习—从入门到放弃(九)RNN入门

1.RNN简介

RNN(Recurrent Neural Network)是一类用于处理序列数据的神经网络。回想一下我们之前说到过的CNN,它可以通过在空间上共享参数的形式减小计算资源;RNN也是如此,不同于CNN基于空间的权值共享,RNN是基于时间来进行这个过程的。

  • RNN 是在时间序列上运行的模型,并且能够记住过去的输入。他们还通过在每个时间步长上使用相同的权重来保存参数。

在这里插入图片描述
上图显示了RNN可以通过“上下文”来进行缺失词的补全,且其具有权值共享的特点(U、V在每一个时间步长上都是相同的)。

2.马尔可夫链和 HMM

2.1序列

时间序列数据是指在不同时间点上收集到的数据,这类数据反映了某一事物、现象等随时间的变化状态或程度。这是时间序列数据的定义,当然这里也可以不是时间,比如文字序列,但总归序列数据有一个特点——后面的数据跟前面的数据有关系。

在这里我们选择ntlk语料库里的数据集进行演示。

import warnings
warnings.simplefilter("ignore")
nltk.download('punkt')
nltk.download('averaged_perceptron_tagger')
nltk.download('brown')
nltk.download('webtext')
category = ['editorial', 'fiction', 'government', 'news', 'religion']
sentences = brown.sents(categories=category)

在建模之前,我们先进行一些探索性数据分析以更好的了解数据结构

lengths = [len(sentence) for sentence in sentences]
lengths = pd.Series(lengths)#输出语料库里每一段句子的长度
lengths.describe()#了解语料库句子长度的描述性统计分析

由于我们将单词建模为句子中的序列,因此我们需要收集语料库中的所有单词

corpus_words = []
for sentence in sentences:
  for word in sentence:
    if "''" not in word and "``" not in word:#去除标点符号
      corpus_words.append(word)

创建词的矩阵

distinct_words = list(set(corpus_words))#将单词中的字母提出来
word_idx_dict = {word: i for i, word in enumerate(distinct_words)}
distinct_words_count = len(list(set(corpus_words)))
next_word_matrix = np.zeros([distinct_words_count, distinct_words_count])

填充跟踪下一个单词的矩阵

for i, word in enumerate(corpus_words[:-1]):
  first_word_idx = word_idx_dict[word]
  next_word_idx = word_idx_dict[corpus_words[i+1]]
  next_word_matrix[first_word_idx][next_word_idx] +=1

2.2马尔可夫链

  • 描述一系列可能事件的随机模型
  • 每个事件的概率仅取决于前一个事件中达到的状态。

最简单的马尔可夫模型假设我们有一个系统,它包含一组有限的状态,并且该系统具有一定的概率在每个时间步长t进行状态转换,从而随着时间生成一系列新状态。让我们称这些初始状态为S
在这里插入图片描述
马尔可夫模型生成一系列状态,其中一种可能的实现是:
在这里插入图片描述
要了解系统如何在状态之间转换,我们现在需要一个转换矩阵。

转换矩阵描述了从一种状态转移到另一种状态的概率(保持在同一状态的概率在语义上等同于转移到同一状态)。

按照惯例,转移矩阵的行对应于当时的状态 t,而列对应于当时的状态 t+1. 因此,行概率总和为 1,因为转换到下一个状态的概率仅取决于当前状态,并且所有可能的状态都是已知和枚举的。
在这里插入图片描述
使用转移矩阵,我们可以表达系统的不同行为。例如:

  • 通过为对角线分配更大的概率质量,我们可以表示系统喜欢停留在当前状态

  • 通过为非对角线分配更大的概率质量,我们可以表示系统喜欢从当前状态转换出来。

使用最有可能的词函数,我们可以开始创建词链并创建序列。在下面的代码中,我们创建了一个简单的链,它可以输出最可能的单词。

def most_likely_word_after(word):
  #我们使用之前建立的追踪矩阵找出最可能出现的词
  most_likely = next_word_matrix[word_idx_dict[word]].argmax()
  return distinct_words[most_likely]
def naive_chain(word, length=15):
  current_word = word
  sentence = word
  # 建立简单马尔科夫链
  for _ in range(length):
    sentence += ' '
    next_word = most_likely_word_after(current_word)
    sentence += next_word
    current_word = next_word
  return sentence

从以上我们可以为单个单词创建随机链。但是对于更有效的语言模型,我们希望对单词集进行建模,并希望运用加权选择的随机链,增强模型的效果。

2.2HMM

有关于HMM,在之前的博文中有所提及,在这里就不再赘述。
AR-HMM模型 自回归隐马尔可夫模型

3.词嵌入

3.1 Word2Vec

词或是我们用来表达语言意义的基本单位。将词映射到实数向量的技术称为词嵌入。

Word2vec 基于分布语义理论 - 出现在彼此周围的词比不出现在彼此周围的词更有可能意味着相似的事物。牢记这一点,我们的工作是创建一个高维空间,在其中保留这些语义关系。

word2vec模式下的两个模型:CBOW和SkipGram

  • CBOW(Continuous Bag-of-Word):以上下文词汇预测当前词
  • SkipGram:以当前词预测其上下文词汇

Word2Vec(sentences, vector_size=size, sg=sg, min_count=min_count)
vector_size:词嵌入向量的大小
sg:即我们的word2vec两个模型的选择了。如果是0, 则是CBOW模型,是1则是Skip-Gram模型,默认是0即CBOW模型。
min_count:可以对字典做截断. 词频少于min_count次数的单词会被丢弃掉, 默认值为5。

def create_word2vec_model(category='news', size=50, sg=1, min_count=5):
  try:
    sentences = brown.sents(categories=category)
    model = Word2Vec(sentences, vector_size=size, sg=sg, min_count=min_count)

  except (AttributeError, TypeError):
      raise AssertionError('Input variable "category" should be a string or list,'
      '"size", "sg", "min_count" should be integers')

  return model
#####################
def model_dictionary(model):
  words = list(model.wv.key_to_index)
  return words

def get_embedding(word, model):
  if word in model.wv.key_to_index:
    return model.wv[word]
  else:
    return None

以上为使用gensim库构建的word2vec模型。有关模型参数可以点击下方链接
word2vec的应用----使用gensim来训练模型
在这里插入图片描述
上图为weather这一词构建的嵌入向量。

word2vec 模型得到的词嵌入在高维空间中。我们将使用tSNE(t 分布随机邻居嵌入),这是一种用于维数推导的统计方法,使我们能够在 2D 或 3D 空间中可视化高维数据。
在这里插入图片描述
我们可以从图中得知,它们能够根据不同的中心词成簇排列,因此可以说词语之间的语义关系被很好的保留了下来。

3.2 词相似度

多义词

在这里插入图片描述
可以发现cricket作为“蟋蟀”或者“板球”是均与中心词“昆虫”或“运动”产生了一定的相似度,表明词嵌入可以很好的表示多义词。

词类比

在这里插入图片描述
可以发现词嵌入可以将单词与单词之间的语义关系阐释出来。

4.具有词嵌入的神经网络

我们使用预训练的 FastText 嵌入在 IMDB 数据集上训练神经网络。然后平均词嵌入以获得整个句子或者段落的嵌入。神经网络将有一个大小为 128 的隐藏层。

建立网络

class NeuralNet(nn.Module):
  def __init__(self, output_size, hidden_size, vocab_size, embedding_length,
               word_embeddings):
    super(NeuralNet, self).__init__()
    #将预训练的嵌入添加到模型之中
    self.word_embeddings = nn.Embedding(vocab_size, embedding_length)#vocab_size—>embedding_length将单词映射到高维空间的实数向量
    self.word_embeddings.weight = nn.Parameter(word_embeddings,
                                               requires_grad=False)
    self.fc1 = nn.Linear(embedding_length, hidden_size)
    self.fc2 = nn.Linear(hidden_size, output_size)


  def forward(self, inputs):

    input = self.word_embeddings(inputs)  # 将单词映射到高维空间的实数向量
    # 将一句话里每个单词的嵌入向量进行平均以代表整句话的嵌入向量
    # torch.nn.functional.avg_pool2d可以用来实现该功能
    pooled = F.avg_pool2d(input, (input.shape[1], 1)).squeeze(1)

    # 让词嵌入的权值在网络中不断传递
    # 全连接层
    x = self.fc1(pooled)

    # ReLU 激活
    x = F.relu(x)
    # 全连接层
    x = self.fc2(x)
    output = F.log_softmax(x, dim=1)#softmax目标函数 输出概率

    return output

NeuralNet(
(word_embeddings): Embedding(100, 300)
(fc1): Linear(in_features=300, out_features=128, bias=True)
(fc2): Linear(in_features=128, out_features=2, bias=True)
)

训练网络
# 模型超参数
learning_rate = 0.0003
output_size = 2
hidden_size = 128#隐藏层数
embedding_length = 300#词嵌入向量大小
epochs = 15#训练事件的个数
word_embeddings = TEXT.vocab.vectors
vocab_size = len(TEXT.vocab)

# Model set-up
nn_model = NeuralNet(output_size,
                     hidden_size,
                     vocab_size,
                     embedding_length,
                     word_embeddings)
nn_model.to(DEVICE)
nn_start_time = time.time()
set_seed(522)
nn_train_loss, nn_train_acc, nn_validation_loss, nn_validation_acc = train(nn_model,
                                                                           DEVICE,
                                                                           train_iter,
                                                                           valid_iter,
                                                                           epochs,
                                                                           learning_rate)
print(f"--- Time taken to train = {(time.time() - nn_start_time)} seconds ---")
test_accuracy = test(nn_model, DEVICE, test_iter)
print(f'\n\nTest Accuracy: {test_accuracy}%')
模型评估
# 可视化从而进行模型评估
plt.figure()
plt.subplot(211)
plot_train_val(np.arange(0, epochs), nn_train_acc, nn_validation_acc,
               'train accuracy', 'val accuracy',
               'Neural Net on IMDB text classification', 'accuracy',
               color='C0')
plt.legend(loc='upper left')
plt.subplot(212)
plot_train_val(np.arange(0, epochs), nn_train_loss,
               nn_validation_loss,
               'train loss', 'val loss',
               '',
               'loss [a.u.]',
               color='C0')
plt.legend(loc='upper left')
plt.show()

在这里插入图片描述
欢迎大家关注公众号奇趣多多一起交流!
在这里插入图片描述
深度学习—从入门到放弃(一)pytorch基础
深度学习—从入门到放弃(二)简单线性神经网络
深度学习—从入门到放弃(三)多层感知器MLP
深度学习—从入门到放弃(四)优化器
深度学习—从入门到放弃(五)正则化
深度学习—从入门到放弃(六)CNN入门
深度学习—从入门到放弃(七)CNN进阶,迁移学习
深度学习—从入门到放弃(八)使用CNN进行人脸识别

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

佩瑞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值