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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
//! High level neural network building blocks such as [modules::Linear], activations, and tuples as [Module]s.
//! Also includes `.save()` & `.load()` for all [Module]s.
//!
//! # Mutable vs Immutable forwards
//!
//! This is provided as two separate traits
//!
//! 1. [ModuleMut::forward_mut()] which receives `&mut self`.
//! 2. [Module::forward()] which receives `&self`.
//!
//! **This has nothing to do with whether gradients are being tracked or not**.
//! It only controls whether the module itself can be modified. Both OwnedTape
//! and NoneTape can still be passed to both, and all modules should conform
//! to this expected behavior.
//!
//! In general, [ModuleMut::forward_mut()] should be used during training,
//! and [Module::forward()] during evaluation/testing/inference/validation.
//!
//! Here is a list of existing modules that have different behavior in these
//! two functions:
//!
//! - [modules::BatchNorm1D]
//! - [modules::BatchNorm2D]
//! - [modules::DropoutOneIn]
//! - [modules::Dropout]
//!
//! # Fallible forwards
//!
//! You can also get a result from Module by using [ModuleMut::try_forward_mut],
//! and [Module::try_forward].
//!
//! Similar to fallible tensor_ops, the main purpose of this is to handle out of memory
//! errors at the device level.
//!
//! # Initializing
//!
//! Use [DeviceBuildExt] for device agnostic module creation/randomization:
//!
//! ```rust
//! # use dfdx::prelude::*;
//! # let dev: Cpu = Default::default();
//! use dfdx::nn::builders::{Linear, DeviceBuildExt};
//! type Model = Linear<5, 2>;
//! let model = dev.build_module::<Model, f32>();
//! ```
//!
//! Here, the return type depends on the device and dtype you are using.
//!
//! For example, when using device [crate::tensor::Cpu] and `f32`, the type
//! is `Linear<5, 2, f32, Cpu>`. When using
//! a `Cuda` device and `f64`, the type is `Linear<5, 2, f64, Cuda>`.
//!
//! Alternatively, you can use [BuildModule], which requires device specific model definitions:
//!
//! ```rust
//! # use dfdx::prelude::*;
//! use dfdx::nn::modules::{Linear, BuildModule};
//! type Dev = Cpu;
//! let dev: Dev = Default::default();
//! let model: Linear<5, 2, f32, Dev> = BuildModule::build(&dev);
//! ```
//!
//! # Allocating & zeroing gradients
//!
//! Use [ZeroGrads::alloc_grads()] and [ZeroGrads::zero_grads()] to reduce allocations,
//! and enable gradient accumulation!
//! This is the equivalent of pytorch's `Optimizer.zero_grad`
//!
//! ```rust
//! # use dfdx::prelude::*;
//! # let dev: Cpu = Default::default();
//! # type Model = Linear<5, 2>;
//! use dfdx::nn::ZeroGrads;
//! let model = dev.build_module::<Model, f32>();
//! let mut grads: Gradients<f32, _> = model.alloc_grads();
//! model.zero_grads(&mut grads);
//! ```
//!
//! # Exponential Moving Average (EMA)
//!
//! All models implement [ModelEMA::ema()] to keep track of an exponential moving average
//! of an entire model.
//!
//! ```rust
//! # use dfdx::prelude::*;
//! # let dev: Cpu = Default::default();
//! # type Model = Linear<5, 2>;
//! use dfdx::nn::ModelEMA;
//! let model = dev.build_module::<Model, f32>();
//! let mut ema_model = dev.build_module::<Model, f32>();
//! ema_model.ema(&model, 0.001);
//! ```
//!
//! # Resetting parameters
//!
//! All modules implement [ResetParams], which allows you to reset a module back to a randomized
//! state:
//!
//! ```rust
//! # use dfdx::prelude::*;
//! # let dev: Cpu = Default::default();
//! type Model = Linear<5, 2>;
//! let mut model = dev.build_module::<Model, f32>();
//! model.reset_params();
//! ```
//!
//! # Sequential models
//!
//! Tuple's implement [Module], so you can string multiple module's together.
//!
//! Here's a single layer MLP:
//! ```rust
//! # use dfdx::prelude::*;
//! type Mlp = (Linear<5, 3>, ReLU, Linear<3, 2>);
//! ```
//!
//! Here's a more complex feedforward network that takes vectors of 5 elements and maps them to 2 elements.
//! ```rust
//! # use dfdx::prelude::*;
//! type ComplexNetwork = (
//! DropoutOneIn<2>, // 1. dropout 50% of input
//! Linear<5, 3>, // 2. pass into a linear layer
//! LayerNorm1D<3>, // 3. normalize elements
//! ReLU, // 4. activate with relu
//! Residual<( // 5. residual connection that adds input to the result of it's sub layers
//! Linear<3, 3>,// 5.a. Apply linear layer
//! ReLU, // 5.b. Apply Relu
//! )>, // 5.c. the input to the residual is added back in after the sub layers
//! Linear<3, 2>, // 6. Apply another linear layer
//! );
//! ```
//!
//! # Saving and Loading
//!
//! # numpy
//!
//! Enable with the `"numpy"` feature.
//!
//! Call [SaveToNpz::save()] and [LoadFromNpz::load()] methods. All modules provided here implement it,
//! including tuples. These all save to/from `.npz` files, which are basically zip files with multiple `.npy`
//! files.
//!
//! This is implemented to be fairly portable. For example you can load a simple MLP into pytorch like so:
//!
//! ```python
//! import torch
//! import numpy as np
//! state_dict = {k: torch.from_numpy(v) for k, v in np.load("dfdx-model.npz").items()}
//! mlp.load_state_dict(state_dict)
//! ```
//!
//! # safetensors
//!
//! Enable with the `"safetensors"` feature.
//!
//! The feature `safetensors` allows to do the same with
//! [https://github.com/huggingface/safetensors]().
//!
//! Call [SaveToSafetensors::save_safetensors()] and [LoadFromSafetensors::load_safetensors()] funcs.
//! All modules provided here implement it, including tuples.
//!
//! These all save to/from `.safetensors` files, which are flat layout with JSON
//! header, allowing for super fast loads (with memory mapping).
//!
//! This is implemented to be fairly portable. For example you can use
//! [https://github.com/huggingface/transformers]()
//!
//! ```python
//! from transformers import pipeline
//!
//! pipe = pipeline(model="gpt2")
//! pipe.save_pretrained("my_local", safe_serialization=True)
//! # This created `my_local/model.safetensors` file which can now be used.
//! ```
pub use ;
pub use *;
pub use ;
pub use ModelEMA;
pub use ;
pub use NumParams;
pub use ResetParams;
pub use ToDevice;
pub use ToDtype;
pub use ZeroGrads;