huantran2004's picture
Upload 127 files
68efce6 verified
Raw
History Blame Contribute Delete
7.5 kB
# ── APViT repo path setup (must precede mmcls/mmcv imports) ─────────────────
import sys
from pathlib import Path as _Path
_apvit_path = str(_Path(__file__).resolve().parent.parent.parent / "APViT")
if _apvit_path not in sys.path:
sys.path.insert(0, _apvit_path)
# ─────────────────────────────────────────────────────────────────────────────
import pandas as pd
import os
import torch
import torchvision.transforms as transforms
from torch.utils.data import DataLoader, Dataset
import torch.nn as nn
from PIL import Image
from pathlib import Path
import mmcv
from mmcls.models import build_classifier
SCRIPT_DIR = Path(__file__).resolve().parent
MODEL_PATH = os.getenv("MODEL_PATH", str(SCRIPT_DIR / "model.pt"))
APVIT_REPO = SCRIPT_DIR.parent.parent / "APViT"
APVIT_CONFIG = APVIT_REPO / "configs" / "apvit" / "RAF.py"
def resolve_images_dir(split_name, explicit_env_var, data_root, extract_root):
explicit = os.getenv(explicit_env_var, "").strip()
candidates = []
if explicit:
candidates.append(Path(explicit))
candidates.append(Path(data_root) / f"{split_name}_set" / "images")
candidates.append(Path(extract_root) / f"{split_name}_extracted" / "images")
extract_split_root = Path(extract_root) / f"{split_name}_extracted"
if extract_split_root.exists():
for p in extract_split_root.rglob("images"):
if p.is_dir():
candidates.append(p)
for p in candidates:
if p.exists() and p.is_dir():
return str(p)
tried = "\n".join([str(p) for p in candidates])
raise FileNotFoundError(
f"Could not find images folder for split='{split_name}'. Tried:\n{tried}"
)
# Load the annotations for validation from CSV file
DATA_ROOT = os.getenv("AFFECTNET_ROOT", "/workspace/data_affectnet/AffectNet")
EXTRACT_ROOT = os.getenv("AFFECTNET_EXTRACT_ROOT", f"{DATA_ROOT}/extracted")
ANNO_ROOT = os.getenv("AFFECTNET_ANNO_ROOT", "../../affectnet_annotations")
IMAGE_FOLDER = resolve_images_dir("train", "AFFECTNET_TRAIN_IMAGES", DATA_ROOT, EXTRACT_ROOT)
IMAGE_FOLDER_TEST = resolve_images_dir("val", "AFFECTNET_VAL_IMAGES", DATA_ROOT, EXTRACT_ROOT)
valid_annotations_path = os.getenv(
"AFFECTNET_VAL_ANNO", f"{ANNO_ROOT}/val_set_annotation_without_lnd.csv"
)
valid_annotations_df = pd.read_csv(valid_annotations_path)
# Set parameters
BATCHSIZE = int(os.getenv("BATCHSIZE", "64"))
NUM_WORKERS = int(os.getenv("NUM_WORKERS", "0"))
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print("DATA_ROOT =", DATA_ROOT)
print("EXTRACT_ROOT =", EXTRACT_ROOT)
print("AFFECTNET_TRAIN_IMAGES =", IMAGE_FOLDER)
print("AFFECTNET_VAL_IMAGES =", IMAGE_FOLDER_TEST)
print("MODEL_PATH =", MODEL_PATH)
# **** Create dataset and data loaders ****
class CustomDataset(Dataset):
def __init__(self, dataframe, root_dir, transform=None, balance=False):
self.dataframe = dataframe
self.transform = transform
self.root_dir = root_dir
self.balance = balance
if self.balance:
self.dataframe = self.balance_dataset()
def __len__(self):
return len(self.dataframe)
def __getitem__(self, idx):
image_path = os.path.join(
self.root_dir, f"{self.dataframe['number'].iloc[idx]}.jpg"
)
if os.path.exists(image_path):
image = Image.open(image_path)
else:
image = Image.new(
"RGB", (112, 112), color="white"
) # Handle missing image file
classes = torch.tensor(self.dataframe["exp"].iloc[idx], dtype=torch.long)
labels = torch.tensor(self.dataframe.iloc[idx, 2:4].values, dtype=torch.float32)
if self.transform:
image = self.transform(image)
return image, classes, labels
def balance_dataset(self):
balanced_df = self.dataframe.groupby("exp", group_keys=False).apply(
lambda x: x.sample(self.dataframe["exp"].value_counts().min())
)
return balanced_df
transform_valid = transforms.Compose(
[
transforms.Resize(112), # APViT / IR-50 requires 112x112 input
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
]
)
valid_dataset = CustomDataset(
dataframe=valid_annotations_df,
root_dir=IMAGE_FOLDER_TEST,
transform=transform_valid,
balance=False,
)
valid_loader = DataLoader(
valid_dataset, batch_size=BATCHSIZE, shuffle=False, num_workers=NUM_WORKERS
)
# ***** Define the model *****
APVIT_EMBED_DIM = 768
def _build_apvit_backbone():
"""Build APViT PoolingVitClassifier (backbone only, no head)."""
cfg = mmcv.Config.fromfile(str(APVIT_CONFIG))
cfg.model.pretrained = None
cfg.model.head = None
ir50_w = APVIT_REPO / "weights" / "backbone_ir50_ms1m_epoch120.pth"
vit_small_w = APVIT_REPO / "weights" / "vit_small_p16_224-15ec54c9.pth"
cfg.model.extractor.pretrained = str(ir50_w) if ir50_w.exists() else None
cfg.model.vit.pretrained = str(vit_small_w) if vit_small_w.exists() else None
return build_classifier(cfg.model)
class APViTWithHead(nn.Module):
def __init__(self, num_outputs):
super().__init__()
self.apvit = _build_apvit_backbone()
self.head = nn.Sequential(
nn.LayerNorm(APVIT_EMBED_DIM),
nn.Linear(APVIT_EMBED_DIM, APVIT_EMBED_DIM),
nn.Tanh(),
nn.Linear(APVIT_EMBED_DIM, num_outputs, bias=False),
)
def forward(self, x):
features, _ = self.apvit.extract_feat(x) # [B, 768] CLS token
return self.head(features)
MODEL = APViTWithHead(num_outputs=10)
MODEL.to(DEVICE) # Put the model to the GPU
# Set the model to evaluation mode
if not Path(MODEL_PATH).exists():
raise FileNotFoundError(
f"Missing Combined checkpoint: {MODEL_PATH}. "
"Run train.py first or set MODEL_PATH to a valid checkpoint."
)
MODEL.load_state_dict(torch.load(MODEL_PATH, map_location=DEVICE))
MODEL.to(DEVICE)
MODEL.eval()
all_labels_cls = []
all_predicted_cls = []
all_true_val = []
all_pred_val = []
all_true_aro = []
all_pred_aro = []
# Start inference on test set
with torch.no_grad():
for images, classes, labels in iter(valid_loader):
images, classes, labels = (
images.to(DEVICE),
classes.to(DEVICE),
labels.to(DEVICE),
)
outputs = MODEL(images)
outputs_cls = outputs[:, :8]
outputs_reg = outputs[:, 8:]
val_pred = outputs_reg[:, 0]
aro_pred = outputs_reg[:, 1]
_, predicted_cls = torch.max(outputs_cls, 1)
all_labels_cls.extend(classes.cpu().numpy())
all_predicted_cls.extend(predicted_cls.cpu().numpy())
val_true = labels[:, 0]
aro_true = labels[:, 1]
all_true_val.extend(val_true.cpu().numpy())
all_true_aro.extend(aro_true.cpu().numpy())
all_pred_val.extend(val_pred.cpu().numpy())
all_pred_aro.extend(aro_pred.cpu().numpy())
df = pd.DataFrame(
{
"cat_pred": all_predicted_cls,
"cat_true": all_labels_cls,
"val_pred": all_pred_val,
"val_true": all_true_val,
"aro_pred": all_pred_aro,
"aro_true": all_true_aro,
}
)
df.to_csv("inference.csv", index=False)