深度学习第12天_RNN实现文本情感分类

Pytorch中LSTM和GRU模块的使用

  1. LSTM介绍

    LSTM和GRU都是由torch.nn提供

    (1)LSTM的api

    torch.nn.LSTM(input_size, hidden_size, num_layers, batch_first, dropout, bidirectional)
    
    a. input_size:输入数据的形状,即embedding_dim
    b. hidden_size:隐藏层的神经元数量,即每一层有多少个LSTM单元
    c. num_layer:即RNN中的LSTM单元的层数
    d. batch_first:默认值为False,输入的数据需要[seq_len,batch,feature],如果为True,则为[batch,seq_len,feature]
    e. dropout:dropout的比例,默认值为0。dropout是一种训练过程中让部分参数随机失活的一种方式,能够提高训练速度,同时能够解决过拟合的问题。这里是在LSTM的最后一层,对每个输出进行dropout
    f. bidirectional:是否使用双向LSTM,默认是False
    
    实例化LSTM对象之后,不仅需要传入数据,还需要前一次的h_0(前一次的隐藏状态)和C_0(前一次的memory)
    即:lstm(input,(h_0,C_0))
    
    LSTM的默认输出为output,(h_n,C_n)
    
    a. output:(seq_len, batch, num_directions*hidden_size) 
    b. h_n:(num_layers*num_directions, batch, hidden_size)
    c. c_n:(num_layers*num_directions, batch, hidden_size)
    
    num_directions:如果只是单向,则为1;如果是双向,则为2
    

    深度学习第12天_RNN实现文本情感分类

    (2)LSTM使用示例

    a. output:把每个时间步上的结果在seq_len这一维度进行拼接
    b. h_n:把不同层的隐藏状态在第0个维度上进行了拼接
    c. 双向LSTM:

    i.   只需要把bidirectional = True
    ii.  output的拼接顺序:正向的第一个拼接反向的最后一个;在最后一个维度进行拼接
    iii. hidden_state:正向和反向各自的形状是[batch_size,hidden_size],双向时会在第0个维度拼接;[layers*num_direction,batch_size,hidden_size];
    	 #第一层的正向
    	 #第一层的反向
    	 #第二层的正向
    	 #第二层的反向
    	 #......(以此类推)
    

    代码如下:

    import torch.nn as nn
    import torch
    
    batch_size = 10
    seq_len = 20 #句子的长度
    vocab_size = 100 #字典的数量
    embedding_dim = 30 #用长度为30的向量表示一个词语
    
    hidden_size = 18
    num_layer = 2
    
    #构造一个batch的数据
    input = torch.randint(low=0,high=100,size=[batch_size,seq_len]) #[10,20]
    
    #数据经过embedding处理
    embedding = nn.Embedding(vocab_size,embedding_dim)
    input_embeded = embedding(input) #[10,20,30]
    
    #把embedding之后的数据传入LSTM
    lstm = nn.LSTM(input_size=embedding_dim,hidden_size=hidden_size,num_layers=num_layer,batch_first=True)
    output,(h_n,c_n) = lstm(input_embeded)
    
    print(output.size()) #[10,20,18]
    print("*"*100)
    print(h_n.size()) #[2*1,10,18]
    print("*"*100)
    print(c_n.size()) #[2*1,10,18]
    
    #获取最后一个时间步上的输出
    last_output = output[:,-1,:]
    #获取最后一次的hidden_state
    last_hidden_state = h_n[-1,:,:]
    print(last_output == last_hidden_state)
    

    (3)GRU的api

    a. 由torch.nn提供
    b. GRU(参数同LSTM)
    c. (output,h_n) = gru(input,h_0)
    d. 形状同LSTM
    
  2. LSTM和GRU的使用注意事项

    (1)在第一次调用之前,需要初始化隐藏状态,若不初始化,默认创建全为0的隐藏状态
    (2)往往会使用LSTM或者GRU的输出的最后一维的结果,来代表LSTM、GRU对文本处理的结果,其形状为[batch,num_directions*hidden_size]

    a. 并不是所有模型都会使用最后一维的结果
    b. 如果实例化LSTM的过程中,batch_first=False,则output[-1]或者output[-1,:,:]可以获取最后一维
    c. 如果实例化LSTM的过程中,batch_first=True,则output[:,-1,:]可以获取最后一维
    

    (3)如果结果是(seq_len,batch_size,num_directionshidden_size),想要把它转化为(batch_size,seq_len,num_directionshidden_size),不能够使用view等变形的方法,需要使用output.permute(1,0,2),即交换0和1轴
    (4)使用双向LSTM的时候,往往会分别使用每个方向的最后一次的output,作为当前数据经过双向LSTM的结果
    即:torch.cat([h_n[-2,:,:],h_n[-1,:,:]],dim=-1)
    最后的表示的size是 [batch_size,hidden_size*2]
    (5)上述内容在GRU中同理

  3. 使用LSTM完成文本情感分类

    为了达到更好的效果,对之前的模型做如下修改

    1.MAX_LEN=200
    2.构建dataset的过程,把数据转化为2分类的问题,pos为1,neg为0,否则25000个样本完成10个类别的划分数据量是不够的
    3.在实例化LSTM的时候,使用dropout=0.5,在model.eval()的过程中,dropout自动会为0
    

    修改模型:

    class MyModel(nn.Module):
    def __init__(self):
        super(MyModel,self).__init__()
        self.embedding = nn.Embedding(len(ws), 100)
        # 假如LSTM
        self.lstm = nn.LSTM(input_size=100,hidden_size=lib.hidden_size,num_layers=lib.num_layers,batch_first=True,bidirectional=lib.bidirectional,dropout=lib.dropout)
        self.fc = nn.Linear(lib.hidden_size*2,2)
    
    def forward(self,input):
        '''
        :param input: [batch_size,max_len]
        :return:
        '''
        x = self.embedding(input)#[batch_size,max_len,100]
        '''
        x:[batch_size,max_len,2*hidden_size]
        h_n:[num_layers*2,batch_size,hidden_size]
        '''
        x,(h_n,c_n) = self.lstm(x)
        #获取两个方向最后一次的output,进行concat操作
        output_fw = h_n[-2,:,:] #正向最后一次输出
        output_bw = h_n[-1,:,:] #反向最后一次输出
        output = torch.cat([output_fw,output_bw],dim=-1) #[batch_size,hidden_size*2]
    
        out = self.fc(output)
        return F.log_softmax(out,dim=-1)
    

    测试模型:

    def eval():
        loss_list = []
        acc_list = []
        data_loader = get_dataloader(train=False,batch_size=lib.test_batch_size)
        for idx,(input,target) in tqdm(enumerate(data_loader),total=len(data_loader),ascii=True,desc="测试:"):
            input = input.to(lib.device)
            target = target.to(lib.device)
            with torch.no_grad():
                output = model(input)
                cur_loss = F.nll_loss(output,target)
                loss_list.append(cur_loss.cpu().item())
                #计算准确率
                pred = output.max(dim=-1)[-1]
                cur_acc = pred.eq(target).float().mean()
                acc_list.append(cur_acc.cpu().item())
        print("total loss,acc",np.mean(loss_list),np.mean(acc_list))
    
上一篇:【预测模型】基于贝叶斯优化的LSTM模型实现数据预测matlab源码


下一篇:【预测模型】基于贝叶斯优化的LSTM模型实现数据预测matlab源码