# BFL (fp8r / nvfp4)

[Black Forest Labs](https://huggingface.co/black-forest-labs) выпускает квантованные варианты своих трансформеров [Flux3](../api/pipelines/flux3) в двух схемах, сохраняя их в виде однофайловых чекпоинтов рядом с исходными весами bf16:

- `fp8r`: rowwise FP8. Каждый квантованный линейный слой хранит `weight` в формате E4M3 и `weight_scale` в формате fp32 для каждой строки. Активации квантуются в E4M3 построчно во время выполнения.
- `nvfp4`: NVFP4 в раскладке [ModelOpt](https://github.com/NVIDIA/Model-Optimizer). Каждый квантованный линейный слой хранит упакованные веса E2M1 `weight` (два значения на байт), блочные масштабы E4M3 для 16 элементов (`weight_scale`), глобальный масштаб `weight_scale_2` в fp32 и откалиброванный масштаб активаций `input_scale` в fp32.

Diffusers загружает оба через `~FromSingleFileMixin.from_single_file` с [BFLQuantizationConfig](/docs/diffusers/main/ru/api/quantization#diffusers.BFLQuantizationConfig). Схема считывается из контрольной точки, поэтому одна и та же конфигурация работает для обоих файлов. Поддерживается только загрузка предварительно квантованных контрольных точек; загрузка на уровне пайплайна не поддерживается.

Пример ниже загружает чекпоинт `fp8r` модели [FLUX 3 Image Klein Base](https://huggingface.co/black-forest-labs/flux-3-image-klein-base), который находится в репозитории модели по пути `variants/fp8r/model.safetensors`. Передайте параметр `config`, чтобы конфигурация модели была прочитана из папки Diffusers в этом репозитории, а затем загрузите остальные компоненты по имени (см. [Загрузка из одного файла](../api/pipelines/flux3#single-file-loading)).

```python
import torch

from diffusers import BFLQuantizationConfig, Flux3Transformer2DModel, ModularPipeline

ckpt_path = "https://huggingface.co/black-forest-labs/flux-3-image-klein-base/blob/main/variants/fp8r/model.safetensors"
transformer = Flux3Transformer2DModel.from_single_file(
    ckpt_path,
    config="black-forest-labs/flux-3-image-klein-base",
    subfolder="transformer",
    quantization_config=BFLQuantizationConfig(compute_dtype=torch.bfloat16),
    dtype=torch.bfloat16,
)
pipe = ModularPipeline.from_pretrained("black-forest-labs/flux-3-image-klein-base")
pipe.load_components(dtype=torch.bfloat16)
pipe.update_components(transformer=transformer)
pipe.to("cuda")

prompt = "A wide-angle wildlife photograph of a red fox standing alert in a snow-covered forest clearing at golden hour."
image = pipe(prompt=prompt, generator=torch.Generator().manual_seed(0), output="images")[0]
image.save("flux3-klein-base-fp8r.png")
```

Замените `variants/fp8r` на `variants/nvfp4`, чтобы загрузить вариант `nvfp4`. Step-distilled [FLUX 3 Image Klein](https://huggingface.co/black-forest-labs/flux-3-image-klein) поставляется с теми же двумя вариантами; загрузите их, указав идентификатор репозитория в качестве `config` и pipeline.

## Ядра

Квантованные веса сохраняются в своём типе данных с низкой точностью. Какой GEMM выполняется, зависит от устройства:

| Схема | Слиянное ядро | Требования |
|---|---|---|
| `fp8r` | `torch._scaled_mm` с rowwise-масштабами | CUDA GPU с вычислительной мощностью 8.9 или выше |
| `nvfp4` | `flashinfer.mm_fp4` (CUTLASS) с `flashinfer.nvfp4_quantize` для активаций | GPU Blackwell (вычислительная способность 10.0 или выше), набор CUDA с `nvcc`, а также `flashinfer-python` и `flashinfer-cubin` той же версии |

Установите оба пакета FlashInfer одной и той же версии, например `pip install flashinfer-python==0.6.13 flashinfer-cubin==0.6.13`. Релиз `flashinfer-cubin` может отставать от `flashinfer-python`, и FlashInfer отказывается импортироваться, если версии различаются.

FlashInfer компилирует свои ядра NVFP4 при первом использовании с помощью CUDA toolkit окружения и определяет целевую архитектуру по видимому GPU (или из переменной `FLASHINFER_CUDA_ARCH_LIST`, если она задана). Потребительские и рабочие станции Blackwell (compute capability 12.0) требуют CUDA toolkit версии 12.9 или новее. При использовании более старой версии toolkit FlashInfer не находит подходящую архитектуру, и первый вызов NVFP4 завершается ошибкой `FlashInfer requires GPUs with sm75 or higher`.

На любом другом устройстве веса деквантуются до `compute_dtype` на каждом проходе вперёд, и слой работает как обычный линейный. В этом случае активации не квантуются, поэтому выходные значения немного отличаются от результатов слиянных ядер.

