【Deep Learning 7】RNN循环神经网络

本文涉及的产品
实时计算 Flink 版,5000CU*H 3个月
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
实时数仓Hologres,5000CU*H 100GB 3个月
简介: 🍊本文旨在以一种通俗易懂的方式来介绍RNN,本文从天气预报开始引入RNN,随后对RNN进行详细介绍,并对几种变体的LSTM、CRU、BiLSTM进行重点介绍。最后以5个实验进行实战训练🍊实验一:Pytorch+Bert+RNN实现文本分类预测模拟🍊实验二:Pytorch+Bert+RNN实现对IMDB影评数据集进行二分类情感分析🍊实验三:Pytorch+Bert+GRU实现对IMDB影评数据集进行二分类情感分析🍊实验四:Pytorch+Bert+LSTM实现对IMDB影评数据集进行二分

image.gif编辑

 

 

🍊本文旨在以一种通俗易懂的方式来介绍RNN,本文从天气预报开始引入RNN,随后对RNN进行详细介绍,并对几种变体的LSTM、GRU、BiLSTM进行重点介绍。最后以4个实验进行实战训练

🍊实验一:Pytorch+Bert+RNN实现文本分类预测模拟

🍊实验二:Pytorch+Bert+RNN实现对IMDB影评数据集进行二分类情感分析

🍊实验三:Pytorch+Bert+GRU实现对IMDB影评数据集进行二分类情感分析

🍊实验四:Pytorch+Bert+LSTM实现对IMDB影评数据集进行二分类情感分析

🍊实验四:Pytorch+Bert+BILSTM实现对IMDB影评数据集进行二分类情感分

一、Introduction

假如现在我们需要预测明天的天气,我们该怎么做呢?首先我们需要采集前几天的气温、降水、云量等情况,随后对这些数据进行处理。因为是分类预测问题,最简单的数据处理方式是将所有的数据放到一个一维的向量中并投入FNN中。听起来还不错,但是有一个问题是怎么多天的各种天气数据合起来参数太多了,俺们普通人的家伙压根儿跑不起来!

image.gif编辑

那么如何简化呢?再次审视该问题,明天的天气是基于前几天的天气情况的,也就是有时间序列的概念,那么如果有一个网络模型每次训练时可使用之前的训练的信息就好了。此外关于参数过多问题,我们在CNN中处理的策略是共享权重,所以这个网络模型如果还有共享权重的功能就更棒了。能够同时实现上述两种的功能的网络,就是RNN

RNN(Recurrent Neural Network),循环神经网络,它具有短期记忆功能,可以同时接受其他神经元和自身神经元的信息。通过时间反向传播算法进行参数学习。可扩展到兼容性更强的记忆网络模型(递归神经网络和图网络)

很多时候RNN也被翻译成递归神经网络,其实这样的叫法是不正确的,因为递归神经网络RecNN(Recursive Neural Network)是空间上的递归,而RNN是时间上的循环,二者是完全不同的两种神经网络模型

二、Principle

2.1 RNN network model

给定一个输入序列𝒙1∶𝑇 = (𝒙1 , 𝒙2 , ⋯ , 𝒙𝑡 , ⋯ , 𝒙𝑇),随后进入隐藏层获取延迟器(类似于记忆块,存储了最近几次隐藏层的活性值)中的信息对序列进行处理,最后输出,其参数更新公式如下

image.gif编辑

其模型图如下

image.gif编辑

FNN可以模拟任何的连续函数,而RNN强到可以模拟任何程序,因为它有动力系统(时间+函数)

具体的计算如下

image.gif编辑

观察该公式,数学功底好的小伙伴可能已经发现RNN的本质其实就是FNN线性层,输入输出维度分别为[input_sieze,hidden_sieze],上面的公式和标准的线性层还是有区别的,我们将其w和b进行变换如下图中所示,这样的效果更加直观

image.gif编辑

2.2 Activaiton function

仔细的小伙伴可以发现Hidden层的激活函数我们使用了Tanh函数(其图像如下),但是为什么不使用Sigmoid呢?这是因为Sigmoid的导数范围在[0,0.25]之内,而Tanh的导数范围在(0,1]。RNN需要不断的循环,导数值小的更容易导致梯度消失(详看2.7)

