{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import torch\nimport torchvision.transforms as transforms\nimport torchvision.datasets as datasets\nimport torchvision.models as models\nimport torch.nn as nn\nimport torch.optim as optim\nimport numpy as np\nfrom PIL import Image\nimport matplotlib.pyplot as plt","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"transformations = transforms.Compose([\n    transforms.Resize(255),\n    transforms.CenterCrop(224),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data = datasets.ImageFolder('../input/hotel-id-2021-fgvc8/train_images', transform=transformations)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_ratio=0.8\n\ntrain_size = int(len(data)*train_ratio)\nval_size = len(data) - train_size\n\ntrain_set, val_set = torch.utils.data.random_split(data, [train_size, val_size])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_loader = torch.utils.data.DataLoader(train_set, batch_size=32, shuffle=True)\nval_loader = torch.utils.data.DataLoader(val_set, batch_size=32, shuffle=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = models.densenet161(pretrained=True)\n\nfor param in model.parameters():\n    param.requires_grad = False","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import os, os.path\nDATA_PATH = '../input/hotel-id-2021-fgvc8/train_images'\nlen([name for name in os.listdir(DATA_PATH) if os.path.isdir(os.path.join(DATA_PATH, name))])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"classifier_input = model.classifier.in_features\nnum_labels = len([name for name in os.listdir(DATA_PATH) if os.path.isdir(os.path.join(DATA_PATH, name))])\n\n# ここは画像認識の構造がよく理解できるようになる\n# 詳細1: https://konchangakita.hatenablog.com/entry/2020/05/03/220000\n# 詳細2: https://www.javaer101.com/article/1077460.html\n# nn.ConV2d(1,6,5): (入力チャンネル、出力チャンネル、カーネルサイズ), 詳細: https://www.atmarkit.co.jp/ait/articles/2005/29/news029_2.html\n# torch.nnの機能まとめ: https://pytorch.org/docs/stable/nn.html#linear-layers\n# 畳み込み→活性化関数→プーリング→畳み込み→活性化関数→プーリング→全結合\n\"\"\"\nclassifier = nn.Sequential(nn.Conv2d(in_channels=3, out_channels=64, \n                                     kernel_size=(5,5), stride=(1,1)),\n                           nn.ReLU(),\n                           nn.MaxPool2d(kernel_size=2, stride=2),\n                           nn.Conv2d(64, 128, 5),\n                           nn.ReLU(),\n                           nn.MaxPool2d(2, stride=1),\n                           nn.Linear(4*4*128, 1024),     # 4×4はcv2のカーネルサイズ5×5をプーリングした結果のものであり、4*4*128はすべての入力特徴量の数値である\n                           nn.ReLU(),\n                           nn.Linear(1024, num_labels),\n                           nn.LogSoftmax(dim=1)\n                           )\nmodel.classifier = classifier\n\"\"\"\nclassifier = nn.Sequential(nn.Linear(classifier_input, 1024),\n                           nn.ReLU(),\n                           nn.Linear(1024, 512),\n                           nn.ReLU(),\n                           nn.Linear(512, num_labels),\n                           nn.LogSoftmax(dim=1)\n                          )\nmodel.classifier = classifier","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nmodel.to(device)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"criterion = nn.NLLLoss()\noptimizer = optim.Adam(model.classifier.parameters())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"epochs = 1\nfor epoch in range(epochs):\n    train_loss = 0\n    val_loss = 0\n    accuracy = 0\n    \n    model.train()\n    counter = 0\n    for inputs, labels in train_loader:\n        inputs, labels = inputs.to(device), labels.to(device)\n        optimizer.zero_grad()\n        output = model.forward(inputs)\n        loss = criterion(output, labels)\n        loss.backward()\n        optimizer.step()\n        train_loss += loss.item()*inputs.size(0)\n        counter += 1\n        print(counter, '/', len(train_loader))\n    \n    model.eval()\n    counter = 0\n    with torch.no_grad():\n        for inputs, labels in val_loader:\n            inputs, labels = inputs.to(device), labels.to(device)\n            output = model.forward(inputs)\n            valloss = criterion(output, labels)\n            val_loss = valloss.item()*inputs.size(0)\n            output = torch.exp(output)\n            top_p, top_class = output.topk(1, dim=1)\n            equals = top_class == labels.view(*top_class.shape)\n            accuracy += torch.mean(equals.type(torch.FloatTensor)).item()\n            counter += 1\n            print(counter,'/',len(val_loader))\n            \n    train_loss = train_loss / len(train_loader.dataset)\n    valid_loss = val_loss / len(val_loader.dataset)\n    print('Accuracy: ', accuracy / len(val_loader))\n    print('Epoch: {} \\tTraining Loss: {:.6f} \\tValidation Loss: {:.6f}'.format(epoch, train_loss, valid_loss))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.eval()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def process_image(image_path):\n    img = Image.open(image_path)\n    width, height = img.size\n    img.resize((255, int(255*height/width)) if width < height else (int(255*width/height), 255))\n    \n    left = (224 - width) / 2\n    top = (224 - height) / 2\n    right = (224 + width) / 2\n    bottom = (224 + height) /2\n    img = img.crop((left, top, right, bottom))\n    \n    img = np.array(img)\n    \n    img = img.transpose((2,0,1))   # HWC → CHW    (推論エンジンのフォーマットはCHW型のため変換が必要)\n    img = img/255\n    \n    img[0] = (img[0] - 0.485) / 0.229\n    img[1] = (img[1] - 0.456) / 0.224\n    img[2] = (img[2] - 0.406) / 0.225\n    \n    img = img[np.newaxis,:]\n    \n    image = torch.from_numpy(img)\n    image = image.float()\n    return image","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def predict(image, model):\n    output = model.forward(image)\n    output = torch.exp(output)\n    probs, classes = output.topk(1, dim=1)\n    return probs.item(), classes.item()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def show_image(image):\n    image = image.numpy()\n    \n    image[0] = image[0]*0.226 + 0.445\n    \n    fig = plt.figure(figsize=(25,4))\n    plt.imshow(np.transpose(image[0], (1,2,0)))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\"\"\"\nTEST_PATH = \nimage_file = []\nfor name_dir in os.listdir(DATA_PATH):\n    dir_path = os.path.join(DATA_PATH, name_dir)\n    for name_img in dir_path:\n        img_path = os.path.join(dir_path, name_img):\n        image_file.append(img_path)\n\"\"\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"TEST_PATH = '../input/hotel-id-2021-fgvc8/test_images'\ntest_file =  []\nfor name in os.listdir(TEST_PATH):\n    test_image = os.path.joint(TEST_PATH, name)\n    test_file.append(test_image)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class_file = []\nfor image_path in test_file:\n    image = process_image(image_path)\n    top_prob, top_class = predict(image, model)\n    show_image(image)\n    print(\"The model is \", top_prob*100, \"% certain that the image has a predicted class of \", top_class)\n    class_file.append(top_class)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cla_to_label = {}\nfor cla, label in zip(range(num_labels), os.listdir(DATA_PATH)):\n    cla_to_label[cla] = label","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"hotel_data = pd.read_csv('../input/hotel-id-2021-fgvc8/train.csv')\nsubmission_data = pd.read_csv('../input/hotel-id-2021-fgvc8/sample_submission.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"hotel_data.drop(['image', 'timestamp'], axis=1, inplace=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"h_id = ''\ncounter = 0\nfor key, value in cla_to_label.items():\n    hotelID = hotel_data[hotel_data['chain'] == value]['hotel_id']\n    for Id in hotelID:\n        h_id = h_id + Id + ' '\n    submission_data['hotel_id'][counter] = h_id\n    counter += 1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission_data.to_csv('./kc_Hotel-ID.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}