DeepSeek 多模态模型

B站影视 2025-02-06 20:51 2

摘要:昨天还看到有人拉踩 deepseek v3 的时候说 deepseekv3 缺少多模态能力,除夕 deepseek 就发了 Janus-Pro, 一个7B 的多模态模型,可以进行多模态理解和生成。

昨天还看到有人拉踩 deepseek v3 的时候说 deepseekv3 缺少多模态能力,除夕 deepseek 就发了 Janus-Pro, 一个7B 的多模态模型,可以进行多模态理解和生成。

粗略看技术报告,本地也跑了一下模型,我认为 Janus 在技术上可能没有 DeepSeekV3 和 R1 那么猛,Janus-Pro同时支持理解和生成,不过自回归的范式更利于 VQA ,图像生成模型其实不适合直接对比Stable Diffusion、Flux等图像生成模型(虽然放了榜单,但是我实测感觉效果是略逊色的),Janus 是和 DALL 、TransFusion、show-o同一个赛道的,更侧重多模态交互能力,而非单独的视频生成。另外,这是个只有7B 的多模态模型,deepseekv3 团队用A100-40G训练的,挺“性价比”的。

本地默认运行的生成结果之一如图:

感慨一下,这个点儿发模型,真“春晚”啊,不过多模态模型相对比较熟悉,我也更感兴趣,还是伴随着爆竹声中加班写了这个技术报告解析。

前序工作

看 github 就可以发现,Janus-Pro有两个前序工作:Janus 和 JanusFlow

JanusFlow 是一个不太一样的架构,用了 Diffusion(rflow)进行图像的生成,后面单独写一个文章吧,本文不再多说。

Janus-Pro 和 Janus 相比,架构图和核心思路都没有换,那主要哪些地方 Pro 了呢?

主要体现在三个方面:训练策略优化、数据规模扩大和模型规模扩大

训练策略优化

Janus 模型结构

最核心的其实是图 3 这个这个训练策略图,看懂它就知道 Janus 这么做的了。

先看一下结构图包括的模块

两个 Encoder 用于图像信息处理 Und. Encoder:理解编码器,使用 SigLIP Gen. Encoder:生成编码器 (如 VQ tokenizer) 通常包含 特征提取 + 向量量化 (Vector Quantization) 。将图像转换为离散的视觉 tokens,以便 LLM 可以处理。Adaptor 用于将理解/生成编码器提取的图像特征映射到 LLM 的输入空间Und. Adaptor:用于将理解编码器提取的图像特征映射到 LLM 的输入空间。Gen. Adaptor:用于将生成编码器生成的离散图像 ID 的嵌入映射到 LLM 的输入空间LLM:在 Janus 是一个 1.5 B 的模型,Pro 则是有 1.5 B 和 7B 两个版本Head:同样包括两个Text Head:用于文本理解和多模态理解任务中的文本预测Image Head:用于视觉生成任务中的图像预测Decoder:图3中没画,Image Deocder:用来将 Head 预测的离散 tokens 转换为图像输出Text De-Tokenizer :用来转换为文本输出

Janus 训练策略

Janus 模型采用了一种三阶段的训练策略,旨在分别优化模型的不同能力:

第一阶段:训练Adaptor和图像Head (Stage I)

在 LLM 参数固定的情况下,对齐视觉和文本模态,使模型能够初步理解图像内容并进行简单的图像生成冻结视觉编码器和 LLM 的参数,只更新理解适配器 (Understanding Adaptor)、生成适配器 (Generation Adaptor) 和图像头的可训练参数。使用包含 125 万个图像-文本配对字幕的数据集 (ShareGPT4V) 用于多模态理解,以及来自 ImageNet-1k 的大约 120 万个样本用于视觉生成。

第二阶段:统一预训练 (Stage II)

