{"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":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-10-22T08:49:27.853551Z","iopub.execute_input":"2022-10-22T08:49:27.853910Z","iopub.status.idle":"2022-10-22T08:49:27.861909Z","shell.execute_reply.started":"2022-10-22T08:49:27.853880Z","shell.execute_reply":"2022-10-22T08:49:27.860913Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Pytorch开发深度学习模型一般步骤\n\n## 1.定义DataSet\n- 理解数据原始形式\n- 理解数据编码方式\n- 理解如何进行数据I/O\n\n## 2.定义模型\n- 定义各个子模块\n- 将子模块合并成最终的模型\n\n## 3.完成Train Pipeline/Valid Pipeline\n- Pytorch一般的Train Pipeline/Valid Pipeline书写\n\n","metadata":{}},{"cell_type":"code","source":"import torch\nfrom torch.utils.data import Dataset\nimport torch.utils.data as D\nfrom torch import nn\nimport pandas as pd\nimport numpy as np\nimport copy\nimport os\nfrom sklearn.metrics import roc_auc_score,log_loss\nfrom tqdm.notebook import tqdm\nfrom collections import defaultdict","metadata":{"execution":{"iopub.status.busy":"2022-10-22T08:49:27.864166Z","iopub.execute_input":"2022-10-22T08:49:27.864975Z","iopub.status.idle":"2022-10-22T08:49:29.949824Z","shell.execute_reply.started":"2022-10-22T08:49:27.864938Z","shell.execute_reply":"2022-10-22T08:49:29.948852Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#参数配置\n\nconfig = {\n    \"train_path\":'/kaggle/input/deepshare-playground/train_behaviour.csv',\n    \"test_path\":'/kaggle/input/deepshare-playground/test_behaviour.csv',\n    \"debug_mode\" : False,\n    \"epoch\" : 20,\n    \"batch\" : 2048,\n    \"lr\" : 0.001,\n    \"device\" : 0,\n}","metadata":{"execution":{"iopub.status.busy":"2022-10-22T08:49:29.951239Z","iopub.execute_input":"2022-10-22T08:49:29.951814Z","iopub.status.idle":"2022-10-22T08:49:29.959074Z","shell.execute_reply.started":"2022-10-22T08:49:29.951784Z","shell.execute_reply":"2022-10-22T08:49:29.955996Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 1.定义DataSet\n- 理解数据原始形式\n- 理解数据编码方式\n- 理解如何进行数据I/O","metadata":{}},{"cell_type":"code","source":"train_df = pd.read_csv(config['train_path'])\nif config['debug_mode']:\n    train_df = train_df[:1000]\ntest_df = pd.read_csv(config['test_path'])","metadata":{"execution":{"iopub.status.busy":"2022-10-22T08:49:29.963771Z","iopub.execute_input":"2022-10-22T08:49:29.964485Z","iopub.status.idle":"2022-10-22T08:49:33.759066Z","shell.execute_reply.started":"2022-10-22T08:49:29.964449Z","shell.execute_reply":"2022-10-22T08:49:33.758108Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.concat([train_df,test_df],axis=0).reset_index(drop=True)","metadata":{"execution":{"iopub.status.busy":"2022-10-22T08:49:33.760577Z","iopub.execute_input":"2022-10-22T08:49:33.760951Z","iopub.status.idle":"2022-10-22T08:49:34.061842Z","shell.execute_reply.started":"2022-10-22T08:49:33.760912Z","shell.execute_reply":"2022-10-22T08:49:34.060824Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 原生离散特征编码\nvocab_map = dict()\nfor col in tqdm(['user_id','item_id']):\n    map_dict = dict(zip(df[col].unique(), range(1,1+df[col].nunique())))\n    # label enc\n    df[col] = df[col].map(map_dict)\n    vocab_map[col] = len(map_dict)+1","metadata":{"execution":{"iopub.status.busy":"2022-10-22T08:49:34.063332Z","iopub.execute_input":"2022-10-22T08:49:34.063812Z","iopub.status.idle":"2022-10-22T08:49:35.566134Z","shell.execute_reply.started":"2022-10-22T08:49:34.063775Z","shell.execute_reply":"2022-10-22T08:49:35.565138Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"vocab_map","metadata":{"execution":{"iopub.status.busy":"2022-10-22T08:49:35.567655Z","iopub.execute_input":"2022-10-22T08:49:35.568254Z","iopub.status.idle":"2022-10-22T08:49:35.577608Z","shell.execute_reply.started":"2022-10-22T08:49:35.568215Z","shell.execute_reply":"2022-10-22T08:49:35.576442Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Dataset构造\nclass BaseDataset(Dataset):\n    def __init__(self,df):\n        self.df = df\n        self.feature_name = ['user_id','item_id']\n        #数据编码\n        self.enc_data()\n\n    def enc_data(self):\n        #使用enc_dict对数据进行编码\n        self.enc_df = copy.deepcopy(self.df)\n        for col in self.feature_name:\n            self.enc_df[col] = torch.Tensor(np.array(self.df[col])).long()\n            \n    def __getitem__(self, index):\n        data = dict()\n        for col in self.feature_name:\n            data[col] = torch.Tensor([self.enc_df[col].iloc[index]]).long().squeeze(-1)\n        if 'label' in self.enc_df.columns:\n            data['label'] = torch.Tensor([self.enc_df['label'].iloc[index]]).squeeze(-1)\n        return data\n\n    def __len__(self):\n        return len(self.df)","metadata":{"execution":{"iopub.status.busy":"2022-10-22T08:49:35.579334Z","iopub.execute_input":"2022-10-22T08:49:35.580502Z","iopub.status.idle":"2022-10-22T08:49:35.590081Z","shell.execute_reply.started":"2022-10-22T08:49:35.580465Z","shell.execute_reply":"2022-10-22T08:49:35.589142Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df = df[df['label'].notna()].reset_index(drop=True)\ntest_df = df[df['label'].isna()].reset_index(drop=True)\ndel test_df['label']\n\ntrain_num = int(len(train_df)*0.8)\nvalid_df = train_df[train_num:].reset_index(drop=True)\ntrain_df = train_df[:train_num].reset_index(drop=True)","metadata":{"execution":{"iopub.status.busy":"2022-10-22T08:49:35.594647Z","iopub.execute_input":"2022-10-22T08:49:35.594918Z","iopub.status.idle":"2022-10-22T08:49:35.982382Z","shell.execute_reply.started":"2022-10-22T08:49:35.594893Z","shell.execute_reply":"2022-10-22T08:49:35.981264Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataset = BaseDataset(train_df)\nvalid_dataset = BaseDataset(valid_df)\ntest_dataset = BaseDataset(test_df)","metadata":{"execution":{"iopub.status.busy":"2022-10-22T08:49:35.983945Z","iopub.execute_input":"2022-10-22T08:49:35.984345Z","iopub.status.idle":"2022-10-22T08:49:36.090997Z","shell.execute_reply.started":"2022-10-22T08:49:35.984303Z","shell.execute_reply":"2022-10-22T08:49:36.089925Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataset.__getitem__(777)","metadata":{"execution":{"iopub.status.busy":"2022-10-22T08:49:36.092483Z","iopub.execute_input":"2022-10-22T08:49:36.093291Z","iopub.status.idle":"2022-10-22T08:49:36.106345Z","shell.execute_reply.started":"2022-10-22T08:49:36.093247Z","shell.execute_reply":"2022-10-22T08:49:36.105173Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_dataset.__getitem__(777)","metadata":{"execution":{"iopub.status.busy":"2022-10-22T08:49:36.110244Z","iopub.execute_input":"2022-10-22T08:49:36.110603Z","iopub.status.idle":"2022-10-22T08:49:36.121006Z","shell.execute_reply.started":"2022-10-22T08:49:36.110570Z","shell.execute_reply":"2022-10-22T08:49:36.119753Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 2.定义模型\n- 定义各个子模块\n- 将子模块合并成最终的模型","metadata":{}},{"cell_type":"code","source":"# 理解Embedding 层\nemb_layer = nn.Embedding(8,4)","metadata":{"execution":{"iopub.status.busy":"2022-10-22T08:49:36.122632Z","iopub.execute_input":"2022-10-22T08:49:36.123031Z","iopub.status.idle":"2022-10-22T08:49:36.130754Z","shell.execute_reply.started":"2022-10-22T08:49:36.122983Z","shell.execute_reply":"2022-10-22T08:49:36.129434Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"emb_layer.weight","metadata":{"execution":{"iopub.status.busy":"2022-10-22T08:49:36.132797Z","iopub.execute_input":"2022-10-22T08:49:36.133268Z","iopub.status.idle":"2022-10-22T08:49:36.143301Z","shell.execute_reply.started":"2022-10-22T08:49:36.133225Z","shell.execute_reply":"2022-10-22T08:49:36.141917Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"idx = torch.from_numpy(np.array([1,2,1]))\nemb_layer(idx)","metadata":{"execution":{"iopub.status.busy":"2022-10-22T08:49:36.145283Z","iopub.execute_input":"2022-10-22T08:49:36.146885Z","iopub.status.idle":"2022-10-22T08:49:36.159432Z","shell.execute_reply.started":"2022-10-22T08:49:36.146839Z","shell.execute_reply":"2022-10-22T08:49:36.157969Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class MF(nn.Module):\n    def __init__(self,\n                embedding_dim = 16,\n                vocab_map = None,\n                loss_fun = 'torch.nn.BCELoss()'):\n        super(MF, self).__init__()\n        self.embedding_dim = embedding_dim\n        self.vocab_map = vocab_map\n        self.loss_fun = eval(loss_fun) # self.loss_fun  = torch.nn.BCELoss()\n        \n        self.user_emb_layer = nn.Embedding(self.vocab_map['user_id'],\n                                          self.embedding_dim)\n        self.item_emb_layer = nn.Embedding(self.vocab_map['item_id'],\n                                          self.embedding_dim)\n        \n        self.mlp = nn.Sequential(\n            nn.Linear(2*self.embedding_dim,self.embedding_dim),\n            nn.ReLU(inplace=True),\n            nn.BatchNorm1d(self.embedding_dim),\n            nn.Linear(self.embedding_dim,1),\n            nn.Sigmoid()\n        )\n        \n    def forward(self,data):\n        user_emb = self.user_emb_layer(data['user_id']) # [batch,emb]\n        item_emb = self.item_emb_layer(data['item_id']) # [batch,emb]\n        mlp_input = torch.cat([user_emb, item_emb],axis=-1)\n        y_pred = self.mlp(mlp_input)\n        if 'label' in data.keys():\n            loss = self.loss_fun(y_pred.squeeze(),data['label'])\n            output_dict = {'pred':y_pred,'loss':loss}\n        else:\n            output_dict = {'pred':y_pred}\n        return output_dict","metadata":{"execution":{"iopub.status.busy":"2022-10-22T08:53:54.462448Z","iopub.execute_input":"2022-10-22T08:53:54.462818Z","iopub.status.idle":"2022-10-22T08:53:54.472981Z","shell.execute_reply.started":"2022-10-22T08:53:54.462788Z","shell.execute_reply":"2022-10-22T08:53:54.471851Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 3.完成Train Pipeline/Valid Pipeline\n- Pytorch一般的Train Pipeline/Valid Pipeline书写","metadata":{}},{"cell_type":"code","source":"#训练模型，验证模型\ndef train_model(model, train_loader, optimizer, device, metric_list=['roc_auc_score','log_loss']):\n    model.train()\n    pred_list = []\n    label_list = []\n    pbar = tqdm(train_loader)\n    for data in pbar:\n\n        for key in data.keys():\n            data[key] = data[key].to(device)\n\n        output = model(data)\n        pred = output['pred']\n        loss = output['loss']\n\n        loss.backward()\n        optimizer.step()\n        model.zero_grad()\n\n        pred_list.extend(pred.squeeze(-1).cpu().detach().numpy())\n        label_list.extend(data['label'].squeeze(-1).cpu().detach().numpy())\n        pbar.set_description(\"Loss {}\".format(loss))\n\n    res_dict = dict()\n    for metric in metric_list:\n        if metric =='log_loss':\n            res_dict[metric] = log_loss(label_list,pred_list, eps=1e-7)\n        else:\n            res_dict[metric] = eval(metric)(label_list,pred_list)\n\n    return res_dict\n\ndef valid_model(model, valid_loader, device, metric_list=['roc_auc_score','log_loss']):\n    model.eval()\n    pred_list = []\n    label_list = []\n\n    for data in (valid_loader):\n\n        for key in data.keys():\n            data[key] = data[key].to(device)\n\n        output = model(data)\n        pred = output['pred']\n\n        pred_list.extend(pred.squeeze(-1).cpu().detach().numpy())\n        label_list.extend(data['label'].squeeze(-1).cpu().detach().numpy())\n\n    res_dict = dict()\n    for metric in metric_list:\n        if metric =='log_loss':\n            res_dict[metric] = log_loss(label_list,pred_list, eps=1e-7)\n        else:\n            res_dict[metric] = eval(metric)(label_list,pred_list)\n\n    return res_dict\n\ndef test_model(model, test_loader, device):\n    model.eval()\n    pred_list = []\n\n    for data in tqdm(test_loader):\n\n        for key in data.keys():\n            data[key] = data[key].to(device)\n\n        output = model(data)\n        pred = output['pred']\n        pred_list.extend(pred.squeeze().cpu().detach().numpy())\n\n    return np.array(pred_list)","metadata":{"execution":{"iopub.status.busy":"2022-10-22T08:53:54.784740Z","iopub.execute_input":"2022-10-22T08:53:54.785088Z","iopub.status.idle":"2022-10-22T08:53:54.800037Z","shell.execute_reply.started":"2022-10-22T08:53:54.785054Z","shell.execute_reply":"2022-10-22T08:53:54.798969Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#dataloader\ntrain_loader = D.DataLoader(train_dataset,batch_size=config['batch'],shuffle=True,num_workers=0)\nvalid_loader = D.DataLoader(valid_dataset,batch_size=config['batch'],shuffle=False,num_workers=0)\ntest_loader = D.DataLoader(test_dataset,batch_size=config['batch'],shuffle=False,num_workers=0)","metadata":{"execution":{"iopub.status.busy":"2022-10-22T08:53:54.959866Z","iopub.execute_input":"2022-10-22T08:53:54.960182Z","iopub.status.idle":"2022-10-22T08:53:54.966597Z","shell.execute_reply.started":"2022-10-22T08:53:54.960154Z","shell.execute_reply":"2022-10-22T08:53:54.965668Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = MF(embedding_dim=64,vocab_map=vocab_map)","metadata":{"execution":{"iopub.status.busy":"2022-10-22T08:53:55.088272Z","iopub.execute_input":"2022-10-22T08:53:55.088572Z","iopub.status.idle":"2022-10-22T08:53:55.121833Z","shell.execute_reply.started":"2022-10-22T08:53:55.088546Z","shell.execute_reply":"2022-10-22T08:53:55.120807Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if torch.cuda.is_available():\n    device = torch.device('cuda')\nelse:\n    device = torch.device('cpu')\n\noptimizer = torch.optim.Adam(model.parameters(), lr=config['lr'], betas=(0.9, 0.999), eps=1e-08, weight_decay=0)\nmodel = model.to(device)\n#模型训练流程\nfor i in range(config['epoch']):\n    #模型训练\n    train_metirc = train_model(model,train_loader,optimizer=optimizer,device=device)\n    #模型验证\n    valid_metric = valid_model(model,valid_loader,device)\n\n    print(\"Train Metric:\")\n    print(train_metirc)\n    print(\"Valid Metric:\")\n    print(valid_metric)","metadata":{"execution":{"iopub.status.busy":"2022-10-22T08:53:55.282138Z","iopub.execute_input":"2022-10-22T08:53:55.283182Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pre = test_model(model,test_loader,device)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"res_df = pd.DataFrame()\nres_df['ID'] = test_df['ID']\nres_df['predict'] = y_pre\nres_df.to_csv('/kaggle/working/MF.csv',index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device","metadata":{"execution":{"iopub.status.busy":"2022-10-22T08:50:17.042611Z","iopub.execute_input":"2022-10-22T08:50:17.043039Z","iopub.status.idle":"2022-10-22T08:50:17.054667Z","shell.execute_reply.started":"2022-10-22T08:50:17.043001Z","shell.execute_reply":"2022-10-22T08:50:17.053791Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}