{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "%matplotlib inline"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n# 7. HPO Concat\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import site\nsite.addsitedir(r\"E:\\AA\\AI4Water\")\nsite.addsitedir(r\"E:\\AA\\easy_mpl\")\n\nfrom ai4water import Model\n\nimport os\nSEP = os.sep\nimport numpy as np\nimport pandas as pd\nimport math\nfrom typing import Union\n\nfrom skopt.plots import plot_objective\nimport matplotlib.pyplot as plt\nplt.rcParams[\"font.family\"] = \"Times New Roman\"\n\nfrom SeqMetrics import RegressionMetrics\n\nfrom ai4water.utils.utils import jsonize\nfrom ai4water.utils.utils import dateandtime_now\nfrom ai4water.hyperopt import Categorical, Real, Integer, HyperOpt\n\nfrom utils import prepare_data, eval_model"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "PREFIX = f\"hpo_lstm_concat_{dateandtime_now()}\"\nITER = 0\nnum_iterations = 200\nlookback = 12\ntarget = 'TP'"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "MONITOR = {\"rmse\": [], \"nse\": [], \"r2\": [], \"mape\": []}"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "def objective_fn(\n        prefix: str = None,\n        return_model: bool = False,\n        epochs:int = 500,\n        verbosity: int = 0,\n        predict : bool = False,\n        target = target,\n        **suggestions\n                )->Union[float, Model]:\n\n    suggestions = jsonize(suggestions)\n    global ITER\n\n    tr_x, tr_y, val_x, val_y, test_x, test_y = prepare_data(\n        target=target, lookback=lookback, batch_size=suggestions[\"batch_size\"])\n\n    x_mean = tr_x[0].mean()\n    x_std = tr_x[0].std()\n    x_mean_st = tr_x[1].mean()\n    x_std_st = tr_x[1].std()\n\n    y_mean = tr_y.mean()\n    y_std = tr_y.std()\n\n    tr_x[0] = (tr_x[0] - x_mean) / x_std\n    tr_x[1] = (tr_x[1] - x_mean_st) / x_std_st\n    tr_y = (tr_y - y_mean) / y_std\n    #tr_y = transformer.fit_transform(tr_y)\n\n    val_x[0] = (val_x[0] - x_mean) / x_std\n    val_x[1] = (val_x[1] - x_mean_st) / x_std_st\n    val_y = (val_y - y_mean) / y_std\n    #val_y = transformer.transform(val_y)\n\n    test_x[0] = (test_x[0] - x_mean) / x_std\n    test_x[1] = (test_x[1] - x_mean_st) / x_std_st\n    test_y = (test_y - y_mean) / y_std\n    #test_y = transformer.transform(test_y)\n\n    num_dyn_inputs = tr_x[0].shape[-1]\n    num_static_inputs = tr_x[1].shape[-1]\n\n    layers = {\n        \"Input_dyn\": {\"batch_shape\": (suggestions[\"batch_size\"], lookback, num_dyn_inputs)},\n        \"Input_cat\": {\"batch_shape\": (suggestions[\"batch_size\"], num_static_inputs)},\n        \"LSTM\": {\"config\": {\"units\": suggestions[\"lstm_units\"]}, \"inputs\": \"Input_dyn\"},\n        \"Dense_cat\": {\"config\": {\"units\": suggestions[\"dense_units\"]}, \"inputs\": \"Input_cat\"},\n        \"Concatenate\": {\"config\": {}, \"inputs\": [\"LSTM\", \"Dense_cat\"]},\n        \"Dense\": 1\n    }\n\n    # build model\n    _model = Model(model = {\"layers\": layers},\n                          batch_size=suggestions[\"batch_size\"],\n                          epochs=epochs,\n                          lr=suggestions[\"lr\"],\n                            prefix=prefix or PREFIX,\n                            verbosity=verbosity)\n\n    # train model\n    _model.fit(x=tr_x, y=tr_y, validation_data=(val_x, val_y))\n\n    # evaluate model\n    t, p = _model.predict(x=val_x, y=val_y, return_true=True,\n                                             process_results=False)\n    metrics = RegressionMetrics(t, p)\n    val_score = metrics.rmse()\n\n    for metric in MONITOR.keys():\n        val = getattr(metrics, metric)()\n        MONITOR[metric].append(val)\n\n    # here we are evaluating model with respect to mse, therefore\n    # we don't need to subtract it from 1.0\n    if not math.isfinite(val_score):\n        val_score = 9999\n\n    print(f\"{ITER} {val_score}\")\n\n    ITER += 1\n\n    if return_model:\n        return _model\n\n    return val_score"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "param_space = [\n    Integer(30, 100, name=\"lstm_units\"),\n    Integer(30, 100, name=\"dense_units\"),\n    Real(0.00001, 0.01, name=\"lr\"),\n    Categorical([\"relu\", \"elu\", \"tanh\", \"sigmoid\"], name=\"activation\"),\n    Categorical([8, 12, 16, 24, 32, 48, 64, 128], name=\"batch_size\")\n                ]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "x0 = [30, 30, 0.001, 'relu', 8]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "optimizer = HyperOpt(\n    algorithm=\"bayes\",\n    objective_fn=objective_fn,\n    param_space=param_space,\n    x0=x0,\n    num_iterations=num_iterations,\n    process_results=False, # we can turn it False if we want post-processing of results\n    opt_path=f\"results{SEP}{PREFIX}\"\n)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "#\n# results = optimizer.fit()\n#\n# best_iteration = optimizer.best_iter()\n#\n# print(f\"optimized parameters are \\n{optimizer.best_paras()} at {best_iteration}\")\n#\n# for key in ['rmse', 'mape']:\n#     print(key, np.nanmin(MONITOR[key]), np.nanargmin(MONITOR[key]))\n#\n# for key in ['r2', 'nse']:\n#     print(key, np.nanmax(MONITOR[key]), np.nanargmax(MONITOR[key]))\n#\n# model = objective_fn(prefix=f\"{PREFIX}{SEP}best\",\n#                      return_model=True,\n#                      epochs=500,\n#                      verbosity=1,\n#                      predict=True,\n#                      **optimizer.best_paras())\n#\n# tr_x, tr_y, val_x, val_y, test_x, test_y = prepare_data(\n#     target=target, lookback=lookback,\n#     batch_size=optimizer.best_paras()['batch_size']\n# )\n#\n# x_mean = tr_x[0].mean()\n# x_std = tr_x[0].std()\n# x_mean_st = tr_x[1].mean()\n# x_std_st = tr_x[1].std()\n#\n# y_mean = tr_y.mean()\n# y_std = tr_y.std()\n#\n# tr_x[0] = (tr_x[0] - x_mean) / x_std\n# tr_x[1] = (tr_x[1] - x_mean_st) / x_std_st\n# tr_y = (tr_y - y_mean) / y_std\n# # tr_y = transformer.fit_transform(tr_y)\n#\n# val_x[0] = (val_x[0] - x_mean) / x_std\n# val_x[1] = (val_x[1] - x_mean_st) / x_std_st\n# val_y = (val_y - y_mean) / y_std\n# # val_y = transformer.transform(val_y)\n#\n# test_x[0] = (test_x[0] - x_mean) / x_std\n# test_x[1] = (test_x[1] - x_mean_st) / x_std_st\n# test_y = (test_y - y_mean) / y_std\n# # test_y = transformer.transform(test_y)\n#\n# model.evaluate(x=tr_x, y=tr_y, metrics=['r2', 'nse', 'rmse'])\n# model.evaluate(x=val_x, y=val_y, metrics=['r2', 'nse', 'rmse'])\n# model.evaluate(x=test_x, y=test_y, metrics=['r2', 'nse', 'rmse'])\n#\n# # tr_t, tr_p = model.predict(x=tr_x, y=tr_y, return_true=True)\n# #\n# # val_t, val_p = model.predict(x=val_x, y=val_y, return_true=True)\n#\n# t, p = model.predict(x=test_x, y=test_y, return_true=True)\n#\n# print(f'r2 = {RegressionMetrics(t, p).r2()}')\n# print(f'nse = {RegressionMetrics(t, p).nse()}')\n# print(f'rmse = {RegressionMetrics(t, p).rmse()}')\n#\n# optimizer._plot_convergence(save=True)\n#\n# optimizer.plot_importance(save=True)\n# plt.tight_layout()\n# plt.show()\n#\n# _ = plot_objective(results)\n# plt.show()\n#\n# optimizer.save_iterations_as_xy()\n#\n# optimizer._plot_parallel_coords(figsize=(14, 8), save=True)\n#\n# monitor = pd.DataFrame.from_dict(MONITOR)\n# a = os.path.split(model.path)\n# a = os.path.split(a[0])\n#\n# monitor.to_csv (r'monitor.csv', index = True, header=True)"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "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.7.9"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}