学习多模态理解和生成能力在 Stage1 的基础上,进一步解冻 LLM和 Text Head。先使用 ImageNet-1k 进行简单的视觉生成训练,帮助模型学习像素关系。受Pixar启发,Janus先用 ImageNet-1 k进行简单的视觉生成训练,以帮助模型掌握基本的像素依赖关系。再使用通用的文本到图像数据增强模型的开放域视觉生成能力。使用所有类型的训练数据:纯文本数据:来自 DeepSeek-LLM 的预训练文本语料库。图像-文本数据:来自 Wiki-How 和 WIT 数据集。图像-caption 数据:来自各种数据集的图像,并使用开源多模态模型重新标注的标题5。数据格式为问题-答案对,例如 " 详细描述图像。" 表格和图表数据:来自 DeepSeek-VL 的相应表格和图表数据5。数据格式为 ""。视觉生成数据:包括图像-标题对,整合并筛选了多个数据集的数据,格式为 ""。在训练过程中,有25%的概率只使用Cpation的第一句话,以训练模型强大的简短描述生成能力。

第三阶段:有监督微调 SFT (Stage III)

使用指令调优数据对预训练模型进行微调,微调除生成编码器外的所有模块参数专注于监督答案,同时屏蔽系统和用户提示。为了确保Janus在多模态理解和生成方面的熟练程度,我们不会为特定任务微调单独的模型。相反,我们使用纯文本对话数据,多模态理解数据和视觉生成数据的混合,确保各种场景的通用性。

每个阶段的数据集组织方式在论文 4.2 中有详细介绍。

存在的问题

在第二阶段 (Stage II) 中,将大部分训练分配给 ImageNet 数据,导致计算效率低下,且效果不佳

The previous version of Janus employs a three-stage training process. Stage I focuses on training the adaptors and the image head. Stage II handles unified pretraining, during which all components except the understanding encoder and the generation encoder has their parameters updated. Stage III is supervised fine-tuning, building upon Stage II by further unlocking the parameters of the understanding encoder during training. This training strategy has certain issues. In Stage II, Janus divides the training for text-to-image capabilities into two parts following PixArt [4]. The first part trains on ImageNet [9] data, using image category names as prompts for text-to-image generation, with the goal of modeling pixel dependence. The second part trains on normal text-to-image data. During implementation, 66.67% of the text-to-image training steps in Stage II are allocated to the first part. However, through further experimentation, we find that this strategy is suboptimal and lead to significant computational inefficiency.

Pro 的改进

延长第一阶段训练时间:增加 Stage I 的训练步骤,即使在 LLM 参数固定的情况下,模型也能有效建模像素依赖性,并根据类别名称生成图像。改进第二阶段训练重点:放弃在 ImageNet 数据集上的训练,直接使用正常的文本到图像数据训练,使模型能够根据详细文本描述生成图像,提高了训练效率和整体性能。调整第三阶段数据比例:将多模态数据、纯文本数据和文本到图像数据的比例从 7:3:10 更改为 5:1:4,通过稍微降低文本到图像数据的比例,可以在保持强大的视觉生成能力的同时,提高多模态理解性能代码

官方的 demo 写的很清晰,很容易看懂流程。

