項(xiàng)目經(jīng)驗(yàn)分享|OpenMMLab 浦視 瞿博文:始于興趣,行于目標(biāo)方向

開(kāi)源之夏個(gè)人專訪與項(xiàng)目經(jīng)驗(yàn)分享持續(xù)開(kāi)放中,歡迎已從開(kāi)源之夏畢業(yè)或正在參與開(kāi)源之夏活動(dòng)的學(xué)生、導(dǎo)師一同加入專訪行動(dòng),掃描文末二維碼填寫專訪問(wèn)卷,與大家分享你眼中的開(kāi)源之夏!
本期項(xiàng)目經(jīng)驗(yàn)分享來(lái)自O(shè)penMMLab 浦視社區(qū)中選學(xué)生——瞿博文,在開(kāi)源之夏2023中承擔(dān)的項(xiàng)目是基于MMPreTrain實(shí)現(xiàn)Prompt-base分類器。

#?關(guān)于?OpenMMLab 浦視
OpenMMLab 誕生于 2018 年,是深度學(xué)習(xí)時(shí)代計(jì)算機(jī)視覺(jué)領(lǐng)域最全面、最具影響力的開(kāi)源算法體系。旨在為學(xué)術(shù)和產(chǎn)業(yè)界提供一個(gè)可跨方向、結(jié)構(gòu)精良、跨站性強(qiáng)、易復(fù)現(xiàn)的統(tǒng)一算法工具庫(kù)。在 2021 年上海人工智能大會(huì)上,發(fā)布了新一代 OpenMMLab,其升級(jí)后涵蓋了更廣泛的算法領(lǐng)域和應(yīng)用場(chǎng)景,實(shí)現(xiàn)了從訓(xùn)練到部署的全鏈條價(jià)值。目前,OpenMMLab 已經(jīng)累計(jì)開(kāi)源了超過(guò) 30 個(gè)算法庫(kù),涵蓋分類、檢測(cè)、分割、視頻理解等眾多算法領(lǐng)域,有超過(guò) 300 種算法實(shí)現(xiàn)、2,400 多個(gè)預(yù)訓(xùn)練模型。在 GitHub 上獲得超過(guò) 75,000 個(gè)標(biāo)星,同時(shí)吸引了超過(guò) 1,600 名社區(qū)開(kāi)發(fā)者參與項(xiàng)目貢獻(xiàn),用戶遍及超過(guò) 110 個(gè)國(guó)家和地區(qū),覆蓋全國(guó)全球頂尖高校、研究機(jī)構(gòu)和企業(yè)。
官網(wǎng):https://openmmlab.com/
# 項(xiàng)目基本信息
項(xiàng)目名稱:基于 MMPreTrain 實(shí)現(xiàn) Prompt-base 分類器
項(xiàng)目導(dǎo)師:馬澤潤(rùn)
項(xiàng)目需求:本題目的任務(wù)是實(shí)現(xiàn)一個(gè) prompt-base 的分類器,它的權(quán)重是固定的,提供簡(jiǎn)單的接口, 給出以下參數(shù)就可以對(duì)任意圖片進(jìn)行分類:
類別名(category)
圖像描述(optional)
圖片樣例(optional)
項(xiàng)目鏈接:https://summer-ospp.ac.cn/org/prodetail/232bc0112
#?項(xiàng)目開(kāi)發(fā)經(jīng)驗(yàn)分享
項(xiàng)目背景與大致流程
項(xiàng)目背景
傳統(tǒng)圖像分類通常遵循預(yù)訓(xùn)練加微調(diào)(pretrain + finetune)的模式,并依賴一個(gè)預(yù)設(shè)的固定類別表。然而,隨著多種視覺(jué)-語(yǔ)言多模態(tài)模型(Vision-Language Models, VLMs)的興起,這種多模態(tài)方法使得模型能夠無(wú)需微調(diào),僅通過(guò)預(yù)設(shè)提示(prompts)即可直接產(chǎn)出卓越的分類結(jié)果。這種做法顛覆了傳統(tǒng)的預(yù)訓(xùn)練模型在圖像分類下游任務(wù)中的微調(diào)方法,標(biāo)志著從經(jīng)典微調(diào)過(guò)渡到一種新的多模態(tài)范式——在這種范式中,模型不需要在下游任務(wù)上進(jìn)行額外訓(xùn)練,而是直接依據(jù)具體任務(wù)構(gòu)建相關(guān)的文本模板(prompt),通過(guò)多模態(tài)推理來(lái)得到分類結(jié)果。
大致流程
?1. 基于 OpenAI 的 CLIP 模型,利用其強(qiáng)大的 zero-shot 能力,實(shí)現(xiàn) Open-Vocabulary 的圖像分類(主要針對(duì)單目標(biāo)分類,即僅有一個(gè)輸出結(jié)果)
2. 基于 RAM(Recognize Anything Model),實(shí)現(xiàn) Open-Vocabulary 的多分類任務(wù),可以將圖像中所有物體進(jìn)行識(shí)別并輸出(即支持多目標(biāo)分類)
關(guān)鍵概念
Registry 機(jī)制:
MM 系列庫(kù)的核心,這一機(jī)制最初由 MMEngine 庫(kù)定義。該機(jī)制為模型、數(shù)據(jù)集、優(yōu)化器、學(xué)習(xí)率調(diào)度器、數(shù)據(jù)預(yù)處理轉(zhuǎn)換、分詞器等組件提供了一個(gè)注冊(cè)表,注冊(cè)表實(shí)現(xiàn)了字符串到具體類的映射。這意味著用戶可以避免復(fù)雜的 import 語(yǔ)句,直接通過(guò)注冊(cè)表快速訪問(wèn)并實(shí)例化所需的類。此外,Registry 機(jī)制還簡(jiǎn)化了配置文件(Config 文件)的編寫過(guò)程,使得用戶配置模型和實(shí)驗(yàn)變得更加高效和靈活。同時(shí),也為模塊測(cè)試提供了便利,對(duì)倉(cāng)庫(kù)的開(kāi)發(fā)者和維護(hù)者來(lái)說(shuō)是一個(gè)福音。
Hook 機(jī)制:
MM 系列庫(kù)的又一個(gè)核心,可以在整個(gè) pipeline 的某個(gè)部分,如:模型的 forward 途中,定義 Hook,從而為輸出模型中間層特征,特征可視化等操作提供了便利。
各種基類:
MM 系列算法庫(kù)提供了一系列的基類,例如 BaseModel、BaseDataProcessor 等。這些基類不僅明確規(guī)定了派生子類必須實(shí)現(xiàn)的方法,而且也便于子類繼承和定制化重寫。通過(guò)這種設(shè)計(jì),MM 系列算法庫(kù)的一致性和模塊化得到了顯著提升,同時(shí)也簡(jiǎn)化了新算法的集成和開(kāi)發(fā)過(guò)程。
項(xiàng)目實(shí)現(xiàn)細(xì)節(jié)
基于 MMPreTrain 實(shí)現(xiàn) CLIP
Step1:將 CLIP 的 ViT 轉(zhuǎn)換成 MMPreTrain 中的 VisionTransformer 的實(shí)現(xiàn)
需要完成以下內(nèi)容:
完成 ViT 的 checkpoint 中的 state_dict 的轉(zhuǎn)換
實(shí)現(xiàn) ViT-B/16 和 ViT-L/14 兩種 setting 的轉(zhuǎn)換
關(guān)鍵函數(shù):
from collections import OrderedDict
def convert_clip(ckpt):
? ?new_ckpt = OrderedDict()
? ?for k, v in list(ckpt.items()):
? ? ? ?new_v = v
? ? ? ?if k.startswith('visual.conv1'):
? ? ? ? ? ?new_k = k.replace('conv1', 'patch_embed.projection')
? ? ? ?elif k.startswith('visual.positional_embedding'):
? ? ? ? ? ?new_k = k.replace('positional_embedding', 'pos_embed')
? ? ? ? ? ?new_v = v.unsqueeze(dim=0)
? ? ? ?elif k.startswith('visual.class_embedding'):
? ? ? ? ? ?new_k = k.replace('class_embedding', 'cls_token')
? ? ? ? ? ?new_v = v.unsqueeze(dim=0).unsqueeze(dim=0)
? ? ? ?elif k.startswith('visual.ln_pre'):
? ? ? ? ? ?new_k = k.replace('ln_pre', 'pre_norm')
? ? ? ?elif k.startswith('visual.transformer.resblocks'):
? ? ? ? ? ?new_k = k.replace('transformer.resblocks', 'layers')
? ? ? ? ? ?if 'ln_1' in k:
? ? ? ? ? ? ? ?new_k = new_k.replace('ln_1', 'ln1')
? ? ? ? ? ?elif 'ln_2' in k:
? ? ? ? ? ? ? ?new_k = new_k.replace('ln_2', 'ln2')
? ? ? ? ? ?elif 'mlp.c_fc' in k:
? ? ? ? ? ? ? ?new_k = new_k.replace('mlp.c_fc', 'ffn.layers.0.0')
? ? ? ? ? ?elif 'mlp.c_proj' in k:
? ? ? ? ? ? ? ?new_k = new_k.replace('mlp.c_proj', 'ffn.layers.1')
? ? ? ? ? ?elif 'attn.in_proj_weight' in k:
? ? ? ? ? ? ? ?new_k = new_k.replace('in_proj_weight', 'qkv.weight')
? ? ? ? ? ?elif 'attn.in_proj_bias' in k:
? ? ? ? ? ? ? ?new_k = new_k.replace('in_proj_bias', 'qkv.bias')
? ? ? ? ? ?elif 'attn.out_proj' in k:
? ? ? ? ? ? ? ?new_k = new_k.replace('out_proj', 'proj')
? ? ? ?elif k.startswith('visual.ln_post'):
? ? ? ? ? ?new_k = k.replace('ln_post', 'ln1')
? ? ? ?elif k.startswith('visual.proj'):
? ? ? ? ? ?new_k = k.replace('visual.proj', 'visual_proj.proj')
? ? ? ?else:
? ? ? ? ? ?new_k = k
? ? ? ?new_ckpt[new_k] = new_v
? ?return new_ckpt
如此即可將 OpenAI 的 Vision Transformer 的權(quán)重轉(zhuǎn)換到 MMPreTrain 內(nèi)置實(shí)現(xiàn)的 Vision Transformer 的格式,方便我們?cè)?MMPreTrain 框架下也可以加載 OpenAI 的 Vision Transformer 權(quán)重。
Step2:實(shí)現(xiàn)一個(gè) CLIP 基類
其中需要完成以下功能:
1. 模型結(jié)構(gòu)組件的定義
2. 實(shí)現(xiàn)圖像處理、文本的處理以及 BBPE(Byte-level Byte Pair Encoding) 分詞
3. 實(shí)現(xiàn)圖像特征的提取,以及文本特征的提取
核心代碼:
class CLIP(BaseModel):
? ?def __init__(self,
? ? ? ? ? ? ? ? vision_backbone: dict,
? ? ? ? ? ? ? ? projection: dict,
? ? ? ? ? ? ? ? text_backbone: dict,
? ? ? ? ? ? ? ? tokenizer: dict,
? ? ? ? ? ? ? ? vocab_size: int,
? ? ? ? ? ? ? ? transformer_width: int,
? ? ? ? ? ? ? ? proj_dim: int,
? ? ? ? ? ? ? ? context_length: int = 77,
? ? ? ? ? ? ? ? data_preprocessor: Optional[dict] = None,
? ? ? ? ? ? ? ? init_cfg: Optional[dict] = None):
? ? ? ?# 定義模型組件,包括圖像、文本編碼器,對(duì)齊所用的projection層、分詞器tokenizer、
? ? ? ?# 對(duì)輸出的logits進(jìn)行scale的一個(gè)可訓(xùn)練常數(shù)logit_scale等
? ?def forward(
? ? ? ?self,
? ? ? ?images: torch.Tensor,
? ? ? ?data_samples: Optional[list] = None,
? ? ? ?mode: str = 'predict',
? ? ? ?**kwargs,
? ?):
? ? ? ?# 僅支持推理,不支持訓(xùn)練
? ? ? ?if mode == 'predict':
? ? ? ? ? ?return self.predict(images, data_samples, **kwargs)
? ? ? ?else:
? ? ? ? ? ?raise RuntimeError(f'Invalid mode "{mode}".')
? ?def extract_image_feat(self, images: torch.Tensor) -> torch.Tensor:
? ? ? ?"""The function to extract image latent features."""
? ?def extract_text_feat(self, texts: torch.Tensor) -> torch.Tensor:
? ? ? ?"""The function to extract text latent features."""
? ?def extract_feat(
? ? ? ? ? ?self, images: torch.Tensor,
? ? ? ? ? ?texts: torch.Tensor) -> Union[torch.Tensor, Tuple[torch.Tensor]]:
? ?def compute_similarity(self, images, texts):
? ? ? ?"""Extract images and texts features and compute cosine similarity."""
? ?@abstractmethod
? ?def predict(self,
? ? ? ? ? ? ? ?images: torch.Tensor,
? ? ? ? ? ? ? ?data_samples: DataSample = None) -> DataSample:
? ? ? ?raise NotImplementedError
? ?def tokenize(self, texts: Union[str, List[str]]) -> torch.LongTensor:
? ? ? ?"""Returns the tokenized representation of given input string(s)
? ? ? ?Args:
? ? ? ? ? ?texts (Union[str, List[str]]): An input string or a list of input
? ? ? ? ? ? ? ?strings to tokenize
? ? ? ? ? ?context_length (int): The context length to use. Defaults to 52.
? ? ? ?Returns:
? ? ? ? ? ?torch.Tensor: Resulting tokens.
? ? ? ?"""
可以看到,predict 方法暫未實(shí)現(xiàn),需要在其子類中進(jìn)行實(shí)現(xiàn)。
Step3:實(shí)現(xiàn)一個(gè) CLIPZeroShot 類
它繼承自 CLIP 基類,并實(shí)現(xiàn)額外的 zero-shot 推理功能,即任意給定一個(gè) category,可以在這個(gè) category 下實(shí)現(xiàn) open-vocabulary 的分類。
具體而言,需要重寫 CLIP 基類沒(méi)有定義的 predict 方法,大致代碼如下:
@MODELS.register_module()
class CLIPZeroShot(CLIP):
? ?def predict(self,
? ? ? ? ? ? ? ?images: torch.Tensor,
? ? ? ? ? ? ? ?data_samples: DataSample = None) -> DataSample:
? ? ? ?if self.text_prototype_embeds is None:
? ? ? ? ? ?self.prepare_text_prototype(device=images.device)
? ? ? ?image_features = self.extract_image_feat(images=images)
? ? ? ?image_features /= image_features.norm(dim=-1, keepdim=True)
? ? ? ?# cosine similarity as logits
? ? ? ?logits_per_image = image_features @ self.text_prototype_embeds.to(
? ? ? ? ? ?image_features.device) * self.logit_scale.exp()
? ? ? ?pred_scores = F.softmax(logits_per_image, dim=1)
? ? ? ?pred_labels = pred_scores.argmax(dim=1, keepdim=True).detach()
? ? ? ?out_data_samples = []
? ? ? ?if data_samples is None:
? ? ? ? ? ?data_samples = [None for _ in range(pred_scores.size(0))]
? ? ? ?for data_sample, score, label in zip(data_samples, pred_scores,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pred_labels):
? ? ? ? ? ?if data_sample is None:
? ? ? ? ? ? ? ?data_sample = DataSample()
? ? ? ? ? ?data_sample.set_pred_score(score).set_pred_label(label)
? ? ? ? ? ?out_data_samples.append(data_sample)
? ? ? ?return out_data_samples
? ?def prepare_text_prototype(self, device) -> None:
? ? ? ?"""The function to prepare text prototypes with prompt."""
? ? ? ?class_embeddings = []
? ? ? ?for classname in track_on_main_process(self.prototype,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'Prepare text prototype...'):
? ? ? ? ? ?# format with class
? ? ? ? ? ?texts = [prompt(classname) for prompt in self.prompt]
? ? ? ? ? ?tokenized_texts = self.tokenize(texts)
? ? ? ? ? ?class_features = self.extract_text_feat(tokenized_texts.to(device))
? ? ? ? ? ?class_features /= class_features.norm(dim=-1, keepdim=True)
? ? ? ? ? ?class_feature = class_features.mean(dim=0)
? ? ? ? ? ?class_feature /= class_feature.norm()
? ? ? ? ? ?class_embeddings.append(class_feature)
? ? ? ?self.text_prototype_embeds = torch.stack(
? ? ? ? ? ?class_embeddings, dim=1).to(device)
簡(jiǎn)單來(lái)說(shuō),即:CLIPZeroShot 類繼承自 CLIP 基類,并在 predict 方法中實(shí)現(xiàn)了圖像的 open-vocabulary 分類。
基于 MMPreTrain 實(shí)現(xiàn) RAM
RAM 中需要使用 CLIP 模型的文本編碼器提取文本特征,所以 RAM 的實(shí)現(xiàn)是基于上述的 MMPreTrain 中 CLIP 實(shí)現(xiàn)的。
Step1:將 RAM 的 SwinTranformer 轉(zhuǎn)換成 MMPreTrain 中的實(shí)現(xiàn)
需要完成的功能:
SwinTransformer 的 checkpoint 中的 state_dict 的轉(zhuǎn)換
在此過(guò)程中,我也遇到了一個(gè)困擾我很久的問(wèn)題,即:
MMPetrain 中采用最新版本的 swin-transformer 實(shí)現(xiàn),其中 PatchMerging 模塊采用 nn.Unfold 實(shí)現(xiàn),而其他 SwinTransformer 實(shí)現(xiàn)大多采用 Slice 再 Concat 的實(shí)現(xiàn)方式,所以在對(duì)應(yīng)的 state_dict 的權(quán)重的通道順序上也需要進(jìn)行轉(zhuǎn)換。
最初,我一直在硬磕這個(gè)問(wèn)題,死磕了很久才得以解決,在和導(dǎo)師交流后,他很快地就在 MMSegmentation 庫(kù)的 Issue 和 PR 中找到了幾乎一模一樣的問(wèn)題和解決方案,這就是開(kāi)源社區(qū)的好處,如果我早點(diǎn)意識(shí)到,也就會(huì)減少很多重復(fù)的工作量了~
關(guān)鍵函數(shù)代碼:
from collections import OrderedDict
def convert_swin(ckpt):
? ?new_ckpt = OrderedDict()
? ?convert_mapping = dict()
? ?def correct_unfold_reduction_order(x):
? ? ? ?out_channel, in_channel = x.shape
? ? ? ?x = x.reshape(out_channel, 4, in_channel // 4)
? ? ? ?x = x[:, [0, 2, 1, 3], :].transpose(1,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?2).reshape(out_channel, in_channel)
? ? ? ?return x
? ?def correct_unfold_norm_order(x):
? ? ? ?in_channel = x.shape[0]
? ? ? ?x = x.reshape(4, in_channel // 4)
? ? ? ?x = x[[0, 2, 1, 3], :].transpose(0, 1).reshape(in_channel)
? ? ? ?return x
? ?for k, v in ckpt.items():
? ? ? ?if 'attn_mask' in k:
? ? ? ? ? ?continue
? ? ? ?if k.startswith('head'):
? ? ? ? ? ?continue
? ? ? ?elif k.startswith('layers'):
? ? ? ? ? ?new_v = v
? ? ? ? ? ?if 'attn.' in k:
? ? ? ? ? ? ? ?new_k = k.replace('attn.', 'attn.w_msa.')
? ? ? ? ? ?elif 'mlp.' in k:
? ? ? ? ? ? ? ?if 'mlp.fc1.' in k:
? ? ? ? ? ? ? ? ? ?new_k = k.replace('mlp.fc1.', 'ffn.layers.0.0.')
? ? ? ? ? ? ? ?elif 'mlp.fc2.' in k:
? ? ? ? ? ? ? ? ? ?new_k = k.replace('mlp.fc2.', 'ffn.layers.1.')
? ? ? ? ? ? ? ?else:
? ? ? ? ? ? ? ? ? ?new_k = k.replace('mlp.', 'ffn.')
? ? ? ? ? ?elif 'downsample' in k:
? ? ? ? ? ? ? ?new_k = k
? ? ? ? ? ? ? ?if 'reduction.' in k:
? ? ? ? ? ? ? ? ? ?new_v = correct_unfold_reduction_order(v)
? ? ? ? ? ? ? ?elif 'norm.' in k:
? ? ? ? ? ? ? ? ? ?new_v = correct_unfold_norm_order(v)
? ? ? ? ? ?else:
? ? ? ? ? ? ? ?new_k = k
? ? ? ? ? ?new_k = new_k.replace('layers', 'stages', 1)
? ? ? ?elif k.startswith('patch_embed'):
? ? ? ? ? ?new_v = v
? ? ? ? ? ?if 'proj' in k:
? ? ? ? ? ? ? ?new_k = k.replace('proj', 'projection')
? ? ? ? ? ?else:
? ? ? ? ? ? ? ?new_k = k
? ? ? ?elif k.startswith('norm'):
? ? ? ? ? ?new_v = v
? ? ? ? ? ?new_k = k.replace('norm', 'norm3')
? ? ? ?else:
? ? ? ? ? ?new_v = v
? ? ? ? ? ?new_k = k
? ? ? ?new_ckpt[new_k] = new_v
? ? ? ?convert_mapping[k] = new_k
? ?return new_ckpt, convert_mapping
Step2:實(shí)現(xiàn) RAM 基類,并基于此實(shí)現(xiàn)默認(rèn)詞表的 RAMNormal 類和支持用戶自定義詞表的 RAMOpenset 類
此處的程序設(shè)計(jì)理念和 CLIPZeroShot 與 CLIP 基類類似,即 RAM 基類實(shí)現(xiàn)一些基本的模型推理和特征提取,而子類的 RAMNormal 和 RAMOpenset 更改其 predict 方法,以完成個(gè)性化的設(shè)計(jì),大致的偽代碼框架如下:
class RAM(BaseModel):
? ?"""The implementation of `RAM <https://arxiv.org/abs/2306.03514>`_."""
? ?def __init__(self,
? ? ? ? ? ? ? ? tokenizer: dict,
? ? ? ? ? ? ? ? vision_backbone: dict,
? ? ? ? ? ? ? ? tag_encoder: dict,
? ? ? ? ? ? ? ? tagging_head: dict,
? ? ? ? ? ? ? ? text_decoder: dict,
? ? ? ? ? ? ? ? device: str = 'cpu',
? ? ? ? ? ? ? ? vision_width: int = 1536,
? ? ? ? ? ? ? ? prompt='a picture of ',
? ? ? ? ? ? ? ? threshold=0.68,
? ? ? ? ? ? ? ? delete_tag_index=[],
? ? ? ? ? ? ? ? tag_list='./data/ram_tag_list.pickle',
? ? ? ? ? ? ? ? tag_list_chinese='./data/ram_tag_list_chinese.pickle',
? ? ? ? ? ? ? ? data_preprocessor: Optional[dict] = None,
? ? ? ? ? ? ? ? init_cfg: Optional[dict] = None):
? ? ? ?# 定義各組件
? ?def load_tag_list(self, tag_list_file):
? ? ? ?# 從文件中得到詞表
? ?def get_label_embed(self):
? ? ? ?# 得到詞表中每個(gè)詞的嵌入特征
? ?def extract_visual_feature(self, images):
? ? ? ?# 提取視覺(jué)特征
? ?def image2tag(self, label_embed, image_embeds, image_atts):
? ? ? ?# image2tag推理
? ?def forward(
? ? ? ?self,
? ? ? ?images: torch.Tensor,
? ? ? ?data_samples: Optional[list] = None,
? ? ? ?mode: str = 'predict',
? ? ? ?**kwargs,
? ?):
? ? ? ?if mode == 'predict':
? ? ? ? ? ?return self.predict(images, data_samples, **kwargs)
? ? ? ?else:
? ? ? ? ? ?raise RuntimeError(f'Invalid mode "{mode}".')
? ?@abstractmethod
? ?def predict(self,
? ? ? ? ? ? ? ?images: torch.Tensor,
? ? ? ? ? ? ? ?data_samples: DataSample = None) -> DataSample:
? ? ? ?raise NotImplementedError
@MODELS.register_module()
class RAMNormal(RAM):
? ?def tag_process(self, logits):
? ? ? ?# 處理詞表
? ?def predict(self,
? ? ? ? ? ? ? ? ? ?images: torch.Tensor,
? ? ? ? ? ? ? ? ? ?data_samples: DataSample = None) -> DataSample:
? ? ? ?# 定義直接加載詞表情況下的predict行為
@MODELS.register_module()
class RAMOpenset(RAMNormal): ?# 繼承RAMNormal類
? ?def set_openset(self,
? ? ? ? ? ? ? ? ? ?categories: List[str] = None,
? ? ? ? ? ? ? ? ? ?clip_ckpt: str = '',
? ? ? ? ? ? ? ? ? ?threshold: float = 0.68):
? ? ? ?# openset的相關(guān)設(shè)置和embedding提取
? ?def tag_process(self, logits):
? ? ? ?# 重寫tag_process函數(shù)
Step3:基于 gradio 實(shí)現(xiàn)一個(gè) webui,能夠讓用戶更便捷的使用 RAM
構(gòu)建一 個(gè)WebUI,可以讓用戶更加方便地使用 RAM,測(cè)試其性能,并且近乎實(shí)時(shí)地看到輸出結(jié)果,體感極強(qiáng)!
項(xiàng)目結(jié)果呈現(xiàn)
CLIP在CIFAR100和ImageNet1k上的zero-shot性能對(duì)齊
如下表展示的數(shù)據(jù)所示,基于 MMPreTrain 實(shí)現(xiàn)的 CLIP 模型在 CIFAR100 和 ImageNet1k 這兩個(gè)數(shù)據(jù)集上的 zero-shot 分類性能,可以與 OpenAI 的 CLIP 模型相媲美。

RAM 的 Gradio WebUI demo 展示
加載預(yù)設(shè)詞表(Normal 模式):


使用自定義詞表(Openset 模式,暫未支持中文輸出):

PR 鏈接
CLIP:https://github.com/open-mmlab/mmpretrain/pull/1737
RAM:https://github.com/open-mmlab/mmpretrain/pull/1802
后續(xù)工作安排
由于我個(gè)人研究方向是多模態(tài)學(xué)習(xí),且現(xiàn)階段對(duì)多模態(tài)大語(yǔ)言模型非常感興趣,在參加 OSPP 后,我也有在持續(xù)關(guān)注 MMPreTrain 和 OpenMMLab 其他倉(cāng)庫(kù)(如:MMGPT 等)的最新進(jìn)展和開(kāi)發(fā)者活動(dòng),我也會(huì)通過(guò)開(kāi)發(fā)者活動(dòng)和日常貢獻(xiàn)等方式繼續(xù)參與 OpenMMLab 社區(qū)的開(kāi)源建設(shè)!
# 開(kāi)源之夏個(gè)人隨訪
--自我介紹--
OSPP:請(qǐng)簡(jiǎn)單介紹一下自己,并說(shuō)一下自己的開(kāi)源經(jīng)歷吧。
瞿博文:大家好,我是瞿博文,本科畢業(yè)于華中科技大學(xué)電子信息工程專業(yè),現(xiàn)在在北京大學(xué)信息工程學(xué)院計(jì)算機(jī)應(yīng)用技術(shù)專業(yè)就讀,是一名研二學(xué)生。在參加開(kāi)源之夏活動(dòng)之前,我主要是在計(jì)算機(jī)保研群的 GitHub 倉(cāng)庫(kù)中提交了一篇經(jīng)驗(yàn)分享文章;還在實(shí)習(xí)期間為一個(gè)視頻動(dòng)作識(shí)別的開(kāi)源項(xiàng)目提交了代碼(相對(duì)來(lái)說(shuō)可能,比較自?shī)首詷?lè)地分享一下,這個(gè)貢獻(xiàn)現(xiàn)在似乎還沒(méi)有被合并呢,哈哈)
OSPP:你有幾段實(shí)習(xí)和項(xiàng)目經(jīng)歷,這些經(jīng)歷和你在開(kāi)源社區(qū)中的經(jīng)歷有什么異同之處呢?
瞿博文:算是比較正式的算是一段實(shí)習(xí)和一段比賽吧,我大四時(shí)在科大訊飛有一段實(shí)習(xí)經(jīng)歷,當(dāng)時(shí)主要做的是圖像目標(biāo)檢測(cè)和視頻動(dòng)作識(shí)別相關(guān)的項(xiàng)目,后來(lái)參加過(guò)Kaggle的一個(gè)有關(guān)視覺(jué)語(yǔ)言多模態(tài)的比賽。這些經(jīng)歷的話,可能kaggle的這段和開(kāi)源社區(qū)的經(jīng)歷更加相似吧,因?yàn)閗aggle也是一個(gè)偏社區(qū)性質(zhì)的競(jìng)賽平臺(tái),有非常多的大佬分享自己的經(jīng)驗(yàn)、方法和代碼,當(dāng)時(shí)能獲得銀牌多虧了kaggle多方大佬的討論和分享。然而,這與開(kāi)源社區(qū)還是有不小區(qū)別的,如果說(shuō)kaggle的分享對(duì)我來(lái)說(shuō)是一種“傳授”的話,我認(rèn)為開(kāi)源社區(qū)的分享應(yīng)該是一種“互通”,是社區(qū)、貢獻(xiàn)者、使用者們互相交流,在過(guò)程中共同發(fā)現(xiàn)新坑新問(wèn)題。同時(shí),開(kāi)源社區(qū)的話涉及更長(zhǎng)期的“承諾”,社區(qū)以及貢獻(xiàn)者們需要更長(zhǎng)期、廣泛地合作和交流,以提供一個(gè)穩(wěn)定而又不斷創(chuàng)新的框架。
OSPP:參與(例如開(kāi)源之夏)開(kāi)源項(xiàng)目開(kāi)發(fā)實(shí)踐與參與競(jìng)賽的體驗(yàn)有什么不同?
瞿博文:排除上面所說(shuō)的“分享”層面的不同,我作為一個(gè)初學(xué)者參加kaggle競(jìng)賽時(shí),可能更關(guān)注于我在競(jìng)賽榜單上的位置,關(guān)注他人分享的經(jīng)驗(yàn)和方法是否能、如何能用到我的方案上,以獲得一個(gè)更高的排名,而沒(méi)有去分享自己的經(jīng)驗(yàn)的意識(shí)(同時(shí)也水平有限),這會(huì)導(dǎo)致在進(jìn)行項(xiàng)目編程和總結(jié)的時(shí)候,忽略掉一些規(guī)范和整體性。從完整項(xiàng)目的角度來(lái)看,似乎是處在一個(gè)toy級(jí)別。
而參加開(kāi)源項(xiàng)目開(kāi)發(fā)實(shí)踐的話,會(huì)在編程時(shí)就對(duì)自己有一些代碼風(fēng)格、質(zhì)量、規(guī)范上的高要求;在提交PR時(shí)會(huì)更整體的去介紹和總結(jié)自己的貢獻(xiàn);在進(jìn)行review交互時(shí),會(huì)不斷地思考如何迭代得更好。這些過(guò)程讓我對(duì)于更加高質(zhì)量項(xiàng)目的建立、提交、迭代有了一些更深入的認(rèn)識(shí)。
--參與開(kāi)源之夏--
OSPP:在開(kāi)源之夏的項(xiàng)目開(kāi)發(fā)過(guò)程中,你有遇到什么困難或挑戰(zhàn)么?你是如何克服的呢?導(dǎo)師和社區(qū)在這一過(guò)程中又給你提供了什么幫助?最大的收獲是什么?
瞿博文:是有遇到一些困難的,就像經(jīng)驗(yàn)貼里所說(shuō)的,在進(jìn)行swin transformer的state_dict轉(zhuǎn)換時(shí),一個(gè)模塊中算子的實(shí)現(xiàn)有所差異,需要重新去計(jì)算,當(dāng)時(shí)花了我很長(zhǎng)時(shí)間去解決,在后來(lái)與導(dǎo)師交流時(shí),導(dǎo)師發(fā)現(xiàn)OpenMMLab社區(qū)的另一個(gè)MMSegmentation庫(kù)中有一個(gè)類似的Issue和相關(guān)PR,能夠很好的解決我的問(wèn)題。當(dāng)時(shí)讓我意識(shí)到了開(kāi)源社區(qū)的好處,對(duì)于開(kāi)發(fā)時(shí)遇到的問(wèn)題,可以先在開(kāi)源社區(qū)進(jìn)行檢索,一些相關(guān)分享是可以很好的避免我們重復(fù)造輪子的。
OSPP:對(duì)于在活動(dòng)中選擇社區(qū)、挑選項(xiàng)目、與導(dǎo)師溝通、撰寫申請(qǐng)書方面,有什么經(jīng)驗(yàn)或建議可以分享給大家么?
瞿博文:以我個(gè)人的經(jīng)歷而言,我比較推薦去選擇與自己的興趣和背景更加相關(guān)的社區(qū)和項(xiàng)目,這大概率可以讓我們寫出有背景、有方案、有一定深度的申請(qǐng)書,在進(jìn)行項(xiàng)目的時(shí)候也可以更加有把握、有方向。至于與導(dǎo)師溝通的話,我覺(jué)得可以盡可能地提前進(jìn)行,這樣可能可以更早的進(jìn)入社區(qū),參與一些Issue和PR,增進(jìn)自己對(duì)于社區(qū)的了解吧,這方面我是個(gè)反例,ddl戰(zhàn)士太挑戰(zhàn)心跳了一點(diǎn)。
--寄語(yǔ)--
OSPP:談一談你對(duì)高校學(xué)生參與開(kāi)源的看法吧
瞿博文:作為高校學(xué)生,我們平時(shí)接觸到的項(xiàng)目應(yīng)該更多是大作業(yè)和課程設(shè)計(jì),或者自發(fā)地進(jìn)行一些個(gè)人項(xiàng)目和競(jìng)賽。做這些項(xiàng)目的目的也主要是了解、學(xué)習(xí)一個(gè)新領(lǐng)域的知識(shí)。參與開(kāi)源可以讓我們更早地接觸到工業(yè)級(jí)的、更加完整的、更加高質(zhì)量的項(xiàng)目,而PR和review就像是初次驗(yàn)收和不斷迭代,這可以讓我們了解到一個(gè)好的項(xiàng)目的完整流程大概是什么樣的,增進(jìn)我們對(duì)于項(xiàng)目的品味和感知,后續(xù)可能就可以做出一些更好地項(xiàng)目了!
END
專欄編輯:大夢(mèng)
校對(duì):校大山、瞿博文
制圖:GoodWhite

專欄投稿請(qǐng)聯(lián)系開(kāi)源小助手:kaiyuanzhixia 或?qū)诰庉嫞篐ungryfish34(備注“專欄投稿”加速通過(guò)),或填寫下方專訪信息收集問(wèn)卷。
