Today (September 17th, 2024), we introduce
NVLM 1.0
, a family of frontier-class multimodal large language models (LLMs) that achieve state-of-the-art results on vision-language tasks, rivaling the leading proprietary models (e.g., GPT-4o) and open-access models (e.g., Llama 3-V 405B and InternVL 2). Remarkably, NVLM 1.0 shows improved text-only performance over its LLM backbone after multimodal training.
In this repo, we are open-sourcing NVLM-1.0-D-72B (decoder-only architecture), the decoder-only model weights and code for the community.
We train our model with legacy
Megatron-LM
and adapt the codebase to Huggingface for model hosting, reproducibility, and inference.
We observe numerical differences between the Megatron and Huggingface codebases, which are within the expected range of variation.
We provide the results from both the Huggingface codebase and the Megatron codebase for reproducibility and comparison with other models.
Results (as of September 17th, 2024) in the multimodal benchmarks are as follows:
Benchmark
MMMU (val / test)
MathVista
OCRBench
AI2D
ChartQA
DocVQA
TextVQA
RealWorldQA
VQAv2
NVLM-D 1.0 72B (Huggingface)
58.7 / 54.9
65.2
852
94.2
86.0
92.6
82.6
69.5
85.4
NVLM-D 1.0 72B (Megatron)
59.7 / 54.6
65.2
853
94.2
86.0
92.6
82.1
69.7
85.4
Llama 3.2 90B
60.3 / -
57.3
-
92.3
85.5
90.1
-
-
78.1
Llama 3-V 70B
60.6 / -
-
-
93.0
83.2
92.2
83.4
-
79.1
Llama 3-V 405B
64.5 / -
-
-
94.1
85.8
92.6
84.8
-
80.2
InternVL2-Llama3-76B
55.2 / -
65.5
839
94.8
88.4
94.1
84.4
72.2
-
GPT-4V
56.8 / 55.7
49.9
645
78.2
78.5
88.4
78.0
61.4
77.2
GPT-4o
69.1 / -
63.8
736
94.2
85.7
92.8
-
-
-
Claude 3.5 Sonnet
68.3 / -
67.7
788
94.7
90.8
95.2
-
-
-
Gemini 1.5 Pro (Aug 2024)
62.2 / -
63.9
754
94.4
87.2
93.1
78.7
70.4
80.2
How to use
When converting Megatron checkpoint to Huggingface, we adapt
InternVL codebase
to support model loading and multi-GPU inference in HF. For training, please refer to
Megatron-LM (Coming soon)
.
Prepare the environment
We provide a docker build file in the
Dockerfile
for reproduction.
The docker image is based on
nvcr.io/nvidia/pytorch:23.09-py3
.
Note: We observe that different transformer versions / CUDA versions / docker versions can lead to slight benchmark number differences. We recommend using the Dockerfile above for precise reproduction.
Model loading
import torch
from transformers import AutoModel
path = "nvidia/NVLM-D-72B"
model = AutoModel.from_pretrained(
path,
torch_dtype=torch.bfloat16,
low_cpu_mem_usage=True,
use_flash_attn=False,
trust_remote_code=True).eval()
Multiple GPUs
The model can be loaded on multiple GPUs as follows:
import torch
import math
from transformers import AutoModel
defsplit_model():
device_map = {}
world_size = torch.cuda.device_count()
num_layers = 80# Since the first GPU will be used for ViT, treat it as half a GPU.
num_layers_per_gpu = math.ceil(num_layers / (world_size - 0.5))
num_layers_per_gpu = [num_layers_per_gpu] * world_size
num_layers_per_gpu[0] = math.ceil(num_layers_per_gpu[0] * 0.5)
layer_cnt = 0for i, num_layer inenumerate(num_layers_per_gpu):
for j inrange(num_layer):
device_map[f'language_model.model.layers.{layer_cnt}'] = i
layer_cnt += 1
device_map['vision_model'] = 0
device_map['mlp1'] = 0
device_map['language_model.model.tok_embeddings'] = 0
device_map['language_model.model.embed_tokens'] = 0
device_map['language_model.output'] = 0
device_map['language_model.model.norm'] = 0
device_map['language_model.lm_head'] = 0
device_map[f'language_model.model.layers.{num_layers - 1}'] = 0return device_map
path = "nvidia/NVLM-D-72B"
device_map = split_model()
model = AutoModel.from_pretrained(
path,
torch_dtype=torch.bfloat16,
low_cpu_mem_usage=True,
use_flash_attn=False,
trust_remote_code=True,
device_map=device_map).eval()
Inference
import torch
from transformers import AutoTokenizer, AutoModel
import math
from PIL import Image
import torchvision.transforms as T
from torchvision.transforms.functional import InterpolationMode
defsplit_model():
device_map = {}
world_size = torch.cuda.device_count()
num_layers = 80# Since the first GPU will be used for ViT, treat it as half a GPU.
num_layers_per_gpu = math.ceil(num_layers / (world_size - 0.5))
num_layers_per_gpu = [num_layers_per_gpu] * world_size
num_layers_per_gpu[0] = math.ceil(num_layers_per_gpu[0] * 0.5)
layer_cnt = 0for i, num_layer inenumerate(num_layers_per_gpu):
for j inrange(num_layer):
device_map[f'language_model.model.layers.{layer_cnt}'] = i
layer_cnt += 1
device_map['vision_model'] = 0
device_map['mlp1'] = 0
device_map['language_model.model.tok_embeddings'] = 0
device_map['language_model.model.embed_tokens'] = 0
device_map['language_model.output'] = 0
device_map['language_model.model.norm'] = 0
device_map['language_model.lm_head'] = 0
device_map[f'language_model.model.layers.{num_layers - 1}'] = 0return device_map
IMAGENET_MEAN = (0.485, 0.456, 0.406)
IMAGENET_STD = (0.229, 0.224, 0.225)
defbuild_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
deffind_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
defdynamic_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 inrange(min_num, max_num + 1) for i inrange(1, n + 1) for j inrange(1, n + 1) if
i * j <= max_num and 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 inrange(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)
assertlen(processed_images) == blocks
if use_thumbnail andlen(processed_images) != 1:
thumbnail_img = image.resize((image_size, image_size))
processed_images.append(thumbnail_img)
return processed_images
defload_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
path = "nvidia/NVLM-D-72B"
device_map = split_model()
model = AutoModel.from_pretrained(
path,
torch_dtype=torch.bfloat16,
low_cpu_mem_usage=True,
use_flash_attn=False,
trust_remote_code=True,
device_map=device_map).eval()
print(model)
tokenizer = AutoTokenizer.from_pretrained(path, trust_remote_code=True, use_fast=False)
generation_config = dict(max_new_tokens=1024, do_sample=False)
# 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}')
# single-image single-round conversation
pixel_values = load_image('path/to/your/example/image.jpg', max_num=6).to(
torch.bfloat16)
question = '<image>\nPlease describe the image shortly.'
response = model.chat(tokenizer, pixel_values, question, generation_config)
print(f'User: {question}\nAssistant: {response}')
@article{nvlm2024,
title={NVLM: Open Frontier-Class Multimodal LLMs},
author={Dai, Wenliang and Lee, Nayeon and Wang, Boxin and Yang, Zhuolin and Liu, Zihan and Barker, Jon and Rintamaki, Tuomas and Shoeybi, Mohammad and Catanzaro, Bryan and Ping, Wei},
journal={arXiv preprint},
year={2024}}
NVLM-D-72B huggingface.co is an AI model on huggingface.co that provides NVLM-D-72B's model effect (), which can be used instantly with this nvidia NVLM-D-72B model. huggingface.co supports a free trial of the NVLM-D-72B model, and also provides paid use of the NVLM-D-72B. Support call NVLM-D-72B model through api, including Node.js, Python, http.
NVLM-D-72B huggingface.co is an online trial and call api platform, which integrates NVLM-D-72B's modeling effects, including api services, and provides a free online trial of NVLM-D-72B, you can try NVLM-D-72B online for free by clicking the link below.
nvidia NVLM-D-72B online free url in huggingface.co:
NVLM-D-72B is an open source model from GitHub that offers a free installation service, and any user can find NVLM-D-72B on GitHub to install. At the same time, huggingface.co provides the effect of NVLM-D-72B install, users can directly use NVLM-D-72B installed effect in huggingface.co for debugging and trial. It also supports api for free installation.