1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use crate::{Backend, BackendTypes, DeviceOps, get_device_settings};
use burn_std::{DType, QuantScheme, Shape};
#[derive(Debug, Clone)]
/// A primitive tensor representation.
pub enum TensorPrimitive<B: BackendTypes> {
/// Float tensor primitive.
Float(B::FloatTensorPrimitive),
/// Quantized float tensor primitive.
QFloat(B::QuantizedTensorPrimitive),
}
impl<B: Backend> TensorPrimitive<B> {
/// Returns the full tensor representation.
pub fn tensor(self) -> B::FloatTensorPrimitive {
match self {
Self::QFloat(tensor) => {
let dtype = get_device_settings::<B>(&tensor.device()).float_dtype;
B::dequantize(tensor, dtype)
}
Self::Float(tensor) => tensor,
}
}
/// Returns a mutable reference to the full tensor representation.
pub fn get_mut_ref(&mut self) -> &mut B::FloatTensorPrimitive {
match self {
Self::QFloat(_tensor) => todo!(),
Self::Float(tensor) => tensor,
}
}
}
impl<B: BackendTypes> TensorMetadata for TensorPrimitive<B> {
type Device = B::Device;
fn dtype(&self) -> DType {
match self {
TensorPrimitive::Float(tensor) => tensor.dtype(),
TensorPrimitive::QFloat(tensor) => tensor.dtype(),
}
}
fn shape(&self) -> Shape {
match self {
TensorPrimitive::Float(tensor) => tensor.shape(),
TensorPrimitive::QFloat(tensor) => tensor.shape(),
}
}
fn rank(&self) -> usize {
match self {
TensorPrimitive::Float(tensor) => tensor.rank(),
TensorPrimitive::QFloat(tensor) => tensor.rank(),
}
}
fn device(&self) -> Self::Device {
match self {
TensorPrimitive::Float(tensor) => tensor.device(),
TensorPrimitive::QFloat(tensor) => tensor.device(),
}
}
fn can_mut(&self) -> bool {
match self {
TensorPrimitive::Float(tensor) => tensor.can_mut(),
TensorPrimitive::QFloat(tensor) => tensor.can_mut(),
}
}
}
/// Tensor metadata trait for tensor primitive.
pub trait TensorMetadata: Clone + Send + Sync + core::fmt::Debug {
/// The device type associated with the tensor.
type Device: DeviceOps;
/// Get the dtype of the tensor.
fn dtype(&self) -> DType;
/// Get the shape of the tensor.
fn shape(&self) -> Shape;
/// Get the number of dimensions of the tensor.
fn rank(&self) -> usize {
self.shape().num_dims()
}
/// Get the device associated with the tensor.
fn device(&self) -> Self::Device;
/// Whether the tensor's buffer can be mutated in place — i.e. this handle
/// uniquely owns it, so an in-place op (`slice_assign`, an inplace kernel)
/// writes the existing allocation instead of copying it first.
///
/// Backends that track buffer ownership (cubecl, fusion, tch) answer
/// precisely; a backend that can't must return a conservative `false` —
/// the buffer may be aliased, so an in-place write can't be assumed safe.
fn can_mut(&self) -> bool;
/// Get the [quantization scheme](QuantScheme) for a quantized float tensor.
///
/// # Panics
/// Panics if the tensor is not quantized.
fn scheme(&self) -> QuantScheme {
match self.dtype() {
DType::QFloat(scheme) => scheme,
other => panic!("Quantization scheme is not valid for dtype {other:?}"),
}
}
}