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 valid(&self) -> Self {
113 self.sync();
114 let value = self.value();
115
116 RunningState::with_id(self.id, value.without_autodiff())
117 }
118
119 fn train(self) -> Self {
120 self.sync();
121 let value = self.value();
122
123 RunningState::with_id(self.id, Tensor::from_inner(value))
124 }
125}
126
127impl<const D: usize> RunningState<Tensor<D>> {
128 pub fn new(value: Tensor<D>) -> Self {
130 Self {
131 id: ParamId::new(),
132 values: Arc::new(Mutex::new(HashMap::new())),
133 value: Arc::new(Mutex::new(value)),
134 }
135 }
136
137 pub fn with_id(id: ParamId, value: Tensor<D>) -> Self {
139 Self {
140 id,
141 values: Arc::new(Mutex::new(HashMap::new())),
142 value: Arc::new(Mutex::new(value)),
143 }
144 }
145
146 pub fn from_record(record: Param<Tensor<D>>) -> Self {
148 let tensor = record.val();
149 Self {
150 id: record.id,
151 values: Arc::new(Mutex::new(HashMap::new())),
152 value: Arc::new(Mutex::new(tensor)),
153 }
154 }
155
156 pub fn update(&self, value: Tensor<D>) {
158 let thread_id = get_thread_current_id();
159 let mut map = self.values.lock();
160
161 if map.contains_key(&thread_id) {
162 self.update_value(&mut map);
163 }
164
165 map.insert(thread_id, value);
166 }
167
168 pub fn value(&self) -> Tensor<D> {
174 let value = self.value.lock();
175 value.clone()
176 }
177
178 pub fn value_sync(&self) -> Tensor<D> {
185 let thread_id = get_thread_current_id();
186 let mut map = self.values.lock();
187
188 if map.contains_key(&thread_id) {
189 self.update_value(&mut map);
190 }
191
192 let value = self.value.lock();
193 value.clone()
194 }
195
196 fn sync(&self) {
197 let mut map = self.values.lock();
198
199 if !map.is_empty() {
200 self.update_value(&mut map);
201 }
202 }
203
204 fn update_value(&self, map: &mut HashMap<ThreadId, Tensor<D>>) {
205 let mut value_updated: Option<Tensor<D>> = None;
206 let mut counter = 0;
207
208 for (_key, tensor) in map.drain() {
209 counter += 1;
210
211 value_updated = match value_updated {
212 Some(current) => {
213 let device = current.device();
214 Some(tensor.to_device(&device).add(current))
215 }
216 None => Some(tensor),
217 };
218 }
219
220 if let Some(value) = value_updated {
221 let value = value.div_scalar(counter);
222 let mut value_old = self.value.lock();
223 *value_old = value;
224 }
225 }
226}