From 1d946b4464dbfde0a609997cb28aef90fdfc2027 Mon Sep 17 00:00:00 2001 From: zhaojinghao Date: Fri, 5 Jan 2024 17:15:57 +0800 Subject: [PATCH] optim --- .../CBA_4feature-checkpoint.ipynb | 1440 +++++++++++++++++ .../CBA_vad_fcad-checkpoint.ipynb | 1311 +++++++++++++++ .../multi-task0102-checkpoint.ipynb | 735 ++++----- 20240102.ipynb | 168 +- CBA_4feature.ipynb | 1440 +++++++++++++++++ CBA_vad_fcad.ipynb | 1316 +++++++++++++++ model.png | Bin 0 -> 33997 bytes multi-task0102.ipynb | 708 +++----- 8 files changed, 6080 insertions(+), 1038 deletions(-) create mode 100644 .ipynb_checkpoints/CBA_4feature-checkpoint.ipynb create mode 100644 .ipynb_checkpoints/CBA_vad_fcad-checkpoint.ipynb create mode 100644 CBA_4feature.ipynb create mode 100644 CBA_vad_fcad.ipynb create mode 100644 model.png diff --git a/.ipynb_checkpoints/CBA_4feature-checkpoint.ipynb b/.ipynb_checkpoints/CBA_4feature-checkpoint.ipynb new file mode 100644 index 0000000..43d01bb --- /dev/null +++ b/.ipynb_checkpoints/CBA_4feature-checkpoint.ipynb @@ -0,0 +1,1440 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "6b84fefd-5936-4da4-ab6b-5b944329ad1d", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "os.environ['CUDA_DEVICE_ORDER'] = 'PCB_BUS_ID'\n", + "os.environ['CUDA_VISIBLE_DEVICES'] = '0, 1'" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "9cf130e3-62ef-46e0-bbdc-b13d9d29318d", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "from sklearn.model_selection import train_test_split\n", + "import matplotlib.pyplot as plt\n", + "#新增加的两行\n", + "from pylab import mpl\n", + "# 设置显示中文字体\n", + "mpl.rcParams[\"font.sans-serif\"] = [\"SimHei\"]\n", + "\n", + "mpl.rcParams[\"axes.unicode_minus\"] = False" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "752381a5-0aeb-4c54-bc48-f9c3f8fc5d17", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Unnamed: 0_level_0弹筒发热量挥发分固定炭
化验编号HadCadNadOadQb,adVadFcad
Unnamed: 0_level_2(%)(%)(%)(%)MJ/kg(%)(%)
027201105293.9370.180.8125.07927.82032.0655.68
127200968833.7868.930.7726.51227.40429.9654.71
227201090843.4869.600.7626.14827.57829.3155.99
327200847083.4766.710.7629.05526.33828.5853.87
427200627213.8768.780.8026.54227.28029.9754.78
...........................
22327200304904.1268.850.9726.05527.86432.9451.89
22427200286333.9767.040.9428.04327.36831.8851.38
22527200286344.1268.420.9626.49327.88633.1652.00
22627200176833.8867.420.9427.76026.61631.6550.56
22727200176783.8166.740.9228.53026.68831.0250.82
\n", + "

228 rows × 8 columns

