{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Attention!!!\n\nThis is a very simple but bad quality notebook. \n - I do not use any sort of ranking loss, which would be better.\n - My strategy instead is to min-max scale the relative times (time/normalized) and apply L1-loss\n - My model is also not optimized. It is a relatively simple GNN that embeds the graph and only processes 1 datapoint at a time and is only trained on 1 epoch.\n - The public score would be much better if you paired this submission with a trained model for layout. Since this only contributes to half of the score.\n - Have fun playing around with it!","metadata":{}},{"cell_type":"code","source":"!pip install torch-geometric torch-scatter","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2023-09-05T04:33:57.045875Z","iopub.execute_input":"2023-09-05T04:33:57.046394Z","iopub.status.idle":"2023-09-05T04:45:40.424917Z","shell.execute_reply.started":"2023-09-05T04:33:57.046342Z","shell.execute_reply":"2023-09-05T04:45:40.423615Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os\nfrom tqdm import tqdm \n\nimport torch\nfrom torch import nn\nfrom torch import Tensor\nfrom torch_geometric.nn import GCNConv\nfrom torch_geometric.datasets import Planetoid\nfrom torch.utils.data import DataLoader, Dataset\ndevice = 'cuda' if torch.cuda.is_available() else 'cpu'","metadata":{"execution":{"iopub.status.busy":"2023-09-05T04:45:40.428942Z","iopub.execute_input":"2023-09-05T04:45:40.429600Z","iopub.status.idle":"2023-09-05T04:45:42.603567Z","shell.execute_reply.started":"2023-09-05T04:45:40.429559Z","shell.execute_reply":"2023-09-05T04:45:42.602588Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We can now load all the data in dataframes to make working with it easier","metadata":{}},{"cell_type":"code","source":"def load_df(directory):\n    splits = [\"train\", \"valid\", \"test\"]\n    dfs = dict()\n    \n    for split in splits:\n        path = os.path.join(directory, split)\n        files = os.listdir(path)\n        list_df = []\n        \n        for file in files:\n            d = dict(np.load(os.path.join(path,file)))\n            d['file'] = file\n            list_df.append(d)\n        dfs[split] = pd.DataFrame.from_dict(list_df)\n    return dfs","metadata":{"execution":{"iopub.status.busy":"2023-09-05T04:45:42.605018Z","iopub.execute_input":"2023-09-05T04:45:42.605639Z","iopub.status.idle":"2023-09-05T04:45:42.613507Z","shell.execute_reply.started":"2023-09-05T04:45:42.605611Z","shell.execute_reply":"2023-09-05T04:45:42.612616Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"If you try to run the following cell completely uncommented the Kaggle kernel will run out of memory and crash, so we will have to study the datasets individually","metadata":{}},{"cell_type":"code","source":"tile_xla = load_df(\"/kaggle/input/predict-ai-model-runtime/npz_all/npz/tile/xla/\")\n#layout_nlp_random = load_df(\"/kaggle/input/predict-ai-model-runtime/npz_all/npz/layout/nlp/random/\")\n#layout_nlp_default = load_df(\"/kaggle/input/predict-ai-model-runtime/npz_all/npz/layout/nlp/default/\")\n#layout_xla_random = load_df(\"/kaggle/input/predict-ai-model-runtime/npz_all/npz/layout/xla/random/\")\n#layout_xla_random = load_df(\"/kaggle/input/predict-ai-model-runtime/npz_all/npz/layout/xla/default/\")","metadata":{"execution":{"iopub.status.busy":"2023-09-05T04:45:42.615232Z","iopub.execute_input":"2023-09-05T04:45:42.615999Z","iopub.status.idle":"2023-09-05T04:46:44.514209Z","shell.execute_reply.started":"2023-09-05T04:45:42.615966Z","shell.execute_reply":"2023-09-05T04:46:44.513230Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Define Dataset and Model","metadata":{}},{"cell_type":"code","source":"class TileDataset(Dataset):\n    def __init__(self, df):\n        self.df = df\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        row = self.df.iloc[idx]\n        config_feat = torch.tensor(row['config_feat'].astype(np.float32))\n        node_feat = torch.tensor(row['node_feat'].astype(np.float32))\n        node_opcode = torch.tensor(row['node_opcode'].astype(np.int32))\n        edge_index = torch.tensor(np.swapaxes(row['edge_index'],0,1).astype(np.int32))\n        target = (row['config_runtime']/row['config_runtime_normalizers']).astype(np.float32)\n        # minmax scale the target, we only care about order\n        target = (target-min(target))/(max(target) -min(target))\n        target = torch.tensor(target)\n        return config_feat,node_feat,node_opcode,edge_index,target","metadata":{"execution":{"iopub.status.busy":"2023-09-05T04:46:44.516923Z","iopub.execute_input":"2023-09-05T04:46:44.517287Z","iopub.status.idle":"2023-09-05T04:46:44.526845Z","shell.execute_reply.started":"2023-09-05T04:46:44.517255Z","shell.execute_reply":"2023-09-05T04:46:44.525734Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class SimpleModel(torch.nn.Module):\n    def __init__(self, hidden_channels, graph_feats, hidden_dim):\n        super().__init__()\n        op_embedding_dim = 4 # I choose 4-dimensional embedding\n        self.embedding = torch.nn.Embedding(120, #120 different op-codes\n                                            op_embedding_dim,\n                                           )\n        assert len(hidden_channels)>0\n        in_channels = op_embedding_dim+140\n        self.convs = torch.nn.ModuleList()\n        last_dim = hidden_channels[-1]\n        self.convs.append(GCNConv(in_channels, hidden_channels[0]))\n        for i in range(len(hidden_channels)-1):\n            self.convs.append(GCNConv(hidden_channels[i], hidden_channels[i+1]))\n        self.convs.append(GCNConv(last_dim, graph_feats))\n        \n        self.dense = torch.nn.Sequential(nn.Linear(graph_feats+24, 64),\n                                         nn.ReLU(),\n                                         nn.Linear(64, 64),\n                                         nn.ReLU(),\n#                                          nn.Linear(64, 32),\n#                                          nn.ReLU(),\n#                                          nn.Linear(32, 64),\n#                                          nn.ReLU(),\n                                         nn.Linear(64, 1),\n                                        )\n\n        self.norms = torch.nn.ModuleList()\n        for i in range(len(hidden_channels)):\n            self.norms.append(torch.nn.BatchNorm1d(hidden_channels[i]))\n        self.norms.append(torch.nn.BatchNorm1d(graph_feats))\n\n    def forward(self, x_cfg: Tensor,x_feat: Tensor, x_op: Tensor, edge_index: Tensor) -> Tensor:\n        \n        #get graph features\n        x = torch.concat([x_feat,self.embedding(x_op)],dim = 1)\n        #pass though conv layers\n        for i, conv in enumerate(self.convs):\n            x = conv(x, edge_index).relu()\n#             print(x.shape)\n#             if i == 0:\n#                 x = conv(x, edge_index).relu()\n#             else:\n#                 x = conv(x, edge_index).relu() + conv(x, edge_index).relu()\n            x = self.norms[i](x)\n#             print(x.shape)\n        # get 1d graph embedding using average pooling\n        x_graph = torch.mean(x,0)\n        \n        \n        #put graph data into config data\n        x = torch.concat([x_cfg,x_graph.repeat((len(x_cfg),1))],axis=1)\n        #put into dense nn\n        x = torch.flatten(self.dense(x))\n        return x\n\nmodel = SimpleModel(hidden_channels = [16,32,16,48],graph_feats = 64,hidden_dim=64).to(device)","metadata":{"execution":{"iopub.status.busy":"2023-09-05T05:10:00.004544Z","iopub.execute_input":"2023-09-05T05:10:00.004970Z","iopub.status.idle":"2023-09-05T05:10:00.040603Z","shell.execute_reply.started":"2023-09-05T05:10:00.004939Z","shell.execute_reply":"2023-09-05T05:10:00.039734Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train few Epoches","metadata":{}},{"cell_type":"code","source":"dataset = TileDataset(tile_xla[\"train\"])\n\n# criterion = torch.nn.SmoothL1Loss()\ncriterion = torch.nn.HuberLoss()\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-4,weight_decay = 0.01)\n\nmodel.train()\nloss_sum = 0\nn = 0\nepoch_num = 30\nfor now_epoch in range(epoch_num):\n    pbar = tqdm(range(len(dataset)))\n    print('--------------epoch {}: ------------------'.format(now_epoch))\n    for i in pbar:\n        cfg_ft,nd_ft,nd_op,ind,target = dataset[i]\n        cfg_ft,nd_ft,nd_op,ind,target = cfg_ft.to(device),nd_ft.to(device),nd_op.to(device),ind.to(device),target.to(device)\n\n        out = model(cfg_ft,nd_ft,nd_op,ind)\n        loss = criterion(out, target)\n        loss.backward()\n        torch.nn.utils.clip_grad_norm_(model.parameters(), 0.01)\n        optimizer.step()\n\n        loss_sum+=loss.item()\n        n+=1\n        pbar.set_description(f'running loss: {(loss_sum/n):.6f},current loss: {(loss.item()):.6f}')","metadata":{"execution":{"iopub.status.busy":"2023-09-05T05:10:05.122643Z","iopub.execute_input":"2023-09-05T05:10:05.123037Z","iopub.status.idle":"2023-09-05T05:10:15.392962Z","shell.execute_reply.started":"2023-09-05T05:10:05.123006Z","shell.execute_reply":"2023-09-05T05:10:15.389867Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Evaluate on Validation Dataset","metadata":{}},{"cell_type":"code","source":"dataset = TileDataset(tile_xla[\"valid\"])\ntile_xla_predictions = []\nmodel.eval()\n\npbar = tqdm(range(len(dataset)))\nfor i in pbar:\n    cfg_ft,nd_ft,nd_op,ind,target = dataset[i]\n    cfg_ft,nd_ft,nd_op,ind,target = cfg_ft.to(device),nd_ft.to(device),nd_op.to(device),ind.to(device),target.to(device)\n    \n    out = model(cfg_ft,nd_ft,nd_op,ind)\n    tile_xla_predictions.append(np.argsort(out.detach().cpu().numpy())[:5])\n\ndef score_tile(predictions, df):\n    score = 0\n    for i in range(len(df)):\n        predbest = min(df.iloc[i]['config_runtime'][predictions[i]])\n        best = min(df.iloc[i]['config_runtime'])\n        score +=2 - predbest/best\n    score /= len(df)\n    return score\nscore_tile(tile_xla_predictions, tile_xla[\"valid\"])","metadata":{"execution":{"iopub.status.busy":"2023-09-05T04:48:20.732436Z","iopub.status.idle":"2023-09-05T04:48:20.732922Z","shell.execute_reply.started":"2023-09-05T04:48:20.732664Z","shell.execute_reply":"2023-09-05T04:48:20.732703Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**0.31 is not bad considering that this model only trained on 1 epoch and is not on a ranking loss!**","metadata":{}},{"cell_type":"markdown","source":"# Predict and Submit (only tile:xla predictions)","metadata":{}},{"cell_type":"code","source":"dataset = TileDataset(tile_xla[\"test\"])\ntile_xla_predictions = []\nmodel.eval()\npbar = tqdm(range(len(dataset)))\nfor i in pbar:\n    cfg_ft,nd_ft,nd_op,ind,target = dataset[i]\n    cfg_ft,nd_ft,nd_op,ind,target = cfg_ft.to(device),nd_ft.to(device),nd_op.to(device),ind.to(device),target.to(device)\n    \n    out = model(cfg_ft,nd_ft,nd_op,ind)\n    tile_xla_predictions.append(np.argsort(out.detach().cpu().numpy())[:5])","metadata":{"execution":{"iopub.status.busy":"2023-09-05T04:48:20.734340Z","iopub.status.idle":"2023-09-05T04:48:20.734825Z","shell.execute_reply.started":"2023-09-05T04:48:20.734547Z","shell.execute_reply":"2023-09-05T04:48:20.734569Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub = pd.read_csv('/kaggle/input/predict-ai-model-runtime/sample_submission.csv')\nfor i,filename in enumerate(tile_xla[\"test\"]['file'].values):\n    id = 'tile:xla:' +filename[:-4]\n    sub.loc[sub.ID == id,'TopConfigs'] = ';'.join(tile_xla_predictions[i].astype(str))\nsub.to_csv('submission.csv',index=False)\nsub","metadata":{"execution":{"iopub.status.busy":"2023-09-05T04:48:20.735964Z","iopub.status.idle":"2023-09-05T04:48:20.736849Z","shell.execute_reply.started":"2023-09-05T04:48:20.736568Z","shell.execute_reply":"2023-09-05T04:48:20.736595Z"},"trusted":true},"execution_count":null,"outputs":[]}],"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"}}