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