\n", + "
" + ], + "text/plain": [ + " Unnamed: 0_level_0 氢 碳 氮 氧 弹筒发热量 挥发分 固定炭\n", + " 化验编号 Had Cad Nad Oad Qb,ad Vad Fcad\n", + " Unnamed: 0_level_2 (%) (%) (%) (%) MJ/kg (%) (%)\n", + "0 2720110529 3.93 70.18 0.81 25.079 27.820 32.06 55.68\n", + "1 2720096883 3.78 68.93 0.77 26.512 27.404 29.96 54.71\n", + "2 2720109084 3.48 69.60 0.76 26.148 27.578 29.31 55.99\n", + "3 2720084708 3.47 66.71 0.76 29.055 26.338 28.58 53.87\n", + "4 2720062721 3.87 68.78 0.80 26.542 27.280 29.97 54.78\n", + ".. ... ... ... ... ... ... ... ...\n", + "223 2720030490 4.12 68.85 0.97 26.055 27.864 32.94 51.89\n", + "224 2720028633 3.97 67.04 0.94 28.043 27.368 31.88 51.38\n", + "225 2720028634 4.12 68.42 0.96 26.493 27.886 33.16 52.00\n", + "226 2720017683 3.88 67.42 0.94 27.760 26.616 31.65 50.56\n", + "227 2720017678 3.81 66.74 0.92 28.530 26.688 31.02 50.82\n", + "\n", + "[228 rows x 8 columns]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data_0102 = pd.read_excel('./data/20240102/20240102.xlsx', header=[0,1,2])\n", + "data_0102" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "972f1e9c-3ebc-45cf-8d1f-7611645e5238", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['化验编号',\n", + " '氢Had(%)',\n", + " '碳Cad(%)',\n", + " '氮Nad(%)',\n", + " '氧Oad(%)',\n", + " '弹筒发热量Qb,adMJ/kg',\n", + " '挥发分Vad(%)',\n", + " '固定炭Fcad(%)']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cols = [''.join([y for y in x if 'Unnamed' not in y]) for x in data_0102.columns]\n", + "cols" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "c95f1106-b3a4-43c6-88ec-3cdebf91d79a", + "metadata": {}, + "outputs": [], + "source": [ + "data_0102.columns = cols" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "2e96af0a-feda-4a1f-a13e-9c8861c6f4d4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
化验编号氢Had(%)碳Cad(%)氮Nad(%)氧Oad(%)弹筒发热量Qb,adMJ/kg挥发分Vad(%)固定炭Fcad(%)
027201105293.9370.180.8125.07927.82032.0655.68
127200968833.7868.930.7726.51227.40429.9654.71
227201090843.4869.600.7626.14827.57829.3155.99
327200847083.4766.710.7629.05526.33828.5853.87
427200627213.8768.780.8026.54227.28029.9754.78
...........................
22327200304904.1268.850.9726.05527.86432.9451.89
22427200286333.9767.040.9428.04327.36831.8851.38
22527200286344.1268.420.9626.49327.88633.1652.00
22627200176833.8867.420.9427.76026.61631.6550.56
22727200176783.8166.740.9228.53026.68831.0250.82
\n", + "

228 rows × 8 columns

\n", + "
" + ], + "text/plain": [ + " 化验编号 氢Had(%) 碳Cad(%) 氮Nad(%) 氧Oad(%) 弹筒发热量Qb,adMJ/kg \\\n", + "0 2720110529 3.93 70.18 0.81 25.079 27.820 \n", + "1 2720096883 3.78 68.93 0.77 26.512 27.404 \n", + "2 2720109084 3.48 69.60 0.76 26.148 27.578 \n", + "3 2720084708 3.47 66.71 0.76 29.055 26.338 \n", + "4 2720062721 3.87 68.78 0.80 26.542 27.280 \n", + ".. ... ... ... ... ... ... \n", + "223 2720030490 4.12 68.85 0.97 26.055 27.864 \n", + "224 2720028633 3.97 67.04 0.94 28.043 27.368 \n", + "225 2720028634 4.12 68.42 0.96 26.493 27.886 \n", + "226 2720017683 3.88 67.42 0.94 27.760 26.616 \n", + "227 2720017678 3.81 66.74 0.92 28.530 26.688 \n", + "\n", + " 挥发分Vad(%) 固定炭Fcad(%) \n", + "0 32.06 55.68 \n", + "1 29.96 54.71 \n", + "2 29.31 55.99 \n", + "3 28.58 53.87 \n", + "4 29.97 54.78 \n", + ".. ... ... \n", + "223 32.94 51.89 \n", + "224 31.88 51.38 \n", + "225 33.16 52.00 \n", + "226 31.65 50.56 \n", + "227 31.02 50.82 \n", + "\n", + "[228 rows x 8 columns]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data_0102" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "04b177a7-2f02-4e23-8ea9-29f34cf3eafc", + "metadata": {}, + "outputs": [], + "source": [ + "out_cols = ['挥发分Vad(%)']\n", + "# out_cols = ['固定炭Fcad(%)']" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "31169fbf-d78e-42f7-87f3-71ba3dd0979d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['挥发分Vad(%)']" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "out_cols" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "feaedd50-f999-45bf-b465-3d359b0c0110", + "metadata": {}, + "outputs": [], + "source": [ + "data = data_0102.copy()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "a40bee0f-011a-4edb-80f8-4e2f40e755fd", + "metadata": {}, + "outputs": [], + "source": [ + "train_data = data.dropna(subset=out_cols).fillna(0)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "535d37b6-b9de-4025-ac8f-62f5bdbe2451", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-01-05 16:22:29.862058: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0\n" + ] + } + ], + "source": [ + "import tensorflow as tf\n", + "from tensorflow import keras\n", + "from tensorflow.keras import layers\n", + "import tensorflow.keras.backend as K" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "1c85d462-f248-4ffb-908f-eb4b20eab179", + "metadata": {}, + "outputs": [], + "source": [ + "class TransformerBlock(layers.Layer):\n", + " def __init__(self, embed_dim, num_heads, ff_dim, name, rate=0.1):\n", + " super().__init__()\n", + " self.att = layers.MultiHeadAttention(num_heads=num_heads, key_dim=embed_dim, name=name)\n", + " self.ffn = keras.Sequential(\n", + " [layers.Dense(ff_dim, activation=\"relu\"), layers.Dense(embed_dim),]\n", + " )\n", + " self.layernorm1 = layers.LayerNormalization(epsilon=1e-6)\n", + " self.layernorm2 = layers.LayerNormalization(epsilon=1e-6)\n", + " self.dropout1 = layers.Dropout(rate)\n", + " self.dropout2 = layers.Dropout(rate)\n", + "\n", + " def call(self, inputs, training):\n", + " attn_output = self.att(inputs, inputs)\n", + " attn_output = self.dropout1(attn_output, training=training)\n", + " out1 = self.layernorm1(inputs + attn_output)\n", + " ffn_output = self.ffn(out1)\n", + " ffn_output = self.dropout2(ffn_output, training=training)\n", + " return self.layernorm2(out1 + ffn_output)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "790284a3-b9d3-4144-b481-38a7c3ecb4b9", + "metadata": {}, + "outputs": [], + "source": [ + "from tensorflow.keras import Model" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "cd9a1ca1-d0ca-4cb5-9ef5-fd5d63576cd2", + "metadata": {}, + "outputs": [], + "source": [ + "from tensorflow.keras.initializers import Constant" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "9bc02f29-0fb7-420d-99a8-435eadc06e29", + "metadata": {}, + "outputs": [], + "source": [ + "# Custom loss layer\n", + "class CustomMultiLossLayer(layers.Layer):\n", + " def __init__(self, nb_outputs=2, **kwargs):\n", + " self.nb_outputs = nb_outputs\n", + " self.is_placeholder = True\n", + " super(CustomMultiLossLayer, self).__init__(**kwargs)\n", + " \n", + " def build(self, input_shape=None):\n", + " # initialise log_vars\n", + " self.log_vars = []\n", + " for i in range(self.nb_outputs):\n", + " self.log_vars += [self.add_weight(name='log_var' + str(i), shape=(1,),\n", + " initializer=tf.initializers.he_normal(), trainable=True)]\n", + " super(CustomMultiLossLayer, self).build(input_shape)\n", + "\n", + " def multi_loss(self, ys_true, ys_pred):\n", + " assert len(ys_true) == self.nb_outputs and len(ys_pred) == self.nb_outputs\n", + " loss = 0\n", + " for y_true, y_pred, log_var in zip(ys_true, ys_pred, self.log_vars):\n", + " mse = (y_true - y_pred) ** 2.\n", + " pre = K.exp(-log_var[0])\n", + " loss += tf.abs(tf.reduce_logsumexp(pre * mse + log_var[0], axis=-1))\n", + " return K.mean(loss)\n", + "\n", + " def call(self, inputs):\n", + " ys_true = inputs[:self.nb_outputs]\n", + " ys_pred = inputs[self.nb_outputs:]\n", + " loss = self.multi_loss(ys_true, ys_pred)\n", + " self.add_loss(loss, inputs=inputs)\n", + " # We won't actually use the output.\n", + " return K.concatenate(inputs, -1)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "a190207e-5a59-4813-9660-758760cf1b73", + "metadata": {}, + "outputs": [], + "source": [ + "num_heads, ff_dim = 3, 16" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "80f32155-e71f-4615-8d0c-01dfd04988fe", + "metadata": {}, + "outputs": [], + "source": [ + "def get_prediction_model():\n", + " inputs = layers.Input(shape=(1,len(feature_cols)), name='input')\n", + " x = layers.Conv1D(filters=64, kernel_size=1, activation='relu')(inputs)\n", + " # x = layers.Dropout(rate=0.1)(x)\n", + " lstm_out = layers.Bidirectional(layers.LSTM(units=64, return_sequences=True))(x)\n", + " lstm_out = layers.Dense(128, activation='relu')(lstm_out)\n", + " transformer_block = TransformerBlock(128, num_heads, ff_dim, name='first_attn')\n", + " out = transformer_block(lstm_out)\n", + " out = layers.GlobalAveragePooling1D()(out)\n", + " out = layers.Dropout(0.1)(out)\n", + " out = layers.Dense(64, activation='relu')(out)\n", + " bet = layers.Dense(1, activation='sigmoid', name='vad')(out)\n", + " model = Model(inputs=[inputs], outputs=[bet])\n", + " return model" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "7a9915ee-0016-44e5-a6fb-5ee90532dc14", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model: \"model_23\"\n", + "_________________________________________________________________\n", + "Layer (type) Output Shape Param # \n", + "=================================================================\n", + "input (InputLayer) [(None, 1, 7)] 0 \n", + "_________________________________________________________________\n", + "conv1d_25 (Conv1D) (None, 1, 64) 512 \n", + "_________________________________________________________________\n", + "bidirectional_25 (Bidirectio (None, 1, 128) 66048 \n", + "_________________________________________________________________\n", + "dense_100 (Dense) (None, 1, 128) 16512 \n", + "_________________________________________________________________\n", + "transformer_block_25 (Transf (None, 1, 128) 202640 \n", + "_________________________________________________________________\n", + "global_average_pooling1d_25 (None, 128) 0 \n", + "_________________________________________________________________\n", + "dropout_77 (Dropout) (None, 128) 0 \n", + "_________________________________________________________________\n", + "dense_103 (Dense) (None, 64) 8256 \n", + "_________________________________________________________________\n", + "vad (Dense) (None, 1) 65 \n", + "=================================================================\n", + "Total params: 294,033\n", + "Trainable params: 294,033\n", + "Non-trainable params: 0\n", + "_________________________________________________________________\n" + ] + } + ], + "source": [ + "model = get_prediction_model()\n", + "model.summary()" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "372011ea-9876-41eb-a4e6-83ccd6c71559", + "metadata": {}, + "outputs": [], + "source": [ + "from tensorflow.python.keras.utils.vis_utils import plot_model" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "1eebdab3-1f88-48a1-b5e0-bc8787528c1b", + "metadata": {}, + "outputs": [], + "source": [ + "maxs = train_data.max()\n", + "mins = train_data.min()\n", + "for col in train_data.columns:\n", + " if maxs[col] - mins[col] == 0:\n", + " continue\n", + " train_data[col] = (train_data[col] - mins[col]) / (maxs[col] - mins[col])" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "7f27bd56-4f6b-4242-9f79-c7d6b3ee2f13", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
化验编号氢Had(%)碳Cad(%)氮Nad(%)氧Oad(%)弹筒发热量Qb,adMJ/kg挥发分Vad(%)固定炭Fcad(%)
00.9965470.7739730.8354140.4565220.1714630.8112490.8477370.828147
10.8511180.6712330.7999430.3695650.2102540.7820380.6748970.794606
20.9811470.4657530.8189560.3478260.2004010.7942560.6213990.838866
30.7213670.4589040.7369470.3478260.2790940.7071830.5613170.765560
40.4870460.7328770.7956870.4347830.2110660.7733310.6757200.797026
...........................
2230.1435530.9041100.7976730.8043480.1978830.8143390.9201650.697095
2240.1237620.8013700.7463110.7391300.2516990.7795100.8329220.679461
2250.1237730.9041100.7854710.7826090.2097400.8158840.9382720.700899
2260.0070660.7397260.7570940.7391300.2440380.7267050.8139920.651107
2270.0070120.6917810.7377980.6956520.2648820.7317600.7621400.660097
\n", + "

228 rows × 8 columns

\n", + "
" + ], + "text/plain": [ + " 化验编号 氢Had(%) 碳Cad(%) 氮Nad(%) 氧Oad(%) 弹筒发热量Qb,adMJ/kg \\\n", + "0 0.996547 0.773973 0.835414 0.456522 0.171463 0.811249 \n", + "1 0.851118 0.671233 0.799943 0.369565 0.210254 0.782038 \n", + "2 0.981147 0.465753 0.818956 0.347826 0.200401 0.794256 \n", + "3 0.721367 0.458904 0.736947 0.347826 0.279094 0.707183 \n", + "4 0.487046 0.732877 0.795687 0.434783 0.211066 0.773331 \n", + ".. ... ... ... ... ... ... \n", + "223 0.143553 0.904110 0.797673 0.804348 0.197883 0.814339 \n", + "224 0.123762 0.801370 0.746311 0.739130 0.251699 0.779510 \n", + "225 0.123773 0.904110 0.785471 0.782609 0.209740 0.815884 \n", + "226 0.007066 0.739726 0.757094 0.739130 0.244038 0.726705 \n", + "227 0.007012 0.691781 0.737798 0.695652 0.264882 0.731760 \n", + "\n", + " 挥发分Vad(%) 固定炭Fcad(%) \n", + "0 0.847737 0.828147 \n", + "1 0.674897 0.794606 \n", + "2 0.621399 0.838866 \n", + "3 0.561317 0.765560 \n", + "4 0.675720 0.797026 \n", + ".. ... ... \n", + "223 0.920165 0.697095 \n", + "224 0.832922 0.679461 \n", + "225 0.938272 0.700899 \n", + "226 0.813992 0.651107 \n", + "227 0.762140 0.660097 \n", + "\n", + "[228 rows x 8 columns]" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train_data" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "baf45a3d-dc01-44fc-9f0b-456964ac2cdb", + "metadata": {}, + "outputs": [], + "source": [ + "# feature_cols = [x for x in train_data.columns if x not in out_cols and '第二次' not in x]\n", + "feature_cols = [x for x in train_data.columns if x not in out_cols]\n", + "use_cols = feature_cols + out_cols" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "f2d27538-d2bc-4202-b0cf-d3e0949b4686", + "metadata": {}, + "outputs": [], + "source": [ + "use_data = train_data.copy()\n", + "for col in use_cols:\n", + " use_data[col] = use_data[col].astype('float32')" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "50daf170-efec-49e5-8f8e-9a45938cacfc", + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.model_selection import KFold, train_test_split\n", + "kf = KFold(n_splits=6, shuffle=True, random_state=42)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "0f863423-be12-478b-a08d-e3c6f5dfb8ee", + "metadata": {}, + "outputs": [], + "source": [ + "from tensorflow.keras import optimizers\n", + "from tensorflow.python.keras.utils.vis_utils import plot_model\n", + "from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score, mean_absolute_percentage_error" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "2c89b32a-017c-4d05-ab78-8b9b8eb0dcbb", + "metadata": {}, + "outputs": [], + "source": [ + "from keras.callbacks import ReduceLROnPlateau\n", + "reduce_lr = ReduceLROnPlateau(monitor='val_loss', patience=10, mode='auto')" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "ca6ce434-80b6-4609-9596-9a5120680462", + "metadata": {}, + "outputs": [], + "source": [ + "def print_eva(y_true, y_pred, tp):\n", + " MSE = mean_squared_error(y_true, y_pred)\n", + " RMSE = np.sqrt(MSE)\n", + " MAE = mean_absolute_error(y_true, y_pred)\n", + " MAPE = mean_absolute_percentage_error(y_true, y_pred)\n", + " R_2 = r2_score(y_true, y_pred)\n", + " print(f\"COL: {tp}, MSE: {format(MSE, '.2E')}\", end=',')\n", + " print(f'RMSE: {round(RMSE, 3)}', end=',')\n", + " print(f'MAPE: {round(MAPE * 100, 3)} %', end=',')\n", + " print(f'MAE: {round(MAE, 3)}', end=',')\n", + " print(f'R_2: {round(R_2, 3)}')\n", + " return [MSE, RMSE, MAE, MAPE, R_2]" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "503bbec7-2020-44c8-b622-05bb41082e43", + "metadata": {}, + "outputs": [], + "source": [ + "from keras.losses import mean_squared_error" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "6308b1dc-8e2e-4bf9-9b28-3b81979bf7e0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "COL: 挥发分Vad, MSE: 3.26E-01,RMSE: 0.571,MAPE: 1.605 %,MAE: 0.478,R_2: 0.93\n", + "COL: 挥发分Vad, MSE: 3.27E-01,RMSE: 0.572,MAPE: 1.669 %,MAE: 0.475,R_2: 0.96\n", + "COL: 挥发分Vad, MSE: 3.65E-01,RMSE: 0.604,MAPE: 1.575 %,MAE: 0.464,R_2: 0.907\n", + "WARNING:tensorflow:5 out of the last 9 calls to .predict_function at 0x7f3ded91edc0> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n", + "COL: 挥发分Vad, MSE: 3.82E-01,RMSE: 0.618,MAPE: 1.707 %,MAE: 0.497,R_2: 0.933\n", + "WARNING:tensorflow:6 out of the last 11 calls to .predict_function at 0x7f3ded94b310> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n", + "COL: 挥发分Vad, MSE: 4.48E-01,RMSE: 0.669,MAPE: 1.801 %,MAE: 0.548,R_2: 0.898\n", + "COL: 挥发分Vad, MSE: 5.19E-01,RMSE: 0.721,MAPE: 1.992 %,MAE: 0.582,R_2: 0.893\n" + ] + } + ], + "source": [ + "vad_eva_list = list()\n", + "fcad_eva_list = list()\n", + "train_data = use_data[use_cols].copy()\n", + "for (train_index, test_index) in kf.split(train_data):\n", + " train = train_data.loc[train_index]\n", + " valid = train_data.loc[test_index]\n", + " X = np.expand_dims(train[feature_cols].values, axis=1)\n", + " Y = [x for x in train[out_cols].values.T]\n", + " X_valid = np.expand_dims(valid[feature_cols].values, axis=1)\n", + " Y_valid = [x for x in valid[out_cols].values.T]\n", + " prediction_model = get_prediction_model()\n", + " prediction_model.compile(optimizer='adam', loss=mean_squared_error)\n", + " hist = prediction_model.fit(X, Y[0], epochs=120, batch_size=8, verbose=0, \n", + " validation_data=(X_valid, Y_valid[0]),\n", + " callbacks=[reduce_lr]\n", + " )\n", + " rst = prediction_model.predict(X_valid)\n", + " pred_rst = pd.DataFrame.from_records(np.asarray(rst), columns=out_cols)\n", + " real_rst = valid[out_cols].copy()\n", + " for col in out_cols:\n", + " pred_rst[col] = pred_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " real_rst[col] = real_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " y_pred_vad = pred_rst[out_cols].values.reshape(-1,)\n", + " # y_pred_fcad = pred_rst['固定炭Fcad(%)'].values.reshape(-1,)\n", + " y_true_vad = real_rst[out_cols].values.reshape(-1,)\n", + " # y_true_fcad = real_rst['固定炭Fcad(%)'].values.reshape(-1,)\n", + " vad_eva = print_eva(y_true_vad, y_pred_vad, tp='挥发分Vad')\n", + " # fcad_eva = print_eva(y_true_fcad, y_pred_fcad, tp='固定炭Fcad')\n", + " vad_eva_list.append(vad_eva)\n", + " # fcad_eva_list.append(fcad_eva)\n", + " del prediction_model" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "f7132465-89e9-4193-829b-c6e7606cd266", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "COL: 固定炭Fcad, MSE: 2.10E-01,RMSE: 0.458,MAPE: 0.687 %,MAE: 0.361,R_2: 0.992\n", + "COL: 固定炭Fcad, MSE: 3.45E-01,RMSE: 0.587,MAPE: 0.865 %,MAE: 0.404,R_2: 0.993\n", + "COL: 固定炭Fcad, MSE: 3.77E-01,RMSE: 0.614,MAPE: 0.837 %,MAE: 0.465,R_2: 0.973\n", + "COL: 固定炭Fcad, MSE: 2.15E-01,RMSE: 0.463,MAPE: 0.693 %,MAE: 0.35,R_2: 0.994\n", + "COL: 固定炭Fcad, MSE: 2.75E-01,RMSE: 0.525,MAPE: 0.746 %,MAE: 0.41,R_2: 0.987\n", + "COL: 固定炭Fcad, MSE: 4.84E-01,RMSE: 0.696,MAPE: 0.968 %,MAE: 0.483,R_2: 0.979\n" + ] + } + ], + "source": [ + "out_cols = ['固定炭Fcad(%)']\n", + "fcad_eva_list = list()\n", + "train_data = use_data[use_cols].copy()\n", + "for (train_index, test_index) in kf.split(train_data):\n", + " train = train_data.loc[train_index]\n", + " valid = train_data.loc[test_index]\n", + " X = np.expand_dims(train[feature_cols].values, axis=1)\n", + " Y = [x for x in train[out_cols].values.T]\n", + " X_valid = np.expand_dims(valid[feature_cols].values, axis=1)\n", + " Y_valid = [x for x in valid[out_cols].values.T]\n", + " prediction_model = get_prediction_model()\n", + " prediction_model.compile(optimizer='adam', loss=mean_squared_error)\n", + " hist = prediction_model.fit(X, Y[0], epochs=120, batch_size=8, verbose=0, \n", + " validation_data=(X_valid, Y_valid[0]),\n", + " callbacks=[reduce_lr]\n", + " )\n", + " rst = prediction_model.predict(X_valid)\n", + " pred_rst = pd.DataFrame.from_records(np.asarray(rst), columns=out_cols)\n", + " real_rst = valid[out_cols].copy()\n", + " for col in out_cols:\n", + " pred_rst[col] = pred_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " real_rst[col] = real_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " y_pred = pred_rst[out_cols].values.reshape(-1,)\n", + " y_true = real_rst[out_cols].values.reshape(-1,)\n", + " fcad_eva = print_eva(y_true, y_pred, tp='固定炭Fcad')\n", + " fcad_eva_list.append(fcad_eva)\n", + " del prediction_model" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "27e0abf7-aa29-467f-bc5e-b66a1adf6165", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "MSE 0.394351\n", + "RMSE 0.625663\n", + "MAE 0.507130\n", + "MAPE 0.017249\n", + "R_2 0.920159\n", + "dtype: float64" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vad_df = pd.DataFrame.from_records(vad_eva_list, columns=['MSE', 'RMSE', 'MAE', 'MAPE', 'R_2'])\n", + "vad_df.sort_values(by='R_2').mean()" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "id": "070cdb94-6e7b-4028-b6d5-ba8570c902ba", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "MSE 0.317628\n", + "RMSE 0.557178\n", + "MAE 0.412263\n", + "MAPE 0.007993\n", + "R_2 0.986373\n", + "dtype: float64" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fcad_df = pd.DataFrame.from_records(fcad_eva_list, columns=['MSE', 'RMSE', 'MAE', 'MAPE', 'R_2'])\n", + "fcad_df.sort_values(by='R_2').mean()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "54c1df2c-c297-4b8d-be8a-3a99cff22545", + "metadata": {}, + "outputs": [], + "source": [ + "train, valid = train_test_split(use_data[use_cols], test_size=0.3, random_state=42, shuffle=True)\n", + "valid, test = train_test_split(valid, test_size=0.3, random_state=42, shuffle=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "e7a914da-b9c2-40d9-96e0-459b0888adba", + "metadata": {}, + "outputs": [], + "source": [ + "prediction_model = get_prediction_model()\n", + "trainable_model = get_trainable_model(prediction_model)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "2494ef5a-5b2b-4f11-b6cd-dc39503c9106", + "metadata": {}, + "outputs": [], + "source": [ + "X = np.expand_dims(train[feature_cols].values, axis=1)\n", + "Y = [x for x in train[out_cols].values.T]\n", + "Y_valid = [x for x in valid[out_cols].values.T]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cf869e4d-0fce-45a2-afff-46fd9b30fd1c", + "metadata": {}, + "outputs": [], + "source": [ + "trainable_model.compile(optimizer='adam', loss=None)\n", + "hist = trainable_model.fit([X, Y[0], Y[1]], epochs=120, batch_size=8, verbose=1, \n", + " validation_data=[np.expand_dims(valid[feature_cols].values, axis=1), Y_valid[0], Y_valid[1]],\n", + " callbacks=[reduce_lr]\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "67bfbe88-5f2c-4659-b2dc-eb9f1b824d04", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[array([[0.73740077],\n", + " [0.89292204],\n", + " [0.7599046 ],\n", + " [0.67802393],\n", + " [0.6815233 ],\n", + " [0.88627005],\n", + " [0.6121343 ],\n", + " [0.7072234 ],\n", + " [0.8561135 ],\n", + " [0.52762157],\n", + " [0.8325021 ],\n", + " [0.50241977],\n", + " [0.8242289 ],\n", + " [0.68957335],\n", + " [0.6980361 ],\n", + " [0.82116604],\n", + " [0.8566438 ],\n", + " [0.53687835],\n", + " [0.56832707],\n", + " [0.78476715],\n", + " [0.85638577]], dtype=float32),\n", + " array([[0.68600863],\n", + " [0.78454906],\n", + " [0.8179163 ],\n", + " [0.94351083],\n", + " [0.86383885],\n", + " [0.69705516],\n", + " [0.6913491 ],\n", + " [0.80277354],\n", + " [0.93557894],\n", + " [0.82278305],\n", + " [0.82674253],\n", + " [0.93518937],\n", + " [0.8094449 ],\n", + " [0.9206344 ],\n", + " [0.7747319 ],\n", + " [0.9137207 ],\n", + " [0.9491073 ],\n", + " [0.93225 ],\n", + " [0.6185102 ],\n", + " [0.8867341 ],\n", + " [0.82890105]], dtype=float32)]" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rst = prediction_model.predict(np.expand_dims(test[feature_cols], axis=1))\n", + "rst" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "7de501e9-05a2-424c-a5f4-85d43ad37592", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[0.9991559102070927, 0.9998196796918477]" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[np.exp(K.get_value(log_var[0]))**0.5 for log_var in trainable_model.layers[-1].log_vars]" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "5c69d03b-34fd-4dbf-aec6-c15093bb22ab", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['挥发分Vad(%)', '固定炭Fcad(%)'], dtype='object')" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "real_rst.columns" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "294813b8-90be-4007-9fd6-c26ee7bb9652", + "metadata": {}, + "outputs": [], + "source": [ + "for col in out_cols:\n", + " pred_rst[col] = pred_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " real_rst[col] = real_rst[col] * (maxs[col] - mins[col]) + mins[col]" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "21739f82-d82a-4bde-8537-9504b68a96d5", + "metadata": {}, + "outputs": [], + "source": [ + "y_pred_vad = pred_rst['挥发分Vad(%)'].values.reshape(-1,)\n", + "y_pred_fcad = pred_rst['固定炭Fcad(%)'].values.reshape(-1,)\n", + "y_true_vad = real_rst['挥发分Vad(%)'].values.reshape(-1,)\n", + "y_true_fcad = real_rst['固定炭Fcad(%)'].values.reshape(-1,)" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "id": "4ec4caa9-7c46-4fc8-a94b-cb659e924304", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "COL: 挥发分Vad, MSE: 3.35E-01,RMSE: 0.579,MAPE: 1.639 %,MAE: 0.504,R_2: 0.87\n", + "COL: 固定炭Fcad, MSE: 1.11E+00,RMSE: 1.055,MAPE: 1.497 %,MAE: 0.814,R_2: 0.876\n" + ] + } + ], + "source": [ + "pm25_eva = print_eva(y_true_vad, y_pred_vad, tp='挥发分Vad')\n", + "pm10_eva = print_eva(y_true_fcad, y_pred_fcad, tp='固定炭Fcad')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ac4a4339-ec7d-4266-8197-5276c2395288", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f15cbb91-1ce7-4fb0-979a-a4bdc452a1ec", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.16" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/.ipynb_checkpoints/CBA_vad_fcad-checkpoint.ipynb b/.ipynb_checkpoints/CBA_vad_fcad-checkpoint.ipynb new file mode 100644 index 0000000..872ea5c --- /dev/null +++ b/.ipynb_checkpoints/CBA_vad_fcad-checkpoint.ipynb @@ -0,0 +1,1311 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "6b84fefd-5936-4da4-ab6b-5b944329ad1d", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "os.environ['CUDA_DEVICE_ORDER'] = 'PCB_BUS_ID'\n", + "os.environ['CUDA_VISIBLE_DEVICES'] = '0, 1'" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "9cf130e3-62ef-46e0-bbdc-b13d9d29318d", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "from sklearn.model_selection import train_test_split\n", + "import matplotlib.pyplot as plt\n", + "#新增加的两行\n", + "from pylab import mpl\n", + "# 设置显示中文字体\n", + "mpl.rcParams[\"font.sans-serif\"] = [\"SimHei\"]\n", + "\n", + "mpl.rcParams[\"axes.unicode_minus\"] = False" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "752381a5-0aeb-4c54-bc48-f9c3f8fc5d17", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Unnamed: 0_level_0弹筒发热量挥发分固定炭
化验编号HadCadNadOadQb,adVadFcad
Unnamed: 0_level_2(%)(%)(%)(%)MJ/kg(%)(%)
027201105293.9370.180.8125.07927.82032.0655.68
127200968833.7868.930.7726.51227.40429.9654.71
227201090843.4869.600.7626.14827.57829.3155.99
327200847083.4766.710.7629.05526.33828.5853.87
427200627213.8768.780.8026.54227.28029.9754.78
...........................
22327200304904.1268.850.9726.05527.86432.9451.89
22427200286333.9767.040.9428.04327.36831.8851.38
22527200286344.1268.420.9626.49327.88633.1652.00
22627200176833.8867.420.9427.76026.61631.6550.56
22727200176783.8166.740.9228.53026.68831.0250.82
\n", + "

228 rows × 8 columns

\n", + "
" + ], + "text/plain": [ + " Unnamed: 0_level_0 氢 碳 氮 氧 弹筒发热量 挥发分 固定炭\n", + " 化验编号 Had Cad Nad Oad Qb,ad Vad Fcad\n", + " Unnamed: 0_level_2 (%) (%) (%) (%) MJ/kg (%) (%)\n", + "0 2720110529 3.93 70.18 0.81 25.079 27.820 32.06 55.68\n", + "1 2720096883 3.78 68.93 0.77 26.512 27.404 29.96 54.71\n", + "2 2720109084 3.48 69.60 0.76 26.148 27.578 29.31 55.99\n", + "3 2720084708 3.47 66.71 0.76 29.055 26.338 28.58 53.87\n", + "4 2720062721 3.87 68.78 0.80 26.542 27.280 29.97 54.78\n", + ".. ... ... ... ... ... ... ... ...\n", + "223 2720030490 4.12 68.85 0.97 26.055 27.864 32.94 51.89\n", + "224 2720028633 3.97 67.04 0.94 28.043 27.368 31.88 51.38\n", + "225 2720028634 4.12 68.42 0.96 26.493 27.886 33.16 52.00\n", + "226 2720017683 3.88 67.42 0.94 27.760 26.616 31.65 50.56\n", + "227 2720017678 3.81 66.74 0.92 28.530 26.688 31.02 50.82\n", + "\n", + "[228 rows x 8 columns]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data_0102 = pd.read_excel('./data/20240102/20240102.xlsx', header=[0,1,2])\n", + "data_0102" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "972f1e9c-3ebc-45cf-8d1f-7611645e5238", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['化验编号',\n", + " '氢Had(%)',\n", + " '碳Cad(%)',\n", + " '氮Nad(%)',\n", + " '氧Oad(%)',\n", + " '弹筒发热量Qb,adMJ/kg',\n", + " '挥发分Vad(%)',\n", + " '固定炭Fcad(%)']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cols = [''.join([y for y in x if 'Unnamed' not in y]) for x in data_0102.columns]\n", + "cols" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "c95f1106-b3a4-43c6-88ec-3cdebf91d79a", + "metadata": {}, + "outputs": [], + "source": [ + "data_0102.columns = cols" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "2e96af0a-feda-4a1f-a13e-9c8861c6f4d4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
化验编号氢Had(%)碳Cad(%)氮Nad(%)氧Oad(%)弹筒发热量Qb,adMJ/kg挥发分Vad(%)固定炭Fcad(%)
027201105293.9370.180.8125.07927.82032.0655.68
127200968833.7868.930.7726.51227.40429.9654.71
227201090843.4869.600.7626.14827.57829.3155.99
327200847083.4766.710.7629.05526.33828.5853.87
427200627213.8768.780.8026.54227.28029.9754.78
...........................
22327200304904.1268.850.9726.05527.86432.9451.89
22427200286333.9767.040.9428.04327.36831.8851.38
22527200286344.1268.420.9626.49327.88633.1652.00
22627200176833.8867.420.9427.76026.61631.6550.56
22727200176783.8166.740.9228.53026.68831.0250.82
\n", + "

228 rows × 8 columns

\n", + "
" + ], + "text/plain": [ + " 化验编号 氢Had(%) 碳Cad(%) 氮Nad(%) 氧Oad(%) 弹筒发热量Qb,adMJ/kg \\\n", + "0 2720110529 3.93 70.18 0.81 25.079 27.820 \n", + "1 2720096883 3.78 68.93 0.77 26.512 27.404 \n", + "2 2720109084 3.48 69.60 0.76 26.148 27.578 \n", + "3 2720084708 3.47 66.71 0.76 29.055 26.338 \n", + "4 2720062721 3.87 68.78 0.80 26.542 27.280 \n", + ".. ... ... ... ... ... ... \n", + "223 2720030490 4.12 68.85 0.97 26.055 27.864 \n", + "224 2720028633 3.97 67.04 0.94 28.043 27.368 \n", + "225 2720028634 4.12 68.42 0.96 26.493 27.886 \n", + "226 2720017683 3.88 67.42 0.94 27.760 26.616 \n", + "227 2720017678 3.81 66.74 0.92 28.530 26.688 \n", + "\n", + " 挥发分Vad(%) 固定炭Fcad(%) \n", + "0 32.06 55.68 \n", + "1 29.96 54.71 \n", + "2 29.31 55.99 \n", + "3 28.58 53.87 \n", + "4 29.97 54.78 \n", + ".. ... ... \n", + "223 32.94 51.89 \n", + "224 31.88 51.38 \n", + "225 33.16 52.00 \n", + "226 31.65 50.56 \n", + "227 31.02 50.82 \n", + "\n", + "[228 rows x 8 columns]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data_0102" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "04b177a7-2f02-4e23-8ea9-29f34cf3eafc", + "metadata": {}, + "outputs": [], + "source": [ + "out_cols = ['挥发分Vad(%)']\n", + "# out_cols = ['固定炭Fcad(%)']" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "31169fbf-d78e-42f7-87f3-71ba3dd0979d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['挥发分Vad(%)']" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "out_cols" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "feaedd50-f999-45bf-b465-3d359b0c0110", + "metadata": {}, + "outputs": [], + "source": [ + "data = data_0102.copy()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "a40bee0f-011a-4edb-80f8-4e2f40e755fd", + "metadata": {}, + "outputs": [], + "source": [ + "train_data = data.dropna(subset=out_cols).fillna(0)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "535d37b6-b9de-4025-ac8f-62f5bdbe2451", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-01-05 17:02:16.953831: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0\n" + ] + } + ], + "source": [ + "import tensorflow as tf\n", + "from tensorflow import keras\n", + "from tensorflow.keras import layers\n", + "import tensorflow.keras.backend as K" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "1c85d462-f248-4ffb-908f-eb4b20eab179", + "metadata": {}, + "outputs": [], + "source": [ + "class TransformerBlock(layers.Layer):\n", + " def __init__(self, embed_dim, num_heads, ff_dim, name, rate=0.1):\n", + " super().__init__()\n", + " self.att = layers.MultiHeadAttention(num_heads=num_heads, key_dim=embed_dim, name=name)\n", + " self.ffn = keras.Sequential(\n", + " [layers.Dense(ff_dim, activation=\"relu\"), layers.Dense(embed_dim),]\n", + " )\n", + " self.layernorm1 = layers.LayerNormalization(epsilon=1e-6)\n", + " self.layernorm2 = layers.LayerNormalization(epsilon=1e-6)\n", + " self.dropout1 = layers.Dropout(rate)\n", + " self.dropout2 = layers.Dropout(rate)\n", + "\n", + " def call(self, inputs, training):\n", + " attn_output = self.att(inputs, inputs)\n", + " attn_output = self.dropout1(attn_output, training=training)\n", + " out1 = self.layernorm1(inputs + attn_output)\n", + " ffn_output = self.ffn(out1)\n", + " ffn_output = self.dropout2(ffn_output, training=training)\n", + " return self.layernorm2(out1 + ffn_output)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "790284a3-b9d3-4144-b481-38a7c3ecb4b9", + "metadata": {}, + "outputs": [], + "source": [ + "from tensorflow.keras import Model" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "cd9a1ca1-d0ca-4cb5-9ef5-fd5d63576cd2", + "metadata": {}, + "outputs": [], + "source": [ + "from tensorflow.keras.initializers import Constant" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "9bc02f29-0fb7-420d-99a8-435eadc06e29", + "metadata": {}, + "outputs": [], + "source": [ + "# Custom loss layer\n", + "class CustomMultiLossLayer(layers.Layer):\n", + " def __init__(self, nb_outputs=2, **kwargs):\n", + " self.nb_outputs = nb_outputs\n", + " self.is_placeholder = True\n", + " super(CustomMultiLossLayer, self).__init__(**kwargs)\n", + " \n", + " def build(self, input_shape=None):\n", + " # initialise log_vars\n", + " self.log_vars = []\n", + " for i in range(self.nb_outputs):\n", + " self.log_vars += [self.add_weight(name='log_var' + str(i), shape=(1,),\n", + " initializer=tf.initializers.he_normal(), trainable=True)]\n", + " super(CustomMultiLossLayer, self).build(input_shape)\n", + "\n", + " def multi_loss(self, ys_true, ys_pred):\n", + " assert len(ys_true) == self.nb_outputs and len(ys_pred) == self.nb_outputs\n", + " loss = 0\n", + " for y_true, y_pred, log_var in zip(ys_true, ys_pred, self.log_vars):\n", + " mse = (y_true - y_pred) ** 2.\n", + " pre = K.exp(-log_var[0])\n", + " loss += tf.abs(tf.reduce_logsumexp(pre * mse + log_var[0], axis=-1))\n", + " return K.mean(loss)\n", + "\n", + " def call(self, inputs):\n", + " ys_true = inputs[:self.nb_outputs]\n", + " ys_pred = inputs[self.nb_outputs:]\n", + " loss = self.multi_loss(ys_true, ys_pred)\n", + " self.add_loss(loss, inputs=inputs)\n", + " # We won't actually use the output.\n", + " return K.concatenate(inputs, -1)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "a190207e-5a59-4813-9660-758760cf1b73", + "metadata": {}, + "outputs": [], + "source": [ + "num_heads, ff_dim = 3, 16" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "80f32155-e71f-4615-8d0c-01dfd04988fe", + "metadata": {}, + "outputs": [], + "source": [ + "def get_prediction_model():\n", + " inputs = layers.Input(shape=(1,len(feature_cols)), name='input')\n", + " x = layers.Conv1D(filters=64, kernel_size=1, activation='relu')(inputs)\n", + " # x = layers.Dropout(rate=0.1)(x)\n", + " lstm_out = layers.Bidirectional(layers.LSTM(units=64, return_sequences=True))(x)\n", + " lstm_out = layers.Dense(128, activation='relu')(lstm_out)\n", + " # transformer_block = TransformerBlock(128, num_heads, ff_dim, name='first_attn')\n", + " # out = transformer_block(lstm_out)\n", + " # out = layers.GlobalAveragePooling1D()(out)\n", + " out = layers.Dropout(0.1)(lstm_out)\n", + " out = layers.Dense(64, activation='relu')(out)\n", + " bet = layers.Dense(1, activation='sigmoid', name='vad')(out)\n", + " model = Model(inputs=inputs, outputs=bet)\n", + " return model" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "372011ea-9876-41eb-a4e6-83ccd6c71559", + "metadata": {}, + "outputs": [], + "source": [ + "from tensorflow.python.keras.utils.vis_utils import plot_model" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "1eebdab3-1f88-48a1-b5e0-bc8787528c1b", + "metadata": {}, + "outputs": [], + "source": [ + "maxs = train_data.max()\n", + "mins = train_data.min()\n", + "for col in train_data.columns:\n", + " if maxs[col] - mins[col] == 0:\n", + " continue\n", + " train_data[col] = (train_data[col] - mins[col]) / (maxs[col] - mins[col])" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "7f27bd56-4f6b-4242-9f79-c7d6b3ee2f13", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
化验编号氢Had(%)碳Cad(%)氮Nad(%)氧Oad(%)弹筒发热量Qb,adMJ/kg挥发分Vad(%)固定炭Fcad(%)
00.9965470.7739730.8354140.4565220.1714630.8112490.8477370.828147
10.8511180.6712330.7999430.3695650.2102540.7820380.6748970.794606
\n", + "
" + ], + "text/plain": [ + " 化验编号 氢Had(%) 碳Cad(%) 氮Nad(%) 氧Oad(%) 弹筒发热量Qb,adMJ/kg \\\n", + "0 0.996547 0.773973 0.835414 0.456522 0.171463 0.811249 \n", + "1 0.851118 0.671233 0.799943 0.369565 0.210254 0.782038 \n", + "\n", + " 挥发分Vad(%) 固定炭Fcad(%) \n", + "0 0.847737 0.828147 \n", + "1 0.674897 0.794606 " + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train_data.head(2)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "baf45a3d-dc01-44fc-9f0b-456964ac2cdb", + "metadata": {}, + "outputs": [], + "source": [ + "# feature_cols = [x for x in train_data.columns if x not in out_cols and '第二次' not in x]\n", + "feature_cols = [x for x in train_data.columns if x not in out_cols]\n", + "use_cols = feature_cols + out_cols" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "f2d27538-d2bc-4202-b0cf-d3e0949b4686", + "metadata": {}, + "outputs": [], + "source": [ + "use_data = train_data.copy()\n", + "for col in use_cols:\n", + " use_data[col] = use_data[col].astype('float32')" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "50daf170-efec-49e5-8f8e-9a45938cacfc", + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.model_selection import KFold, train_test_split\n", + "kf = KFold(n_splits=6, shuffle=True, random_state=42)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "0f863423-be12-478b-a08d-e3c6f5dfb8ee", + "metadata": {}, + "outputs": [], + "source": [ + "from tensorflow.keras import optimizers\n", + "from tensorflow.python.keras.utils.vis_utils import plot_model\n", + "from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score, mean_absolute_percentage_error" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "2c89b32a-017c-4d05-ab78-8b9b8eb0dcbb", + "metadata": {}, + "outputs": [], + "source": [ + "from keras.callbacks import ReduceLROnPlateau\n", + "reduce_lr = ReduceLROnPlateau(monitor='val_loss', patience=10, mode='auto')" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "ae24eea7-7dc1-4e33-9d41-3baff07ebb88", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model: \"model_2\"\n", + "_________________________________________________________________\n", + "Layer (type) Output Shape Param # \n", + "=================================================================\n", + "input (InputLayer) [(None, 1, 7)] 0 \n", + "_________________________________________________________________\n", + "conv1d_3 (Conv1D) (None, 1, 64) 512 \n", + "_________________________________________________________________\n", + "bidirectional_3 (Bidirection (None, 1, 128) 66048 \n", + "_________________________________________________________________\n", + "dense_5 (Dense) (None, 1, 128) 16512 \n", + "_________________________________________________________________\n", + "dropout_3 (Dropout) (None, 1, 128) 0 \n", + "_________________________________________________________________\n", + "dense_6 (Dense) (None, 1, 64) 8256 \n", + "_________________________________________________________________\n", + "vad (Dense) (None, 1, 1) 65 \n", + "=================================================================\n", + "Total params: 91,393\n", + "Trainable params: 91,393\n", + "Non-trainable params: 0\n", + "_________________________________________________________________\n" + ] + } + ], + "source": [ + "model = get_prediction_model()\n", + "model.summary()" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "ca6ce434-80b6-4609-9596-9a5120680462", + "metadata": {}, + "outputs": [], + "source": [ + "def print_eva(y_true, y_pred, tp):\n", + " MSE = mean_squared_error(y_true, y_pred)\n", + " RMSE = np.sqrt(MSE)\n", + " MAE = mean_absolute_error(y_true, y_pred)\n", + " MAPE = mean_absolute_percentage_error(y_true, y_pred)\n", + " R_2 = r2_score(y_true, y_pred)\n", + " print(f\"COL: {tp}, MSE: {format(MSE, '.2E')}\", end=',')\n", + " print(f'RMSE: {round(RMSE, 3)}', end=',')\n", + " print(f'MAPE: {round(MAPE * 100, 3)} %', end=',')\n", + " print(f'MAE: {round(MAE, 3)}', end=',')\n", + " print(f'R_2: {round(R_2, 3)}')\n", + " return [MSE, RMSE, MAE, MAPE, R_2]" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "503bbec7-2020-44c8-b622-05bb41082e43", + "metadata": {}, + "outputs": [], + "source": [ + "from keras.losses import mean_squared_error" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6308b1dc-8e2e-4bf9-9b28-3b81979bf7e0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "COL: 挥发分Vad, MSE: 2.49E-01,RMSE: 0.499,MAPE: 1.336 %,MAE: 0.398,R_2: 0.946\n", + "COL: 挥发分Vad, MSE: 3.81E-01,RMSE: 0.617,MAPE: 1.597 %,MAE: 0.455,R_2: 0.954\n", + "COL: 挥发分Vad, MSE: 5.71E-01,RMSE: 0.756,MAPE: 2.077 %,MAE: 0.621,R_2: 0.854\n" + ] + } + ], + "source": [ + "vad_eva_list = list()\n", + "fcad_eva_list = list()\n", + "train_data = use_data[use_cols].copy()\n", + "for (train_index, test_index) in kf.split(train_data):\n", + " train = train_data.loc[train_index]\n", + " valid = train_data.loc[test_index]\n", + " X = np.expand_dims(train[feature_cols].values, axis=1)\n", + " Y = [x for x in train[out_cols].values.T]\n", + " X_valid = np.expand_dims(valid[feature_cols].values, axis=1)\n", + " Y_valid = [x for x in valid[out_cols].values.T]\n", + " prediction_model = get_prediction_model()\n", + " prediction_model.compile(optimizer='adam', loss=mean_squared_error)\n", + " hist = prediction_model.fit(X, Y[0], epochs=120, batch_size=8, verbose=0, \n", + " validation_data=(X_valid, Y_valid[0]),\n", + " callbacks=[reduce_lr]\n", + " )\n", + " rst = prediction_model.predict(X_valid).squeeze(axis=1)\n", + " pred_rst = pd.DataFrame.from_records(np.asarray(rst), columns=out_cols)\n", + " real_rst = valid[out_cols].copy()\n", + " for col in out_cols:\n", + " pred_rst[col] = pred_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " real_rst[col] = real_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " y_pred_vad = pred_rst[out_cols].values.reshape(-1,)\n", + " # y_pred_fcad = pred_rst['固定炭Fcad(%)'].values.reshape(-1,)\n", + " y_true_vad = real_rst[out_cols].values.reshape(-1,)\n", + " # y_true_fcad = real_rst['固定炭Fcad(%)'].values.reshape(-1,)\n", + " vad_eva = print_eva(y_true_vad, y_pred_vad, tp='挥发分Vad')\n", + " # fcad_eva = print_eva(y_true_fcad, y_pred_fcad, tp='固定炭Fcad')\n", + " vad_eva_list.append(vad_eva)\n", + " # fcad_eva_list.append(fcad_eva)\n", + " del prediction_model" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "f7132465-89e9-4193-829b-c6e7606cd266", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "COL: 固定炭Fcad, MSE: 2.10E-01,RMSE: 0.458,MAPE: 0.687 %,MAE: 0.361,R_2: 0.992\n", + "COL: 固定炭Fcad, MSE: 3.45E-01,RMSE: 0.587,MAPE: 0.865 %,MAE: 0.404,R_2: 0.993\n", + "COL: 固定炭Fcad, MSE: 3.77E-01,RMSE: 0.614,MAPE: 0.837 %,MAE: 0.465,R_2: 0.973\n", + "COL: 固定炭Fcad, MSE: 2.15E-01,RMSE: 0.463,MAPE: 0.693 %,MAE: 0.35,R_2: 0.994\n", + "COL: 固定炭Fcad, MSE: 2.75E-01,RMSE: 0.525,MAPE: 0.746 %,MAE: 0.41,R_2: 0.987\n", + "COL: 固定炭Fcad, MSE: 4.84E-01,RMSE: 0.696,MAPE: 0.968 %,MAE: 0.483,R_2: 0.979\n" + ] + } + ], + "source": [ + "out_cols = ['固定炭Fcad(%)']\n", + "fcad_eva_list = list()\n", + "train_data = use_data[use_cols].copy()\n", + "for (train_index, test_index) in kf.split(train_data):\n", + " train = train_data.loc[train_index]\n", + " valid = train_data.loc[test_index]\n", + " X = np.expand_dims(train[feature_cols].values, axis=1)\n", + " Y = [x for x in train[out_cols].values.T]\n", + " X_valid = np.expand_dims(valid[feature_cols].values, axis=1)\n", + " Y_valid = [x for x in valid[out_cols].values.T]\n", + " prediction_model = get_prediction_model()\n", + " prediction_model.compile(optimizer='adam', loss=mean_squared_error)\n", + " hist = prediction_model.fit(X, Y[0], epochs=120, batch_size=8, verbose=0, \n", + " validation_data=(X_valid, Y_valid[0]),\n", + " callbacks=[reduce_lr]\n", + " )\n", + " rst = prediction_model.predict(X_valid).squeeze(axis=1)\n", + " pred_rst = pd.DataFrame.from_records(np.asarray(rst), columns=out_cols)\n", + " real_rst = valid[out_cols].copy()\n", + " for col in out_cols:\n", + " pred_rst[col] = pred_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " real_rst[col] = real_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " y_pred = pred_rst[out_cols].values.reshape(-1,)\n", + " y_true = real_rst[out_cols].values.reshape(-1,)\n", + " fcad_eva = print_eva(y_true, y_pred, tp='固定炭Fcad')\n", + " fcad_eva_list.append(fcad_eva)\n", + " del prediction_model" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "27e0abf7-aa29-467f-bc5e-b66a1adf6165", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "MSE 0.394351\n", + "RMSE 0.625663\n", + "MAE 0.507130\n", + "MAPE 0.017249\n", + "R_2 0.920159\n", + "dtype: float64" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vad_df = pd.DataFrame.from_records(vad_eva_list, columns=['MSE', 'RMSE', 'MAE', 'MAPE', 'R_2'])\n", + "vad_df.sort_values(by='R_2').mean()" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "id": "070cdb94-6e7b-4028-b6d5-ba8570c902ba", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "MSE 0.317628\n", + "RMSE 0.557178\n", + "MAE 0.412263\n", + "MAPE 0.007993\n", + "R_2 0.986373\n", + "dtype: float64" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fcad_df = pd.DataFrame.from_records(fcad_eva_list, columns=['MSE', 'RMSE', 'MAE', 'MAPE', 'R_2'])\n", + "fcad_df.sort_values(by='R_2').mean()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "54c1df2c-c297-4b8d-be8a-3a99cff22545", + "metadata": {}, + "outputs": [], + "source": [ + "train, valid = train_test_split(use_data[use_cols], test_size=0.3, random_state=42, shuffle=True)\n", + "valid, test = train_test_split(valid, test_size=0.3, random_state=42, shuffle=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "e7a914da-b9c2-40d9-96e0-459b0888adba", + "metadata": {}, + "outputs": [], + "source": [ + "prediction_model = get_prediction_model()\n", + "trainable_model = get_trainable_model(prediction_model)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "2494ef5a-5b2b-4f11-b6cd-dc39503c9106", + "metadata": {}, + "outputs": [], + "source": [ + "X = np.expand_dims(train[feature_cols].values, axis=1)\n", + "Y = [x for x in train[out_cols].values.T]\n", + "Y_valid = [x for x in valid[out_cols].values.T]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cf869e4d-0fce-45a2-afff-46fd9b30fd1c", + "metadata": {}, + "outputs": [], + "source": [ + "trainable_model.compile(optimizer='adam', loss=None)\n", + "hist = trainable_model.fit([X, Y[0], Y[1]], epochs=120, batch_size=8, verbose=1, \n", + " validation_data=[np.expand_dims(valid[feature_cols].values, axis=1), Y_valid[0], Y_valid[1]],\n", + " callbacks=[reduce_lr]\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "67bfbe88-5f2c-4659-b2dc-eb9f1b824d04", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[array([[0.73740077],\n", + " [0.89292204],\n", + " [0.7599046 ],\n", + " [0.67802393],\n", + " [0.6815233 ],\n", + " [0.88627005],\n", + " [0.6121343 ],\n", + " [0.7072234 ],\n", + " [0.8561135 ],\n", + " [0.52762157],\n", + " [0.8325021 ],\n", + " [0.50241977],\n", + " [0.8242289 ],\n", + " [0.68957335],\n", + " [0.6980361 ],\n", + " [0.82116604],\n", + " [0.8566438 ],\n", + " [0.53687835],\n", + " [0.56832707],\n", + " [0.78476715],\n", + " [0.85638577]], dtype=float32),\n", + " array([[0.68600863],\n", + " [0.78454906],\n", + " [0.8179163 ],\n", + " [0.94351083],\n", + " [0.86383885],\n", + " [0.69705516],\n", + " [0.6913491 ],\n", + " [0.80277354],\n", + " [0.93557894],\n", + " [0.82278305],\n", + " [0.82674253],\n", + " [0.93518937],\n", + " [0.8094449 ],\n", + " [0.9206344 ],\n", + " [0.7747319 ],\n", + " [0.9137207 ],\n", + " [0.9491073 ],\n", + " [0.93225 ],\n", + " [0.6185102 ],\n", + " [0.8867341 ],\n", + " [0.82890105]], dtype=float32)]" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rst = prediction_model.predict(np.expand_dims(test[feature_cols], axis=1))\n", + "rst" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "7de501e9-05a2-424c-a5f4-85d43ad37592", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[0.9991559102070927, 0.9998196796918477]" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[np.exp(K.get_value(log_var[0]))**0.5 for log_var in trainable_model.layers[-1].log_vars]" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "5c69d03b-34fd-4dbf-aec6-c15093bb22ab", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['挥发分Vad(%)', '固定炭Fcad(%)'], dtype='object')" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "real_rst.columns" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "294813b8-90be-4007-9fd6-c26ee7bb9652", + "metadata": {}, + "outputs": [], + "source": [ + "for col in out_cols:\n", + " pred_rst[col] = pred_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " real_rst[col] = real_rst[col] * (maxs[col] - mins[col]) + mins[col]" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "21739f82-d82a-4bde-8537-9504b68a96d5", + "metadata": {}, + "outputs": [], + "source": [ + "y_pred_vad = pred_rst['挥发分Vad(%)'].values.reshape(-1,)\n", + "y_pred_fcad = pred_rst['固定炭Fcad(%)'].values.reshape(-1,)\n", + "y_true_vad = real_rst['挥发分Vad(%)'].values.reshape(-1,)\n", + "y_true_fcad = real_rst['固定炭Fcad(%)'].values.reshape(-1,)" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "id": "4ec4caa9-7c46-4fc8-a94b-cb659e924304", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "COL: 挥发分Vad, MSE: 3.35E-01,RMSE: 0.579,MAPE: 1.639 %,MAE: 0.504,R_2: 0.87\n", + "COL: 固定炭Fcad, MSE: 1.11E+00,RMSE: 1.055,MAPE: 1.497 %,MAE: 0.814,R_2: 0.876\n" + ] + } + ], + "source": [ + "pm25_eva = print_eva(y_true_vad, y_pred_vad, tp='挥发分Vad')\n", + "pm10_eva = print_eva(y_true_fcad, y_pred_fcad, tp='固定炭Fcad')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ac4a4339-ec7d-4266-8197-5276c2395288", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f15cbb91-1ce7-4fb0-979a-a4bdc452a1ec", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.16" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/.ipynb_checkpoints/multi-task0102-checkpoint.ipynb b/.ipynb_checkpoints/multi-task0102-checkpoint.ipynb index 3ca3e56..e04979d 100644 --- a/.ipynb_checkpoints/multi-task0102-checkpoint.ipynb +++ b/.ipynb_checkpoints/multi-task0102-checkpoint.ipynb @@ -549,7 +549,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2024-01-04 16:49:03.492957: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0\n" + "2024-01-05 16:46:07.061819: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0\n" ] } ], @@ -563,51 +563,6 @@ { "cell_type": "code", "execution_count": 12, - "id": "c2318ce6-60d2-495c-91cd-67ca53609cf8", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING:tensorflow:From /tmp/ipykernel_45930/337460670.py:1: is_gpu_available (from tensorflow.python.framework.test_util) is deprecated and will be removed in a future version.\n", - "Instructions for updating:\n", - "Use `tf.config.list_physical_devices('GPU')` instead.\n" - ] - }, - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2024-01-04 16:49:04.396035: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 AVX512F FMA\n", - "To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", - "2024-01-04 16:49:04.407586: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcuda.so.1\n", - "2024-01-04 16:49:04.465739: E tensorflow/stream_executor/cuda/cuda_driver.cc:328] failed call to cuInit: CUDA_ERROR_INVALID_DEVICE: invalid device ordinal\n", - "2024-01-04 16:49:04.465795: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:169] retrieving CUDA diagnostic information for host: zhaojh-yv621\n", - "2024-01-04 16:49:04.465807: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:176] hostname: zhaojh-yv621\n", - "2024-01-04 16:49:04.466010: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:200] libcuda reported version is: 520.61.5\n", - "2024-01-04 16:49:04.466041: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:204] kernel reported version is: 520.61.5\n", - "2024-01-04 16:49:04.466045: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:310] kernel version seems to match DSO: 520.61.5\n" - ] - } - ], - "source": [ - "tf.test.is_gpu_available()" - ] - }, - { - "cell_type": "code", - "execution_count": 13, "id": "1c85d462-f248-4ffb-908f-eb4b20eab179", "metadata": {}, "outputs": [], @@ -635,7 +590,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 13, "id": "790284a3-b9d3-4144-b481-38a7c3ecb4b9", "metadata": {}, "outputs": [], @@ -645,7 +600,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 14, "id": "cd9a1ca1-d0ca-4cb5-9ef5-fd5d63576cd2", "metadata": {}, "outputs": [], @@ -655,7 +610,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 15, "id": "9bc02f29-0fb7-420d-99a8-435eadc06e29", "metadata": {}, "outputs": [], @@ -695,7 +650,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 16, "id": "a190207e-5a59-4813-9660-758760cf1b73", "metadata": {}, "outputs": [], @@ -705,20 +660,12 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 17, "id": "80f32155-e71f-4615-8d0c-01dfd04988fe", "metadata": {}, "outputs": [], "source": [ "def get_prediction_model():\n", - " def build_output(out, out_name):\n", - " self_block = TransformerBlock(64, num_heads, ff_dim, name=f'{out_name}_attn')\n", - " out = self_block(out)\n", - " out = layers.GlobalAveragePooling1D()(out)\n", - " out = layers.Dropout(0.1)(out)\n", - " out = layers.Dense(32, activation=\"relu\")(out)\n", - " # out = layers.Dense(1, name=out_name, activation=\"sigmoid\")(out)\n", - " return out\n", " inputs = layers.Input(shape=(1,len(feature_cols)), name='input')\n", " x = layers.Conv1D(filters=64, kernel_size=1, activation='relu')(inputs)\n", " # x = layers.Dropout(rate=0.1)(x)\n", @@ -729,10 +676,10 @@ " out = layers.GlobalAveragePooling1D()(out)\n", " out = layers.Dropout(0.1)(out)\n", " out = layers.Dense(64, activation='relu')(out)\n", - " out = K.expand_dims(out, axis=1)\n", + " # out = K.expand_dims(out, axis=1)\n", "\n", - " bet = build_output(out, 'vad')\n", - " mesco = build_output(out, 'fcad')\n", + " bet = layers.Dense(32, activation=\"relu\")(out)\n", + " mesco = layers.Dense(32, activation=\"relu\")(out)\n", "\n", " bet = layers.Dense(1, activation='sigmoid', name='vad')(bet)\n", " mesco = layers.Dense(1, activation='sigmoid', name='fcad')(mesco)\n", @@ -743,7 +690,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 18, "id": "264001b1-5e4a-4786-96fd-2b5c70ab3212", "metadata": {}, "outputs": [], @@ -757,6 +704,16 @@ " return Model([inputs, bet_real, mesco_real], out)" ] }, + { + "cell_type": "code", + "execution_count": 19, + "id": "372011ea-9876-41eb-a4e6-83ccd6c71559", + "metadata": {}, + "outputs": [], + "source": [ + "from tensorflow.python.keras.utils.vis_utils import plot_model" + ] + }, { "cell_type": "code", "execution_count": 20, @@ -1002,6 +959,241 @@ { "cell_type": "code", "execution_count": 24, + "id": "50daf170-efec-49e5-8f8e-9a45938cacfc", + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.model_selection import KFold, train_test_split\n", + "kf = KFold(n_splits=6, shuffle=True, random_state=42)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "0f863423-be12-478b-a08d-e3c6f5dfb8ee", + "metadata": {}, + "outputs": [], + "source": [ + "from tensorflow.keras import optimizers\n", + "from tensorflow.python.keras.utils.vis_utils import plot_model\n", + "from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score, mean_absolute_percentage_error" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "2c89b32a-017c-4d05-ab78-8b9b8eb0dcbb", + "metadata": {}, + "outputs": [], + "source": [ + "from keras.callbacks import ReduceLROnPlateau\n", + "reduce_lr = ReduceLROnPlateau(monitor='val_loss', patience=10, mode='auto')" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "ca6ce434-80b6-4609-9596-9a5120680462", + "metadata": {}, + "outputs": [], + "source": [ + "def print_eva(y_true, y_pred, tp):\n", + " MSE = mean_squared_error(y_true, y_pred)\n", + " RMSE = np.sqrt(MSE)\n", + " MAE = mean_absolute_error(y_true, y_pred)\n", + " MAPE = mean_absolute_percentage_error(y_true, y_pred)\n", + " R_2 = r2_score(y_true, y_pred)\n", + " print(f\"COL: {tp}, MSE: {format(MSE, '.2E')}\", end=',')\n", + " print(f'RMSE: {round(RMSE, 3)}', end=',')\n", + " print(f'MAPE: {round(MAPE * 100, 3)} %', end=',')\n", + " print(f'MAE: {round(MAE, 3)}', end=',')\n", + " print(f'R_2: {round(R_2, 3)}')\n", + " return [MSE, RMSE, MAE, MAPE, R_2]" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "10213bc5-bf13-46ed-9ce9-b1dbc5af72ee", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-01-05 16:46:22.503307: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcuda.so.1\n", + "2024-01-05 16:46:22.560854: E tensorflow/stream_executor/cuda/cuda_driver.cc:328] failed call to cuInit: CUDA_ERROR_INVALID_DEVICE: invalid device ordinal\n", + "2024-01-05 16:46:22.560909: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:169] retrieving CUDA diagnostic information for host: zhaojh-yv621\n", + "2024-01-05 16:46:22.560920: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:176] hostname: zhaojh-yv621\n", + "2024-01-05 16:46:22.561113: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:200] libcuda reported version is: 520.61.5\n", + "2024-01-05 16:46:22.561132: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:204] kernel reported version is: 520.61.5\n", + "2024-01-05 16:46:22.561135: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:310] kernel version seems to match DSO: 520.61.5\n", + "2024-01-05 16:46:22.561424: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 AVX512F FMA\n", + "To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.\n" + ] + }, + { + "ename": "ValueError", + "evalue": "in user code:\n\n /tmp/ipykernel_16320/2404117700.py:31 call *\n return K.concatenate(inputs, -1)\n /root/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/util/dispatch.py:206 wrapper **\n return target(*args, **kwargs)\n /root/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/keras/backend.py:3098 concatenate\n return array_ops.concat([to_dense(x) for x in tensors], axis)\n /root/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/util/dispatch.py:206 wrapper\n return target(*args, **kwargs)\n /root/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/ops/array_ops.py:1768 concat\n return gen_array_ops.concat_v2(values=values, axis=axis, name=name)\n /root/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/ops/gen_array_ops.py:1227 concat_v2\n _, _, _op, _outputs = _op_def_library._apply_op_helper(\n /root/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/framework/op_def_library.py:748 _apply_op_helper\n op = g._create_op_internal(op_type_name, inputs, dtypes=None,\n /root/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/framework/func_graph.py:599 _create_op_internal\n return super(FuncGraph, self)._create_op_internal( # pylint: disable=protected-access\n /root/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/framework/ops.py:3557 _create_op_internal\n ret = Operation(\n /root/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/framework/ops.py:2041 __init__\n self._c_op = _create_c_op(self._graph, node_def, inputs,\n /root/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/framework/ops.py:1883 _create_c_op\n raise ValueError(str(e))\n\n ValueError: Shape must be rank 2 but is rank 3 for '{{node custom_multi_loss_layer/concat}} = ConcatV2[N=4, T=DT_FLOAT, Tidx=DT_INT32](Placeholder, Placeholder_1, Placeholder_2, Placeholder_3, custom_multi_loss_layer/concat/axis)' with input shapes: [?,1], [?,1], [?,1,1], [?,1,1], [].\n", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[28], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m prediction_model \u001b[38;5;241m=\u001b[39m get_prediction_model()\n\u001b[0;32m----> 2\u001b[0m trainable_model \u001b[38;5;241m=\u001b[39m \u001b[43mget_trainable_model\u001b[49m\u001b[43m(\u001b[49m\u001b[43mprediction_model\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 3\u001b[0m trainable_model\u001b[38;5;241m.\u001b[39mcompile(optimizer\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124madam\u001b[39m\u001b[38;5;124m'\u001b[39m, loss\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m)\n", + "Cell \u001b[0;32mIn[18], line 6\u001b[0m, in \u001b[0;36mget_trainable_model\u001b[0;34m(prediction_model)\u001b[0m\n\u001b[1;32m 4\u001b[0m bet_real \u001b[38;5;241m=\u001b[39m layers\u001b[38;5;241m.\u001b[39mInput(shape\u001b[38;5;241m=\u001b[39m(\u001b[38;5;241m1\u001b[39m,), name\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mvad_real\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 5\u001b[0m mesco_real \u001b[38;5;241m=\u001b[39m layers\u001b[38;5;241m.\u001b[39mInput(shape\u001b[38;5;241m=\u001b[39m(\u001b[38;5;241m1\u001b[39m,), name\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mfcad_real\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[0;32m----> 6\u001b[0m out \u001b[38;5;241m=\u001b[39m \u001b[43mCustomMultiLossLayer\u001b[49m\u001b[43m(\u001b[49m\u001b[43mnb_outputs\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m2\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[43mbet_real\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmesco_real\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mbet\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmesco\u001b[49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 7\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m Model([inputs, bet_real, mesco_real], out)\n", + "File \u001b[0;32m~/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/keras/engine/base_layer.py:969\u001b[0m, in \u001b[0;36mLayer.__call__\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 963\u001b[0m \u001b[38;5;66;03m# Functional Model construction mode is invoked when `Layer`s are called on\u001b[39;00m\n\u001b[1;32m 964\u001b[0m \u001b[38;5;66;03m# symbolic `KerasTensor`s, i.e.:\u001b[39;00m\n\u001b[1;32m 965\u001b[0m \u001b[38;5;66;03m# >> inputs = tf.keras.Input(10)\u001b[39;00m\n\u001b[1;32m 966\u001b[0m \u001b[38;5;66;03m# >> outputs = MyLayer()(inputs) # Functional construction mode.\u001b[39;00m\n\u001b[1;32m 967\u001b[0m \u001b[38;5;66;03m# >> model = tf.keras.Model(inputs, outputs)\u001b[39;00m\n\u001b[1;32m 968\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m _in_functional_construction_mode(\u001b[38;5;28mself\u001b[39m, inputs, args, kwargs, input_list):\n\u001b[0;32m--> 969\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_functional_construction_call\u001b[49m\u001b[43m(\u001b[49m\u001b[43minputs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 970\u001b[0m \u001b[43m \u001b[49m\u001b[43minput_list\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 972\u001b[0m \u001b[38;5;66;03m# Maintains info about the `Layer.call` stack.\u001b[39;00m\n\u001b[1;32m 973\u001b[0m call_context \u001b[38;5;241m=\u001b[39m base_layer_utils\u001b[38;5;241m.\u001b[39mcall_context()\n", + "File \u001b[0;32m~/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/keras/engine/base_layer.py:1107\u001b[0m, in \u001b[0;36mLayer._functional_construction_call\u001b[0;34m(self, inputs, args, kwargs, input_list)\u001b[0m\n\u001b[1;32m 1102\u001b[0m training_arg_passed_by_framework \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m 1104\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m call_context\u001b[38;5;241m.\u001b[39menter(\n\u001b[1;32m 1105\u001b[0m layer\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m, inputs\u001b[38;5;241m=\u001b[39minputs, build_graph\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m, training\u001b[38;5;241m=\u001b[39mtraining_value):\n\u001b[1;32m 1106\u001b[0m \u001b[38;5;66;03m# Check input assumptions set after layer building, e.g. input shape.\u001b[39;00m\n\u001b[0;32m-> 1107\u001b[0m outputs \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_keras_tensor_symbolic_call\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1108\u001b[0m \u001b[43m \u001b[49m\u001b[43minputs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43minput_masks\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1110\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m outputs \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 1111\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mA layer\u001b[39m\u001b[38;5;130;01m\\'\u001b[39;00m\u001b[38;5;124ms `call` method should return a \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 1112\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mTensor or a list of Tensors, not None \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 1113\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m(layer: \u001b[39m\u001b[38;5;124m'\u001b[39m \u001b[38;5;241m+\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mname \u001b[38;5;241m+\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m).\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", + "File \u001b[0;32m~/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/keras/engine/base_layer.py:840\u001b[0m, in \u001b[0;36mLayer._keras_tensor_symbolic_call\u001b[0;34m(self, inputs, input_masks, args, kwargs)\u001b[0m\n\u001b[1;32m 838\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m nest\u001b[38;5;241m.\u001b[39mmap_structure(keras_tensor\u001b[38;5;241m.\u001b[39mKerasTensor, output_signature)\n\u001b[1;32m 839\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 840\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_infer_output_signature\u001b[49m\u001b[43m(\u001b[49m\u001b[43minputs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43minput_masks\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/keras/engine/base_layer.py:880\u001b[0m, in \u001b[0;36mLayer._infer_output_signature\u001b[0;34m(self, inputs, args, kwargs, input_masks)\u001b[0m\n\u001b[1;32m 878\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_maybe_build(inputs)\n\u001b[1;32m 879\u001b[0m inputs \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_maybe_cast_inputs(inputs)\n\u001b[0;32m--> 880\u001b[0m outputs \u001b[38;5;241m=\u001b[39m \u001b[43mcall_fn\u001b[49m\u001b[43m(\u001b[49m\u001b[43minputs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 882\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_handle_activity_regularization(inputs, outputs)\n\u001b[1;32m 883\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_set_mask_metadata(inputs, outputs, input_masks,\n\u001b[1;32m 884\u001b[0m build_graph\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m)\n", + "File \u001b[0;32m~/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/autograph/impl/api.py:695\u001b[0m, in \u001b[0;36mconvert..decorator..wrapper\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 693\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e: \u001b[38;5;66;03m# pylint:disable=broad-except\u001b[39;00m\n\u001b[1;32m 694\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mhasattr\u001b[39m(e, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mag_error_metadata\u001b[39m\u001b[38;5;124m'\u001b[39m):\n\u001b[0;32m--> 695\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m e\u001b[38;5;241m.\u001b[39mag_error_metadata\u001b[38;5;241m.\u001b[39mto_exception(e)\n\u001b[1;32m 696\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 697\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m\n", + "\u001b[0;31mValueError\u001b[0m: in user code:\n\n /tmp/ipykernel_16320/2404117700.py:31 call *\n return K.concatenate(inputs, -1)\n /root/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/util/dispatch.py:206 wrapper **\n return target(*args, **kwargs)\n /root/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/keras/backend.py:3098 concatenate\n return array_ops.concat([to_dense(x) for x in tensors], axis)\n /root/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/util/dispatch.py:206 wrapper\n return target(*args, **kwargs)\n /root/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/ops/array_ops.py:1768 concat\n return gen_array_ops.concat_v2(values=values, axis=axis, name=name)\n /root/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/ops/gen_array_ops.py:1227 concat_v2\n _, _, _op, _outputs = _op_def_library._apply_op_helper(\n /root/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/framework/op_def_library.py:748 _apply_op_helper\n op = g._create_op_internal(op_type_name, inputs, dtypes=None,\n /root/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/framework/func_graph.py:599 _create_op_internal\n return super(FuncGraph, self)._create_op_internal( # pylint: disable=protected-access\n /root/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/framework/ops.py:3557 _create_op_internal\n ret = Operation(\n /root/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/framework/ops.py:2041 __init__\n self._c_op = _create_c_op(self._graph, node_def, inputs,\n /root/miniconda3/envs/python38/lib/python3.8/site-packages/tensorflow/python/framework/ops.py:1883 _create_c_op\n raise ValueError(str(e))\n\n ValueError: Shape must be rank 2 but is rank 3 for '{{node custom_multi_loss_layer/concat}} = ConcatV2[N=4, T=DT_FLOAT, Tidx=DT_INT32](Placeholder, Placeholder_1, Placeholder_2, Placeholder_3, custom_multi_loss_layer/concat/axis)' with input shapes: [?,1], [?,1], [?,1,1], [?,1,1], [].\n" + ] + } + ], + "source": [ + "prediction_model = get_prediction_model()\n", + "trainable_model = get_trainable_model(prediction_model)\n", + "trainable_model.compile(optimizer='adam', loss=None)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4a1be90d-b8f1-4fe1-9952-1cdcc489fab5", + "metadata": {}, + "outputs": [], + "source": [ + "plot_model(prediction_model)" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "6308b1dc-8e2e-4bf9-9b28-3b81979bf7e0", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-01-05 13:55:16.952556: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:176] None of the MLIR Optimization Passes are enabled (registered 2)\n", + "2024-01-05 13:55:16.970806: I tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 2200000000 Hz\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "COL: 挥发分Vad, MSE: 5.39E-01,RMSE: 0.734,MAPE: 1.948 %,MAE: 0.582,R_2: 0.883\n", + "COL: 固定炭Fcad, MSE: 7.77E-01,RMSE: 0.881,MAPE: 1.246 %,MAE: 0.654,R_2: 0.969\n", + "COL: 挥发分Vad, MSE: 8.80E-01,RMSE: 0.938,MAPE: 2.679 %,MAE: 0.783,R_2: 0.893\n", + "COL: 固定炭Fcad, MSE: 1.32E+00,RMSE: 1.149,MAPE: 1.814 %,MAE: 0.907,R_2: 0.974\n", + "COL: 挥发分Vad, MSE: 6.68E-01,RMSE: 0.817,MAPE: 2.064 %,MAE: 0.606,R_2: 0.829\n", + "COL: 固定炭Fcad, MSE: 9.89E-01,RMSE: 0.995,MAPE: 1.427 %,MAE: 0.798,R_2: 0.929\n", + "COL: 挥发分Vad, MSE: 6.34E-01,RMSE: 0.796,MAPE: 2.099 %,MAE: 0.62,R_2: 0.889\n", + "COL: 固定炭Fcad, MSE: 4.93E-01,RMSE: 0.702,MAPE: 1.058 %,MAE: 0.542,R_2: 0.985\n", + "WARNING:tensorflow:5 out of the last 9 calls to .predict_function at 0x7f0801c91c10> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n", + "COL: 挥发分Vad, MSE: 2.34E+00,RMSE: 1.53,MAPE: 4.385 %,MAE: 1.317,R_2: 0.467\n", + "COL: 固定炭Fcad, MSE: 2.21E+02,RMSE: 14.87,MAPE: 27.662 %,MAE: 14.835,R_2: -9.385\n", + "WARNING:tensorflow:6 out of the last 11 calls to .predict_function at 0x7f0801cf34c0> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n", + "COL: 挥发分Vad, MSE: 6.16E-01,RMSE: 0.785,MAPE: 2.29 %,MAE: 0.674,R_2: 0.873\n", + "COL: 固定炭Fcad, MSE: 1.04E+00,RMSE: 1.02,MAPE: 1.603 %,MAE: 0.811,R_2: 0.956\n" + ] + } + ], + "source": [ + "vad_eva_list = list()\n", + "fcad_eva_list = list()\n", + "train_data = use_data[use_cols].copy()\n", + "for (train_index, test_index) in kf.split(train_data):\n", + " train = train_data.loc[train_index]\n", + " valid = train_data.loc[test_index]\n", + " X = np.expand_dims(train[feature_cols].values, axis=1)\n", + " Y = [x for x in train[out_cols].values.T]\n", + " X_valid = np.expand_dims(valid[feature_cols].values, axis=1)\n", + " Y_valid = [x for x in valid[out_cols].values.T]\n", + " prediction_model = get_prediction_model()\n", + " trainable_model = get_trainable_model(prediction_model)\n", + " trainable_model.compile(optimizer='adam', loss=None)\n", + " hist = trainable_model.fit([X, Y[0], Y[1]], epochs=120, batch_size=8, verbose=0, \n", + " validation_data=[X_valid, Y_valid[0], Y_valid[1]],\n", + " callbacks=[reduce_lr]\n", + " )\n", + " rst = prediction_model.predict(X_valid)\n", + " pred_rst = pd.DataFrame.from_records(np.squeeze(np.asarray(rst), axis=2).T, columns=out_cols)\n", + " real_rst = valid[out_cols].copy()\n", + " for col in out_cols:\n", + " pred_rst[col] = pred_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " real_rst[col] = real_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " y_pred_vad = pred_rst['挥发分Vad(%)'].values.reshape(-1,)\n", + " y_pred_fcad = pred_rst['固定炭Fcad(%)'].values.reshape(-1,)\n", + " y_true_vad = real_rst['挥发分Vad(%)'].values.reshape(-1,)\n", + " y_true_fcad = real_rst['固定炭Fcad(%)'].values.reshape(-1,)\n", + " vad_eva = print_eva(y_true_vad, y_pred_vad, tp='挥发分Vad')\n", + " fcad_eva = print_eva(y_true_fcad, y_pred_fcad, tp='固定炭Fcad')\n", + " vad_eva_list.append(vad_eva)\n", + " fcad_eva_list.append(fcad_eva)\n", + " del trainable_model\n", + " del prediction_model" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "27e0abf7-aa29-467f-bc5e-b66a1adf6165", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "MSE 0.667414\n", + "RMSE 0.814141\n", + "MAE 0.652951\n", + "MAPE 0.022159\n", + "R_2 0.873633\n", + "dtype: float64" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vad_df = pd.DataFrame.from_records(vad_eva_list, columns=['MSE', 'RMSE', 'MAE', 'MAPE', 'R_2'])\n", + "vad_df.sort_values(by='R_2')[1:].mean()" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "070cdb94-6e7b-4028-b6d5-ba8570c902ba", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "MSE 0.923848\n", + "RMSE 0.949375\n", + "MAE 0.742411\n", + "MAPE 0.014295\n", + "R_2 0.962834\n", + "dtype: float64" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fcad_df = pd.DataFrame.from_records(fcad_eva_list, columns=['MSE', 'RMSE', 'MAE', 'MAPE', 'R_2'])\n", + "fcad_df.sort_values(by='R_2')[1:].mean()" + ] + }, + { + "cell_type": "code", + "execution_count": null, "id": "54c1df2c-c297-4b8d-be8a-3a99cff22545", "metadata": {}, "outputs": [], @@ -1021,80 +1213,6 @@ "trainable_model = get_trainable_model(prediction_model)" ] }, - { - "cell_type": "code", - "execution_count": 32, - "id": "4f832a1e-48e2-4467-b381-35b9d2f1271a", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Model: \"model_3\"\n", - "__________________________________________________________________________________________________\n", - "Layer (type) Output Shape Param # Connected to \n", - "==================================================================================================\n", - "input (InputLayer) [(None, 1, 6)] 0 \n", - "__________________________________________________________________________________________________\n", - "conv1d_3 (Conv1D) (None, 1, 64) 448 input[0][0] \n", - "__________________________________________________________________________________________________\n", - "bidirectional_3 (Bidirectional) (None, 1, 128) 66048 conv1d_3[0][0] \n", - "__________________________________________________________________________________________________\n", - "dense_30 (Dense) (None, 1, 128) 16512 bidirectional_3[0][0] \n", - "__________________________________________________________________________________________________\n", - "transformer_block_9 (Transforme (None, 1, 128) 202640 dense_30[0][0] \n", - "__________________________________________________________________________________________________\n", - "global_average_pooling1d_9 (Glo (None, 128) 0 transformer_block_9[0][0] \n", - "__________________________________________________________________________________________________\n", - "dropout_29 (Dropout) (None, 128) 0 global_average_pooling1d_9[0][0] \n", - "__________________________________________________________________________________________________\n", - "dense_33 (Dense) (None, 64) 8256 dropout_29[0][0] \n", - "__________________________________________________________________________________________________\n", - "tf.expand_dims_3 (TFOpLambda) (None, 1, 64) 0 dense_33[0][0] \n", - "__________________________________________________________________________________________________\n", - "transformer_block_10 (Transform (None, 1, 64) 52176 tf.expand_dims_3[0][0] \n", - "__________________________________________________________________________________________________\n", - "transformer_block_11 (Transform (None, 1, 64) 52176 tf.expand_dims_3[0][0] \n", - "__________________________________________________________________________________________________\n", - "global_average_pooling1d_10 (Gl (None, 64) 0 transformer_block_10[0][0] \n", - "__________________________________________________________________________________________________\n", - "global_average_pooling1d_11 (Gl (None, 64) 0 transformer_block_11[0][0] \n", - "__________________________________________________________________________________________________\n", - "dropout_32 (Dropout) (None, 64) 0 global_average_pooling1d_10[0][0]\n", - "__________________________________________________________________________________________________\n", - "dropout_35 (Dropout) (None, 64) 0 global_average_pooling1d_11[0][0]\n", - "__________________________________________________________________________________________________\n", - "dense_36 (Dense) (None, 32) 2080 dropout_32[0][0] \n", - "__________________________________________________________________________________________________\n", - "dense_39 (Dense) (None, 32) 2080 dropout_35[0][0] \n", - "__________________________________________________________________________________________________\n", - "vad (Dense) (None, 1) 33 dense_36[0][0] \n", - "__________________________________________________________________________________________________\n", - "fcad (Dense) (None, 1) 33 dense_39[0][0] \n", - "==================================================================================================\n", - "Total params: 402,482\n", - "Trainable params: 402,482\n", - "Non-trainable params: 0\n", - "__________________________________________________________________________________________________\n" - ] - } - ], - "source": [ - "prediction_model.summary()" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "id": "9289f452-a5a4-40c4-b942-f6cb2e348548", - "metadata": {}, - "outputs": [], - "source": [ - "from tensorflow.keras import optimizers\n", - "from tensorflow.python.keras.utils.vis_utils import plot_model" - ] - }, { "cell_type": "code", "execution_count": 34, @@ -1109,268 +1227,10 @@ }, { "cell_type": "code", - "execution_count": 35, - "id": "9a62dea1-4f05-411b-9756-a91623580581", - "metadata": {}, - "outputs": [], - "source": [ - "from keras.callbacks import ReduceLROnPlateau\n", - "reduce_lr = ReduceLROnPlateau(monitor='val_loss', patience=10, mode='auto')" - ] - }, - { - "cell_type": "code", - "execution_count": 40, + "execution_count": null, "id": "cf869e4d-0fce-45a2-afff-46fd9b30fd1c", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Epoch 1/120\n", - "20/20 [==============================] - 5s 59ms/step - loss: 1.8316 - val_loss: 1.8096\n", - "Epoch 2/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 1.7903 - val_loss: 1.7691\n", - "Epoch 3/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 1.7506 - val_loss: 1.7307\n", - "Epoch 4/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 1.7110 - val_loss: 1.6914\n", - "Epoch 5/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 1.6711 - val_loss: 1.6497\n", - "Epoch 6/120\n", - "20/20 [==============================] - 0s 24ms/step - loss: 1.6314 - val_loss: 1.6098\n", - "Epoch 7/120\n", - "20/20 [==============================] - 0s 24ms/step - loss: 1.5909 - val_loss: 1.5695\n", - "Epoch 8/120\n", - "20/20 [==============================] - 0s 24ms/step - loss: 1.5506 - val_loss: 1.5296\n", - "Epoch 9/120\n", - "20/20 [==============================] - 0s 24ms/step - loss: 1.5109 - val_loss: 1.4891\n", - "Epoch 10/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 1.4706 - val_loss: 1.4500\n", - "Epoch 11/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 1.4306 - val_loss: 1.4104\n", - "Epoch 12/120\n", - "20/20 [==============================] - 0s 22ms/step - loss: 1.3907 - val_loss: 1.3746\n", - "Epoch 13/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 1.3508 - val_loss: 1.3296\n", - "Epoch 14/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 1.3106 - val_loss: 1.2895\n", - "Epoch 15/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 1.2706 - val_loss: 1.2515\n", - "Epoch 16/120\n", - "20/20 [==============================] - 0s 22ms/step - loss: 1.2315 - val_loss: 1.2104\n", - "Epoch 17/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 1.1908 - val_loss: 1.1702\n", - "Epoch 18/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 1.1508 - val_loss: 1.1320\n", - "Epoch 19/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 1.1114 - val_loss: 1.0917\n", - "Epoch 20/120\n", - "20/20 [==============================] - 0s 24ms/step - loss: 1.0718 - val_loss: 1.0513\n", - "Epoch 21/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 1.0315 - val_loss: 1.0178\n", - "Epoch 22/120\n", - "20/20 [==============================] - 0s 24ms/step - loss: 0.9918 - val_loss: 0.9704\n", - "Epoch 23/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.9511 - val_loss: 0.9321\n", - "Epoch 24/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.9114 - val_loss: 0.8913\n", - "Epoch 25/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.8718 - val_loss: 0.8520\n", - "Epoch 26/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.8314 - val_loss: 0.8124\n", - "Epoch 27/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.7922 - val_loss: 0.7727\n", - "Epoch 28/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.7519 - val_loss: 0.7307\n", - "Epoch 29/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.7119 - val_loss: 0.6932\n", - "Epoch 30/120\n", - "20/20 [==============================] - 0s 22ms/step - loss: 0.6720 - val_loss: 0.6531\n", - "Epoch 31/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.6336 - val_loss: 0.6155\n", - "Epoch 32/120\n", - "20/20 [==============================] - 1s 26ms/step - loss: 0.5931 - val_loss: 0.5738\n", - "Epoch 33/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.5517 - val_loss: 0.5324\n", - "Epoch 34/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.5135 - val_loss: 0.4943\n", - "Epoch 35/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 0.4724 - val_loss: 0.4602\n", - "Epoch 36/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.4326 - val_loss: 0.4126\n", - "Epoch 37/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.3947 - val_loss: 0.3758\n", - "Epoch 38/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.3558 - val_loss: 0.3350\n", - "Epoch 39/120\n", - "20/20 [==============================] - 0s 22ms/step - loss: 0.3154 - val_loss: 0.3031\n", - "Epoch 40/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.2771 - val_loss: 0.2592\n", - "Epoch 41/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.2459 - val_loss: 0.2370\n", - "Epoch 42/120\n", - "20/20 [==============================] - 1s 27ms/step - loss: 0.2267 - val_loss: 0.2210\n", - "Epoch 43/120\n", - "20/20 [==============================] - 0s 24ms/step - loss: 0.2050 - val_loss: 0.1947\n", - "Epoch 44/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.1840 - val_loss: 0.1728\n", - "Epoch 45/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 0.1628 - val_loss: 0.1533\n", - "Epoch 46/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.1430 - val_loss: 0.1322\n", - "Epoch 47/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.1230 - val_loss: 0.1147\n", - "Epoch 48/120\n", - "20/20 [==============================] - 1s 24ms/step - loss: 0.1026 - val_loss: 0.0940\n", - "Epoch 49/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0830 - val_loss: 0.0750\n", - "Epoch 50/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0639 - val_loss: 0.0529\n", - "Epoch 51/120\n", - "20/20 [==============================] - 0s 22ms/step - loss: 0.0436 - val_loss: 0.0352\n", - "Epoch 52/120\n", - "20/20 [==============================] - 0s 24ms/step - loss: 0.0241 - val_loss: 0.0162\n", - "Epoch 53/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0092 - val_loss: 0.0084\n", - "Epoch 54/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0067 - val_loss: 0.0074\n", - "Epoch 55/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0080 - val_loss: 0.0071\n", - "Epoch 56/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0070 - val_loss: 0.0063\n", - "Epoch 57/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0062 - val_loss: 0.0076\n", - "Epoch 58/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0056 - val_loss: 0.0048\n", - "Epoch 59/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0050 - val_loss: 0.0071\n", - "Epoch 60/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0057 - val_loss: 0.0054\n", - "Epoch 61/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0044 - val_loss: 0.0092\n", - "Epoch 62/120\n", - "20/20 [==============================] - 1s 26ms/step - loss: 0.0068 - val_loss: 0.0070\n", - "Epoch 63/120\n", - "20/20 [==============================] - 1s 24ms/step - loss: 0.0059 - val_loss: 0.0065\n", - "Epoch 64/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0055 - val_loss: 0.0060\n", - "Epoch 65/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0053 - val_loss: 0.0056\n", - "Epoch 66/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0058 - val_loss: 0.0077\n", - "Epoch 67/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0051 - val_loss: 0.0054\n", - "Epoch 68/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 0.0047 - val_loss: 0.0048\n", - "Epoch 69/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0041 - val_loss: 0.0048\n", - "Epoch 70/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0037 - val_loss: 0.0049\n", - "Epoch 71/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0041 - val_loss: 0.0049\n", - "Epoch 72/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 0.0036 - val_loss: 0.0049\n", - "Epoch 73/120\n", - "20/20 [==============================] - 1s 24ms/step - loss: 0.0038 - val_loss: 0.0048\n", - "Epoch 74/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0037 - val_loss: 0.0050\n", - "Epoch 75/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0037 - val_loss: 0.0048\n", - "Epoch 76/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0038 - val_loss: 0.0048\n", - "Epoch 77/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 0.0037 - val_loss: 0.0048\n", - "Epoch 78/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0038 - val_loss: 0.0048\n", - "Epoch 79/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0036 - val_loss: 0.0048\n", - "Epoch 80/120\n", - "20/20 [==============================] - 0s 22ms/step - loss: 0.0034 - val_loss: 0.0048\n", - "Epoch 81/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0034 - val_loss: 0.0047\n", - "Epoch 82/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0037 - val_loss: 0.0047\n", - "Epoch 83/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0033 - val_loss: 0.0047\n", - "Epoch 84/120\n", - "20/20 [==============================] - 0s 22ms/step - loss: 0.0037 - val_loss: 0.0047\n", - "Epoch 85/120\n", - "20/20 [==============================] - 0s 24ms/step - loss: 0.0036 - val_loss: 0.0047\n", - "Epoch 86/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0034 - val_loss: 0.0047\n", - "Epoch 87/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0034 - val_loss: 0.0047\n", - "Epoch 88/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0034 - val_loss: 0.0047\n", - "Epoch 89/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 0.0036 - val_loss: 0.0047\n", - "Epoch 90/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0036 - val_loss: 0.0047\n", - "Epoch 91/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0036 - val_loss: 0.0047\n", - "Epoch 92/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0034 - val_loss: 0.0047\n", - "Epoch 93/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0034 - val_loss: 0.0047\n", - "Epoch 94/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0037 - val_loss: 0.0047\n", - "Epoch 95/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 0.0035 - val_loss: 0.0047\n", - "Epoch 96/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0032 - val_loss: 0.0047\n", - "Epoch 97/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0035 - val_loss: 0.0047\n", - "Epoch 98/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 0.0038 - val_loss: 0.0047\n", - "Epoch 99/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0033 - val_loss: 0.0047\n", - "Epoch 100/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0036 - val_loss: 0.0047\n", - "Epoch 101/120\n", - "20/20 [==============================] - 1s 26ms/step - loss: 0.0033 - val_loss: 0.0047\n", - "Epoch 102/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0035 - val_loss: 0.0047\n", - "Epoch 103/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0035 - val_loss: 0.0047\n", - "Epoch 104/120\n", - "20/20 [==============================] - 0s 22ms/step - loss: 0.0035 - val_loss: 0.0047\n", - "Epoch 105/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0036 - val_loss: 0.0047\n", - "Epoch 106/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0034 - val_loss: 0.0047\n", - "Epoch 107/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0036 - val_loss: 0.0047\n", - "Epoch 108/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 0.0034 - val_loss: 0.0047\n", - "Epoch 109/120\n", - "20/20 [==============================] - 1s 24ms/step - loss: 0.0037 - val_loss: 0.0047\n", - "Epoch 110/120\n", - "20/20 [==============================] - 0s 24ms/step - loss: 0.0038 - val_loss: 0.0047\n", - "Epoch 111/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0036 - val_loss: 0.0047\n", - "Epoch 112/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0035 - val_loss: 0.0047\n", - "Epoch 113/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0037 - val_loss: 0.0047\n", - "Epoch 114/120\n", - "20/20 [==============================] - 0s 20ms/step - loss: 0.0035 - val_loss: 0.0047\n", - "Epoch 115/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0033 - val_loss: 0.0047\n", - "Epoch 116/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 0.0036 - val_loss: 0.0047\n", - "Epoch 117/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0032 - val_loss: 0.0047\n", - "Epoch 118/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0036 - val_loss: 0.0047\n", - "Epoch 119/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0037 - val_loss: 0.0047\n", - "Epoch 120/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 0.0036 - val_loss: 0.0047\n" - ] - } - ], + "outputs": [], "source": [ "trainable_model.compile(optimizer='adam', loss=None)\n", "hist = trainable_model.fit([X, Y[0], Y[1]], epochs=120, batch_size=8, verbose=1, \n", @@ -1463,38 +1323,6 @@ "[np.exp(K.get_value(log_var[0]))**0.5 for log_var in trainable_model.layers[-1].log_vars]" ] }, - { - "cell_type": "code", - "execution_count": 43, - "id": "b0d5d8ad-aadd-4218-b5b7-9691a2d3eeef", - "metadata": {}, - "outputs": [], - "source": [ - "pred_rst = pd.DataFrame.from_records(np.squeeze(np.asarray(rst), axis=2).T, columns=out_cols)" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "id": "0a2bcb45-da86-471b-a61d-314e29430d6a", - "metadata": {}, - "outputs": [], - "source": [ - "real_rst = test[out_cols].copy()" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "id": "e124f7c0-fdd5-43b9-b649-ff7d9dd59641", - "metadata": {}, - "outputs": [], - "source": [ - "for col in out_cols:\n", - " pred_rst[col] = pred_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", - " real_rst[col] = real_rst[col] * (maxs[col] - mins[col]) + mins[col]" - ] - }, { "cell_type": "code", "execution_count": 46, @@ -1516,6 +1344,18 @@ "real_rst.columns" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "294813b8-90be-4007-9fd6-c26ee7bb9652", + "metadata": {}, + "outputs": [], + "source": [ + "for col in out_cols:\n", + " pred_rst[col] = pred_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " real_rst[col] = real_rst[col] * (maxs[col] - mins[col]) + mins[col]" + ] + }, { "cell_type": "code", "execution_count": 47, @@ -1531,38 +1371,7 @@ }, { "cell_type": "code", - "execution_count": 48, - "id": "26ea6cfa-efad-443c-9dd9-844f8be42b91", - "metadata": {}, - "outputs": [], - "source": [ - "from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score, mean_absolute_percentage_error" - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "id": "28072e7c-c9d5-4ff6-940d-e94ae879afc9", - "metadata": {}, - "outputs": [], - "source": [ - "def print_eva(y_true, y_pred, tp):\n", - " MSE = mean_squared_error(y_true, y_pred)\n", - " RMSE = np.sqrt(MSE)\n", - " MAE = mean_absolute_error(y_true, y_pred)\n", - " MAPE = mean_absolute_percentage_error(y_true, y_pred)\n", - " R_2 = r2_score(y_true, y_pred)\n", - " print(f\"COL: {tp}, MSE: {format(MSE, '.2E')}\", end=',')\n", - " print(f'RMSE: {round(RMSE, 4)}', end=',')\n", - " print(f'MAPE: {round(MAPE, 4) * 100} %', end=',')\n", - " print(f'MAE: {round(MAE, 4)}', end=',')\n", - " print(f'R_2: {round(R_2, 4)}')\n", - " return [MSE, RMSE, MAE, MAPE, R_2]" - ] - }, - { - "cell_type": "code", - "execution_count": 51, + "execution_count": 56, "id": "4ec4caa9-7c46-4fc8-a94b-cb659e924304", "metadata": {}, "outputs": [ @@ -1570,8 +1379,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "COL: 比表面积, MSE: 3.35E-01,RMSE: 0.5791,MAPE: 1.6400000000000001 %,MAE: 0.5041,R_2: 0.8698\n", - "COL: 总孔体积, MSE: 1.11E+00,RMSE: 1.0549,MAPE: 1.5 %,MAE: 0.8137,R_2: 0.876\n" + "COL: 挥发分Vad, MSE: 3.35E-01,RMSE: 0.579,MAPE: 1.639 %,MAE: 0.504,R_2: 0.87\n", + "COL: 固定炭Fcad, MSE: 1.11E+00,RMSE: 1.055,MAPE: 1.497 %,MAE: 0.814,R_2: 0.876\n" ] } ], diff --git a/20240102.ipynb b/20240102.ipynb index f8dc9bd..a2ab242 100644 --- a/20240102.ipynb +++ b/20240102.ipynb @@ -12,7 +12,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 2, "id": "6a94278b-8f51-4edc-966b-4a32876a4536", "metadata": {}, "outputs": [ @@ -215,7 +215,7 @@ "[228 rows x 8 columns]" ] }, - "execution_count": 6, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -227,7 +227,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 3, "id": "f72789a6-f3fa-4ab1-8b62-999413958608", "metadata": {}, "outputs": [ @@ -244,7 +244,7 @@ " '固定炭Fcad(%)']" ] }, - "execution_count": 10, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -256,7 +256,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 4, "id": "6ffb1989-3f45-4d1c-84c9-59b1045b7d9e", "metadata": {}, "outputs": [], @@ -266,7 +266,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 5, "id": "9c708cc0-9f1b-4669-a350-6d24cb720794", "metadata": {}, "outputs": [], @@ -276,7 +276,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 6, "id": "103349e1-aa4a-427a-a489-9ab28787088b", "metadata": {}, "outputs": [ @@ -286,7 +286,7 @@ "['氢Had(%)', '碳Cad(%)', '氮Nad(%)', '氧Oad(%)', '弹筒发热量Qb,adMJ/kg']" ] }, - "execution_count": 16, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -298,7 +298,7 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 7, "id": "839e45dc-e9c8-4956-950b-035687469c81", "metadata": {}, "outputs": [ @@ -409,7 +409,7 @@ "4 54.78 " ] }, - "execution_count": 44, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -421,17 +421,7 @@ }, { "cell_type": "code", - "execution_count": 19, - "id": "24233d12-9468-49b8-a371-0c6c508c387e", - "metadata": {}, - "outputs": [], - "source": [ - "import seaborn as sns" - ] - }, - { - "cell_type": "code", - "execution_count": 21, + "execution_count": 8, "id": "54cd27a6-1a8a-47c0-93d9-c948960a7842", "metadata": {}, "outputs": [], @@ -441,7 +431,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 9, "id": "bba14f71-9d69-4c82-b6bc-b9b74c725b25", "metadata": {}, "outputs": [], @@ -451,7 +441,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 10, "id": "e3a9ad55-0132-430f-ac57-c2e7f8e8590a", "metadata": {}, "outputs": [], @@ -461,13 +451,12 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 25, "id": "013c6a58-65f6-48e9-8d7f-b56c87de5b11", "metadata": {}, "outputs": [], "source": [ - "param_xgb = {\"silent\": True,\n", - " \"obj\": 'reg:linear',\n", + "params_xgb = {\"objective\": 'reg:squarederror',\n", " \"subsample\": 1,\n", " \"max_depth\": 15,\n", " \"eta\": 0.3,\n", @@ -475,12 +464,12 @@ " \"lambda\": 1,\n", " \"alpha\": 0,\n", " \"colsample_bytree\": 0.9,}\n", - "num_round = 1000" + "num_boost_round = 1000" ] }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 26, "id": "086f1901-8388-47e9-ae7c-1b2709bc1e22", "metadata": {}, "outputs": [], @@ -491,7 +480,7 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 27, "id": "fb7b06af-84bc-483c-b086-7826d7befc9c", "metadata": {}, "outputs": [ @@ -499,30 +488,30 @@ "name": "stdout", "output_type": "stream", "text": [ - "MSE: 1.9436, RMSE: 1.3941, MAE: 1.1861, MAPE: 3.94 %, R_2: 0.6095\n", - "MSE: 1.8735, RMSE: 1.3688, MAE: 1.132, MAPE: 3.77 %, R_2: 0.495\n", - "MSE: 2.0587, RMSE: 1.4348, MAE: 1.0706, MAPE: 4.08 %, R_2: 0.7862\n", - "MSE: 1.9298, RMSE: 1.3892, MAE: 1.1469, MAPE: 3.84 %, R_2: 0.5332\n", - "MSE: 1.4583, RMSE: 1.2076, MAE: 1.097, MAPE: 3.67 %, R_2: 0.6894\n", - "MSE: 2.0822, RMSE: 1.443, MAE: 1.1645, MAPE: 3.88 %, R_2: 0.5975\n", - "MSE: 1.3521, RMSE: 1.1628, MAE: 0.9905, MAPE: 3.37 %, R_2: 0.7479\n", - "MSE: 1.4057, RMSE: 1.1856, MAE: 0.9998, MAPE: 3.3 %, R_2: 0.2946\n", - "MSE: 2.2274, RMSE: 1.4925, MAE: 1.2638, MAPE: 4.19 %, R_2: 0.6785\n", - "MSE: 1.4866, RMSE: 1.2193, MAE: 1.0797, MAPE: 3.67 %, R_2: 0.7261\n" + "MSE: 0.475, RMSE: 0.6892, MAE: 0.5507, MAPE: 1.86 %, R_2: 0.9046\n", + "MSE: 1.1415, RMSE: 1.0684, MAE: 0.9133, MAPE: 3.06 %, R_2: 0.6923\n", + "MSE: 0.7247, RMSE: 0.8513, MAE: 0.6606, MAPE: 2.32 %, R_2: 0.9247\n", + "MSE: 1.3652, RMSE: 1.1684, MAE: 0.9609, MAPE: 3.24 %, R_2: 0.6698\n", + "MSE: 0.4552, RMSE: 0.6747, MAE: 0.5732, MAPE: 1.94 %, R_2: 0.903\n", + "MSE: 0.6357, RMSE: 0.7973, MAE: 0.6374, MAPE: 2.2 %, R_2: 0.8771\n", + "MSE: 0.9972, RMSE: 0.9986, MAE: 0.752, MAPE: 2.47 %, R_2: 0.8141\n", + "MSE: 1.5218, RMSE: 1.2336, MAE: 1.0569, MAPE: 3.45 %, R_2: 0.2363\n", + "MSE: 0.6891, RMSE: 0.8301, MAE: 0.6825, MAPE: 2.22 %, R_2: 0.9005\n", + "MSE: 1.6864, RMSE: 1.2986, MAE: 1.0004, MAPE: 3.51 %, R_2: 0.6893\n" ] }, { "data": { "text/plain": [ - "MSE 1.781792\n", - "RMSE 1.329760\n", - "MAE 1.113084\n", - "MAPE 0.037719\n", - "R_2 0.615796\n", + "MSE 0.969172\n", + "RMSE 0.961023\n", + "MAE 0.778783\n", + "MAPE 0.026288\n", + "R_2 0.761188\n", "dtype: float64" ] }, - "execution_count": 43, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } @@ -558,7 +547,7 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 28, "id": "90841cb7-4f28-4a33-93ac-93df69f1a5a1", "metadata": {}, "outputs": [ @@ -566,30 +555,30 @@ "name": "stdout", "output_type": "stream", "text": [ - "MSE: 4.6724, RMSE: 2.1616, MAE: 1.7297, MAPE: 3.42 %, R2: 0.8346\n", - "MSE: 3.0512, RMSE: 1.7468, MAE: 1.4485, MAPE: 2.62 %, R2: 0.8011\n", - "MSE: 7.6672, RMSE: 2.769, MAE: 1.951, MAPE: 4.56 %, R2: 0.8856\n", - "MSE: 4.0334, RMSE: 2.0083, MAE: 1.487, MAPE: 2.77 %, R2: 0.8216\n", - "MSE: 2.6382, RMSE: 1.6243, MAE: 1.1551, MAPE: 2.12 %, R2: 0.846\n", - "MSE: 5.8097, RMSE: 2.4103, MAE: 1.8683, MAPE: 3.8 %, R2: 0.83\n", - "MSE: 2.3446, RMSE: 1.5312, MAE: 1.1294, MAPE: 2.28 %, R2: 0.9069\n", - "MSE: 3.0069, RMSE: 1.734, MAE: 1.3782, MAPE: 2.46 %, R2: 0.6541\n", - "MSE: 4.1652, RMSE: 2.0409, MAE: 1.5685, MAPE: 3.2 %, R2: 0.859\n", - "MSE: 4.2023, RMSE: 2.05, MAE: 1.6284, MAPE: 3.2 %, R2: 0.869\n" + "MSE: 0.9821, RMSE: 0.991, MAE: 0.7698, MAPE: 1.44 %, R2: 0.9652\n", + "MSE: 1.2674, RMSE: 1.1258, MAE: 0.8756, MAPE: 1.64 %, R2: 0.9174\n", + "MSE: 0.9137, RMSE: 0.9559, MAE: 0.757, MAPE: 1.46 %, R2: 0.9864\n", + "MSE: 1.6012, RMSE: 1.2654, MAE: 1.0173, MAPE: 1.89 %, R2: 0.9292\n", + "MSE: 1.4694, RMSE: 1.2122, MAE: 0.8524, MAPE: 1.59 %, R2: 0.9142\n", + "MSE: 0.7552, RMSE: 0.869, MAE: 0.7202, MAPE: 1.39 %, R2: 0.9779\n", + "MSE: 0.5474, RMSE: 0.7398, MAE: 0.5467, MAPE: 1.0 %, R2: 0.9783\n", + "MSE: 1.2779, RMSE: 1.1305, MAE: 0.9452, MAPE: 1.73 %, R2: 0.853\n", + "MSE: 1.1908, RMSE: 1.0912, MAE: 0.9004, MAPE: 1.72 %, R2: 0.9597\n", + "MSE: 3.9312, RMSE: 1.9827, MAE: 1.2707, MAPE: 2.65 %, R2: 0.8775\n" ] }, { "data": { "text/plain": [ - "MSE 4.159107\n", - "RMSE 2.007631\n", - "MAE 1.534427\n", - "MAPE 0.030424\n", - "R2 0.830794\n", + "MSE 1.393623\n", + "RMSE 1.136351\n", + "MAE 0.865538\n", + "MAPE 0.016509\n", + "R2 0.935872\n", "dtype: float64" ] }, - "execution_count": 48, + "execution_count": 28, "metadata": {}, "output_type": "execute_result" } @@ -625,61 +614,10 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": null, "id": "aa67bc97-1258-44bb-9dae-14ace1661ff6", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
MSERMSEMAEMAPER2
十折交叉验证均值4.1591072.0076311.5344270.0304240.830794
\n", - "
" - ], - "text/plain": [ - " MSE RMSE MAE MAPE R2\n", - "十折交叉验证均值 4.159107 2.007631 1.534427 0.030424 0.830794" - ] - }, - "execution_count": 67, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [] }, { diff --git a/CBA_4feature.ipynb b/CBA_4feature.ipynb new file mode 100644 index 0000000..43d01bb --- /dev/null +++ b/CBA_4feature.ipynb @@ -0,0 +1,1440 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "6b84fefd-5936-4da4-ab6b-5b944329ad1d", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "os.environ['CUDA_DEVICE_ORDER'] = 'PCB_BUS_ID'\n", + "os.environ['CUDA_VISIBLE_DEVICES'] = '0, 1'" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "9cf130e3-62ef-46e0-bbdc-b13d9d29318d", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "from sklearn.model_selection import train_test_split\n", + "import matplotlib.pyplot as plt\n", + "#新增加的两行\n", + "from pylab import mpl\n", + "# 设置显示中文字体\n", + "mpl.rcParams[\"font.sans-serif\"] = [\"SimHei\"]\n", + "\n", + "mpl.rcParams[\"axes.unicode_minus\"] = False" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "752381a5-0aeb-4c54-bc48-f9c3f8fc5d17", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Unnamed: 0_level_0弹筒发热量挥发分固定炭
化验编号HadCadNadOadQb,adVadFcad
Unnamed: 0_level_2(%)(%)(%)(%)MJ/kg(%)(%)
027201105293.9370.180.8125.07927.82032.0655.68
127200968833.7868.930.7726.51227.40429.9654.71
227201090843.4869.600.7626.14827.57829.3155.99
327200847083.4766.710.7629.05526.33828.5853.87
427200627213.8768.780.8026.54227.28029.9754.78
...........................
22327200304904.1268.850.9726.05527.86432.9451.89
22427200286333.9767.040.9428.04327.36831.8851.38
22527200286344.1268.420.9626.49327.88633.1652.00
22627200176833.8867.420.9427.76026.61631.6550.56
22727200176783.8166.740.9228.53026.68831.0250.82
\n", + "

228 rows × 8 columns

\n", + "
" + ], + "text/plain": [ + " Unnamed: 0_level_0 氢 碳 氮 氧 弹筒发热量 挥发分 固定炭\n", + " 化验编号 Had Cad Nad Oad Qb,ad Vad Fcad\n", + " Unnamed: 0_level_2 (%) (%) (%) (%) MJ/kg (%) (%)\n", + "0 2720110529 3.93 70.18 0.81 25.079 27.820 32.06 55.68\n", + "1 2720096883 3.78 68.93 0.77 26.512 27.404 29.96 54.71\n", + "2 2720109084 3.48 69.60 0.76 26.148 27.578 29.31 55.99\n", + "3 2720084708 3.47 66.71 0.76 29.055 26.338 28.58 53.87\n", + "4 2720062721 3.87 68.78 0.80 26.542 27.280 29.97 54.78\n", + ".. ... ... ... ... ... ... ... ...\n", + "223 2720030490 4.12 68.85 0.97 26.055 27.864 32.94 51.89\n", + "224 2720028633 3.97 67.04 0.94 28.043 27.368 31.88 51.38\n", + "225 2720028634 4.12 68.42 0.96 26.493 27.886 33.16 52.00\n", + "226 2720017683 3.88 67.42 0.94 27.760 26.616 31.65 50.56\n", + "227 2720017678 3.81 66.74 0.92 28.530 26.688 31.02 50.82\n", + "\n", + "[228 rows x 8 columns]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data_0102 = pd.read_excel('./data/20240102/20240102.xlsx', header=[0,1,2])\n", + "data_0102" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "972f1e9c-3ebc-45cf-8d1f-7611645e5238", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['化验编号',\n", + " '氢Had(%)',\n", + " '碳Cad(%)',\n", + " '氮Nad(%)',\n", + " '氧Oad(%)',\n", + " '弹筒发热量Qb,adMJ/kg',\n", + " '挥发分Vad(%)',\n", + " '固定炭Fcad(%)']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cols = [''.join([y for y in x if 'Unnamed' not in y]) for x in data_0102.columns]\n", + "cols" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "c95f1106-b3a4-43c6-88ec-3cdebf91d79a", + "metadata": {}, + "outputs": [], + "source": [ + "data_0102.columns = cols" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "2e96af0a-feda-4a1f-a13e-9c8861c6f4d4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
化验编号氢Had(%)碳Cad(%)氮Nad(%)氧Oad(%)弹筒发热量Qb,adMJ/kg挥发分Vad(%)固定炭Fcad(%)
027201105293.9370.180.8125.07927.82032.0655.68
127200968833.7868.930.7726.51227.40429.9654.71
227201090843.4869.600.7626.14827.57829.3155.99
327200847083.4766.710.7629.05526.33828.5853.87
427200627213.8768.780.8026.54227.28029.9754.78
...........................
22327200304904.1268.850.9726.05527.86432.9451.89
22427200286333.9767.040.9428.04327.36831.8851.38
22527200286344.1268.420.9626.49327.88633.1652.00
22627200176833.8867.420.9427.76026.61631.6550.56
22727200176783.8166.740.9228.53026.68831.0250.82
\n", + "

228 rows × 8 columns

\n", + "
" + ], + "text/plain": [ + " 化验编号 氢Had(%) 碳Cad(%) 氮Nad(%) 氧Oad(%) 弹筒发热量Qb,adMJ/kg \\\n", + "0 2720110529 3.93 70.18 0.81 25.079 27.820 \n", + "1 2720096883 3.78 68.93 0.77 26.512 27.404 \n", + "2 2720109084 3.48 69.60 0.76 26.148 27.578 \n", + "3 2720084708 3.47 66.71 0.76 29.055 26.338 \n", + "4 2720062721 3.87 68.78 0.80 26.542 27.280 \n", + ".. ... ... ... ... ... ... \n", + "223 2720030490 4.12 68.85 0.97 26.055 27.864 \n", + "224 2720028633 3.97 67.04 0.94 28.043 27.368 \n", + "225 2720028634 4.12 68.42 0.96 26.493 27.886 \n", + "226 2720017683 3.88 67.42 0.94 27.760 26.616 \n", + "227 2720017678 3.81 66.74 0.92 28.530 26.688 \n", + "\n", + " 挥发分Vad(%) 固定炭Fcad(%) \n", + "0 32.06 55.68 \n", + "1 29.96 54.71 \n", + "2 29.31 55.99 \n", + "3 28.58 53.87 \n", + "4 29.97 54.78 \n", + ".. ... ... \n", + "223 32.94 51.89 \n", + "224 31.88 51.38 \n", + "225 33.16 52.00 \n", + "226 31.65 50.56 \n", + "227 31.02 50.82 \n", + "\n", + "[228 rows x 8 columns]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data_0102" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "04b177a7-2f02-4e23-8ea9-29f34cf3eafc", + "metadata": {}, + "outputs": [], + "source": [ + "out_cols = ['挥发分Vad(%)']\n", + "# out_cols = ['固定炭Fcad(%)']" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "31169fbf-d78e-42f7-87f3-71ba3dd0979d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['挥发分Vad(%)']" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "out_cols" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "feaedd50-f999-45bf-b465-3d359b0c0110", + "metadata": {}, + "outputs": [], + "source": [ + "data = data_0102.copy()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "a40bee0f-011a-4edb-80f8-4e2f40e755fd", + "metadata": {}, + "outputs": [], + "source": [ + "train_data = data.dropna(subset=out_cols).fillna(0)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "535d37b6-b9de-4025-ac8f-62f5bdbe2451", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-01-05 16:22:29.862058: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0\n" + ] + } + ], + "source": [ + "import tensorflow as tf\n", + "from tensorflow import keras\n", + "from tensorflow.keras import layers\n", + "import tensorflow.keras.backend as K" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "1c85d462-f248-4ffb-908f-eb4b20eab179", + "metadata": {}, + "outputs": [], + "source": [ + "class TransformerBlock(layers.Layer):\n", + " def __init__(self, embed_dim, num_heads, ff_dim, name, rate=0.1):\n", + " super().__init__()\n", + " self.att = layers.MultiHeadAttention(num_heads=num_heads, key_dim=embed_dim, name=name)\n", + " self.ffn = keras.Sequential(\n", + " [layers.Dense(ff_dim, activation=\"relu\"), layers.Dense(embed_dim),]\n", + " )\n", + " self.layernorm1 = layers.LayerNormalization(epsilon=1e-6)\n", + " self.layernorm2 = layers.LayerNormalization(epsilon=1e-6)\n", + " self.dropout1 = layers.Dropout(rate)\n", + " self.dropout2 = layers.Dropout(rate)\n", + "\n", + " def call(self, inputs, training):\n", + " attn_output = self.att(inputs, inputs)\n", + " attn_output = self.dropout1(attn_output, training=training)\n", + " out1 = self.layernorm1(inputs + attn_output)\n", + " ffn_output = self.ffn(out1)\n", + " ffn_output = self.dropout2(ffn_output, training=training)\n", + " return self.layernorm2(out1 + ffn_output)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "790284a3-b9d3-4144-b481-38a7c3ecb4b9", + "metadata": {}, + "outputs": [], + "source": [ + "from tensorflow.keras import Model" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "cd9a1ca1-d0ca-4cb5-9ef5-fd5d63576cd2", + "metadata": {}, + "outputs": [], + "source": [ + "from tensorflow.keras.initializers import Constant" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "9bc02f29-0fb7-420d-99a8-435eadc06e29", + "metadata": {}, + "outputs": [], + "source": [ + "# Custom loss layer\n", + "class CustomMultiLossLayer(layers.Layer):\n", + " def __init__(self, nb_outputs=2, **kwargs):\n", + " self.nb_outputs = nb_outputs\n", + " self.is_placeholder = True\n", + " super(CustomMultiLossLayer, self).__init__(**kwargs)\n", + " \n", + " def build(self, input_shape=None):\n", + " # initialise log_vars\n", + " self.log_vars = []\n", + " for i in range(self.nb_outputs):\n", + " self.log_vars += [self.add_weight(name='log_var' + str(i), shape=(1,),\n", + " initializer=tf.initializers.he_normal(), trainable=True)]\n", + " super(CustomMultiLossLayer, self).build(input_shape)\n", + "\n", + " def multi_loss(self, ys_true, ys_pred):\n", + " assert len(ys_true) == self.nb_outputs and len(ys_pred) == self.nb_outputs\n", + " loss = 0\n", + " for y_true, y_pred, log_var in zip(ys_true, ys_pred, self.log_vars):\n", + " mse = (y_true - y_pred) ** 2.\n", + " pre = K.exp(-log_var[0])\n", + " loss += tf.abs(tf.reduce_logsumexp(pre * mse + log_var[0], axis=-1))\n", + " return K.mean(loss)\n", + "\n", + " def call(self, inputs):\n", + " ys_true = inputs[:self.nb_outputs]\n", + " ys_pred = inputs[self.nb_outputs:]\n", + " loss = self.multi_loss(ys_true, ys_pred)\n", + " self.add_loss(loss, inputs=inputs)\n", + " # We won't actually use the output.\n", + " return K.concatenate(inputs, -1)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "a190207e-5a59-4813-9660-758760cf1b73", + "metadata": {}, + "outputs": [], + "source": [ + "num_heads, ff_dim = 3, 16" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "80f32155-e71f-4615-8d0c-01dfd04988fe", + "metadata": {}, + "outputs": [], + "source": [ + "def get_prediction_model():\n", + " inputs = layers.Input(shape=(1,len(feature_cols)), name='input')\n", + " x = layers.Conv1D(filters=64, kernel_size=1, activation='relu')(inputs)\n", + " # x = layers.Dropout(rate=0.1)(x)\n", + " lstm_out = layers.Bidirectional(layers.LSTM(units=64, return_sequences=True))(x)\n", + " lstm_out = layers.Dense(128, activation='relu')(lstm_out)\n", + " transformer_block = TransformerBlock(128, num_heads, ff_dim, name='first_attn')\n", + " out = transformer_block(lstm_out)\n", + " out = layers.GlobalAveragePooling1D()(out)\n", + " out = layers.Dropout(0.1)(out)\n", + " out = layers.Dense(64, activation='relu')(out)\n", + " bet = layers.Dense(1, activation='sigmoid', name='vad')(out)\n", + " model = Model(inputs=[inputs], outputs=[bet])\n", + " return model" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "7a9915ee-0016-44e5-a6fb-5ee90532dc14", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model: \"model_23\"\n", + "_________________________________________________________________\n", + "Layer (type) Output Shape Param # \n", + "=================================================================\n", + "input (InputLayer) [(None, 1, 7)] 0 \n", + "_________________________________________________________________\n", + "conv1d_25 (Conv1D) (None, 1, 64) 512 \n", + "_________________________________________________________________\n", + "bidirectional_25 (Bidirectio (None, 1, 128) 66048 \n", + "_________________________________________________________________\n", + "dense_100 (Dense) (None, 1, 128) 16512 \n", + "_________________________________________________________________\n", + "transformer_block_25 (Transf (None, 1, 128) 202640 \n", + "_________________________________________________________________\n", + "global_average_pooling1d_25 (None, 128) 0 \n", + "_________________________________________________________________\n", + "dropout_77 (Dropout) (None, 128) 0 \n", + "_________________________________________________________________\n", + "dense_103 (Dense) (None, 64) 8256 \n", + "_________________________________________________________________\n", + "vad (Dense) (None, 1) 65 \n", + "=================================================================\n", + "Total params: 294,033\n", + "Trainable params: 294,033\n", + "Non-trainable params: 0\n", + "_________________________________________________________________\n" + ] + } + ], + "source": [ + "model = get_prediction_model()\n", + "model.summary()" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "372011ea-9876-41eb-a4e6-83ccd6c71559", + "metadata": {}, + "outputs": [], + "source": [ + "from tensorflow.python.keras.utils.vis_utils import plot_model" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "1eebdab3-1f88-48a1-b5e0-bc8787528c1b", + "metadata": {}, + "outputs": [], + "source": [ + "maxs = train_data.max()\n", + "mins = train_data.min()\n", + "for col in train_data.columns:\n", + " if maxs[col] - mins[col] == 0:\n", + " continue\n", + " train_data[col] = (train_data[col] - mins[col]) / (maxs[col] - mins[col])" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "7f27bd56-4f6b-4242-9f79-c7d6b3ee2f13", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
化验编号氢Had(%)碳Cad(%)氮Nad(%)氧Oad(%)弹筒发热量Qb,adMJ/kg挥发分Vad(%)固定炭Fcad(%)
00.9965470.7739730.8354140.4565220.1714630.8112490.8477370.828147
10.8511180.6712330.7999430.3695650.2102540.7820380.6748970.794606
20.9811470.4657530.8189560.3478260.2004010.7942560.6213990.838866
30.7213670.4589040.7369470.3478260.2790940.7071830.5613170.765560
40.4870460.7328770.7956870.4347830.2110660.7733310.6757200.797026
...........................
2230.1435530.9041100.7976730.8043480.1978830.8143390.9201650.697095
2240.1237620.8013700.7463110.7391300.2516990.7795100.8329220.679461
2250.1237730.9041100.7854710.7826090.2097400.8158840.9382720.700899
2260.0070660.7397260.7570940.7391300.2440380.7267050.8139920.651107
2270.0070120.6917810.7377980.6956520.2648820.7317600.7621400.660097
\n", + "

228 rows × 8 columns

\n", + "
" + ], + "text/plain": [ + " 化验编号 氢Had(%) 碳Cad(%) 氮Nad(%) 氧Oad(%) 弹筒发热量Qb,adMJ/kg \\\n", + "0 0.996547 0.773973 0.835414 0.456522 0.171463 0.811249 \n", + "1 0.851118 0.671233 0.799943 0.369565 0.210254 0.782038 \n", + "2 0.981147 0.465753 0.818956 0.347826 0.200401 0.794256 \n", + "3 0.721367 0.458904 0.736947 0.347826 0.279094 0.707183 \n", + "4 0.487046 0.732877 0.795687 0.434783 0.211066 0.773331 \n", + ".. ... ... ... ... ... ... \n", + "223 0.143553 0.904110 0.797673 0.804348 0.197883 0.814339 \n", + "224 0.123762 0.801370 0.746311 0.739130 0.251699 0.779510 \n", + "225 0.123773 0.904110 0.785471 0.782609 0.209740 0.815884 \n", + "226 0.007066 0.739726 0.757094 0.739130 0.244038 0.726705 \n", + "227 0.007012 0.691781 0.737798 0.695652 0.264882 0.731760 \n", + "\n", + " 挥发分Vad(%) 固定炭Fcad(%) \n", + "0 0.847737 0.828147 \n", + "1 0.674897 0.794606 \n", + "2 0.621399 0.838866 \n", + "3 0.561317 0.765560 \n", + "4 0.675720 0.797026 \n", + ".. ... ... \n", + "223 0.920165 0.697095 \n", + "224 0.832922 0.679461 \n", + "225 0.938272 0.700899 \n", + "226 0.813992 0.651107 \n", + "227 0.762140 0.660097 \n", + "\n", + "[228 rows x 8 columns]" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train_data" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "baf45a3d-dc01-44fc-9f0b-456964ac2cdb", + "metadata": {}, + "outputs": [], + "source": [ + "# feature_cols = [x for x in train_data.columns if x not in out_cols and '第二次' not in x]\n", + "feature_cols = [x for x in train_data.columns if x not in out_cols]\n", + "use_cols = feature_cols + out_cols" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "f2d27538-d2bc-4202-b0cf-d3e0949b4686", + "metadata": {}, + "outputs": [], + "source": [ + "use_data = train_data.copy()\n", + "for col in use_cols:\n", + " use_data[col] = use_data[col].astype('float32')" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "50daf170-efec-49e5-8f8e-9a45938cacfc", + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.model_selection import KFold, train_test_split\n", + "kf = KFold(n_splits=6, shuffle=True, random_state=42)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "0f863423-be12-478b-a08d-e3c6f5dfb8ee", + "metadata": {}, + "outputs": [], + "source": [ + "from tensorflow.keras import optimizers\n", + "from tensorflow.python.keras.utils.vis_utils import plot_model\n", + "from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score, mean_absolute_percentage_error" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "2c89b32a-017c-4d05-ab78-8b9b8eb0dcbb", + "metadata": {}, + "outputs": [], + "source": [ + "from keras.callbacks import ReduceLROnPlateau\n", + "reduce_lr = ReduceLROnPlateau(monitor='val_loss', patience=10, mode='auto')" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "ca6ce434-80b6-4609-9596-9a5120680462", + "metadata": {}, + "outputs": [], + "source": [ + "def print_eva(y_true, y_pred, tp):\n", + " MSE = mean_squared_error(y_true, y_pred)\n", + " RMSE = np.sqrt(MSE)\n", + " MAE = mean_absolute_error(y_true, y_pred)\n", + " MAPE = mean_absolute_percentage_error(y_true, y_pred)\n", + " R_2 = r2_score(y_true, y_pred)\n", + " print(f\"COL: {tp}, MSE: {format(MSE, '.2E')}\", end=',')\n", + " print(f'RMSE: {round(RMSE, 3)}', end=',')\n", + " print(f'MAPE: {round(MAPE * 100, 3)} %', end=',')\n", + " print(f'MAE: {round(MAE, 3)}', end=',')\n", + " print(f'R_2: {round(R_2, 3)}')\n", + " return [MSE, RMSE, MAE, MAPE, R_2]" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "503bbec7-2020-44c8-b622-05bb41082e43", + "metadata": {}, + "outputs": [], + "source": [ + "from keras.losses import mean_squared_error" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "6308b1dc-8e2e-4bf9-9b28-3b81979bf7e0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "COL: 挥发分Vad, MSE: 3.26E-01,RMSE: 0.571,MAPE: 1.605 %,MAE: 0.478,R_2: 0.93\n", + "COL: 挥发分Vad, MSE: 3.27E-01,RMSE: 0.572,MAPE: 1.669 %,MAE: 0.475,R_2: 0.96\n", + "COL: 挥发分Vad, MSE: 3.65E-01,RMSE: 0.604,MAPE: 1.575 %,MAE: 0.464,R_2: 0.907\n", + "WARNING:tensorflow:5 out of the last 9 calls to .predict_function at 0x7f3ded91edc0> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n", + "COL: 挥发分Vad, MSE: 3.82E-01,RMSE: 0.618,MAPE: 1.707 %,MAE: 0.497,R_2: 0.933\n", + "WARNING:tensorflow:6 out of the last 11 calls to .predict_function at 0x7f3ded94b310> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n", + "COL: 挥发分Vad, MSE: 4.48E-01,RMSE: 0.669,MAPE: 1.801 %,MAE: 0.548,R_2: 0.898\n", + "COL: 挥发分Vad, MSE: 5.19E-01,RMSE: 0.721,MAPE: 1.992 %,MAE: 0.582,R_2: 0.893\n" + ] + } + ], + "source": [ + "vad_eva_list = list()\n", + "fcad_eva_list = list()\n", + "train_data = use_data[use_cols].copy()\n", + "for (train_index, test_index) in kf.split(train_data):\n", + " train = train_data.loc[train_index]\n", + " valid = train_data.loc[test_index]\n", + " X = np.expand_dims(train[feature_cols].values, axis=1)\n", + " Y = [x for x in train[out_cols].values.T]\n", + " X_valid = np.expand_dims(valid[feature_cols].values, axis=1)\n", + " Y_valid = [x for x in valid[out_cols].values.T]\n", + " prediction_model = get_prediction_model()\n", + " prediction_model.compile(optimizer='adam', loss=mean_squared_error)\n", + " hist = prediction_model.fit(X, Y[0], epochs=120, batch_size=8, verbose=0, \n", + " validation_data=(X_valid, Y_valid[0]),\n", + " callbacks=[reduce_lr]\n", + " )\n", + " rst = prediction_model.predict(X_valid)\n", + " pred_rst = pd.DataFrame.from_records(np.asarray(rst), columns=out_cols)\n", + " real_rst = valid[out_cols].copy()\n", + " for col in out_cols:\n", + " pred_rst[col] = pred_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " real_rst[col] = real_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " y_pred_vad = pred_rst[out_cols].values.reshape(-1,)\n", + " # y_pred_fcad = pred_rst['固定炭Fcad(%)'].values.reshape(-1,)\n", + " y_true_vad = real_rst[out_cols].values.reshape(-1,)\n", + " # y_true_fcad = real_rst['固定炭Fcad(%)'].values.reshape(-1,)\n", + " vad_eva = print_eva(y_true_vad, y_pred_vad, tp='挥发分Vad')\n", + " # fcad_eva = print_eva(y_true_fcad, y_pred_fcad, tp='固定炭Fcad')\n", + " vad_eva_list.append(vad_eva)\n", + " # fcad_eva_list.append(fcad_eva)\n", + " del prediction_model" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "f7132465-89e9-4193-829b-c6e7606cd266", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "COL: 固定炭Fcad, MSE: 2.10E-01,RMSE: 0.458,MAPE: 0.687 %,MAE: 0.361,R_2: 0.992\n", + "COL: 固定炭Fcad, MSE: 3.45E-01,RMSE: 0.587,MAPE: 0.865 %,MAE: 0.404,R_2: 0.993\n", + "COL: 固定炭Fcad, MSE: 3.77E-01,RMSE: 0.614,MAPE: 0.837 %,MAE: 0.465,R_2: 0.973\n", + "COL: 固定炭Fcad, MSE: 2.15E-01,RMSE: 0.463,MAPE: 0.693 %,MAE: 0.35,R_2: 0.994\n", + "COL: 固定炭Fcad, MSE: 2.75E-01,RMSE: 0.525,MAPE: 0.746 %,MAE: 0.41,R_2: 0.987\n", + "COL: 固定炭Fcad, MSE: 4.84E-01,RMSE: 0.696,MAPE: 0.968 %,MAE: 0.483,R_2: 0.979\n" + ] + } + ], + "source": [ + "out_cols = ['固定炭Fcad(%)']\n", + "fcad_eva_list = list()\n", + "train_data = use_data[use_cols].copy()\n", + "for (train_index, test_index) in kf.split(train_data):\n", + " train = train_data.loc[train_index]\n", + " valid = train_data.loc[test_index]\n", + " X = np.expand_dims(train[feature_cols].values, axis=1)\n", + " Y = [x for x in train[out_cols].values.T]\n", + " X_valid = np.expand_dims(valid[feature_cols].values, axis=1)\n", + " Y_valid = [x for x in valid[out_cols].values.T]\n", + " prediction_model = get_prediction_model()\n", + " prediction_model.compile(optimizer='adam', loss=mean_squared_error)\n", + " hist = prediction_model.fit(X, Y[0], epochs=120, batch_size=8, verbose=0, \n", + " validation_data=(X_valid, Y_valid[0]),\n", + " callbacks=[reduce_lr]\n", + " )\n", + " rst = prediction_model.predict(X_valid)\n", + " pred_rst = pd.DataFrame.from_records(np.asarray(rst), columns=out_cols)\n", + " real_rst = valid[out_cols].copy()\n", + " for col in out_cols:\n", + " pred_rst[col] = pred_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " real_rst[col] = real_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " y_pred = pred_rst[out_cols].values.reshape(-1,)\n", + " y_true = real_rst[out_cols].values.reshape(-1,)\n", + " fcad_eva = print_eva(y_true, y_pred, tp='固定炭Fcad')\n", + " fcad_eva_list.append(fcad_eva)\n", + " del prediction_model" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "27e0abf7-aa29-467f-bc5e-b66a1adf6165", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "MSE 0.394351\n", + "RMSE 0.625663\n", + "MAE 0.507130\n", + "MAPE 0.017249\n", + "R_2 0.920159\n", + "dtype: float64" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vad_df = pd.DataFrame.from_records(vad_eva_list, columns=['MSE', 'RMSE', 'MAE', 'MAPE', 'R_2'])\n", + "vad_df.sort_values(by='R_2').mean()" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "id": "070cdb94-6e7b-4028-b6d5-ba8570c902ba", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "MSE 0.317628\n", + "RMSE 0.557178\n", + "MAE 0.412263\n", + "MAPE 0.007993\n", + "R_2 0.986373\n", + "dtype: float64" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fcad_df = pd.DataFrame.from_records(fcad_eva_list, columns=['MSE', 'RMSE', 'MAE', 'MAPE', 'R_2'])\n", + "fcad_df.sort_values(by='R_2').mean()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "54c1df2c-c297-4b8d-be8a-3a99cff22545", + "metadata": {}, + "outputs": [], + "source": [ + "train, valid = train_test_split(use_data[use_cols], test_size=0.3, random_state=42, shuffle=True)\n", + "valid, test = train_test_split(valid, test_size=0.3, random_state=42, shuffle=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "e7a914da-b9c2-40d9-96e0-459b0888adba", + "metadata": {}, + "outputs": [], + "source": [ + "prediction_model = get_prediction_model()\n", + "trainable_model = get_trainable_model(prediction_model)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "2494ef5a-5b2b-4f11-b6cd-dc39503c9106", + "metadata": {}, + "outputs": [], + "source": [ + "X = np.expand_dims(train[feature_cols].values, axis=1)\n", + "Y = [x for x in train[out_cols].values.T]\n", + "Y_valid = [x for x in valid[out_cols].values.T]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cf869e4d-0fce-45a2-afff-46fd9b30fd1c", + "metadata": {}, + "outputs": [], + "source": [ + "trainable_model.compile(optimizer='adam', loss=None)\n", + "hist = trainable_model.fit([X, Y[0], Y[1]], epochs=120, batch_size=8, verbose=1, \n", + " validation_data=[np.expand_dims(valid[feature_cols].values, axis=1), Y_valid[0], Y_valid[1]],\n", + " callbacks=[reduce_lr]\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "67bfbe88-5f2c-4659-b2dc-eb9f1b824d04", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[array([[0.73740077],\n", + " [0.89292204],\n", + " [0.7599046 ],\n", + " [0.67802393],\n", + " [0.6815233 ],\n", + " [0.88627005],\n", + " [0.6121343 ],\n", + " [0.7072234 ],\n", + " [0.8561135 ],\n", + " [0.52762157],\n", + " [0.8325021 ],\n", + " [0.50241977],\n", + " [0.8242289 ],\n", + " [0.68957335],\n", + " [0.6980361 ],\n", + " [0.82116604],\n", + " [0.8566438 ],\n", + " [0.53687835],\n", + " [0.56832707],\n", + " [0.78476715],\n", + " [0.85638577]], dtype=float32),\n", + " array([[0.68600863],\n", + " [0.78454906],\n", + " [0.8179163 ],\n", + " [0.94351083],\n", + " [0.86383885],\n", + " [0.69705516],\n", + " [0.6913491 ],\n", + " [0.80277354],\n", + " [0.93557894],\n", + " [0.82278305],\n", + " [0.82674253],\n", + " [0.93518937],\n", + " [0.8094449 ],\n", + " [0.9206344 ],\n", + " [0.7747319 ],\n", + " [0.9137207 ],\n", + " [0.9491073 ],\n", + " [0.93225 ],\n", + " [0.6185102 ],\n", + " [0.8867341 ],\n", + " [0.82890105]], dtype=float32)]" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rst = prediction_model.predict(np.expand_dims(test[feature_cols], axis=1))\n", + "rst" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "7de501e9-05a2-424c-a5f4-85d43ad37592", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[0.9991559102070927, 0.9998196796918477]" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[np.exp(K.get_value(log_var[0]))**0.5 for log_var in trainable_model.layers[-1].log_vars]" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "5c69d03b-34fd-4dbf-aec6-c15093bb22ab", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['挥发分Vad(%)', '固定炭Fcad(%)'], dtype='object')" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "real_rst.columns" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "294813b8-90be-4007-9fd6-c26ee7bb9652", + "metadata": {}, + "outputs": [], + "source": [ + "for col in out_cols:\n", + " pred_rst[col] = pred_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " real_rst[col] = real_rst[col] * (maxs[col] - mins[col]) + mins[col]" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "21739f82-d82a-4bde-8537-9504b68a96d5", + "metadata": {}, + "outputs": [], + "source": [ + "y_pred_vad = pred_rst['挥发分Vad(%)'].values.reshape(-1,)\n", + "y_pred_fcad = pred_rst['固定炭Fcad(%)'].values.reshape(-1,)\n", + "y_true_vad = real_rst['挥发分Vad(%)'].values.reshape(-1,)\n", + "y_true_fcad = real_rst['固定炭Fcad(%)'].values.reshape(-1,)" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "id": "4ec4caa9-7c46-4fc8-a94b-cb659e924304", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "COL: 挥发分Vad, MSE: 3.35E-01,RMSE: 0.579,MAPE: 1.639 %,MAE: 0.504,R_2: 0.87\n", + "COL: 固定炭Fcad, MSE: 1.11E+00,RMSE: 1.055,MAPE: 1.497 %,MAE: 0.814,R_2: 0.876\n" + ] + } + ], + "source": [ + "pm25_eva = print_eva(y_true_vad, y_pred_vad, tp='挥发分Vad')\n", + "pm10_eva = print_eva(y_true_fcad, y_pred_fcad, tp='固定炭Fcad')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ac4a4339-ec7d-4266-8197-5276c2395288", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f15cbb91-1ce7-4fb0-979a-a4bdc452a1ec", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.16" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/CBA_vad_fcad.ipynb b/CBA_vad_fcad.ipynb new file mode 100644 index 0000000..3c4d394 --- /dev/null +++ b/CBA_vad_fcad.ipynb @@ -0,0 +1,1316 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "6b84fefd-5936-4da4-ab6b-5b944329ad1d", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "os.environ['CUDA_DEVICE_ORDER'] = 'PCB_BUS_ID'\n", + "os.environ['CUDA_VISIBLE_DEVICES'] = '0, 1'" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "9cf130e3-62ef-46e0-bbdc-b13d9d29318d", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "from sklearn.model_selection import train_test_split\n", + "import matplotlib.pyplot as plt\n", + "#新增加的两行\n", + "from pylab import mpl\n", + "# 设置显示中文字体\n", + "mpl.rcParams[\"font.sans-serif\"] = [\"SimHei\"]\n", + "\n", + "mpl.rcParams[\"axes.unicode_minus\"] = False" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "752381a5-0aeb-4c54-bc48-f9c3f8fc5d17", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Unnamed: 0_level_0弹筒发热量挥发分固定炭
化验编号HadCadNadOadQb,adVadFcad
Unnamed: 0_level_2(%)(%)(%)(%)MJ/kg(%)(%)
027201105293.9370.180.8125.07927.82032.0655.68
127200968833.7868.930.7726.51227.40429.9654.71
227201090843.4869.600.7626.14827.57829.3155.99
327200847083.4766.710.7629.05526.33828.5853.87
427200627213.8768.780.8026.54227.28029.9754.78
...........................
22327200304904.1268.850.9726.05527.86432.9451.89
22427200286333.9767.040.9428.04327.36831.8851.38
22527200286344.1268.420.9626.49327.88633.1652.00
22627200176833.8867.420.9427.76026.61631.6550.56
22727200176783.8166.740.9228.53026.68831.0250.82
\n", + "

228 rows × 8 columns

\n", + "
" + ], + "text/plain": [ + " Unnamed: 0_level_0 氢 碳 氮 氧 弹筒发热量 挥发分 固定炭\n", + " 化验编号 Had Cad Nad Oad Qb,ad Vad Fcad\n", + " Unnamed: 0_level_2 (%) (%) (%) (%) MJ/kg (%) (%)\n", + "0 2720110529 3.93 70.18 0.81 25.079 27.820 32.06 55.68\n", + "1 2720096883 3.78 68.93 0.77 26.512 27.404 29.96 54.71\n", + "2 2720109084 3.48 69.60 0.76 26.148 27.578 29.31 55.99\n", + "3 2720084708 3.47 66.71 0.76 29.055 26.338 28.58 53.87\n", + "4 2720062721 3.87 68.78 0.80 26.542 27.280 29.97 54.78\n", + ".. ... ... ... ... ... ... ... ...\n", + "223 2720030490 4.12 68.85 0.97 26.055 27.864 32.94 51.89\n", + "224 2720028633 3.97 67.04 0.94 28.043 27.368 31.88 51.38\n", + "225 2720028634 4.12 68.42 0.96 26.493 27.886 33.16 52.00\n", + "226 2720017683 3.88 67.42 0.94 27.760 26.616 31.65 50.56\n", + "227 2720017678 3.81 66.74 0.92 28.530 26.688 31.02 50.82\n", + "\n", + "[228 rows x 8 columns]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data_0102 = pd.read_excel('./data/20240102/20240102.xlsx', header=[0,1,2])\n", + "data_0102" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "972f1e9c-3ebc-45cf-8d1f-7611645e5238", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['化验编号',\n", + " '氢Had(%)',\n", + " '碳Cad(%)',\n", + " '氮Nad(%)',\n", + " '氧Oad(%)',\n", + " '弹筒发热量Qb,adMJ/kg',\n", + " '挥发分Vad(%)',\n", + " '固定炭Fcad(%)']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cols = [''.join([y for y in x if 'Unnamed' not in y]) for x in data_0102.columns]\n", + "cols" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "c95f1106-b3a4-43c6-88ec-3cdebf91d79a", + "metadata": {}, + "outputs": [], + "source": [ + "data_0102.columns = cols" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "2e96af0a-feda-4a1f-a13e-9c8861c6f4d4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
化验编号氢Had(%)碳Cad(%)氮Nad(%)氧Oad(%)弹筒发热量Qb,adMJ/kg挥发分Vad(%)固定炭Fcad(%)
027201105293.9370.180.8125.07927.82032.0655.68
127200968833.7868.930.7726.51227.40429.9654.71
227201090843.4869.600.7626.14827.57829.3155.99
327200847083.4766.710.7629.05526.33828.5853.87
427200627213.8768.780.8026.54227.28029.9754.78
...........................
22327200304904.1268.850.9726.05527.86432.9451.89
22427200286333.9767.040.9428.04327.36831.8851.38
22527200286344.1268.420.9626.49327.88633.1652.00
22627200176833.8867.420.9427.76026.61631.6550.56
22727200176783.8166.740.9228.53026.68831.0250.82
\n", + "

228 rows × 8 columns

\n", + "
" + ], + "text/plain": [ + " 化验编号 氢Had(%) 碳Cad(%) 氮Nad(%) 氧Oad(%) 弹筒发热量Qb,adMJ/kg \\\n", + "0 2720110529 3.93 70.18 0.81 25.079 27.820 \n", + "1 2720096883 3.78 68.93 0.77 26.512 27.404 \n", + "2 2720109084 3.48 69.60 0.76 26.148 27.578 \n", + "3 2720084708 3.47 66.71 0.76 29.055 26.338 \n", + "4 2720062721 3.87 68.78 0.80 26.542 27.280 \n", + ".. ... ... ... ... ... ... \n", + "223 2720030490 4.12 68.85 0.97 26.055 27.864 \n", + "224 2720028633 3.97 67.04 0.94 28.043 27.368 \n", + "225 2720028634 4.12 68.42 0.96 26.493 27.886 \n", + "226 2720017683 3.88 67.42 0.94 27.760 26.616 \n", + "227 2720017678 3.81 66.74 0.92 28.530 26.688 \n", + "\n", + " 挥发分Vad(%) 固定炭Fcad(%) \n", + "0 32.06 55.68 \n", + "1 29.96 54.71 \n", + "2 29.31 55.99 \n", + "3 28.58 53.87 \n", + "4 29.97 54.78 \n", + ".. ... ... \n", + "223 32.94 51.89 \n", + "224 31.88 51.38 \n", + "225 33.16 52.00 \n", + "226 31.65 50.56 \n", + "227 31.02 50.82 \n", + "\n", + "[228 rows x 8 columns]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data_0102" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "04b177a7-2f02-4e23-8ea9-29f34cf3eafc", + "metadata": {}, + "outputs": [], + "source": [ + "out_cols = ['挥发分Vad(%)']\n", + "# out_cols = ['固定炭Fcad(%)']" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "31169fbf-d78e-42f7-87f3-71ba3dd0979d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['挥发分Vad(%)']" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "out_cols" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "feaedd50-f999-45bf-b465-3d359b0c0110", + "metadata": {}, + "outputs": [], + "source": [ + "data = data_0102.copy()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "a40bee0f-011a-4edb-80f8-4e2f40e755fd", + "metadata": {}, + "outputs": [], + "source": [ + "train_data = data.dropna(subset=out_cols).fillna(0)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "535d37b6-b9de-4025-ac8f-62f5bdbe2451", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-01-05 17:02:16.953831: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0\n" + ] + } + ], + "source": [ + "import tensorflow as tf\n", + "from tensorflow import keras\n", + "from tensorflow.keras import layers\n", + "import tensorflow.keras.backend as K" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "1c85d462-f248-4ffb-908f-eb4b20eab179", + "metadata": {}, + "outputs": [], + "source": [ + "class TransformerBlock(layers.Layer):\n", + " def __init__(self, embed_dim, num_heads, ff_dim, name, rate=0.1):\n", + " super().__init__()\n", + " self.att = layers.MultiHeadAttention(num_heads=num_heads, key_dim=embed_dim, name=name)\n", + " self.ffn = keras.Sequential(\n", + " [layers.Dense(ff_dim, activation=\"relu\"), layers.Dense(embed_dim),]\n", + " )\n", + " self.layernorm1 = layers.LayerNormalization(epsilon=1e-6)\n", + " self.layernorm2 = layers.LayerNormalization(epsilon=1e-6)\n", + " self.dropout1 = layers.Dropout(rate)\n", + " self.dropout2 = layers.Dropout(rate)\n", + "\n", + " def call(self, inputs, training):\n", + " attn_output = self.att(inputs, inputs)\n", + " attn_output = self.dropout1(attn_output, training=training)\n", + " out1 = self.layernorm1(inputs + attn_output)\n", + " ffn_output = self.ffn(out1)\n", + " ffn_output = self.dropout2(ffn_output, training=training)\n", + " return self.layernorm2(out1 + ffn_output)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "790284a3-b9d3-4144-b481-38a7c3ecb4b9", + "metadata": {}, + "outputs": [], + "source": [ + "from tensorflow.keras import Model" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "cd9a1ca1-d0ca-4cb5-9ef5-fd5d63576cd2", + "metadata": {}, + "outputs": [], + "source": [ + "from tensorflow.keras.initializers import Constant" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "9bc02f29-0fb7-420d-99a8-435eadc06e29", + "metadata": {}, + "outputs": [], + "source": [ + "# Custom loss layer\n", + "class CustomMultiLossLayer(layers.Layer):\n", + " def __init__(self, nb_outputs=2, **kwargs):\n", + " self.nb_outputs = nb_outputs\n", + " self.is_placeholder = True\n", + " super(CustomMultiLossLayer, self).__init__(**kwargs)\n", + " \n", + " def build(self, input_shape=None):\n", + " # initialise log_vars\n", + " self.log_vars = []\n", + " for i in range(self.nb_outputs):\n", + " self.log_vars += [self.add_weight(name='log_var' + str(i), shape=(1,),\n", + " initializer=tf.initializers.he_normal(), trainable=True)]\n", + " super(CustomMultiLossLayer, self).build(input_shape)\n", + "\n", + " def multi_loss(self, ys_true, ys_pred):\n", + " assert len(ys_true) == self.nb_outputs and len(ys_pred) == self.nb_outputs\n", + " loss = 0\n", + " for y_true, y_pred, log_var in zip(ys_true, ys_pred, self.log_vars):\n", + " mse = (y_true - y_pred) ** 2.\n", + " pre = K.exp(-log_var[0])\n", + " loss += tf.abs(tf.reduce_logsumexp(pre * mse + log_var[0], axis=-1))\n", + " return K.mean(loss)\n", + "\n", + " def call(self, inputs):\n", + " ys_true = inputs[:self.nb_outputs]\n", + " ys_pred = inputs[self.nb_outputs:]\n", + " loss = self.multi_loss(ys_true, ys_pred)\n", + " self.add_loss(loss, inputs=inputs)\n", + " # We won't actually use the output.\n", + " return K.concatenate(inputs, -1)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "a190207e-5a59-4813-9660-758760cf1b73", + "metadata": {}, + "outputs": [], + "source": [ + "num_heads, ff_dim = 3, 16" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "80f32155-e71f-4615-8d0c-01dfd04988fe", + "metadata": {}, + "outputs": [], + "source": [ + "def get_prediction_model():\n", + " inputs = layers.Input(shape=(1,len(feature_cols)), name='input')\n", + " x = layers.Conv1D(filters=64, kernel_size=1, activation='relu')(inputs)\n", + " # x = layers.Dropout(rate=0.1)(x)\n", + " lstm_out = layers.Bidirectional(layers.LSTM(units=64, return_sequences=True))(x)\n", + " lstm_out = layers.Dense(128, activation='relu')(lstm_out)\n", + " # transformer_block = TransformerBlock(128, num_heads, ff_dim, name='first_attn')\n", + " # out = transformer_block(lstm_out)\n", + " # out = layers.GlobalAveragePooling1D()(out)\n", + " out = layers.Dropout(0.1)(lstm_out)\n", + " out = layers.Dense(64, activation='relu')(out)\n", + " bet = layers.Dense(1, activation='sigmoid', name='vad')(out)\n", + " model = Model(inputs=inputs, outputs=bet)\n", + " return model" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "372011ea-9876-41eb-a4e6-83ccd6c71559", + "metadata": {}, + "outputs": [], + "source": [ + "from tensorflow.python.keras.utils.vis_utils import plot_model" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "1eebdab3-1f88-48a1-b5e0-bc8787528c1b", + "metadata": {}, + "outputs": [], + "source": [ + "maxs = train_data.max()\n", + "mins = train_data.min()\n", + "for col in train_data.columns:\n", + " if maxs[col] - mins[col] == 0:\n", + " continue\n", + " train_data[col] = (train_data[col] - mins[col]) / (maxs[col] - mins[col])" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "7f27bd56-4f6b-4242-9f79-c7d6b3ee2f13", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
化验编号氢Had(%)碳Cad(%)氮Nad(%)氧Oad(%)弹筒发热量Qb,adMJ/kg挥发分Vad(%)固定炭Fcad(%)
00.9965470.7739730.8354140.4565220.1714630.8112490.8477370.828147
10.8511180.6712330.7999430.3695650.2102540.7820380.6748970.794606
\n", + "
" + ], + "text/plain": [ + " 化验编号 氢Had(%) 碳Cad(%) 氮Nad(%) 氧Oad(%) 弹筒发热量Qb,adMJ/kg \\\n", + "0 0.996547 0.773973 0.835414 0.456522 0.171463 0.811249 \n", + "1 0.851118 0.671233 0.799943 0.369565 0.210254 0.782038 \n", + "\n", + " 挥发分Vad(%) 固定炭Fcad(%) \n", + "0 0.847737 0.828147 \n", + "1 0.674897 0.794606 " + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train_data.head(2)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "baf45a3d-dc01-44fc-9f0b-456964ac2cdb", + "metadata": {}, + "outputs": [], + "source": [ + "# feature_cols = [x for x in train_data.columns if x not in out_cols and '第二次' not in x]\n", + "feature_cols = [x for x in train_data.columns if x not in out_cols]\n", + "use_cols = feature_cols + out_cols" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "f2d27538-d2bc-4202-b0cf-d3e0949b4686", + "metadata": {}, + "outputs": [], + "source": [ + "use_data = train_data.copy()\n", + "for col in use_cols:\n", + " use_data[col] = use_data[col].astype('float32')" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "50daf170-efec-49e5-8f8e-9a45938cacfc", + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.model_selection import KFold, train_test_split\n", + "kf = KFold(n_splits=6, shuffle=True, random_state=42)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "0f863423-be12-478b-a08d-e3c6f5dfb8ee", + "metadata": {}, + "outputs": [], + "source": [ + "from tensorflow.keras import optimizers\n", + "from tensorflow.python.keras.utils.vis_utils import plot_model\n", + "from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score, mean_absolute_percentage_error" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "2c89b32a-017c-4d05-ab78-8b9b8eb0dcbb", + "metadata": {}, + "outputs": [], + "source": [ + "from keras.callbacks import ReduceLROnPlateau\n", + "reduce_lr = ReduceLROnPlateau(monitor='val_loss', patience=10, mode='auto')" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "ae24eea7-7dc1-4e33-9d41-3baff07ebb88", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model: \"model_2\"\n", + "_________________________________________________________________\n", + "Layer (type) Output Shape Param # \n", + "=================================================================\n", + "input (InputLayer) [(None, 1, 7)] 0 \n", + "_________________________________________________________________\n", + "conv1d_3 (Conv1D) (None, 1, 64) 512 \n", + "_________________________________________________________________\n", + "bidirectional_3 (Bidirection (None, 1, 128) 66048 \n", + "_________________________________________________________________\n", + "dense_5 (Dense) (None, 1, 128) 16512 \n", + "_________________________________________________________________\n", + "dropout_3 (Dropout) (None, 1, 128) 0 \n", + "_________________________________________________________________\n", + "dense_6 (Dense) (None, 1, 64) 8256 \n", + "_________________________________________________________________\n", + "vad (Dense) (None, 1, 1) 65 \n", + "=================================================================\n", + "Total params: 91,393\n", + "Trainable params: 91,393\n", + "Non-trainable params: 0\n", + "_________________________________________________________________\n" + ] + } + ], + "source": [ + "model = get_prediction_model()\n", + "model.summary()" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "ca6ce434-80b6-4609-9596-9a5120680462", + "metadata": {}, + "outputs": [], + "source": [ + "def print_eva(y_true, y_pred, tp):\n", + " MSE = mean_squared_error(y_true, y_pred)\n", + " RMSE = np.sqrt(MSE)\n", + " MAE = mean_absolute_error(y_true, y_pred)\n", + " MAPE = mean_absolute_percentage_error(y_true, y_pred)\n", + " R_2 = r2_score(y_true, y_pred)\n", + " print(f\"COL: {tp}, MSE: {format(MSE, '.2E')}\", end=',')\n", + " print(f'RMSE: {round(RMSE, 3)}', end=',')\n", + " print(f'MAPE: {round(MAPE * 100, 3)} %', end=',')\n", + " print(f'MAE: {round(MAE, 3)}', end=',')\n", + " print(f'R_2: {round(R_2, 3)}')\n", + " return [MSE, RMSE, MAE, MAPE, R_2]" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "503bbec7-2020-44c8-b622-05bb41082e43", + "metadata": {}, + "outputs": [], + "source": [ + "from keras.losses import mean_squared_error" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "id": "6308b1dc-8e2e-4bf9-9b28-3b81979bf7e0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "COL: 挥发分Vad, MSE: 2.49E-01,RMSE: 0.499,MAPE: 1.336 %,MAE: 0.398,R_2: 0.946\n", + "COL: 挥发分Vad, MSE: 3.81E-01,RMSE: 0.617,MAPE: 1.597 %,MAE: 0.455,R_2: 0.954\n", + "COL: 挥发分Vad, MSE: 5.71E-01,RMSE: 0.756,MAPE: 2.077 %,MAE: 0.621,R_2: 0.854\n", + "WARNING:tensorflow:5 out of the last 45 calls to .predict_function at 0x7f00004145e0> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n", + "COL: 挥发分Vad, MSE: 3.24E-01,RMSE: 0.569,MAPE: 1.575 %,MAE: 0.46,R_2: 0.943\n", + "WARNING:tensorflow:6 out of the last 47 calls to .predict_function at 0x7f0165b81e50> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n", + "COL: 挥发分Vad, MSE: 3.13E-01,RMSE: 0.56,MAPE: 1.548 %,MAE: 0.466,R_2: 0.929\n", + "COL: 挥发分Vad, MSE: 4.94E-01,RMSE: 0.703,MAPE: 1.852 %,MAE: 0.539,R_2: 0.898\n" + ] + } + ], + "source": [ + "vad_eva_list = list()\n", + "fcad_eva_list = list()\n", + "train_data = use_data[use_cols].copy()\n", + "for (train_index, test_index) in kf.split(train_data):\n", + " train = train_data.loc[train_index]\n", + " valid = train_data.loc[test_index]\n", + " X = np.expand_dims(train[feature_cols].values, axis=1)\n", + " Y = [x for x in train[out_cols].values.T]\n", + " X_valid = np.expand_dims(valid[feature_cols].values, axis=1)\n", + " Y_valid = [x for x in valid[out_cols].values.T]\n", + " prediction_model = get_prediction_model()\n", + " prediction_model.compile(optimizer='adam', loss=mean_squared_error)\n", + " hist = prediction_model.fit(X, Y[0], epochs=120, batch_size=8, verbose=0, \n", + " validation_data=(X_valid, Y_valid[0]),\n", + " callbacks=[reduce_lr]\n", + " )\n", + " rst = prediction_model.predict(X_valid).squeeze(axis=1)\n", + " pred_rst = pd.DataFrame.from_records(np.asarray(rst), columns=out_cols)\n", + " real_rst = valid[out_cols].copy()\n", + " for col in out_cols:\n", + " pred_rst[col] = pred_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " real_rst[col] = real_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " y_pred_vad = pred_rst[out_cols].values.reshape(-1,)\n", + " # y_pred_fcad = pred_rst['固定炭Fcad(%)'].values.reshape(-1,)\n", + " y_true_vad = real_rst[out_cols].values.reshape(-1,)\n", + " # y_true_fcad = real_rst['固定炭Fcad(%)'].values.reshape(-1,)\n", + " vad_eva = print_eva(y_true_vad, y_pred_vad, tp='挥发分Vad')\n", + " # fcad_eva = print_eva(y_true_fcad, y_pred_fcad, tp='固定炭Fcad')\n", + " vad_eva_list.append(vad_eva)\n", + " # fcad_eva_list.append(fcad_eva)\n", + " del prediction_model" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "id": "f7132465-89e9-4193-829b-c6e7606cd266", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "COL: 固定炭Fcad, MSE: 1.75E-01,RMSE: 0.419,MAPE: 0.639 %,MAE: 0.339,R_2: 0.993\n", + "COL: 固定炭Fcad, MSE: 2.85E-01,RMSE: 0.534,MAPE: 0.822 %,MAE: 0.386,R_2: 0.994\n", + "COL: 固定炭Fcad, MSE: 2.23E-01,RMSE: 0.472,MAPE: 0.609 %,MAE: 0.344,R_2: 0.984\n", + "COL: 固定炭Fcad, MSE: 1.89E-01,RMSE: 0.435,MAPE: 0.662 %,MAE: 0.318,R_2: 0.994\n", + "COL: 固定炭Fcad, MSE: 2.94E-01,RMSE: 0.542,MAPE: 0.842 %,MAE: 0.446,R_2: 0.986\n", + "COL: 固定炭Fcad, MSE: 2.30E-01,RMSE: 0.48,MAPE: 0.741 %,MAE: 0.386,R_2: 0.99\n" + ] + } + ], + "source": [ + "out_cols = ['固定炭Fcad(%)']\n", + "fcad_eva_list = list()\n", + "train_data = use_data[use_cols].copy()\n", + "for (train_index, test_index) in kf.split(train_data):\n", + " train = train_data.loc[train_index]\n", + " valid = train_data.loc[test_index]\n", + " X = np.expand_dims(train[feature_cols].values, axis=1)\n", + " Y = [x for x in train[out_cols].values.T]\n", + " X_valid = np.expand_dims(valid[feature_cols].values, axis=1)\n", + " Y_valid = [x for x in valid[out_cols].values.T]\n", + " prediction_model = get_prediction_model()\n", + " prediction_model.compile(optimizer='adam', loss=mean_squared_error)\n", + " hist = prediction_model.fit(X, Y[0], epochs=120, batch_size=8, verbose=0, \n", + " validation_data=(X_valid, Y_valid[0]),\n", + " callbacks=[reduce_lr]\n", + " )\n", + " rst = prediction_model.predict(X_valid).squeeze(axis=1)\n", + " pred_rst = pd.DataFrame.from_records(np.asarray(rst), columns=out_cols)\n", + " real_rst = valid[out_cols].copy()\n", + " for col in out_cols:\n", + " pred_rst[col] = pred_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " real_rst[col] = real_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " y_pred = pred_rst[out_cols].values.reshape(-1,)\n", + " y_true = real_rst[out_cols].values.reshape(-1,)\n", + " fcad_eva = print_eva(y_true, y_pred, tp='固定炭Fcad')\n", + " fcad_eva_list.append(fcad_eva)\n", + " del prediction_model" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "id": "27e0abf7-aa29-467f-bc5e-b66a1adf6165", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "MSE 0.388723\n", + "RMSE 0.617294\n", + "MAE 0.489930\n", + "MAPE 0.016641\n", + "R_2 0.920706\n", + "dtype: float64" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vad_df = pd.DataFrame.from_records(vad_eva_list, columns=['MSE', 'RMSE', 'MAE', 'MAPE', 'R_2'])\n", + "vad_df.sort_values(by='R_2').mean()" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "id": "070cdb94-6e7b-4028-b6d5-ba8570c902ba", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "MSE 0.232791\n", + "RMSE 0.480288\n", + "MAE 0.369610\n", + "MAPE 0.007189\n", + "R_2 0.990404\n", + "dtype: float64" + ] + }, + "execution_count": 67, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fcad_df = pd.DataFrame.from_records(fcad_eva_list, columns=['MSE', 'RMSE', 'MAE', 'MAPE', 'R_2'])\n", + "fcad_df.sort_values(by='R_2').mean()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "54c1df2c-c297-4b8d-be8a-3a99cff22545", + "metadata": {}, + "outputs": [], + "source": [ + "train, valid = train_test_split(use_data[use_cols], test_size=0.3, random_state=42, shuffle=True)\n", + "valid, test = train_test_split(valid, test_size=0.3, random_state=42, shuffle=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "e7a914da-b9c2-40d9-96e0-459b0888adba", + "metadata": {}, + "outputs": [], + "source": [ + "prediction_model = get_prediction_model()\n", + "trainable_model = get_trainable_model(prediction_model)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "2494ef5a-5b2b-4f11-b6cd-dc39503c9106", + "metadata": {}, + "outputs": [], + "source": [ + "X = np.expand_dims(train[feature_cols].values, axis=1)\n", + "Y = [x for x in train[out_cols].values.T]\n", + "Y_valid = [x for x in valid[out_cols].values.T]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cf869e4d-0fce-45a2-afff-46fd9b30fd1c", + "metadata": {}, + "outputs": [], + "source": [ + "trainable_model.compile(optimizer='adam', loss=None)\n", + "hist = trainable_model.fit([X, Y[0], Y[1]], epochs=120, batch_size=8, verbose=1, \n", + " validation_data=[np.expand_dims(valid[feature_cols].values, axis=1), Y_valid[0], Y_valid[1]],\n", + " callbacks=[reduce_lr]\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "67bfbe88-5f2c-4659-b2dc-eb9f1b824d04", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[array([[0.73740077],\n", + " [0.89292204],\n", + " [0.7599046 ],\n", + " [0.67802393],\n", + " [0.6815233 ],\n", + " [0.88627005],\n", + " [0.6121343 ],\n", + " [0.7072234 ],\n", + " [0.8561135 ],\n", + " [0.52762157],\n", + " [0.8325021 ],\n", + " [0.50241977],\n", + " [0.8242289 ],\n", + " [0.68957335],\n", + " [0.6980361 ],\n", + " [0.82116604],\n", + " [0.8566438 ],\n", + " [0.53687835],\n", + " [0.56832707],\n", + " [0.78476715],\n", + " [0.85638577]], dtype=float32),\n", + " array([[0.68600863],\n", + " [0.78454906],\n", + " [0.8179163 ],\n", + " [0.94351083],\n", + " [0.86383885],\n", + " [0.69705516],\n", + " [0.6913491 ],\n", + " [0.80277354],\n", + " [0.93557894],\n", + " [0.82278305],\n", + " [0.82674253],\n", + " [0.93518937],\n", + " [0.8094449 ],\n", + " [0.9206344 ],\n", + " [0.7747319 ],\n", + " [0.9137207 ],\n", + " [0.9491073 ],\n", + " [0.93225 ],\n", + " [0.6185102 ],\n", + " [0.8867341 ],\n", + " [0.82890105]], dtype=float32)]" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rst = prediction_model.predict(np.expand_dims(test[feature_cols], axis=1))\n", + "rst" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "7de501e9-05a2-424c-a5f4-85d43ad37592", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[0.9991559102070927, 0.9998196796918477]" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[np.exp(K.get_value(log_var[0]))**0.5 for log_var in trainable_model.layers[-1].log_vars]" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "5c69d03b-34fd-4dbf-aec6-c15093bb22ab", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['挥发分Vad(%)', '固定炭Fcad(%)'], dtype='object')" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "real_rst.columns" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "294813b8-90be-4007-9fd6-c26ee7bb9652", + "metadata": {}, + "outputs": [], + "source": [ + "for col in out_cols:\n", + " pred_rst[col] = pred_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " real_rst[col] = real_rst[col] * (maxs[col] - mins[col]) + mins[col]" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "21739f82-d82a-4bde-8537-9504b68a96d5", + "metadata": {}, + "outputs": [], + "source": [ + "y_pred_vad = pred_rst['挥发分Vad(%)'].values.reshape(-1,)\n", + "y_pred_fcad = pred_rst['固定炭Fcad(%)'].values.reshape(-1,)\n", + "y_true_vad = real_rst['挥发分Vad(%)'].values.reshape(-1,)\n", + "y_true_fcad = real_rst['固定炭Fcad(%)'].values.reshape(-1,)" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "id": "4ec4caa9-7c46-4fc8-a94b-cb659e924304", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "COL: 挥发分Vad, MSE: 3.35E-01,RMSE: 0.579,MAPE: 1.639 %,MAE: 0.504,R_2: 0.87\n", + "COL: 固定炭Fcad, MSE: 1.11E+00,RMSE: 1.055,MAPE: 1.497 %,MAE: 0.814,R_2: 0.876\n" + ] + } + ], + "source": [ + "pm25_eva = print_eva(y_true_vad, y_pred_vad, tp='挥发分Vad')\n", + "pm10_eva = print_eva(y_true_fcad, y_pred_fcad, tp='固定炭Fcad')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ac4a4339-ec7d-4266-8197-5276c2395288", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f15cbb91-1ce7-4fb0-979a-a4bdc452a1ec", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.16" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/model.png b/model.png new file mode 100644 index 0000000000000000000000000000000000000000..f43081e14809314719985a066d81edec61693275 GIT binary patch literal 33997 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 Vnwti=0B;TH&8xQ(1ux%y`ClO)VRZli literal 0 HcmV?d00001 diff --git a/multi-task0102.ipynb b/multi-task0102.ipynb index e833668..3f3c53f 100644 --- a/multi-task0102.ipynb +++ b/multi-task0102.ipynb @@ -549,7 +549,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2024-01-04 16:49:03.492957: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0\n" + "2024-01-05 16:46:07.061819: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0\n" ] } ], @@ -563,51 +563,6 @@ { "cell_type": "code", "execution_count": 12, - "id": "c2318ce6-60d2-495c-91cd-67ca53609cf8", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING:tensorflow:From /tmp/ipykernel_45930/337460670.py:1: is_gpu_available (from tensorflow.python.framework.test_util) is deprecated and will be removed in a future version.\n", - "Instructions for updating:\n", - "Use `tf.config.list_physical_devices('GPU')` instead.\n" - ] - }, - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2024-01-04 16:49:04.396035: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 AVX512F FMA\n", - "To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", - "2024-01-04 16:49:04.407586: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcuda.so.1\n", - "2024-01-04 16:49:04.465739: E tensorflow/stream_executor/cuda/cuda_driver.cc:328] failed call to cuInit: CUDA_ERROR_INVALID_DEVICE: invalid device ordinal\n", - "2024-01-04 16:49:04.465795: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:169] retrieving CUDA diagnostic information for host: zhaojh-yv621\n", - "2024-01-04 16:49:04.465807: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:176] hostname: zhaojh-yv621\n", - "2024-01-04 16:49:04.466010: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:200] libcuda reported version is: 520.61.5\n", - "2024-01-04 16:49:04.466041: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:204] kernel reported version is: 520.61.5\n", - "2024-01-04 16:49:04.466045: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:310] kernel version seems to match DSO: 520.61.5\n" - ] - } - ], - "source": [ - "tf.test.is_gpu_available()" - ] - }, - { - "cell_type": "code", - "execution_count": 13, "id": "1c85d462-f248-4ffb-908f-eb4b20eab179", "metadata": {}, "outputs": [], @@ -635,7 +590,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 13, "id": "790284a3-b9d3-4144-b481-38a7c3ecb4b9", "metadata": {}, "outputs": [], @@ -645,7 +600,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 14, "id": "cd9a1ca1-d0ca-4cb5-9ef5-fd5d63576cd2", "metadata": {}, "outputs": [], @@ -655,7 +610,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 15, "id": "9bc02f29-0fb7-420d-99a8-435eadc06e29", "metadata": {}, "outputs": [], @@ -695,7 +650,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 16, "id": "a190207e-5a59-4813-9660-758760cf1b73", "metadata": {}, "outputs": [], @@ -705,20 +660,12 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 29, "id": "80f32155-e71f-4615-8d0c-01dfd04988fe", "metadata": {}, "outputs": [], "source": [ "def get_prediction_model():\n", - " def build_output(out, out_name):\n", - " self_block = TransformerBlock(64, num_heads, ff_dim, name=f'{out_name}_attn')\n", - " out = self_block(out)\n", - " out = layers.GlobalAveragePooling1D()(out)\n", - " out = layers.Dropout(0.1)(out)\n", - " out = layers.Dense(32, activation=\"relu\")(out)\n", - " # out = layers.Dense(1, name=out_name, activation=\"sigmoid\")(out)\n", - " return out\n", " inputs = layers.Input(shape=(1,len(feature_cols)), name='input')\n", " x = layers.Conv1D(filters=64, kernel_size=1, activation='relu')(inputs)\n", " # x = layers.Dropout(rate=0.1)(x)\n", @@ -729,10 +676,10 @@ " out = layers.GlobalAveragePooling1D()(out)\n", " out = layers.Dropout(0.1)(out)\n", " out = layers.Dense(64, activation='relu')(out)\n", - " out = K.expand_dims(out, axis=1)\n", + " # out = K.expand_dims(out, axis=1)\n", "\n", - " bet = build_output(out, 'vad')\n", - " mesco = build_output(out, 'fcad')\n", + " bet = layers.Dense(32, activation=\"relu\")(out)\n", + " mesco = layers.Dense(32, activation=\"relu\")(out)\n", "\n", " bet = layers.Dense(1, activation='sigmoid', name='vad')(bet)\n", " mesco = layers.Dense(1, activation='sigmoid', name='fcad')(mesco)\n", @@ -743,7 +690,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 18, "id": "264001b1-5e4a-4786-96fd-2b5c70ab3212", "metadata": {}, "outputs": [], @@ -757,6 +704,16 @@ " return Model([inputs, bet_real, mesco_real], out)" ] }, + { + "cell_type": "code", + "execution_count": 19, + "id": "372011ea-9876-41eb-a4e6-83ccd6c71559", + "metadata": {}, + "outputs": [], + "source": [ + "from tensorflow.python.keras.utils.vis_utils import plot_model" + ] + }, { "cell_type": "code", "execution_count": 20, @@ -1002,6 +959,220 @@ { "cell_type": "code", "execution_count": 24, + "id": "50daf170-efec-49e5-8f8e-9a45938cacfc", + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.model_selection import KFold, train_test_split\n", + "kf = KFold(n_splits=6, shuffle=True, random_state=42)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "0f863423-be12-478b-a08d-e3c6f5dfb8ee", + "metadata": {}, + "outputs": [], + "source": [ + "from tensorflow.keras import optimizers\n", + "from tensorflow.python.keras.utils.vis_utils import plot_model\n", + "from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score, mean_absolute_percentage_error" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "2c89b32a-017c-4d05-ab78-8b9b8eb0dcbb", + "metadata": {}, + "outputs": [], + "source": [ + "from keras.callbacks import ReduceLROnPlateau\n", + "reduce_lr = ReduceLROnPlateau(monitor='val_loss', patience=10, mode='auto')" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "ca6ce434-80b6-4609-9596-9a5120680462", + "metadata": {}, + "outputs": [], + "source": [ + "def print_eva(y_true, y_pred, tp):\n", + " MSE = mean_squared_error(y_true, y_pred)\n", + " RMSE = np.sqrt(MSE)\n", + " MAE = mean_absolute_error(y_true, y_pred)\n", + " MAPE = mean_absolute_percentage_error(y_true, y_pred)\n", + " R_2 = r2_score(y_true, y_pred)\n", + " print(f\"COL: {tp}, MSE: {format(MSE, '.2E')}\", end=',')\n", + " print(f'RMSE: {round(RMSE, 3)}', end=',')\n", + " print(f'MAPE: {round(MAPE * 100, 3)} %', end=',')\n", + " print(f'MAE: {round(MAE, 3)}', end=',')\n", + " print(f'R_2: {round(R_2, 3)}')\n", + " return [MSE, RMSE, MAE, MAPE, R_2]" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "10213bc5-bf13-46ed-9ce9-b1dbc5af72ee", + "metadata": {}, + "outputs": [], + "source": [ + "prediction_model = get_prediction_model()\n", + "trainable_model = get_trainable_model(prediction_model)\n", + "trainable_model.compile(optimizer='adam', loss=None)" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "4a1be90d-b8f1-4fe1-9952-1cdcc489fab5", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "plot_model(prediction_model)" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "6308b1dc-8e2e-4bf9-9b28-3b81979bf7e0", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-01-05 16:53:33.639598: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:176] None of the MLIR Optimization Passes are enabled (registered 2)\n", + "2024-01-05 16:53:33.658810: I tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 2200000000 Hz\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "COL: 挥发分Vad, MSE: 1.73E+00,RMSE: 1.316,MAPE: 3.178 %,MAE: 0.961,R_2: 0.626\n", + "COL: 固定炭Fcad, MSE: 2.28E+02,RMSE: 15.111,MAPE: 28.087 %,MAE: 15.088,R_2: -8.016\n", + "COL: 挥发分Vad, MSE: 8.81E-01,RMSE: 0.939,MAPE: 2.56 %,MAE: 0.745,R_2: 0.893\n", + "COL: 固定炭Fcad, MSE: 1.18E+00,RMSE: 1.085,MAPE: 1.679 %,MAE: 0.836,R_2: 0.977\n", + "COL: 挥发分Vad, MSE: 4.92E-01,RMSE: 0.701,MAPE: 1.855 %,MAE: 0.548,R_2: 0.874\n", + "COL: 固定炭Fcad, MSE: 9.80E-01,RMSE: 0.99,MAPE: 1.413 %,MAE: 0.774,R_2: 0.93\n", + "COL: 挥发分Vad, MSE: 4.56E+01,RMSE: 6.756,MAPE: 22.559 %,MAE: 6.7,R_2: -6.995\n", + "COL: 固定炭Fcad, MSE: 1.12E+02,RMSE: 10.605,MAPE: 20.153 %,MAE: 10.579,R_2: -2.311\n", + "WARNING:tensorflow:5 out of the last 9 calls to .predict_function at 0x7f2c5ec9aa60> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n", + "COL: 挥发分Vad, MSE: 8.31E-01,RMSE: 0.912,MAPE: 2.389 %,MAE: 0.728,R_2: 0.811\n", + "COL: 固定炭Fcad, MSE: 1.75E+02,RMSE: 13.221,MAPE: 24.517 %,MAE: 13.188,R_2: -7.209\n", + "WARNING:tensorflow:6 out of the last 11 calls to .predict_function at 0x7f2c5e414940> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n", + "COL: 挥发分Vad, MSE: 5.16E-01,RMSE: 0.719,MAPE: 2.022 %,MAE: 0.591,R_2: 0.894\n", + "COL: 固定炭Fcad, MSE: 1.33E+00,RMSE: 1.154,MAPE: 1.496 %,MAE: 0.739,R_2: 0.944\n" + ] + } + ], + "source": [ + "vad_eva_list = list()\n", + "fcad_eva_list = list()\n", + "train_data = use_data[use_cols].copy()\n", + "for (train_index, test_index) in kf.split(train_data):\n", + " train = train_data.loc[train_index]\n", + " valid = train_data.loc[test_index]\n", + " X = np.expand_dims(train[feature_cols].values, axis=1)\n", + " Y = [x for x in train[out_cols].values.T]\n", + " X_valid = np.expand_dims(valid[feature_cols].values, axis=1)\n", + " Y_valid = [x for x in valid[out_cols].values.T]\n", + " prediction_model = get_prediction_model()\n", + " trainable_model = get_trainable_model(prediction_model)\n", + " trainable_model.compile(optimizer='adam', loss=None)\n", + " hist = trainable_model.fit([X, Y[0], Y[1]], epochs=120, batch_size=8, verbose=0, \n", + " validation_data=[X_valid, Y_valid[0], Y_valid[1]],\n", + " callbacks=[reduce_lr]\n", + " )\n", + " rst = prediction_model.predict(X_valid)\n", + " pred_rst = pd.DataFrame.from_records(np.squeeze(np.asarray(rst), axis=2).T, columns=out_cols)\n", + " real_rst = valid[out_cols].copy()\n", + " for col in out_cols:\n", + " pred_rst[col] = pred_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " real_rst[col] = real_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " y_pred_vad = pred_rst['挥发分Vad(%)'].values.reshape(-1,)\n", + " y_pred_fcad = pred_rst['固定炭Fcad(%)'].values.reshape(-1,)\n", + " y_true_vad = real_rst['挥发分Vad(%)'].values.reshape(-1,)\n", + " y_true_fcad = real_rst['固定炭Fcad(%)'].values.reshape(-1,)\n", + " vad_eva = print_eva(y_true_vad, y_pred_vad, tp='挥发分Vad')\n", + " fcad_eva = print_eva(y_true_fcad, y_pred_fcad, tp='固定炭Fcad')\n", + " vad_eva_list.append(vad_eva)\n", + " fcad_eva_list.append(fcad_eva)\n", + " del trainable_model\n", + " del prediction_model" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "27e0abf7-aa29-467f-bc5e-b66a1adf6165", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "MSE 0.890323\n", + "RMSE 0.917209\n", + "MAE 0.714643\n", + "MAPE 0.024009\n", + "R_2 0.819531\n", + "dtype: float64" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vad_df = pd.DataFrame.from_records(vad_eva_list, columns=['MSE', 'RMSE', 'MAE', 'MAPE', 'R_2'])\n", + "vad_df.sort_values(by='R_2')[1:].mean()" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "070cdb94-6e7b-4028-b6d5-ba8570c902ba", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "MSE 58.149181\n", + "RMSE 5.410969\n", + "MAE 5.223220\n", + "MAPE 0.098516\n", + "R_2 -1.333914\n", + "dtype: float64" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fcad_df = pd.DataFrame.from_records(fcad_eva_list, columns=['MSE', 'RMSE', 'MAE', 'MAPE', 'R_2'])\n", + "fcad_df.sort_values(by='R_2')[1:].mean()" + ] + }, + { + "cell_type": "code", + "execution_count": null, "id": "54c1df2c-c297-4b8d-be8a-3a99cff22545", "metadata": {}, "outputs": [], @@ -1021,80 +1192,6 @@ "trainable_model = get_trainable_model(prediction_model)" ] }, - { - "cell_type": "code", - "execution_count": 32, - "id": "4f832a1e-48e2-4467-b381-35b9d2f1271a", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Model: \"model_3\"\n", - "__________________________________________________________________________________________________\n", - "Layer (type) Output Shape Param # Connected to \n", - "==================================================================================================\n", - "input (InputLayer) [(None, 1, 6)] 0 \n", - "__________________________________________________________________________________________________\n", - "conv1d_3 (Conv1D) (None, 1, 64) 448 input[0][0] \n", - "__________________________________________________________________________________________________\n", - "bidirectional_3 (Bidirectional) (None, 1, 128) 66048 conv1d_3[0][0] \n", - "__________________________________________________________________________________________________\n", - "dense_30 (Dense) (None, 1, 128) 16512 bidirectional_3[0][0] \n", - "__________________________________________________________________________________________________\n", - "transformer_block_9 (Transforme (None, 1, 128) 202640 dense_30[0][0] \n", - "__________________________________________________________________________________________________\n", - "global_average_pooling1d_9 (Glo (None, 128) 0 transformer_block_9[0][0] \n", - "__________________________________________________________________________________________________\n", - "dropout_29 (Dropout) (None, 128) 0 global_average_pooling1d_9[0][0] \n", - "__________________________________________________________________________________________________\n", - "dense_33 (Dense) (None, 64) 8256 dropout_29[0][0] \n", - "__________________________________________________________________________________________________\n", - "tf.expand_dims_3 (TFOpLambda) (None, 1, 64) 0 dense_33[0][0] \n", - "__________________________________________________________________________________________________\n", - "transformer_block_10 (Transform (None, 1, 64) 52176 tf.expand_dims_3[0][0] \n", - "__________________________________________________________________________________________________\n", - "transformer_block_11 (Transform (None, 1, 64) 52176 tf.expand_dims_3[0][0] \n", - "__________________________________________________________________________________________________\n", - "global_average_pooling1d_10 (Gl (None, 64) 0 transformer_block_10[0][0] \n", - "__________________________________________________________________________________________________\n", - "global_average_pooling1d_11 (Gl (None, 64) 0 transformer_block_11[0][0] \n", - "__________________________________________________________________________________________________\n", - "dropout_32 (Dropout) (None, 64) 0 global_average_pooling1d_10[0][0]\n", - "__________________________________________________________________________________________________\n", - "dropout_35 (Dropout) (None, 64) 0 global_average_pooling1d_11[0][0]\n", - "__________________________________________________________________________________________________\n", - "dense_36 (Dense) (None, 32) 2080 dropout_32[0][0] \n", - "__________________________________________________________________________________________________\n", - "dense_39 (Dense) (None, 32) 2080 dropout_35[0][0] \n", - "__________________________________________________________________________________________________\n", - "vad (Dense) (None, 1) 33 dense_36[0][0] \n", - "__________________________________________________________________________________________________\n", - "fcad (Dense) (None, 1) 33 dense_39[0][0] \n", - "==================================================================================================\n", - "Total params: 402,482\n", - "Trainable params: 402,482\n", - "Non-trainable params: 0\n", - "__________________________________________________________________________________________________\n" - ] - } - ], - "source": [ - "prediction_model.summary()" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "id": "9289f452-a5a4-40c4-b942-f6cb2e348548", - "metadata": {}, - "outputs": [], - "source": [ - "from tensorflow.keras import optimizers\n", - "from tensorflow.python.keras.utils.vis_utils import plot_model" - ] - }, { "cell_type": "code", "execution_count": 34, @@ -1109,268 +1206,10 @@ }, { "cell_type": "code", - "execution_count": 35, - "id": "9a62dea1-4f05-411b-9756-a91623580581", - "metadata": {}, - "outputs": [], - "source": [ - "from keras.callbacks import ReduceLROnPlateau\n", - "reduce_lr = ReduceLROnPlateau(monitor='val_loss', patience=10, mode='auto')" - ] - }, - { - "cell_type": "code", - "execution_count": 40, + "execution_count": null, "id": "cf869e4d-0fce-45a2-afff-46fd9b30fd1c", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Epoch 1/120\n", - "20/20 [==============================] - 5s 59ms/step - loss: 1.8316 - val_loss: 1.8096\n", - "Epoch 2/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 1.7903 - val_loss: 1.7691\n", - "Epoch 3/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 1.7506 - val_loss: 1.7307\n", - "Epoch 4/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 1.7110 - val_loss: 1.6914\n", - "Epoch 5/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 1.6711 - val_loss: 1.6497\n", - "Epoch 6/120\n", - "20/20 [==============================] - 0s 24ms/step - loss: 1.6314 - val_loss: 1.6098\n", - "Epoch 7/120\n", - "20/20 [==============================] - 0s 24ms/step - loss: 1.5909 - val_loss: 1.5695\n", - "Epoch 8/120\n", - "20/20 [==============================] - 0s 24ms/step - loss: 1.5506 - val_loss: 1.5296\n", - "Epoch 9/120\n", - "20/20 [==============================] - 0s 24ms/step - loss: 1.5109 - val_loss: 1.4891\n", - "Epoch 10/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 1.4706 - val_loss: 1.4500\n", - "Epoch 11/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 1.4306 - val_loss: 1.4104\n", - "Epoch 12/120\n", - "20/20 [==============================] - 0s 22ms/step - loss: 1.3907 - val_loss: 1.3746\n", - "Epoch 13/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 1.3508 - val_loss: 1.3296\n", - "Epoch 14/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 1.3106 - val_loss: 1.2895\n", - "Epoch 15/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 1.2706 - val_loss: 1.2515\n", - "Epoch 16/120\n", - "20/20 [==============================] - 0s 22ms/step - loss: 1.2315 - val_loss: 1.2104\n", - "Epoch 17/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 1.1908 - val_loss: 1.1702\n", - "Epoch 18/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 1.1508 - val_loss: 1.1320\n", - "Epoch 19/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 1.1114 - val_loss: 1.0917\n", - "Epoch 20/120\n", - "20/20 [==============================] - 0s 24ms/step - loss: 1.0718 - val_loss: 1.0513\n", - "Epoch 21/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 1.0315 - val_loss: 1.0178\n", - "Epoch 22/120\n", - "20/20 [==============================] - 0s 24ms/step - loss: 0.9918 - val_loss: 0.9704\n", - "Epoch 23/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.9511 - val_loss: 0.9321\n", - "Epoch 24/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.9114 - val_loss: 0.8913\n", - "Epoch 25/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.8718 - val_loss: 0.8520\n", - "Epoch 26/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.8314 - val_loss: 0.8124\n", - "Epoch 27/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.7922 - val_loss: 0.7727\n", - "Epoch 28/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.7519 - val_loss: 0.7307\n", - "Epoch 29/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.7119 - val_loss: 0.6932\n", - "Epoch 30/120\n", - "20/20 [==============================] - 0s 22ms/step - loss: 0.6720 - val_loss: 0.6531\n", - "Epoch 31/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.6336 - val_loss: 0.6155\n", - "Epoch 32/120\n", - "20/20 [==============================] - 1s 26ms/step - loss: 0.5931 - val_loss: 0.5738\n", - "Epoch 33/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.5517 - val_loss: 0.5324\n", - "Epoch 34/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.5135 - val_loss: 0.4943\n", - "Epoch 35/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 0.4724 - val_loss: 0.4602\n", - "Epoch 36/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.4326 - val_loss: 0.4126\n", - "Epoch 37/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.3947 - val_loss: 0.3758\n", - "Epoch 38/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.3558 - val_loss: 0.3350\n", - "Epoch 39/120\n", - "20/20 [==============================] - 0s 22ms/step - loss: 0.3154 - val_loss: 0.3031\n", - "Epoch 40/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.2771 - val_loss: 0.2592\n", - "Epoch 41/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.2459 - val_loss: 0.2370\n", - "Epoch 42/120\n", - "20/20 [==============================] - 1s 27ms/step - loss: 0.2267 - val_loss: 0.2210\n", - "Epoch 43/120\n", - "20/20 [==============================] - 0s 24ms/step - loss: 0.2050 - val_loss: 0.1947\n", - "Epoch 44/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.1840 - val_loss: 0.1728\n", - "Epoch 45/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 0.1628 - val_loss: 0.1533\n", - "Epoch 46/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.1430 - val_loss: 0.1322\n", - "Epoch 47/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.1230 - val_loss: 0.1147\n", - "Epoch 48/120\n", - "20/20 [==============================] - 1s 24ms/step - loss: 0.1026 - val_loss: 0.0940\n", - "Epoch 49/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0830 - val_loss: 0.0750\n", - "Epoch 50/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0639 - val_loss: 0.0529\n", - "Epoch 51/120\n", - "20/20 [==============================] - 0s 22ms/step - loss: 0.0436 - val_loss: 0.0352\n", - "Epoch 52/120\n", - "20/20 [==============================] - 0s 24ms/step - loss: 0.0241 - val_loss: 0.0162\n", - "Epoch 53/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0092 - val_loss: 0.0084\n", - "Epoch 54/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0067 - val_loss: 0.0074\n", - "Epoch 55/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0080 - val_loss: 0.0071\n", - "Epoch 56/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0070 - val_loss: 0.0063\n", - "Epoch 57/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0062 - val_loss: 0.0076\n", - "Epoch 58/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0056 - val_loss: 0.0048\n", - "Epoch 59/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0050 - val_loss: 0.0071\n", - "Epoch 60/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0057 - val_loss: 0.0054\n", - "Epoch 61/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0044 - val_loss: 0.0092\n", - "Epoch 62/120\n", - "20/20 [==============================] - 1s 26ms/step - loss: 0.0068 - val_loss: 0.0070\n", - "Epoch 63/120\n", - "20/20 [==============================] - 1s 24ms/step - loss: 0.0059 - val_loss: 0.0065\n", - "Epoch 64/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0055 - val_loss: 0.0060\n", - "Epoch 65/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0053 - val_loss: 0.0056\n", - "Epoch 66/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0058 - val_loss: 0.0077\n", - "Epoch 67/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0051 - val_loss: 0.0054\n", - "Epoch 68/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 0.0047 - val_loss: 0.0048\n", - "Epoch 69/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0041 - val_loss: 0.0048\n", - "Epoch 70/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0037 - val_loss: 0.0049\n", - "Epoch 71/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0041 - val_loss: 0.0049\n", - "Epoch 72/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 0.0036 - val_loss: 0.0049\n", - "Epoch 73/120\n", - "20/20 [==============================] - 1s 24ms/step - loss: 0.0038 - val_loss: 0.0048\n", - "Epoch 74/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0037 - val_loss: 0.0050\n", - "Epoch 75/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0037 - val_loss: 0.0048\n", - "Epoch 76/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0038 - val_loss: 0.0048\n", - "Epoch 77/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 0.0037 - val_loss: 0.0048\n", - "Epoch 78/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0038 - val_loss: 0.0048\n", - "Epoch 79/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0036 - val_loss: 0.0048\n", - "Epoch 80/120\n", - "20/20 [==============================] - 0s 22ms/step - loss: 0.0034 - val_loss: 0.0048\n", - "Epoch 81/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0034 - val_loss: 0.0047\n", - "Epoch 82/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0037 - val_loss: 0.0047\n", - "Epoch 83/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0033 - val_loss: 0.0047\n", - "Epoch 84/120\n", - "20/20 [==============================] - 0s 22ms/step - loss: 0.0037 - val_loss: 0.0047\n", - "Epoch 85/120\n", - "20/20 [==============================] - 0s 24ms/step - loss: 0.0036 - val_loss: 0.0047\n", - "Epoch 86/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0034 - val_loss: 0.0047\n", - "Epoch 87/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0034 - val_loss: 0.0047\n", - "Epoch 88/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0034 - val_loss: 0.0047\n", - "Epoch 89/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 0.0036 - val_loss: 0.0047\n", - "Epoch 90/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0036 - val_loss: 0.0047\n", - "Epoch 91/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0036 - val_loss: 0.0047\n", - "Epoch 92/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0034 - val_loss: 0.0047\n", - "Epoch 93/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0034 - val_loss: 0.0047\n", - "Epoch 94/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0037 - val_loss: 0.0047\n", - "Epoch 95/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 0.0035 - val_loss: 0.0047\n", - "Epoch 96/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0032 - val_loss: 0.0047\n", - "Epoch 97/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0035 - val_loss: 0.0047\n", - "Epoch 98/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 0.0038 - val_loss: 0.0047\n", - "Epoch 99/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0033 - val_loss: 0.0047\n", - "Epoch 100/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0036 - val_loss: 0.0047\n", - "Epoch 101/120\n", - "20/20 [==============================] - 1s 26ms/step - loss: 0.0033 - val_loss: 0.0047\n", - "Epoch 102/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0035 - val_loss: 0.0047\n", - "Epoch 103/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0035 - val_loss: 0.0047\n", - "Epoch 104/120\n", - "20/20 [==============================] - 0s 22ms/step - loss: 0.0035 - val_loss: 0.0047\n", - "Epoch 105/120\n", - "20/20 [==============================] - 0s 23ms/step - loss: 0.0036 - val_loss: 0.0047\n", - "Epoch 106/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0034 - val_loss: 0.0047\n", - "Epoch 107/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0036 - val_loss: 0.0047\n", - "Epoch 108/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 0.0034 - val_loss: 0.0047\n", - "Epoch 109/120\n", - "20/20 [==============================] - 1s 24ms/step - loss: 0.0037 - val_loss: 0.0047\n", - "Epoch 110/120\n", - "20/20 [==============================] - 0s 24ms/step - loss: 0.0038 - val_loss: 0.0047\n", - "Epoch 111/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0036 - val_loss: 0.0047\n", - "Epoch 112/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0035 - val_loss: 0.0047\n", - "Epoch 113/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0037 - val_loss: 0.0047\n", - "Epoch 114/120\n", - "20/20 [==============================] - 0s 20ms/step - loss: 0.0035 - val_loss: 0.0047\n", - "Epoch 115/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0033 - val_loss: 0.0047\n", - "Epoch 116/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 0.0036 - val_loss: 0.0047\n", - "Epoch 117/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0032 - val_loss: 0.0047\n", - "Epoch 118/120\n", - "20/20 [==============================] - 0s 26ms/step - loss: 0.0036 - val_loss: 0.0047\n", - "Epoch 119/120\n", - "20/20 [==============================] - 0s 25ms/step - loss: 0.0037 - val_loss: 0.0047\n", - "Epoch 120/120\n", - "20/20 [==============================] - 0s 21ms/step - loss: 0.0036 - val_loss: 0.0047\n" - ] - } - ], + "outputs": [], "source": [ "trainable_model.compile(optimizer='adam', loss=None)\n", "hist = trainable_model.fit([X, Y[0], Y[1]], epochs=120, batch_size=8, verbose=1, \n", @@ -1463,38 +1302,6 @@ "[np.exp(K.get_value(log_var[0]))**0.5 for log_var in trainable_model.layers[-1].log_vars]" ] }, - { - "cell_type": "code", - "execution_count": 43, - "id": "b0d5d8ad-aadd-4218-b5b7-9691a2d3eeef", - "metadata": {}, - "outputs": [], - "source": [ - "pred_rst = pd.DataFrame.from_records(np.squeeze(np.asarray(rst), axis=2).T, columns=out_cols)" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "id": "0a2bcb45-da86-471b-a61d-314e29430d6a", - "metadata": {}, - "outputs": [], - "source": [ - "real_rst = test[out_cols].copy()" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "id": "e124f7c0-fdd5-43b9-b649-ff7d9dd59641", - "metadata": {}, - "outputs": [], - "source": [ - "for col in out_cols:\n", - " pred_rst[col] = pred_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", - " real_rst[col] = real_rst[col] * (maxs[col] - mins[col]) + mins[col]" - ] - }, { "cell_type": "code", "execution_count": 46, @@ -1516,6 +1323,18 @@ "real_rst.columns" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "294813b8-90be-4007-9fd6-c26ee7bb9652", + "metadata": {}, + "outputs": [], + "source": [ + "for col in out_cols:\n", + " pred_rst[col] = pred_rst[col] * (maxs[col] - mins[col]) + mins[col]\n", + " real_rst[col] = real_rst[col] * (maxs[col] - mins[col]) + mins[col]" + ] + }, { "cell_type": "code", "execution_count": 47, @@ -1529,37 +1348,6 @@ "y_true_fcad = real_rst['固定炭Fcad(%)'].values.reshape(-1,)" ] }, - { - "cell_type": "code", - "execution_count": 48, - "id": "26ea6cfa-efad-443c-9dd9-844f8be42b91", - "metadata": {}, - "outputs": [], - "source": [ - "from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score, mean_absolute_percentage_error" - ] - }, - { - "cell_type": "code", - "execution_count": 55, - "id": "28072e7c-c9d5-4ff6-940d-e94ae879afc9", - "metadata": {}, - "outputs": [], - "source": [ - "def print_eva(y_true, y_pred, tp):\n", - " MSE = mean_squared_error(y_true, y_pred)\n", - " RMSE = np.sqrt(MSE)\n", - " MAE = mean_absolute_error(y_true, y_pred)\n", - " MAPE = mean_absolute_percentage_error(y_true, y_pred)\n", - " R_2 = r2_score(y_true, y_pred)\n", - " print(f\"COL: {tp}, MSE: {format(MSE, '.2E')}\", end=',')\n", - " print(f'RMSE: {round(RMSE, 3)}', end=',')\n", - " print(f'MAPE: {round(MAPE * 100, 3)} %', end=',')\n", - " print(f'MAE: {round(MAE, 3)}', end=',')\n", - " print(f'R_2: {round(R_2, 3)}')\n", - " return [MSE, RMSE, MAE, MAPE, R_2]" - ] - }, { "cell_type": "code", "execution_count": 56,