{"cells":[{"metadata":{"trusted":true},"cell_type":"code","source":"!mkdir dogsvscats\n!unzip ../input/dogs-vs-cats-redux-kernels-edition/train -d dogsvscats/\n!unzip ../input/dogs-vs-cats-redux-kernels-edition/test -d dogsvscats/","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"92f7e9c9-1d45-49e4-95cd-954610d05a3e","_cell_guid":"b4b3c134-6f06-4947-9653-0c8fdb5c8b80","trusted":true},"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.utils.data as data\nimport matplotlib.pyplot as plt\nimport torchvision.transforms as transforms\nfrom PIL import Image\nimport pandas as pd\nimport numpy as np\nimport math\nimport time\nimport os\nimport gc\n\n# Configurations\nINPUT_PATH = \"dogsvscats\"\nOUTPUT_PATH = \"dogsvscats\"\nORIGIN_DATA_SIZE = 12500\nTARGET_DATA_SIZE = 12500\nRATIO = 0.99\nEPOCH = 15\nBATCH_SIZE = 75\nLOSS_FUNC = nn.BCELoss()\nLR = 0.0001\nSWITCH = 2\nUPDATE = 5\nTRANSFORM = transforms.Compose([transforms.Resize((256,256)),\n                                transforms.RandomCrop((224,224)),\n                                transforms.ToTensor(),\n                                transforms.Normalize((0.485,0.456,0.406),(0.229,0.224,0.225))\n                               ])\nPARAMETERS = \"../input/vgg19parameters20/VGG1920-L(0.164306)E(4.400)\"\n\nclass ImageDataset(data.Dataset):\n    def __init__(self, image_list, label_list):\n        self.data = image_list\n        self.label = label_list\n\n    def __getitem__(self, index):\n        global TRANSFORM\n        img = Image.open(self.data[index])\n        data = TRANSFORM(img)\n        img.close()\n        return data.cuda(),torch.cuda.FloatTensor([self.label[index]])\n\n    def __len__(self):\n        return len(self.data)\n\nclass VGG(nn.Module):\n    def __init__(self, name=\"11\"):\n        super(VGG, self).__init__()\n        self.name = \"VGG\"+name\n        self.conv = nn.Sequential()\n        i = 1; p = 1\n        self.conv.add_module('conv-{0}'.format(i),nn.Conv2d(in_channels=  3, out_channels= 64, kernel_size=3, stride=1, padding=1))\n        self.conv.add_module('ReLU-{0}'.format(i),nn.ReLU());i+=1\n        if name in [\"13\",\"16-1\",\"16\",\"19\"]:\n            self.conv.add_module('conv-{0}'.format(i),nn.Conv2d(in_channels= 64, out_channels= 64, kernel_size=3, stride=1, padding=1))\n            self.conv.add_module('ReLU-{0}'.format(i),nn.ReLU());i+=1\n        if name in [\"11-LRN\"]:\n            self.conv.add_module('LRN',nn.LocalResponseNorm(size=2))\n        self.conv.add_module('MaxPooling-{0}'.format(p),nn.MaxPool2d(kernel_size=2, stride=2));p+=1   # 224 -> 112\n\n        self.conv.add_module('conv-{0}'.format(i),nn.Conv2d(in_channels= 64, out_channels=128, kernel_size=3, stride=1, padding=1))\n        self.conv.add_module('ReLU-{0}'.format(i),nn.ReLU());i+=1\n        if name in [\"13\",\"16-1\",\"16\",\"19\"]:\n            self.conv.add_module('conv-{0}'.format(i),nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=1, padding=1))\n            self.conv.add_module('ReLU-{0}'.format(i),nn.ReLU());i+=1\n        self.conv.add_module('MaxPooling-{0}'.format(p),nn.MaxPool2d(kernel_size=2, stride=2));p+=1   # 112 -> 56\n\n        self.conv.add_module('conv-{0}'.format(i),nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, stride=1, padding=1))\n        self.conv.add_module('ReLU-{0}'.format(i),nn.ReLU());i+=1\n        self.conv.add_module('conv-{0}'.format(i),nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=1))\n        self.conv.add_module('ReLU-{0}'.format(i),nn.ReLU());i+=1\n        if name in [\"16\",\"19\"]:\n            self.conv.add_module('conv-{0}'.format(i),nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=1))\n            self.conv.add_module('ReLU-{0}'.format(i),nn.ReLU());i+=1\n        if name in [\"16-1\"]:\n            self.conv.add_module('conv-{0}'.format(i),nn.Conv2d(in_channels=256, out_channels=256, kernel_size=1, stride=1, padding=0))\n            self.conv.add_module('ReLU-{0}'.format(i),nn.ReLU());i+=1\n        if name in [\"19\"]:\n            self.conv.add_module('conv-{0}'.format(i),nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=1))\n            self.conv.add_module('ReLU-{0}'.format(i),nn.ReLU());i+=1\n        self.conv.add_module('MaxPooling-{0}'.format(p),nn.MaxPool2d(kernel_size=2, stride=2));p+=1   # 56 -> 28\n\n        self.conv.add_module('conv-{0}'.format(i),nn.Conv2d(in_channels=256, out_channels=512, kernel_size=3, stride=1, padding=1))\n        self.conv.add_module('ReLU-{0}'.format(i),nn.ReLU());i+=1\n        self.conv.add_module('conv-{0}'.format(i),nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1))\n        self.conv.add_module('ReLU-{0}'.format(i),nn.ReLU());i+=1\n        if name in [\"16\",\"19\"]:\n            self.conv.add_module('conv-{0}'.format(i),nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1))\n            self.conv.add_module('ReLU-{0}'.format(i),nn.ReLU());i+=1\n        if name in [\"16-1\"]:\n            self.conv.add_module('conv-{0}'.format(i),nn.Conv2d(in_channels=512, out_channels=512, kernel_size=1, stride=1, padding=0))\n            self.conv.add_module('ReLU-{0}'.format(i),nn.ReLU());i+=1\n        if name in [\"19\"]:\n            self.conv.add_module('conv-{0}'.format(i),nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1))\n            self.conv.add_module('ReLU-{0}'.format(i),nn.ReLU());i+=1\n        self.conv.add_module('MaxPooling-{0}'.format(p),nn.MaxPool2d(kernel_size=2, stride=2));p+=1   # 28 -> 14\n\n        self.conv.add_module('conv-{0}'.format(i),nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1))\n        self.conv.add_module('ReLU-{0}'.format(i),nn.ReLU());i+=1\n        self.conv.add_module('conv-{0}'.format(i),nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1))\n        self.conv.add_module('ReLU-{0}'.format(i),nn.ReLU());i+=1\n        if name in [\"16\",\"19\"]:\n            self.conv.add_module('conv-{0}'.format(i),nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1))\n            self.conv.add_module('ReLU-{0}'.format(i),nn.ReLU());i+=1\n        if name in [\"16-1\"]:\n            self.conv.add_module('conv-{0}'.format(i),nn.Conv2d(in_channels=512, out_channels=512, kernel_size=1, stride=1, padding=0))\n            self.conv.add_module('ReLU-{0}'.format(i),nn.ReLU());i+=1\n        if name in [\"19\"]:\n            self.conv.add_module('conv-{0}'.format(i),nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1))\n            self.conv.add_module('ReLU-{0}'.format(i),nn.ReLU());i+=1\n        self.conv.add_module('MaxPooling-{0}'.format(p),nn.MaxPool2d(kernel_size=2, stride=2));p+=1   # 14 -> 7\n\n        self.fc = nn.Sequential(\n            nn.Linear(512*7*7,4096),\n            nn.ReLU(),\n            nn.Dropout(0.5),\n            nn.Linear(4096,4096),\n            nn.ReLU(),\n            nn.Dropout(0.5),\n            nn.Linear(4096,1000),\n            nn.ReLU(),\n            nn.Linear(1000,1),\n            nn.Sigmoid()\n        )\n\n    def forward(self, x):\n        x = self.conv(x)\n        x = x.view(x.shape[0], -1)\n        x = self.fc(x)\n        return x\n\ndef train(optimizer):\n    global net\n    global EPOCH\n    global BATCH_SIZE\n    global train_data\n    global validate_data\n    global PROGRAM_START\n    print('['+net.name+'] with optimizer ['+str(type(optimizer))+']:')\n    train_loader = data.DataLoader(train_data, batch_size=BATCH_SIZE, shuffle=True, num_workers=0)\n    validate_loader = data.DataLoader(validate_data, batch_size=1, shuffle=False, num_workers=0)\n    BATCH = len(train_loader)\n    m = len(validate_loader)\n    for epoch in range(EPOCH):\n        EPOCH_START = time.time()\n        print(\"\\tEpoch #{0}/{1}:\".format(epoch+1,EPOCH))\n        for batch,(x,y) in enumerate(train_loader):\n            optimizer.zero_grad()\n            t = net(x)\n            loss = LOSS_FUNC(t,y)\n            print(\"\\t\\tBatch #{0}/{1}: \".format(batch+1,BATCH) + \"Loss = %.6f\"%float(loss))\n            loss.backward()\n            optimizer.step()\n        with torch.no_grad():\n            L = 0.\n            E = 0.\n            for batch,(x,y) in enumerate(validate_loader):\n                t = net(x)\n                L += float(LOSS_FUNC(t,y))\n                E += float((float(t[0][0])>0.5)!=y)\n            print(\"\\t  Validation Loss = %.6f. Error Rate = %.3f%%\"%(L/m,E*100/m))\n            if((epoch+1)%UPDATE==0):\n                torch.save(net.state_dict(),OUTPUT_PATH+\"/{0}[{1}]\".format(net.name,epoch+1)+\"-L(%.6f)E(%.3f).pt\"%(L/m,E*100/m))\n                torch.save(optimizer.state_dict(),OUTPUT_PATH+\"/{0}[{1}]\".format(net.name,epoch+1)+\"-L(%.6f)E(%.3f)-optimizer.pt\"%(L/m,E*100/m))\n        print(\"\\t  Finish epoch #{0}\".format(epoch+1)+\" in %.4f s.\"%(time.time()-EPOCH_START)+\" Total Time Cost = %.4f s.\"%(time.time()-PROGRAM_START))\n\ndef run(filename):\n    global net\n    global test_data\n    prediction = []\n    test_loader = data.DataLoader(test_data, batch_size=1, shuffle=False, num_workers=0)\n    with torch.no_grad():\n        for i,(x,y) in enumerate(test_loader):\n            t = net(x)\n            prediction.append([i+1,float(t[0][0])])\n    submission = pd.DataFrame(prediction)\n    submission.columns = ['id','label']\n    submission.to_csv(filename+\".csv\",index=0)\n\ndef load():\n    np.random.seed(998244353)\n    torch.manual_seed(998244353)\n    image_list = []\n    label_list = []\n    for i in range(ORIGIN_DATA_SIZE):\n        image_list.append(INPUT_PATH+\"/train/cat.{0}.jpg\".format(i))\n        label_list.append(0)\n        image_list.append(INPUT_PATH+\"/train/dog.{0}.jpg\".format(i))\n        label_list.append(1)\n    n = int(ORIGIN_DATA_SIZE*2*RATIO)\n    train_data = ImageDataset(image_list[:n],label_list[:n])\n    validate_data = ImageDataset(image_list[n:],label_list[n:])\n    image_list = []\n    for i in range(TARGET_DATA_SIZE):\n        image_list.append(INPUT_PATH+\"/test/{0}.jpg\".format(i+1))\n    test_data = ImageDataset(image_list,[0]*TARGET_DATA_SIZE)\n    # np.random.seed()\n    # torch.seed()\n    return train_data,validate_data,test_data\n\nprint(\"*****Start\")\nPROGRAM_START = time.time()\ntrain_data,validate_data,test_data = load()\nprint(\"Finish reading data in %.4f s.\"%(time.time()-PROGRAM_START))\nnet = VGG(\"19\")\nif SWITCH//2==1 and PARAMETERS!=\"\":\n    net.load_state_dict(torch.load(PARAMETERS+\".pt\"))\n    print(\"Load Model [\"+PARAMETERS+\".pt] Success!\")\nnet.cuda()\noptimizer = optim.RMSprop(net.parameters(), lr=LR, alpha=0.9)\nif SWITCH//2==1 and PARAMETERS!=\"\":\n    optimizer.load_state_dict(torch.load(PARAMETERS+\"-optimizer.pt\"))\n    print(\"Load Optimizer [\"+PARAMETERS+\"-optimizer.pt] Success!\")\nLOSS_FUNC.cuda()\nif SWITCH% 2==1:\n    train(optimizer)\nTRANSFORM = transforms.Compose([transforms.Resize((224,224)),\n                                transforms.ToTensor(),\n                                transforms.Normalize((0.485,0.456,0.406),(0.229,0.224,0.225))\n                               ])\nrun(OUTPUT_PATH+\"/{0}\".format(net.name))\nprint(\"*****Finish\")","execution_count":null,"outputs":[]}],"metadata":{"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"}},"nbformat":4,"nbformat_minor":1}