use burn::module::Module;
use burn::nn::{Linear, LinearConfig};
use burn::tensor::{activation, backend::Backend, Tensor};
#[derive(Module, Debug)]
pub struct DailyGRU<B: Backend> {
input_size: usize,
hidden_size: usize,
dropout_rate: f64,
update_gate_input: Linear<B>,
update_gate_hidden: Linear<B>,
reset_gate_input: Linear<B>,
reset_gate_hidden: Linear<B>,
output_gate_input: Linear<B>,
output_gate_hidden: Linear<B>,
}
impl<B: Backend> DailyGRU<B> {
pub fn new(
input_size: usize,
hidden_size: usize,
dropout_rate: f64,
device: &B::Device,
) -> Self {
let update_gate_input_config = LinearConfig::new(input_size, hidden_size);
let update_gate_hidden_config = LinearConfig::new(hidden_size, hidden_size);
let reset_gate_input_config = LinearConfig::new(input_size, hidden_size);
let reset_gate_hidden_config = LinearConfig::new(hidden_size, hidden_size);
let output_gate_input_config = LinearConfig::new(input_size, hidden_size);
let output_gate_hidden_config = LinearConfig::new(hidden_size, hidden_size);
let update_gate_input = update_gate_input_config.init(device);
let update_gate_hidden = update_gate_hidden_config.init(device);
let reset_gate_input = reset_gate_input_config.init(device);
let reset_gate_hidden = reset_gate_hidden_config.init(device);
let output_gate_input = output_gate_input_config.init(device);
let output_gate_hidden = output_gate_hidden_config.init(device);
Self {
input_size,
hidden_size,
dropout_rate,
update_gate_input,
update_gate_hidden,
reset_gate_input,
reset_gate_hidden,
output_gate_input,
output_gate_hidden,
}
}
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 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 z_t = activation::sigmoid(
self.update_gate_input.forward(x_t.clone())
+ self.update_gate_hidden.forward(h.clone()),
);
let r_t = activation::sigmoid(
self.reset_gate_input.forward(x_t.clone())
+ self.reset_gate_hidden.forward(h.clone()),
);
let h_tilde = activation::tanh(
self.output_gate_input.forward(x_t)
+ self.output_gate_hidden.forward(r_t * h.clone()),
);
h = (Tensor::ones_like(&z_t) - z_t.clone()) * h_tilde + z_t * h;
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
}
}