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