diff --git a/22-06-17-DL/Diamond_custom.ipynb b/22-06-17-DL/Diamond_custom.ipynb new file mode 100644 index 0000000..2e67993 --- /dev/null +++ b/22-06-17-DL/Diamond_custom.ipynb @@ -0,0 +1,1498 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "name": "Keras.ipynb", + "provenance": [], + "toc_visible": true, + "authorship_tag": "ABX9TyMHa43EodRi7Ii/GrWrt/mn", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "DataSet: https://www.kaggle.com/datasets/shivam2503/diamonds" + ], + "metadata": { + "id": "6e_s7G9AmmF4" + } + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "2_wrKy6tmWDP", + "outputId": "79d314a2-77be-426b-db75-c0cc73cc8cdd" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Archive: /content/archive.zip\n", + " inflating: diamonds.csv \n" + ] + } + ], + "source": [ + "! unzip /content/archive.zip" + ] + }, + { + "cell_type": "code", + "source": [ + "SEED = 40" + ], + "metadata": { + "id": "bfzq2tmZkLNe" + }, + "execution_count": 12, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "import numpy as np\n", + "import pandas as pd" + ], + "metadata": { + "id": "l_YDxihVmtKc" + }, + "execution_count": 4, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "df = pd.read_csv('diamonds.csv')\n", + "df.head()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "id": "ZGlvfpy_mybm", + "outputId": "5cf885cc-5f38-4698-c8d1-c152b91f8595" + }, + "execution_count": 5, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " Unnamed: 0 carat cut color clarity depth table price x y \\\n", + "0 1 0.23 Ideal E SI2 61.5 55.0 326 3.95 3.98 \n", + "1 2 0.21 Premium E SI1 59.8 61.0 326 3.89 3.84 \n", + "2 3 0.23 Good E VS1 56.9 65.0 327 4.05 4.07 \n", + "3 4 0.29 Premium I VS2 62.4 58.0 334 4.20 4.23 \n", + "4 5 0.31 Good J SI2 63.3 58.0 335 4.34 4.35 \n", + "\n", + " z \n", + "0 2.43 \n", + "1 2.31 \n", + "2 2.31 \n", + "3 2.63 \n", + "4 2.75 " + ], + "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", + "
Unnamed: 0caratcutcolorclaritydepthtablepricexyz
010.23IdealESI261.555.03263.953.982.43
120.21PremiumESI159.861.03263.893.842.31
230.23GoodEVS156.965.03274.054.072.31
340.29PremiumIVS262.458.03344.204.232.63
450.31GoodJSI263.358.03354.344.352.75
\n", + "
\n", + " \n", + " \n", + " \n", + "\n", + " \n", + "
\n", + "
\n", + " " + ] + }, + "metadata": {}, + "execution_count": 5 + } + ] + }, + { + "cell_type": "code", + "source": [ + "df.drop('Unnamed: 0', axis=1, inplace = True)" + ], + "metadata": { + "id": "ggmAfo5qp4Ss" + }, + "execution_count": 6, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "df.isna().sum()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "3-4KdSBOm3xG", + "outputId": "0f6a0062-e0f8-4eed-9c65-fe4fce55b17b" + }, + "execution_count": 7, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "carat 0\n", + "cut 0\n", + "color 0\n", + "clarity 0\n", + "depth 0\n", + "table 0\n", + "price 0\n", + "x 0\n", + "y 0\n", + "z 0\n", + "dtype: int64" + ] + }, + "metadata": {}, + "execution_count": 7 + } + ] + }, + { + "cell_type": "code", + "source": [ + "df.info()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "GVJ1LszMnLsX", + "outputId": "ddb8256d-9fc3-4f18-9c29-c83dd12961e1" + }, + "execution_count": 8, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\n", + "RangeIndex: 53940 entries, 0 to 53939\n", + "Data columns (total 10 columns):\n", + " # Column Non-Null Count Dtype \n", + "--- ------ -------------- ----- \n", + " 0 carat 53940 non-null float64\n", + " 1 cut 53940 non-null object \n", + " 2 color 53940 non-null object \n", + " 3 clarity 53940 non-null object \n", + " 4 depth 53940 non-null float64\n", + " 5 table 53940 non-null float64\n", + " 6 price 53940 non-null int64 \n", + " 7 x 53940 non-null float64\n", + " 8 y 53940 non-null float64\n", + " 9 z 53940 non-null float64\n", + "dtypes: float64(6), int64(1), object(3)\n", + "memory usage: 4.1+ MB\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "from sklearn.preprocessing import OrdinalEncoder\n", + "\n", + "cut = ['Fair', 'Good', 'Very Good', 'Premium', 'Ideal']\n", + "color = ['D', 'E', 'F', 'G', 'H', 'I', 'J']\n", + "clarity = ['I1', 'SI2', 'SI1', 'VS2', 'VS1', 'VVS2', 'VVS1', 'IF']\n", + "\n", + "oe = OrdinalEncoder(categories = [cut, color, clarity])\n", + "oe.fit_transform(df[['cut', 'color', 'clarity']])" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "YzNS0HzEnv91", + "outputId": "61f3bc82-be65-4fdb-a110-61658006d263" + }, + "execution_count": 9, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "array([[4., 1., 1.],\n", + " [3., 1., 2.],\n", + " [1., 1., 4.],\n", + " ...,\n", + " [2., 0., 2.],\n", + " [3., 4., 1.],\n", + " [4., 0., 1.]])" + ] + }, + "metadata": {}, + "execution_count": 9 + } + ] + }, + { + "cell_type": "code", + "source": [ + "from sklearn.compose import ColumnTransformer\n", + "from sklearn.preprocessing import StandardScaler\n", + "\n", + "df['xyz'] = df['x']*df['y']*df['z']\n", + "\n", + "real_num = ['carat','depth','table', 'x','y','z', 'xyz']\n", + "cl = ColumnTransformer([\n", + " ('1', OrdinalEncoder(categories = [cut, color, clarity]), ['cut', 'color', 'clarity']),\n", + " ('2', StandardScaler(),real_num)\n", + "])\n", + "\n" + ], + "metadata": { + "id": "gIR-vkMHnNWO" + }, + "execution_count": 10, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "Y = df['price']\n", + "X = df.drop('price', axis=1)\n", + "\n", + "X = cl.fit_transform(X)\n", + "X = StandardScaler().fit_transform(X)" + ], + "metadata": { + "id": "KxNuja7LpyU7" + }, + "execution_count": 28, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "X.shape" + ], + "metadata": { + "id": "4DybCoG9kijg", + "outputId": "9ba34c78-2c71-4be4-f3ea-9b0400c0a5d7", + "colab": { + "base_uri": "https://localhost:8080/" + } + }, + "execution_count": 29, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "(53940, 10)" + ] + }, + "metadata": {}, + "execution_count": 29 + } + ] + }, + { + "cell_type": "code", + "source": [ + "from sklearn.model_selection import train_test_split\n", + "\n", + "xtrain, xtest, ytrain, ytest = train_test_split(X, Y, random_state = SEED)" + ], + "metadata": { + "id": "uLVGkYvWqLtR" + }, + "execution_count": 30, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "from sklearn.linear_model import LinearRegression\n", + "from sklearn.metrics import mean_squared_error\n", + "\n", + "lin = LinearRegression()\n", + "lin.fit(xtrain, ytrain)\n", + "\n", + "mean_squared_error(ytest, lin.predict(xtest))" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "PfIerOxzqgEw", + "outputId": "839346b2-f682-4ffd-8317-f6833df7e00f" + }, + "execution_count": 31, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "1498228.1729978432" + ] + }, + "metadata": {}, + "execution_count": 31 + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Keras" + ], + "metadata": { + "id": "-2Khue1sq47v" + } + }, + { + "cell_type": "code", + "source": [ + "(X.shape[1],)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "SviZAZELrLQT", + "outputId": "8e419068-b606-44fd-99b7-ded8dda8a0cf" + }, + "execution_count": 16, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "(10,)" + ] + }, + "metadata": {}, + "execution_count": 16 + } + ] + }, + { + "cell_type": "code", + "source": [ + "import tensorflow as tf" + ], + "metadata": { + "id": "C55_zzG0q1LE" + }, + "execution_count": 17, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Weight Init https://www.tensorflow.org/api_docs/python/tf/keras/initializers" + ], + "metadata": { + "id": "9gv5tdXklK0z" + } + }, + { + "cell_type": "code", + "source": [ + "model = tf.keras.Sequential([\n", + " tf.keras.Input(shape=(X.shape[1],), name='input'),\n", + " tf.keras.layers.Dense(20, activation='leaky_relu', kernel_initializer='he_uniform', name='dense_1'),\n", + " tf.keras.layers.Dense(10, activation='leaky_relu', kernel_initializer='he_uniform', name='dense_2'),\n", + " tf.keras.layers.Dense(1, activation='linear', name='output'),\n", + "])\n", + "model.summary()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "OPD93aYyq8hj", + "outputId": "6df73215-4297-4d2d-f12f-3c4701e9d53c" + }, + "execution_count": 32, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Model: \"sequential_1\"\n", + "_________________________________________________________________\n", + " Layer (type) Output Shape Param # \n", + "=================================================================\n", + " dense_1 (Dense) (None, 20) 220 \n", + " \n", + " dense_2 (Dense) (None, 10) 210 \n", + " \n", + " output (Dense) (None, 1) 11 \n", + " \n", + "=================================================================\n", + "Total params: 441\n", + "Trainable params: 441\n", + "Non-trainable params: 0\n", + "_________________________________________________________________\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Layers\n", + "\n", + "\n", + "\n", + "* `get_layer()`\n", + "* `get_weights`\n", + "* `set_weights`\n", + "\n" + ], + "metadata": { + "id": "NrZvXwPZu78I" + } + }, + { + "cell_type": "code", + "source": [ + "# model.layers[1].name\n", + "model.get_layer('dense_2').name" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "id": "G81upI49sdur", + "outputId": "cfc15da8-f36a-4f0c-9ec4-750257fa4dd8" + }, + "execution_count": 19, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "'dense_2'" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + } + }, + "metadata": {}, + "execution_count": 19 + } + ] + }, + { + "cell_type": "code", + "source": [ + "model.get_layer('dense_2').trainable = False\n", + "\n", + "model.summary()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ym6z-0r2uh_Q", + "outputId": "2da97e6d-6008-4407-89c3-b5c7ae825596" + }, + "execution_count": 20, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Model: \"sequential\"\n", + "_________________________________________________________________\n", + " Layer (type) Output Shape Param # \n", + "=================================================================\n", + " dense_1 (Dense) (None, 20) 220 \n", + " \n", + " dense_2 (Dense) (None, 10) 210 \n", + " \n", + " output (Dense) (None, 1) 11 \n", + " \n", + "=================================================================\n", + "Total params: 441\n", + "Trainable params: 231\n", + "Non-trainable params: 210\n", + "_________________________________________________________________\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "model.trainable = True\n", + "model.summary()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "JTjwvss-umXM", + "outputId": "d359f3fb-bf7b-4a3e-d6dd-2e530f773376" + }, + "execution_count": 21, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Model: \"sequential\"\n", + "_________________________________________________________________\n", + " Layer (type) Output Shape Param # \n", + "=================================================================\n", + " dense_1 (Dense) (None, 20) 220 \n", + " \n", + " dense_2 (Dense) (None, 10) 210 \n", + " \n", + " output (Dense) (None, 1) 11 \n", + " \n", + "=================================================================\n", + "Total params: 441\n", + "Trainable params: 441\n", + "Non-trainable params: 0\n", + "_________________________________________________________________\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "weights, biases = model.get_layer('dense_2').get_weights()\n", + "weights.shape, biases.shape" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "911lkX7evCUf", + "outputId": "679dbae6-c373-4704-a5da-3632aa4f5872" + }, + "execution_count": 23, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "((20, 10), (10,))" + ] + }, + "metadata": {}, + "execution_count": 23 + } + ] + }, + { + "cell_type": "code", + "source": [ + "model.get_layer('dense_2').set_weights((weights, biases))" + ], + "metadata": { + "id": "Jj88lZqmve7e" + }, + "execution_count": 24, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Training" + ], + "metadata": { + "id": "BdQxG6kpwMbX" + } + }, + { + "cell_type": "code", + "source": [ + "optimizer = tf.keras.optimizers.Adam(\n", + " learning_rate=0.01,\n", + " beta_1=0.9,\n", + " beta_2=0.999,\n", + " epsilon=1e-07,\n", + " amsgrad=False,\n", + " name=\"Adam\",\n", + ")\n", + "\n", + "model.compile(\n", + " optimizer = optimizer,\n", + " loss = 'mse',\n", + " metrics = ['mae']\n", + ")" + ], + "metadata": { + "id": "1vGyBjajwD_L" + }, + "execution_count": 33, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "history = model.fit(xtrain, ytrain, epochs=20, batch_size=32, validation_data=(xtest, ytest))" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "loHCOYGCxSZi", + "outputId": "10b44359-8e5b-44ae-d20c-b54c1430750f" + }, + "execution_count": 34, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Epoch 1/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 4126269.2500 - mae: 1155.9417 - val_loss: 1013396.1875 - val_mae: 628.8307\n", + "Epoch 2/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 1071703.1250 - mae: 560.4971 - val_loss: 798690.7500 - val_mae: 525.2033\n", + "Epoch 3/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 872668.1250 - mae: 505.2391 - val_loss: 727379.6875 - val_mae: 484.0403\n", + "Epoch 4/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 731504.0000 - mae: 464.1201 - val_loss: 664893.0625 - val_mae: 453.8429\n", + "Epoch 5/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 653399.3125 - mae: 441.1927 - val_loss: 612473.5625 - val_mae: 426.9374\n", + "Epoch 6/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 613934.8125 - mae: 422.3171 - val_loss: 599795.4375 - val_mae: 415.0961\n", + "Epoch 7/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 594179.2500 - mae: 415.1149 - val_loss: 588223.5625 - val_mae: 424.5157\n", + "Epoch 8/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 581641.4375 - mae: 411.0179 - val_loss: 560804.5000 - val_mae: 420.3340\n", + "Epoch 9/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 567633.8125 - mae: 405.9885 - val_loss: 580659.1875 - val_mae: 405.4107\n", + "Epoch 10/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 549532.5000 - mae: 402.3339 - val_loss: 524761.0625 - val_mae: 398.7661\n", + "Epoch 11/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 544760.6250 - mae: 398.9495 - val_loss: 512673.5625 - val_mae: 392.6149\n", + "Epoch 12/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 513657.9375 - mae: 390.3521 - val_loss: 497101.1562 - val_mae: 381.3392\n", + "Epoch 13/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 503235.5312 - mae: 383.9448 - val_loss: 485992.5312 - val_mae: 378.1144\n", + "Epoch 14/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 487951.0938 - mae: 379.6519 - val_loss: 463189.7500 - val_mae: 371.7734\n", + "Epoch 15/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 485077.0625 - mae: 377.6407 - val_loss: 475196.0625 - val_mae: 383.2153\n", + "Epoch 16/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 474165.5312 - mae: 374.8802 - val_loss: 480229.4375 - val_mae: 398.1135\n", + "Epoch 17/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 470443.9062 - mae: 374.5289 - val_loss: 452923.6250 - val_mae: 365.0916\n", + "Epoch 18/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 458504.0312 - mae: 372.3924 - val_loss: 442998.0312 - val_mae: 365.8562\n", + "Epoch 19/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 456432.1562 - mae: 372.0327 - val_loss: 515682.5625 - val_mae: 403.4404\n", + "Epoch 20/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 450242.7812 - mae: 369.8306 - val_loss: 440685.7188 - val_mae: 359.1219\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "pd.DataFrame(history.history).plot()\n", + "# history.history" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 293 + }, + "id": "Fq5no1R4yRW4", + "outputId": "a1a2f667-d4dd-4382-d6a2-ef9d17b30f7e" + }, + "execution_count": 36, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "" + ] + }, + "metadata": {}, + "execution_count": 36 + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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\n" + }, + "metadata": { + "needs_background": "light" + } + } + ] + }, + { + "cell_type": "code", + "source": [ + "print('Linear', mean_squared_error(ytest, lin.predict(xtest)))\n", + "\n", + "print('Model', mean_squared_error(ytest, model.predict(xtest)))" + ], + "metadata": { + "id": "mIxYl3aTpR7-", + "outputId": "45850f37-e119-43da-ba2b-0bb9aedf9f7e", + "colab": { + "base_uri": "https://localhost:8080/" + } + }, + "execution_count": 38, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Linear 1498228.1729978432\n", + "Model 440685.65217331244\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Further Topics are Advanced one\n" + ], + "metadata": { + "id": "cqumlE863ovu" + } + }, + { + "cell_type": "markdown", + "source": [ + "# CallBack\n", + "\n", + "https://keras.io/api/callbacks/" + ], + "metadata": { + "id": "2CCZIqvc0KyK" + } + }, + { + "cell_type": "code", + "source": [ + "def ee():\n", + " print('ee')\n", + "\n", + "lambda_callback = tf.keras.callbacks.LambdaCallback(\n", + " on_epoch_begin=None,\n", + " on_epoch_end=ee,\n", + " on_batch_begin=None,\n", + " on_batch_end=None,\n", + " on_train_begin=None,\n", + " on_train_end=None,\n", + ")\n", + "\n", + "class CustomCallback(tf.keras.callbacks.Callback):\n", + " # def on_epoch_begin():\n", + " # pass\n", + " def on_epoch_end(self, epoch, logs):\n", + " print(logs)\n", + " \n", + " # def on_batch_begin(**kwarg):\n", + " # pass\n", + " # def on_batch_end(**kwarg):\n", + " # pass\n", + " # def on_train_begin(**kwarg):\n", + " # pass\n", + " # def on_train_end(**kwarg):\n", + " # pass" + ], + "metadata": { + "id": "cIpxqhXLzCd7" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "history = model.fit(xtrain, ytrain, epochs=20, batch_size=32, validation_data=(xtest, ytest), callbacks=[CustomCallback()])" + ], + "metadata": { + "id": "y7f9qNPt1N_u" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "model = tf.keras.Sequential([\n", + " tf.keras.Input(shape=(X.shape[1],), name='input'),\n", + " tf.keras.layers.Dense(20, activation='leaky_relu', kernel_initializer='he_uniform', name='dense_1'),\n", + " tf.keras.layers.Dense(10, activation='leaky_relu', kernel_initializer='he_uniform', name='dense_2'),\n", + " tf.keras.layers.Dense(1, activation='linear', name='output'),\n", + "])\n", + "model.compile(\n", + " optimizer = 'adam',\n", + " loss = 'mse',\n", + " metrics = ['mae']\n", + ")" + ], + "metadata": { + "id": "5SfJGU6l29cM" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "early_stoping = tf.keras.callbacks.EarlyStopping(\n", + " monitor=\"val_loss\",\n", + " min_delta=100000,\n", + " patience=5,\n", + " restore_best_weights=False,\n", + ")\n", + "model_checkpoint = tf.keras.callbacks.ModelCheckpoint(\n", + " './models/',\n", + " monitor=\"val_loss\",\n", + " save_best_only=True,\n", + " save_weights_only=True,# weights, optimizer\n", + ")\n", + "\n", + "history = model.fit(xtrain, ytrain, epochs=1000, batch_size=32, validation_data=(xtest, ytest), callbacks=[early_stoping, model_checkpoint])" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "iq87YMVZ13xS", + "outputId": "4999c881-1726-4115-b529-793ce98d02ab" + }, + "execution_count": 39, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Epoch 1/1000\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 446543.5312 - mae: 369.1822 - val_loss: 426672.5625 - val_mae: 364.1584\n", + "Epoch 2/1000\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 438971.3750 - mae: 366.2079 - val_loss: 423471.9688 - val_mae: 360.3270\n", + "Epoch 3/1000\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 440695.2188 - mae: 368.9779 - val_loss: 427952.0000 - val_mae: 371.2900\n", + "Epoch 4/1000\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 429475.6875 - mae: 364.6230 - val_loss: 415963.5312 - val_mae: 362.4906\n", + "Epoch 5/1000\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 429838.2188 - mae: 364.4676 - val_loss: 412596.1250 - val_mae: 356.9526\n", + "Epoch 6/1000\n", + "1265/1265 [==============================] - 4s 3ms/step - loss: 425586.5938 - mae: 362.7749 - val_loss: 415960.8125 - val_mae: 362.5457\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Functional API\n", + "\n", + "https://www.tensorflow.org/api_docs/python/tf/keras/layers?version=nightly" + ], + "metadata": { + "id": "AwbeS4g_8vKn" + } + }, + { + "cell_type": "code", + "source": [ + "# model = tf.keras.Sequential([\n", + "# tf.keras.Input(shape=(X.shape[1],), name='input'),\n", + "# tf.keras.layers.Dense(20, activation='leaky_relu', kernel_initializer='he_uniform', name='dense_1'),\n", + "# tf.keras.layers.Dense(10, activation='leaky_relu', kernel_initializer='he_uniform', name='dense_2'),\n", + "# tf.keras.layers.Dense(20, activation='leaky_relu', kernel_initializer='he_uniform', name='dense_3'),\n", + "# tf.keras.layers.Dense(1, activation='linear', name='output'),\n", + "# ])\n", + "\n", + "model_input = tf.keras.Input(shape=(X.shape[1],), name='input')\n", + "dense_1 = tf.keras.layers.Dense(20, activation='leaky_relu', kernel_initializer='he_uniform', name='dense_1')(model_input)\n", + "dense_2 = tf.keras.layers.Dense(20, activation='leaky_relu', kernel_initializer='he_uniform', name='dense_2')(dense_1)\n", + "dense_3 = tf.keras.layers.Dense(10, activation='leaky_relu', kernel_initializer='he_uniform', name='dense_3')(tf.keras.layers.add([dense_1, dense_2]))\n", + "model_output = tf.keras.layers.Dense(1, activation='linear', name='output')(dense_3)\n", + "\n", + "model = tf.keras.Model(inputs=[model_input], outputs=[model_output])\n", + "\n", + "model.compile(\n", + " optimizer = 'adam',\n", + " loss = 'mse',\n", + " metrics = ['mae']\n", + ")\n", + "\n", + "model.summary()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "58MZJ7UvAVwm", + "outputId": "aa14352f-78a6-441f-fddb-1910f23c764f" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Model: \"model_4\"\n", + "__________________________________________________________________________________________________\n", + " Layer (type) Output Shape Param # Connected to \n", + "==================================================================================================\n", + " input (InputLayer) [(None, 9)] 0 [] \n", + " \n", + " dense_1 (Dense) (None, 20) 200 ['input[0][0]'] \n", + " \n", + " dense_2 (Dense) (None, 20) 420 ['dense_1[0][0]'] \n", + " \n", + " add_2 (Add) (None, 20) 0 ['dense_1[0][0]', \n", + " 'dense_2[0][0]'] \n", + " \n", + " dense_3 (Dense) (None, 10) 210 ['add_2[0][0]'] \n", + " \n", + " output (Dense) (None, 1) 11 ['dense_3[0][0]'] \n", + " \n", + "==================================================================================================\n", + "Total params: 841\n", + "Trainable params: 841\n", + "Non-trainable params: 0\n", + "__________________________________________________________________________________________________\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "model_input = tf.keras.Input(shape=(X.shape[1],), name='input')\n", + "dense_1 = tf.keras.layers.Dense(20, activation='leaky_relu', kernel_initializer='he_uniform', name='dense_1')(model_input)\n", + "dense_2 = tf.keras.layers.Dense(10, activation='leaky_relu', kernel_initializer='he_uniform', name='dense_2')(dense_1)\n", + "concat = tf.keras.layers.Concatenate()([dense_1, dense_2])\n", + "dense_3 = tf.keras.layers.Dense(5, activation='leaky_relu', kernel_initializer='he_uniform', name='dense_3')(concat)\n", + "model_output = tf.keras.layers.Dense(1, activation='linear', name='output')(dense_3)\n", + "\n", + "model = tf.keras.Model(inputs=[model_input], outputs=[model_output])\n", + "\n", + "model.compile(\n", + " optimizer = 'adam',\n", + " loss = 'mse',\n", + " metrics = ['mae']\n", + ")\n", + "\n", + "model.summary()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "67EhDHxTAq2i", + "outputId": "09014fd7-d6c2-4396-9680-b6a648035863" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Model: \"model_5\"\n", + "__________________________________________________________________________________________________\n", + " Layer (type) Output Shape Param # Connected to \n", + "==================================================================================================\n", + " input (InputLayer) [(None, 9)] 0 [] \n", + " \n", + " dense_1 (Dense) (None, 20) 200 ['input[0][0]'] \n", + " \n", + " dense_2 (Dense) (None, 10) 210 ['dense_1[0][0]'] \n", + " \n", + " concatenate_1 (Concatenate) (None, 30) 0 ['dense_1[0][0]', \n", + " 'dense_2[0][0]'] \n", + " \n", + " dense_3 (Dense) (None, 5) 155 ['concatenate_1[0][0]'] \n", + " \n", + " output (Dense) (None, 1) 6 ['dense_3[0][0]'] \n", + " \n", + "==================================================================================================\n", + "Total params: 571\n", + "Trainable params: 571\n", + "Non-trainable params: 0\n", + "__________________________________________________________________________________________________\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "tf.keras.utils.plot_model(model)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 564 + }, + "id": "HyzklfdVBV1T", + "outputId": "4b5d815c-52b0-4bf0-af89-4d1222049736" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "" + ], + "image/png": "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\n" + }, + "metadata": {}, + "execution_count": 88 + } + ] + }, + { + "cell_type": "code", + "source": [ + "model_input = tf.keras.Input(shape=(X.shape[1],), name='input')\n", + "\n", + "dense_1 = tf.keras.layers.Dense(20, activation='leaky_relu', kernel_initializer='he_uniform', name='dense_1')(model_input)\n", + "dense_2 = tf.keras.layers.Dense(10, activation='leaky_relu', kernel_initializer='he_uniform', name='dense_2')(dense_1)\n", + "concat = tf.keras.layers.Concatenate()([dense_1, dense_2])\n", + "model_output = tf.keras.layers.Dense(1, activation='linear', name='output')(concat)\n", + "\n", + "model = tf.keras.Model(inputs=[model_input], outputs=[model_output, concat])\n", + "\n", + "model.compile(\n", + " optimizer = 'adam',\n", + " loss = ['mse'],\n", + " metrics = ['mae']\n", + ")\n", + "\n", + "tf.keras.utils.plot_model(model)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 466 + }, + "id": "canejM8SB2JN", + "outputId": "e5fcdafb-aa65-4d5b-cb5b-3360a0df2a76" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "" + ], + "image/png": "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\n" + }, + "metadata": {}, + "execution_count": 96 + } + ] + }, + { + "cell_type": "code", + "source": [ + "history = model.fit(xtrain, ytrain, epochs=5, batch_size=32, validation_data=(xtest, ytest))" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "urRTNJBmB7Lm", + "outputId": "2d217457-dac0-4d38-c774-5936aeaaa98d" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Epoch 1/5\n", + "1265/1265 [==============================] - 4s 2ms/step - loss: 19443602.0000 - output_loss: 19443602.0000 - output_mae: 2841.3425 - concatenate_7_mae: 3896.1292 - val_loss: 6633373.5000 - val_output_loss: 6633373.5000 - val_output_mae: 1785.1199 - val_concatenate_7_mae: 3919.7078\n", + "Epoch 2/5\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 4023764.2500 - output_loss: 4023764.2500 - output_mae: 1377.2480 - concatenate_7_mae: 3876.2539 - val_loss: 3077297.0000 - val_output_loss: 3077297.0000 - val_output_mae: 1138.7142 - val_concatenate_7_mae: 3927.1462\n", + "Epoch 3/5\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 2166064.7500 - output_loss: 2166064.7500 - output_mae: 1005.4685 - concatenate_7_mae: 3881.5818 - val_loss: 2239321.5000 - val_output_loss: 2239321.5000 - val_output_mae: 929.3035 - val_concatenate_7_mae: 3929.8960\n", + "Epoch 4/5\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 1497824.6250 - output_loss: 1497824.6250 - output_mae: 830.7947 - concatenate_7_mae: 3884.1799 - val_loss: 1851428.2500 - val_output_loss: 1851428.2500 - val_output_mae: 786.3316 - val_concatenate_7_mae: 3932.3213\n", + "Epoch 5/5\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 1209720.5000 - output_loss: 1209720.5000 - output_mae: 739.7021 - concatenate_7_mae: 3886.1221 - val_loss: 1731644.6250 - val_output_loss: 1731644.6250 - val_output_mae: 726.5963 - val_concatenate_7_mae: 3934.2502\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# BatchNorm" + ], + "metadata": { + "id": "3a6NMzcmDvio" + } + }, + { + "cell_type": "code", + "source": [ + "model = tf.keras.Sequential([\n", + " tf.keras.Input(shape=(X.shape[1],), name='input'),\n", + " \n", + " tf.keras.layers.Dense(20, kernel_initializer='he_uniform', name='dense_1', kernel_regularizer=tf.keras.regularizers.L1(l1=0.02)),\n", + " tf.keras.layers.BatchNormalization(name='batchnorm1'),\n", + " tf.keras.layers.ReLU(),\n", + "\n", + " tf.keras.layers.Dropout(rate=0.2), # previous layer is affected\n", + " \n", + " tf.keras.layers.Dense(10, kernel_initializer='he_uniform', name='dense_2', kernel_regularizer='l2'),\n", + " tf.keras.layers.BatchNormalization(name='batchnorm2'),\n", + " tf.keras.layers.ReLU(),\n", + "\n", + " tf.keras.layers.Dropout(rate=0.2), # previous layer is affected\n", + "\n", + " tf.keras.layers.Dense(1, activation='linear', name='output'),\n", + "])\n", + "\n", + "model.compile(\n", + " optimizer = 'adam',\n", + " loss = 'mse',\n", + " metrics = ['mae']\n", + ")\n", + "\n", + "model.summary()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Ov0x16CSDokK", + "outputId": "86d35b91-544c-48ab-e2f7-fb7a2b2d73c2" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Model: \"sequential_20\"\n", + "_________________________________________________________________\n", + " Layer (type) Output Shape Param # \n", + "=================================================================\n", + " dense_1 (Dense) (None, 20) 200 \n", + " \n", + " batchnorm1 (BatchNormalizat (None, 20) 80 \n", + " ion) \n", + " \n", + " re_lu_6 (ReLU) (None, 20) 0 \n", + " \n", + " dropout_2 (Dropout) (None, 20) 0 \n", + " \n", + " dense_2 (Dense) (None, 10) 210 \n", + " \n", + " batchnorm2 (BatchNormalizat (None, 10) 40 \n", + " ion) \n", + " \n", + " re_lu_7 (ReLU) (None, 10) 0 \n", + " \n", + " dropout_3 (Dropout) (None, 10) 0 \n", + " \n", + " output (Dense) (None, 1) 11 \n", + " \n", + "=================================================================\n", + "Total params: 541\n", + "Trainable params: 481\n", + "Non-trainable params: 60\n", + "_________________________________________________________________\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "history = model.fit(xtrain, ytrain, epochs=20, batch_size=32, validation_data=(xtest, ytest))" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "IJh_4n3MEm6V", + "outputId": "83b89eae-cc11-4ae8-f456-0739d7c444a9" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Epoch 1/20\n", + "1265/1265 [==============================] - 6s 3ms/step - loss: 31092216.0000 - mae: 3911.5173 - val_loss: 31323378.0000 - val_mae: 3943.1685\n", + "Epoch 2/20\n", + "1265/1265 [==============================] - 3s 3ms/step - loss: 30429744.0000 - mae: 3870.1997 - val_loss: 30414290.0000 - val_mae: 3887.7966\n", + "Epoch 3/20\n", + "1265/1265 [==============================] - 3s 3ms/step - loss: 29355664.0000 - mae: 3799.7788 - val_loss: 29083384.0000 - val_mae: 3803.1350\n", + "Epoch 4/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 27960278.0000 - mae: 3705.4343 - val_loss: 27489924.0000 - val_mae: 3698.7102\n", + "Epoch 5/20\n", + "1265/1265 [==============================] - 3s 3ms/step - loss: 26221450.0000 - mae: 3584.6946 - val_loss: 25511474.0000 - val_mae: 3564.4148\n", + "Epoch 6/20\n", + "1265/1265 [==============================] - 3s 3ms/step - loss: 24265120.0000 - mae: 3440.2009 - val_loss: 23339488.0000 - val_mae: 3406.4849\n", + "Epoch 7/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 22079126.0000 - mae: 3272.7253 - val_loss: 20944722.0000 - val_mae: 3231.8457\n", + "Epoch 8/20\n", + "1265/1265 [==============================] - 3s 3ms/step - loss: 19836192.0000 - mae: 3089.2517 - val_loss: 18642378.0000 - val_mae: 3050.1194\n", + "Epoch 9/20\n", + "1265/1265 [==============================] - 3s 3ms/step - loss: 17530376.0000 - mae: 2884.8950 - val_loss: 15899387.0000 - val_mae: 2798.4241\n", + "Epoch 10/20\n", + "1265/1265 [==============================] - 3s 3ms/step - loss: 15187069.0000 - mae: 2662.8132 - val_loss: 13397392.0000 - val_mae: 2567.2976\n", + "Epoch 11/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 12946217.0000 - mae: 2431.8345 - val_loss: 11183434.0000 - val_mae: 2295.0916\n", + "Epoch 12/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 10797393.0000 - mae: 2188.1177 - val_loss: 8532675.0000 - val_mae: 2020.5256\n", + "Epoch 13/20\n", + "1265/1265 [==============================] - 3s 3ms/step - loss: 8796306.0000 - mae: 1940.0984 - val_loss: 6984680.0000 - val_mae: 1741.3541\n", + "Epoch 14/20\n", + "1265/1265 [==============================] - 3s 3ms/step - loss: 7076949.0000 - mae: 1702.2233 - val_loss: 5245982.5000 - val_mae: 1509.8745\n", + "Epoch 15/20\n", + "1265/1265 [==============================] - 3s 3ms/step - loss: 5664502.0000 - mae: 1486.8158 - val_loss: 3993390.0000 - val_mae: 1247.0170\n", + "Epoch 16/20\n", + "1265/1265 [==============================] - 3s 3ms/step - loss: 4626841.0000 - mae: 1321.6732 - val_loss: 2923536.5000 - val_mae: 1047.4983\n", + "Epoch 17/20\n", + "1265/1265 [==============================] - 3s 3ms/step - loss: 3853236.5000 - mae: 1205.2939 - val_loss: 2587632.2500 - val_mae: 946.7275\n", + "Epoch 18/20\n", + "1265/1265 [==============================] - 3s 2ms/step - loss: 3323822.0000 - mae: 1123.4414 - val_loss: 2155173.2500 - val_mae: 723.6109\n", + "Epoch 19/20\n", + "1265/1265 [==============================] - 3s 3ms/step - loss: 3130168.2500 - mae: 1102.2725 - val_loss: 1725843.2500 - val_mae: 526.8715\n", + "Epoch 20/20\n", + "1265/1265 [==============================] - 3s 3ms/step - loss: 2921132.5000 - mae: 1066.2325 - val_loss: 2020326.3750 - val_mae: 563.4874\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "" + ], + "metadata": { + "id": "25IAMgOPGrey" + }, + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file