简介:这是一份面向零基础学习者的多模态AI入门PPT笔记,专为科研人员与开发者设计,系统梳理从Transformer基础到前沿多模态模型的核心脉络。内容覆盖ViT图像编码机制、CLIP图文对齐原理、BLIP/BLIP2图文生成与理解、Flamingo与MiniCPM-V等架构演进,并配套代码实现细节与动手实验指南,助力读者打通理论—代码—实践闭环。资源为单文件PDF格式,共1个4.39MB的高清学习文档,结构清晰,含Preliminary、ViT、CLIP、BLIP系列、动手实验等8大模块,每部分均融合原理图解、关键公式、PyTorch代码片段及训练流程说明。目前已有2233人学习下载,适合希望在有限时间内建立多模态知识框架、快速上手主流模型并开展实验验证的初学者。
1. 多模态不是“AI杂技”,而是让机器像人一样看图说话的入门钥匙
你有没有试过给朋友发一张照片,配一句“这顿饭我吃了半小时,但快乐值拉满”,对方秒懂——图里是热腾腾的火锅、冒泡的啤酒、你笑出眼角纹的脸?人脑天生就能把图像、文字、甚至语气(“拉满”这种夸张说法)自动对齐、互相解释。而传统AI不是这样:一个模型只认图(比如识别猫狗),另一个只读字(比如判断这句话是夸还是骂),它们之间像隔着一堵墙,谁也不懂谁在说什么。多模态学习,就是亲手拆掉这堵墙的第一把锤子。
它不教AI“同时做两件事”,而是教它建立图像和文字之间的“共同语言”——比如让一张“金毛犬叼飞盘”的图,在AI心里自动对应“活泼”“户外”“运动”这些词;反过来,当你输入“一只湿漉漉的柴犬站在雨里”,AI能立刻生成或找到最匹配的图。这份《零基础入门多模态学习PPT》就是专为“第一次听说ViT、CLIP、BLIP”这类名字的新手准备的:它不从论文公式开始,而是用切片面包(ViT)、双语词典(CLIP)、图文翻译官(BLIP)这些你能摸得着的比喻,带你亲手跑通第一个“看图说句话”的小实验。适合完全没碰过PyTorch、连transformer是函数还是变形金刚都分不清的你——只要你会装Python、能敲几行命令,今天就能让电脑第一次“看懂”你的照片。
2. 先搞懂一个概念:ViT不是“把图片当文字喂给Transformer”,而是给图像造了一套新字母表
ViT(Vision Transformer)常被简化成“把图片切成小块,当单词喂给Transformer”。这话没错,但容易让你误以为只要调个库、改个参数就能跑通。其实真正的门槛在于:ViT不是在复用NLP的现成字母表,而是为图像重新发明了一套“视觉字母”(patch tokens),并教会Transformer用这套字母写“图像句子”。理解这点,你才能避开后续所有模型的底层逻辑陷阱。我们用一张224×224的猫图来拆解这个“造字母”过程。
2.1 图片切片:不是裁剪,是给图像做“像素级分词”
想象你有一张A4纸大小的猫图(224×224像素),现在要用一把16×16像素的“尺子”去量它。这把尺子不会重叠、不会留白,像拼图一样严丝合缝地铺满整张纸——结果得到14×14=196个独立的小方块(patches)。每个小方块就是ViT的“视觉字母”。注意:这不是Photoshop里的裁剪操作,而是数学上的空间重排(spatial rearrangement)。代码里用nn.Conv2d实现,但它的本质是:
- 输入:
(batch, 3, 224, 224)→ 3代表RGB三通道 - 卷积核:
kernel_size=16, stride=16→ 每次只“扫描”一个16×16区域 - 输出:
(batch, 768, 14, 14)→ 768是“字母表大小”(即每个字母的维度)
提示:为什么用卷积而不是直接切片?因为卷积能自动学习每个小方块的特征表达(比如边缘、纹理),比简单取平均值更鲁棒。新手常误以为
Conv2d只是加速工具,其实它是ViT“造字母”的第一道工序。
2.2 字母编码:把16×16像素块,压缩成一个768维的“向量字母”
现在你有196个小方块,每个是16×16×3=768个像素值。ViT要做的,是把这些原始像素“翻译”成768维的向量——就像把“cat”这个词映射成[0.2, -1.5, 0.8, ...]这样的词向量。关键代码在_process_input()函数里:
def _process_input(self, x: torch.Tensor) -> torch.Tensor: n, c, h, w = x.shape # n=batch_size, c=3(RGB), h=w=224 p = self.patch_size # p=16 n_h = h // p # 14 n_w = w // p # 14 # 步骤1:用卷积把每个16x16块映射成768维向量 # (n,3,224,224) -> (n,768,14,14) x = self.conv_proj(x) # 步骤2:把14x14个块展平成序列,类似NLP的token序列 # (n,768,14,14) -> (n,768,196) -> (n,196,768) x = x.reshape(n, self.hidden_dim, n_h * n_w) x = x.permute(0, 2, 1) # 调整维度顺序,适配Transformer输入格式 return x这段代码的玄机在permute(0,2,1):它把原本按“通道优先”组织的数据(768个特征图,每张14×14),强行重排成“序列优先”(196个视觉字母,每个768维)。这就是ViT的“字母表”诞生时刻——196个向量,每个向量是你对图像局部区域的768维理解。后续所有注意力计算,都是在这196个向量之间展开的。
2.3 加入“句首标记”:为什么ViT一定要加一个[CLS]token?
NLP里的BERT会在句子开头加[CLS]标记,用来聚合整句话的语义。ViT照搬了这个设计,但在图像里它没有“语法意义”,纯粹是一个可学习的语义锚点。代码中这行是关键:
batch_class_token = self.class_token.expand(n, -1, -1) # 创建n个[CLS]向量 x = torch.cat([batch_class_token, x], dim=1) # 拼接到196个视觉字母前 → 总共197个tokenself.class_token是一个可训练的参数(比如[0.1, -0.3, 0.7, ...]),它不来自图像,而是模型自己学会的“全局语义开关”。Transformer编码后,我们只取x[:, 0](即[CLS]位置的输出)送入分类头——相当于问:“模型,你综合看了这196个局部信息后,整张图最核心的语义是什么?” 这就是ViT做图像分类的“决策中心”。
2.4 位置编码:图像没有“前后顺序”,为什么还要加位置信息?
文字有天然顺序(“猫追狗”≠“狗追猫”),但196个视觉字母是网格状排列的,没有默认先后。ViT用随机初始化的pos_embedding强行赋予它们坐标感:
self.pos_embedding = nn.Parameter(torch.empty(1, 197, 768).normal_(std=0.02)) # 在forward中:x = x + self.pos_embedding这个pos_embedding的形状是(1,197,768),意味着它对每个位置(0到196)分配了一个独特的768维偏置向量。比如位置0([CLS])的偏置是[0.01, -0.05, ...],位置1(左上角第一个patch)是[0.02, 0.03, ...]。Transformer的注意力机制会学习:当计算“左上角patch关注谁”时,位置编码会让它更倾向关注邻近的patch(位置2、14、15),而非远端的patch(位置195)。没有位置编码,ViT就退化成一个无序的“视觉词袋”,根本学不会空间关系。
2.5 常见问题排查:ViT入门必踩的5个坑
现象1:模型训练时loss不下降,准确率卡在10%(随机水平)
原因:位置编码未正确加载或维度不匹配。新手常把pos_embedding初始化成(197,768),但实际需要(1,197,768)(必须带batch维度1)。
解决:检查pos_embedding的shape,用print(self.pos_embedding.shape)确认;若错误,改为nn.Parameter(torch.empty(1, seq_len, hidden_dim))。
现象2:_process_input()报错RuntimeError: Given groups=1, weight of size [768, 3, 16, 16], expected input[1, 3, 224, 224]
原因:输入图像未归一化到[0,1]范围。nn.Conv2d对数值敏感,若像素值是[0,255]整数,会导致梯度爆炸。
解决:在送入ViT前加归一化:x = x.float() / 255.0,再x = transforms.Normalize(mean=[0.485,0.456,0.406], std=[0.229,0.224,0.225])(x)。
现象3:forward()中x[:,0]取[CLS]时维度报错
原因:x的shape是(n,197,768),但误用了x[0](取第0个样本)而非x[:,0](取所有样本的第0个token)。
解决:牢记[:,0]表示“所有batch的第0个位置”,[0]表示“第0个batch的全部位置”。
现象4:训练速度极慢,GPU显存爆满
原因:ViT的注意力计算复杂度是O(N²),N=197时已需计算约4万个相似度。若batch_size设为32,显存占用翻倍。
解决:新手起步用batch_size=8;或改用torch.compile(model)(PyTorch 2.0+)自动优化。
现象5:模型能训,但测试集准确率远低于训练集(过拟合)
原因:ViT对数据量极度饥渴。ImageNet训练需千万级图像,而新手常只用几百张猫狗图。
解决:立即启用DropPath(随机丢弃部分Transformer层)和Stochastic Depth;或直接用预训练权重(如vit_base_patch16_224)微调。
3. CLIP不是“图文搜索引擎”,而是教会AI用同一把尺子衡量图像和文字的标定协议
如果你觉得ViT是“让AI学会看图”,那CLIP就是“让AI明白‘猫’这个词和猫的图片,在同一个语义宇宙里距离很近”。它不生成文字,也不分类图像,而是干一件更基础的事:把图像和文字投影到同一个高维空间,让匹配的图文对(如“金毛犬”+金毛图)彼此靠近,不匹配的(如“金毛犬”+汽车图)彼此远离。这个空间就是CLIP的“共同语义宇宙”,而它的标定协议,就是对比学习(Contrastive Learning)。
3.1 CLIP的双塔结构:两个独立模型,共享一个目标
CLIP由两个子模型组成:
- Image Encoder:一个ViT(或ResNet),把图片转成图像向量
I ∈ R^D - Text Encoder:一个Transformer(类似BERT),把文字转成语义向量
T ∈ R^D
关键在于:两个编码器输出维度D必须完全相同(如512),且训练目标是让I和T的余弦相似度最大化。代码结构非常清晰:
class CLIP(nn.Module): def __init__(self, image_encoder, text_encoder, embed_dim=512): super().__init__() self.image_encoder = image_encoder # ViT or ResNet self.text_encoder = text_encoder # Text Transformer self.logit_scale = nn.Parameter(torch.ones([]) * np.log(1/0.07)) # 控制相似度缩放 def forward(self, images, texts): image_features = self.image_encoder(images) # (B, D) text_features = self.text_encoder(texts) # (B, D) # 归一化向量,使余弦相似度=点积 image_features = F.normalize(image_features, dim=-1) text_features = F.normalize(text_features, dim=-1) # 计算相似度矩阵:每张图vs每段文字 logits_per_image = image_features @ text_features.t() * self.logit_scale.exp() logits_per_text = logits_per_image.t() return logits_per_image, logits_per_text注意logits_per_image的形状是(B,B):第i行表示第i张图与所有B段文字的相似度得分。训练时,我们期望对角线(i,i)得分最高(正样本),其他位置得分低(负样本)。这就是CLIP的“对比”本质——不是单独优化单个图文对,而是让每个正样本在所有候选中脱颖而出。
3.2 对比损失:让AI学会“找不同”的数学表达
CLIP不用交叉熵,而用对称对比损失(Symmetric Contrastive Loss),它同时优化图像到文本、文本到图像两个方向:
def contrastive_loss(logits_per_image, logits_per_text): # 图像→文本:每张图的正确文字应在所有文字中得分最高 labels = torch.arange(len(logits_per_image)) # [0,1,2,...,B-1] loss_i2t = F.cross_entropy(logits_per_image, labels) # 文本→图像:每段文字的正确图片应在所有图片中得分最高 loss_t2i = F.cross_entropy(logits_per_text, labels) return (loss_i2t + loss_t2i) / 2这个损失函数的血泪经验是:它极度依赖batch内负样本的质量。如果batch里只有猫狗图和“猫”“狗”文字,模型很快学会“猫图只和‘猫’字相似”,但无法泛化到“猫图也和‘宠物’‘毛茸茸’相似”。所以CLIP的训练数据是4亿图文对(来自互联网),确保每个batch都有海量无关负样本。新手实验时,务必用足够多样的图文对(比如COCO数据集的33万张图+50万条描述),否则模型会陷入“死记硬背”。
3.3 零样本迁移:为什么CLIP能“看图识物”而无需训练?
CLIP最震撼的能力是零样本分类(Zero-shot Classification)。比如你有一张未知类别的图,和一个类别列表["cat", "dog", "car", "plane"],CLIP可以这样做:
# 步骤1:用text_encoder编码所有类别名 texts = ["a photo of a cat", "a photo of a dog", "a photo of a car", "a photo of a plane"] text_features = text_encoder(tokenize(texts)) # (4, 512) # 步骤2:用image_encoder编码输入图 image_features = image_encoder(image) # (1, 512) # 步骤3:计算相似度,选最高分类别 similarity = image_features @ text_features.t() # (1, 4) predicted_class = texts[similarity.argmax().item()] # 如"cat"这里没有反向传播,没有梯度更新,纯靠预训练学到的“语义对齐”能力。它的原理是:CLIP在训练时见过无数“猫图+‘cat’文字”的组合,因此在语义空间里,“猫图向量”和“cat文字向量”天然靠近。当新图出现时,它在空间中的位置会自然靠近最相似的文字向量。这就像你从未见过“雪豹”,但看到它的图,仍能联想到“豹子”“雪山”“稀有”,因为你的大脑早已建立动物语义地图——CLIP做的,就是给AI建这样一张地图。
3.4 CLIP vs ViT:别再混淆这两个“视觉Transformer”
新手最大的认知陷阱,是把CLIP当成ViT的升级版。其实它们是完全不同的物种:
| 特性 | ViT | CLIP |
|---|---|---|
| 目标 | 单任务:图像分类/检测 | 多任务基础:图文对齐 |
| 输入 | 只接受图像 | 同时接受图像+文字 |
| 输出 | 一个类别概率分布 | 一对向量(图像向量+文字向量) |
| 训练数据 | ImageNet等标注图像 | 4亿网络图文对(无精细标注) |
| 下游应用 | 直接分类、分割 | 零样本分类、图文检索、提示工程(如Stable Diffusion) |
提示:你可以把ViT看作“单科状元”(专精图像理解),CLIP是“跨学科教授”(打通图像与语言)。想快速验证想法?先用ViT;想让模型理解你的自然语言指令?必须过CLIP这一关。
3.5 常见问题排查:CLIP实战的4个隐形地雷
现象1:零样本分类准确率低于随机(25%),且所有相似度分数接近
原因:文本编码时未添加上下文模板。CLIP对文字表述极其敏感,直接输入"cat"效果差,必须用"a photo of a cat"等模板包裹。
解决:固定使用CLIP官方模板:["a photo of a {}"],或更丰富的["a photo of a {}.", "a blurry photo of the {}.", ...]。
现象2:训练loss下降但相似度矩阵全为0
原因:logit_scale参数未正确初始化。CLIP用exp(logit_scale)控制相似度范围,若logit_scale初始为0,exp(0)=1导致相似度太小。
解决:按原文初始化:self.logit_scale = nn.Parameter(torch.ones([]) * np.log(1/0.07)),其中0.07是温度系数。
现象3:GPU显存不足,@运算报OOM
原因:image_features @ text_features.t()生成(B,B)矩阵,B=1024时需16GB显存。
解决:分块计算——将text_features切分成小块,逐块计算相似度,用torch.cat()拼接结果。
现象4:微调CLIP时,图像分支loss下降但文本分支loss震荡
原因:两个编码器学习率不一致。图像分支通常更难优化,需更低学习率(如1e-6),文本分支可用1e-5。
解决:用torch.optim.AdamW时,为不同参数组设置不同lr:
optimizer = AdamW([ {'params': model.image_encoder.parameters(), 'lr': 1e-6}, {'params': model.text_encoder.parameters(), 'lr': 1e-5}, ])4. BLIP不是“CLIP+Captioning”,而是给AI装上“自问自答”的反思引擎
如果CLIP教会AI“图文匹配”,ViT教会AI“看图”,那么BLIP(Bootstrapped Language-Image Pretraining)要解决的是更现实的问题:当图文不完美匹配时(比如图里有猫,文字却说“这是狗”),AI如何自我纠正?它不像CLIP那样被动接受图文对,而是主动扮演三个角色:
- 教师:用已有知识判断图文是否匹配(ITM任务)
- 学生:根据图像生成文字描述(Captioning任务)
- 考官:用生成的文字反向验证图像理解是否正确(Filtering任务)
这种“自问自答”的闭环,让BLIP在真实场景(如社交媒体图文混杂)中鲁棒性远超CLIP。
4.1 BLIP的三阶段训练:从“抄答案”到“自己出题”
BLIP的魔力在于其渐进式训练策略,分为三个阶段:
阶段1:多任务联合预训练(Pretrain)
同时优化三个目标:
- Image-Text Matching (ITM):判断图文是否匹配(二分类)
- Image Captioning (Cap):根据图像生成文字(自回归生成)
- Masked Language Modeling (MLM):遮盖文字中部分词,让模型预测(类似BERT)
这三个任务共享一个多模态编码器(Multimodal Encoder),它把图像和文字融合成统一表示。代码中,ITM和Cap共用大部分参数,但输出头不同:
class BLIP_Pretrain(nn.Module): def __init__(self, med_config='configs/med_config.json'): super().__init__() self.visual_encoder = VisionTransformer() # ViT self.text_encoder = BertModel(config=med_config) # BERT self.text_decoder = BertLMHeadModel(config=med_config) # BERT decoder for captioning # ITM head:二分类 self.itm_head = nn.Sequential( nn.Linear(768, 512), nn.ReLU(), nn.Linear(512, 2) ) # Cap head:自回归生成 self.decoder = self.text_decoder.lm_head def forward(self, image, text, mode='multimodal'): if mode == 'itm': # ITM:输入图文对,输出匹配概率 output = self.multimodal_encoder(image, text) itm_logits = self.itm_head(output[:,0]) # 取[CLS]向量 return itm_logits elif mode == 'captioning': # Cap:输入图像,生成文字 image_embeds = self.visual_encoder(image) caption_output = self.text_decoder.generate( inputs_embeds=image_embeds, max_length=20, num_beams=3 ) return caption_output阶段2:有监督微调(Finetune)
在特定任务(如COCO Captioning)上,只优化Captioning分支,冻结其他部分。此时BLIP专注提升生成质量。
阶段3:引导式过滤(Bootstrapping)
这才是BLIP的“灵魂”:用预训练好的模型,为大量无标注图像自动生成伪标签(pseudo-captions),再筛选高质量伪标签加入训练集。流程如下:
- 用当前模型为10万张无标注图生成10条描述
- 用ITM模块打分,保留ITM得分>0.9的图文对
- 将这些高质量伪对加入训练集,重新预训练
- 重复步骤1-3,迭代3轮
提示:这个过程就像老师让学生互评作文——学生(模型)先写,再用评分标准(ITM)挑出好作文,最后用好作文当新教材。BLIP的“自举”(Bootstrapping)之名,正源于此。
4.2 BLIP的多模态编码器:如何让图像和文字真正“对话”?
ViT和CLIP的编码器是单向的(图→向量,文→向量),而BLIP的编码器是双向交叉注意力(Cross-Attention),让图像和文字互相修改对方的表示:
# 伪代码:BLIP的cross-attention层 class CrossAttentionLayer(nn.Module): def forward(self, image_features, text_features): # 图像作为Key/Value,文字作为Query # 文字向量会关注图像中哪些区域(如“猫耳朵”对应图中耳朵区域) text_attended = self.text_to_image_attn( query=text_features, # 文字是query key=image_features, # 图像是key value=image_features # 图像是value ) # 文字作为Key/Value,图像作为Query # 图像向量会关注文字中哪些词(如图中“毛茸茸”区域对应词“fluffy”) image_attended = self.image_to_text_attn( query=image_features, # 图像是query key=text_features, # 文字是key value=text_features # 文字是value ) return text_attended, image_attended这种双向交互,让BLIP能回答“图中哪里有猫?”(定位)或“文字中哪个词描述了图中这个区域?”(解释),而CLIP只能回答“图文是否匹配”。
4.3 从BLIP到BLIP2:为什么说“冻结ViT+注入Adapter”是工业级选择?
BLIP2是BLIP的重大升级,核心思想是:不训练庞大的ViT,而是用轻量级Adapter(适配器)桥接现有视觉模型与语言模型。它的结构是:
- 冻结的视觉编码器:直接加载预训练ViT或SigLIP权重(不更新参数)
- 可训练的Q-Former:一个小型Transformer,负责从冻结的ViT特征中“查询”关键视觉信息
- 冻结的语言模型:加载LLaMA或Flan-T5,只训练Q-Former与LLM的连接
class BLIP2(nn.Module): def __init__(self, vit_model, llm_model): super().__init__() self.vit = vit_model # frozen self.llm = llm_model # frozen # Q-Former:可训练的查询模块 self.qformer = QFormer(num_query_tokens=32, hidden_size=768) # 投影层:把Q-Former输出映射到LLM输入空间 self.llm_proj = nn.Linear(768, llm_model.config.hidden_size) def forward(self, image, text): # 步骤1:用冻结ViT提取图像特征 image_embeds = self.vit(image) # (B, 197, 768) # 步骤2:Q-Former从图像特征中“查询”32个关键token query_tokens = self.qformer(image_embeds) # (B, 32, 768) # 步骤3:投影到LLM空间,并拼接文字输入 llm_input = self.llm_proj(query_tokens) # (B, 32, 4096) llm_input = torch.cat([llm_input, text_embeds], dim=1) # (B, 32+L, 4096) return self.llm(llm_input)这种设计让BLIP2训练成本降低80%,且能灵活替换视觉/语言骨干模型。对新手而言,这意味着:你可以直接下载Hugging Face上Salesforce/blip2-opt-2.7b,一行代码加载,无需从头训练ViT。
4.4 常见问题排查:BLIP系列模型的5个部署陷阱
现象1:BLIP2生成文字时卡在第一个词,反复输出<unk>
原因:文本分词器(tokenizer)与语言模型不匹配。BLIP2用OPT模型时,必须用facebook/opt-2.7b配套的tokenizer,而非通用BERT tokenizer。
解决:严格按Hugging Face模型页说明加载:
from transformers import AutoProcessor, Blip2ForConditionalGeneration processor = AutoProcessor.from_pretrained("Salesforce/blip2-opt-2.7b") model = Blip2ForConditionalGeneration.from_pretrained("Salesforce/blip2-opt-2.7b", torch_dtype=torch.float16)现象2:微调BLIP时,ITM任务loss下降但Captioning loss不降
原因:Captioning任务需要teacher-forcing,但新手常误用generate()方法(用于推理,非训练)。
解决:训练时必须用forward()计算loss:
outputs = model( pixel_values=image, input_ids=text_input_ids, # 文字token ids labels=text_labels, # 遮盖后的label ids ) loss = outputs.loss现象3:Q-Former训练不稳定,loss剧烈震荡
原因:Q-Former的学习率过高。因其参数量小(仅百万级),需比主模型低10倍学习率(如1e-4 vs 1e-3)。
解决:为Q-Former参数组单独设置lr:
optimizer = AdamW([ {'params': model.qformer.parameters(), 'lr': 1e-4}, {'params': model.llm_proj.parameters(), 'lr': 1e-4}, ])现象4:生成文字过长(>50词),或包含无关符号([SEP])
原因:generate()参数未限制。默认会一直生成到eos_token_id,但若模型未学会停顿,会失控。
解决:强制约束生成长度:
out = model.generate( pixel_values=image, max_new_tokens=20, # 最多生成20个新词 num_beams=3, # beam search提升质量 do_sample=False, # 关闭采样,用确定性搜索 early_stopping=True # 遇到eos提前结束 )现象5:多卡训练时,Q-Former梯度同步失败
原因:Q-Former未正确注册到DDP(DistributedDataParallel)。因其是嵌套在BLIP2内部的子模块,易被忽略。
解决:手动将Q-Former加入DDP:
model = torch.nn.parallel.DistributedDataParallel( model, find_unused_parameters=True # 允许未参与计算的参数(如Q-Former) )5. 动手实验:用50行代码跑通你的第一个多模态模型——从ViT分类到BLIP2看图说话
理论讲完,现在动手。我们不做大项目,只聚焦一个最小可行实验:用预训练ViT做猫狗二分类,再用BLIP2为同一张图生成描述。这50行代码覆盖了数据加载、模型调用、推理全流程,且全部基于Hugging Face生态(免编译、免配置),新手复制粘贴即可运行。
5.1 准备工作:3分钟安装所有依赖
打开终端,执行以下命令(假设已安装Python 3.8+和pip):
# 创建虚拟环境(推荐,避免包冲突) python -m venv multimodal_env source multimodal_env/bin/activate # Linux/Mac # multimodal_env\Scripts\activate # Windows # 安装核心库 pip install torch torchvision transformers datasets accelerate pillow scikit-learn # 验证CUDA(如有GPU) python -c "import torch; print(torch.cuda.is_available())"注意:若无GPU,
torch会自动安装CPU版本,推理速度稍慢但功能完整。所有模型均支持CPU推理。
5.2 第一步:用ViT做猫狗分类(20行代码)
我们用Hugging Face的google/vit-base-patch16-224预训练模型,搭配Kaggle公开的猫狗数据集(已处理为标准格式):
from transformers import ViTFeatureExtractor, ViTForImageClassification from PIL import Image import requests # 1. 加载预训练ViT模型和特征提取器 feature_extractor = ViTFeatureExtractor.from_pretrained('google/vit-base-patch16-224') model = ViTForImageClassification.from_pretrained('google/vit-base-patch16-224') # 2. 加载一张测试图(可替换为你本地的猫.jpg或狗.jpg) url = "https://huggingface.co/datasets/huggingface/cats-image/resolve/main/cats/cats_image.png" image = Image.open(requests.get(url, stream=True).raw) # 3. 预处理:调整尺寸、归一化、转tensor inputs = feature_extractor(images=image, return_tensors="pt") # 4. 推理 outputs = model(**inputs) logits = outputs.logits # 5. 解析结果:获取最高概率的类别 predicted_class_idx = logits.argmax(-1).item() predicted_class = model.config.id2label[predicted_class_idx] print(f"预测类别: {predicted_class}") # 输出: tabby cat print(f"置信度: {logits.softmax(dim=-1)[0][predicted_class_idx].item():.3f}")这段代码的每一步都在解决一个新手痛点:
feature_extractor自动完成ViT要求的所有预处理(尺寸缩放、归一化),你无需手动写transforms;model.config.id2label直接给出人类可读的类别名,不用查ImageNet索引表;logits.softmax()将原始输出转为0~1的概率,直观显示模型有多确定。
5.3 第二步:用BLIP2为图生成描述(15行代码)
接着,我们用同一张图,让BLIP2生成自然语言描述:
from transformers import Blip2Processor, Blip2ForConditionalGeneration import torch # 1. 加载BLIP2处理器和模型(自动选择最优精度) processor = Blip2Processor.from_pretrained("Salesforce/blip2-opt-2.7b") model = Blip2ForConditionalGeneration.from_pretrained( "Salesforce/blip2-opt-2.7b", torch_dtype=torch.float16 # 半精度,节省显存 ) # 2. 用同一张图,但需重新预处理(BLIP2有自己的processor) inputs = processor(images=image, return_tensors="pt").to <p> <a href="https://download.csdn.net/download/qq_37734256/90201013" style="color:#ec7500;font-size:14px;"> 本文还有配套的精品资源,点击获取 </a> <img alt="menu-r.4af5f7ec.gif" src="https://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif" style="width:16px;margin-left:4px;vertical-align:text-bottom;cursor:text;"> </p>