From json file
[{
"image": "gene_crop/4x/0.jpg",
"caption": "a woman standing on a set of stairs with her hand on the railings and her leg on the railings of the stair case",
"image_id": "4x_0",
"label": [0, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]},
{
"image": "gene_crop/4x/1.jpg",
"caption": "a woman in a pink shirt and white shorts standing on a beach next to the ocean with a boat in the distance and a man in the background",
"image_id": "4x_1",
"label": [0, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]}, ...]
Attribute prompts correspond to attribute label
Image from paper
Re-drawed Image
Link to whiteboard: just register email, then view: https://miro.com/welcomeonboard/VktCZkRHcjJIZ2NzVmtjaHVNcHdOMXpORThsZE1OSk9aNEJVa2FBRWpFa1pSQTd0Wnk4RzRrbG93S29hZFVIWXwzMDc0NDU3MzYzMzk5NTU1NzQ1fDI=?share_link_id=935922303615
Idea from constrastive learning loss, that used in almost papers, e.g. CLIP
From a minibatch $\mathcal{B}$, sample $\mathcal{B_2}$ set of pairs of $(I, A)$ that:
Calculate loss for each pair $(I, A)$ in $\mathcal{B_2}$:
$$\mathbf{L} = \{l^{cls}, l^1, \dotsc, l^{k_L}\} = \text{TextEncoder}(A)$$
$$\mathbf{C} = \{c^{cls}, c^1, \dotsc, c^{c_L}\} = \text{CrossEncoder}(\mathbf{V}, \mathbf{L})$$
$$p_{matched}(I, A) = Sigmoid(MLP(c^{cls}))$$
Final IAM loss for a minibatch $\mathcal{B}$: $$ \mathcal{L_{IAC}}(\mathcal{B}) = \mathbb{E}_{(I, A)\sim \mathcal{B_2}}[\mathcal{L_{IAM}}(I, A)]$$
Given a fix set of binary attribute prompt $\mathcal{A_{prompt}}$, do this strategy to generate masked prompt:
$\rightarrow$ $A_{mask} = \text{MASK}(A)$
Recall $\mathcal{B_1} = \{(I, A) | I \in \text{mini-batch } \mathcal{B}; A \in \mathcal{A_{prompt}}; I \text{ match } A\}$
For each pair $(I, A)$ in $\mathcal{B_1}$ $\rightarrow$ get $(I, A_{mask})$
Final loss for MAL $$ \mathcal{L_{MAL}}(\mathcal{B}) = \mathbb{E}_{token_{mask} \sim (I, A)\text{ / } (I, A) \sim \mathcal{B}}[CELoss(token_{mask})]$$
$$\mathcal{L_{APL}} = \mathcal{L_{MAL}}(\mathcal{B}) + \mathcal{L_{IAC}}(\mathcal{B}) + \mathcal{L_{IAM}}(\mathcal{B})$$
Input for loss function and How to sampling input?
Pretraining
Evaluate APTM on finetunning TBPR datasets:
Evaluate APTM on PAR datasets:
Only use 0.3/1.5M images to get SOTA benchmark
import os, sys
from pathlib import Path
ROOT_PATH = Path('../paper_clones/APTM').resolve()
sys.path.append(str(ROOT_PATH))
#FOR MALS DATASET
IMAGE_PATH = Path('../NEW_DATASET/MALS/imgs').resolve()
MODEL_PATH = ROOT_PATH/'MODEL'/'pretrained'/'checkpoint_31.pth'
MALS_ANNO_PATH = Path('../NEW_DATASET/MALS/gene_attrs')
CUHK_ANNO_PATH = ROOT_PATH/'data/finetune'
import torch; print(torch.cuda.is_available())
import pandas as pd
import matplotlib.pyplot as plt
from pathlib import Path
import yaml
import torch.nn.functional as F
from easydict import EasyDict as edict
from torchinfo import summary
import argparse
import os
import math
import numpy as np
import random
import time
import datetime
import json
from pathlib import Path
from prettytable import PrettyTable
import torch
from torchvision import transforms
from torchvision.transforms import InterpolationMode
import PIL
import torch.backends.cudnn as cudnn
import torch.distributed as dist
#### LOCAL MODULES
from models import aptm, bert, model_retrieval, swin_transformer, tokenization_bert
from models.model_retrieval import APTM_Retrieval
from models.tokenization_bert import BertTokenizer
import utils
from dataset import create_dataset, create_sampler, create_loader
from dataset.re_dataset import TextMaskingGenerator
from scheduler import create_scheduler
from optim import create_optimizer
from trains import train, train_attr
from train_pa100ks import train_pa100k, train_pa100k_only_img_classifier
from reTools import evaluation, mAP
from reTools import evaluation_attr, itm_eval_attr
from reTools import evaluation_attr_only_img_classifier, itm_eval_attr_only_img_classifier
config_reader = lambda file: yaml.load(open(file, 'r'), Loader=yaml.Loader)
config_path = ROOT_PATH / "configs"
retrieval_mals_config = config_reader(config_path / 'Retrieval_gene.yaml')
config = retrieval_mals_config
config['vision_config'] = config_path / 'config_swinB_384.json'
config['text_encoder'] = 'bert-base-uncased'
config['text_config'] = config_path / 'config_bert.json'
config['image_root'] = IMAGE_PATH
config['test_file'] = CUHK_ANNO_PATH/'cuhk_test.json'
config['val_file'] = CUHK_ANNO_PATH/'cuhk_val.json'
config['train_file'] = [MALS_ANNO_PATH/'g_c_g_a_0_attrs.json']
print(config['eda'], config['LabelSmooth'])
model = APTM_Retrieval(config)
model.load_pretrained(
MODEL_PATH, config, is_eval=False
)
tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")
mask_generator = TextMaskingGenerator(tokenizer, config['mask_prob'], config['max_masks'],
config['skipgram_prb'], config['skipgram_size'],
config['mask_whole_word'])
import nltk; nltk.download('wordnet')
config['batch_size_train'] = 16
train_dataset, val_dataset, test_dataset = create_dataset('re_cuhk', config)
train_loader, _, _ = create_loader([train_dataset, val_dataset, test_dataset],
samplers=[None, None, None], #not use distributed mode
batch_size=[config['batch_size_train']] + [
config['batch_size_test']] * 2,
num_workers=[4, 4, 4], is_trains=[True, False, False],
collate_fns=[None, None, None])
train_batch = next(iter(train_loader)) #BATCHSIZE 16
sample = train_batch[0]
print('Batch is a tuple of length ', len(train_batch), '\n')
print('IMAGE: ', train_batch[0].shape)
print('CAPTION: ', len(train_batch[1]))
print('PERSON ID: ', len(train_batch[2]),)
print('LABEL ATTRIBUTE: ', train_batch[3].shape)
print('example text: ', train_batch[1][0], '\n')
print('example label vector:', train_batch[3][0])
Preprocess batch input before feeding into train model
from train_tools import mlm
model.cuda()
def preprocess(batch, device='cuda'):
(image, text, idx, label) = batch
image = image.to(device)
idx = idx.to(device)
text_input = tokenizer(text, padding='max_length', truncation=True, max_length=config['max_tokens'],
return_tensors="pt").to(device)
label = label.to(device)
attr = ['the person is a woman', 'the person is a man',
'the person is younger than 18 years old', 'the person is older than 18 years old',
'the person with short hair', 'the person with long hair',
'the person with a hat', 'the person without a hat',
'the person with a backpack', 'the person without a backpack',
'the person with a handbag', 'the person without a handbag',
'the person with a bag', 'the person without a bag',
'the person wears long sleeved upper clothes', 'the person wears short sleeved upper clothes',
'the person wears long dress or long pants', 'the person wears short dress or short pants',
'the person wears dress or skirt', 'the person wears pants or shorts',
'the person wears black upper clothes', 'the person does not wear black upper clothes',
'the person wears white upper clothes', 'the person does not wear white upper clothes',
'the person wears red upper clothes', 'the person does not wear red upper clothes',
'the person wears purple upper clothes', 'the person does not wear purple upper clothes',
'the person wears yellow upper clothes', 'the person does not wear yellow upper clothes',
'the person wears blue upper clothes', 'the person does not wear blue upper clothes',
'the person wears green upper clothes', 'the person does not wear green upper clothes',
'the person wears gray upper clothes', 'the person does not wear gray upper clothes',
'the person wears black lower clothes', 'the person does not wear black lower clothes',
'the person wears white lower clothes', 'the person does not wear white lower clothes',
'the person wears purple lower clothes', 'the person does not wear purple lower clothes',
'the person wears yellow lower clothes', 'the person does not wear yellow lower clothes',
'the person wears blue lower clothes', 'the person does not wear blue lower clothes',
'the person wears green lower clothes', 'the person does not wear green lower clothes',
'the person wears pink lower clothes', 'the person does not wear pink lower clothes',
'the person wears gray lower clothes', 'the person does not wear gray lower clothes',
'the person wears brown lower clothes', 'the person does not wear brown lower clothes',
]
attr_input = tokenizer(attr, padding='longest', max_length=config['max_tokens'],
return_tensors="pt").to(device)
text_ids_masked, masked_pos, masked_ids = mlm(text, text_input, tokenizer, device, mask_generator,
config)
attr_text_ids_masked, attr_masked_pos, attr_masked_ids = mlm(attr, attr_input, tokenizer, device,
mask_generator, config, True)
return {
"image": image,
"text_ids_masked": text_ids_masked,
"masked_pos": masked_pos,
"text_ids": text_input.input_ids,
"text_atts": text_input.attention_mask,
"masked_ids": masked_ids,
"idx": idx,
"attr_text_ids": attr_input.input_ids,
"attr_text_atts": attr_input.attention_mask,
"attr_text_ids_masked": attr_text_ids_masked,
"attr_masked_pos": attr_masked_pos,
"attr_masked_ids": attr_masked_ids,
"label": label
}
preprocessed_batch = preprocess(train_batch)
Feed data into train model
model.eval()
model.cuda()
with torch.no_grad():
(loss_itc, loss_itm, loss_mlm, loss_attr) = res = model(**preprocessed_batch)
del preprocessed_batch
from torchview import draw_graph
model_graph = draw_graph(model, input_data=preprocessed_batch, device='cuda', expand_nested=True, graph_name='APTM', save_graph=True, filename='APTM_architecture.svg', directory='architecture_image')