use burn::module::Module;
use burn::nn::{Linear, LinearConfig};
use burn::tensor::{activation, backend::Backend, Tensor};
#[derive(Module, Debug)]
pub struct DailyLSTM<B: Backend> {
input_size: usize,
hidden_size: usize,
dropout_rate: f64,
input_gate: Linear<B>,
forget_gate: Linear<B>,
cell_gate: Linear<B>,
output_gate: Linear<B>,
input_recurrent: Linear<B>,
forget_recurrent: Linear<B>,
cell_recurrent: Linear<B>,
output_recurrent: Linear<B>,
}
impl<B: Backend> DailyLSTM<B> {
pub fn new(
input_size: usize,
hidden_size: usize,
dropout_rate: f64,
device: &B::Device,
) -> Self {
let input_gate_config = LinearConfig::new(input_size, hidden_size);
let forget_gate_config = LinearConfig::new(input_size, hidden_size);
let cell_gate_config = LinearConfig::new(input_size, hidden_size);
let output_gate_config = LinearConfig::new(input_size, hidden_size);
let input_recurrent_config = LinearConfig::new(hidden_size, hidden_size);
let forget_recurrent_config = LinearConfig::new(hidden_size, hidden_size);
let cell_recurrent_config = LinearConfig::new(hidden_size, hidden_size);
let output_recurrent_config = LinearConfig::new(hidden_size, hidden_size);
let input_gate = input_gate_config.init(device);
let forget_gate = forget_gate_config.init(device);
let cell_gate = cell_gate_config.init(device);
let output_gate = output_gate_config.init(device);
let input_recurrent = input_recurrent_config.init(device);
let forget_recurrent = forget_recurrent_config.init(device);
let cell_recurrent = cell_recurrent_config.init(device);
let output_recurrent = output_recurrent_config.init(device);
Self {
input_size,
hidden_size,
dropout_rate,
input_gate,
forget_gate,
cell_gate,
output_gate,
input_recurrent,
forget_recurrent,
cell_recurrent,
output_recurrent,
}
}
pub fn forward(&self, x: Tensor<B, 3>) -> Tensor<B, 3> {
let device = x.device();
let batch_size = x.dims()[0];
let sequence_length = x.dims()[1];
let mut h = Tensor::zeros([batch_size, self.hidden_size], &device);
let mut c = Tensor::zeros([batch_size, self.hidden_size], &device);
let mut outputs = Tensor::zeros([batch_size, sequence_length, self.hidden_size], &device);
for t in 0..sequence_length {
let x_t = x
.clone()
.narrow(1, t, 1)
.reshape([batch_size, self.input_size]);
let i_t = activation::sigmoid(
self.input_gate.forward(x_t.clone()) + self.input_recurrent.forward(h.clone()),
);
let f_t = activation::sigmoid(
self.forget_gate.forward(x_t.clone()) + self.forget_recurrent.forward(h.clone()),
);
let g_t = activation::tanh(
self.cell_gate.forward(x_t.clone()) + self.cell_recurrent.forward(h.clone()),
);
let o_t = activation::sigmoid(
self.output_gate.forward(x_t) + self.output_recurrent.forward(h.clone()),
);
c = f_t * c + i_t * g_t;
h = o_t * activation::tanh(c.clone());
let h_reshaped = h.clone().reshape([batch_size, 1, self.hidden_size]);
outputs =
outputs.slice_assign([0..batch_size, t..t + 1, 0..self.hidden_size], h_reshaped);
}
outputs
}
pub fn hidden_size(&self) -> usize {
self.hidden_size
}
}