image.gif编辑

2.3 Example      

假如有以下的网络,网络权重参数w全部为1,权重b为0,无激活函数,当我们输入[1,1] [2,2] [1,1]的时候会输出什么呢?

第一个时间状态时。Memory块中并没有数据因此Hidden数据为1+1+0+0=2。并将Hidden的数据存储到Memory中

image.gif编辑

第二个时间状态时,Hidden数据为2+2+2+2=8

image.gif编辑

第三个时间状态时,Hidden数据为1+1+8+8=18

image.gif编辑

输入两次[1,1],但是输出不同,而且第二个[1,1]使用了第一个[1,1]中的信息,说明模型具有时序记忆功能

2.4 LSTM

长短期记忆神经网络Long Short-term Memory,注意 -- 符号位于short和term之间,所以你可以理解为较长的短期记忆神经网络

相比于RNN,其不同之处在于在网络传播的过程中,部分网络有概率传播截断了,有选择的加入新的信息、遗忘信息。我们将其称为门控机制。门控机制可改善RNN的长程依赖问题

LSTM主要有Output Gate、Input Gate和Memory Gate。所有门控函数其输出值只有0和1,因此激活函数使用的是Sigmoid,网络自行学习来判断门的开闭

image.gif编辑

假设我们在三个门分别输入z,zo和zi,让我们来看看门控机制是如何运行的吧

image.gif编辑

1 首先是f(zi),若其值为0,则f(zi)*g(z)为0,表示输入无效

2 其次是cf(zf),c为先前的记忆块,如果f(zf)为0,则记忆门生效,表示遗忘先前记忆

