{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":67356,"databundleVersionId":8006601,"sourceType":"competition"}],"dockerImageVersionId":30698,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# 0. INTRODUCTION\n\n- make predict model \n- using ECFP (Extended-Connectivity Fingerprints) \n- using LightGBM","metadata":{}},{"cell_type":"markdown","source":"# 1. Prepare","metadata":{}},{"cell_type":"markdown","source":"## 1.1. install nescesary tools\n\n- DuckDB\n    - DuckDB is a fast in-process analytical database\n\n    \n- RDKit\n    - RDKit is a collection of cheminformatics and machine-learning software written in C++ and Python.","metadata":{}},{"cell_type":"code","source":"!pip install duckdb ## ENABLE when factory reset","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install rdkit ## ENABLE when factory reset","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 1.2. import libraries","metadata":{}},{"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","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import dask.dataframe as dd\nimport duckdb","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from rdkit import Chem\nfrom rdkit.Chem import AllChem","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import lightgbm as lgb","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\nfrom sklearn.metrics import average_precision_score\nfrom sklearn.preprocessing import OneHotEncoder","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import time\nimport datetime","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from multiprocessing import Pool","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.decomposition import PCA\nfrom sklearn.cluster import KMeans\n\nimport matplotlib\nimport matplotlib.pyplot as plt\n\nimport seaborn as sns","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torchvision\nimport torchvision.transforms as transforms\nfrom torch.utils.data import DataLoader","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 1.3. define functions and classies","metadata":{}},{"cell_type":"markdown","source":"- from below code, THANK YOU!\n    - [leash-tutorial-ecfps-and-random-forest](https://www.kaggle.com/code/andrewdblevins/leash-tutorial-ecfps-and-random-forest)\n    - [chemensemble-molecular-binding-with-ensemble](https://www.kaggle.com/code/yujansaya/chemensemble-molecular-binding-with-ensemble)","metadata":{}},{"cell_type":"code","source":"def generate_ecfp(molecule, radius=2, bits=1024):\n    if molecule is None:\n        return None\n    return list(Chem.AllChem.GetMorganFingerprintAsBitVect(molecule, radius, nBits=bits))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def from_SMILE_series_to_ecfp(smile_str_series): \n    return smile_str_series.apply(Chem.MolFromSmiles).apply(generate_ecfp)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_X(df_in): \n    t0_0 = time.time()\n    \n    ecfp_bb1  = from_SMILE_series_to_ecfp(df_in.loc[:, \"buildingblock1_smiles\"])\n    ecfp_bb2  = from_SMILE_series_to_ecfp(df_in.loc[:, \"buildingblock2_smiles\"])\n    ecfp_bb3  = from_SMILE_series_to_ecfp(df_in.loc[:, \"buildingblock3_smiles\"])\n    ecfp_mlcl = from_SMILE_series_to_ecfp(df_in.loc[:, \"molecule_smiles\"])\n    \n    X = np.array([s+t+u+v for s, t, u, v in zip(ecfp_bb1, \n                                                ecfp_bb2, \n                                                ecfp_bb3, \n                                                ecfp_mlcl)])\n    t0_1 = time.time()\n    print(\"get_X(): index {} ~ {}, elapsed time: {:0.03f} sec\".format(df_in.index.min(), df_in.index.max(), t0_1-t0_0))\n    \n    return X\n    ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_submission_data(df_in, clf_in): \n    t0_0 = time.time()\n    \n    X_test = get_X(df_in)\n    y_pred = clf_in.predict_proba(X_test)\n    \n    df_pred = pd.DataFrame(y_pred, columns=[\"complements_prob\", \"binds\"], index=df_in.index)\n    \n    ret_df = pd.concat(\n        [\n            df_in.loc[:, \"id\"], \n            df_pred.loc[:, \"binds\"]\n        ], axis=1\n    )\n    \n    return ret_df\n    ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- to make cross product set for iterator","metadata":{}},{"cell_type":"code","source":"def get_cross_product_of_series(val_series_1, val_series_2, series_name_1 = \"series_1\", series_name_2 = \"series_2\"): \n\n    tmp_sets = [[s, t] for s in val_series_1 for t in val_series_2]\n    ret_dict = {i1:{series_name_1:val_set[0], series_name_2:val_set[1]} for i1, val_set in enumerate(tmp_sets)}\n    \n    return ret_dict","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_cross_product_parameter_set(prm_dict): \n    key_list = []\n    tmp_list = [[]]\n    for k, val_vctr in prm_dict.items(): \n        tmp_list = [s+[t] for s in tmp_list for t in val_vctr]\n        key_list += [k]\n\n    ret_dict = {}\n    for i1, val_vctr in enumerate(tmp_list): \n        ret_dict[i1] = {k:v for k, v in zip(key_list, val_vctr)}\n        \n    return ret_dict\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def my_ap(y_true, y_score): \n    ap = average_precision_score(y_true, y_score, average=\"macro\", pos_label=1, sample_weight=None)\n    return \"ap\", ap, True\n    ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plotScatterChart(\n    dict_data:'dictionary', \n    wholeFigSize_width=12, \n    wholeFigSize_height=8, \n    subplotNumber_width=1, \n    subplotNumber_height=1, \n    subplots_adjust={'bottom':0.3, 'top':0.85, 'left':0.1, 'right':0.85, 'wspace':0.5, 'hspace':0.5}, \n    dirPath_outPng='', \n    fileName_outPng='', \n    titleStr_suptitle='', \n    color_set = [\"#000000\", \"#999999\", \n                 \"#AA0000\", \"#FF4500\", \n                 \"#008800\", \"#98FB98\", \n                 \"#000080\", \"#ADD8E6\"], \n    isShowLegend=True\n) : \n    plt.rcParams[\"font.size\"] = 12\n    fig = plt.figure(figsize=(wholeFigSize_width, wholeFigSize_height))  # 全体枠の大きさ (w, h) inch\n\n    ## i1 = 0\n    ## dict_i1 = dict_data[i1]\n    for i1, dict_i1 in dict_data.items() : \n\n        ## df = dict_i1['data']\n\n        subplotPosition = i1+1\n\n        ax = fig.add_subplot(subplotNumber_height, subplotNumber_width, subplotPosition) # サブプロットの位置 (vertical, horizontal, number)\n        fig.subplots_adjust(\n            bottom=subplots_adjust['bottom'], \n            top=subplots_adjust['top'], \n            left=subplots_adjust['left'], \n            right=subplots_adjust['right'], \n            wspace=subplots_adjust['wspace'], \n            hspace=subplots_adjust['hspace']\n        )\n\n        ## j1=0\n        ## v = dict_i1['data'][j1]\n        for j1, v in dict_i1['data'].items() : \n            rects = ax.scatter(\n                v[\"val\"][\"x\"], \n                v[\"val\"][\"y\"], \n                color=color_set[j1 % len(color_set)], \n                s=10\n            )\n        ## end ; for j1, v in dict_i1['data'].items() : \n        del j1, v\n\n        if isShowLegend : \n            ax.legend(\n                [vv['name'] for kk,vv in dict_i1['data'].items()], \n                bbox_to_anchor=(1, 1), \n                loc='upper left', \n                borderaxespad=0\n            )\n\n        ax.set_xlim(dict_i1['axisScale']['x'])\n        ax.set_ylim(dict_i1['axisScale']['y'])\n\n        ax.set_title(dict_i1['title'])\n\n        ax.set_xlabel('{}'.format(dict_i1['axisName_01']))\n        ax.set_ylabel('{}'.format(dict_i1['axisName_02']))\n\n        ax.grid(which='major', alpha=0.5, linestyle='-')\n\n    ## end ; for i1, dict_i1 in dict_data.items() : \n\n    plt.suptitle(titleStr_suptitle)\n\n    if ((dirPath_outPng!='')&(fileName_outPng!='')) : \n        plt.savefig(dirPath_outPng+'/'+fileName_outPng, bbox_inches=\"tight\") \n    else : \n        plt.show()\n    ## end ; if ((dirPath_outPng!='')&(fileName_outPng!='')) : \n\n    plt.close()\n\n    return 0\n## end ; def plotScatterChart(\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 1.4. set input and output parameteres","metadata":{}},{"cell_type":"code","source":"prms_in_ = {\n    \"train\": {\n        \"file\": {\n            \"path\": \"/kaggle/input/leash-BELKA\", \n            \"name\": \"train.parquet\"\n        }\n    }, \n    \"test\": {\n        \"file\": {\n            \"path\": \"/kaggle/input/leash-BELKA\", \n            \"name\": \"test.parquet\"\n        }\n    }\n}\n\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"prms_out_ = {\n    \"model\": {\n        \"file\": {\n            \"path\": \"/kaggle/working/leash-BELKA/010_VAE2/model\", \n            \"name\": \"model_VAE_{protein_name}_{binds}.pt\"\n        }\n    }, \n    \"model_loss\": {\n        \"file\": {\n            \"path\": \"/kaggle/working/leash-BELKA/010_VAE2/model\", \n            \"name\": \"loss_VAE_{protein_name}_{binds}.csv\"\n        }\n    }\n}","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 2. read files\n\n## 2.1. with dask","metadata":{}},{"cell_type":"code","source":"dskdf_ = {}\nfor info_lgcl_nm in [\"train\", \"test\"]: \n    dskdf_[info_lgcl_nm] = dd.read_parquet(\n        \"/\".join([v for k, v in prms_in_[info_lgcl_nm][\"file\"].items()])\n    )","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 2.1. with DuckDB","metadata":{}},{"cell_type":"markdown","source":"### 2.1.1. set query","metadata":{}},{"cell_type":"code","source":"query_str_ = {}","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# query_str_[\"train\"] = \"\"\"\n# SELECT * FROM parquet_scan('{train_path}')\n# ORDER BY random() \n# LIMIT {limit_row}\n# \"\"\".format(\n#     train_path=\"/\".join([v for k, v in prms_in_[\"train\"][\"file\"].items()]), \n#     limit_row=100000\n# )\n\nquery_str_base = \"\"\"\n(\n    SELECT * FROM parquet_scan('{train_path}') \n    WHERE binds = {binds}  AND protein_name = '{protein_name}'\n    ORDER BY random() \n    LIMIT {limit_row}\n)\n\"\"\"\n\niterator_val_set_ = get_cross_product_parameter_set(\n    {\n        \"binds\": [0, 1], \n        \"protein_name\": [\"HSA\", \"BRD4\", \"sEH\"]\n    }\n)\n\nquery_str_[\"train\"] = \"\"\nfor i1, val_set in iterator_val_set_.items(): \n    \n    if i1>0: \n        query_str_[\"train\"] += \"UNION ALL \"\n    \n    query_str_[\"train\"] += query_str_base.format(\n        train_path=\"/\".join([v for k, v in prms_in_[\"train\"][\"file\"].items()]), \n        binds=val_set[\"binds\"], \n        protein_name=val_set[\"protein_name\"], \n        limit_row=32768\n    )\n\nprint(\"query: {query_str}\".format(query_str=query_str_[\"train\"]))","metadata":{"scrolled":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"query_str_[\"test\"] = \"\"\"\nSELECT * FROM parquet_scan('{test_path}')\n\"\"\".format(\n    test_path=\"/\".join([v for k, v in prms_in_[\"test\"][\"file\"].items()]), \n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 2.1.2. execute query (read)","metadata":{}},{"cell_type":"code","source":"df_ = {}","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"t0_0 = time.time()\n\ncon = duckdb.connect()\ndf_[\"train\"] = con.query(query_str_[\"train\"]).df()\ncon.close()\n\nt0_1 = time.time()\nprint(\"train, elapsed time: {:0.03f} sec\".format(t0_1-t0_0))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"t0_0 = time.time()\n\ncon = duckdb.connect()\ndf_[\"test\"] = con.query(query_str_[\"test\"]).df()\ncon.close()\n\nt0_1 = time.time()\nprint(\"test, elapsed time: {:0.03f} sec\".format(t0_1-t0_0))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 3. make ecfp data","metadata":{}},{"cell_type":"code","source":"df_keys = df_[\"train\"].loc[:, [\"id\", \"protein_name\", \"binds\"]]\n\necfp_ = {}\ndf_ecfp_ = {}\nclnms_SMILES = [\"buildingblock1_smiles\", \"buildingblock2_smiles\", \"buildingblock3_smiles\", \"molecule_smiles\"]\nfor clnm in clnms_SMILES: \n    t1_0 = time.time()\n    \n    ecfp_[clnm]= from_SMILE_series_to_ecfp(df_[\"train\"].loc[:, clnm])\n\n    t1_1 = time.time()\n    print(\"from_SMILE_series_to_ecfp, column: {}, elapsed time: {:0.03f} sec\".format(clnm, t1_1-t1_0))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"prefix_synonym = {\n    \"buildingblock1_smiles\": \"bb1\", \n    \"buildingblock2_smiles\": \"bb2\", \n    \"buildingblock3_smiles\": \"bb3\", \n    \"molecule_smiles\": \"mlcl\"\n}\nfor clnm in clnms_SMILES: \n    t1_0 = time.time()\n    \n    df_ecfp_[clnm] = pd.DataFrame(ecfp_[clnm].tolist())\n    df_ecfp_[clnm] = df_ecfp_[clnm].rename(columns=lambda s:\"{}_{}\".format(prefix_synonym[clnm], s))\n\n    t1_1 = time.time()\n    print(\"to DataFrame, column: {}, elapsed time: {:0.03f} sec\".format(clnm, t1_1-t1_0))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 4. get train-valid data","metadata":{}},{"cell_type":"code","source":"df_train_Xy = pd.concat(\n    [\n        pd.concat(df_ecfp_, axis=1), \n        df_keys\n    ], axis=1\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train_ = {}\nX_valid_ = {}\ngrpby_key_i1 = [\"protein_name\", \"binds\"]\nfor key_i1, df_grp_i1 in df_train_Xy.groupby(grpby_key_i1): \n    \n    X_train_[key_i1], X_valid_[key_i1]= train_test_split(\n        df_grp_i1.reset_index(drop=True).drop(df_keys.columns, axis=1).values, \n        test_size=0.3, \n        random_state=20240505\n    )","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"del df_[\"train\"], ecfp_, df_train_Xy","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 5. VAE","metadata":{}},{"cell_type":"code","source":"class Encoder(nn.Module):\n    def __init__(self, orig_dim, encoded_dim):\n        super().__init__()\n        self.lr = nn.Linear(orig_dim, 10*orig_dim)\n        self.lr_ave = nn.Linear(10*orig_dim, encoded_dim)   #average\n        self.lr_dev = nn.Linear(10*orig_dim, encoded_dim)   #log(sigma^2)\n        self.relu = nn.ReLU()\n    def forward(self, x):\n        x = self.lr(x)\n        x = self.relu(x)\n        ave = self.lr_ave(x)\n        log_dev = self.lr_dev(x)\n\n        eps = torch.randn_like(ave)\n        z = ave + torch.exp(log_dev / 2) * eps\n        return z, ave, log_dev\n\nclass Decoder(nn.Module):\n    def __init__(self, encoded_dim, decoded_dim):\n        super().__init__()\n        self.lr = nn.Linear(encoded_dim, 10*encoded_dim)\n        self.lr2 = nn.Linear(10*encoded_dim, decoded_dim)\n        self.relu = nn.ReLU()\n\n    def forward(self, z):\n        x = self.lr(z)\n        x = self.relu(x)\n        x = self.lr2(x)\n        output = torch.sigmoid(x)\n        return output\n\nclass VAE(nn.Module):\n    def __init__(self, orig_dim, encoded_dim, decoded_dim):\n        super().__init__()\n        self.encoder = Encoder(orig_dim, encoded_dim)\n        self.decoder = Decoder(encoded_dim, decoded_dim)\n\n    def forward(self, x):\n        z, ave, log_dev = self.encoder(x)\n        output = self.decoder(z)\n        return output, z, ave, log_dev","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def criterion(predict, target, ave, log_dev):\n    bce_loss = F.binary_cross_entropy(predict, target, reduction='sum')\n    kl_loss = -0.5 * torch.sum(1 + log_dev - ave**2 - log_dev.exp())\n    loss = bce_loss + kl_loss\n    return loss","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 4.0. overview\n","metadata":{}},{"cell_type":"code","source":"BATCH_SIZE = 256\nnum_epochs = 32\nencoded_dim = 512","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for (protein_name, binds), X_train_i1 in X_train_.items():\n    print(\"-- protein_name: {} , binds: {}---------- ---------- ----------\".format(protein_name, binds))\n\n    train_loader = DataLoader(dataset=X_train_i1, \n                              batch_size=BATCH_SIZE,\n                              shuffle=True,\n                              num_workers=0)\n\n    valid_loader = DataLoader(dataset=X_valid_[(protein_name, binds)],\n                              batch_size=BATCH_SIZE,\n                              shuffle=True,\n                              num_workers=0)\n\n    orig_dim = X_train_i1.shape[1]\n    decoded_dim = X_train_i1.shape[1]\n\n\n    device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\") \n    model = VAE(orig_dim, encoded_dim, decoded_dim).to(device)\n    optimizer = torch.optim.Adam(model.parameters(), lr=0.001)\n    scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=[15], gamma=0.1)\n\n    history = {\"train_loss\": [], \"valid_loss\": [], \"ave\": [], \"log_dev\": [], \"z\": [], \"i1\":[]}\n\n    for epoch in range(num_epochs):\n        model.train()\n\n        i1_last = -1\n        t2_0 = time.time()\n        for i1, x in enumerate(train_loader):\n\n            output, z, ave, log_dev = model(x.to(torch.float32))\n\n            history[\"ave\"].append(ave)\n            history[\"log_dev\"].append(log_dev)\n            history[\"z\"].append(z)\n            history[\"i1\"].append(i1)\n            loss = criterion(output, x.to(torch.float32), ave, log_dev)\n\n            optimizer.zero_grad()\n            loss.backward()\n            optimizer.step()\n\n            if ((i1+1)%100==0) or ((i1+1)==len(train_loader)):\n                t2_1 = time.time()\n                print(\n                    \"Epoch: {}, i1: {:,d}~{:,d} (total: {}), elapsed time: {:0.03f} sec\".format(\n                        epoch, i1_last+1, i1, len(train_loader), t2_1-t2_0\n                    )\n                )\n                print(\"    train_loss: {:0,.04f}\".format(loss))\n                i1_last = i1\n                t2_0 = time.time()\n            ## end ; if (i+1) % 100 == 0:\n\n            history[\"train_loss\"].append(loss)\n        ## end ; for i1, x in enumerate(train_loader):\n\n        model.eval()\n        with torch.no_grad():\n            for i1, x in enumerate(valid_loader):\n                output, z, ave, log_dev = model(x.to(torch.float32))\n\n                loss = criterion(output, x.to(torch.float32), ave, log_dev)\n                history[\"valid_loss\"].append(loss)\n            ## end ; for i1, x in enumerate(valid_loader):\n\n            print(\"    valid_loss: {:0,.04f}\".format(loss))\n        ## end ; with torch.no_grad():\n\n        scheduler.step()\n    ## end ; for epoch in range(num_epochs):\n\n    print(\"\")\n\n    ## save pytorch model --------- --------- --------- --------- ---------\n    path_model_out = prms_out_[\"model\"][\"file\"][\"path\"]\n    os.makedirs(path_model_out, exist_ok=True)\n\n    flnm_model_out = prms_out_[\"model\"][\"file\"][\"name\"].format(protein_name=protein_name, binds=binds)\n    torch.save(model, \"{}/{}\".format(path_model_out, flnm_model_out))\n\n\n    ## output loss value --------- --------- --------- --------- ---------\n    loss_ = {}\n    for data_set in [\"train\", \"valid\"]: \n        loss_tensor = torch.stack(history[\"{}_loss\".format(data_set)])\n        loss_[data_set] = loss_tensor.to('cpu').detach().numpy().copy()\n\n    df_loss_out = pd.DataFrame()\n    for data_set, loss_np in loss_.items(): \n        df_loss_out = pd.concat(\n            [df_loss_out, pd.DataFrame(loss_np, columns=[data_set])], axis=1\n        )\n\n    flnm_model_loss_out = prms_out_[\"model_loss\"][\"file\"][\"name\"].format(protein_name=protein_name, binds=binds)\n\n    df_loss_out.to_csv( \n        \"{}/{}\".format(path_model_out, flnm_model_loss_out), \n        sep=\"\\t\",  \n        quotechar=\"\\\"\",  \n        quoting=1, \n        encoding=\"utf-8\", \n        header=True, \n        index=False\n    ) \n    \n## end ; for protein_name in protein_names: ","metadata":{"scrolled":true,"trusted":true},"execution_count":null,"outputs":[]}]}