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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//! Dimension and shape validators shared by the recurrent layers
//!
//! Each function is a narrow guard that a layer calls before it trusts a dimension or a tensor
//! shape. [`validate_recurrent_dimensions`] composes 2 calls to
//! [`validate_dimension_greater_than_zero`], 1 per dimension. [`validate_input_3d`] guards the
//! rank of the forward input. [`split_grad_output`] guards the shape of the backward gradient and
//! builds the initial running gradient of the backward recurrence.
use crateError;
use crateTensor;
use ;
/// Validates that a dimension value is greater than 0
///
/// # Parameters
///
/// - `value` - The dimension value to validate
/// - `name` - The name of the dimension, used to build the error message
///
/// # Returns
///
/// - `Result<(), Error>` - `Ok(())` when `value` is greater than 0, otherwise the failing `Error`
///
/// # Errors
///
/// - [`Error::InvalidParameter`] - If `value` is 0
pub
/// Validates input dimensions for recurrent layers
///
/// # Parameters
///
/// - `input_dim` - The input dimension to validate
/// - `units` - The units dimension to validate
///
/// # Returns
///
/// - `Result<(), Error>` - `Ok(())` when both dimensions are greater than 0, otherwise the
/// failing `Error`
///
/// # Errors
///
/// - [`Error::InvalidParameter`] - If `input_dim` or `units` is 0
pub
/// Validates that the input tensor is 3D for recurrent layers
///
/// # Parameters
///
/// - `input` - The input tensor to validate
///
/// # Returns
///
/// - `Result<(), Error>` - `Ok(())` when `input` has 3 dimensions, otherwise the failing `Error`
///
/// # Errors
///
/// - [`Error::InvalidInput`] - If `input` is not 3D
pub
/// Splits the upstream gradient into the running hidden-state gradient and the per-step direct
/// contributions
///
/// With `return_sequences` off, the whole upstream gradient is the gradient of the single
/// returned state, so it starts the backward recurrence directly. With `return_sequences` on,
/// the upstream gradient has 1 direct contribution per processing step. The backward recurrence
/// starts at 0 and adds each slice.
///
/// # Parameters
///
/// - `grad_output` - Upstream gradient from the next layer
/// - `layer` - Name of the layer, used to build the error message
/// - `return_sequences` - True when the forward pass returned every timestep
/// - `batch` - Batch size recorded by the forward pass
/// - `timesteps` - Length of the time axis recorded by the forward pass
/// - `units` - Number of units of the layer
///
/// # Returns
///
/// - `Result<(Array2<f32>, Option<ArrayView3<f32>>), Error>` - The initial running gradient, and
/// the per-step contributions when `return_sequences` is true
///
/// # Errors
///
/// - [`Error::InvalidInput`] - If the gradient rank does not match `return_sequences`
/// - [`Error::InvalidInput`] - If `return_sequences` is true and the gradient shape is not
/// `[batch, timesteps, units]`
pub