from transformers import AutoModelForCausalLMfrom janus.models import MultiModalityCausalLM, VLChatProcessor# specify the path to the modelmodel_path = "deepseek-ai/Janus-Pro-7B"vl_chat_processor: VLChatProcessor = VLChatProcessor.from_pretrained(model_path)tokenizer = vl_chat_processor.tokenizervl_gpt: MultiModalityCausalLM = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True)vl_gpt = vl_gpt.to(torch.bfloat16).cuda.evalconversation = [{"role": "","content": "A stunning princess from kabul in red, white traditional clothing, blue eyes, brown hair",},{"role": "", "content": ""},]sft_format = vl_chat_processor.apply_sft_template_for_multi_turn_prompts(conversations=conversation,sft_format=vl_chat_processor.sft_format,system_prompt="",)prompt = sft_format + vl_chat_processor.image_start_tag@torch.inference_modedef generate(mmgpt: MultiModalityCausalLM,vl_chat_processor: VLChatProcessor,prompt: str,temperature: float = 1,parallel_size: int = 16,cfg_weight: float = 5,image_token_num_per_image: int = 576,img_size: int = 384,patch_size: int = 16,):input_ids = vl_chat_processor.tokenizer.encode(prompt)# print("input_ids :",len(linput_ids))input_ids = torch.LongTensor(input_ids)tokens = torch.zeros((parallel_size*2, len(input_ids)), dtype=torch.int).cudafor i in range(parallel_size*2):tokens[i, :] = input_idsif i % 2 != 0:tokens[i, 1:-1] = vl_chat_processor.pad_idprint("tokens :",tokens.shape)inputs_embeds = mmgpt.language_model.get_input_embeddings(tokens)print("inputs_embeds :",inputs_embeds.shape)generated_tokens = torch.zeros((parallel_size, image_token_num_per_image), dtype=torch.int).cudafor i in range(image_token_num_per_image):outputs = mmgpt.language_model.model(inputs_embeds=inputs_embeds, use_cache=True, past_key_values=outputs.past_key_values if i != 0 else None)hidden_states = outputs.last_hidden_statelogits = mmgpt.gen_head(hidden_states[:, -1, :])logit_cond = logits[0::2, :]logit_uncond = logits[1::2, :]logits = logit_uncond + cfg_weight * (logit_cond-logit_uncond)probs = torch.softmax(logits / temperature, dim=-1)next_token = torch.multinomial(probs, num_samples=1)generated_tokens[:, i] = next_token.squeeze(dim=-1)next_token = torch.cat([next_token.unsqueeze(dim=1), next_token.unsqueeze(dim=1)], dim=1).view(-1)img_embeds = mmgpt.prepare_gen_img_embeds(next_token)inputs_embeds = img_embeds.unsqueeze(dim=1)print("generated_tokens : ",generated_tokens.shape)dec = mmgpt.gen_vision_model.decode_code(generated_tokens.to(dtype=torch.int), shape=[parallel_size, 8, img_size//patch_size, img_size//patch_size])dec = dec.to(torch.float32).cpu.numpy.transpose(0, 2, 3, 1)dec = np.clip((dec + 1) / 2 * 255, 0, 255)visual_img = np.zeros((parallel_size, img_size, img_size, 3), dtype=np.uint8)visual_img[:, :, :] = decos.makedirs('generated_samples', exist_ok=True)for i in range(parallel_size):save_path = os.path.join('generated_samples', "img_{}.jpg".format(i))PIL.Image.fromarray(visual_img[i]).save(save_path)generate(vl_gpt,vl_chat_processor,prompt,)数据 Scaling多模态理解数据:在第二阶段预训练数据中,增加了约 9000 万个样本,包括图像标题数据集、表格、图表和文档理解数据。在第三阶段的SFT数据中,增加了来自 DeepSeek-VL2 的数据集,如 MEME 理解、中文对话数据等,以增强模型的对话体验。视觉生成数据:引入约 7200 万个合成的美学数据样本,使得统一预训练阶段的真实数据与合成数据比例达到 1:1,提升文本到图像生成质量模型 Scaling

Janus使用1.5B LLM验证了视觉编码解耦的有效性,在Janus-Pro中将模型扩展到1.5B和7 B,当使用较大规模的LLM时,与较小的模型相比,多模态理解和视觉生成的损失的收敛速度显著提高。

实验

实验细节

基础语言模型 (Base Language Model):Janus-Pro 实验使用了 DeepSeek-LLM (1.5B 和 7B)作为基础语言模型,这是一个最大支持 4096 个 token 序列长度的模型。视觉编码器 (Vision Encoder):在理解任务中,使用了 SigLIP-Large-Patch16-384 作为视觉编码器。生成编码器的codebook 大小为 16,384 ,将图像下采样 16 倍,用于将图像转换为离散的 ID。适配器 (Adaptors):理解适配器 (Understanding Adaptor) 和生成适配器 (Generation Adaptor) 都是两层的 MLP。图像处理 (Image Processing):所有图像都被调整大小为 384 × 384 像素。对于多模态理解数据,图像的长边被调整大小,短边用背景颜色(RGB:127, 127, 127)填充到 384。对于视觉生成数据,短边被调整大小为 384,长边被裁剪到 384。训练数据处理 (Training Data Handling):在训练过程中使用sequence packing 来提高训练效率。将所有数据类型按照指定的比例混合在单个训练步骤中。训练框架 (Training Framework):Janus 模型是使用 HAI-LLM 进行训练和评估.训练资源 (Training Resources):每个node 8 个 Nvidia A100 (40GB) GPU。1.5B 参数模型在 16 个 node 训练大约需要 7 天。7B 参数模型在 32 个 node 训练大约需要 14 天。详细超参

定量评测

可视化评测

来源:搭配灵感盒

相关推荐