forked from songyouwei/ABSA-PyTorch
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdynamic_rnn.py
91 lines (80 loc) · 3.84 KB
/
dynamic_rnn.py
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# -*- coding: utf-8 -*-
# file: dynamic_rnn.py
# author: songyouwei <[email protected]>
# Copyright (C) 2018. All Rights Reserved.
import torch
import torch.nn as nn
import numpy as np
class DynamicLSTM(nn.Module):
def __init__(self, input_size, hidden_size, num_layers=1, bias=True, batch_first=True, dropout=0,
bidirectional=False, only_use_last_hidden_state=False, rnn_type = 'LSTM'):
"""
LSTM which can hold variable length sequence, use like TensorFlow's RNN(input, length...).
:param input_size:The number of expected features in the input x
:param hidden_size:The number of features in the hidden state h
:param num_layers:Number of recurrent layers.
:param bias:If False, then the layer does not use bias weights b_ih and b_hh. Default: True
:param batch_first:If True, then the input and output tensors are provided as (batch, seq, feature)
:param dropout:If non-zero, introduces a dropout layer on the outputs of each RNN layer except the last layer
:param bidirectional:If True, becomes a bidirectional RNN. Default: False
:param rnn_type: {LSTM, GRU, RNN}
"""
super(DynamicLSTM, self).__init__()
self.input_size = input_size
self.hidden_size = hidden_size
self.num_layers = num_layers
self.bias = bias
self.batch_first = batch_first
self.dropout = dropout
self.bidirectional = bidirectional
self.only_use_last_hidden_state = only_use_last_hidden_state
self.rnn_type = rnn_type
if self.rnn_type == 'LSTM':
self.RNN = nn.LSTM(
input_size=input_size, hidden_size=hidden_size, num_layers=num_layers,
bias=bias, batch_first=batch_first, dropout=dropout, bidirectional=bidirectional)
elif self.rnn_type == 'GRU':
self.RNN = nn.GRU(
input_size=input_size, hidden_size=hidden_size, num_layers=num_layers,
bias=bias, batch_first=batch_first, dropout=dropout, bidirectional=bidirectional)
elif self.rnn_type == 'RNN':
self.RNN = nn.RNN(
input_size=input_size, hidden_size=hidden_size, num_layers=num_layers,
bias=bias, batch_first=batch_first, dropout=dropout, bidirectional=bidirectional)
def forward(self, x, x_len):
"""
sequence -> sort -> pad and pack ->process using RNN -> unpack ->unsort
:param x: sequence embedding vectors
:param x_len: numpy/tensor list
:return:
"""
"""sort"""
x_sort_idx = torch.sort(-x_len)[1].long()
x_unsort_idx = torch.sort(x_sort_idx)[1].long()
x_len = x_len[x_sort_idx]
x = x[x_sort_idx]
"""pack"""
x_emb_p = torch.nn.utils.rnn.pack_padded_sequence(x, x_len, batch_first=self.batch_first)
# process using the selected RNN
if self.rnn_type == 'LSTM':
out_pack, (ht, ct) = self.RNN(x_emb_p, None)
else:
out_pack, ht = self.RNN(x_emb_p, None)
ct = None
"""unsort: h"""
ht = torch.transpose(ht, 0, 1)[
x_unsort_idx] # (num_layers * num_directions, batch, hidden_size) -> (batch, ...)
ht = torch.transpose(ht, 0, 1)
if self.only_use_last_hidden_state:
return ht
else:
"""unpack: out"""
out = torch.nn.utils.rnn.pad_packed_sequence(out_pack, batch_first=self.batch_first) # (sequence, lengths)
out = out[0] #
out = out[x_unsort_idx]
"""unsort: out c"""
if self.rnn_type =='LSTM':
ct = torch.transpose(ct, 0, 1)[
x_unsort_idx] # (num_layers * num_directions, batch, hidden_size) -> (batch, ...)
ct = torch.transpose(ct, 0, 1)
return out, (ht, ct)