Project: 068_Two_Effects_One_Trigger_On_the_Modality_Gap_Object | Function: inter_intra_cossine_sims (iclr)

system: You are an expert Python programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow Python best practices and maintain consistent code style.
Return **only** the complete Python function code.

user: Complete this Python function:

**DESCRIPTION:** Implements the core computation for MOAD (Matching Object Attribute Distance) by calculating intra-class and inter-class cosine similarities for measuring object vs attribute bias in embeddings

**KEY TERMS:** {
  "intra_sims_batched": "sim⁺ (matching similarities)",
  "cross_sims_batched": "sim⁻ (non-matching similarities)",
  "all_features": "L2-normalized embeddings",
  "labels": "object or attribute classes"
}

**CONTEXT CODE:** from functools import partial
import torch
from pathlib import Path
import open_clip
import os
from tqdm import tqdm
import json

from data_loaders import CompositionDataset
from settings import MIT_STATES_DIR, UT_ZAPPOS_DIR

@torch.no_grad()
def compute_accuracy(preds: torch.Tensor, labels: torch.Tensor) -> float:
    return (torch.sum(preds==labels) / preds.size(0)).item()*100

@torch.no_grad()
def inter_intra_cossine_sims(all_features, all_cls_labels=None, all_att_mat_bool=None):
    '''
    all_features: (batch, dunn_idx_img_cls)
    all_cls_labels: (batch, ) class labels
    all_att_mat_bool: (batch, nr_individual attributes ) (ie. sinlge column for example red and green, not a general color column)

    use either all_cls_labels or all_att_mat_bool
    '''
    raise NotImplementedError("Function implementation has been masked for testing")
    
@torch.no_grad()
def encode_clip(model, loader, tokenizer, prompts=None):
    device = next(model.parameters()).device

    with torch.amp.autocast(device_type=device.type):
        all_image_features, labels = [], []
        attr_labels, attr_label = [], None
        for batch in tqdm(loader, leave=False, total=len(loader)):
            if len(batch) == 3:
                inputs, attr_label, label = batch
            else:
                raise NotImplementedError
            if isinstance(inputs, tuple):
                inputs = torch.stack(inputs, dim=0)
            
            image_features = model.encode_image(inputs.to(device))        
            image_features /= image_features.norm(dim=-1, keepdim=True)
            all_image_features.append(image_features.cpu())

            labels.append(label)
            attr_labels.append(attr_label)
        
        all_image_features = torch.cat(all_image_features, dim=0)

        if prompts is not None:
            labels = torch.cat(labels, dim=0)
            text = tokenizer(prompts).to(device)
            try:
                text_features = model.encode_text(text.to(device)).cpu()
            except Exception:
                text_features = []
                for t in text:
                    text_features.append(model.encode_text(t.unsqueeze(0)).cpu())
                text_features = torch.cat(text_features, dim=0)
            text_features /= text_features.norm(dim=-1, keepdim=True)
            attr_labels = torch.cat(attr_labels, dim=0)
            return all_image_features, text_features, labels, attr_labels
        else:
            raise NotImplementedError

def main(args):
    args.output_dir = Path(args.output_dir) / "performance_vs_object_bias"
    os.makedirs(args.output_dir, exist_ok=True)
    
    model_name, pretrain_dataset = args.model.split("__")
    model, _, preprocess = open_clip.create_model_and_transforms(model_name, pretrained=pretrain_dataset, cache_dir=args.cache_dir)
    tokenizer = open_clip.get_tokenizer(model_name)
    model = model.to(args.device)
    model.eval()
    tokenizer = partial(tokenizer, context_length=model.context_length)

    datasets = ["mit-states", "ut-zappos"] if args.dataset == "all" else [args.dataset]

    for dataset in datasets:
        print(5*"#", dataset, 5*"#")
        if "mit-states" in dataset or "ut-zappos" == dataset:   
            if "mit-states" in dataset:
                root = MIT_STATES_DIR
            elif "ut-zappos" == dataset:
                root = UT_ZAPPOS_DIR
            else:
                raise NotImplementedError
            data = CompositionDataset(root=root, split="test", transform=preprocess, also_return_obj_label=True)
            loader = torch.utils.data.DataLoader(
                data,
                batch_size=args.batch_size,
                shuffle=False,
                num_workers=4,
                pin_memory=False,
            )
            prompts = [f"an image of a {attr.lower().replace('.', ' ')} object" for attr in data.attr2idx.keys()]
        else:
            raise NotImplementedError
        
        dataset_model_str = f"{dataset}_{args.model}"

        if not args.regenerate and os.path.isfile(args.output_dir / f"{dataset_model_str}.json"):
            if dataset == datasets[-1]:
                return
            continue

        if not args.regenerate and os.path.isfile(args.output_dir / f"{dataset_model_str}_img_feats.pth") and os.path.isfile(args.output_dir / f"{dataset_model_str}_txt_feats.pth"):
            image_features = torch.load(args.output_dir / f"{dataset_model_str}_img_feats.pth", map_location="cpu")
            text_features = torch.load(args.output_dir / f"{dataset_model_str}_txt_feats.pth", map_location="cpu")
            if os.path.isfile(args.output_dir / f"{dataset_model_str}_obj_labels.pth"):
                obj_labels = torch.load(args.output_dir / f"{dataset_model_str}_obj_labels.pth", map_location="cpu")
            if os.path.isfile(args.output_dir / f"{dataset_model_str}_attr_labels.pth"):
                attr_labels = torch.load(args.output_dir / f"{dataset_model_str}_attr_labels.pth", map_location="cpu")
        else:
            if "mit-states" in dataset or "ut-zappos" == dataset:


Complete the function implementation replacing "raise NotImplementedError".