1use super::reparameterization_dyn::{self, DynReparameterization};
2use super::{Param, ParamId, Parameter, Reparameterization};
3use crate::module::{
4 AutodiffModule, Content, Module, ModuleDisplay, ModuleDisplayDefault, ModuleMapper,
5 ModuleVisitor,
6};
7use alloc::{boxed::Box, format, string::ToString, vec::Vec};
8use burn_tensor::{Bool, Device, Float, Int, Tensor, TensorData};
9
10impl<const D: usize> super::sealed::Sealed for Tensor<D, Float> {
11 fn materialize(self, reparameterization: &dyn DynReparameterization) -> Self {
12 *reparameterization
13 .materialize_dyn(Box::new(self))
14 .downcast::<Tensor<D>>()
15 .expect("Reparameterization should preserve tensor rank")
16 }
17}
18impl<const D: usize> super::sealed::Sealed for Tensor<D, Int> {}
19impl<const D: usize> super::sealed::Sealed for Tensor<D, Bool> {}
20
21impl<const D: usize> Parameter for Tensor<D, Float> {
22 fn device(&self) -> Device {
23 Tensor::device(self)
24 }
25
26 fn is_require_grad(&self) -> bool {
27 Tensor::is_require_grad(self)
28 }
29
30 fn set_require_grad(self, require_grad: bool) -> Self {
31 Tensor::set_require_grad(self, require_grad)
32 }
33
34 fn shape(&self) -> burn_std::Shape {
35 Tensor::shape(self)
36 }
37
38 fn load_to_device(self, device: &Device) -> Self {
39 if self.device() != *device {
40 Tensor::to_device(self, device).detach()
41 } else {
42 self
43 }
44 }
45}
46
47impl<const D: usize> Parameter for Tensor<D, Int> {
48 fn device(&self) -> Device {
49 Tensor::device(self)
50 }
51
52 fn is_require_grad(&self) -> bool {
53 false
54 }
55
56 fn set_require_grad(self, _require_grad: bool) -> Self {
57 self
58 }
59
60 fn shape(&self) -> burn_std::Shape {
61 Tensor::shape(self)
62 }
63
64 fn load_to_device(self, device: &Device) -> Self {
65 if self.device() != *device {
66 Tensor::to_device(self, device)
67 } else {
68 self
69 }
70 }
71}
72
73impl<const D: usize> Parameter for Tensor<D, Bool> {
74 fn device(&self) -> Device {
75 Tensor::device(self)
76 }
77
78 fn is_require_grad(&self) -> bool {
79 false
80 }
81
82 fn set_require_grad(self, _require_grad: bool) -> Self {
83 self
84 }
85
86 fn shape(&self) -> burn_std::Shape {
87 Tensor::shape(self)
88 }
89
90 fn load_to_device(self, device: &Device) -> Self {
91 if self.device() != *device {
92 Tensor::to_device(self, device)
93 } else {
94 self
95 }
96 }
97}
98
99impl<const D: usize> Param<Tensor<D>> {
100 pub fn from_tensor(value: Tensor<D>) -> Self {
108 Param::initialized(ParamId::new(), value.require_grad())
111 }
112
113 pub fn from_data<T>(data: T, device: &Device) -> Self
115 where
116 T: Into<TensorData>,
117 {
118 let data: TensorData = data.into();
119 device.memory_persistent_allocations(data, |data| {
122 let value = Tensor::from_data(data, device);
123 Param::initialized(ParamId::new(), value.require_grad())
124 })
125 }
126
127 pub(crate) fn with_reparameterization<R>(mut self, reparameterization: R) -> Self
129 where
130 R: Reparameterization,
131 {
132 self.reparameterization = Some(reparameterization_dyn::boxed::<R, D>(reparameterization));
133 self
134 }
135}
136
137impl<const D: usize> Module for Param<Tensor<D>> {
138 fn visit<V: ModuleVisitor>(&self, visitor: &mut V) {
139 match self.reparameterization_dyn() {
140 None => visitor.visit_float(self),
141 Some(reparameterization) => {
142 visitor.visit_float(&self.without_reparameterization());
143 visitor.enter_module(reparameterization.name(), "Reparameterization");
144 reparameterization_dyn::visit(reparameterization, visitor);
145 visitor.exit_module(reparameterization.name(), "Reparameterization");
146 }
147 }
148 }
149
150 fn map<M: ModuleMapper>(mut self, mapper: &mut M) -> Self {
151 match self.reparameterization.take() {
152 None => mapper.map_float(self),
153 Some(reparameterization) => {
154 let base = mapper.map_float(self);
155 mapper.enter_module(reparameterization.name(), "Reparameterization");
156 let reparameterization = reparameterization_dyn::map(reparameterization, mapper);
157 mapper.exit_module(reparameterization.name(), "Reparameterization");
158 base.with_dyn_reparameterization(Some(reparameterization))
159 }
160 }
161 }
162
163 fn to_device(mut self, device: &Device) -> Self {
164 let reparameterization = self.reparameterization.take();
165 let base = self.map(|tensor| tensor.to_device(device));
166 match reparameterization {
167 None => base,
168 Some(reparameterization) => {
169 base.with_dyn_reparameterization(Some(reparameterization.to_device_dyn(device)))
170 }
171 }
172 }
173
174 fn fork(mut self, device: &Device) -> Self {
175 let reparameterization = self.reparameterization.take();
176 let base = self.map(|tensor| {
177 let is_require_grad = tensor.is_require_grad();
178 let mut tensor = tensor.to_device(device).detach();
179
180 if is_require_grad {
181 tensor = tensor.require_grad();
182 }
183
184 tensor
185 });
186 match reparameterization {
187 None => base,
188 Some(reparameterization) => {
189 base.with_dyn_reparameterization(Some(reparameterization.fork_dyn(device)))
190 }
191 }
192 }
193
194 fn collect_devices(&self, mut devices: Vec<Device>) -> Vec<Device> {
195 let device = self.base().device();
196
197 if !devices.contains(&device) {
198 devices.push(device)
199 }
200
201 if let Some(reparameterization) = self.reparameterization_dyn() {
202 devices = reparameterization.collect_devices_dyn(devices);
203 }
204
205 devices
206 }
207}
208
209impl<const D: usize> ModuleDisplayDefault for Param<Tensor<D>> {
210 fn content(&self, content: Content) -> Option<Content> {
211 let id = if content.display_settings.show_param_id() {
212 format!(", id: {}", self.id)
213 } else {
214 "".to_string()
215 };
216 let string = format!(
217 "ParamTensor {{rank: {D}, shape: {:?}, kind: float{id}}}",
218 self.shape().as_slice()
219 );
220 content.add_formatted(&string).optional()
221 }
222}
223impl<const D: usize> ModuleDisplay for Param<Tensor<D>> {}
224
225impl<const D: usize> Module for Param<Tensor<D, Int>> {
226 fn visit<V: ModuleVisitor>(&self, visitor: &mut V) {
227 visitor.visit_int(self)
228 }
229
230 fn map<M: ModuleMapper>(self, mapper: &mut M) -> Self {
231 mapper.map_int(self)
232 }
233
234 fn to_device(self, device: &Device) -> Self {
235 self.map(|tensor| tensor.to_device(device))
236 }
237
238 fn fork(self, device: &Device) -> Self {
239 self.to_device(device) }
241
242 fn collect_devices(&self, mut devices: Vec<Device>) -> Vec<Device> {
243 let device = self.val().device();
244
245 if !devices.contains(&device) {
246 devices.push(device)
247 }
248
249 devices
250 }
251}
252
253impl<const D: usize> ModuleDisplayDefault for Param<Tensor<D, Int>> {
254 fn content(&self, content: Content) -> Option<Content> {
255 let id = if content.display_settings.show_param_id() {
256 format!(", id: {}", self.id)
257 } else {
258 "".to_string()
259 };
260 let string = format!(
261 "ParamTensor {{rank: {D}, shape: {:?}, kind: int{id}}}",
262 self.shape().as_slice()
263 );
264 content.add_formatted(&string).optional()
265 }
266}
267impl<const D: usize> ModuleDisplay for Param<Tensor<D, Int>> {}
268
269impl<const D: usize> Module for Param<Tensor<D, Bool>> {
270 fn visit<V: ModuleVisitor>(&self, visitor: &mut V) {
271 visitor.visit_bool(self)
272 }
273
274 fn map<M: ModuleMapper>(self, mapper: &mut M) -> Self {
275 mapper.map_bool(self)
276 }
277
278 fn to_device(self, device: &Device) -> Self {
279 self.map(|tensor| tensor.to_device(device))
280 }
281
282 fn fork(self, device: &Device) -> Self {
283 self.to_device(device) }
285
286 fn collect_devices(&self, mut devices: Vec<Device>) -> Vec<Device> {
287 let device = self.val().device();
288
289 if !devices.contains(&device) {
290 devices.push(device)
291 }
292
293 devices
294 }
295}
296
297impl<const D: usize> ModuleDisplayDefault for Param<Tensor<D, Bool>> {
298 fn content(&self, content: Content) -> Option<Content> {
299 let id = if content.display_settings.show_param_id() {
300 format!(", id: {}", self.id)
301 } else {
302 "".to_string()
303 };
304
305 let string = format!(
306 "ParamTensor {{rank: {D}, shape: {:?}, kind: bool{id}}}",
307 self.shape().as_slice()
308 );
309 content.add_formatted(&string).optional()
310 }
311}
312
313impl<const D: usize> ModuleDisplay for Param<Tensor<D, Bool>> {}
314
315impl<const D: usize> AutodiffModule for Param<Tensor<D>> {
316 fn valid(&self) -> Self {
317 let require_grad = self.require_grad;
320 let mut param = Param::initialized(self.id, self.val().inner().set_require_grad(false));
321 param.require_grad = require_grad;
322 param
323 }
324
325 fn from_inner(mut module: Self) -> Self {
326 let reparameterization = module.reparameterization.take();
328 let tensor = Tensor::from_inner(module.val()).set_require_grad(module.require_grad);
330 let base = Param::initialized(module.id, tensor);
331 match reparameterization {
332 None => base,
333 Some(reparameterization) => {
334 base.with_dyn_reparameterization(Some(reparameterization.from_inner_dyn()))
335 }
336 }
337 }
338}
339
340impl<const D: usize> AutodiffModule for Param<Tensor<D, Int>> {
341 fn valid(&self) -> Self {
342 Param::initialized(self.id, self.val().inner())
343 }
344
345 fn from_inner(module: Self) -> Self {
346 Param::initialized(module.id, Tensor::from_inner(module.val()))
347 }
348}
349
350impl<const D: usize> AutodiffModule for Param<Tensor<D, Bool>> {
351 fn valid(&self) -> Self {
352 Param::initialized(self.id, self.val().inner())
353 }
354
355 fn from_inner(module: Self) -> Self {
356 Param::initialized(module.id, Tensor::from_inner(module.val()))
357 }
358}
359
360#[cfg(all(test, feature = "std", feature = "autodiff"))]
361mod tests {
362 use super::*;
363 use crate::{module::Module, test_device};
364
365 #[test]
366 fn test_param_require_grad_stateful() {
367 let device = test_device().autodiff();
368 let tensor = Tensor::<2>::ones([3, 3], &device).require_grad();
369
370 let param = Param::initialized(ParamId::new(), tensor);
371 assert!(param.is_require_grad());
372 assert!(param.require_grad);
373
374 let param = param.valid();
375 assert!(!param.is_require_grad());
376 assert!(param.require_grad); let param = param.train();
381 assert!(param.is_require_grad());
382 assert!(param.require_grad); let param = param.no_grad();
385 assert!(!param.is_require_grad());
386 assert!(!param.require_grad); let param = param.valid();
389 assert!(!param.is_require_grad()); assert!(!param.require_grad); let param = param.train();
393 assert!(!param.is_require_grad());
394 assert!(!param.require_grad); }
396}