UForm Multimodal AI Library

repository·main·Indexed 23 days ago

https://github.com/unum-cloud/uform

A multimodal AI library for content understanding (embeddings) and generation (chat, captioning, VQA). UForm provides pocket-sized models designed for portability across servers and mobile devices using ONNX, CoreML, and PyTorch. It includes JavaScript and Python SDKs for generating text and image embeddings, and its generative models are compatible with the Hugging Face transformers library.

Tokens
10.2K
Snippets
27
Records
46
Agent score
79%

What's inside UForm

  1. Optimize large-scale search performance

    main

    For large-scale search applications, native JavaScript may be too slow. To improve performance:

    1. Down-cast embeddings: Convert embeddings to smaller numeric representations to reduce memory and computation without significant loss in recall.
    2. Use specialized libraries: For high-performance vector search, integrate with libraries like USearch or SimSimD.
  2. Optimize embeddings via down-casting and quantization

    main

    To reduce memory usage and increase speed, you can convert embeddings into smaller numeric representations.

    • f16 (Half-precision): Recommended in almost all cases for a ~2x speedup with minimal accuracy loss, unless using very old hardware.
    • i8 (Integer 8-bit): Possible via linear scaling, but may impact recall on very large collections (millions of entries).
    • b1 (Binary): Quantizing high-dimensional embeddings (512 or 768) into single-bit representations for faster search.

    Note: These approaches are natively supported by the USearch vector-search engine and SimSIMD numerics libraries.

    import numpy as np
    
    f32_embedding: np.ndarray = model.encode_text(text_data, return_features=False)
    f16_embedding: np.ndarray = f32_embedding.astype(np.float16)
    i8_embedding: np.ndarray = (f32_embedding * 127).astype(np.int8)
    b1_embedding: np.ndarray = np.packbits((f32_embedding > 0).astype(np.uint8))
  3. Optimize performance by choosing computeUnits

    main

    When initializing encoders, you can specify computeUnits to control which Apple hardware is used. While .all is the default for maximum compatibility, explicitly targeting the Apple Neural Engine (ANE) can significantly improve performance, especially for quantized models.

    Performance Comparison (Median Latency on M4 iPad):

    ModelGPU Text E.ANE Text E.GPU Image E.ANE Image E.
    english-small2.53 ms0.53 ms6.57 ms1.23 ms
    english-base2.54 ms0.61 ms18.90 ms3.79 ms
    english-large2.30 ms0.61 ms79.68 ms20.94 ms
    multilingual-base2.34 ms0.50 ms18.98 ms3.77 ms

    Note: Quantized encoders use a mixture of i8, f16, and f32 and rely heavily on the ANE for performance.

  4. Use Matryoshka embeddings for hierarchical search

    main

    Matryoshka embeddings allow you to slice large embeddings into smaller parts, enabling hierarchical search strategies. This is an alternative to standard quantization.

    import numpy as np
    
    large_embedding: np.ndarray = model.encode_text(text_data, return_features=False)
    small_embedding: np.ndarray = large_embedding[:, :256]
    tiny_embedding: np.ndarray = large_embedding[:, :64]
  5. Quick Start: Using Embedding Models

    main

    UForm embedding models allow you to understand and search visual and textual content. You can load a model using get_model, which returns both processors and models for different modalities (TEXT and IMAGE). By default, it uses dtype='bfloat16' for approximately 2x speedup with minimal accuracy loss.

    from uform import get_model, Modality
    
    # Load the model and processors
    processors, models = get_model('unum-cloud/uform3-image-text-english-small', device='cuda')
    
    # Access specific encoders and processors
    model_text = models[Modality.TEXT_ENCODER]
    model_image = models[Modality.IMAGE_ENCODER]
    processor_text = processors[Modality.TEXT_ENCODER]
    processor_image = processors[Modality.IMAGE_ENCODER]
  6. Enable Multi-GPU Parallelism with PyTorch

    main

    To increase throughput, wrap the model encoders in torch.nn.DataParallel.

    Important Notes:

    1. Set model.return_features = False on the original models before wrapping.
    2. When using the DataParallel wrapper, you must use the .forward() method instead of .encode().
    3. Use .detach().cpu().numpy() to convert the resulting tensors back into NumPy arrays.
    from uform import get_model, Modality
    import torch.nn as nn
    
    # Load model
    processors, models = get_model('unum-cloud/uform-vl-english-small', backend='torch')
    
    model_text = models[Modality.TEXT_ENCODER]
    model_image = models[Modality.IMAGE_ENCODER]
    processor_text = processors[Modality.TEXT_ENCODER]
    processor_image = processors[Modality.IMAGE_ENCODER]
    
    # Prepare for parallel
    model_text.return_features = False
    model_image.return_features = False
    model_text_parallel = nn.DataParallel(model_text)
    model_image_parallel = nn.DataParallel(model_image)
    
    # Usage pattern
    def get_image_embedding(images):
        preprocessed = processor_image(images)
        embedding = model_image_parallel.forward(preprocessed)
        return embedding.detach().cpu().numpy()
  7. Reduce deployment size using ONNX runtime

    main

    To avoid the heavy PyTorch dependency (which can be ~5.2GB), you can install UForm with the ONNX runtime. This significantly reduces memory consumption and deployment latency, often bringing the total weight down to ~100MB for both model and runtime.

    Supported ONNX execution providers include:

    • XNNPACK
    • CUDA and TensorRT (Nvidia GPUs)
    • OpenVINO (Intel)
    • DirectML (Windows)
    • ROCm (AMD)
    • CoreML (Apple)
    # Install with Torch dependency
    $ conda create -n uform_torch python=3.10 -y
    $ conda activate uform_torch && pip install -e ".[torch]" && conda deactivate
    
    # Install with ONNX runtime (lighter weight)
    $ conda create -n uform_onnx python=3.10 -y
    $ conda activate uform_onnx && pip install -e ".[onnx]" && conda deactivate
  8. Install the UForm Swift SDK

    main

    To use UForm in your Swift project, add it via Swift Package Manager.

    1. Initialize your package (if starting from scratch):
    swift package init --type executable
    1. Add the UForm dependency:
    swift package add uform
    1. Import the module in your Swift files:
    import UForm
    swift package init --type executable
    swift package add uform
  9. Quick Start: Using Generative Models

    main

    UForm generative models are designed for Chat, Image Captioning, and Visual Question Answering (VQA). They are natively compatible with the transformers library. You can load them using AutoModel and AutoProcessor with trust_remote_code=True.

    from transformers import AutoModel, AutoProcessor
    import torch
    from PIL import Image
    
    model = AutoModel.from_pretrained('unum-cloud/uform-gen2-dpo', trust_remote_code=True)
    processor = AutoProcessor.from_pretrained('unum-cloud/uform-gen2-dpo', trust_remote_code=True)
    
    prompt = 'Question or Instruction'
    image = Image.open('image.jpg')
    
    inputs = processor(text=[prompt], images=[image], return_tensors='pt')
    
    with torch.inference_mode():
         output = model.generate(
            **inputs,
            do_sample=False,
            use_cache=True,
            max_new_tokens=256,
            eos_token_id=151645,
            pad_token_id=processor.tokenizer.pad_token_id
        )
    
    prompt_len = inputs['input_ids'].shape[1]
    decoded_text = processor.batch_decode(output[:, prompt_len:])[0]
  10. Configure ONNX with CUDA and TensorRT

    main

    When using CUDA 12 or newer with ONNX backends, you must install the Nvidia toolkit and the specific onnxruntime-gpu package from the custom repository.

    Follow these steps to set up the environment:

    1. Install the Nvidia CUDA keyring and toolkit.
    2. Install onnxruntime-gpu using the specific extra index URL.
    3. Export CUDA_PATH, PATH, and LD_LIBRARY_PATH to point to your CUDA installation.
    wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb
    sudo dpkg -i cuda-keyring_1.1-1_all.deb
    sudo apt-get update
    sudo apt-get -y install cuda-toolkit-12
    pip install onnxruntime-gpu --extra-index-url https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/onnxruntime-cuda-12/pypi/simple/
    export CUDA_PATH="/usr/local/cuda-12/bin"
    export PATH="/usr/local/cuda-12/bin${PATH:+:${PATH}}"
    export LD_LIBRARY_PATH="/usr/local/cuda-12/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"