{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceType":"competition","sourceId":8078,"databundleVersionId":862231},{"sourceType":"datasetVersion","sourceId":12353309,"datasetId":7788128,"databundleVersionId":12911718},{"sourceType":"datasetVersion","sourceId":12565234,"datasetId":7934793,"databundleVersionId":13155960},{"sourceType":"datasetVersion","sourceId":12603838,"datasetId":7885335,"databundleVersionId":13201327}],"dockerImageVersionId":31041,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Imports","metadata":{}},{"cell_type":"code","source":"# Data preprocessing\nimport numpy as np\nimport pandas as pd\nimport os\nimport shutil\nimport random\nimport time\nimport pickle\nfrom glob import glob\nfrom sklearn.preprocessing import LabelEncoder, StandardScaler\nfrom sklearn.model_selection import train_test_split\n\n# Torch\nimport torch\nfrom torch import nn\nimport torch.nn.functional as F\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision.utils import save_image\nfrom torch import optim\n\nfrom torchvision import transforms,models\nfrom torchinfo import summary\n\n# Visualizing\nfrom tqdm.auto import tqdm\nimport matplotlib.pyplot as plt\nfrom PIL import Image\nimport cv2\nimport math","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:34.807260Z","iopub.execute_input":"2025-07-28T22:24:34.807530Z","iopub.status.idle":"2025-07-28T22:24:34.812775Z","shell.execute_reply.started":"2025-07-28T22:24:34.807511Z","shell.execute_reply":"2025-07-28T22:24:34.811989Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Import model weights","metadata":{}},{"cell_type":"code","source":"epochs = glob('/kaggle/input/model-checkpoint/*')\nepochs = sorted(epochs, key=lambda x: int(x.split('_')[-1]))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:26:07.617104Z","iopub.execute_input":"2025-07-28T22:26:07.617378Z","iopub.status.idle":"2025-07-28T22:26:07.621677Z","shell.execute_reply.started":"2025-07-28T22:26:07.617358Z","shell.execute_reply":"2025-07-28T22:26:07.621061Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"input_base = '/kaggle/input/model-checkpoint'\noutput_base = '/kaggle/working'\n\nfor epoch in tqdm(epochs, desc='Copying Folders'):\n    epoch_x = epoch.split('/')[-1]\n    destination = os.path.join(output_base, epoch_x)\n\n    if os.path.exists(destination):\n        #print(f\"Skipping {epoch_x} — already exists.\")\n        continue\n\n    source = os.path.join(input_base, epoch_x)\n    shutil.copytree(source, destination, dirs_exist_ok=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:36.599990Z","iopub.execute_input":"2025-07-28T22:24:36.600297Z","iopub.status.idle":"2025-07-28T22:24:36.616012Z","shell.execute_reply.started":"2025-07-28T22:24:36.600277Z","shell.execute_reply":"2025-07-28T22:24:36.615240Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"workers = 2\nisCuda = True\ndevice = torch.device(\"cuda:0\" if (torch.cuda.is_available() and isCuda) else \"cpu\")\ntorch.backends.cudnn.benchmark = True\nprint(\"Device: {}\".format(device))\n\nmodel_saved_dir = \"/kaggle/working\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:38.250228Z","iopub.execute_input":"2025-07-28T22:24:38.251043Z","iopub.status.idle":"2025-07-28T22:24:38.255731Z","shell.execute_reply.started":"2025-07-28T22:24:38.251017Z","shell.execute_reply":"2025-07-28T22:24:38.254909Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Model Initializations","metadata":{}},{"cell_type":"code","source":"seed = 42\nrandom.seed(seed)\ntorch.manual_seed(seed)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:40.606958Z","iopub.execute_input":"2025-07-28T22:24:40.607516Z","iopub.status.idle":"2025-07-28T22:24:40.613741Z","shell.execute_reply.started":"2025-07-28T22:24:40.607494Z","shell.execute_reply":"2025-07-28T22:24:40.613114Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# StarGAN v2 Hyperparameters\n\nnf = 64             # Base number of filters in Generator/Discriminator\nnd = 10             # Number of domains (camera classes)\nsdim = 64           # Dimension of style code (output of Style Encoder)\n\n# Loss weights\nlambda_gp  = 1.     # Gradient penalty for discriminator\nlambda_sty = 1.     # Style consistency loss\nlambda_ds  = 1.      # Diversity sensitive loss\nlambda_cyc = 1.     # Cycle consistency loss\n\n# Optimizer settings\nlr = 1e-4           # Learning rate for G, D, E\nbetas = (0.0, 0.99) # Adam optimizer betas\nweight_decay = 1e-4 # Weight decay for regularization\n\n# Training loop settings\nbatch_size   = 4    # Batch size\nepochs       = 30   # Total number of training epochs\nds_epochs    = 5    # Epochs after which diversity-sensitive loss is annealed to 0\nn_print      = 100  # Print loss after every n iterations\nn_img_save   = 2000 # Generate images after every n iterations\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:42.031279Z","iopub.execute_input":"2025-07-28T22:24:42.031875Z","iopub.status.idle":"2025-07-28T22:24:42.036497Z","shell.execute_reply.started":"2025-07-28T22:24:42.031854Z","shell.execute_reply":"2025-07-28T22:24:42.035713Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Weight initializations\ndef init_conv_weight(m):\n    if isinstance(m, nn.Conv2d):\n        nn.init.kaiming_uniform_(m.weight)\n        if m.bias is not None:\n            nn.init.constant_(m.bias, 0.)\n\ndef init_fc_weight_zero(m):\n    if isinstance(m, nn.Linear):\n        nn.init.kaiming_uniform_(m.weight)\n        nn.init.constant_(m.bias, 0.)\n\ndef init_fc_weight_one(m):\n    if isinstance(m, nn.Linear):\n        nn.init.kaiming_uniform_(m.weight)\n        nn.init.constant_(m.bias, 1.)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:43.388743Z","iopub.execute_input":"2025-07-28T22:24:43.389250Z","iopub.status.idle":"2025-07-28T22:24:43.393925Z","shell.execute_reply.started":"2025-07-28T22:24:43.389227Z","shell.execute_reply":"2025-07-28T22:24:43.393139Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Dataset & DataLoader","metadata":{}},{"cell_type":"code","source":"img_path = glob('/kaggle/input/ieee-sp-cup-camera-model-identification-dataset/*/*')\nprint(f\"Image Loaded: {len(img_path)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:44.480479Z","iopub.execute_input":"2025-07-28T22:24:44.481228Z","iopub.status.idle":"2025-07-28T22:24:44.573796Z","shell.execute_reply.started":"2025-07-28T22:24:44.481205Z","shell.execute_reply":"2025-07-28T22:24:44.573196Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.DataFrame(img_path,columns=['image_path'])\ndf['camera_model'] = df['image_path'].apply(lambda x: x.split('/')[-2])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:45.063641Z","iopub.execute_input":"2025-07-28T22:24:45.063935Z","iopub.status.idle":"2025-07-28T22:24:45.100981Z","shell.execute_reply.started":"2025-07-28T22:24:45.063914Z","shell.execute_reply":"2025-07-28T22:24:45.100218Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:46.113123Z","iopub.execute_input":"2025-07-28T22:24:46.113411Z","iopub.status.idle":"2025-07-28T22:24:46.121717Z","shell.execute_reply.started":"2025-07-28T22:24:46.113392Z","shell.execute_reply":"2025-07-28T22:24:46.121100Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"le = LabelEncoder()\ndf['camera_model'] = le.fit_transform(df['camera_model'])\ndf['camera_model'].value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:46.798563Z","iopub.execute_input":"2025-07-28T22:24:46.799332Z","iopub.status.idle":"2025-07-28T22:24:46.817240Z","shell.execute_reply.started":"2025-07-28T22:24:46.799300Z","shell.execute_reply":"2025-07-28T22:24:46.816593Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"le.inverse_transform([1,2])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:47.504307Z","iopub.execute_input":"2025-07-28T22:24:47.504579Z","iopub.status.idle":"2025-07-28T22:24:47.509846Z","shell.execute_reply.started":"2025-07-28T22:24:47.504560Z","shell.execute_reply":"2025-07-28T22:24:47.509269Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df, test_df = train_test_split(\n    df,\n    test_size=0.1,              # 10% for test (or validation)\n    stratify=df['camera_model'],       # keep camera balance\n    random_state=42\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:48.359638Z","iopub.execute_input":"2025-07-28T22:24:48.359920Z","iopub.status.idle":"2025-07-28T22:24:48.385380Z","shell.execute_reply.started":"2025-07-28T22:24:48.359901Z","shell.execute_reply":"2025-07-28T22:24:48.384568Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df['camera_model'].value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:49.326825Z","iopub.execute_input":"2025-07-28T22:24:49.327607Z","iopub.status.idle":"2025-07-28T22:24:49.335099Z","shell.execute_reply.started":"2025-07-28T22:24:49.327575Z","shell.execute_reply":"2025-07-28T22:24:49.334266Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_df['camera_model'].value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:50.037473Z","iopub.execute_input":"2025-07-28T22:24:50.038116Z","iopub.status.idle":"2025-07-28T22:24:50.043929Z","shell.execute_reply.started":"2025-07-28T22:24:50.038066Z","shell.execute_reply":"2025-07-28T22:24:50.043104Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class CameraPatchDataset(Dataset):\n    def __init__(self, img_paths, labels, transform='test'):\n        self.image_paths = img_paths.tolist()\n        self.labels = labels.tolist()\n        if transform == 'train':\n            self.transform = transforms.Compose([\n                transforms.RandomHorizontalFlip(),  # geometric only\n                transforms.ToTensor(),\n                transforms.Normalize((0.5,)*3,(0.5,)*3)  # keep for stable training\n            ])\n        else:\n            self.transform = transforms.Compose([\n                transforms.ToTensor(),\n                transforms.Normalize((0.5,)*3,(0.5,)*3)  # keep for stable training\n            ])\n    def __len__(self):\n        return len(self.image_paths)\n\n    def __getitem__(self, idx):\n        img_path = self.image_paths[idx]\n        img = Image.open(img_path).convert(\"RGB\")\n        label = self.labels[idx]\n        if self.transform:\n            img = self.transform(img)\n        return img, label\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:50.632472Z","iopub.execute_input":"2025-07-28T22:24:50.633029Z","iopub.status.idle":"2025-07-28T22:24:50.638766Z","shell.execute_reply.started":"2025-07-28T22:24:50.633005Z","shell.execute_reply":"2025-07-28T22:24:50.637991Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load dataset\ntrain_dataset = CameraPatchDataset(train_df['image_path'], train_df['camera_model'], transform='train')\ntest_dataset = CameraPatchDataset(test_df['image_path'], test_df['camera_model'], transform='test')\n\n# Main training loaders\ndataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=2, pin_memory=True)\nref_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=2, pin_memory=True)\n#ref2_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=2, pin_memory=True)\n\n# Evaluation/test loaders\ntest_dataloader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False, num_workers=2, pin_memory=True)\nref_test_dataloader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False, num_workers=2, pin_memory=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:52.155563Z","iopub.execute_input":"2025-07-28T22:24:52.155927Z","iopub.status.idle":"2025-07-28T22:24:52.168211Z","shell.execute_reply.started":"2025-07-28T22:24:52.155899Z","shell.execute_reply":"2025-07-28T22:24:52.167404Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def unnormalize(tensor):\n    # Assumes Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))\n    return tensor * 0.5 + 0.5","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:52.937689Z","iopub.execute_input":"2025-07-28T22:24:52.937927Z","iopub.status.idle":"2025-07-28T22:24:52.941564Z","shell.execute_reply.started":"2025-07-28T22:24:52.937910Z","shell.execute_reply":"2025-07-28T22:24:52.940794Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # Assume image_path is a list or Series of valid paths\n# # Pick first 100 (or randomly sample 100)\n# fig, axes = plt.subplots(10, 10, figsize=(15, 15))\n# plt.subplots_adjust(wspace=0.1, hspace=0.1)\n\n# for i, ax in enumerate(axes.flat):\n#     ax.imshow(unnormalize(test_dataset[i][0]).permute(1,2,0))\n#     ax.axis('off')\n\n# plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:54.961190Z","iopub.execute_input":"2025-07-28T22:24:54.961477Z","iopub.status.idle":"2025-07-28T22:24:54.965071Z","shell.execute_reply.started":"2025-07-28T22:24:54.961458Z","shell.execute_reply":"2025-07-28T22:24:54.964351Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Model","metadata":{}},{"cell_type":"code","source":"class ResBlock(nn.Module):\n    def __init__(self, in_ch, out_ch, norm=False, down=False):\n        super(ResBlock, self).__init__()\n        self.conv1 = nn.Conv2d(in_ch, in_ch, 3, 1, 1)\n        self.conv2 = nn.Conv2d(in_ch, out_ch, 3, 1, 1)\n\n        self.norm = norm\n        if norm:\n            self.norm1 = nn.InstanceNorm2d(in_ch, affine=True)\n            self.norm2 = nn.InstanceNorm2d(in_ch, affine=True)\n\n        self.lrelu = nn.LeakyReLU(0.2)\n        self.is_down = down\n\n        self.is_sc = in_ch != out_ch\n        if self.is_sc:\n            self.sc = nn.Conv2d(in_ch, out_ch, 1, 1, 0, bias=False)\n\n    def down(self, x):\n        return F.avg_pool2d(x, 2)\n\n    def forward(self, x):\n        if self.norm: res = self.norm1(x)\n        else: res = x\n        res = self.conv1(self.lrelu(res))\n        if self.is_sc: x = self.sc(x)\n        if self.is_down:\n            x = self.down(x)\n            res = self.down(res)\n        if self.norm: res = self.norm2(res)\n        res = self.conv2(self.lrelu(res))\n        return (x + res) / math.sqrt(2)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:55.831938Z","iopub.execute_input":"2025-07-28T22:24:55.832458Z","iopub.status.idle":"2025-07-28T22:24:55.839131Z","shell.execute_reply.started":"2025-07-28T22:24:55.832435Z","shell.execute_reply":"2025-07-28T22:24:55.838424Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class AdaIN(nn.Module):\n    def __init__(self, sdim, nf):\n        super(AdaIN, self).__init__()\n        self.norm = nn.InstanceNorm2d(nf)\n        self.gamma = nn.Linear(sdim, nf)\n        self.beta = nn.Linear(sdim, nf)\n        self.apply(init_fc_weight_one)\n\n    def forward(self, x, s):\n        B, C, H, W = x.size()\n        return (1 + self.gamma(s).view(B, C, 1, 1)) * self.norm(x) + self.beta(s).view(B, C, 1, 1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:56.226297Z","iopub.execute_input":"2025-07-28T22:24:56.226591Z","iopub.status.idle":"2025-07-28T22:24:56.231897Z","shell.execute_reply.started":"2025-07-28T22:24:56.226571Z","shell.execute_reply":"2025-07-28T22:24:56.231237Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class AdaINResBlock(nn.Module):\n    def __init__(self, in_ch, out_ch, sdim, up=False):\n        super(AdaINResBlock, self).__init__()\n        self.conv1 = nn.Conv2d(in_ch, out_ch, 3, 1, 1)\n        self.conv2 = nn.Conv2d(out_ch, out_ch, 3, 1, 1)\n        self.norm1 = AdaIN(sdim, in_ch)\n        self.norm2 = AdaIN(sdim, out_ch)\n        self.lrelu = nn.LeakyReLU(0.2)\n        self.is_up = up\n        self.is_sc = in_ch != out_ch\n        if self.is_sc:\n            self.sc = nn.Conv2d(in_ch, out_ch, 1, 1, 0, bias=False)\n\n    def up(self, x):\n        return F.interpolate(x, scale_factor=2, mode='nearest')\n\n    def forward(self, x, s):\n        res = self.lrelu(self.norm1(x, s))\n        if self.is_up:\n            x = self.up(x)\n            res = self.up(res)\n        if self.is_sc: x = self.sc(x)\n        res = self.conv1(res)\n        res = self.conv2(self.lrelu(self.norm2(res, s)))\n        return (x + res) / math.sqrt(2)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:56.576411Z","iopub.execute_input":"2025-07-28T22:24:56.577110Z","iopub.status.idle":"2025-07-28T22:24:56.583331Z","shell.execute_reply.started":"2025-07-28T22:24:56.577064Z","shell.execute_reply":"2025-07-28T22:24:56.582557Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Generator(nn.Module):\n    def __init__(self, nf, sdim):\n        super(Generator, self).__init__()\n        self.conv_in = nn.Conv2d(3, nf, 3, 1, 1)\n        self.enc = nn.Sequential(\n            ResBlock(nf, 2*nf, norm=True, down=True),\n            ResBlock(2*nf, 4*nf, norm=True, down=True),\n            ResBlock(4*nf, 8*nf, norm=True, down=True),\n            ResBlock(8*nf, 8*nf, norm=True),\n            ResBlock(8*nf, 8*nf, norm=True)\n        )\n        self.dec = nn.ModuleList([\n            AdaINResBlock(8*nf, 8*nf, sdim),\n            AdaINResBlock(8*nf, 8*nf, sdim),\n            AdaINResBlock(8*nf, 4*nf, sdim, up=True),\n            AdaINResBlock(4*nf, 2*nf, sdim, up=True),\n            AdaINResBlock(2*nf, nf, sdim, up=True)\n        ])\n        self.conv_out = nn.Sequential(\n            nn.InstanceNorm2d(nf, affine=True),\n            nn.LeakyReLU(0.2),\n            nn.Conv2d(nf, 3, 1, 1, 0)\n        )\n        self.apply(init_conv_weight)\n\n    def forward(self, x, s):\n        x = self.conv_in(x)\n        x = self.enc(x)\n        for layer in self.dec:\n            x = layer(x, s)\n        x = self.conv_out(x)\n        return x","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:57.868524Z","iopub.execute_input":"2025-07-28T22:24:57.869100Z","iopub.status.idle":"2025-07-28T22:24:57.875662Z","shell.execute_reply.started":"2025-07-28T22:24:57.869059Z","shell.execute_reply":"2025-07-28T22:24:57.874723Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class StyleEncoder(nn.Module):\n    def __init__(self, nf, nd, sdim):\n        super().__init__()\n        self.nd = nd\n        self.sdim = sdim\n\n        self.conv_in = nn.Conv2d(3, nf, 3, 1, 1)\n        # 5 downsamples → H/32 × W/32\n        self.res = nn.Sequential(\n            ResBlock(nf,  2*nf, down=True),\n            ResBlock(2*nf, 4*nf, down=True),\n            ResBlock(4*nf, 8*nf, down=True),\n            ResBlock(8*nf, 8*nf, down=True),\n            ResBlock(8*nf, 8*nf, down=True),\n        )\n        # Pool to 1×1 then map to nd*sdim\n        self.pool = nn.AdaptiveAvgPool2d(1)\n        self.conv_out = nn.Sequential(\n            nn.LeakyReLU(0.2),\n            nn.Conv2d(8*nf, nd*sdim, 1, 1, 0)\n        )\n        self.apply(init_conv_weight)\n\n    def forward(self, x, y):\n        B = x.size(0)\n        x = self.conv_in(x)        # → [B, nf, H, W]\n        x = self.res(x)            # → [B, 8*nf, H/32, W/32]\n        x = self.pool(x)           # → [B, 8*nf, 1, 1]\n        out = self.conv_out(x)     # → [B, nd*sdim, 1, 1]\n        style = out.view(B, self.nd, self.sdim)  # → [B, nd, sdim]\n\n        # ensure y is a LongTensor on the same device\n        if not torch.is_tensor(y):\n            y = torch.tensor(y, dtype=torch.long, device=style.device)\n        else:\n            y = y.to(style.device)\n\n        # pick each sample’s style vector\n        return style[torch.arange(B, device=style.device), y]  # → [B, sdim]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:58.176294Z","iopub.execute_input":"2025-07-28T22:24:58.176582Z","iopub.status.idle":"2025-07-28T22:24:58.183587Z","shell.execute_reply.started":"2025-07-28T22:24:58.176564Z","shell.execute_reply":"2025-07-28T22:24:58.182833Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Discriminator(nn.Module):\n    def __init__(self, nf, nd):\n        super(Discriminator, self).__init__()\n        self.conv_in = nn.Conv2d(3, nf, 3, 1, 1)\n        self.res = nn.Sequential(\n            ResBlock(nf, 2*nf, down=True),\n            ResBlock(2*nf, 4*nf, down=True),\n            ResBlock(4*nf, 8*nf, down=True),\n            ResBlock(8*nf, 8*nf, down=True),\n            ResBlock(8*nf, 8*nf, down=True)\n        )\n        self.conv_out = nn.Sequential(\n            nn.LeakyReLU(0.2),\n            nn.Conv2d(8*nf, 8*nf, 4, 1, 0),\n            nn.LeakyReLU(0.2),\n            nn.Conv2d(8*nf, nd, 1, 1, 0)\n        )\n        self.apply(init_conv_weight)\n\n    def forward(self, x, y):  # x: B x 3 x H x W, y: B\n        B = x.size(0)\n        x = self.conv_in(x)         # B x nf x H x W\n        x = self.res(x)             # B x 8nf x 4 x 4\n        x = self.conv_out(x)        # B x nd x 1 x 1\n        x = x.view(B, -1)           # B x nd\n    \n        if not torch.is_tensor(y):\n            y = torch.tensor(y, dtype=torch.long, device=x.device)\n        elif y.device != x.device:\n            y = y.to(x.device)\n    \n        i = torch.arange(B, device=x.device)\n        return x[i, y]              # B\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:24:59.777428Z","iopub.execute_input":"2025-07-28T22:24:59.777914Z","iopub.status.idle":"2025-07-28T22:24:59.784629Z","shell.execute_reply.started":"2025-07-28T22:24:59.777892Z","shell.execute_reply":"2025-07-28T22:24:59.783737Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Model:\n    def __init__(self, nf, nd, sdim, lr, betas, weight_decay):\n        self.G = Generator(nf, sdim).cuda()\n        #self.F = MappingNetwork(nz, nd, sdim).cuda()\n        self.D = Discriminator(nf, nd).cuda()\n        self.E = StyleEncoder(nf, nd, sdim).cuda()\n\n        self.optG = optim.Adam(self.G.parameters(), lr=lr, betas=betas, weight_decay=weight_decay)\n        #self.optF = optim.Adam(self.F.parameters(), lr=lr_f, betas=betas, weight_decay=weight_decay)\n        self.optD = optim.Adam(self.D.parameters(), lr=lr, betas=betas, weight_decay=weight_decay)\n        self.optE = optim.Adam(self.E.parameters(), lr=lr, betas=betas, weight_decay=weight_decay)\n\n    def save(self, path):\n        torch.save(self.G.state_dict(), path + '_G.pt')\n        #torch.save(self.F.state_dict(), path + '_F.pt')\n        torch.save(self.D.state_dict(), path + '_D.pt')\n        torch.save(self.E.state_dict(), path + '_E.pt')\n\n    def load(self, path):\n        self.G.load_state_dict(torch.load(path + '_G.pt'))\n        #self.F.load_state_dict(torch.load(path + '_F.pt'))\n        self.D.load_state_dict(torch.load(path + '_D.pt'))\n        self.E.load_state_dict(torch.load(path + '_E.pt'))\n\n    def zero_grad(self):\n        self.optG.zero_grad()\n        #self.optF.zero_grad()\n        self.optD.zero_grad()\n        self.optE.zero_grad()\n\n    def train(self):\n        self.G.train()\n        #self.F.train()\n        self.D.train()\n        self.E.train()\n\n    def eval(self):\n        self.G.eval()\n        #self.F.eval()\n        self.D.eval()\n        self.E.eval()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:25:00.088254Z","iopub.execute_input":"2025-07-28T22:25:00.088709Z","iopub.status.idle":"2025-07-28T22:25:00.095977Z","shell.execute_reply.started":"2025-07-28T22:25:00.088689Z","shell.execute_reply":"2025-07-28T22:25:00.095116Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = Model(nf, nd, sdim, lr, betas, weight_decay)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:25:01.752382Z","iopub.execute_input":"2025-07-28T22:25:01.752655Z","iopub.status.idle":"2025-07-28T22:25:02.506238Z","shell.execute_reply.started":"2025-07-28T22:25:01.752633Z","shell.execute_reply":"2025-07-28T22:25:02.505655Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def gradient_penalty(out, x):\n    grad = torch.autograd.grad(\n        outputs=out.sum(),\n        inputs=x,\n        create_graph=True,\n        retain_graph=True,\n        only_inputs=True\n    )[0].view(x.size(0), -1)\n    return 0.5 * torch.mean(torch.sum(grad.pow(2), dim=1))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:25:02.525437Z","iopub.execute_input":"2025-07-28T22:25:02.525680Z","iopub.status.idle":"2025-07-28T22:25:02.529767Z","shell.execute_reply.started":"2025-07-28T22:25:02.525663Z","shell.execute_reply":"2025-07-28T22:25:02.529051Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # Training\n\n# # Paths and naming\n# model_name = 'stargan-v2-camera'\n# loss_path  = f\"{model_saved_dir}/{model_name}_loss.txt\"\n# img_path   = f\"{model_saved_dir}/{model_name}_img.pkl\"\n# model_path = f\"{model_saved_dir}/{model_name}\"\n\n# # Resume settings\n# # 1) Load model weights\n# model.load(model_path)  # this will load G.pt, D.pt and E.pt\n# imgs = []\n\n# # 2) Load your losses & image-snapshots\n# with open(loss_path, 'rb') as f:\n#     losses = pickle.load(f)\n\n# # 3) Set start_epoch so your loop picks up after epoch 1\n# start_epoch = 6 # 6 ta shesh hoise \n# print(f\" Resuming from epoch {start_epoch}.  Loaded {len(losses['train_d2'])} D-losses and {len(imgs)} snapshots.\")\n\n# if start_epoch == 0:\n#     losses = {'train_d2': [], 'train_g2': []}\n\n# # Loss and annealing\n# l1 = torch.nn.L1Loss()\n# lambda_ds_zero = lambda_ds\n# lambda_ds = max((lambda_ds_zero * (ds_epochs - start_epoch)) / epochs, 0.)\n\n# # Training loop with tqdm\n# for ep in range(start_epoch, epochs):\n#     model.train()\n#     epoch_start = time.time()\n#     step, d2_sum, g2_sum = 0, 0.0, 0.0\n\n#     train_iter = tqdm(\n#         zip(dataloader, ref_dataloader, ref2_dataloader),\n#         total=len(dataloader),\n#         desc=f\"Epoch {ep+1}/{epochs}\",\n#         leave=False\n#     )\n\n#     for (x, y), (x_ref, y_), (x_ref2, _) in train_iter:\n#         step += 1\n#         global_step = ep * len(dataloader) + step\n\n#         # Move to device\n#         x       = x.to(device);      x.requires_grad_()\n#         y       = y.to(device)\n#         x_ref   = x_ref.to(device)\n#         y_      = y_.to(device)\n#         x_ref2  = x_ref2.to(device)\n\n#         # ---- Discriminator step ----\n#         model.zero_grad()\n#         out_real  = model.D(x, y)\n#         loss_real = F.binary_cross_entropy_with_logits(out_real, torch.ones_like(out_real))\n\n#         with torch.no_grad():\n#             s_ref  = model.E(x_ref, y_)\n#             x_fake = model.G(x, s_ref)\n\n#         out_fake  = model.D(x_fake, y_)\n#         loss_fake = F.binary_cross_entropy_with_logits(out_fake, torch.zeros_like(out_fake))\n#         loss_gp   = gradient_penalty(out_real, x)\n\n#         loss_d = loss_real + loss_fake + lambda_gp * loss_gp\n#         loss_d.backward()\n#         model.optD.step()\n#         losses['train_d2'].append(loss_d.item()); d2_sum += loss_d.item()\n\n#         # ---- Generator step ----\n#         model.zero_grad()\n#         s_ref    = model.E(x_ref, y_)\n#         x_fake   = model.G(x, s_ref)\n#         out_fake = model.D(x_fake, y_)\n#         loss_adv = F.binary_cross_entropy_with_logits(out_fake, torch.ones_like(out_fake))\n\n#         s_pred = model.E(x_fake, y_)\n#         loss_sty = l1(s_ref, s_pred)\n\n#         s_ref2 = model.E(x_ref2, y_)\n#         x_fake2 = model.G(x, s_ref2)\n#         loss_ds_val = l1(x_fake, x_fake2.detach())\n\n#         # Cycle consistency (no grad through E here)\n#         with torch.no_grad():\n#             s_src = model.E(x, y)\n#         x_rec   = model.G(x_fake, s_src)\n#         loss_cyc = l1(x, x_rec)\n\n#         loss_g = loss_adv + lambda_sty * loss_sty - lambda_ds * loss_ds_val + lambda_cyc * loss_cyc\n#         loss_g.backward()\n#         model.optG.step()\n#         model.optE.step()\n#         losses['train_g2'].append(loss_g.item()); g2_sum += loss_g.item()\n\n#         # ---- Periodic image snapshots (single batch on CPU) ----\n\n#         if global_step % n_img_save == 0:\n#             model.eval()\n#             with torch.no_grad():\n#                 total_samples = len(test_dataset)\n#                 batch_size = 4  # or whatever your test batch size is\n        \n#                 indices = random.sample(range(total_samples), k=batch_size * 2)\n#                 src_indices = indices[:batch_size]\n#                 ref_indices = indices[batch_size:]\n        \n#                 x_val  = torch.stack([test_dataset[i][0] for i in src_indices]).to(device)\n#                 y_val  = torch.tensor([test_dataset[i][1] for i in src_indices]).to(device)\n        \n#                 x_ref_val = torch.stack([test_dataset[i][0] for i in ref_indices]).to(device)\n#                 y_ref     = torch.tensor([test_dataset[i][1] for i in ref_indices]).to(device)\n        \n#                 s_val    = model.E(x_ref_val, y_ref)\n#                 gen_imgs = model.G(x_val, s_val).detach().cpu()\n#                 src_imgs = x_val.cpu()\n#                 ref_imgs = x_ref_val.cpu()\n#                 src_lbls = y_val.cpu().numpy()\n#                 ref_lbls = y_ref.cpu().numpy()\n        \n#             imgs.append({\n#                 'step':     global_step,\n#                 'src_imgs': src_imgs,\n#                 'ref_imgs': ref_imgs,\n#                 'gen_imgs': gen_imgs,\n#                 'src_lbls': src_lbls,\n#                 'ref_lbls': ref_lbls\n#             })\n#             model.train()\n#             train_iter.write(f\"[Step {global_step}] Saved snapshot (batch size {src_imgs.size(0)})\")\n\n\n#         # Anneal diversity weight\n#         lambda_ds = max(lambda_ds - lambda_ds_zero / (len(dataloader) * epochs), 0.)\n\n#         # Update tqdm postfix\n#         if step % n_print == 0 or step == len(dataloader):\n#             train_iter.set_postfix({\n#                 'D2': f\"{d2_sum/step:.4f}\",\n#                 'G2': f\"{g2_sum/step:.4f}\"\n#             })\n\n#     # ---- End of epoch: save model & logs ----\n#     epoch_time = time.time() - epoch_start\n#     model.save(model_path)\n#     with open(loss_path, 'wb') as f:\n#         pickle.dump(losses, f)\n#     with open(img_path, 'wb') as f:\n#         pickle.dump(imgs, f)\n    \n#     print(f\"Epoch {ep+1}/{epochs} completed in {int(epoch_time)}s — model & logs saved.\")\n    \n#     # ---- Zip the checkpoint for this epoch ----\n#     import zipfile\n#     import os\n    \n#     epoch_num = ep + 1\n#     checkpoint_name = f\"epoch_{epoch_num}.zip\"\n#     checkpoint_path = os.path.join(model_saved_dir, checkpoint_name)\n    \n#     with zipfile.ZipFile(checkpoint_path, 'w') as zipf:\n#         files_to_zip = [\n#             f\"{model_name}_G.pt\",\n#             f\"{model_name}_D.pt\",\n#             f\"{model_name}_E.pt\",\n#             f\"{model_name}_loss.txt\",\n#             f\"{model_name}_img.pkl\"\n#         ]\n#         for file in files_to_zip:\n#             file_path = os.path.join(model_saved_dir, file)\n#             zipf.write(file_path, arcname=file)\n    \n#     print(f\"Checkpoint zipped: {checkpoint_path}\")\n\n#     print(f\"Epoch {ep+1}/{epochs} completed in {int(epoch_time)}s — model & logs saved.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:29:46.498678Z","iopub.execute_input":"2025-07-28T22:29:46.498904Z","iopub.status.idle":"2025-07-28T22:29:46.505677Z","shell.execute_reply.started":"2025-07-28T22:29:46.498888Z","shell.execute_reply":"2025-07-28T22:29:46.504996Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Inference","metadata":{}},{"cell_type":"code","source":"src_path = glob('/kaggle/input/inference-camera-modelling/src_img/*')\nprint(f\"Number of images in source path: {len(src_path)}\")\nref_path = glob('/kaggle/input/inference-camera-modelling/ref_img/*/*')\nprint(f\"Number of images in source path: {len(ref_path)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:25:11.783518Z","iopub.execute_input":"2025-07-28T22:25:11.783800Z","iopub.status.idle":"2025-07-28T22:25:11.834687Z","shell.execute_reply.started":"2025-07-28T22:25:11.783783Z","shell.execute_reply":"2025-07-28T22:25:11.834075Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"src_path[0].split('/')[-1].split('.')[0].split('_')[0]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:25:12.742376Z","iopub.execute_input":"2025-07-28T22:25:12.742656Z","iopub.status.idle":"2025-07-28T22:25:12.747703Z","shell.execute_reply.started":"2025-07-28T22:25:12.742638Z","shell.execute_reply":"2025-07-28T22:25:12.747140Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"src_df = pd.DataFrame(src_path,columns=['img_path'])\nsrc_df['model'] = src_df['img_path'].apply(lambda x:x.split('/')[-1].split('.')[0].split('_')[0])\nsrc_df['label']=le.transform(src_df['model'])\n\nref_df = pd.DataFrame(ref_path,columns=['img_path'])\nref_df['model'] = ref_df['img_path'].apply(lambda x:x.split('/')[-2])\nref_df['label']=le.transform(ref_df['model'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:25:13.775754Z","iopub.execute_input":"2025-07-28T22:25:13.776031Z","iopub.status.idle":"2025-07-28T22:25:13.784099Z","shell.execute_reply.started":"2025-07-28T22:25:13.776012Z","shell.execute_reply":"2025-07-28T22:25:13.783355Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ref_df['model']=='LG-Nexus-5x'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:25:16.428621Z","iopub.execute_input":"2025-07-28T22:25:16.428881Z","iopub.status.idle":"2025-07-28T22:25:16.432027Z","shell.execute_reply.started":"2025-07-28T22:25:16.428864Z","shell.execute_reply":"2025-07-28T22:25:16.431402Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# model.load('/kaggle/working/epoch_24/stargan-v2-camera')\n# model.eval()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:25:16.920771Z","iopub.execute_input":"2025-07-28T22:25:16.921506Z","iopub.status.idle":"2025-07-28T22:25:16.924539Z","shell.execute_reply.started":"2025-07-28T22:25:16.921480Z","shell.execute_reply":"2025-07-28T22:25:16.923796Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"transform = transforms.Compose([\n    transforms.Resize((256, 256)),\n    transforms.ToTensor(),\n    transforms.Normalize([0.5]*3, [0.5]*3)\n])\n\ndef load_image(path):\n    img = Image.open(path).convert('RGB')\n    return transform(img).unsqueeze(0).to(device)  # [1, C, H, W]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:25:17.464932Z","iopub.execute_input":"2025-07-28T22:25:17.465230Z","iopub.status.idle":"2025-07-28T22:25:17.469706Z","shell.execute_reply.started":"2025-07-28T22:25:17.465211Z","shell.execute_reply":"2025-07-28T22:25:17.469077Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def img_from_same_cam(src,ref):\n    ref_img = load_image(ref_df['img_path'][ref])\n    ref_lbl = ref_df['label'][ref]\n    \n    with torch.no_grad():\n        style_vec = model.E(ref_img,ref_lbl)\n\n    plt.figure(figsize=(20,5))\n    for i,src_idx in enumerate(src):\n        src_img = load_image(ref_df['img_path'][src_idx])\n        src_lbl = ref_df['label'][src_idx]\n        \n        with torch.no_grad():\n            gen_img = model.G(src_img,style_vec)\n        \n        plt.subplot(2,9,i+1),plt.imshow(unnormalize(src_img.cpu()[0].permute(1,2,0))),plt.title(le.inverse_transform([src_lbl])[0]),plt.axis('off')\n        plt.subplot(2,9,i+10),plt.imshow(unnormalize(gen_img.cpu()[0].permute(1,2,0))),plt.title(le.inverse_transform([ref_lbl])[0]),plt.axis('off')\n    \n    plt.tight_layout()\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:25:19.057182Z","iopub.execute_input":"2025-07-28T22:25:19.057859Z","iopub.status.idle":"2025-07-28T22:25:19.063474Z","shell.execute_reply.started":"2025-07-28T22:25:19.057834Z","shell.execute_reply":"2025-07-28T22:25:19.062644Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def img_from_diff_cam(src,ref):\n    plt.figure(figsize=(30,10))\n    for j,src_idx in enumerate(src):\n        src_img = load_image(ref_df['img_path'][src_idx])\n        src_lbl = ref_df['label'][src_idx]\n        plt.subplot(5,10,j*10+1),plt.imshow(unnormalize(src_img.cpu()[0].permute(1,2,0))),plt.title(le.inverse_transform([src_lbl])[0]),plt.axis('off')\n        \n        for i,ref_idx in enumerate(ref):\n            ref_img = load_image(ref_df['img_path'][ref_idx])\n            ref_lbl = ref_df['label'][ref_idx]\n            \n            with torch.no_grad():\n                style_vec = model.E(ref_img,ref_lbl)\n                gen_img = model.G(src_img,style_vec)\n            plt.subplot(5,10,j*10+i+2),plt.imshow(unnormalize(gen_img.cpu()[0].permute(1,2,0))),plt.title(le.inverse_transform([ref_lbl])[0]),plt.axis('off')\n    \n    plt.tight_layout()\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:25:22.965050Z","iopub.execute_input":"2025-07-28T22:25:22.965337Z","iopub.status.idle":"2025-07-28T22:25:22.971879Z","shell.execute_reply.started":"2025-07-28T22:25:22.965314Z","shell.execute_reply":"2025-07-28T22:25:22.971215Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for epoch in epochs:\n    model.load(os.path.join(epoch,'stargan-v2-camera'))\n    model.eval()\n    print(f\"\\nFor epoch: {epoch.split('/')[-1].split('_')[-1]}\\n\")\n    img_from_diff_cam(src=[0,1,2,3,4],ref=[5,10,15,20,25,30,35,40,45])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T21:25:03.813134Z","iopub.execute_input":"2025-07-28T21:25:03.813379Z","iopub.status.idle":"2025-07-28T21:27:02.698077Z","shell.execute_reply.started":"2025-07-28T21:25:03.813362Z","shell.execute_reply":"2025-07-28T21:27:02.696920Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for epoch in epochs:\n    model.load(os.path.join(epoch,'stargan-v2-camera'))\n    model.eval()\n    print(f\"\\nFor epoch: {epoch.split('/')[-1].split('_')[-1]}\\n\")\n    img_from_same_cam(src=[5,10,15,20,25,30,35,40,45],ref=10)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T21:27:21.910239Z","iopub.execute_input":"2025-07-28T21:27:21.910520Z","iopub.status.idle":"2025-07-28T21:27:59.577392Z","shell.execute_reply.started":"2025-07-28T21:27:21.910501Z","shell.execute_reply":"2025-07-28T21:27:59.576497Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Loss Plot","metadata":{}},{"cell_type":"code","source":"model.load('/kaggle/working/epoch_28/stargan-v2-camera')\nmodel.eval()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:25:28.656044Z","iopub.execute_input":"2025-07-28T22:25:28.656562Z","iopub.status.idle":"2025-07-28T22:25:28.860099Z","shell.execute_reply.started":"2025-07-28T22:25:28.656539Z","shell.execute_reply":"2025-07-28T22:25:28.859324Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"src_indices_per_cam = [[i + j for j in range(5)] for i in range(0, 50, 5)]\nref_indices = [i for i in range(0, 50, 5)]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T21:42:13.328856Z","iopub.execute_input":"2025-07-28T21:42:13.329165Z","iopub.status.idle":"2025-07-28T21:42:13.333701Z","shell.execute_reply.started":"2025-07-28T21:42:13.329144Z","shell.execute_reply":"2025-07-28T21:42:13.333009Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for src_idx,ref in enumerate(ref_indices):\n     img_from_same_cam(src=src_indices_per_cam[src_idx],ref=ref)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T21:42:14.056719Z","iopub.execute_input":"2025-07-28T21:42:14.057006Z","iopub.status.idle":"2025-07-28T21:42:23.480121Z","shell.execute_reply.started":"2025-07-28T21:42:14.056984Z","shell.execute_reply":"2025-07-28T21:42:23.479371Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# with open('/kaggle/working/stargan-v2-camera_loss.txt', 'rb') as f:\n#     losses = pickle.load(f)\n\n# for i, snap in enumerate(snapshots):\n#     step = snap['step']\n#     d_loss = losses['train_d2'][step - 1]  # steps are 1-indexed in your logs\n#     g_loss = losses['train_g2'][step - 1]\n#     print(f\"Snap {i}: Step {step} | D Loss: {d_loss:.4f}, G Loss: {g_loss:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T21:45:38.344032Z","iopub.execute_input":"2025-07-28T21:45:38.344767Z","iopub.status.idle":"2025-07-28T21:45:38.359361Z","shell.execute_reply.started":"2025-07-28T21:45:38.344746Z","shell.execute_reply":"2025-07-28T21:45:38.358320Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"D_loss=[]\nG_loss=[]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:25:38.607545Z","iopub.execute_input":"2025-07-28T22:25:38.607850Z","iopub.status.idle":"2025-07-28T22:25:38.611777Z","shell.execute_reply.started":"2025-07-28T22:25:38.607829Z","shell.execute_reply":"2025-07-28T22:25:38.611030Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for epoch in tqdm(epochs,desc='Loading losses'):\n    epoch_x = epoch.split('/')[-1]\n    with open(f'/kaggle/working/{epoch_x}/stargan-v2-camera_loss.txt', 'rb') as f:\n        losses = pickle.load(f)\n        D_loss.append(np.mean(losses['train_d2']))\n        G_loss.append(np.mean(losses['train_g2']))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:26:19.037568Z","iopub.execute_input":"2025-07-28T22:26:19.038211Z","iopub.status.idle":"2025-07-28T22:26:19.987837Z","shell.execute_reply.started":"2025-07-28T22:26:19.038176Z","shell.execute_reply":"2025-07-28T22:26:19.986947Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"len(D_loss)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:26:22.457301Z","iopub.execute_input":"2025-07-28T22:26:22.458173Z","iopub.status.idle":"2025-07-28T22:26:22.462515Z","shell.execute_reply.started":"2025-07-28T22:26:22.458144Z","shell.execute_reply":"2025-07-28T22:26:22.461817Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"epoch_x = [epoch.split('/')[-1].split('_')[-1] for epoch in epochs]\n# Step 3: Plot\nplt.figure(figsize=(10, 5))\nplt.plot(epoch_x,G_loss, label='G Loss', marker='o')\nplt.plot(epoch_x, D_loss, label='D Loss', marker='s')\nplt.xlabel('Epoch')\nplt.ylabel('Average Loss')\nplt.title('Generator and Discriminator Loss vs Epoch')\nplt.grid(True)\nplt.legend()\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:26:25.925686Z","iopub.execute_input":"2025-07-28T22:26:25.926339Z","iopub.status.idle":"2025-07-28T22:26:26.271996Z","shell.execute_reply.started":"2025-07-28T22:26:25.926316Z","shell.execute_reply":"2025-07-28T22:26:26.271262Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # Store all step-wise losses as dictionaries\n# D_loss_all = {}\n# G_loss_all = {}\n# epoch_names = []\n\n# # --- Step 1: Load per-step losses from each epoch file ---\n# for epoch_path in tqdm(epochs, desc='Loading all step-wise losses'):\n#     epoch_name = epoch_path.split('/')[-1]  # e.g., \"epoch_01\"\n#     epoch_names.append(epoch_name)\n\n#     with open(f'/kaggle/working/{epoch_name}/stargan-v2-camera_loss.txt', 'rb') as f:\n#         losses = pickle.load(f)\n#         D_loss_all[epoch_name] = losses['train_d2']  # store list directly\n#         G_loss_all[epoch_name] = losses['train_g2']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:26:27.005657Z","iopub.execute_input":"2025-07-28T22:26:27.006300Z","iopub.status.idle":"2025-07-28T22:26:27.500072Z","shell.execute_reply.started":"2025-07-28T22:26:27.006280Z","shell.execute_reply":"2025-07-28T22:26:27.499390Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# G_loss_all['epoch_24'][:10]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-25T18:33:25.908412Z","iopub.execute_input":"2025-07-25T18:33:25.908687Z","iopub.status.idle":"2025-07-25T18:33:25.913891Z","shell.execute_reply.started":"2025-07-25T18:33:25.908666Z","shell.execute_reply":"2025-07-25T18:33:25.913305Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# for epoch in G_loss_all.keys():\n#     print(f\"{epoch}(min) = {min(G_loss_all[f'{epoch}'])}\")\n#     print(f\"{epoch}(max) = {max(G_loss_all[f'{epoch}'])}\")\n#     print(f\"{epoch}(avg) = {sum(G_loss_all[f'{epoch}'])/len(G_loss_all[f'{epoch}'])}\")\n#     print('\\n')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-25T18:28:09.525330Z","iopub.execute_input":"2025-07-25T18:28:09.525596Z","iopub.status.idle":"2025-07-25T18:28:09.622116Z","shell.execute_reply.started":"2025-07-25T18:28:09.525577Z","shell.execute_reply":"2025-07-25T18:28:09.621500Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # --- Step 3: Plot losses for that epoch (per step) ---\n# def plot_epoch_losses(epoch_index):\n#     g = G_loss_all[epoch_index]\n#     d = D_loss_all[epoch_index]\n\n#     plt.figure(figsize=(10, 5))\n#     plt.plot(g, label='G Loss', marker='o')\n#     plt.plot(d, label='D Loss', marker='s')\n#     plt.xlabel(\"Step\")\n#     plt.ylabel(\"Loss\")\n#     plt.title(f\"Loss Per Step - Epoch {epoch_names[epoch_index]}\")\n#     plt.grid(True)\n#     plt.legend()\n#     plt.tight_layout()\n#     plt.show()\n\n# # Example: plot losses for epoch 0\n# plot_epoch_losses(epoch_index=0)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## TSME of Style Encoder","metadata":{}},{"cell_type":"code","source":"model.load('/kaggle/working/epoch_28/stargan-v2-camera')\nmodel.eval()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:30:01.032906Z","iopub.execute_input":"2025-07-28T22:30:01.033658Z","iopub.status.idle":"2025-07-28T22:30:01.165581Z","shell.execute_reply.started":"2025-07-28T22:30:01.033631Z","shell.execute_reply":"2025-07-28T22:30:01.164776Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"style_vectors = []\nlabels = []\n\nwith torch.no_grad():\n    for img, label in tqdm(ref_test_dataloader):\n        img = img.to(device)\n        label = label.to(device)\n\n        style = model.E(img, label)  # shape: (batch, style_dim)\n        style_vectors.append(style.cpu().numpy())\n        labels.append(label.cpu().numpy())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:30:01.320579Z","iopub.execute_input":"2025-07-28T22:30:01.321153Z","iopub.status.idle":"2025-07-28T22:30:24.214412Z","shell.execute_reply.started":"2025-07-28T22:30:01.321124Z","shell.execute_reply":"2025-07-28T22:30:24.213498Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"style_vectors = np.concatenate(style_vectors, axis=0)\nlabels = np.concatenate(labels, axis=0)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:30:29.874008Z","iopub.execute_input":"2025-07-28T22:30:29.874878Z","iopub.status.idle":"2025-07-28T22:30:29.884528Z","shell.execute_reply.started":"2025-07-28T22:30:29.874834Z","shell.execute_reply":"2025-07-28T22:30:29.883883Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.manifold import TSNE\nimport matplotlib.pyplot as plt\n\n# Reduce to 2D\ntsne = TSNE(n_components=2, perplexity=30, learning_rate=200)\nstyle_tsne = tsne.fit_transform(style_vectors)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:30:31.357407Z","iopub.execute_input":"2025-07-28T22:30:31.357997Z","iopub.status.idle":"2025-07-28T22:30:55.369435Z","shell.execute_reply.started":"2025-07-28T22:30:31.357974Z","shell.execute_reply":"2025-07-28T22:30:55.368641Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import seaborn as sns\nimport pandas as pd\n\ntsne_df = pd.DataFrame({\n    'x': style_tsne[:, 0],\n    'y': style_tsne[:, 1],\n    'camera_model': le.inverse_transform(labels)\n})\n\nplt.figure(figsize=(10, 8))\nsns.scatterplot(data=tsne_df, x='x', y='y', hue='camera_model', palette='tab10')\nplt.title('t-SNE of Style Vectors from StyleEncoder')\nplt.legend(title='Camera Model', bbox_to_anchor=(1.05, 1), loc='upper left')\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:30:55.370926Z","iopub.execute_input":"2025-07-28T22:30:55.371252Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Converting Full Image","metadata":{}},{"cell_type":"code","source":"# import cv2\n# import numpy as np\n# import torch\n\n# # Pad image so it's divisible by 256\n# def pad_to_multiple(img, multiple=256):\n#     h, w = img.shape[:2]\n#     new_h = ((h + multiple - 1) // multiple) * multiple\n#     new_w = ((w + multiple - 1) // multiple) * multiple\n#     pad_h = new_h - h\n#     pad_w = new_w - w\n#     padded_img = cv2.copyMakeBorder(img, 0, pad_h, 0, pad_w, cv2.BORDER_REFLECT)\n#     return padded_img, h, w\n\n# # Split full image into 256x256 patches\n# def split_into_patches_with_coords(img, patch_size=256, stride=128):\n#     patches = []\n#     coords = []\n#     for i in range(0, img.shape[0] - patch_size + 1, stride):\n#         for j in range(0, img.shape[1] - patch_size + 1, stride):\n#             patch = img[i:i+patch_size, j:j+patch_size]\n#             patches.append(patch)\n#             coords.append((i, j))\n#     return patches, coords\n\n\n# # Reconstruct full image from list of patches\n# def stitch_blended(patches, coords, height, width, patch_size=256):\n#     output = np.zeros((height, width, 3), dtype=np.float32)\n#     weight = np.zeros((height, width, 3), dtype=np.float32)\n\n#     for patch, (i, j) in zip(patches, coords):\n#         patch = patch.astype(np.float32)\n#         output[i:i+patch_size, j:j+patch_size] += patch\n#         weight[i:i+patch_size, j:j+patch_size] += 1.0\n\n#     output = (output / np.maximum(weight, 1e-5)).clip(0, 255).astype(np.uint8)\n#     return output\n\n\n# # Preprocess patch to tensor: [H,W,3] → [1,3,H,W]\n# def preprocess_patch(patch):\n#     patch = patch.astype(np.float32) / 127.5 - 1.0  # Normalize to [-1, 1]\n#     return torch.from_numpy(patch).permute(2, 0, 1).unsqueeze(0).to(device)\n\n# # Unnormalize tensor from [-1,1] → [0,255] for display\n# def unnormalize(tensor):\n#     return ((tensor + 1) * 127.5).clamp(0, 255).byte()\n\n\n# def stylize_full_image_blended(src_path, ref_img_tensor, ref_lbl, model, patch_size=256, stride=128):\n#     img = cv2.imread(src_path)[:, :, ::-1]  # RGB\n#     padded_img, orig_h, orig_w = pad_to_multiple(img, patch_size)\n#     patches, coords = split_into_patches_with_coords(padded_img, patch_size, stride)\n\n#     with torch.no_grad():\n#         style = model.E(ref_img_tensor, torch.tensor([ref_lbl]).to(device))\n\n#     stylized_patches = []\n\n#     for patch in patches:\n#         patch_tensor = preprocess_patch(patch)\n#         with torch.no_grad():\n#             gen_patch = model.G(patch_tensor, style)\n#         gen_np = unnormalize(gen_patch[0].cpu()).permute(1, 2, 0).numpy()\n#         stylized_patches.append(gen_np)\n\n#     final_img = stitch_blended(stylized_patches, coords, padded_img.shape[0], padded_img.shape[1])\n#     return final_img[:orig_h, :orig_w]\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:39:21.178891Z","iopub.execute_input":"2025-07-28T22:39:21.179468Z","iopub.status.idle":"2025-07-28T22:39:21.190716Z","shell.execute_reply.started":"2025-07-28T22:39:21.179444Z","shell.execute_reply":"2025-07-28T22:39:21.189950Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# import matplotlib.pyplot as plt\n# import cv2\n\n# # 1. Select reference image from your ref_df\n# ref_row = ref_df.iloc[5]\n# ref_img = load_image(ref_row['img_path'])     # [1,3,256,256]\n# ref_lbl = ref_row['label']                    # int\n\n# # 2. Define path to full-size source image\n# src_path = '/kaggle/input/sp-society-camera-model-identification/train/train/Sony-NEX-7/(Nex7)111.JPG'\n\n# output_img = stylize_full_image_blended(\n#     src_path=src_path,\n#     ref_img_tensor=ref_img,\n#     ref_lbl=ref_lbl,\n#     model=model\n# )\n\n# # Display\n# plt.figure(figsize=(16, 8))\n# plt.subplot(1, 2, 1)\n# plt.imshow(orig_img)\n# plt.title(\"Original\")\n# plt.axis('off')\n\n# plt.subplot(1, 2, 2)\n# plt.imshow(output_img)\n# plt.title(f\"Stylized as {ref_row['model']}\")\n# plt.axis('off')\n# plt.tight_layout()\n# plt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-28T22:41:34.021776Z","iopub.execute_input":"2025-07-28T22:41:34.022100Z","iopub.status.idle":"2025-07-28T22:42:05.108886Z","shell.execute_reply.started":"2025-07-28T22:41:34.022060Z","shell.execute_reply":"2025-07-28T22:42:05.108051Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print('')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Utility","metadata":{}},{"cell_type":"code","source":"# 1. gather files\nfiles = glob.glob('/kaggle/working/*.pt') + glob.glob('/kaggle/working/*.pkl') + glob.glob('/kaggle/working/*.txt')\n\n# 2. create zip\nzip_path = '/kaggle/working/checkpoint_epoch_4.zip'\nwith zipfile.ZipFile(zip_path, 'w') as zf:\n    for f in files:\n        # arcname makes sure only the filename is stored, not the full path\n        zf.write(f, arcname=os.path.basename(f))\n\nprint(f\"✓ Created {zip_path} with {len(files)} files\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-16T08:06:14.546742Z","iopub.execute_input":"2025-07-16T08:06:14.547027Z","iopub.status.idle":"2025-07-16T08:06:15.276241Z","shell.execute_reply.started":"2025-07-16T08:06:14.547007Z","shell.execute_reply":"2025-07-16T08:06:15.275601Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"base_save_dir = \"/kaggle/working/saved_cameras\"\nzip_path = \"/kaggle/working/ref_img.zip\"\nshutil.make_archive(base_name=zip_path.replace('.zip', ''), format='zip', root_dir=base_save_dir)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Delete file\nfile_path = \"/kaggle/working/stargan-v2-camera_G.pt\"\n\nif os.path.exists(file_path):\n    os.remove(file_path)\n    print(f\"✅ Deleted: {file_path}\")\nelse:\n    print(\"❌ File does not exist.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-25T16:24:34.249907Z","iopub.execute_input":"2025-07-25T16:24:34.250458Z","iopub.status.idle":"2025-07-25T16:24:34.275523Z","shell.execute_reply.started":"2025-07-25T16:24:34.250437Z","shell.execute_reply":"2025-07-25T16:24:34.274960Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def delete_folder(path):\n    for root, dirs, files in os.walk(path, topdown=False):\n        for file in files:\n            os.remove(os.path.join(root, file))\n        for dir in dirs:\n            os.rmdir(os.path.join(root, dir))\n    os.rmdir(path)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for epoch in tqdm(epochs,desc='Deleting Folders'):\n    epoch_x = epoch.split('/')[-1]\n    delete_folder(f'/kaggle/working/{epoch_x}')","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}