1use burn_backend::{
2 DeviceOps, ExecutionError, FloatDType, Shape, Slice, TensorData, TensorMetadata,
3 TensorPrimitive,
4 ops::QTensorOps,
5 quantization::{QuantPropagation, QuantScheme, QuantizationParametersPrimitive},
6 tensor::{FloatTensor, IntTensor, QuantizedTensor},
7};
8
9use crate::{Dispatch, DispatchDevice};
10
11impl QTensorOps<Self> for Dispatch {
12 fn q_from_data(data: TensorData, device: &DispatchDevice) -> QuantizedTensor<Self> {
13 creation_op!(Quantized, device, |device| B::q_from_data(data, device))
14 }
15
16 fn quantize(
17 tensor: FloatTensor<Self>,
18 scheme: &QuantScheme,
19 qparams: QuantizationParametersPrimitive<Self>,
20 ) -> QuantizedTensor<Self> {
21 let QuantizationParametersPrimitive { scales, global } = qparams;
22 multi_op!(
25 inputs[(tensor, float), (scales, float)],
26 opt_inputs[(global, float)],
27 => Quantized,
28 B::quantize(tensor, scheme, QuantizationParametersPrimitive { scales, global })
29 )
30 }
31
32 fn dequantize(tensor: QuantizedTensor<Self>, dtype: FloatDType) -> FloatTensor<Self> {
33 unary_op!(tensor, quantized, |tensor| B::dequantize(tensor, dtype) => Float)
34 }
35
36 fn q_to_device(
37 tensor: QuantizedTensor<Self>,
38 device: &DispatchDevice,
39 ) -> QuantizedTensor<Self> {
40 to_device!(
41 Quantized,
42 quantized,
43 tensor,
44 device,
45 q_to_device,
46 |inner, device| {
47 let data =
48 burn_backend::read_sync(B1::q_into_data(inner)).expect("Should read data");
49 B2::q_from_data(data, device)
50 }
51 )
52 }
53
54 fn q_reshape(tensor: QuantizedTensor<Self>, shape: Shape) -> QuantizedTensor<Self> {
55 unary_op!(tensor, quantized, |tensor| B::q_reshape(tensor, shape) => Quantized)
56 }
57
58 async fn q_into_data(tensor: QuantizedTensor<Self>) -> Result<TensorData, ExecutionError> {
59 unary_op!(tensor, quantized, |tensor| B::q_into_data(tensor).await)
60 }
61
62 fn q_expand(tensor: QuantizedTensor<Self>, shape: Shape) -> QuantizedTensor<Self> {
63 unary_op!(tensor, quantized, |tensor| B::q_expand(tensor, shape) => Quantized)
64 }
65
66 fn q_swap_dims(
67 tensor: QuantizedTensor<Self>,
68 dim1: usize,
69 dim2: usize,
70 ) -> QuantizedTensor<Self> {
71 unary_op!(tensor, quantized, |tensor| B::q_swap_dims(tensor, dim1, dim2) => Quantized)
72 }
73
74 fn q_permute(tensor: QuantizedTensor<Self>, axes: &[usize]) -> QuantizedTensor<Self> {
75 unary_op!(tensor, quantized, |tensor| B::q_permute(tensor, axes) => Quantized)
76 }
77
78 fn q_flip(tensor: QuantizedTensor<Self>, axes: &[usize]) -> QuantizedTensor<Self> {
79 unary_op!(tensor, quantized, |tensor| B::q_flip(tensor, axes) => Quantized)
80 }
81
82 fn q_select(
83 tensor: QuantizedTensor<Self>,
84 dim: usize,
85 indices: IntTensor<Self>,
86 ) -> QuantizedTensor<Self> {
87 binary_op!(
88 (tensor, quantized),
89 (indices, int),
90 |tensor, indices| B::q_select(tensor, dim, indices) => Quantized
91 )
92 }
93
94 fn q_slice(tensor: QuantizedTensor<Self>, slices: &[Slice]) -> QuantizedTensor<Self> {
95 unary_op!(tensor, quantized, |tensor| B::q_slice(tensor, slices) => Quantized)
96 }
97
98 fn q_matmul(lhs: TensorPrimitive<Self>, rhs: TensorPrimitive<Self>) -> TensorPrimitive<Self> {
99 match (lhs, rhs) {
101 (TensorPrimitive::QFloat(lhs), TensorPrimitive::QFloat(rhs)) => {
102 let propagation = lhs.device().defaults().quantization.propagation;
103 if matches!(propagation, QuantPropagation::Propagate) {
104 let out = binary_op!(
105 (lhs, quantized),
106 (rhs, quantized),
107 |lhs, rhs| {
108 if let TensorPrimitive::QFloat(out) = B::q_matmul(
109 TensorPrimitive::QFloat(lhs),
110 TensorPrimitive::QFloat(rhs),
111 ) {
112 out
113 } else {
114 unreachable!()
115 }
116 } => Quantized
117 );
118 TensorPrimitive::QFloat(out)
119 } else {
120 let out = binary_op!(
121 (lhs, quantized),
122 (rhs, quantized),
123 |lhs, rhs| {
124 if let TensorPrimitive::Float(out) = B::q_matmul(
125 TensorPrimitive::QFloat(lhs),
126 TensorPrimitive::QFloat(rhs),
127 ) {
128 out
129 } else {
130 unreachable!()
131 }
132 } => Float
133 );
134 TensorPrimitive::Float(out)
135 }
136 }
137 (TensorPrimitive::Float(lhs), TensorPrimitive::QFloat(rhs)) => {
138 let propagation = rhs.device().defaults().quantization.propagation;
139 if matches!(propagation, QuantPropagation::Propagate) {
143 let out = binary_float!(
144 (lhs, float),
145 (rhs, quantized),
146 |lhs, rhs| {
147 if let TensorPrimitive::QFloat(out) = B::q_matmul(
148 TensorPrimitive::Float(lhs),
149 TensorPrimitive::QFloat(rhs),
150 ) {
151 out
152 } else {
153 unreachable!()
154 }
155 } => Quantized
156 );
157 TensorPrimitive::QFloat(out)
158 } else {
159 let out = binary_float!(
160 (lhs, float),
161 (rhs, quantized),
162 |lhs, rhs| {
163 if let TensorPrimitive::Float(out) = B::q_matmul(
164 TensorPrimitive::Float(lhs),
165 TensorPrimitive::QFloat(rhs),
166 ) {
167 out
168 } else {
169 unreachable!()
170 }
171 } => Float
172 );
173 TensorPrimitive::Float(out)
174 }
175 }
176 (TensorPrimitive::QFloat(lhs), TensorPrimitive::Float(rhs)) => {
177 let propagation = lhs.device().defaults().quantization.propagation;
178 if matches!(propagation, QuantPropagation::Propagate) {
179 let out = binary_float!(
180 (lhs, quantized),
181 (rhs, float),
182 |lhs, rhs| {
183 if let TensorPrimitive::QFloat(out) = B::q_matmul(
184 TensorPrimitive::QFloat(lhs),
185 TensorPrimitive::Float(rhs),
186 ) {
187 out
188 } else {
189 unreachable!()
190 }
191 } => Quantized
192 );
193 TensorPrimitive::QFloat(out)
194 } else {
195 let out = binary_float!(
196 (lhs, quantized),
197 (rhs, float),
198 |lhs, rhs| {
199 if let TensorPrimitive::Float(out) = B::q_matmul(
200 TensorPrimitive::QFloat(lhs),
201 TensorPrimitive::Float(rhs),
202 ) {
203 out
204 } else {
205 unreachable!()
206 }
207 } => Float
208 );
209 TensorPrimitive::Float(out)
210 }
211 }
212 _ => unreachable!(),
213 }
214 }
215}