{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import copy\nimport cv2\nimport numpy as np \nimport os\nimport pandas as pd \nimport traceback\nimport zipfile\n\n\nfrom tqdm import tqdm\nfrom sklearn.metrics import roc_auc_score, accuracy_score\nfrom sklearn.model_selection import train_test_split\n\nimport torch\nfrom torch import nn\nfrom torch.nn import functional as F\nfrom torch.utils.data import DataLoader, Dataset\n\n\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"with zipfile.ZipFile('/kaggle/input/dogs-vs-cats/train.zip', 'r') as zip_ref:\n    zip_ref.extractall('data')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(os.listdir('data'))\nprint(len(os.listdir('/kaggle/working/data/train')))\nprint(os.listdir('/kaggle/working/data/train')[:10])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class DataPreparation():\n    def __init__(self, img_size=64, data_path='/data'):\n        self.img_size=img_size\n        self.data_path = data_path\n        self.labels = {'cat': 0, 'dog': 1}\n        self.training_data =[]\n        self.cat_cnt = 0\n        self.dog_cnt = 0\n        \n    def prepare_train_data(self):\n        for f in tqdm(os.listdir(self.data_path)):\n            try:\n                file_path = os.path.join(self.data_path, f)\n                label = self.labels[f[:f.index('.')]]\n                img = cv2.imread(file_path, cv2.IMREAD_GRAYSCALE)\n                img = cv2.resize(img, (self.img_size, self.img_size))\n                self.training_data.append([np.array(img), label])\n                \n                if label == 0:\n                    self.cat_cnt += 1\n                elif label == 1:\n                    self.dog_cnt += 1\n                    \n            except Exception as e:\n                pass\n                # print(e)\n                \n            \n        np.random.shuffle(self.training_data)\n        print('Cats: {}'.format(self.cat_cnt))\n        print('Dogs: {}'.format(self.dog_cnt))\n            \n            \ncats_and_dogs = DataPreparation(img_size=128, data_path='/kaggle/working/data/train')\ncats_and_dogs.prepare_train_data()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X = torch.Tensor([i[0] for i in cats_and_dogs.training_data]).view(-1, 1, 128, 128)\n\nX_max = X.max() # to re-use with new data\nX /= X_max\ny = torch.Tensor([i[1] for i in cats_and_dogs.training_data])\n\n\nX_train, X_test, y_train, y_test = train_test_split(\n    X, y, test_size=0.1, stratify=y)\n\ndel cats_and_dogs","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nplt.imshow(X[12664].view(128, 128), cmap=\"gray\")\nprint(y[12664])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class nnDataset(Dataset):\n    def __init__(self, X_data, y_data):\n        self.X_data = X_data\n        self.y_data = y_data\n        \n    def __getitem__(self, index):\n        return self.X_data[index], self.y_data[index].long()\n        \n    def __len__ (self):\n        return len(self.X_data)\n    \n\ntrain = nnDataset(X_train, y_train)\ntest = nnDataset(X_test, y_test)\n\ntrain_loader = DataLoader(dataset=train, batch_size=64, shuffle=True)\ntest_loader = DataLoader(dataset=test, batch_size=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class Net(torch.nn.Module):\n    def __init__(self):\n        super(Net, self).__init__()\n        # 1 слой\n        self.conv1 = torch.nn.Conv2d(in_channels=1,\n                                     out_channels=32,\n                                     kernel_size=5,\n                                     padding=2)\n        \n        # 2 слой\n        self.conv2 = torch.nn.Conv2d(in_channels=32,\n                                     out_channels=64,\n                                     kernel_size=5,\n                                     padding=2)\n        \n        # 3 слой\n        self.conv3 = torch.nn.Conv2d(in_channels=64,\n                                     out_channels=128,\n                                     kernel_size=5,\n                                     padding=2)\n        \n        # 4 слой\n        self.conv4 = torch.nn.Conv2d(in_channels=128,\n                                     out_channels=128,\n                                     kernel_size=3,\n                                     padding=1)\n        \n        self.fc1 = torch.nn.Linear(8*8*128, 512)\n        self.fc2 = torch.nn.Linear(512, 128)        \n        self.fc3 = torch.nn.Linear(128, 32)        \n        self.fc4 = torch.nn.Linear(32, 2)\n        \n        \n        self.max_pool = torch.nn.MaxPool2d(kernel_size=2,\n                                        stride=2)\n       \n        self.avg_pool = torch.nn.AvgPool2d(kernel_size=2,\n                                        stride=2)\n        \n        self.batch_norm1 = torch.nn.BatchNorm1d(512)\n        self.batch_norm2 = torch.nn.BatchNorm1d(128)\n        \n        self.dropout50 =  torch.nn.Dropout(p=0.5)\n        self.dropout25 =  torch.nn.Dropout(p=0.25)\n        \n        self.act = torch.nn.ReLU()\n\n        \n        \n\n    def forward(self, x):\n        x = self.conv1(x) # 128 x 128\n        x = self.max_pool(x) # 64 x 64\n        x = self.dropout25(x)\n        x = self.act(x)\n        \n        \n        x = self.conv2(x)\n        x = self.max_pool(x) # 32 x 32\n        x = self.dropout25(x)\n        x = self.act(x)\n        \n         \n        x = self.conv3(x)\n        x = self.max_pool(x) # 16 x 16\n        x = self.dropout25(x)\n        x = self.act(x)\n        \n        x = self.conv4(x)\n        x = self.max_pool(x) # 8 x 8\n        x = self.dropout25(x)\n        x = self.act(x)\n        \n        x = x.view(x.size(0), x.size(1) * x.size(2) * x.size(3))\n\n        x = self.fc1(x) # 8 x 8 x 128\n        x = self.batch_norm1(x)\n        x = self.act(x)\n        x = self.fc2(x)\n        x = self.batch_norm2(x)\n        x = self.act(x)\n        x = self.fc3(x)\n        x = self.dropout25(x)\n        x = self.act(x)\n        x = self.fc4(x)\n        \n        return F.softmax(x, dim=1) # torch.sigmoid(x)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n\n# model = binaryClassification(n_features=64*64, n_hidden_neurons=64, dropout_ratio=0.1)\nmodel = Net()\nmodel.to(device)\n\ncriterion = torch.nn.CrossEntropyLoss() \noptimizer = torch.optim.Adam(model.parameters(), lr=1e-3)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def train_eval_nn(model,\n                  train_dataloader, test_dataloader,\n                  loss_function, optimizer,\n                  n_epochs, early_stopping_patience,\n                  lr=1e-3, l2_reg_alpha=0,\n                  scheduler=None, device=None):\n    \n    if device is None:\n        device = 'cuda' if torch.cuda.is_available() else 'cpu'\n    device = torch.device(device)\n    model.to(device)\n    \n    if scheduler:\n        optimizer = torch.optim.Adam(model.parameters(), lr=lr, weight_decay=l2_reg_alpha)\n        lr_scheduler = scheduler(optimizer)\n    else:\n        lr_scheduler = None\n\n    \n    best_val_loss = float('inf')\n    best_epoch_i = 0\n    best_model = copy.deepcopy(model)\n\n    for epoch_i in range(n_epochs):\n        try:\n            model.train()\n            mean_train_loss = 0\n            train_batches_n = 0\n\n\n            for idx, (batch_x, batch_y) in enumerate(train_dataloader):\n                if idx > 10000:\n                    break\n                optimizer.zero_grad()\n\n                x_batch = batch_x.to(device)\n                y_batch = batch_y.to(device)\n                preds = model(x_batch)\n                loss_val = loss_function(preds, y_batch)\n                # optimizer.zero_grad()\n\n                loss_val.backward()\n                optimizer.step()\n\n                mean_train_loss += float(loss_val)\n                train_batches_n += 1\n\n            mean_train_loss /= train_batches_n\n            print('Среднее значение функции потерь на обучении', mean_train_loss)\n\n\n            model.eval()               \n            mean_val_loss = 0\n            val_batches_n = 0\n\n            with torch.no_grad():\n                for idx, (batch_x, batch_y) in enumerate(test_dataloader):\n                    if idx > 1000:\n                        break\n\n                    x_batch = batch_x.to(device)\n                    y_batch = batch_y.to(device)\n\n                    preds = model.forward(x_batch)\n                    loss_val = loss_function(preds, y_batch)\n\n                    mean_val_loss += float(loss_val)\n                    val_batches_n += 1\n\n            mean_val_loss /= val_batches_n\n            print('Среднее значение функции потерь на валидации', mean_val_loss)\n            \n            if mean_val_loss < best_val_loss:\n                best_epoch_i = epoch_i\n                best_val_loss = mean_val_loss\n                best_model = copy.deepcopy(model)\n                print('Новая лучшая модель!')\n                \n            elif epoch_i - best_epoch_i > early_stopping_patience:\n                print('Модель не улучшилась за последние {} эпох, прекращаем обучение'.format(\n                early_stopping_patience))\n                break\n            \n            if lr_scheduler:\n                lr_scheduler.step(mean_val_loss)\n                \n            print()\n        except KeyboardInterrupt:\n            print('Досрочно остановлено пользователем')\n            break\n                \n        except Exception as ex:\n            print('Ошибка при обучении {}\\n{}'.format(ex, traceback.format_exc()))\n            break\n            \n    return best_val_loss, best_model\n\n\n\nbest_val_loss, best_model = train_eval_nn(model=model, device=device,\n              train_dataloader=train_loader,\n              test_dataloader=test_loader,\n              loss_function=criterion, optimizer=optimizer,\n              n_epochs=500, early_stopping_patience=20,\n               lr=1e-3, l2_reg_alpha=0,\n              scheduler=lambda optim: torch.optim.lr_scheduler.StepLR(optim, step_size=10, gamma=0.1))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def predict_with_model(model, dataset, device=None, batch_size=32, num_workers=0, return_labels=False):\n    if device is None:\n        device = 'cuda' if torch.cuda.is_available() else 'cpu'\n    results_by_batch = []\n\n    device = torch.device(device)\n    model.to(device)\n    model.eval()\n\n    dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=False, num_workers=num_workers)\n    labels = []\n    with torch.no_grad():\n        import tqdm\n        for batch_x, batch_y in tqdm.tqdm(dataloader, total=len(dataset)/batch_size):\n            batch_x = batch_x.to(device)\n\n            if return_labels:\n                labels.append(batch_y.numpy())\n\n            batch_pred = model(batch_x)\n            results_by_batch.append(batch_pred.detach().cpu().numpy())\n\n    if return_labels:\n        return np.concatenate(results_by_batch, 0), np.concatenate(labels, 0)\n    else:\n        return np.concatenate(results_by_batch, 0)\n    \n    \ntest_pred = predict_with_model(best_model, test, return_labels=True)\n\n\nprint('Accuracy:', accuracy_score(y_test, np.argmax(test_pred[0], axis=1)))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img = cv2.imread('/kaggle/input/mars-the-doggie/photo_2020-05-02_20-06-38.jpg', cv2.IMREAD_GRAYSCALE)\n# img = cv2.resize(img, (self.img_size, self.img_size))\n\nplt.imshow(img, cmap=\"gray\");","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img = cv2.resize(img, (128, 128))\n\nmars = torch.Tensor(img).view(-1, 1, 128, 128)\nmars /= X_max\n\npred = best_model.forward(mars.to(device)).detach().cpu().numpy()\npred_label = np.argmax(pred, axis=1)\npred_label = 'Dog' if pred_label==1 else 'Cat'\n\nprint('Mars is {}'.format(pred_label))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img = cv2.imread('/kaggle/input/ivanych/photo_2020-05-02_20-46-12.jpg', cv2.IMREAD_GRAYSCALE)\n# img = cv2.resize(img, (self.img_size, self.img_size))\n\nplt.imshow(img, cmap=\"gray\");","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img = cv2.resize(img, (128, 128))\n\ndzhoy = torch.Tensor(img).view(-1, 1, 128, 128)\ndzhoy /= X_max\n\n\npred = best_model.forward(dzhoy.to(device)).detach().cpu().numpy()\npred_label = np.argmax(pred, axis=1)\npred_label = 'Dog' if pred_label==1 else 'Cat'\n\nprint('Dzhoy is {}'.format(pred_label))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img = cv2.imread('/kaggle/input/marik/photo_2020-05-02_20-53-04.jpg', cv2.IMREAD_GRAYSCALE)\n# img = cv2.resize(img, (self.img_size, self.img_size))\n\nplt.imshow(img, cmap=\"gray\");","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img = cv2.resize(img, (128, 128))\n\nmarik = torch.Tensor(img).view(-1, 1, 128, 128)\nmarik /= X_max\n\n\npred = best_model.forward(marik.to(device)).detach().cpu().numpy()\npred_label = np.argmax(pred, axis=1)\npred_label = 'Dog' if pred_label==1 else 'Cat'\n\nprint('Marik is {}'.format(pred_label))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img = cv2.imread('/kaggle/input/bulldog/photo_2020-05-02_21-08-43.jpg', cv2.IMREAD_GRAYSCALE)\n# img = cv2.resize(img, (self.img_size, self.img_size))\n\nplt.imshow(img, cmap=\"gray\");","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img = cv2.resize(img, (128, 128))\n\nbulldog = torch.Tensor(img).view(-1, 1, 128, 128)\nbulldog /= X_max\n\npred = best_model.forward(bulldog.to(device)).detach().cpu().numpy()\npred_label = np.argmax(pred, axis=1)\npred_label = 'Dog' if pred_label==1 else 'Cat'\n\nprint('This is {}'.format(pred_label))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img = cv2.imread('/kaggle/input/big-cat/photo_2020-05-02_21-34-45.jpg', cv2.IMREAD_GRAYSCALE)\n# img = cv2.resize(img, (self.img_size, self.img_size))\n\nplt.imshow(img, cmap=\"gray\");","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img = cv2.resize(img, (128, 128))\n\ncat = torch.Tensor(img).view(-1, 1, 128, 128)\ncat /= X_max\n\npred = best_model.forward(cat.to(device)).detach().cpu().numpy()\npred_label = np.argmax(pred, axis=1)\npred_label = 'Dog' if pred_label==1 else 'Cat'\n\nprint('This is {}'.format(pred_label))","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}