{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.10","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":23823,"databundleVersionId":1920183,"sourceType":"competition"},{"sourceId":1983975,"sourceType":"datasetVersion","datasetId":1182793},{"sourceId":2165946,"sourceType":"datasetVersion","datasetId":1300160},{"sourceId":2182061,"sourceType":"datasetVersion","datasetId":1136931},{"sourceId":2188154,"sourceType":"datasetVersion","datasetId":1313589},{"sourceId":2194412,"sourceType":"datasetVersion","datasetId":1317588},{"sourceId":2211395,"sourceType":"datasetVersion","datasetId":1325931},{"sourceId":2211693,"sourceType":"datasetVersion","datasetId":1328208},{"sourceId":2211791,"sourceType":"datasetVersion","datasetId":1328270},{"sourceId":2211937,"sourceType":"datasetVersion","datasetId":1328360},{"sourceId":2214724,"sourceType":"datasetVersion","datasetId":1330046},{"sourceId":3075714,"sourceType":"datasetVersion","datasetId":849808},{"sourceId":11920265,"sourceType":"datasetVersion","datasetId":7494043},{"sourceId":12069073,"sourceType":"datasetVersion","datasetId":7596830},{"sourceId":12076621,"sourceType":"datasetVersion","datasetId":7601990},{"sourceId":12076657,"sourceType":"datasetVersion","datasetId":7602018},{"sourceId":12126734,"sourceType":"datasetVersion","datasetId":7635997},{"sourceId":12127290,"sourceType":"datasetVersion","datasetId":7636434}],"dockerImageVersionId":30097,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!mkdir -p /root/.cache/torch/hub/checkpoints\n!cp -r ../input/landmark-additional-packages/rwightman_gen-efficientnet-pytorch_master/rwightman_gen-efficientnet-pytorch_master /root/.cache/torch/hub\n!cp ../input/landmark-additional-packages/tf_efficientnet_b3_aa-84b4657e.pth /root/.cache/torch/hub/checkpoints/\n!cp ../input/landmark-additional-packages/tf_efficientnet_b5_ra-9a3e5369.pth /root/.cache/torch/hub/checkpoints/\n!cp ../input/landmark-additional-packages/se_resnext50_32x4d-a260b3a4.pth /root/.cache/torch/hub/checkpoints/\n!cp ../input/landmark-additional-packages/resnet50d_ra2-464e36ba.pth /root/.cache/torch/hub/checkpoints/","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T09:34:58.357049Z","iopub.execute_input":"2025-06-16T09:34:58.357537Z","execution_failed":"2025-06-16T09:34:31.528Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#!pip install \"../input/landmark-additional-packages/EfficientNet-PyTorch/EfficientNet-PyTorch-master\" # sucess\n","metadata":{"trusted":true,"execution":{"execution_failed":"2025-06-16T09:34:31.529Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"## 安装关键包，从你拥有的 input 路径中提取\n\n#!pip install \"../input/landmark-additional-packages/pycocotools-2.0.2/dist/pycocotools-2.0.2.tar\"  #success","metadata":{"trusted":true,"execution":{"execution_failed":"2025-06-16T09:34:31.529Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#!pip install \"../input/landmark-additional-packages/faiss_gpu-1.7.0-cp37-cp37m-manylinux2014_x86_64.whl\" #may fail\n#!pip install \"../input/landmark-additional-packages/pytorch_zoo-master\" # mayfail","metadata":{"trusted":true,"execution":{"execution_failed":"2025-06-16T09:34:31.529Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#!ls ../input/landmark-additional-packages/\n","metadata":{"trusted":true,"execution":{"execution_failed":"2025-06-16T09:34:31.529Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#!pip install \"../input/landmark-additional-packages/timm-0.3.4-py3-none-any.whl\" # already in the system\n#!pip install \"../input/landmark-additional-packages/geffnet-1.0.0-py3-none-any.whl\" # already in the system","metadata":{"trusted":true,"execution":{"execution_failed":"2025-06-16T09:34:31.529Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#!pip install \"../input/landmark-additional-packages/pretrainedmodels-0.7.4/pretrainedmodels-0.7.4\" # success","metadata":{"trusted":true,"execution":{"execution_failed":"2025-06-16T09:34:31.529Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# the raw data has\n#!pip install -q ../input/landmark-additional-packages/timm-0.3.4-py3-none-any.whl\n#!pip install -q ../input/landmark-additional-packages/geffnet-1.0.0-py3-none-any.whl\n#!pip install -q ../input/landmark-additional-packages/EfficientNet-PyTorch/EfficientNet-PyTorch-master\n#!pip install -q ../input/landmark-additional-packages/pycocotools-2.0.2/dist/pycocotools-2.0.2.tar\n#!pip install -q ../input/landmark-additional-packages/pretrainedmodels-0.7.4/pretrainedmodels-0.7.4","metadata":{"trusted":true,"execution":{"execution_failed":"2025-06-16T09:34:31.529Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# the raw data has\n#!pip install \"/kaggle/input/hpamisc/pytorch_zoo-master\"\n#!pip install \"/kaggle/input/hpamisc/pycocotools-2.0-cp37-cp37m-linux_x86_64.whl\"\n#!pip install \"/kaggle/input/hpamisc/faiss_gpu-1.7.0-cp37-cp37m-manylinux2014_x86_64.whl\"","metadata":{"trusted":true,"execution":{"execution_failed":"2025-06-16T09:34:31.53Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#!pip install \"../input/landmark-additional-packages/timm-0.4.12-py3-none-any.whl\"\n","metadata":{"trusted":true,"execution":{"execution_failed":"2025-06-16T09:34:31.53Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#! python ../input/maozi-no-arcface/maozi_no_arcface.py","metadata":{"trusted":true,"execution":{"execution_failed":"2025-06-16T09:34:31.53Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# new model","metadata":{}},{"cell_type":"markdown","source":"final permission: 给定一张单细胞图像，预测像素级别的结构类型（即每个像素属于哪个 class）","metadata":{}},{"cell_type":"code","source":"import os\nimport torch\nimport pandas as pd\nfrom PIL import Image\nimport numpy as np\nfrom torch.utils.data import Dataset\n\nclass WeakSupervisionSegDataset(Dataset):\n    def __init__(self, csv_path, image_dir, mask_dir, image_size=(224, 224), num_classes=19):\n        self.df = pd.read_csv(csv_path)\n\n        # 保障字段存在\n        if 'confidence' in self.df.columns:\n            self.df['confidence'] = pd.to_numeric(self.df['confidence'], errors='coerce').fillna(0.0)\n        else:\n            self.df['confidence'] = 0.0\n\n        self.image_dir = image_dir\n        self.mask_dir = mask_dir\n        self.image_size = image_size\n        self.num_classes = num_classes\n\n        # 按照 cell_id 分组\n        self.cells = self.df.groupby(['image_id', 'cell_id']).apply(lambda x: x.to_dict('records')).reset_index(name='records')\n\n    def __len__(self):\n        return len(self.cells)\n\n    def find_mask_for_cell(self, image_id, cell_id):\n        folder = os.path.join(self.mask_dir, image_id)\n        if not os.path.exists(folder):\n            return None, None\n        for fname in os.listdir(folder):\n            if fname.endswith(f'cell{cell_id}.png'):\n                class_id = int(fname.split('class')[1].split('_')[0])\n                return os.path.join(folder, fname), class_id\n        return None, None\n\n    def __getitem__(self, idx):\n        records = self.cells.iloc[idx]['records']\n        image_id = records[0]['image_id']\n        cell_id = records[0]['cell_id']\n        filename = records[0]['filename']\n\n        image_path = os.path.join(self.image_dir, filename)\n        image = Image.open(image_path).convert('RGB').resize(self.image_size)\n        image = np.array(image).astype(np.float32) / 255.0\n        image = torch.from_numpy(image).permute(2, 0, 1)\n\n        # 初始化 mask 和 confidence\n        mask = torch.zeros((self.num_classes, *self.image_size), dtype=torch.uint8)\n        confidences = [0.0] * self.num_classes\n\n        # 尝试找到唯一真实 mask\n        mask_path, true_class_id = self.find_mask_for_cell(image_id, cell_id)\n\n        #print(f\"\\n当前 sample: {filename}\")\n        if mask_path is not None:\n            m = Image.open(mask_path).resize(self.image_size)\n            m = np.array(m) > 0\n\n            for r in records:\n                pred_class = int(r['pred_class'])\n                conf = float(r.get('confidence', 0.0))\n                mask[pred_class] = torch.from_numpy(m.astype(np.uint8))\n                confidences[pred_class] = conf\n\n                #print(f\"  - pred_class: {pred_class} | conf: {conf} | mask: {mask_path} True\")\n        else:\n            #print(f\" 无掩膜：{image_id}, cell{cell_id}\")\n            pass\n\n        return image, mask, confidences, {\n            'image_id': image_id,\n            'cell_id': cell_id,\n            'filename': filename\n        }\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T09:50:51.596248Z","iopub.execute_input":"2025-06-18T09:50:51.596689Z","iopub.status.idle":"2025-06-18T09:50:51.612682Z","shell.execute_reply.started":"2025-06-18T09:50:51.596649Z","shell.execute_reply":"2025-06-18T09:50:51.611381Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"dataset = WeakSupervisionSegDataset(\n    csv_path='/kaggle/input/weak-supervision-0-003/weak_supervision_labels_topk.csv',\n    image_dir='/kaggle/input/weak-supervision-0-003/cell_crops',\n    mask_dir='/kaggle/input/mmdetec-0-003/masks_thr05/masks_thr05'\n)\n\nimg, msk, confs, meta = dataset[1]\n\nprint(\"image shape:\", img.shape)\nprint(\"mask shape:\", msk.shape)\nprint(\"confidences:\", confs)\nprint(\"meta:\", meta)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T09:50:57.094987Z","iopub.execute_input":"2025-06-18T09:50:57.095353Z","iopub.status.idle":"2025-06-18T09:50:57.370447Z","shell.execute_reply.started":"2025-06-18T09:50:57.095322Z","shell.execute_reply":"2025-06-18T09:50:57.369332Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"因为cell crops只是认为的复制了不同的class。所以之哟有一样的image id和cell id，就拥有一样的mask。用这个逻辑找到mask的具体文件。","metadata":{}},{"cell_type":"markdown","source":"# Binary Mask ","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nfrom tqdm import tqdm\n\n# ✅ 路径设定\ncsv_path = '/kaggle/input/weak-supervision-0-003/weak_supervision_labels_topk.csv'\nsave_path = '/kaggle/working/class_presence_vectors.csv'  # 输出文件路径\n\n# ✅ 读取原始 CSV\ndf = pd.read_csv(csv_path)\n\n# ✅ 初始化输出列表\noutput = []\n\n# ✅ 聚合每个唯一 cell（image_id + cell_id）\ngrouped = df.groupby(['image_id', 'cell_id'])\n\n# ✅ 设置置信度阈值\nthreshold = 0.5\n\n# ✅ 构建向量\nfor (image_id, cell_id), group in tqdm(grouped, desc=\"🔧 构建 0/1 类别向量\"):\n    vec = [0] * 19\n    for _, row in group.iterrows():\n        pred_class = int(row['pred_class'])\n        conf = float(row['confidence'])\n        if conf >= threshold:\n            vec[pred_class] = 1\n    output.append({\n        'image_id': image_id,\n        'cell_id': cell_id,\n        'vector': vec\n    })\n\n# ✅ 转换为 DataFrame 并展开向量列\ndf_out = pd.DataFrame(output)\nvector_df = pd.DataFrame(df_out['vector'].to_list(), columns=[f'class_{i}' for i in range(19)])\nfinal_df = pd.concat([df_out[['image_id', 'cell_id']], vector_df], axis=1)\n\n# ✅ 保存结果\nfinal_df.to_csv(save_path, index=False)\nprint(f\"✅ 已保存 CSV 到: {save_path}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T09:51:10.2392Z","iopub.execute_input":"2025-06-18T09:51:10.239578Z","iopub.status.idle":"2025-06-18T09:51:10.667348Z","shell.execute_reply.started":"2025-06-18T09:51:10.239546Z","shell.execute_reply":"2025-06-18T09:51:10.666006Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\n# 读取 CSV\ncsv_path = '/kaggle/working/class_presence_vectors.csv'\ndf = pd.read_csv(csv_path)\n\n# 显示前 5 行\nprint(\"📋 前 5 行示例：\")\nprint(df.head())\n\n# 显示总行数 & 字段\nprint(f\"\\n✅ 总共 {len(df)} 个细胞，字段包括：\\n{df.columns.tolist()}\")\n\n# 检查每类（0-18）结构的出现频率（即有多少 cell 被标记为该类）\nprint(\"\\n📊 每类结构出现频率（1 的数量）：\")\nprint(df.iloc[:, 3:].sum())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T08:07:17.199906Z","iopub.execute_input":"2025-06-18T08:07:17.200287Z","iopub.status.idle":"2025-06-18T08:07:17.225334Z","shell.execute_reply.started":"2025-06-18T08:07:17.200255Z","shell.execute_reply":"2025-06-18T08:07:17.223861Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# pos_weight","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nimport torch\n\n# 读取你的 presence 向量文件\ncsv_path = '/kaggle/working/class_presence_vectors.csv'\ndf = pd.read_csv(csv_path)\n\n# 识别所有 class 字段（自动检测以 'class_' 开头的列）\nclass_cols = [col for col in df.columns if col.startswith('class_')]\n\n# 每一类结构的正样本数（即被标记为 1 的 cell 数量）\npos_counts = df[class_cols].sum().values  # shape: [19]\n\n# 每一类结构的负样本数（即被标记为 0 的 cell 数量）\nneg_counts = len(df) - pos_counts\n\n# 计算 pos_weight = neg / pos（防止除以0）\npos_weight = neg_counts / (pos_counts + 1e-5)\n\n# 打印每一类结构的出现频率\nprint(\"📊 每类结构的正样本数（1 的数量）：\")\nfor name, count in zip(class_cols, pos_counts):\n    print(f\"{name}: {int(count)} cells\")\n\n# 打印每一类的 pos_weight\nprint(\"\\n🧮 每类结构的 pos_weight：\")\nfor name, pw in zip(class_cols, pos_weight):\n    print(f\"{name}: {pw:.4f}\")\n\n# 转为 PyTorch tensor 并发送到设备\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n# 转为 tensor 并限制最大值（防止 loss 爆炸）\nmax_clip = 20.0  # 你可以根据经验设置为 10 或 20\nclipped_weights = torch.tensor(pos_weight, dtype=torch.float32)\nclipped_weights = torch.clamp(clipped_weights, max=max_clip).to(device)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T08:34:20.561664Z","iopub.execute_input":"2025-06-18T08:34:20.562234Z","iopub.status.idle":"2025-06-18T08:34:20.592173Z","shell.execute_reply.started":"2025-06-18T08:34:20.562191Z","shell.execute_reply":"2025-06-18T08:34:20.590952Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 构建 Dataset + DataLoader","metadata":{}},{"cell_type":"code","source":"from torch.utils.data import DataLoader, random_split\n\n# 构建数据集\ncsv_path = '/kaggle/input/weak-supervision-0-003/weak_supervision_labels_topk.csv'\nimage_dir = '/kaggle/input/weak-supervision-0-003/cell_crops'\nmask_dir = '/kaggle/input/mmdetec-0-003/masks_thr05/masks_thr05'\n\ndataset = WeakSupervisionSegDataset(csv_path, image_dir, mask_dir)\n\n# 划分训练 / 验证\ntrain_size = int(0.8 * len(dataset))\nval_size = len(dataset) - train_size\ntrain_dataset, val_dataset = random_split(dataset, [train_size, val_size])\n\ntrain_loader = DataLoader(train_dataset, batch_size=8, shuffle=True)\nval_loader = DataLoader(val_dataset, batch_size=8, shuffle=False)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T08:34:20.594161Z","iopub.execute_input":"2025-06-18T08:34:20.594582Z","iopub.status.idle":"2025-06-18T08:34:20.872255Z","shell.execute_reply.started":"2025-06-18T08:34:20.59453Z","shell.execute_reply":"2025-06-18T08:34:20.871037Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch.nn as nn\nloss_fn = nn.BCEWithLogitsLoss()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T08:34:20.874874Z","iopub.execute_input":"2025-06-18T08:34:20.875301Z","iopub.status.idle":"2025-06-18T08:34:20.879969Z","shell.execute_reply.started":"2025-06-18T08:34:20.875266Z","shell.execute_reply":"2025-06-18T08:34:20.878816Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch.nn as nn\nimport torch.nn.functional as F\n\nclass SimpleUNet(nn.Module):\n    def __init__(self, in_channels=3, out_channels=19):\n        super(SimpleUNet, self).__init__()\n\n        def conv_block(in_ch, out_ch):\n            return nn.Sequential(\n                nn.Conv2d(in_ch, out_ch, kernel_size=3, padding=1),\n                nn.BatchNorm2d(out_ch),\n                nn.LeakyReLU(inplace=True),\n                nn.Conv2d(out_ch, out_ch, kernel_size=3, padding=1),\n                nn.BatchNorm2d(out_ch),\n                nn.LeakyReLU(inplace=True)\n            )\n\n        self.enc1 = conv_block(in_channels, 64)\n        self.pool1 = nn.MaxPool2d(2)\n\n        self.enc2 = conv_block(64, 128)\n        self.pool2 = nn.MaxPool2d(2)\n\n        self.bottleneck = conv_block(128, 256)\n\n        self.up1 = nn.ConvTranspose2d(256, 128, 2, stride=2)\n        self.dec1 = conv_block(256, 128)\n\n        self.up2 = nn.ConvTranspose2d(128, 64, 2, stride=2)\n        self.dec2 = conv_block(128, 64)\n\n        self.final = nn.Conv2d(64, out_channels, kernel_size=1)\n\n    def forward(self, x):\n        e1 = self.enc1(x)\n        p1 = self.pool1(e1)\n\n        e2 = self.enc2(p1)\n        p2 = self.pool2(e2)\n\n        b = self.bottleneck(p2)\n\n        u1 = self.up1(b)\n        d1 = self.dec1(torch.cat([u1, e2], dim=1))\n\n        u2 = self.up2(d1)\n        d2 = self.dec2(torch.cat([u2, e1], dim=1))\n\n        out = self.final(d2)\n        return out\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T08:34:20.882115Z","iopub.execute_input":"2025-06-18T08:34:20.882583Z","iopub.status.idle":"2025-06-18T08:34:20.905107Z","shell.execute_reply.started":"2025-06-18T08:34:20.882534Z","shell.execute_reply":"2025-06-18T08:34:20.903757Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def dice_loss(pred, target, smooth=1.):\n    pred = torch.sigmoid(pred)\n    inter = (pred * target).sum(dim=(2,3))\n    union = pred.sum(dim=(2,3)) + target.sum(dim=(2,3))\n    return 1 - ((2 * inter + smooth) / (union + smooth)).mean()\n\nclass PixelWiseWeightedBCEDiceLoss(nn.Module):\n    def __init__(self, pos_weight):\n        super().__init__()\n        # 将 [19] 维的向量 reshape 成 [1, 19, 1, 1]，用于广播到 [B, 19, H, W]\n        self.pos_weight = pos_weight.view(1, -1, 1, 1)\n        self.bce_loss = nn.BCEWithLogitsLoss(reduction='none')\n\n    def forward(self, pred, target):\n        bce = self.bce_loss(pred, target)                         # [B, 19, H, W]\n        weighted_bce = bce * self.pos_weight.to(pred.device)     # 权重广播应用\n        bce_mean = weighted_bce.mean()\n        dice = dice_loss(pred, target)\n        return bce_mean + dice\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T08:34:20.906744Z","iopub.execute_input":"2025-06-18T08:34:20.907095Z","iopub.status.idle":"2025-06-18T08:34:20.921738Z","shell.execute_reply.started":"2025-06-18T08:34:20.90706Z","shell.execute_reply":"2025-06-18T08:34:20.9204Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\nmodel = SimpleUNet(in_channels=3, out_channels=19).to(device)\ncriterion = PixelWiseWeightedBCEDiceLoss(pos_weight=clipped_weights).to(device)\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-4)\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T08:34:20.92294Z","iopub.execute_input":"2025-06-18T08:34:20.923266Z","iopub.status.idle":"2025-06-18T08:34:20.969601Z","shell.execute_reply.started":"2025-06-18T08:34:20.923233Z","shell.execute_reply":"2025-06-18T08:34:20.968627Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tqdm import tqdm\n\nfor epoch in range(5):  # 测试跑 3 epoch\n    model.train()\n    running_loss = 0.0\n\n    # 用 tqdm 包装训练集 DataLoader\n    train_loader_tqdm = tqdm(train_loader, desc=f\"Epoch {epoch+1}\", leave=False)\n\n    for images, masks, _, _ in train_loader_tqdm:\n        images = images.to(device)\n        masks = masks.to(device).float()  # [B, 19, H, W]\n\n        outputs = model(images)  # [B, 19, H, W]\n\n        loss = criterion(outputs, masks)\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n\n        running_loss += loss.item()\n\n        # 📊 在 tqdm 的后缀显示当前 loss\n        train_loader_tqdm.set_postfix(loss=loss.item())\n\n    print(f\"✅ Epoch {epoch+1}, Total Loss: {running_loss:.4f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T08:38:22.07155Z","iopub.execute_input":"2025-06-18T08:38:22.071937Z","iopub.status.idle":"2025-06-18T09:45:53.752543Z","shell.execute_reply.started":"2025-06-18T08:38:22.071904Z","shell.execute_reply":"2025-06-18T09:45:53.749986Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"✅ Dataset 总样本数:\", len(dataset))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T08:37:35.307567Z","iopub.execute_input":"2025-06-18T08:37:35.307971Z","iopub.status.idle":"2025-06-18T08:37:35.313844Z","shell.execute_reply.started":"2025-06-18T08:37:35.307934Z","shell.execute_reply":"2025-06-18T08:37:35.312711Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# next","metadata":{}},{"cell_type":"code","source":"import torch\nimport torch.nn.functional as F\nimport matplotlib.pyplot as plt\n\ntarget_image_id = '5b931256-bb99-11e8-b2b9-ac1f6b6435d0'\nmodel.eval()\ncount = 0\n\nwith torch.no_grad():\n    for batch_idx, (images, masks, confidences, metas) in enumerate(val_loader):\n        images = images.to(device)\n        outputs = model(images)\n        probs = torch.sigmoid(outputs)  # [B, 19, H, W]\n        \n        for i in range(len(images)):\n            image_id = metas['image_id'][i]\n            if image_id != target_image_id:\n                continue  # 跳过不是目标图像的\n            \n            count += 1\n            meta = {\n                'image_id': image_id,\n                'cell_id': metas['cell_id'][i],\n                'filename': metas['filename'][i]\n            }\n\n            image_np = images[i].cpu().permute(1, 2, 0).numpy()\n            mask_np = masks[i].cpu().numpy()\n            prob_np = probs[i].cpu().numpy()\n\n            max_conf_per_class = prob_np.reshape(19, -1).max(axis=1)\n            topk = 3\n            top_classes = max_conf_per_class.argsort()[-topk:][::-1]\n            top_confs = max_conf_per_class[top_classes]\n\n            print(f\"\\n📌 image_id: {meta['image_id']}, cell_id: {meta['cell_id']}\")\n            for cls, conf in zip(top_classes, top_confs):\n                print(f\"  🔹 Class {cls}: max pixel confidence = {conf:.4f}\")\n\n            fig, axs = plt.subplots(1, topk + 1, figsize=(15, 5))\n            axs[0].imshow(image_np)\n            axs[0].set_title(\"Original Image\")\n            axs[0].axis('off')\n\n            for j, cls in enumerate(top_classes):\n                axs[j + 1].imshow(prob_np[cls], cmap='hot')\n                axs[j + 1].set_title(f'Class {cls} (conf: {top_confs[j]:.2f})')\n                axs[j + 1].axis('off')\n\n            plt.tight_layout()\n            plt.show()\n\nprint(f\"\\n✅ 共预测出 {count} 个 cell 属于图像 {target_image_id}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T09:47:06.893282Z","iopub.execute_input":"2025-06-18T09:47:06.893795Z","iopub.status.idle":"2025-06-18T09:48:05.005681Z","shell.execute_reply.started":"2025-06-18T09:47:06.893681Z","shell.execute_reply":"2025-06-18T09:48:05.004594Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\n# 加载 CSV\ncsv_path = '/kaggle/input/weak-supervision-0-003/weak_supervision_labels_topk.csv'\ndf = pd.read_csv(csv_path)\n\n# 筛选特定 image_id 的行\ntarget_image_id = '5b931256-bb99-11e8-b2b9-ac1f6b6435d0'\nsubset = df[df['image_id'] == target_image_id]\n\n# 获取 unique cell_id 数量\nunique_cell_ids = subset['cell_id'].nunique()\nprint(f\"🧪 图像 {target_image_id} 中共有 {unique_cell_ids} 个唯一 cell_id\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T09:48:05.032993Z","iopub.execute_input":"2025-06-18T09:48:05.033385Z","iopub.status.idle":"2025-06-18T09:48:05.050196Z","shell.execute_reply.started":"2025-06-18T09:48:05.033342Z","shell.execute_reply":"2025-06-18T09:48:05.048416Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 假设你已经有 val_dataset 和 image_id\ntarget_id = '5b931256-bb99-11e8-b2b9-ac1f6b6435d0'\nval_count = 0\nfor i in range(len(val_dataset)):\n    item = val_dataset[i]\n    if item[3]['image_id'] == target_id:\n        val_count += 1\n\nprint(f\"📊 在验证集中，图像 {target_id} 有 {val_count} 个 cell 被用于验证\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T09:48:29.251152Z","iopub.execute_input":"2025-06-18T09:48:29.251648Z","iopub.status.idle":"2025-06-18T09:48:36.153626Z","shell.execute_reply.started":"2025-06-18T09:48:29.251599Z","shell.execute_reply":"2025-06-18T09:48:36.152255Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"target_id = '5b931256-bb99-11e8-b2b9-ac1f6b6435d0'\ntrain_count = 0\nfor i in range(len(train_dataset)):\n    item = train_dataset[i]\n    if item[3]['image_id'] == target_id:\n        train_count += 1\n\nprint(f\"📊 在训练集中，图像 {target_id} 有 {train_count} 个 cell 被用于训练\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T09:48:36.15557Z","iopub.execute_input":"2025-06-18T09:48:36.15596Z","iopub.status.idle":"2025-06-18T09:49:04.266972Z","shell.execute_reply.started":"2025-06-18T09:48:36.155922Z","shell.execute_reply":"2025-06-18T09:49:04.26574Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\n# 载入 CSV 文件\ncsv_path = '/kaggle/input/weak-supervision-0-003/weak_supervision_labels_topk.csv'\ndf = pd.read_csv(csv_path)\n\n# 设定目标 image_id\ntarget_image_id = '5b931256-bb99-11e8-b2b9-ac1f6b6435d0'\n\n# 筛选出该图像的所有记录\ndf_target = df[df['image_id'] == target_image_id]\n\n# 唯一的 filename 数量\nunique_filenames = df_target['filename'].nunique()\n\n# 唯一的 (image_id, cell_id) 数量\nunique_cells = df_target[['image_id', 'cell_id']].drop_duplicates().shape[0]\n\n# 输出结果\nprint(f\"📁 图像 {target_image_id} 中有 {unique_filenames} 个唯一 filename\")\nprint(f\"🧫 图像 {target_image_id} 中有 {unique_cells} 个唯一 (image_id, cell_id) 组合（即不同细胞）\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T09:49:04.269147Z","iopub.execute_input":"2025-06-18T09:49:04.269649Z","iopub.status.idle":"2025-06-18T09:49:04.288028Z","shell.execute_reply.started":"2025-06-18T09:49:04.269598Z","shell.execute_reply":"2025-06-18T09:49:04.286973Z"}},"outputs":[],"execution_count":null}]}