Selon l'équipe de recherche de NVIDIA, le nouveau modèle d'IA excelle dans les tâches de vision-langage tout en maintenant et même en améliorant les performances en texte seul par rapport à leurs LLM de base. Dans leur article, les chercheurs déclarent : « Nous présentons le NVLM 1.0, une famille de grands modèles de langage multimodaux d'avant garde qui obtiennent des résultats de pointe dans les tâches de vision-langage, rivalisant avec les principaux modèles propriétaires (par exemple, GPT-4o) et les modèles en libre accès. »
Contrairement à d'autres modèles propriétaires dont les performances textuelles diminuent considérablement avec le temps, le modèle NVLM-D-72B a augmenté sa précision de 4,3 points en moyenne sur les principaux benchmarks textuels.
Le LLM a également été capable d'interpréter des graphiques et des tableaux, d'analyser des images, de comprendre des mèmes, de coder des logiciels et de résoudre des problèmes mathématiques. Les poids du modèle sont accessibles au public sur Hugging Face et NVIDIA indique qu'elle publiera ultérieurement le code d'entraînement.
Détails du modèle
Le 17 septembre 2024, NVIDIA a présenté le NVLM 1.0, une famille de grands modèles de langage (LLM) multimodaux d'avant-garde qui obtiennent des résultats de pointe sur les tâches vision-langage, rivalisant avec les principaux modèles propriétaires (par exemple, GPT-4o) et les modèles en accès libre (par exemple, Llama 3-V 405B et InternVL 2). Fait remarquable, le NVLM 1.0 présente des performances améliorées pour le texte seul par rapport à son homologue LLM après une formation multimodale.
En termes de conception de modèle, NVIDIA a effectué une comparaison complète entre les LLM multimodaux à décodeur uniquement (par exemple, LLaVA) et les modèles basés sur l'attention croisée (par exemple, Flamingo). En se basant sur les forces et les faiblesses des deux approches, NVIDIA a proposé une nouvelle architecture qui améliore à la fois l'efficacité de l'entraînement et les capacités de raisonnement multimodal.
En outre, NVIDIA a introduit une conception 1-D tile-tagging pour les images à haute résolution dynamique à base de tuiles, ce qui améliore considérablement les performances sur le raisonnement multimodal et les tâches liées à la reconnaissance optique des caractères (OCR).
En ce qui concerne les données d'entraînement, NVIDIA a méticuleusement préparé et fourni des informations détaillées sur ses ensembles de données multimodales de pré-entraînement et de mise au point supervisée. Leurs conclusions indiquent que la qualité des ensembles de données et la diversité des tâches sont plus importantes que l'échelle, même pendant la phase de pré-entraînement, sur toutes les architectures. Ils ont notamment développé une multimodalité de niveau production pour les modèles NVLM-1.0, leur permettant d'exceller dans les tâches de vision et de langage tout en maintenant et même en améliorant les performances pour le texte seul par rapport à leurs modèles LLM.
Pour y parvenir, NVIDIA a conçu et intégré un ensemble de données textuelles de haute qualité dans la formation multimodale, ainsi qu'une quantité substantielle de données mathématiques et de raisonnement multimodales, ce qui a permis d'améliorer les capacités mathématiques et de codage dans les différents modes.
Pour faire avancer la recherche dans ce domaine, NVIDIA a publié les poids du modèle et ouvrira le code à la communauté : https://nvlm-project.github.io/. Le modèle NVLM-1.0-D-72B (architecture à décodeur uniquement), les poids du modèle à décodeur uniquement et le code sont également mis à la disposition de la communauté sur Hugging Face.
Résultats des tests de référence
NVIDIA a formé son modèle avec l'ancien Megatron-LM et a adapté la base de code à Huggingface pour l'hébergement du modèle, la reproductibilité et l'inférence. NVIDIA a observé des différences numériques entre les bases de code Megatron et Huggingface, qui se situent dans la fourchette de variation attendue. Les résultats de la base de code Huggingface et de la base de code Megatron sont fournis à des fins de reproductibilité et de comparaison avec d'autres modèles.
Les résultats (au 17 septembre 2024) dans les benchmarks multimodaux sont les suivants :
Comment l'utiliser
Lors de la conversion du point de contrôle Megatron en Huggingface, la base de code InternVL est adaptée pour supporter le chargement du modèle et l'inférence multi-GPU dans HF. Pour la formation, il faut se référer à Megatron-LM (bientôt disponible).
Préparer l'environnement
Un fichier de construction Docker est fourni dans le Dockerfile pour la reproduction.
L'image docker est basée sur nvcr.io/nvidia/pytorch:23.09-py3.
Note : Nous observons que différentes versions de transformateur / versions CUDA / versions de docker peuvent conduire à de légères différences dans les numéros de référence. Il est recommandé d'utiliser le Dockerfile ci-dessus pour une reproduction précise.
Chargement du modèle
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | 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() |
Plusieurs GPU
Le modèle peut être chargé sur plusieurs GPU comme suit :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | import torch import math from transformers import AutoModel def split_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 = 0 for i, num_layer in enumerate(num_layers_per_gpu): for j in range(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}'] = 0 return 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() |
Inférence
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | import torch from transformers import AutoTokenizer, AutoModel import math from PIL import Image import torchvision.transforms as T from torchvision.transforms.functional import InterpolationMode def split_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 = 0 for i, num_layer in enumerate(num_layers_per_gpu): for j in range(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}'] = 0 return device_map 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 <= 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 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 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}') |
Licence
L'utilisation de ce modèle est régie par la licence cc-by-nc-4.0
Source : "NVLM: Open Frontier-Class Multimodal LLMs" (NVIDIA)
Et vous ?
Quel est votre avis sur le sujet ?
Que pensez-vous des performances de cette famille de modèles d'IA de NVIDIA ?
Trouvez-vous les résultats de cette étude crédibles ou pertinents ?
Avez-vous utilisé cet outil ou un outil similaire pour votre usage ou le développement d'applications, et si oui, qu'en pensez-vous ?
Voir aussi :
Mistral AI et NVIDIA dévoilent Mistral NeMo 12B, un modèle d'IA d'entreprise que les développeurs peuvent personnaliser et déployer pour des applications prenant en charge les chatbots et autres tâches
ChatRTX, le chatbot IA expérimental de Nvidia, prend en charge davantage de modèles d'IA comme Gemma de Google, les requêtes vocales, et fonctionne localement sur un PC Windows équipé d'un GPU RTX
NVIDIA introduit l'IA dans le monde physique à la CVPR, avec NVIDIA Omniverse Cloud Sensor RTX, un nouvel ensemble de microservices, et JeDi qui simplifie la génération d'images personnalisées