{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"#Pytorch modules\nimport torch\nfrom torch import nn\nfrom torch import optim\nfrom torch.utils.data import DataLoader\n\n#Import metcirs\nfrom sklearn.metrics import confusion_matrix, accuracy_score\n\n#Import math libs\nimport numpy as np\nfrom scipy import signal\n\n#Plotting\nimport matplotlib.pyplot as plt\nfrom mpl_toolkits.axes_grid1 import make_axes_locatable\nfrom mlxtend.plotting import plot_confusion_matrix\n\n#Status bar\nfrom tqdm.notebook import tqdm\n\n# Load files\nimport json\nimport os\nimport pandas as pd\n\nfrom collections import namedtuple","metadata":{"execution":{"iopub.status.busy":"2022-09-05T11:31:07.464372Z","iopub.execute_input":"2022-09-05T11:31:07.466258Z","iopub.status.idle":"2022-09-05T11:31:10.362227Z","shell.execute_reply.started":"2022-09-05T11:31:07.466137Z","shell.execute_reply":"2022-09-05T11:31:10.361093Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Helper functions","metadata":{}},{"cell_type":"code","source":"def rand_diap(num, diap):\n        low = np.log(diap[0])\n        high = np.log(diap[1])\n        tmp = np.random.rand(num)\n        tmp *= high - low\n        tmp += low\n        return np.exp(tmp)","metadata":{"execution":{"iopub.status.busy":"2022-09-05T11:31:10.364204Z","iopub.execute_input":"2022-09-05T11:31:10.364846Z","iopub.status.idle":"2022-09-05T11:31:10.371235Z","shell.execute_reply.started":"2022-09-05T11:31:10.364806Z","shell.execute_reply":"2022-09-05T11:31:10.370216Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Constants","metadata":{}},{"cell_type":"code","source":"ROOT_DIR = '../input/classification-of-defects-in-a-rotary-machine'\nRESULT_DIR = '../input/train-mlp/'\nWORK_DIR = './'\n\nSENSORS_LIST = np.array([0, 1, 2, 3, 8, 9])\nSENSORS_NUM = len(SENSORS_LIST)\nSENSORS_NAMES =  np.array(['X_left_bearing',\n                            'Y_left_bearing',\n                            'X_right_bearing',\n                            'Y_right_bearing',\n                            'X_left_bearing_smoosed',\n                            'Y_left_bearing_smoosed',\n                            'X_right_bearing_smoosed',\n                            'Y_right_bearing_smoosed',\n                            'Temperature_left',\n                            'Temperature_right'])[SENSORS_LIST]\nCLASSES_NUM = 4\n                    \nMEAN = np.array([5.506143093109131, \n                6.501108169555664, \n                6.133607864379883, \n                7.200148582458496, \n                5.506143093109131, \n                6.501108646392822, \n                6.133608341217041, \n                7.200153827667236, \n                1109.86279296875, \n                1108.7576904296875])[SENSORS_LIST]\n\nSTD = np.array([0.21205657720565796,\n                0.14815978705883026,\n                0.4135267734527588,\n                0.1607103794813156,\n                0.20784716308116913,\n                0.13870318233966827,\n                0.411641925573349,\n                0.15539060533046722,\n                6.792581558227539,\n                6.066262245178223])[SENSORS_LIST]","metadata":{"execution":{"iopub.status.busy":"2022-09-05T11:31:10.372818Z","iopub.execute_input":"2022-09-05T11:31:10.373412Z","iopub.status.idle":"2022-09-05T11:31:10.391638Z","shell.execute_reply.started":"2022-09-05T11:31:10.373374Z","shell.execute_reply":"2022-09-05T11:31:10.390334Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Create datasets","metadata":{}},{"cell_type":"code","source":"class DefectsDataset(torch.utils.data.Dataset):\n    def __init__(self, exp_nums=[1, 2, 3, 4], n=1000, sensors_list=SENSORS_LIST, mode='train'):\n        self.inputs = []\n        self.targets = []\n        self.n = n\n        self.sensors_list = sensors_list\n        \n        files = os.listdir(ROOT_DIR)\n        for file in files:\n            if mode == 'train' and 'data' in file and int(file.split('_')[1]) in exp_nums:\n                class_index = int(file.split('_')[2][:-4]) - 1\n                self.load_csv(class_index, os.path.join(ROOT_DIR, file))\n\n            elif mode == 'submit' and 'Series' in file and int(file.split('_')[1][:-4]) in exp_nums:\n                class_index = 0\n                self.load_csv(class_index, os.path.join(ROOT_DIR, file))\n        \n        self.inputs = torch.from_numpy(np.array(self.inputs).astype(np.float32))\n        self.targets = torch.from_numpy(np.array(self.targets).astype(np.int64))\n        \n        for i in range(len(MEAN)):\n            self.inputs[:, i] = (self.inputs[:, i] - MEAN[i]) / STD[i]\n    \n    def load_csv(self, class_index, path):\n        df = pd.read_csv(path)\n        df = df.to_numpy().astype(np.float32).T\n        df[8, :] = signal.savgol_filter(self.smoothing(df[8, :]), 1501, 1)\n        df[9, :] = signal.savgol_filter(self.smoothing(df[9, :]), 1501, 1)\n        for i in range(df.shape[1] // self.n):\n            self.inputs.append(df[self.sensors_list, i * self.n:(i + 1) * self.n])\n            self.targets.append(class_index)\n    \n    @staticmethod\n    def smoothing(array):\n        for i in range(len(array) // 1000):\n            try:\n                array[i * 1000:(i + 1) * 1000] = np.linspace(array[i * 1000], array[(i + 1) * 1000], 1000)\n            except IndexError:\n                array[i * 1000:(i + 1) * 1000] = np.linspace(array[i * 1000], array[((i + 1) * 1000) - 1], 1000)\n        return array\n                \n    def __getitem__(self, index):\n        return self.inputs[index], self.targets[index]\n    \n    def __len__(self):\n        return len(self.targets)","metadata":{"execution":{"iopub.status.busy":"2022-09-05T11:31:10.396713Z","iopub.execute_input":"2022-09-05T11:31:10.397306Z","iopub.status.idle":"2022-09-05T11:31:10.421656Z","shell.execute_reply.started":"2022-09-05T11:31:10.397269Z","shell.execute_reply":"2022-09-05T11:31:10.420493Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Create callback for train process","metadata":{}},{"cell_type":"markdown","source":"# Functions for work with model","metadata":{}},{"cell_type":"code","source":"def predict(loader, model):\n    \"\"\"Make model prediction on loader.\n\n    Args:\n        model (Model): Model for training.\n        loader (DataLoader): loader with data.\n\n    Returns:\n        tuple: (act_classes, pred_classes):\n            outputs_all (torch.Tensor): Tensor of all outputs.\n            labels_all (torch.Tensor): Tensor of actual labels.\n    \"\"\"\n    model.eval()\n\n    labels_all = None\n    outputs_all = None\n\n    for inputs, labels in iter(loader):\n        if torch.cuda.is_available():\n            inputs, labels = inputs.to('cuda'), labels.to('cuda')\n\n        outputs = model.forward(inputs)\n        if labels_all is None:\n            labels_all = labels.cpu()\n            outputs_all = outputs.cpu()\n\n        else:\n            labels_all = torch.cat((labels_all, labels.cpu()))\n            outputs_all = torch.cat((outputs_all, outputs.cpu()), 0)\n\n    model = None\n    inputs = None\n    labels = None\n    outputs = None\n    sm = None\n\n    torch.cuda.empty_cache()\n\n    return outputs_all, labels_all","metadata":{"execution":{"iopub.status.busy":"2022-09-05T11:31:10.423220Z","iopub.execute_input":"2022-09-05T11:31:10.423913Z","iopub.status.idle":"2022-09-05T11:31:10.438778Z","shell.execute_reply.started":"2022-09-05T11:31:10.423873Z","shell.execute_reply":"2022-09-05T11:31:10.437678Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model","metadata":{}},{"cell_type":"code","source":"class MLP(nn.Module):\n    def __init__(self, hidden_layer_size, hidden_layers, num_classes, frame_length):\n        super(MLP, self).__init__()\n        layers = []\n        for i in range(hidden_layers):\n            if not i:\n                layers += [nn.Linear(frame_length * SENSORS_NUM, hidden_layer_size, bias=False),\n                            nn.BatchNorm1d(hidden_layer_size),\n                            nn.ReLU(inplace=True)]\n            else:\n                layers += [nn.Linear(hidden_layer_size, hidden_layer_size, bias=False),\n                            nn.BatchNorm1d(hidden_layer_size),\n                            nn.ReLU(inplace=True)]\n            \n        layers.append(nn.Linear(hidden_layer_size, num_classes))\n                      \n        self.classifer = nn.Sequential(*layers)\n\n    def forward(self, x):\n        x = torch.flatten(x, 1)\n        x = self.classifer(x)\n        return x","metadata":{"execution":{"iopub.status.busy":"2022-09-05T11:31:10.440461Z","iopub.execute_input":"2022-09-05T11:31:10.440793Z","iopub.status.idle":"2022-09-05T11:31:10.455062Z","shell.execute_reply.started":"2022-09-05T11:31:10.440758Z","shell.execute_reply":"2022-09-05T11:31:10.453617Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with open(f'{RESULT_DIR}history/MLP.json', 'r') as fp:\n    run_record = json.load(fp)\n\nbest_val_metric = None\nbest_hyperparams = None\nbest_run = None\nbest_model_path = None\n\nfor key, train_info in run_record.items():\n    if best_val_metric is None or best_val_metric < train_info['final_val_metric']:\n        best_val_metric = train_info['final_val_metric']\n        best_hyperparams = train_info['hyperparams']\n        best_run = train_info\n        best_model_path = key\n        \nmodel = MLP(best_hyperparams[\"hidden_layer_size\"], best_hyperparams[\"hidden_layers\"],\n            CLASSES_NUM, best_hyperparams['frame_length'])\n\nmodel.load_state_dict(torch.load(f'{RESULT_DIR}models/MLP.pth'))\nif torch.cuda.is_available():\n    model = model.to('cuda')","metadata":{"execution":{"iopub.status.busy":"2022-09-05T11:31:10.459585Z","iopub.execute_input":"2022-09-05T11:31:10.459944Z","iopub.status.idle":"2022-09-05T11:31:13.872235Z","shell.execute_reply.started":"2022-09-05T11:31:10.459903Z","shell.execute_reply":"2022-09-05T11:31:13.871222Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Submission","metadata":{}},{"cell_type":"code","source":"predictions = []\nids = []\nsm = torch.nn.Softmax(dim=1)\n    \nfiles = os.listdir(ROOT_DIR)\nfiles = list(filter(lambda x: 'Series' in x, files))\nfiles.sort(key=lambda x: int(x.split('_')[1][:-4]))\n    \nfor file in files:\n    if 'Series' in file:\n        cur_id = int(file.split('_')[1][:-4])\n        dataset = DefectsDataset([cur_id], best_hyperparams['frame_length'], mode='submit')\n        loader = DataLoader(dataset, 32)\n        outputs = predict(loader, model)[0]\n        prediction = sm(outputs).sum(dim=0).argmax()\n        predictions.append(prediction.item() + 1)\n        ids.append(cur_id)\n        \nsubmit_df = pd.DataFrame({'id': ids, 'class': predictions})\nsubmit_df.to_csv(f'{WORK_DIR}submission.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2022-09-05T11:31:13.873506Z","iopub.execute_input":"2022-09-05T11:31:13.873894Z","iopub.status.idle":"2022-09-05T11:31:42.693253Z","shell.execute_reply.started":"2022-09-05T11:31:13.873855Z","shell.execute_reply":"2022-09-05T11:31:42.692222Z"},"trusted":true},"execution_count":null,"outputs":[]}]}