(shape: tuple[int, int], block_size: tuple[int, int], dtype: str)
| 176 | |
| 177 | |
| 178 | def blockwise_quant_fp8_e4m3(shape: tuple[int, int], block_size: tuple[int, int], dtype: str): |
| 179 | w_full_np = (np.random.rand(*shape) * 2 - 1).astype(dtype) |
| 180 | w_scale_shape = ( |
| 181 | *shape[:-2], |
| 182 | (shape[-2] + block_size[0] - 1) // block_size[0], |
| 183 | (shape[-1] + block_size[1] - 1) // block_size[1], |
| 184 | ) |
| 185 | # For each (block_size[0], block_size[1]) block, compute the max abs value of `w_full_np` |
| 186 | w_max_abs_np = np.zeros(w_scale_shape, dtype="float32") |
| 187 | for i in range(w_scale_shape[-2]): |
| 188 | for j in range(w_scale_shape[-1]): |
| 189 | block_shape = ( |
| 190 | *shape[:-2], |
| 191 | min(block_size[0], shape[-2] - i * block_size[0]), |
| 192 | min(block_size[1], shape[-1] - j * block_size[1]), |
| 193 | ) |
| 194 | w_max_abs_np[..., i, j] = np.max( |
| 195 | np.abs( |
| 196 | w_full_np[ |
| 197 | ..., |
| 198 | i * block_size[0] : min((i + 1) * block_size[0], shape[-2]), |
| 199 | j * block_size[1] : min((j + 1) * block_size[1], shape[-1]), |
| 200 | ] |
| 201 | ).reshape(*shape[:-2], block_shape[-2] * block_shape[-1]), |
| 202 | axis=-1, |
| 203 | ) |
| 204 | # Scale is the `w_max_abs_np` divided by the max value of quant_dtype in ml_dtypes |
| 205 | fp8_max = float(ml_dtypes.finfo("float8_e4m3fn").max) |
| 206 | w_scale_np = w_max_abs_np / fp8_max |
| 207 | # `w_np` is the `w_full_np` divided by the `w_scale_np` (with block awareness), |
| 208 | # clamped to (-fp8_max, fp8_max), and cast to `quant_dtype` |
| 209 | w_np = np.zeros_like(w_full_np, dtype="float8_e4m3fn") |
| 210 | if len(w_scale_shape) == 2: |
| 211 | for i in range(w_scale_shape[-2]): |
| 212 | for j in range(w_scale_shape[-1]): |
| 213 | w_np[ |
| 214 | i * block_size[0] : min((i + 1) * block_size[0], shape[-2]), |
| 215 | j * block_size[1] : min((j + 1) * block_size[1], shape[-1]), |
| 216 | ] = np.clip( |
| 217 | w_full_np[ |
| 218 | i * block_size[0] : min((i + 1) * block_size[0], shape[-2]), |
| 219 | j * block_size[1] : min((j + 1) * block_size[1], shape[-1]), |
| 220 | ] |
| 221 | / w_scale_np[..., i, j], |
| 222 | -fp8_max, |
| 223 | fp8_max, |
| 224 | ) |
| 225 | else: |
| 226 | for e in range(w_scale_shape[0]): |
| 227 | for i in range(w_scale_shape[-2]): |
| 228 | for j in range(w_scale_shape[-1]): |
| 229 | w_np[ |
| 230 | e, |
| 231 | i * block_size[0] : min((i + 1) * block_size[0], shape[-2]), |
| 232 | j * block_size[1] : min((j + 1) * block_size[1], shape[-1]), |
| 233 | ] = np.clip( |
| 234 | w_full_np[ |
| 235 | e, |
no test coverage detected
searching dependent graphs…