use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, RwLock};
use crate::autograd::GradSlot;
use crate::tensor::{Device, Tensor};
#[derive(Clone)]
pub struct Param {
value: Arc<RwLock<Tensor>>,
grad: GradSlot,
trainable: Arc<AtomicBool>,
}
impl Param {
pub fn new(value: Tensor) -> Param {
Param {
value: Arc::new(RwLock::new(value.detach())),
grad: GradSlot::new(),
trainable: Arc::new(AtomicBool::new(true)),
}
}
pub fn tensor(&self) -> Tensor {
let value = self.value.read().unwrap();
if !self.is_trainable() {
return value.detach();
}
Tensor::leaf(
value.storage_arc(),
value.shape().to_vec(),
value.device(),
self.grad.clone(),
)
}
pub fn freeze(&self) {
self.trainable.store(false, Ordering::Relaxed);
self.grad.clear();
}
pub fn unfreeze(&self) {
self.trainable.store(true, Ordering::Relaxed);
}
pub fn is_trainable(&self) -> bool {
self.trainable.load(Ordering::Relaxed)
}
pub fn value(&self) -> Tensor {
self.value.read().unwrap().detach()
}
pub fn set_value(&self, value: Tensor) {
assert_eq!(
value.shape(),
self.value.read().unwrap().shape(),
"set_value: shape must not change"
);
*self.value.write().unwrap() = value.detach();
}
pub fn grad(&self) -> Option<Tensor> {
self.grad.get()
}
pub fn zero_grad(&self) {
self.grad.clear();
}
pub fn set_grad(&self, grad: Tensor) {
self.grad.clear();
self.grad.accumulate(grad.detach());
}
pub fn to_device(&self, device: Device) {
let mut value = self.value.write().unwrap();
if value.device() != device {
*value = value.to(device).detach();
self.grad.clear();
}
}
pub fn shape(&self) -> Vec<usize> {
self.value.read().unwrap().shape().to_vec()
}
pub fn numel(&self) -> usize {
self.value.read().unwrap().numel()
}
pub fn device(&self) -> Device {
self.value.read().unwrap().device()
}
}
impl std::fmt::Debug for Param {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Param{:?} on {}", self.shape(), self.device())
}
}
#[derive(Clone)]
pub struct Buffer {
value: Arc<RwLock<Tensor>>,
}
impl Buffer {
pub fn new(value: Tensor) -> Buffer {
Buffer {
value: Arc::new(RwLock::new(value.detach())),
}
}
pub fn value(&self) -> Tensor {
self.value.read().unwrap().detach()
}
pub fn set_value(&self, value: Tensor) {
*self.value.write().unwrap() = value.detach();
}
pub fn to_device(&self, device: Device) {
let mut value = self.value.write().unwrap();
if value.device() != device {
*value = value.to(device).detach();
}
}
}