Bumblebee Documentation

repository·main·Indexed 23 days ago

https://github.com/elixir-nx/bumblebee

An Elixir library providing pre-trained Neural Network models by integrating with the Hugging Face Hub and building on top of Axon and Nx. It supports PyTorch and Safetensors formats, offering tools for inference, model loading, and integration with Phoenix LiveView. The library includes specialized schedulers like DDIM and LCM for diffusion models and recommends using EXLA for high-performance CPU and GPU computations.

Tokens
7K
Snippets
8
Records
37
Agent score
81%

What's inside Bumblebee

  1. How model support works in Bumblebee

    main

    Bumblebee is an Elixir counterpart to the Python Transformers library. It does not store the actual model weights itself, but rather implements the logic to fetch and pair trained parameters with a model architecture.

    Key Requirements:

    1. Implementation: The model architecture must be implemented in Bumblebee. You can verify this by checking if the class name under "architectures" in the repository's config.json exists in the Bumblebee codebase.
    2. Format: Bumblebee supports pytorch_model.bin (PyTorch) and model.safetensors (Safetensors). It does not support Flax (flax_model.msgpack) or Tensorflow (tf_model.h5) formats.
    3. Subdirectories: If a repository contains multiple models (e.g., stabilityai/stable-diffusion-2), use the subdir option: Bumblebee.load_model({:hf, "model-repo", subdir: "..."}).
  2. Handling 'slow' tokenizers in Hugging Face

    main

    Bumblebee requires a tokenizer.json file (the "fast tokenizer" format used by Rust). If a repository only provides a "slow tokenizer" (via tokenizer_config.json), you have two options:

    1. Reuse a tokenizer: If the model is a fine-tuned version of a base model, load the tokenizer from the original base model repository.
    2. Generate a tokenizer.json: Use a tokenizer generator tool to create the file. You can then load it using a specific Git revision: Bumblebee.load_tokenizer({:hf, "model-repo", revision: "..."}).
  3. Integrate Bumblebee into a Phoenix LiveView application

    main

    Integrating Bumblebee tasks into an application follows a two-step pattern:

    1. Startup: On application startup, load the necessary models and preprocessors, build an instance of Nx.Serving, and start it under the application supervision tree.
    2. Inference: To make predictions from user input, use Nx.Serving.batched_run/2. It is highly recommended to wrap this call in a Task to avoid blocking other user interactions.

    Using Nx.Serving.batched_run/2 is critical because it automatically batches requests from concurrent users and distributes the results back to them transparently, improving throughput.

  4. Manage model data for deployments

    main

    By default, Bumblebee downloads model data from HuggingFace on the first run. To avoid downloading data during deployment, use one of these two strategies:

    1. Explicit local versioning

    Version model files alongside your repository (e.g., using Git LFS) or in object storage. Fetch them to a local directory during deployment. Change your loading calls from HuggingFace to local paths:

    # Instead of {:hf, "..."}
    Bumblebee.load_xyz({:local, "/path/to/model"})

    2. Cached from Hugging Face

    Control the cache directory using the BUMBLEBEE_CACHE_DIR environment variable. In Docker environments, you can populate this cache during the build stage:

    1. Define a function to load all models (e.g., MyApp.Servings.load_all/0).
    2. In your Dockerfile, run mix eval 'MyApp.Servings.load_all()' (or the equivalent for your release) to write models to the cache directory.
    3. Copy the BUMBLEBEE_CACHE_DIR contents to the final image.
    4. Set BUMBLEBEE_OFFLINE=true in the final image to ensure models are always loaded from the local cache.
    def load_all do
      Bumblebee.load_xyz({:hf, "microsoft/resnet"})
      Bumblebee.load_xyz({:hf, "foo/bar/baz"})
    end
  5. Install Bumblebee and EXLA

    main

    To use Bumblebee, add it and exla to your mix.exs dependencies. exla is highly recommended as it allows for just-in-time compilation and execution on CPU or GPU.

    To use GPUs, you must set the XLA_TARGET environment variable according to the XLA documentation.

    def deps do
      [
        {:bumblebee, "~> 0.6.0"},
        {:exla, ">= 0.0.0"}
      ]
    end
  6. Install Bumblebee in Notebooks or Scripts

    main

    In Livebook notebooks or standalone Elixir scripts, use Mix.install/2 to install both Bumblebee and EXLA, and to configure the Nx default backend in a single step.

    Mix.install(
      [
        {:bumblebee, "~> 0.6.0"},
        {:exla, ">= 0.0.0"}
      ],
      config: [nx: [default_backend: EXLA.Backend]]
    )
  7. Configure Nx and EXLA for optimal performance

    main

    For high-performance numerical computations, it is recommended to use EXLA. To prevent small, one-off operations (like data preparation) from competing with large neural network computations for GPU resources, follow this configuration pattern:

    1. Set the default backend to CPU: This ensures small operations like Nx.sum/1 run on the CPU.
      config :nx, :default_backend, {EXLA.Backend, client: :host}
    2. Use EXLA for model computations: Explicitly pass compiler: EXLA for expensive computations. When using Nx.Serving, pass compile: true and defn_options: [compiler: EXLA] during creation.
    3. Load parameters onto the GPU: To avoid the overhead of copying parameters from CPU to GPU every time a model runs, load them directly onto the GPU using the backend option in Bumblebee.load_model/2.
    4. Pre-compile shapes: Specify compile and defn_options in your serving to ensure computations are compiled upfront during boot.
    serving =
      Bumblebee.Text.text_embedding(model_info, tokenizer,
        compile: [batch_size: 1, sequence_length: 512],
        defn_options: [compiler: EXLA]
      )
  8. Optimize client-side image and audio processing

    main

    To reduce server load and network bandwidth, move preprocessing work to the client (browser) before sending data to the Bumblebee server:

    Images

    Instead of uploading full-resolution PNG/JPEG files, use the browser's Canvas API to:

    • Resize the image to the dimensions required by the Neural Network.
    • Decode the image into raw pixel values immediately.

    Audio

    Decoding audio on the server typically requires ffmpeg. To avoid this, use the client to:

    • Preprocess the audio.
    • Send raw PCM data with a single channel directly to the server.

    For real-time streaming requirements, consider using the Membrane Framework.

  9. What is a Featurizer in Bumblebee?

    main

    A featurizer is an abstraction used to convert raw data (such as text, images, or audio) into a format that a machine learning model can consume, typically a batched Nx.t or Nx.Container.t.

    Every featurizer module in Bumblebee implements the Bumblebee.Featurizer behaviour and is expected to define a configuration struct. The featurization process typically follows these stages:

    1. process_input/2: Converts a single raw input into a tensor.
    2. process_batch/2 (Optional): A numerical function that performs batch processing on the tensors produced by process_input/2. This stage is highly efficient when used with Nx.Serving, as it can be merged with the model computation and compiled together.
    3. batch_template/2 (Optional): Provides a template tensor of a specific batch size, used to prepare for batch processing.
  10. Configure Bumblebee progress bar settings

    main

    You can adjust how the progress bar behaves during model downloads in your application configuration.

    # Update every 10% instead of every 1%
    config :bumblebee, :progress_bar_step, 10
    
    # Disable progress bar entirely
    config :bumblebee, :progress_bar_enabled, false
  11. How PNDM sampling works

    main

    PNDM (Pseudo Numerical Methods for Diffusion Models) sampling relies on two numerical methods for solving ODEs: the Runge-Kutta (RK) method and the linear multi-step (LMS) method.

    Because the transfer part (approximating the next sample based on the current sample and gradient) is non-linear, these are referred to as 'pseudo' numerical methods (PRK and PLMS).

    Sampling Modes

    1. Standard (PRK + PLMS): Uses the Runge-Kutta method for the first few steps (to establish a gradient history) and then switches to the linear multi-step method. This typically requires at least 4 steps.
    2. Reduced Warmup (reduce_warmup: true): Uses lower-order linear multi-step for the initial samples instead of Runge-Kutta. This is more efficient as it requires fewer forward passes of the model. This requires at least 2 steps.
  12. How text generation and streaming work

    main

    Bumblebee's generation logic uses iterative inference (autoregression). For encoder-decoder models, the encoder is run once, and its state is reused across all decoding iterations.

    Streaming Hook Data

    If you use the streaming capability, the hook receives a map for each token generated. Each attribute is a tensor with a leading batch dimension:

    AttributeDescription
    :token_idThe newly generated token ID
    :finished?Boolean indicating if the sequence reached an EOS token or max length
    :lengthThe current length of the generated sequence (stops increasing once finished)