Model reference · open weights

Mini-InternVL2-DA-Medical

LLMs OpenGVLab Vision + text 1 build Open weights 7k dl/mo

Mini-InternVL2-DA-Medical is an open-weight language model from OpenGVLab. Mini-InternVL2-4B-DA-Medical (BF16) weighs 8.3 GB; the smallest configuration that runs it is RTX 4060 Ti 16 GB.

  • Mini-InternVL2-DA-Medical is a 4.1B parameter image-text-to-text model developed by OpenGVLab.
  • It is built upon Mini-InternVL and fine-tuned for the medical image domain using a unified adaptation framework.
  • The model supports multilingual inputs and is released under the MIT licence.

Summary of the OpenGVLab/Mini-InternVL2-4B-DA-Medical model card, 2026-10-01

What it is

Released byOpenGVLab
Released2024-12-07
Parameters4.1B
VRAM8.3 GB for the weights

What it runs on

Memory and cards for Mini-InternVL2-4B-DA-Medical (BF16)

8.3 GBweights, file size
393 MBcache per 1K tokens
1.9 GBruntime overhead, at least
131,072 tokenscontext max
CardRequests at onceContext maxMemory
8K each32K each
RTX 3060 12 GB——3K11.6 GB
RTX 4060 Ti 16 GB1—13K15.4 GB
RTX 3090 24 GB4132K23.4 GB
RTX 4090 24 GB4132K23.4 GB
RTX 5090 32 GB6151K31.0 GB
L40S 48 GB10283K44.0 GB
A100 80 GB215all 128K78.2 GB
H100 80 GB205all 128K78.1 GB
RTX PRO 6000 Blackwell 96 GB256all 128K93.8 GB
DGX Spark (GB10) 128 GB unified297all 128K107 GB
H200 141 GB389all 128K138 GB
B200 180 GB5012all 128K176 GB
2× RTX 3060 12 GB
tensor parallel
3—27K11.6 GB a card
2× RTX 4060 Ti 16 GB
tensor parallel
5146K15.4 GB a card
2× RTX 4090 24 GB
tensor parallel
10286K23.4 GB a card
2× RTX 3090 24 GB
tensor parallel
10286K23.4 GB a card
2× RTX 5090 32 GB
tensor parallel
153124K31.0 GB a card
Memory needed at each load
Requests at once8K tokens each32K tokens each
113.4 GB23.0 GB
526.3 GB74.6 GB
835.9 GB113 GB
1661.7 GB216 GB
32113 GB422 GB
64216 GB835 GB

One card, with vLLM's small-card settings.

From the model card

What OpenGVLab says about Mini-InternVL2-DA-Medical

Read the model card

[📂 GitHub] [🆕 Blog] [📜 Mini-InternVL] [📜 InternVL 1.0] [📜 InternVL 1.5] [📜 InternVL 2.5]

[🗨️ InternVL Chat Demo] [🤗 HF Demo] [🚀 Quick Start] [📖 中文解读] [📖 Documents]

Introduction

We release the adaptation models for the specific domains: autonomous driving, medical images, and remote sensing.

These models are built upon Mini-InternVL and fine-tuned using a unified adaptation framework, achieving good performance on tasks in specific domains.

The script for evaluation is in the document.

Training datasets

  • General domain dataset:

    ShareGPT4V, AllSeeingV2, LLaVA-Instruct-ZH, DVQA, ChartQA, AI2D, DocVQA, GeoQA+, SynthDoG-EN

  • Medicalt dataset:

    PMC-OA, MedICaT, Open-i, MedPix, Quilt-1M, RP3D, MIMIC-CXR, Retina Image Bank and others

Quick Start

We provide an example code to run Mini-InternVL2-4B using transformers.

Please use transformers>=4.37.2 to ensure the model works normally.

import numpy as np
import torch
import torchvision.transforms as T
from decord import VideoReader, cpu
from PIL import Image
from torchvision.transforms.functional import InterpolationMode
from transformers import AutoModel, AutoTokenizer

IMAGENET_MEAN = (0.485, 0.456, 0.406)
IMAGENET_STD = (0.229, 0.224, 0.225)

