forked from SciSharp/TensorFlow.NET
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLSTM.cs
More file actions
126 lines (113 loc) · 4.45 KB
/
LSTM.cs
File metadata and controls
126 lines (113 loc) · 4.45 KB
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
using System.Linq;
using Tensorflow.Keras.ArgsDefinition;
using Tensorflow.Keras.Engine;
using Tensorflow.Common.Types;
using Tensorflow.Common.Extensions;
using Tensorflow.Keras.Saving;
namespace Tensorflow.Keras.Layers
{
/// <summary>
/// Long Short-Term Memory layer - Hochreiter 1997.
///
/// See [the Keras RNN API guide](https://www.tensorflow.org/guide/keras/rnn)
/// for details about the usage of RNN API.
/// </summary>
public class LSTM : RNN
{
LSTMArgs _args;
InputSpec[] _state_spec;
InputSpec _input_spec;
bool _could_use_gpu_kernel;
public LSTMArgs Args { get => _args; }
public LSTM(LSTMArgs args) :
base(CreateCell(args), args)
{
_args = args;
_input_spec = new InputSpec(ndim: 3);
_state_spec = new[] { args.Units, args.Units }.Select(dim => new InputSpec(shape: (-1, dim))).ToArray();
_could_use_gpu_kernel = args.Activation == keras.activations.Tanh
&& args.RecurrentActivation == keras.activations.Sigmoid
&& args.RecurrentDropout == 0 && !args.Unroll && args.UseBias
&& ops.executing_eagerly_outside_functions();
}
private static IRnnCell CreateCell(LSTMArgs lstmArgs)
{
return new LSTMCell(new LSTMCellArgs()
{
Units = lstmArgs.Units,
Activation = lstmArgs.Activation,
RecurrentActivation = lstmArgs.RecurrentActivation,
UseBias = lstmArgs.UseBias,
KernelInitializer = lstmArgs.KernelInitializer,
RecurrentInitializer = lstmArgs.RecurrentInitializer,
UnitForgetBias = lstmArgs.UnitForgetBias,
BiasInitializer = lstmArgs.BiasInitializer,
// TODO(Rinne): kernel_regularizer
// TODO(Rinne): recurrent_regularizer
// TODO(Rinne): bias_regularizer
// TODO(Rinne): kernel_constriant
// TODO(Rinne): recurrent_constriant
// TODO(Rinne): bias_constriant
Dropout = lstmArgs.Dropout,
RecurrentDropout = lstmArgs.RecurrentDropout,
Implementation = lstmArgs.Implementation,
DType = lstmArgs.DType,
Trainable = lstmArgs.Trainable
});
}
protected override Tensors Call(Tensors inputs, Tensors initial_state = null, bool? training = null, IOptionalArgs? optional_args = null)
{
// skip the condition of ragged input
(inputs, initial_state, _) = _process_inputs(inputs, initial_state, null);
Tensor mask = null;
if(optional_args is RnnOptionalArgs rnnArgs)
{
mask = rnnArgs.Mask;
}
var single_input = inputs.Single;
var input_shape = single_input.shape;
var timesteps = _args.TimeMajor ? input_shape[0] : input_shape[1];
_maybe_reset_cell_dropout_mask(Cell);
Func<Tensors, Tensors, (Tensors, Tensors)> step = (inputs, states) =>
{
var res = Cell.Apply(inputs, states, training is null ? true : training.Value);
var (output, state) = res;
return (output, state);
};
var (last_output, outputs, states) = keras.backend.rnn(
step,
inputs,
initial_state,
constants: null,
go_backwards: _args.GoBackwards,
mask: mask,
unroll: _args.Unroll,
input_length: ops.convert_to_tensor(timesteps),
time_major: _args.TimeMajor,
zero_output_for_mask: _args.ZeroOutputForMask,
return_all_outputs: _args.ReturnSequences
);
Tensor output;
if (_args.ReturnSequences)
{
output = keras.backend.maybe_convert_to_ragged(false, outputs, (int)timesteps, _args.GoBackwards);
}
else
{
output = last_output;
}
if (_args.ReturnState)
{
return new Tensor[] { output }.Concat(states).ToArray().ToTensors();
}
else
{
return output;
}
}
public override IKerasConfig get_config()
{
return _args;
}
}
}