{"metadata":{"kernelspec":{"name":"python3","language":"python","display_name":"Python 3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"}],"dockerImageVersionId":31153,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# I'm Something of a Painter Myself\nThis notebook trains a DCGAN to generate paintings.","metadata":{}},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as pooppt\nfrom torchvision import transforms as ttt\nfrom torch.utils.data import DataLoader as DL, Dataset as dsds\nimport os, zipfile\nfrom PIL import Image\nimport matplotlib.pyplot as blahplt\n\nugly_flag = True\n\nclass WeirdG(nn.Module):\n    def __init__(self):\n        super(WeirdG,self).__init__()\n        zz = nn.ReLU(True)\n        self.enc = nn.Sequential(\n            nn.Conv2d(3,64,4,2,1),\n            zz,\n            nn.Conv2d(64,128,4,2,1),\n            nn.BatchNorm2d(128),\n            zz,\n            nn.Conv2d(128,256,4,2,1),\n            nn.BatchNorm2d(256),\n            zz\n        )\n        self.dec = nn.Sequential(\n            nn.ConvTranspose2d(256,128,4,2,1),\n            nn.BatchNorm2d(128),\n            zz,\n            nn.ConvTranspose2d(128,64,4,2,1),\n            nn.BatchNorm2d(64),\n            zz,\n            nn.ConvTranspose2d(64,3,4,2,1),\n            nn.Tanh()\n        )\n\n    def forward(self,q):\n        a = self.enc(q)\n        a = self.dec(a)\n        return a\n\nclass BadD(nn.Module):\n    def __init__(self):\n        super(BadD,self).__init__()\n        hmm = nn.LeakyReLU(0.2,True)\n        self.whatever = nn.Sequential(\n            nn.Conv2d(3,64,4,2,1),\n            hmm,\n            nn.Conv2d(64,128,4,2,1),\n            nn.BatchNorm2d(128),\n            hmm,\n            nn.Conv2d(128,256,4,2,1),\n            nn.BatchNorm2d(256),\n            hmm,\n            nn.Conv2d(256,1,4,1,1)\n        )\n    def forward(self,k):\n        return self.whatever(k)\n\nG = WeirdG()\nD = BadD()\n\ndev = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nG = G.to(dev)\nD = D.to(dev)\n\nmse = nn.MSELoss()\nabs_loss1 = nn.L1Loss()\nabs_loss2 = nn.L1Loss()\n\noptG = pooppt.Adam(G.parameters(),lr=0.0001,betas=(0.5,0.999))\noptD = pooppt.Adam(D.parameters(),lr=0.0001,betas=(0.5,0.999))\n\ncrappy_tf = ttt.Compose([\n    ttt.Resize((256,256)),\n    ttt.ToTensor(),\n    ttt.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5])\n])\n\ndata_root = '/kaggle/input/gan-getting-started/'\npathA = os.path.join(data_root,'photo_jpg')\npathB = os.path.join(data_root,'monet_jpg')\n\nlstA = [os.path.join(pathA,x) for x in os.listdir(pathA)]\nlstB = [os.path.join(pathB,x) for x in os.listdir(pathB)]\n\nclass RandoDataset(dsds):\n    def __init__(self,files,tr=None):\n        self.f = files\n        self.t = tr\n    def __len__(self):\n        return len(self.f)\n    def __getitem__(self,i):\n        ff = self.f[i]\n        im = Image.open(ff).convert(\"RGB\")\n        if self.t:\n            im = self.t(im)\n        return im\n\nsetA = RandoDataset(lstA,crappy_tf)\nsetB = RandoDataset(lstB,crappy_tf)\n\nloadA = DL(setA,batch_size=16,shuffle=True)\nloadB = DL(setB,batch_size=2,shuffle=True)\n\nepo = 10\nfor zzepoch in range(epo):\n    for aa,(pict,mon) in enumerate(zip(loadA,loadB)):\n        rA = pict.to(dev)\n        rB = mon.to(dev)\n\n        optG.zero_grad()\n        fak = G(rA)\n        val = D(fak)\n        gl = mse(val,torch.ones_like(val)) + abs_loss1(G(fak),rA) + abs_loss2(G(rA),rA)\n        gl.backward()\n        optG.step()\n\n        optD.zero_grad()\n        rv = D(rB)\n        fv = D(fak.detach())\n        dl = (mse(rv,torch.ones_like(rv)) + mse(fv,torch.zeros_like(fv)))/2\n        dl.backward()\n        optD.step()\n\n        if aa % 10 == 0:\n            print(\"Epoch {}/{} step {} G={} D={}\".format(zzepoch+1,epo,aa,gl.item(),dl.item()))\n\n# visualization\ndef dumb_vis(ld,G,ct=5):\n    G.eval()\n    with torch.no_grad():\n        for _,pb in enumerate(ld):\n            rr = pb.to(dev)\n            ff = G(rr)\n            ff = (ff*0.5+0.5).clamp(0,1)\n            idx = 0\n            while idx < min(ct,len(ff)):\n                re = ttt.ToPILImage()(rr[idx].cpu())\n                fe = ttt.ToPILImage()(ff[idx].cpu())\n                blahplt.figure(figsize=(8,4))\n                blahplt.subplot(1,2,1)\n                blahplt.title(\"orig\")\n                blahplt.imshow(re)\n                blahplt.axis(\"off\")\n                blahplt.subplot(1,2,2)\n                blahplt.title(\"fake\")\n                blahplt.imshow(fe)\n                blahplt.axis(\"off\")\n                blahplt.show()\n                ct -= 1\n                if ct <= 0:\n                    return\n                idx+=1\n\ndumb_vis(loadA,G)\n\nbadout = \"../tmp/generated_images\"\nos.makedirs(badout,exist_ok=True)\n\nwith zipfile.ZipFile(\"images.zip\",\"w\") as zipp:\n    cnum = 1\n    for k,pb in enumerate(loadA):\n        ra = pb.to(dev)\n        fk = G(ra)\n        fk = (fk*0.5+0.5).clamp(0,1)\n        for jj,it in enumerate(fk):\n            xx = ttt.ToPILImage()(it.cpu())\n            pth = os.path.join(badout,\"img_\"+str(cnum)+\".jpg\")\n            xx.save(pth)\n            zipp.write(pth,os.path.basename(pth))\n            cnum+=1\n            if cnum>8000:\n                break\n        if cnum>8000:\n            break\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-23T18:52:55.774828Z","iopub.execute_input":"2025-10-23T18:52:55.775471Z","iopub.status.idle":"2025-10-23T18:58:46.171743Z","shell.execute_reply.started":"2025-10-23T18:52:55.775429Z","shell.execute_reply":"2025-10-23T18:58:46.170956Z"}},"outputs":[],"execution_count":null}]}