{"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":"import numpy as np\nimport pandas as pd\n\n\ndf = pd.read_csv(\"../input/h-and-m-personalized-fashion-recommendations/transactions_train.csv\", dtype={\"article_id\": str})\nprint(df.shape)\ndf.head()","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-08-04T04:23:49.360189Z","iopub.execute_input":"2022-08-04T04:23:49.361026Z","iopub.status.idle":"2022-08-04T04:25:01.439490Z","shell.execute_reply.started":"2022-08-04T04:23:49.360938Z","shell.execute_reply":"2022-08-04T04:25:01.438597Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"af = pd.read_csv(\"../input/h-and-m-personalized-fashion-recommendations/articles.csv\", dtype={\"article_id\": str,'product_code':str,'product_type_no':str,'graphical_appearance_no':str,'colour_group_code':str,'perceived_colour_value_id':str,'perceived_colour_master_id':str,'department_no':str,'index_code':str,'index_group_no':str,'section_no':str,'garment_group_no':str}) #convert","metadata":{"execution":{"iopub.status.busy":"2022-08-04T04:25:01.441255Z","iopub.execute_input":"2022-08-04T04:25:01.442287Z","iopub.status.idle":"2022-08-04T04:25:02.499781Z","shell.execute_reply.started":"2022-08-04T04:25:01.442249Z","shell.execute_reply":"2022-08-04T04:25:02.498844Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"af.drop(labels=['prod_name','product_type_name','product_group_name','graphical_appearance_name','colour_group_name','perceived_colour_value_name','perceived_colour_master_name','department_name','index_name','index_group_name','index_name','index_group_name','section_name','garment_group_name','detail_desc'], axis=1,inplace=True)","metadata":{"execution":{"iopub.status.busy":"2022-08-04T04:25:02.501265Z","iopub.execute_input":"2022-08-04T04:25:02.501539Z","iopub.status.idle":"2022-08-04T04:25:02.534565Z","shell.execute_reply.started":"2022-08-04T04:25:02.501492Z","shell.execute_reply":"2022-08-04T04:25:02.533798Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"af.head()","metadata":{"execution":{"iopub.status.busy":"2022-08-04T04:25:02.536842Z","iopub.execute_input":"2022-08-04T04:25:02.537166Z","iopub.status.idle":"2022-08-04T04:25:02.552414Z","shell.execute_reply.started":"2022-08-04T04:25:02.537114Z","shell.execute_reply":"2022-08-04T04:25:02.551654Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df[\"t_dat\"] = pd.to_datetime(df[\"t_dat\"])\ndf[\"t_dat\"].max()","metadata":{"execution":{"iopub.status.busy":"2022-08-04T04:25:02.553904Z","iopub.execute_input":"2022-08-04T04:25:02.554427Z","iopub.status.idle":"2022-08-04T04:25:07.366717Z","shell.execute_reply.started":"2022-08-04T04:25:02.554384Z","shell.execute_reply":"2022-08-04T04:25:07.365949Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"active_articles = df.groupby(\"article_id\")[\"t_dat\"].max().reset_index()\nactive_articles = active_articles[active_articles[\"t_dat\"] >= \"2019-09-01\"].reset_index()\nactive_articles.shape","metadata":{"execution":{"iopub.status.busy":"2022-08-04T04:25:07.368254Z","iopub.execute_input":"2022-08-04T04:25:07.368747Z","iopub.status.idle":"2022-08-04T04:25:12.438968Z","shell.execute_reply.started":"2022-08-04T04:25:07.368709Z","shell.execute_reply":"2022-08-04T04:25:12.438181Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = df[df[\"article_id\"].isin(active_articles[\"article_id\"])].reset_index(drop=True)\ndf.shape","metadata":{"execution":{"iopub.status.busy":"2022-08-04T04:25:12.440196Z","iopub.execute_input":"2022-08-04T04:25:12.441208Z","iopub.status.idle":"2022-08-04T04:25:19.488864Z","shell.execute_reply.started":"2022-08-04T04:25:12.441147Z","shell.execute_reply":"2022-08-04T04:25:19.488016Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"af = af[af[\"article_id\"].isin(active_articles[\"article_id\"])].reset_index(drop=True)\naf.shape","metadata":{"execution":{"iopub.status.busy":"2022-08-04T04:25:19.490405Z","iopub.execute_input":"2022-08-04T04:25:19.490723Z","iopub.status.idle":"2022-08-04T04:25:19.553627Z","shell.execute_reply.started":"2022-08-04T04:25:19.490693Z","shell.execute_reply":"2022-08-04T04:25:19.552691Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df[\"week\"] = (df[\"t_dat\"].max() - df[\"t_dat\"]).dt.days // 7\ndf[\"week\"].value_counts()","metadata":{"execution":{"iopub.status.busy":"2022-08-04T04:25:19.555324Z","iopub.execute_input":"2022-08-04T04:25:19.555623Z","iopub.status.idle":"2022-08-04T04:25:20.997925Z","shell.execute_reply.started":"2022-08-04T04:25:19.555581Z","shell.execute_reply":"2022-08-04T04:25:20.997151Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"new_row = pd.DataFrame({'article_id':'#', 'product_code':'#', 'product_type_no':'#',\n       'graphical_appearance_no':'#','colour_group_code':'#',\n       'perceived_colour_value_id':'#','perceived_colour_master_id':'#',\n       'department_no':'#','index_code':'#','index_group_no':'#', 'section_no':'#',\n       'garment_group_no':'#'}, index =[0])###placeholder","metadata":{"execution":{"iopub.status.busy":"2022-08-04T04:25:21.000585Z","iopub.execute_input":"2022-08-04T04:25:21.000905Z","iopub.status.idle":"2022-08-04T04:25:21.008389Z","shell.execute_reply.started":"2022-08-04T04:25:21.000871Z","shell.execute_reply":"2022-08-04T04:25:21.007586Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"af = pd.concat([new_row,af[:]]).reset_index(drop=True)#add placeholders","metadata":{"execution":{"iopub.status.busy":"2022-08-04T04:25:21.009659Z","iopub.execute_input":"2022-08-04T04:25:21.009984Z","iopub.status.idle":"2022-08-04T04:25:21.033047Z","shell.execute_reply.started":"2022-08-04T04:25:21.009949Z","shell.execute_reply":"2022-08-04T04:25:21.032335Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"af.head()","metadata":{"execution":{"iopub.status.busy":"2022-08-04T04:25:21.034259Z","iopub.execute_input":"2022-08-04T04:25:21.034582Z","iopub.status.idle":"2022-08-04T04:25:21.050782Z","shell.execute_reply.started":"2022-08-04T04:25:21.034542Z","shell.execute_reply":"2022-08-04T04:25:21.050011Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"af.sort_values(by='article_id',inplace = True)#make sure each index represent each article_id","metadata":{"execution":{"iopub.status.busy":"2022-08-04T04:25:21.052297Z","iopub.execute_input":"2022-08-04T04:25:21.053153Z","iopub.status.idle":"2022-08-04T04:25:21.098995Z","shell.execute_reply.started":"2022-08-04T04:25:21.053038Z","shell.execute_reply":"2022-08-04T04:25:21.098336Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.preprocessing import LabelEncoder\n\narticle_ids = np.unique(af[\"article_id\"].values)\n\nle_article = LabelEncoder()\nle_article.fit(article_ids)\n\naf[\"article_id\"] = le_article.transform(af[\"article_id\"])\ndf[\"article_id\"] = le_article.transform(df[\"article_id\"])","metadata":{"execution":{"iopub.status.busy":"2022-08-04T04:25:21.100169Z","iopub.execute_input":"2022-08-04T04:25:21.100480Z","iopub.status.idle":"2022-08-04T04:25:32.019167Z","shell.execute_reply.started":"2022-08-04T04:25:21.100445Z","shell.execute_reply":"2022-08-04T04:25:32.018364Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#incorporate other features\nf1 = np.unique(af['product_code'].values)\nf2 = np.unique(af['product_type_no'].values)\nf3 = np.unique(af['graphical_appearance_no'].values)\nf4 = np.unique(af['colour_group_code'].values)\nf5 = np.unique(af['perceived_colour_value_id'].values)\nf6 = np.unique(af['perceived_colour_master_id'].values)\nf7 = np.unique(af['department_no'].values)\nf8 = np.unique(af['index_code'].values)\nf9 = np.unique(af['index_group_no'].values)\nf10 = np.unique(af['section_no'].values)\nf11 = np.unique(af['garment_group_no'].values)","metadata":{"execution":{"iopub.status.busy":"2022-08-04T04:25:32.020504Z","iopub.execute_input":"2022-08-04T04:25:32.020811Z","iopub.status.idle":"2022-08-04T04:25:32.506234Z","shell.execute_reply.started":"2022-08-04T04:25:32.020754Z","shell.execute_reply":"2022-08-04T04:25:32.505295Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"le_f1 = LabelEncoder()\nle_f2 = LabelEncoder()\nle_f3 = LabelEncoder()\nle_f4 = LabelEncoder()\nle_f5 = LabelEncoder()\nle_f6 = LabelEncoder()\nle_f7 = LabelEncoder()\nle_f8 = LabelEncoder()\nle_f9 = LabelEncoder()\nle_f10 = LabelEncoder()\nle_f11 = LabelEncoder()\nle_f1.fit(f1)\nle_f2.fit(f2)\nle_f3.fit(f3)\nle_f4.fit(f4)\nle_f5.fit(f5)\nle_f6.fit(f6)\nle_f7.fit(f7)\nle_f8.fit(f8)\nle_f9.fit(f9)\nle_f10.fit(f10)\nle_f11.fit(f11)\naf['product_code'] = le_f1.transform(af['product_code'])\naf['product_type_no'] = le_f2.transform(af['product_type_no'])\naf['graphical_appearance_no'] = le_f3.transform(af['graphical_appearance_no'])\naf['colour_group_code'] = le_f4.transform(af['colour_group_code'])\naf['perceived_colour_value_id'] = le_f5.transform(af['perceived_colour_value_id'])\naf['perceived_colour_master_id'] = le_f6.transform(af['perceived_colour_master_id'])\naf['department_no'] = le_f7.transform(af['department_no'])\naf['index_code'] = le_f8.transform(af['index_code'])\naf['index_group_no'] = le_f9.transform(af['index_group_no'])\naf['section_no'] = le_f10.transform(af['section_no'])\naf['garment_group_no'] = le_f11.transform(af['garment_group_no'])","metadata":{"execution":{"iopub.status.busy":"2022-08-04T04:25:32.507655Z","iopub.execute_input":"2022-08-04T04:25:32.507931Z","iopub.status.idle":"2022-08-04T04:25:32.761938Z","shell.execute_reply.started":"2022-08-04T04:25:32.507892Z","shell.execute_reply":"2022-08-04T04:25:32.761090Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"af.head()","metadata":{"execution":{"iopub.status.busy":"2022-08-04T04:25:32.763191Z","iopub.execute_input":"2022-08-04T04:25:32.763492Z","iopub.status.idle":"2022-08-04T04:25:32.776533Z","shell.execute_reply.started":"2022-08-04T04:25:32.763456Z","shell.execute_reply":"2022-08-04T04:25:32.775675Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"WEEK_HIST_MAX = 5\n\ndef create_dataset(df, week):\n    hist_df = df[(df[\"week\"] > week) & (df[\"week\"] <= week + WEEK_HIST_MAX)]\n    hist_df = hist_df.groupby(\"customer_id\").agg({\"article_id\": list, \"week\": list}).reset_index()\n    hist_df.rename(columns={\"week\": 'week_history'}, inplace=True)\n    \n    target_df = df[df[\"week\"] == week]\n    target_df = target_df.groupby(\"customer_id\").agg({\"article_id\": list}).reset_index()\n    target_df.rename(columns={\"article_id\": \"target\"}, inplace=True)\n    target_df[\"week\"] = week\n    \n    return target_df.merge(hist_df, on=\"customer_id\", how=\"left\")\n\nval_weeks = [0]\ntrain_weeks = [1, 2, 3, 4]\n\n\nval_df = pd.concat([create_dataset(df, w) for w in val_weeks]).reset_index(drop=True)\ntrain_df = pd.concat([create_dataset(df, w) for w in train_weeks]).reset_index(drop=True)\ntrain_df.shape, val_df.shape","metadata":{"execution":{"iopub.status.busy":"2022-08-04T04:25:32.777925Z","iopub.execute_input":"2022-08-04T04:25:32.778749Z","iopub.status.idle":"2022-08-04T04:26:05.093430Z","shell.execute_reply.started":"2022-08-04T04:25:32.778695Z","shell.execute_reply":"2022-08-04T04:26:05.092649Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.utils.data import Dataset, DataLoader\nimport torch\nfrom tqdm import tqdm\n\nclass HMDataset(Dataset):\n    def __init__(self, df, seq_len, is_test=False):\n        self.df = df.reset_index(drop=True)\n        self.seq_len = seq_len\n        self.is_test = is_test\n    \n    def __len__(self):\n        return self.df.shape[0]\n    \n    def __getitem__(self, index):\n        row = self.df.iloc[index]\n        \n        if self.is_test:\n            target = torch.zeros(2).float()\n        else:\n            target = torch.zeros(len(article_ids)).float()\n            for t in row.target:\n                target[t] = 1.0\n            \n        article_hist = torch.zeros(self.seq_len).long()\n        week_hist = torch.ones(self.seq_len).float()\n        \n        article_hist_np = np.zeros(self.seq_len).astype(int)\n        \n        \n        if isinstance(row.article_id, list):\n            if len(row.article_id) >= self.seq_len:\n                article_hist = torch.LongTensor(row.article_id[-self.seq_len:])\n                week_hist = (torch.LongTensor(row.week_history[-self.seq_len:]) - row.week)/WEEK_HIST_MAX/2\n            else:\n                article_hist[-len(row.article_id):] = torch.LongTensor(row.article_id)\n                week_hist[-len(row.article_id):] = (torch.LongTensor(row.week_history) - row.week)/WEEK_HIST_MAX/2\n        \n        \n        if isinstance(row.article_id, list):\n            if len(row.article_id) >= self.seq_len:\n                article_hist_np = np.array(row.article_id[-self.seq_len:])\n            else:\n                article_hist_np[-len(row.article_id):] = np.array(row.article_id)\n                \n        ##2 hours for inference        \n        #print(article_hist_np)\n        \n        vfunc = np.vectorize(lambda x: af.iloc[x,1])\n        f1 = torch.from_numpy(vfunc(article_hist_np))\n        vfunc = np.vectorize(lambda x: af.iloc[x,2])\n        f2 = torch.from_numpy(vfunc(article_hist_np))\n        vfunc = np.vectorize(lambda x: af.iloc[x,3])\n        f3 = torch.from_numpy(vfunc(article_hist_np))\n        vfunc = np.vectorize(lambda x: af.iloc[x,4])\n        f4 = torch.from_numpy(vfunc(article_hist_np))\n        vfunc = np.vectorize(lambda x: af.iloc[x,5])\n        f5 = torch.from_numpy(vfunc(article_hist_np))\n        vfunc = np.vectorize(lambda x: af.iloc[x,6])\n        f6 = torch.from_numpy(vfunc(article_hist_np))\n        vfunc = np.vectorize(lambda x: af.iloc[x,7])\n        f7 = torch.from_numpy(vfunc(article_hist_np))\n        vfunc = np.vectorize(lambda x: af.iloc[x,8])\n        f8 = torch.from_numpy(vfunc(article_hist_np))\n        vfunc = np.vectorize(lambda x: af.iloc[x,9])\n        f9 = torch.from_numpy(vfunc(article_hist_np))\n        vfunc = np.vectorize(lambda x: af.iloc[x,10])\n        f10 = torch.from_numpy(vfunc(article_hist_np))\n        vfunc = np.vectorize(lambda x: af.iloc[x,11])\n        f11 = torch.from_numpy(vfunc(article_hist_np))\n\n\n#         2 hours for inference\n#         article_hist1 = copy.deepcopy(article_hist)\n#         f1 = article_hist1.apply_(lambda x : af.iloc[x,1])\n#         article_hist2 = copy.deepcopy(article_hist)\n#         f2 = article_hist2.apply_(lambda x : af.iloc[x,2])\n#         article_hist3 = copy.deepcopy(article_hist)\n#         f3 = article_hist3.apply_(lambda x : af.iloc[x,3])\n#         article_hist4 = copy.deepcopy(article_hist)\n#         f4 = article_hist4.apply_(lambda x : af.iloc[x,4])\n#         article_hist5 = copy.deepcopy(article_hist)\n#         f5 = article_hist5.apply_(lambda x : af.iloc[x,5])\n#         article_hist6 = copy.deepcopy(article_hist)\n#         f6 = article_hist6.apply_(lambda x : af.iloc[x,6])\n#         article_hist7 = copy.deepcopy(article_hist)\n#         f7 = article_hist7.apply_(lambda x : af.iloc[x,7])\n#         article_hist8 = copy.deepcopy(article_hist)\n#         f8 = article_hist8.apply_(lambda x : af.iloc[x,8])\n#         article_hist9 = copy.deepcopy(article_hist)\n#         f9 = article_hist9.apply_(lambda x : af.iloc[x,9])\n#         article_hist10 = copy.deepcopy(article_hist)\n#         f10 = article_hist10.apply_(lambda x : af.iloc[x,10])\n#         article_hist11 = copy.deepcopy(article_hist)\n#         f11 = article_hist11.apply_(lambda x : af.iloc[x,11])\n\n#         4 hours for inference\n#         article_hist_ = pd.DataFrame(article_hist.cpu().numpy())\n#         f1 = torch.from_numpy(article_hist_.applymap(lambda x: af.iloc[x,1]).to_numpy()).squeeze()\n#         f2 = torch.from_numpy(article_hist_.applymap(lambda x: af.iloc[x,2]).to_numpy()).squeeze()\n#         f3 = torch.from_numpy(article_hist_.applymap(lambda x: af.iloc[x,3]).to_numpy()).squeeze()\n#         f4 = torch.from_numpy(article_hist_.applymap(lambda x: af.iloc[x,4]).to_numpy()).squeeze()\n#         f5 = torch.from_numpy(article_hist_.applymap(lambda x: af.iloc[x,5]).to_numpy()).squeeze()\n#         f6 = torch.from_numpy(article_hist_.applymap(lambda x: af.iloc[x,6]).to_numpy()).squeeze()\n#         f7 = torch.from_numpy(article_hist_.applymap(lambda x: af.iloc[x,7]).to_numpy()).squeeze()\n#         f8 = torch.from_numpy(article_hist_.applymap(lambda x: af.iloc[x,8]).to_numpy()).squeeze()\n#         f9 = torch.from_numpy(article_hist_.applymap(lambda x: af.iloc[x,9]).to_numpy()).squeeze()\n#         f10 = torch.from_numpy(article_hist_.applymap(lambda x: af.iloc[x,10]).to_numpy()).squeeze()\n#         f11 = torch.from_numpy(article_hist_.applymap(lambda x: af.iloc[x,11]).to_numpy()).squeeze()\n\n        \n        return article_hist, week_hist, target, (f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11)\n    \nHMDataset(val_df, 64)[1]","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"all_f1 = torch.from_numpy(af.iloc[:,1].values).cuda()\nall_f2 = torch.from_numpy(af.iloc[:,2].values).cuda()\nall_f3 = torch.from_numpy(af.iloc[:,3].values).cuda()\nall_f4 = torch.from_numpy(af.iloc[:,4].values).cuda()\nall_f5 = torch.from_numpy(af.iloc[:,5].values).cuda()\nall_f6 = torch.from_numpy(af.iloc[:,6].values).cuda()\nall_f7 = torch.from_numpy(af.iloc[:,7].values).cuda()\nall_f8 = torch.from_numpy(af.iloc[:,8].values).cuda()\nall_f9 = torch.from_numpy(af.iloc[:,9].values).cuda()\nall_f10 = torch.from_numpy(af.iloc[:,10].values).cuda()\nall_f11 = torch.from_numpy(af.iloc[:,11].values).cuda()\nall_f = (all_f1,all_f2,all_f3,all_f4,all_f5,all_f6,all_f7,all_f8,all_f9,all_f10,all_f11)","metadata":{"execution":{"iopub.status.busy":"2022-08-04T04:48:32.091497Z","iopub.execute_input":"2022-08-04T04:48:32.091766Z","iopub.status.idle":"2022-08-04T04:48:32.106354Z","shell.execute_reply.started":"2022-08-04T04:48:32.091737Z","shell.execute_reply":"2022-08-04T04:48:32.105569Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"all_f","metadata":{"execution":{"iopub.status.busy":"2022-08-04T04:48:33.951353Z","iopub.execute_input":"2022-08-04T04:48:33.951619Z","iopub.status.idle":"2022-08-04T04:48:33.963033Z","shell.execute_reply.started":"2022-08-04T04:48:33.951584Z","shell.execute_reply":"2022-08-04T04:48:33.962266Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def adjust_lr(optimizer, epoch):\n    if epoch < 1:\n        lr = 5e-5\n    elif epoch < 6:\n        lr = 1e-3\n    elif epoch < 9:\n        lr = 1e-4\n    else:\n        lr = 1e-5\n\n    for p in optimizer.param_groups:\n        p['lr'] = lr\n    return lr\n    \ndef get_optimizer(net):\n    optimizer = torch.optim.Adam(filter(lambda p: p.requires_grad, net.parameters()), lr=3e-4, betas=(0.9, 0.999),\n                                 eps=1e-08)\n    return optimizer","metadata":{"execution":{"iopub.status.busy":"2022-08-04T05:10:08.177130Z","iopub.execute_input":"2022-08-04T05:10:08.178183Z","iopub.status.idle":"2022-08-04T05:10:08.184412Z","shell.execute_reply.started":"2022-08-04T05:10:08.178116Z","shell.execute_reply":"2022-08-04T05:10:08.183666Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch.nn as nn\nimport torch.nn.functional as F\n\nclass HMModel(nn.Module):\n    def __init__(self, article_shape,f1_shape,f2_shape,f3_shape,f4_shape,f5_shape,f6_shape,f7_shape,f8_shape,f9_shape,f10_shape,f11_shape,all_f):\n        super(HMModel, self).__init__()\n        \n        self.all_f1 = all_f[0]\n        self.all_f2 = all_f[1]\n        self.all_f3 = all_f[2]\n        self.all_f4 = all_f[3]\n        self.all_f5 = all_f[4]\n        self.all_f6 = all_f[5]\n        self.all_f7 = all_f[6]\n        self.all_f8 = all_f[7]\n        self.all_f9 = all_f[8]\n        self.all_f10 = all_f[9]\n        self.all_f11 = all_f[10]\n        \n        self.article_emb = nn.Embedding(article_shape[0], embedding_dim=article_shape[1])\n        \n        self.f1_emb = nn.Embedding(f1_shape[0], embedding_dim=f1_shape[1])\n        self.f2_emb = nn.Embedding(f2_shape[0], embedding_dim=f2_shape[1])\n        self.f3_emb = nn.Embedding(f3_shape[0], embedding_dim=f3_shape[1])\n        self.f4_emb = nn.Embedding(f4_shape[0], embedding_dim=f4_shape[1])\n        self.f5_emb = nn.Embedding(f5_shape[0], embedding_dim=f5_shape[1])\n        self.f6_emb = nn.Embedding(f6_shape[0], embedding_dim=f6_shape[1])\n        self.f7_emb = nn.Embedding(f7_shape[0], embedding_dim=f7_shape[1])\n        self.f8_emb = nn.Embedding(f8_shape[0], embedding_dim=f8_shape[1])\n        self.f9_emb = nn.Embedding(f9_shape[0], embedding_dim=f9_shape[1])\n        self.f10_emb = nn.Embedding(f10_shape[0], embedding_dim=f10_shape[1])\n        self.f11_emb = nn.Embedding(f11_shape[0], embedding_dim=f11_shape[1])\n        \n        self.article_likelihood = nn.Parameter(torch.zeros(article_shape[0]), requires_grad=True)\n        \n        self.top = nn.Sequential(nn.Conv1d(3, 8, kernel_size=1), nn.LeakyReLU(),\n                                 nn.Conv1d(8, 3, kernel_size=1), nn.LeakyReLU(),\n                                 nn.Conv1d(3, 1, kernel_size=1))\n        \n    def forward(self, inputs, f_):\n        article_hist, week_hist = inputs[0], inputs[1]\n        \n        x = self.article_emb(article_hist)\n\n        #Get the embedding for articles in article_hist.\n        x1 = self.f1_emb(f_[0])\n        x_m = torch.cat((x,x1),2)##[256,16,317]\n        x2 = self.f2_emb(f_[1])\n        x_m = torch.cat((x_m,x2),2)###[256,16,322]\n        x3 = self.f3_emb(f_[2])\n        x_m = torch.cat((x_m,x3),2)###[256,16,327]\n        x4 = self.f4_emb(f_[3])\n        x_m = torch.cat((x_m,x4),2)###[256,16,332]\n        x5 = self.f5_emb(f_[4])\n        x_m = torch.cat((x_m,x5),2)###[256,16,337]\n        \n        x6 = self.f6_emb(f_[5])\n        x_m = torch.cat((x_m,x6),2)###[256,16,342]\n        x7 = self.f7_emb(f_[6])\n        x_m = torch.cat((x_m,x7),2)###[256,16,347]\n        x8 = self.f8_emb(f_[7])\n        x_m = torch.cat((x_m,x2),2)###[256,16,352]\n        x9 = self.f9_emb(f_[8])\n        x_m = torch.cat((x_m,x2),2)###[256,16,357]\n        x10 = self.f10_emb(f_[9])\n        x_m = torch.cat((x_m,x2),2)###[256,16,362]\n        x11 = self.f11_emb(f_[10])\n        x_m = torch.cat((x_m,x11),2)###[256,16,367]\n        \n        \n        \n        \n        #Get the embedding for all articles\n        x_all = self.article_emb.weight###[105543, 312]\n        f1_all = self.f1_emb(self.all_f1)###[105543, 10]\n        all_ = torch.cat((x_all,f1_all),1)###[105543, 317]\n        f2_all = self.f2_emb(self.all_f2)\n        all_ = torch.cat((all_,f2_all),1)###[105543, 322]\n        f3_all = self.f3_emb(self.all_f3)\n        all_ = torch.cat((all_,f3_all),1)###[105543, 327]\n        f4_all = self.f4_emb(self.all_f4)\n        all_ = torch.cat((all_,f4_all),1)###[105543, 332]\n        f5_all = self.f5_emb(self.all_f5) \n        all_ = torch.cat((all_,f5_all),1)###[105543, 337]\n        \n        f6_all = self.f6_emb(self.all_f6)\n        all_ = torch.cat((all_,f6_all),1)###[105543, 342]\n        f7_all = self.f7_emb(self.all_f7)\n        all_ = torch.cat((all_,f7_all),1)###[105543, 347]\n        f8_all = self.f8_emb(self.all_f8)\n        all_ = torch.cat((all_,f8_all),1)###[105543, 352]\n        f9_all = self.f9_emb(self.all_f9)\n        all_ = torch.cat((all_,f9_all),1)###[105543, 357]\n        f10_all = self.f10_emb(self.all_f10)\n        all_ = torch.cat((all_,f10_all),1)###[105543, 362]\n        f11_all = self.f11_emb(self.all_f11)\n        all_ = torch.cat((all_,f11_all),1)###[105543, 367]\n    \n        x_m = F.normalize(x_m, dim=2)\n        \n        x = x_m@F.normalize(all_).T ###[256,16,105543]\n        \n        x, indices = x.max(axis=1)\n        x = x.clamp(1e-3, 0.999)\n        x = -torch.log(1/x - 1)\n        \n        max_week = week_hist.unsqueeze(2).repeat(1, 1, x.shape[-1]).gather(1, indices.unsqueeze(1).repeat(1, week_hist.shape[1], 1))\n        max_week = max_week.mean(axis=1).unsqueeze(1)\n        \n        x = torch.cat([x.unsqueeze(1), max_week,\n                       self.article_likelihood[None, None, :].repeat(x.shape[0], 1, 1)], axis=1)\n        \n        x = self.top(x).squeeze(1)\n         \n        return x\n\nmodel = HMModel((len(le_article.classes_), 312),(len(le_f1.classes_),10),(len(le_f2.classes_),10),(len(le_f3.classes_),10),(len(le_f4.classes_),10),(len(le_f5.classes_),10),(len(le_f6.classes_),10),(len(le_f7.classes_),10),(len(le_f8.classes_),10),(len(le_f9.classes_),10),(len(le_f10.classes_),10),(len(le_f11.classes_),10),all_f)\nmodel = model.cuda()","metadata":{"execution":{"iopub.status.busy":"2022-08-04T05:10:10.552711Z","iopub.execute_input":"2022-08-04T05:10:10.552999Z","iopub.status.idle":"2022-08-04T05:10:10.837332Z","shell.execute_reply.started":"2022-08-04T05:10:10.552967Z","shell.execute_reply":"2022-08-04T05:10:10.836495Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import sys\n\ndef calc_map(topk_preds, target_array, k=12):\n    metric = []\n    tp, fp = 0, 0\n    \n    for pred in topk_preds:\n        if target_array[pred]:\n            tp += 1\n            metric.append(tp/(tp + fp))\n        else:\n            fp += 1\n            \n    return np.sum(metric) / min(k, target_array.sum())\n\ndef read_data(data):\n\n    return tuple(d.cuda() for d in data[:2]),tuple(d.cuda() for d in data[3]), data[2].cuda()\n\n\ndef validate(model, val_loader, k=12):\n    model.eval()\n    \n    tbar = tqdm(val_loader, file=sys.stdout)\n    \n    maps = []\n    \n    with torch.no_grad():\n        for idx, data in enumerate(tbar):\n            inputs, f, target = read_data(data)\n\n\n            logits = model(inputs,f)\n\n            _, indices = torch.topk(logits, k, dim=1)\n\n            indices = indices.detach().cpu().numpy()\n            target = target.detach().cpu().numpy()\n\n            for i in range(indices.shape[0]):\n                maps.append(calc_map(indices[i], target[i]))\n        \n    \n    return np.mean(maps)\n\nSEQ_LEN = 16\n\nBS = 256\nNW = 8\n\nval_dataset = HMDataset(val_df, SEQ_LEN)\n\nval_loader = DataLoader(val_dataset, batch_size=BS, shuffle=False, num_workers=NW,\n                          pin_memory=False, drop_last=False)\n","metadata":{"execution":{"iopub.status.busy":"2022-08-04T05:02:59.227224Z","iopub.execute_input":"2022-08-04T05:02:59.228006Z","iopub.status.idle":"2022-08-04T05:02:59.268188Z","shell.execute_reply.started":"2022-08-04T05:02:59.227961Z","shell.execute_reply":"2022-08-04T05:02:59.267187Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Train and validate","metadata":{}},{"cell_type":"code","source":"def dice_loss(y_pred, y_true):\n    y_pred = y_pred.sigmoid()\n    intersect = (y_true*y_pred).sum(axis=1)\n    \n    return 1 - (intersect/(intersect + y_true.sum(axis=1) + y_pred.sum(axis=1))).mean()\n\n\ndef train(model, train_loader, val_loader, epochs):\n    np.random.seed(SEED)\n    \n    optimizer = get_optimizer(model)\n    scaler = torch.cuda.amp.GradScaler()\n\n    criterion = torch.nn.BCEWithLogitsLoss()\n    \n    for e in range(epochs):\n        model.train()\n        tbar = tqdm(train_loader, file=sys.stdout)\n        \n        lr = adjust_lr(optimizer, e)\n        \n        loss_list = []\n\n        for idx, data in enumerate(tbar):\n            inputs, f, target = read_data(data)\n            \n            optimizer.zero_grad()\n            \n            with torch.cuda.amp.autocast():\n                logits = model(inputs,f)\n\n                loss = criterion(logits, target) + dice_loss(logits, target)\n            \n            \n            #loss.backward()\n            scaler.scale(loss).backward()\n            #optimizer.step()\n            scaler.step(optimizer)\n            scaler.update()\n            \n            loss_list.append(loss.detach().cpu().item())\n            \n            avg_loss = np.round(100*np.mean(loss_list), 4)\n\n            tbar.set_description(f\"Epoch {e+1} Loss: {avg_loss} lr: {lr}\")\n            \n            \n        #val_map = validate(model, val_loader)\n\n        #log_text = f\"Epoch {e+1}\\nTrain Loss: {avg_loss}\\nValidation MAP: {val_map}\\n\"\n        \n            \n        #print(log_text)\n        \n        #logfile = open(f\"models/{MODEL_NAME}_{SEED}.txt\", 'a')\n        #logfile.write(log_text)\n        #logfile.close()\n    return model\n\n\nMODEL_NAME = \"exp001\"\nSEED = 0\n\ntrain_dataset = HMDataset(train_df, SEQ_LEN)\n\ntrain_loader = DataLoader(train_dataset, batch_size=BS, shuffle=True, num_workers=NW,\n                          pin_memory=False, drop_last=True)\n\nmodel = train(model, train_loader, val_loader, epochs=5)","metadata":{"execution":{"iopub.status.busy":"2022-08-04T05:03:02.832274Z","iopub.execute_input":"2022-08-04T05:03:02.832841Z","iopub.status.idle":"2022-08-04T05:08:54.267267Z","shell.execute_reply.started":"2022-08-04T05:03:02.832805Z","shell.execute_reply":"2022-08-04T05:08:54.254078Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(read_data(train_dataset[0])[1])","metadata":{"execution":{"iopub.status.busy":"2022-08-04T04:08:08.130036Z","iopub.execute_input":"2022-08-04T04:08:08.130724Z","iopub.status.idle":"2022-08-04T04:08:08.155737Z","shell.execute_reply.started":"2022-08-04T04:08:08.130685Z","shell.execute_reply":"2022-08-04T04:08:08.154974Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Finetune with more recent data for submission (include validation set)","metadata":{}},{"cell_type":"code","source":"train_dataset = HMDataset(train_df[train_df[\"week\"] < 4].append(val_df), SEQ_LEN)\ntrain_loader = DataLoader(train_dataset, batch_size=BS, shuffle=True, num_workers=NW,\n                          pin_memory=False, drop_last=True)\n\nmodel = train(model, train_loader, val_loader, epochs=2)","metadata":{"execution":{"iopub.status.busy":"2022-08-04T05:09:12.761918Z","iopub.execute_input":"2022-08-04T05:09:12.762766Z","iopub.status.idle":"2022-08-04T05:10:01.624363Z","shell.execute_reply.started":"2022-08-04T05:09:12.762718Z","shell.execute_reply":"2022-08-04T05:10:01.615213Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df = pd.read_csv('../input/h-and-m-personalized-fashion-recommendations/sample_submission.csv').drop(\"prediction\", axis=1)\nprint(test_df.shape)\ntest_df.head()","metadata":{"execution":{"iopub.status.busy":"2022-08-04T05:10:17.673105Z","iopub.execute_input":"2022-08-04T05:10:17.673574Z","iopub.status.idle":"2022-08-04T05:10:22.470585Z","shell.execute_reply.started":"2022-08-04T05:10:17.673530Z","shell.execute_reply":"2022-08-04T05:10:22.469810Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def create_test_dataset(test_df):\n    week = -1\n    test_df[\"week\"] = week\n    \n    hist_df = df[(df[\"week\"] > week) & (df[\"week\"] <= week + WEEK_HIST_MAX)]\n    hist_df = hist_df.groupby(\"customer_id\").agg({\"article_id\": list, \"week\": list}).reset_index()\n    hist_df.rename(columns={\"week\": 'week_history'}, inplace=True)\n    \n    \n    return test_df.merge(hist_df, on=\"customer_id\", how=\"left\")\n\ntest_df = create_test_dataset(test_df)\ntest_df.head()","metadata":{"execution":{"iopub.status.busy":"2022-08-04T05:10:25.101824Z","iopub.execute_input":"2022-08-04T05:10:25.102407Z","iopub.status.idle":"2022-08-04T05:10:32.313192Z","shell.execute_reply.started":"2022-08-04T05:10:25.102371Z","shell.execute_reply":"2022-08-04T05:10:32.312458Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df[\"article_id\"].isnull().mean()","metadata":{"execution":{"iopub.status.busy":"2022-08-04T05:10:35.721116Z","iopub.execute_input":"2022-08-04T05:10:35.721889Z","iopub.status.idle":"2022-08-04T05:10:35.780000Z","shell.execute_reply.started":"2022-08-04T05:10:35.721851Z","shell.execute_reply":"2022-08-04T05:10:35.779189Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_ds = HMDataset(test_df, SEQ_LEN, is_test=True)\ntest_loader = DataLoader(test_ds, batch_size=BS, shuffle=False, num_workers=NW,\n                          pin_memory=False, drop_last=False)\n\n\ndef inference(model, loader, k=12):\n    model.eval()\n    \n    tbar = tqdm(loader, file=sys.stdout)\n    \n    preds = []\n    \n    with torch.no_grad():\n        for idx, data in enumerate(tbar):\n            inputs,f, target = read_data(data)\n\n            logits = model(inputs,f)\n\n            _, indices = torch.topk(logits, k, dim=1)\n\n            indices = indices.detach().cpu().numpy()\n            target = target.detach().cpu().numpy()\n\n            for i in range(indices.shape[0]):\n                preds.append(\" \".join(list(le_article.inverse_transform(indices[i]))))\n        \n    \n    return preds\n\n\ntest_df[\"prediction\"] = inference(model, test_loader)","metadata":{"execution":{"iopub.status.busy":"2022-08-04T05:10:44.258665Z","iopub.execute_input":"2022-08-04T05:10:44.258967Z","iopub.status.idle":"2022-08-04T05:12:24.915749Z","shell.execute_reply.started":"2022-08-04T05:10:44.258933Z","shell.execute_reply":"2022-08-04T05:12:24.914499Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df.to_csv(\"submission.csv\", index=False, columns=[\"customer_id\", \"prediction\"])","metadata":{"execution":{"iopub.status.busy":"2022-03-18T13:20:11.209147Z","iopub.status.idle":"2022-03-18T13:20:11.209811Z","shell.execute_reply.started":"2022-03-18T13:20:11.209573Z","shell.execute_reply":"2022-03-18T13:20:11.209598Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}