{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":6799,"databundleVersionId":4225553,"sourceType":"competition"},{"sourceId":4886313,"sourceType":"datasetVersion","datasetId":2833220},{"sourceId":10858687,"sourceType":"datasetVersion","datasetId":6745165},{"sourceId":10858826,"sourceType":"datasetVersion","datasetId":6745275}],"dockerImageVersionId":30919,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install faiss-gpu","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-07T17:52:13.422932Z","iopub.status.idle":"2025-03-07T17:52:13.423228Z","shell.execute_reply":"2025-03-07T17:52:13.423111Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torchvision.transforms as transforms\nimport torchvision.datasets as datasets\nimport torchvision.models as models\nfrom torch.utils.data import DataLoader\nfrom torchvision.datasets.folder import default_loader\nimport faiss\nimport numpy as np\nimport math\nimport pandas as pd\nimport os\nfrom tqdm import tqdm","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-07T15:14:21.245772Z","iopub.execute_input":"2025-03-07T15:14:21.246028Z","iopub.status.idle":"2025-03-07T15:14:27.491069Z","shell.execute_reply.started":"2025-03-07T15:14:21.246005Z","shell.execute_reply":"2025-03-07T15:14:27.490351Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Paths based on Kaggle directory structure\ntrain_dir = \"/kaggle/input/imagenet-object-localization-challenge/ILSVRC/Data/CLS-LOC/train\"\ndataset_path = \"/kaggle/input/imagenet-validation-dataset\"\n\n# Define image transformations\ntransform = transforms.Compose([\n    transforms.Resize(256),\n    transforms.CenterCrop(224),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), \n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-07T15:15:53.995113Z","iopub.execute_input":"2025-03-07T15:15:53.995535Z","iopub.status.idle":"2025-03-07T15:15:54.000461Z","shell.execute_reply.started":"2025-03-07T15:15:53.995504Z","shell.execute_reply":"2025-03-07T15:15:53.999587Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load datasets\ntrain_dataset = datasets.ImageFolder(train_dir, transform=transform)\nval_dataset_full = datasets.ImageFolder(root=dataset_path, transform=transform)\nval_dataset_centroids = torch.utils.data.Subset(val_dataset_full, range(10000))\nval_dataset_properties = torch.utils.data.Subset(val_dataset_full, range(50000))\n\n# Create DataLoaders\ntrain_loader = DataLoader(train_dataset, batch_size=256, shuffle=True, num_workers=4)\nval_loader_centroids = DataLoader(val_dataset_centroids, batch_size=256, shuffle=False, num_workers=4)\nval_loader_properties = DataLoader(val_dataset_properties, batch_size=256, shuffle=False, num_workers=4)\n\nprint(f\"Training samples: {len(train_dataset)}, Validation (Centroids) samples: {len(val_dataset_centroids)}, Validation (Properties) samples: {len(val_dataset_properties)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-07T15:23:21.615246Z","iopub.execute_input":"2025-03-07T15:23:21.615681Z","iopub.status.idle":"2025-03-07T15:58:11.223212Z","shell.execute_reply.started":"2025-03-07T15:23:21.61565Z","shell.execute_reply":"2025-03-07T15:58:11.222366Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load model\nfeature_extractor = torch.hub.load('pytorch/vision:v0.10.0', 'resnet18', pretrained=True)\nfeature_extractor.fc = torch.nn.Identity()\nfeature_extractor.eval().to(\"cuda\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-07T16:08:56.317062Z","iopub.execute_input":"2025-03-07T16:08:56.317527Z","iopub.status.idle":"2025-03-07T16:08:58.57492Z","shell.execute_reply.started":"2025-03-07T16:08:56.317477Z","shell.execute_reply":"2025-03-07T16:08:58.574218Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Extract training features\nprint(\"Extracting training features...\")\ntrain_features, train_labels = [], []\nwith torch.no_grad():\n    for images, labels in tqdm(train_loader, desc='Extracting Training Features'):\n        images = images.to(\"cuda\")\n        features = feature_extractor(images).cpu().numpy()\n        train_features.append(features)\n        train_labels.append(labels.numpy())\ntrain_features = np.vstack(train_features)\ntrain_labels = np.concatenate(train_labels)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-07T16:09:11.068994Z","iopub.execute_input":"2025-03-07T16:09:11.069315Z","iopub.status.idle":"2025-03-07T17:36:41.824206Z","shell.execute_reply.started":"2025-03-07T16:09:11.069292Z","shell.execute_reply":"2025-03-07T17:36:41.82283Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Extract validation features\nval_features, val_labels = [], []\nwith torch.no_grad():\n    for images, labels in tqdm(val_loader_properties, desc='Extracting Validation Features'):\n        images = images.to(\"cuda\")\n        features = feature_extractor(images).cpu().numpy()\n        val_features.append(features)\n        val_labels.append(labels.numpy())\nval_features = np.vstack(val_features)\nval_labels = np.concatenate(val_labels)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-07T17:52:18.011602Z","iopub.execute_input":"2025-03-07T17:52:18.011933Z","iopub.status.idle":"2025-03-07T17:55:01.284899Z","shell.execute_reply.started":"2025-03-07T17:52:18.011906Z","shell.execute_reply":"2025-03-07T17:55:01.283669Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tqdm import tqdm\nimport faiss\nimport numpy as np\n\nprint(\"Training FAISS KMeans...\")\nd = train_features.shape[1]  # Feature dimension\nnum_clusters = 10000  # Keep your defined number of clusters\n\n# Initialize FAISS KMeans clustering\nkmeans = faiss.Kmeans(d, num_clusters, niter=20, verbose=True, gpu=True)\nkmeans.train(train_features)  # Train on training features\n\n# Assign clusters to training images\nprint(\"Clustering training images...\")\n_, train_clusters = kmeans.index.search(train_features, 1)\ntrain_clusters = train_clusters.flatten()  # Ensure proper shape\n\n# Assign clusters to validation images\nprint(\"Clustering validation images...\")\n_, val_clusters = kmeans.index.search(val_features, 1)\nval_clusters = val_clusters.flatten()  # Ensure proper shape\n\nprint(\"FAISS clustering complete.\")\n\n# Debugging: Check cluster assignments\nprint(\"Unique train clusters:\", np.unique(train_clusters))\nprint(\"Unique val clusters:\", np.unique(val_clusters))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-07T18:31:17.974233Z","iopub.execute_input":"2025-03-07T18:31:17.974585Z","iopub.status.idle":"2025-03-07T18:32:16.78363Z","shell.execute_reply.started":"2025-03-07T18:31:17.974551Z","shell.execute_reply":"2025-03-07T18:32:16.782621Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def compute_C(model, loader, device):\n    C_max = 0\n    model.eval()\n    with torch.no_grad():\n        for images, labels in tqdm(loader, desc=\"Computing C\"):\n            images, labels = images.to(device), labels.to(device)\n            outputs = model(images)\n            predictions = torch.argmax(outputs, dim=1)\n            loss = (predictions != labels).float()\n            C_max = max(C_max, loss.max().item())\n    return C_max\n\n\ndef compute_epsilon_Zi(val_clusters, val_labels, num_clusters):\n    global epsilon_S\n    epsilon_Zi = np.zeros(num_clusters)\n    for i in tqdm(range(num_clusters), desc=\"Computing epsilon_Zi\"):\n        indices = np.where(train_clusters == i)[0]\n        if len(indices) > 0:\n            cluster_loss = np.mean(train_labels[indices] != np.argmax(np.bincount(train_labels[indices])))\n            epsilon_Zi[i] = cluster_loss\n        epsilon_S = np.max(epsilon_Zi)\n    return epsilon_Zi\n\n\ndef compute_epsiloni_h(val_clusters, val_labels, num_clusters):\n    epsiloni_h = np.zeros(num_clusters)\n    for i in tqdm(range(num_clusters), desc=\"Computing epsiloni_h\"):\n        indices = np.where(train_clusters == i)[0]\n        if len(indices) > 0:\n            cluster_loss = np.mean(train_labels[indices] != np.argmax(np.bincount(train_labels[indices])))\n            epsiloni_h[i] = cluster_loss\n    return epsiloni_h\n\n\ndef compute_empirical_loss(train_clusters, train_labels, num_clusters):\n    total_loss = 0\n    for i in tqdm(range(num_clusters), desc=\"Computing empirical loss\"):\n        indices = np.where(train_clusters == i)[0]\n        if len(indices) > 0:\n            total_loss += np.mean(train_labels[indices] != np.argmax(np.bincount(train_labels[indices]))) * len(indices)\n    return total_loss / len(train_labels)\n\n\ndef compute_epsiloni_h_bar(val_clusters, val_labels, num_clusters):\n    epsiloni_h_bar = np.zeros(num_clusters)\n    for i in tqdm(range(num_clusters), desc=\"Computing epsiloni_h_bar\"):\n        indices = np.where(train_clusters == i)[0]\n        if len(indices) > 0:\n            epsiloni_h_bar[i] = np.mean(np.abs(train_labels[indices] - np.mean(train_labels[indices])))\n    return epsiloni_h_bar\n\n\ndef compute_ai_h(val_clusters, val_labels, num_clusters):\n    ai_h = np.zeros(num_clusters)\n    for i in tqdm(range(num_clusters), desc=\"Computing ai_h\"):\n        indices = np.where(train_clusters == i)[0]\n        if len(indices) > 0:\n            ai_h[i] = np.mean(np.abs(train_labels[indices] - np.mean(train_labels[indices])))\n    return ai_h","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-07T18:58:36.515461Z","iopub.execute_input":"2025-03-07T18:58:36.515847Z","iopub.status.idle":"2025-03-07T18:58:36.527301Z","shell.execute_reply.started":"2025-03-07T18:58:36.515814Z","shell.execute_reply":"2025-03-07T18:58:36.526295Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from collections import Counter\nfrom tqdm import tqdm\nimport numpy as np\nimport math\nimport torch\n\ndef run_experiment():\n\n    print(\"Computing properties...\")\n\n    # Compute properties with progress bars\n    print(\"Computing supremum 0-1 loss (C)...\")\n    C = compute_C(feature_extractor, val_loader_properties, device=\"cuda\")\n    \n    print(\"Computing epsilon_Zi...\")\n    epsilon_Zi = compute_epsilon_Zi(train_clusters, train_labels, num_clusters)\n    \n    epsilon_S = np.max(epsilon_Zi)\n\n    print(\"Computing epsiloni_h...\")\n    epsiloni_h = compute_epsiloni_h(train_clusters, train_labels, num_clusters)\n    \n    print(\"Computing empirical loss F_S_h...\")\n    F_S_h = compute_empirical_loss(train_clusters, train_labels, num_clusters)\n    \n    print(\"Computing epsiloni_h_bar...\")\n    epsiloni_h_bar = compute_epsiloni_h_bar(train_clusters, train_labels, num_clusters)\n    \n    print(\"Computing a_i_h...\")\n    a_i_h = compute_ai_h(train_clusters, train_labels, num_clusters)\n    \n    # Compute bounds\n    delta = 0.01\n    T_S = 10000\n    n = len(val_dataset_properties)\n    cluster_counts = Counter(train_clusters)\n    cluster_freqs = np.array([cluster_counts.get(i, 0) / n for i in range(num_clusters)])\n    \n    print(\"Computing bound g2...\")\n    g2 = C * (math.sqrt(2) + 1) * math.sqrt((T_S * math.log(2 * num_clusters / delta)) / n + (2 * C * T_S * math.log(2 * num_clusters / delta)) / n)\n\n    print(\"Computing bound 6...\")\n    bound_6 = g2 + F_S_h + np.sum(cluster_freqs * epsiloni_h)\n    \n    print(\"Computing bound 2...\")\n    bound_2 = g2 + F_S_h + epsilon_S\n    \n    print(\"Computing bound 7...\")\n    bound_7 = g2 + F_S_h + np.sum(cluster_freqs * epsiloni_h_bar)\n    \n    print(\"Computing bound 8...\")\n    bound_8 = g2 + np.sum(cluster_freqs * a_i_h)\n\n    # Print results\n    print(f\"Bound 2: {bound_2}\")\n    print(f\"Bound 6: {bound_6}\")\n    print(f\"Bound 7: {bound_7}\")\n    print(f\"Bound 8: {bound_8}\")\n    print(f\"Supremum 0-1 loss C: {C}\")\n    print(f\"Epsilon_S: {epsilon_S}\")\n    print(f\"Mean epsiloni_h: {np.mean(epsiloni_h)}\")\n    print(f\"g2: {g2}\")\n    print(f\"F_S_h: {F_S_h}\")\n    print(f\"epsiloni_h_bar: {epsiloni_h_bar}\")\n    print(f\"a_i_h: {a_i_h}\")\n\nrun_experiment()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-07T18:58:39.168782Z","iopub.execute_input":"2025-03-07T18:58:39.169106Z","iopub.status.idle":"2025-03-07T19:02:11.846877Z","shell.execute_reply.started":"2025-03-07T18:58:39.169081Z","shell.execute_reply":"2025-03-07T19:02:11.845865Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Train cluster distribution:\", np.bincount(train_clusters))\nprint(\"Validation cluster distribution:\", np.bincount(val_clusters))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-07T18:45:43.174799Z","iopub.execute_input":"2025-03-07T18:45:43.175154Z","iopub.status.idle":"2025-03-07T18:45:43.184482Z","shell.execute_reply.started":"2025-03-07T18:45:43.175128Z","shell.execute_reply":"2025-03-07T18:45:43.18359Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}