【新手入门】全网最全的 CLIP 代码讲解

前言

文章性质:简陋的学习记录 📖

主要内容:本文简单记录了作者在阅读 CLIP 代码及其 LoRA 微调时的部分笔记。

冷知识+1:小伙伴们不经意的 点赞 👍🏻 与 收藏 ✨ 可以让作者更有创作动力! 

目录

一、CLIPModel

二、Bottleneck

三、AttentionPool2d

四、ModifiedResNet

五、CLIPModelWithLoRA


一、CLIPModel

__init__ 是初始化方法,接受两个参数:name 模型名称,num_classes 分类任务的类别数。

调用父类 nn.Module 的初始化方法,确保模型正确继承其功能。

使用 clip 库的 load 函数加载指定名称的预训练模型和预处理函数,并将模型加载到 CPU 上。

self.model 是加载的 CLIP 模型,self.preprocess 是对应的预处理函数。

self.fc 是全连接层,将模型的输出特征映射到指定的类别数。 

CHANNELS[name] 是字典,根据模型名称获取相应的特征维度。

forward 是前向传播方法,接受输入 x 和布尔参数 return_feature,用于控制是否返回中间特征。

调用加载的 CLIP 模型的 encode_image 方法,对输入图像进行编码,提取其特征表示。

如果 return_feature 为真,则返回提取的图像特征。这在需要获取图像嵌入表示时非常有用。

如果 return_feature 为假,则将提取的特征通过全连接层 fc,输出分类结果。

from .clip import clip 
from PIL import Image
import torch.nn as nn

CHANNELS = {
    "RN50" : 1024,
    "ViT-L/14" : 768
}

class CLIPModel(nn.Module):
    def __init__(self, name, num_classes=1):
        super(CLIPModel, self).__init__()

        self.model, self.preprocess = clip.load(name, device="cpu")
        self.fc = nn.Linear(CHANNELS[name], num_classes)

    def forward(self, x, return_feature=False):
        features = self.model.encode_image(x) 
        if return_feature:
            return features
        return self.fc(features)

总结:CLIPModel 类利用预训练的 CLIP 模型对输入图像进行特征提取,并通过一个全连接层完成特定任务的分类。

二、Bottleneck

第一层卷积(conv1)是 1x1 的卷积层,用于减少通道数,从 inplanes 降维到 planes。

随后进行批归一化和 ReLU 激活。

        self.conv1 = nn.Conv2d(inplanes, planes, 1, bias=False)
        self.bn1 = nn.BatchNorm2d(planes)
        self.relu1 = nn.ReLU(inplace=True)

第二层卷积(conv2)是3x3 的卷积层,保持通道数不变,主要用于特征提取。

随后同样进行批归一化和 ReLU 激活。 

        self.conv2 = nn.Conv2d(planes, planes, 3, padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(planes)
        self.relu2 = nn.ReLU(inplace=True)

如果步幅大于 1,则在第二层卷积后添加一个平均池化层进行下采样;否则,使用恒等映射。

        self.avgpool = nn.AvgPool2d(stride) if stride > 1 else nn.Identity()

第三层卷积(conv3)是 1x1 的卷积层,用于恢复通道数,从 planes 扩展到 planes*4。

随后同样进行批归一化和 ReLU 激活。  

        self.conv3 = nn.Conv2d(planes, planes * self.expansion, 1, bias=False)
        self.bn3 = nn.BatchNorm2d(planes * self.expansion)
        self.relu3 = nn.ReLU(inplace=True)

当输入和输出的尺寸或通道数不匹配时,需要使用下采样层使它们一致。

这里通过一个平均池化层和一个 1x1 的卷积层来调整尺寸和通道数,并进行批归一化。

        self.downsample = None
        self.stride = stride

        if stride > 1 or inplanes != planes * Bottleneck.expansion:
            self.downsample = nn.Sequential(OrderedDict([
                ("-1", nn.AvgPool2d(stride)),
                ("0", nn.Conv2d(inplanes, planes * self.expansion, 1, stride=1, bias=False)),
                ("1", nn.BatchNorm2d(planes * self.expansion))
            ]))

在前向传播中,输入 x 经过三层卷积和相应的批归一化、激活函数处理,得到 out。

如果存在下采样层,则对输入 x 进行下采样以匹配 out 的尺寸和通道数。

然后将 out 与 identity(即原始输入或下采样后的输入)相加,形成残差连接。

最后通过 ReLU 激活函数输出结果。 

    def forward(self, x: torch.Tensor):
        identity = x

        out = self.relu1(self.bn1(self.conv1(x)))
        out = self.relu2(self.bn2(self.conv2(out)))
        out = self.avgpool(out)
        out = self.bn3(self.conv3(out))

        if self.downsample is not None:
            identity = self.downsample(x
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

作者正在煮茶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值