3 最后是f(zo),若其值为0,则h(c')*f(zo)为0,表示输出无效

2.5 GRU

GRU是LSTM的简化版,在数据集较少的时候,二者效果基本差不多,因此我们考虑硬件的算力时间成本时,偏向于GRU

GRU的核心思想为只关注记住了多少信息,遗忘了多少信息。因此GRU只有两个门:更新门(RNN中的输入门和记忆门)和重置门

image.gif编辑

计算过程解析

1 首先计算更新门和重置门的数值

2 上一层hidden与重置门相乘,决定遗忘了多少信息,再与当前的信息进行相加

3 (1-更新门)与hidden相乘,决定记住了多少信息,再与输出2乘更新门进行相乘,得到最终的hidden

2.6 BiLSTM

BiLSTM是LSTM的升级版,核心思想是训练的特征可以同时获取过去和将来的信息

其网络模型分为两个独立的LSTM(神经网络参数是独立的),将初始序列分别以正序和逆序输入到LSTM中,最后将两个输出的向量拼接在一起形成最终的词向量

目前论文中的神经网络往往会加一层BiLSTM来获取更加有效的特征表示

image.gif编辑

image.gif编辑

2.7 RNN long-range dependency issue

在Training RNN的时候,往往会发现损失值并非随着层数的增加而慢慢减少,而是在不断跳动      

image.gif编辑

主要原因是RNN有一个最大的问题--长程依赖。RNN会不断的进行迭代,假如有1.01或者0.99这个数字,当循环了1000次之后,1.01会变成2w,0.99接近于0。因此数值要么变得无限的大(梯度爆炸),要么变得无限小(梯度消失

image.gif编辑

我们将所有的Loss绘制出来可以发现,3D图陡峭和平坦位置两级分化,如下图中所示

image.gif编辑

对于梯度爆炸问题,可以设置一个梯度阈值进行限制

对于梯度消失问题,根本问题是连乘公式,因此可以将其改成带加法的连乘如残差网络和门控机制(因此在我们往往使用LSTM而不使用经典RNN)

三、Experiment

3.1 代码技巧

Pytorch提供了封装好的RNN、LSTM、GRU、BiLSTM模块

cell = torch.nn.RNNCell(input_size=input_size, hidden_size=hidden_size,num_layers=num_layers)

image.gif

输入参数

    • input_size:每个单词维度
    • hidden_size:隐含层的维度(不一定要等于句子长度)
    • num_layers:RNN层数,默认是1,单层LSTM
    • bias:是否使用bias
    • batch_first:默认为False,如果设置为True,则表示第一个维度表示的是batch_size
    • dropout:随机失活
    • bidirectional:是否使用BiLSTM

    输出参数

    output, (hn, cn) = lstm(inputs)

    output_last = output[:,-1,:]

      • output:每个时间步输出
      • output_last:最后一个时间步隐藏层神经元输出,一般是我们最终要获取的数据
      • hn:最后一个时间步隐藏层的状态
      • cn:最后一个时间步隐藏层的遗忘门值

      num_layers代表RNN的层数

      image.gif编辑

      image.gif编辑

      image.gif编辑

      3.2 实验一:文本分类预测模拟

      问题:设计一个RNN网络模型,实现输入的数据是happy,输出预测数据为phayp

      题目解析

      首先我们需要将每个母转化为词向量,最常见的词向量为One-Hot编码 。通过One-Hot后每个单词的维度为4

      image.gif编辑

      输入文本序列通过RNN之后要想得到paphy需要进行分类预测,因此需要加一层Softmax,最后与target计算交叉熵损失函数进行时间序列反向传播

      image.gif编辑

      Code

      import torch
      # Paramaters
      INPUT_SIZE = 4
      HIDDEN_SIZE = 4
      BATCH_SIZE = 1
      NUM_LAYERS = 1
      SEQ_LEN = 5
      # Prepare for the data
      words_bag = ['a', 'h', 'p', 'y']
      one_hot_bag = [[1, 0, 0, 0],
                     [0, 1, 0, 0],
                     [0, 0, 1, 0],
                     [0, 0, 0, 1]]
      input = [1, 0, 2, 2, 3]
      target = [2, 1, 0, 3, 2]
      input_one_hot = [one_hot_bag[x] for x in input]
      inputs = torch.Tensor(input_one_hot).view(SEQ_LEN, BATCH_SIZE, INPUT_SIZE)
      targets = torch.LongTensor(target)
      print('inputs.shape', inputs.shape, 'targets.shape', targets.shape)
      # Design model
      class Model(torch.nn.Module):
          def __init__(self, INPUT_SIZE, HIDDEN_SIZE, BATCH_SIZE, NUM_LAYERS):
              super(Model, self).__init__()
              self.input_size = INPUT_SIZE
              self.hidden_size = HIDDEN_SIZE
              self.batch_size = BATCH_SIZE
              self.num_layers = NUM_LAYERS
              self.rnn = torch.nn.RNN(input_size=self.input_size, hidden_size=self.hidden_size,
                                      num_layers=self.num_layers)
          def forward(self, input):
              # Every batch must have h0
              hidden = torch.zeros(self.num_layers,
                                   self.batch_size,
                                   self.hidden_size)
              out, _ = self.rnn(input, hidden)
              # Inorder to make Cross_Entropy with targets
              out = out.view(-1, self.hidden_size)
              return out
      rnn_model = Model(INPUT_SIZE, HIDDEN_SIZE, BATCH_SIZE, NUM_LAYERS)
      # Define the model and loss
      criterion = torch.nn.CrossEntropyLoss()
      optimizer = torch.optim.Adam(rnn_model.parameters(), lr=0.05)
      # Training
      for epoch in range(20):
          outputs = rnn_model(inputs)
          loss = criterion(outputs, targets)
          optimizer.zero_grad()
          loss.backward()
          optimizer.step()
          _, idx = outputs.max(dim=1)
          idx=idx.data.numpy()
          print('Predict:',''.join([words_bag[x] for x in idx]),end='')
          print(',Epoch [%d/20] loss=%.3f' % (epoch+1,loss.item()))

      image.gif

      Result

      image.gif编辑

      从结果可以看到损失值在不断的减少,从Epoch8开始预测值就已经成功是phayp了

      3.3 非模型代码

      由于本篇文章主要讲解关于RNN的内容。因此弱化了非网络模型部分代码,感兴趣的小伙伴可以看这篇完整项目的文章  IMDB文本分析实战

      该项目已在Github上开源,开箱即用,代码地址:sentiment_analysis_Imdb

      对于网络模型来说,只能接受数字数据类型,因此我们需要建立一个语言模型,目的是将每个单词变成一个向量,每个句子变成一个矩阵。关于语言模型,其已经发展历史非常悠久了(发展历史如下),我们可以直接使用这些模型

      image.gif编辑

      由于Bert模型比较主流(虽然它本身已经用了RNN的方法),但是它用起来也比较方便,效果也好,因此本篇文章采用的语言模型为Bert

      以下是配置文件config.py,看论文源代码的大牛们似乎都这么写,博主也就照葫芦画瓢

      import os
      import sys
      import time
      import torch
      import random
      import logging
      import argparse
      from datetime import datetime
      def get_config():
          parser = argparse.ArgumentParser()
          '''Base'''
          parser.add_argument('--num_classes', type=int, default=2)
          parser.add_argument('--model_name', type=str, default='bert',
                              choices=['bert', 'roberta', 'glove', 'fasttext', 'word2vce', 'elmo', 'gpt'])
          parser.add_argument('--method_name', type=str, default='gru',
                              choices=['gru', 'rnn', 'bilstm', 'textcnn', 'rnn', 'bert_transformer'])
          '''Optimization'''
          parser.add_argument('--train_batch_size', type=int, default=8)
          parser.add_argument('--test_batch_size', type=int, default=32)
          parser.add_argument('--num_epoch', type=int, default=50)
          parser.add_argument('--lr', type=float, default=1e-5)
          parser.add_argument('--weight_decay', type=float, default=0.01)
          '''Environment'''
          parser.add_argument('--device', type=str, default='cuda')
          parser.add_argument('--backend', default=False, action='store_true')
          parser.add_argument('--workers', type=int, default=0)
          parser.add_argument('--timestamp', type=int, default='{:.0f}{:03}'.format(time.time(), random.randint(0, 999)))
          args = parser.parse_args()
          args.device = torch.device(args.device)
          '''logger'''
          args.log_name = '{}_{}_{}.log'.format(args.model_name, args.method_name,
                                                datetime.now().strftime('%Y-%m-%d_%H-%M-%S')[2:])
          if not os.path.exists('logs'):
              os.mkdir('logs')
          logger = logging.getLogger()
          logger.setLevel(logging.INFO)
          logger.addHandler(logging.StreamHandler(sys.stdout))
          logger.addHandler(logging.FileHandler(os.path.join('logs', args.log_name)))
          return args, logger

      image.gif

      以下是数据集Data.py文件。主要功能是加载数据集,并制作对应的DataSet和DataLoader

      from functools import partial
      import pandas as pd
      import torch
      from sklearn.model_selection import train_test_split
      from torch.utils.data import Dataset, DataLoader
      # Make MyDataset
      class MyDataset(Dataset):
          def __init__(self, sentences, labels, method_name, model_name):
              self.sentences = sentences
              self.labels = labels
              self.method_name = method_name
              self.model_name = model_name
              dataset = list()
              index = 0
              for data in sentences:
                  tokens = data.split(' ')
                  labels_id = labels[index]
                  index += 1
                  dataset.append((tokens, labels_id))
              self._dataset = dataset
          def __getitem__(self, index):
              return self._dataset[index]
          def __len__(self):
              return len(self.sentences)
      # Make tokens for every batch
      def my_collate(batch, tokenizer):
          tokens, label_ids = map(list, zip(*batch))
          text_ids = tokenizer(tokens,
                               padding=True,
                               truncation=True,
                               max_length=320,
                               is_split_into_words=True,
                               add_special_tokens=True,
                               return_tensors='pt')
          return text_ids, torch.tensor(label_ids)
      # Load dataset
      def load_dataset(tokenizer, train_batch_size, test_batch_size, model_name, method_name, workers):
          data = pd.read_csv('datasets.csv', sep=None, header=0, encoding='utf-8', engine='python')
          len1 = int(len(list(data['labels'])) * 0.1)
          labels = list(data['labels'])[0:len1]
          sentences = list(data['sentences'])[0:len1]
          # split train_set and test_set
          tr_sen, te_sen, tr_lab, te_lab = train_test_split(sentences, labels, train_size=0.8)
          # Dataset
          train_set = MyDataset(tr_sen, tr_lab, method_name, model_name)
          test_set = MyDataset(te_sen, te_lab, method_name, model_name)
          # DataLoader
          collate_fn = partial(my_collate, tokenizer=tokenizer)
          train_loader = DataLoader(train_set, batch_size=train_batch_size, shuffle=True, num_workers=workers,
                                    collate_fn=collate_fn, pin_memory=True)
          test_loader = DataLoader(test_set, batch_size=test_batch_size, shuffle=True, num_workers=workers,
                                   collate_fn=collate_fn, pin_memory=True)
          return train_loader, test_loader

      image.gif

      以下是Main.py文件,主要功能是加载数据集,并使用run方法进行训练和测试

      import torch
      import torch.nn as nn
      from tqdm import tqdm
      from transformers import logging, AutoTokenizer, AutoModel
      from config import get_config
      from data import load_dataset
      from model import Transformer, Gru_Model, BiLstm_Model, Lstm_Model, Rnn_Model
      class Niubility:
          def __init__(self, args, logger):
              self.args = args
              self.logger = logger
              self.logger.info('> creating model {}'.format(args.model_name))
              # Operate the model
              if args.model_name == 'bert':
                  self.tokenizer = AutoTokenizer.from_pretrained('bert-base-uncased')
                  base_model = AutoModel.from_pretrained('bert-base-uncased')
              elif args.model_name == 'roberta':
                  self.tokenizer = AutoTokenizer.from_pretrained('roberta-base', add_prefix_space=True)
                  base_model = AutoModel.from_pretrained('roberta-base')
              else:
                  raise ValueError('unknown model')
              # Operate the method
              if args.method_name == 'bert_transformer':
                  self.Mymodel = Transformer(base_model, args.num_classes)
              elif args.method_name == 'gru':
                  self.Mymodel = Gru_Model(base_model, args.num_classes)
              elif args.method_name == 'lstm':
                  self.Mymodel = Lstm_Model(base_model, args.num_classes)
              elif args.method_name == 'bilstm':
                  self.Mymodel = BiLstm_Model(base_model, args.num_classes)
              else:
                  self.Mymodel = Rnn_Model(base_model, args.num_classes)
              self.Mymodel.to(args.device)
              if args.device.type == 'cuda':
                  self.logger.info('> cuda memory allocated: {}'.format(torch.cuda.memory_allocated(args.device.index)))
              self._print_args()
          def _print_args(self):
              self.logger.info('> training arguments:')
              for arg in vars(self.args):
                  self.logger.info(f">>> {arg}: {getattr(self.args, arg)}")
          def _train(self, dataloader, criterion, optimizer):
              train_loss, n_correct, n_train = 0, 0, 0
              # Turn on the train mode
              self.Mymodel.train()
              for inputs, targets in tqdm(dataloader, disable=self.args.backend, ascii='>='):
                  inputs = {k: v.to(self.args.device) for k, v in inputs.items()}
                  targets = targets.to(self.args.device)
                  predicts = self.Mymodel(inputs)
                  loss = criterion(predicts, targets)
                  optimizer.zero_grad()
                  loss.backward()
                  optimizer.step()
                  train_loss += loss.item() * targets.size(0)
                  n_correct += (torch.argmax(predicts, dim=1) == targets).sum().item()
                  n_train += targets.size(0)
              return train_loss / n_train, n_correct / n_train
          def _test(self, dataloader, criterion):
              test_loss, n_correct, n_test = 0, 0, 0
              # Turn on the eval mode
              self.Mymodel.eval()
              with torch.no_grad():
                  for inputs, targets in tqdm(dataloader, disable=self.args.backend, ascii=' >='):
                      inputs = {k: v.to(self.args.device) for k, v in inputs.items()}
                      targets = targets.to(self.args.device)
                      predicts = self.Mymodel(inputs)
                      loss = criterion(predicts, targets)
                      test_loss += loss.item() * targets.size(0)
                      n_correct += (torch.argmax(predicts, dim=1) == targets).sum().item()
                      n_test += targets.size(0)
              return test_loss / n_test, n_correct / n_test
          def run(self):
              train_dataloader, test_dataloader = load_dataset(tokenizer=self.tokenizer,
                                                               train_batch_size=self.args.train_batch_size,
                                                               test_batch_size=self.args.test_batch_size,
                                                               model_name=self.args.model_name,
                                                               method_name=self.args.method_name,
                                                               workers=self.args.workers)
              _params = filter(lambda x: x.requires_grad, self.Mymodel.parameters())
              criterion = nn.CrossEntropyLoss()
              optimizer = torch.optim.AdamW(_params, lr=self.args.lr, weight_decay=self.args.weight_decay)
              # Get the best_loss and the best_acc
              best_loss, best_acc = 0, 0
              for epoch in range(self.args.num_epoch):
                  train_loss, train_acc = self._train(train_dataloader, criterion, optimizer)
                  test_loss, test_acc = self._test(test_dataloader, criterion)
                  if test_acc > best_acc or (test_acc == best_acc and test_loss < best_loss):
                      best_acc, best_loss = test_acc, test_loss
                  self.logger.info(
                      '{}/{} - {:.2f}%'.format(epoch + 1, self.args.num_epoch, 100 * (epoch + 1) / self.args.num_epoch))
                  self.logger.info('[train] loss: {:.4f}, acc: {:.2f}'.format(train_loss, train_acc * 100))
                  self.logger.info('[test] loss: {:.4f}, acc: {:.2f}'.format(test_loss, test_acc * 100))
              self.logger.info('best loss: {:.4f}, best acc: {:.2f}'.format(best_loss, best_acc * 100))
              self.logger.info('log saved: {}'.format(self.args.log_name))
      if __name__ == '__main__':
          logging.set_verbosity_error()
          args, logger = get_config()
          nb = Niubility(args, logger)
          nb.run()

      image.gif

      3.4 实验二:Pytorch+RNN 二分类情感分析

      问题:搭建RNN模型实现对IMDB数据集进行分类

      RNN网络模型代码如下

      Init:

      self.base_model:使用语言模型

      self.num_classes:预测类的数量

      self.Rnn:Rnn模型,input_size为bert默认的单词维度,hidden_size为句子长度,当然hidden_size不一定要和句子长度一样,num_layers使用一层Rnn就行了

      self.fc:使用常规FNN+Softmax即可

      forward:

      前三行代码:获取bert语言模型每个单词的token值。因为本篇文章主要讲RNN,因此大家如果不知道Bert就不必深究了

      x, _ = self.Gru(tokens):x获取的是最终隐藏层的表示,_表示该位置的参数用不到

      x = self.fc(x):进行全连接分类

      class Rnn_Model(nn.Module):
          def __init__(self, base_model, num_classes):
              super().__init__()
              self.base_model = base_model
              self.num_classes = num_classes
              self.Rnn = nn.RNN(input_size=768,
                                hidden_size=320,
                                num_layers=1,
                                batch_first=True)
              self.fc = nn.Sequential(nn.Dropout(0.5),
                                      nn.Linear(320, 80),
                                      nn.Linear(80, 20),
                                      nn.Linear(20, self.num_classes),
                                      nn.Softmax(dim=1))
              for param in base_model.parameters():
                  param.requires_grad = (True)
          def forward(self, inputs):
              raw_outputs = self.base_model(**inputs)
              cls_feats = raw_outputs.last_hidden_state
              outputs, _ = self.Rnn(cls_feats)
              outputs = outputs[:, -1, :]
              outputs = self.fc(outputs)
              return outputs

      image.gif

      3.5 实验三:Pytorch+GRU 二分类情感分析

      问题:搭建GRU模型实现对IMDB数据集进行分类

      GRU模块基本上与RNN模块一致,需要修改的地方在于nn.RNN换成nn.GRU

      class Gru_Model(nn.Module):
          def __init__(self, base_model, num_classes):
              super().__init__()
              self.base_model = base_model
              self.num_classes = num_classes
              self.Gru = nn.GRU(input_size=768,
                                hidden_size=320,
                                num_layers=1,
                                batch_first=True)
              self.fc = nn.Sequential(nn.Dropout(0.5),
                                      nn.Linear(320, 80),
                                      nn.Linear(80, 20),
                                      nn.Linear(20, self.num_classes),
                                      nn.Softmax(dim=1))
              for param in base_model.parameters():
                  param.requires_grad = (True)
          def forward(self, inputs):
              raw_outputs = self.base_model(**inputs)
              tokens = raw_outputs.last_hidden_state
              gru_output, _ = self.Gru(tokens)
              outputs = gru_output[:, -1, :]
              outputs = self.fc(outputs)
              return outputs

      image.gif

      3.6 实验四:Pytorch+LSTM 二分类情感分析

      问题:搭建LSTM模型实现对IMDB数据集进行分类

      LSTM模块基本上与RNN模块一致,需要修改的地方在于nn.RNN换成nn.LSTM

      class Lstm_Model(nn.Module):
          def __init__(self, base_model, num_classes):
              super().__init__()
              self.base_model = base_model
              self.num_classes = num_classes
              self.Lstm = nn.LSTM(input_size=768,
                                  hidden_size=320,
                                  num_layers=1,
                                  batch_first=True)
              self.fc = nn.Sequential(nn.Dropout(0.5),
                                      nn.Linear(320, 80),
                                      nn.Linear(80, 20),
                                      nn.Linear(20, self.num_classes),
                                      nn.Softmax(dim=1))
              for param in base_model.parameters():
                  param.requires_grad = (True)
          def forward(self, inputs):
              raw_outputs = self.base_model(**inputs)
              tokens = raw_outputs.last_hidden_state
              lstm_output, _ = self.Lstm(tokens)
              outputs = lstm_output[:, -1, :]
              outputs = self.fc(outputs)
              return outputs

      image.gif

      3.7 实验五:Pytorch+BILSTM 二分类情感分析

      问题:搭建BILSTM模型实现对IMDB数据集进行分类

      BiLstm为双向lstm,在lstm的基础上修改两处地方

      第一处:在nn.LSTM中添加bidirectional=True

      第二处:在nn.fc的输入维度需要*2

      class BiLstm_Model(nn.Module):
          def __init__(self, base_model, num_classes):
              super().__init__()
              self.base_model = base_model
              self.num_classes = num_classes
              # Open the bidirectional
              self.BiLstm = nn.LSTM(input_size=768,
                                    hidden_size=320,
                                    num_layers=1,
                                    batch_first=True,
                                    bidirectional=True)
              self.fc = nn.Sequential(nn.Dropout(0.5),
                                      nn.Linear(320 * 2, 80),
                                      nn.Linear(80, 20),
                                      nn.Linear(20, self.num_classes),
                                      nn.Softmax(dim=1))
              for param in base_model.parameters():
                  param.requires_grad = (True)
          def forward(self, inputs):
              raw_outputs = self.base_model(**inputs)
              cls_feats = raw_outputs.last_hidden_state
              outputs, _ = self.BiLstm(cls_feats)
              outputs = outputs[:, -1, :]
              outputs = self.fc(outputs)
              return outputs

      image.gif

      3.8 Result

      到了最快乐的炼丹时间,看看最终的效果怎么样

      image.gif编辑

      分析

        • LSTM与BiLSTM的效果总体上要优于其他模型
        • Roberta比Bert的效果好,Roberta不愧是升级版Bert
        • 使用FNN的本身的效果就比较好是因为Bert本身带有LSTM的网络层
        • Roberta+LSTM/BiLSTM的组合效果是最优的

        参考资料

        《机器学习》周志华

        《深度学习与机器学习》吴恩达

        《神经网络与与深度学习》邱锡鹏

        《Pytorch深度学习实战》刘二大人

        相关实践学习
        【文生图】一键部署Stable Diffusion基于函数计算
        本实验教你如何在函数计算FC上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。函数计算提供一定的免费额度供用户使用。本实验答疑钉钉群:29290019867
        建立 Serverless 思维
        本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
        目录
        相关文章
        |
        1月前
        |
        机器学习/深度学习 数据采集 存储
        时间序列预测新突破:深入解析循环神经网络(RNN)在金融数据分析中的应用
        【10月更文挑战第7天】时间序列预测是数据科学领域的一个重要课题,特别是在金融行业中。准确的时间序列预测能够帮助投资者做出更明智的决策,比如股票价格预测、汇率变动预测等。近年来,随着深度学习技术的发展,尤其是循环神经网络(Recurrent Neural Networks, RNNs)及其变体如长短期记忆网络(LSTM)和门控循环单元(GRU),在处理时间序列数据方面展现出了巨大的潜力。本文将探讨RNN的基本概念,并通过具体的代码示例展示如何使用这些模型来进行金融数据分析。
        218 2
        |
        4月前
        |
        机器学习/深度学习 数据采集 人工智能
        Python实现深度神经网络RNN-LSTM分类模型(医学疾病诊断)
        Python实现深度神经网络RNN-LSTM分类模型(医学疾病诊断)
        142 0
        Python实现深度神经网络RNN-LSTM分类模型(医学疾病诊断)
        |
        11天前
        |
        机器学习/深度学习 自然语言处理 前端开发
        前端神经网络入门:Brain.js - 详细介绍和对比不同的实现 - CNN、RNN、DNN、FFNN -无需准备环境打开浏览器即可测试运行-支持WebGPU加速
        本文介绍了如何使用 JavaScript 神经网络库 **Brain.js** 实现不同类型的神经网络,包括前馈神经网络(FFNN)、深度神经网络(DNN)和循环神经网络(RNN)。通过简单的示例和代码,帮助前端开发者快速入门并理解神经网络的基本概念。文章还对比了各类神经网络的特点和适用场景,并简要介绍了卷积神经网络(CNN)的替代方案。
        |
        1月前
        |
        机器学习/深度学习 存储 自然语言处理
        深度学习入门:循环神经网络------RNN概述,词嵌入层,循环网络层及案例实践!(万字详解!)
        深度学习入门:循环神经网络------RNN概述,词嵌入层,循环网络层及案例实践!(万字详解!)
        |
        3月前
        |
        自然语言处理 C# 开发者
        Uno Platform多语言开发秘籍大公开:轻松驾驭全球用户,一键切换语言,让你的应用成为跨文化交流的桥梁!
        【8月更文挑战第31天】Uno Platform 是一个强大的开源框架,允许使用 C# 和 XAML 构建跨平台的原生移动、Web 和桌面应用程序。本文详细介绍如何通过 Uno Platform 创建多语言应用,包括准备工作、设置多语言资源、XAML 中引用资源、C# 中加载资源以及处理语言更改。通过简单的步骤和示例代码,帮助开发者轻松实现应用的国际化。
        41 1
        |
        3月前
        |
        机器学习/深度学习 人工智能 自然语言处理
        TensorFlow 中的循环神经网络超厉害!从理论到实践详解,带你领略 RNN 的强大魅力!
        【8月更文挑战第31天】循环神经网络(RNN)在人工智能领域扮演着重要角色,尤其在TensorFlow框架下处理序列数据时展现出强大功能。RNN具有记忆能力,能捕捉序列中的长期依赖关系,适用于自然语言处理、机器翻译和语音识别等多个领域。尽管存在长期依赖和梯度消失等问题,但通过LSTM和GRU等改进结构可以有效解决。在TensorFlow中实现RNN十分简便,为处理复杂序列数据提供了有力支持。
        35 0
        |
        3月前
        |
        机器学习/深度学习 人工智能 自然语言处理
        7.1 NLP经典神经网络 RNN LSTM
        该文章介绍了自然语言处理中的情感分析任务,探讨了如何使用深度神经网络,特别是循环神经网络(RNN)和长短时记忆网络(LSTM),来处理和分析文本数据中的复杂情感倾向。
        |
        4月前
        |
        机器学习/深度学习 数据采集 人工智能
        循环神经网络RNN
        7月更文挑战第2天
        91 11
        |
        4月前
        |
        机器学习/深度学习 PyTorch 算法框架/工具
        图神经网络是一类用于处理图结构数据的神经网络。与传统的深度学习模型(如卷积神经网络CNN和循环神经网络RNN)不同,
        图神经网络是一类用于处理图结构数据的神经网络。与传统的深度学习模型(如卷积神经网络CNN和循环神经网络RNN)不同,
        |
        4月前
        |
        机器学习/深度学习 数据采集 数据挖掘
        Python实现循环神经网络RNN-LSTM回归模型项目实战(股票价格预测)
        Python实现循环神经网络RNN-LSTM回归模型项目实战(股票价格预测)
        192 0