def build_transform(input_size):
    MEAN, STD = IMAGENET_MEAN, IMAGENET_STD
    transform = T.Compose([
        T.Lambda(lambda img: img.convert('RGB') if img.mode != 'RGB' else img),
        T.Resize((input_size, input_size), interpolation=InterpolationMode.BICUBIC),
        T.ToTensor(),
        T.Normalize(mean=MEAN, std=STD)
    ])
    return transform

def find_closest_aspect_ratio(aspect_ratio, target_ratios, width, height, image_size):
    best_ratio_diff = float('inf')
    best_ratio = (1, 1)
    area = width * height
    for ratio in target_ratios:
        target_aspect_ratio = ratio[0] / ratio[1]
        ratio_diff = abs(aspect_ratio - target_aspect_ratio)
        if ratio_diff < best_ratio_diff:
            best_ratio_diff = ratio_diff
            best_ratio = ratio
        elif ratio_diff == best_ratio_diff:
            if area > 0.5 * image_size * image_size * ratio[0] * ratio[1]:
                best_ratio = ratio
    return best_ratio

def dynamic_preprocess(image, min_num=1, max_num=12, image_size=448, use_thumbnail=False):
    orig_width, orig_height = image.size
    aspect_ratio = orig_width / orig_height

    # calculate the existing image aspect ratio
    target_ratios = set(
        (i, j) for n in range(min_num, max_num + 1) for i in range(1, n + 1) for j in range(1, n + 1) if
        i * j = min_num)
    target_ratios = sorted(target_ratios, key=lambda x: x[0] * x[1])

    # find the closest aspect ratio to the target
    target_aspect_ratio = find_closest_aspect_ratio(
        aspect_ratio, target_ratios, orig_width, orig_height, image_size)

    # calculate the target width and height
    target_width = image_size * target_aspect_ratio[0]
    target_height = image_size * target_aspect_ratio[1]
    blocks = target_aspect_ratio[0] * target_aspect_ratio[1]

    # resize the image
    resized_img = image.resize((target_width, target_height))
    processed_images = []
    for i in range(blocks):
        box = (
            (i % (target_width // image_size)) * image_size,
            (i // (target_width // image_size)) * image_size,
            ((i % (target_width // image_size)) + 1) * image_size,
            ((i // (target_width // image_size)) + 1) * image_size
        )
        # split the image
        split_img = resized_img.crop(box)
        processed_images.append(split_img)
    assert len(processed_images) == blocks
    if use_thumbnail and len(processed_images) != 1:
        thumbnail_img = image.resize((image_size, image_size))
        processed_images.append(thumbnail_img)
    return processed_images

def load_image(image_file, input_size=448, max_num=12):
    image = Image.open(image_file).convert('RGB')
    transform = build_transform(input_size=input_size)
    images = dynamic_preprocess(image, image_size=input_size, use_thumbnail=True, max_num=max_num)
    pixel_values = [transform(image) for image in images]
    pixel_values = torch.stack(pixel_values)
    return pixel_values

# If you want to load a model using multiple GPUs, please refer to the `Multiple GPUs` section.
path = 'OpenGVLab/Mini-InternVL2-4B-DA-Medical'
model = AutoModel.from_pretrained(
    path,
    torch_dtype=torch.bfloat16,
    low_cpu_mem_usage=True,
    use_flash_attn=True,
    trust_remote_code=True).eval().cuda()
tokenizer = AutoTokenizer.from_pretrained(path, trust_remote_code=True, use_fast=False)

# set the max number of tiles in `max_num`
pixel_values = load_image('path/to/image.jpg', max_num=12).to(torch.bfloat16).cuda()
generation_config = dict(max_new_tokens=1024, do_sample=True)

# pure-text conversation (纯文本对话)
question = 'Hello, who are you?'
response, history = model.chat(tokenizer, None, question, generation_config, history=None, return_history=True)
print(f'User: {question}\nAssistant: {response}')

question = 'Can you tell me a story?'
response, history = model.chat(tokenizer, None, question, generation_config, history=history, return_history=True)
print(f'User: {question}\nAssistant: {response}')

# single-image single-round conversation (单图单轮对话)
question = '\nPlease describe the image shortly.'
response = model.chat(tokenizer, pixel_values, question, generation_

Quoted from the model card on Hugging Face. The full card is behind the Hugging Face link above.

© 2026 AxForge · EU-hosted AI infrastructure Pricing Docs Trust Privacy Terms