burn_core/module/param/
running.rs1use super::ParamId;
2use crate::module::{
3 AutodiffModule, Content, Module, ModuleDisplay, ModuleDisplayDefault, ModuleMapper,
4 ModuleVisitor, Param,
5};
6
7use alloc::string::ToString;
8use alloc::vec::Vec;
9
10#[cfg(target_has_atomic = "ptr")]
11use alloc::sync::Arc;
12
13#[cfg(not(target_has_atomic = "ptr"))]
14use portable_atomic_util::Arc;
15
16use burn_std::stub::Mutex;
17use burn_tensor::{Device, Tensor};
18
19#[cfg(feature = "std")]
20mod threading {
21 pub(super) use std::collections::HashMap;
22 pub(super) use std::thread::ThreadId;
23
24 #[inline(always)]
25 pub(super) fn get_thread_current_id() -> ThreadId {
26 std::thread::current().id()
27 }
28}
29
30#[cfg(not(feature = "std"))]
31mod threading {
32 pub(super) use burn_std::stub::ThreadId;
33 pub(super) use hashbrown::HashMap;
34
35 #[inline(always)]
36 pub(super) fn get_thread_current_id() -> ThreadId {
37 panic!("Current thread id is not available")
38 }
39}
40
41use threading::*;
43
44#[derive(Clone, Debug)]
50pub struct RunningState<V> {
51 id: ParamId,
52 values: Arc<Mutex<HashMap<ThreadId, V>>>,
53 value: Arc<Mutex<V>>,
54}
55
56impl<V> core::fmt::Display for RunningState<V> {
59 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
60 write!(f, "RunningState(id={})", self.id)
61 }
62}
63
64impl<V> ModuleDisplayDefault for RunningState<V> {
65 fn content(&self, content: Content) -> Option<Content> {
66 content
67 .add_formatted(&"RunningState".to_string())
68 .optional()
69 }
70}
71
72impl<V> ModuleDisplay for RunningState<V> {}
73
74impl<const D: usize> Module for RunningState<Tensor<D>> {
75 fn visit<V: ModuleVisitor>(&self, visitor: &mut V) {
76 let tensor = self.value.lock().unwrap();
77 let param = Param::initialized(self.id, tensor.clone());
78 visitor.visit_float(¶m)
79 }
80
81 fn map<M: ModuleMapper>(self, mapper: &mut M) -> Self {
82 let mut tensor = self.value.lock().unwrap();
83 let param = Param::initialized(self.id, tensor.clone());
84 let param_out = mapper.map_float(param);
85 let (_, tensor_out, _) = param_out.consume();
86
87 *tensor = tensor_out;
88 core::mem::drop(tensor);
89
90 self
91 }
92
93 fn to_device(self, device: &Device) -> Self {
94 let mut tensor = self.value.lock().unwrap();
95 let tensor_out = tensor.clone().to_device(device);
96
97 *tensor = tensor_out;
98 core::mem::drop(tensor);
99
100 self
101 }
102
103 fn fork(self, device: &Device) -> Self {
104 self.to_device(device) }
106
107 fn collect_devices(&self, mut devices: Vec<Device>) -> Vec<Device> {
108 let device = self.value.lock().unwrap().device();
109
110 if !devices.contains(&device) {
111 devices.push(device)
112 }
113
114 devices
115 }
116}
117
118impl<const D: usize> RunningState<Tensor<D>> {
119 pub fn new(value: Tensor<D>) -> Self {
121 Self {
122 id: ParamId::new(),
123 values: Arc::new(Mutex::new(HashMap::new())),
124 value: Arc::new(Mutex::new(value)),
125 }
126 }
127
128 pub fn with_id(id: ParamId, value: Tensor<D>) -> Self {
130 Self {
131 id,
132 values: Arc::new(Mutex::new(HashMap::new())),
133 value: Arc::new(Mutex::new(value)),
134 }
135 }
136
137 pub fn from_record(record: Param<Tensor<D>>) -> Self {
139 let tensor = record.val();
140 Self {
141 id: record.id,
142 values: Arc::new(Mutex::new(HashMap::new())),
143 value: Arc::new(Mutex::new(tensor)),
144 }
145 }
146
147 pub fn update(&self, value: Tensor<D>) {
149 let thread_id = get_thread_current_id();
150 let mut map = self.values.lock().unwrap();
151
152 if map.contains_key(&thread_id) {
153 self.update_value(&mut map);
154 }
155
156 map.insert(thread_id, value);
157 }
158
159 pub fn value(&self) -> Tensor<D> {
165 let value = self.value.lock().unwrap();
166 value.clone()
167 }
168
169 pub fn value_sync(&self) -> Tensor<D> {
176 let thread_id = get_thread_current_id();
177 let mut map = self.values.lock().unwrap();
178
179 if map.contains_key(&thread_id) {
180 self.update_value(&mut map);
181 }
182
183 let value = self.value.lock().unwrap();
184 value.clone()
185 }
186
187 fn sync(&self) {
188 let mut map = self.values.lock().unwrap();
189
190 if !map.is_empty() {
191 self.update_value(&mut map);
192 }
193 }
194
195 fn update_value(&self, map: &mut HashMap<ThreadId, Tensor<D>>) {
196 let mut value_updated: Option<Tensor<D>> = None;
197 let mut counter = 0;
198
199 for (_key, tensor) in map.drain() {
200 counter += 1;
201
202 value_updated = match value_updated {
203 Some(current) => {
204 let device = current.device();
205 Some(tensor.to_device(&device).add(current))
206 }
207 None => Some(tensor),
208 };
209 }
210
211 if let Some(value) = value_updated {
212 let value = value.div_scalar(counter);
213 let mut value_old = self.value.lock().unwrap();
214 *value_old = value;
215 }
216 }
217}
218
219impl<const D: usize> AutodiffModule for RunningState<Tensor<D>> {
220 fn valid(&self) -> Self {
221 self.sync();
222 let value = self.value();
223
224 RunningState::with_id(self.id, value.inner())
225 }
226
227 fn from_inner(module: Self) -> Self {
228 module.sync();
229 let value = module.value();
230
231 RunningState::with_id(module.id, Tensor::from_inner(value))
232 }
233}