From 2726bc94ec72b1c04a1e818dbcf6ddb363ff43f2 Mon Sep 17 00:00:00 2001 From: "Dr. Kashif Rasul" Date: Fri, 18 Dec 2020 13:02:26 +0100 Subject: [PATCH] added back TransformedIterableDataset --- examples/m5.ipynb | 78 ++++++++++++++++++++++++++++++++++++----- pts/dataset/__init__.py | 1 + pts/dataset/loader.py | 35 ++++++++++++++++++ pts/model/estimator.py | 37 ++++++++++--------- pts/trainer.py | 14 ++++---- 5 files changed, 132 insertions(+), 33 deletions(-) create mode 100644 pts/dataset/__init__.py create mode 100644 pts/dataset/loader.py diff --git a/examples/m5.ipynb b/examples/m5.ipynb index a115f84..e5ad034 100644 --- a/examples/m5.ipynb +++ b/examples/m5.ipynb @@ -168,7 +168,7 @@ " freq=dataset.metadata.freq,\n", " scaling=True,\n", " trainer=Trainer(device=device,\n", - " epochs=1,\n", + " epochs=50,\n", " learning_rate=1e-3,\n", " num_batches_per_epoch=120,\n", " batch_size=256,\n", @@ -209,7 +209,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "metadata": {}, "outputs": [], "source": [ @@ -219,31 +219,91 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 25, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Running evaluation: 100%|██████████| 30490/30490 [03:42<00:00, 137.06it/s]\n" + ] + } + ], "source": [ - "evaluator = Evaluator()\n", + "evaluator = Evaluator(num_workers=0)\n", "agg_metrics, item_metrics = evaluator(iter(tss), iter(forecasts), num_series=len(dataset.test))" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 26, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"MSE\": 6.058231599133125,\n", + " \"abs_error\": 898994.0,\n", + " \"abs_target_sum\": 1231764.0,\n", + " \"abs_target_mean\": 1.4428196598416343,\n", + " \"seasonal_error\": 1.1272178349378457,\n", + " \"MASE\": 0.9187582800838673,\n", + " \"MAPE\": 0.3138891162975238,\n", + " \"sMAPE\": 0.721700212685564,\n", + " \"OWA\": NaN,\n", + " \"MSIS\": 8.565326751268298,\n", + " \"QuantileLoss[0.1]\": 241247.00000000003,\n", + " \"Coverage[0.1]\": 0.002498477252494963,\n", + " \"QuantileLoss[0.2]\": 459438.39999999997,\n", + " \"Coverage[0.2]\": 0.011113714098299208,\n", + " \"QuantileLoss[0.3]\": 646149.0,\n", + " \"Coverage[0.3]\": 0.029292976619969074,\n", + " \"QuantileLoss[0.4]\": 795096.4,\n", + " \"Coverage[0.4]\": 0.06370121351262709,\n", + " \"QuantileLoss[0.5]\": 898994.0,\n", + " \"Coverage[0.5]\": 0.11985428477721033,\n", + " \"QuantileLoss[0.6]\": 954627.2,\n", + " \"Coverage[0.6]\": 0.19450873822799047,\n", + " \"QuantileLoss[0.7]\": 939651.9999999999,\n", + " \"Coverage[0.7]\": 0.3110961439347796,\n", + " \"QuantileLoss[0.8]\": 840218.8,\n", + " \"Coverage[0.8]\": 0.4717834887316684,\n", + " \"QuantileLoss[0.9]\": 618277.3999999999,\n", + " \"Coverage[0.9]\": 0.6762791079042308,\n", + " \"RMSE\": 2.4613475169372414,\n", + " \"NRMSE\": 1.7059287348547787,\n", + " \"ND\": 0.7298427296137897,\n", + " \"wQuantileLoss[0.1]\": 0.19585488778694624,\n", + " \"wQuantileLoss[0.2]\": 0.37299222903088575,\n", + " \"wQuantileLoss[0.3]\": 0.5245720771186688,\n", + " \"wQuantileLoss[0.4]\": 0.6454941043901267,\n", + " \"wQuantileLoss[0.5]\": 0.7298427296137897,\n", + " \"wQuantileLoss[0.6]\": 0.775008199622655,\n", + " \"wQuantileLoss[0.7]\": 0.7628506759411705,\n", + " \"wQuantileLoss[0.8]\": 0.6821264462997783,\n", + " \"wQuantileLoss[0.9]\": 0.5019446907037386,\n", + " \"mean_absolute_QuantileLoss\": 710411.1333333333,\n", + " \"mean_wQuantileLoss\": 0.576742893389751,\n", + " \"MAE_Coverage\": 0.29109687277119217\n", + "}\n" + ] + } + ], "source": [ "print(json.dumps(agg_metrics, indent=4))" ] }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 27, "metadata": {}, "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAX4AAAEGCAYAAABiq/5QAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/d3fzzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAfTklEQVR4nO3df3xcdZ3v8ddnJj8aktqWFMf+klYKaFtoIbkKFnk0dPGyAoUHcFnQXXv34qP3h7i6urZ4veCK9/FYYXW9eNfVrYJbVyRgK7QW1GVL6l5dqVBJSwsiBdulRVrJppWpbZpkPvePOWknk0kmmcyZHznv5+Mxj5wfc+a8M0k+c/I93/M95u6IiEh0xModQERESkuFX0QkYlT4RUQiRoVfRCRiVPhFRCKmptwBRmP69Ok+d+7cgrY9evQojY2NxQ0UEmUtvmrJCcoalmrJGkbO7du3v+7uZwxZ4e4V/2hpafFCdXR0FLxtqSlr8VVLTndlDUu1ZA0jJ/C056ipauoREYkYFX4RkYhR4RcRiRgVfhGRiFHhFxGJGBV+EZEK1JXsYccrh+lK9hT9tauiH7+ISJRs7DzAmg07qY3F6E2luPv681mxZFbRXl9H/CIiFaQr2cOaDTs53pvijZ4+jvemWL1hZ1GP/EMr/GZ2rpl1Zjx+Z2YfM7PTzexxM3sx+DotrAwiItVmf/cxamODS3NtLMb+7mNF20dohd/dX3D3Je6+BGgBfg88DNwGbHH3s4EtwbyIiACzpzXQm0oNWtabSjF7WkPR9lGqpp7lwEvuvg+4BlgXLF8HXFuiDCIiFa+5qZ67rz+fSbUxJtfXMKk2xt3Xn09zU33R9lGqk7s3AQ8E0wl3/00w/RqQKFEGEZGqsGLJLJbOn87+7mPMntZQ1KIPYB7yPXfNrA54FVjo7gfN7LC7T81Y3+3uQ9r5zWwVsAogkUi0tLe3F7T/ZDJJU1NTQduWmrIWX7XkBGUNS7VkDSNnW1vbdndvHbIi18htxXyQbtr5p4z5F4AZwfQM4IV8r6HROStPtWStlpzuyhqWask60UbnvJlTzTwAm4CVwfRKYGMJMoiISCDUwm9mjcDlwPcyFn8euNzMXgT+IJgXEZESCfXkrrsfBZqzlnWR7uUjIiJloCt3RUQiRoVfRCRiVPhFRCJGhV9EJGJU+EVEIkaFX0QkYlT4RUQiRoVfRCRiVPhFRCJGhV9EJGJU+EVEIkaFX0QkYlT4RUQiRoVfRCRiVPhFRCJGhV9EJGJU+EVEIkaFX0QkYlT4RUQiJuybrU81s/Vm9ksze97MLjaz083scTN7Mfg6LcwMIiIyWNhH/PcAP3T3twOLgeeB24At7n42sCWYFxGREgmt8JvZFOBS4F4Adz/h7oeBa4B1wdPWAdeGlUFERIYydw/nhc2WAGuB50gf7W8HPgoccPepwXMM6B6Yz9p+FbAKIJFItLS3txeUI5lM0tTUVNC2paasxVctOUFZw1ItWcPI2dbWtt3dW4escPdQHkAr0Ae8K5i/B/gccDjred35XqulpcUL1dHRUfC2paasxVctOd2VNSzVkjWMnMDTnqOmhtnGvx/Y7+7bgvn1wIXAQTObARB8PRRiBhERyRJa4Xf314BXzOzcYNFy0s0+m4CVwbKVwMawMoiIyFA1Ib/+R4D7zawOeBn4U9IfNg+Z2S3APuDGkDOIiEiGUAu/u3eSbuvPtjzM/YqIyPB05a6ISMSo8IuIRIwKv4hIxKjwi4hEjAq/iEjEqPCLiESMCr+ISMSo8IuIRIwKv4hIxKjwi4hEjAq/iEjEqPCLiESMCr+ISMSo8IuIRIwKv4hIxKjwi4hEjAq/iEjEqPCLiESMCr+ISMSEes9dM9sLvAH0A33u3mpmpwMPAnOBvcCN7t4dZg4RETmlFEf8be6+xN0Hbrp+G7DF3c8GtgTzIiJSIuVo6rkGWBdMrwOuLUMGEZHIMncP78XNfg10Aw78vbuvNbPD7j41WG9A98B81rargFUAiUSipb29vaAMyWSSpqamwr6BElPW4quWnKCsYamWrGHkbGtr257R2nKKu4f2AGYFX98M7AAuBQ5nPac73+u0tLR4oTo6OgrettSUtfiqJae7soalWrKGkRN42nPU1FCbetz9QPD1EPAw8E7goJnNAAi+Hgozg4iIDBZa4TezRjObPDANvBfYBWwCVgZPWwlsDCuDiIgMFWZ3zgTwcLoZnxrgO+7+QzN7CnjIzG4B9gE3hphBRESyhFb43f1lYHGO5V3A8rD2KyIiI9OVuyIiEaPCLyISMSr8IiIRo8IvIhIxKvwiIhGjwi8iEjEq/CIiEaPCLyISMSr8IiIRo8IvIhIxKvwiIhGjwi8iEjEq/CIiEaPCLyISMSr8IiIRo8IvIhIxKvwiIhGjwi8iEjEq/CIiERN64TezuJk9Y2abg/l5ZrbNzPaY2YNmVhd2BhEROaUUR/wfBZ7PmL8L+JK7zwe6gVtKkEFERAKhFn4zmw1cCXwjmDfgMmB98JR1wLVhZhARkcHM3cN7cbP1wF8Bk4G/AP4z8GRwtI+ZzQF+4O6Lcmy7ClgFkEgkWtrb2wvKkEwmaWpqKmjbUlPW4quWnKCsYamWrGHkbGtr2+7urUNWuPuwD+CyjOl5Weuuy7PtVcDfBdPLgM3AdGBPxnPmALtGeh13p6WlxQvV0dFR8LalpqzFVy053ZU1LNWSNYycwNOeo6bma+r5Qsb0hqx1/yvPtkuBFWa2F2gn3cRzDzDVzGqC58wGDuR5HRERKaJ8hd+Gmc41P4i7f8rdZ7v7XOAm4Al3/wDQAdwQPG0lsHH0cUVEZLzyFX4fZjrX/GitAT5uZnuAZuDeAl9HREQKUJNn/dvMbBPpo/uBaYL5eaPdibtvBbYG0y8D7xxzUhERKYp8hf+ajOkvZK3LnhcRkSowYuF39x9nzptZLbAIOODuh8IMJiIi4Rixjd/MvmZmC4PpKcAO4FvAM2Z2cwnyiYhIkeU7ufsed98dTP8p8Ct3Pw9oAVaHmkxEREKRr/CfyJi+HHgEwN1fCyuQiIiEK1/hP2xmV5nZBaQvyPohQHABVkPY4UREpPjy9er5r8CXgbcAH8s40l8OPBpmMBERCUe+Xj2/Aq7IsfxHZvbvoaUSEZHQ5DviH8TMFgA3B4/DwNBR30REpKLlLfxmNpdTxb4XOBNodfe9oSYTEZFQ5OvH/zPSbfk1wPXu3gK8oaIvIlK98vXqOUj6JioJ4IxgWXh3bhERkdCNWPjd/VrgPGA78Jdm9mtgmplpkDURkSqVt43f3Y8A3wS+aWYJ4EbgS2b2VnefE3ZAEREprjHdbN3dD7r7/3X3pcAlIWUSEZEQjXjEnzH+/nBWFDGLiIiUQL6mnouBV4AHgG3kud2iiIhUvnyF/y2kB2e7GXg/6a6dD2SM2CkiIlUmX6+efnf/obuvBC4C9gBbzezWfC9sZpPM7OdmtsPMdpvZZ4Pl88xsm5ntMbMHzayuKN+JiIiMSt6Tu2ZWb2bXAd8GPkx60LaHR/HaPcBl7r4YWAJcYWYXAXcBX3L3+UA3cEuB2UVEpAD5rtz9FvAz4ELgs+7+H9z9c+5+IN8Le1oymK0NHg5cBqwPlq8Dri0wu4iIFCDfEf8fA2cDHwX+1cx+FzzeMLPf5XtxM4ubWSdwCHgceAk47O59wVP2A7MKTi8iImNm7uGPwGBmU0k3D90O/EPQzIOZzQF+4O6LcmyzClgFkEgkWtrb2wvadzKZpKmpqcDkpaWsxdOfck70p+g7/nsmT55c7jijUunvaSZlLb4wcra1tW139yGjKI9pWOZCufthM+sg3T10qpnVBEf9s4GczUbuvhZYC9Da2urLli0raN9bt26l0G1LTVmLY2PnAdZs2EltLMZ/O9eZM+dsViyp/H8sK/k9zaasxVfKnGO6cncszOyM4EgfM2sg3S30eaADuCF42kpgY1gZJHq6kj2s2bCT470p3ujpI+XO6g076Ur2lDuaSMUIrfADM4AOM9sJPAU87u6bgTXAx81sD9AM3BtiBomY/d3HqI0N/rWujcXY332sTIlEKk9oTT3uvhO4IMfylwGN7imhmD2tgd5UatCy3lSK2dMaypRIpPKEecQvUnLNTfXcff35TKqNMbm+hpgZd19/Ps1N9eWOJlIxSnJyV6SUViyZxdL509nffYzXX3yG5VVwYleklHTELxNSc1M9i+dMJR7TuIIi2VT4RUQiRoVfRCRiVPhFRCJGhT/iupI97HjlsC5wEokQ9eqJsMyhDXpTKe6+/vyqGNpARMZHR/wRlT20wfHelIY2EIkIFf6I0tAGItGlwh9RGtpAJLpU+CMqe2iDSbUxDW0gEhE6uTuBdCV72N99jNnTGkZVwDOHNhjtNiJS/VT4J4ix9tDJ/JBYPGdq6YKKSNmp8E8AmT10jpNut1+9YSdL50/PeRSvbpwi0aY2/glgLD101I1TRFT4J4Cx9NBRN04RUeGfAMbSQ0fdOEVEbfwTxGh76Ax8SKzOauNXjx6R6Ait8JvZHOBbQAJwYK2732NmpwMPAnOBvcCN7t4dVo4oaW6qVzdOEckrzKaePuAT7r4AuAj4sJktAG4Dtrj72cCWYF5KbOAOVSr6ItETWuF399+4+y+C6TeA54FZwDXAuuBp64Brw8ogIiJDmbuHvxOzucC/AIuAf3P3qcFyA7oH5rO2WQWsAkgkEi3t7e0F7TuZTNLU1FTQtqWmrMVXLTlBWcNSLVnDyNnW1rbd3VuHrHD3UB9AE7AduC6YP5y1vjvfa7S0tHihOjo6Ct621JS1+Kolp7uyhqVasoaRE3jac9TUULtzmlktsAG4392/Fyw+aGYzgvUzgENhZhARkcFCK/xBM869wPPu/jcZqzYBK4PplcDGsDJIbrrdoki0hdmPfynwJ8CzZtYZLPufwOeBh8zsFmAfcGOIGSSLxukRkdAKv7v/BLBhVi8Pa78yvLEO5iYiE5OGbIgQjdMjIqDCHykap0dEQIU/UnS7RREBDdIWORqnR0RU+MdprPe5rYT9jXYwNxGZmFT4x6HUXSPVFVNEikFt/AUq9S0MdctEESkWFf4ClbprpLpiikixqPAXqNRdI9UVU0SKRYW/QKXuGqmumCJSLDq5Ow6l7hqprpgiUgwq/ONU6q6R6opZHqXutisSJhV+kTzUjVYmGrXxi4xA3WhlIlLhFxmButHKRKTCX2K6+1V1UTdamYhU+EtoY+cBlt71BH/8jW0svesJNnUeKHckyaMau9Hq4ELy0cndUcjVo2OsvTx096vqVU3daHUiWkZDhT+PXH9IDmP64+pK9tDxy0PUxAbfiXKgrbiSC4mkVUM3Wh1cyGiFVvjN7D7gKuCQuy8Klp0OPAjMBfYCN7p7d1gZxivXH9In1+8AjJ6+0f1xbew8wOr1O4hhHOsLp61YfcwFTp2IHvi9BB1cSG5htvH/A3BF1rLbgC3ufjawJZivWLl6dJgZ8WGO3LN1JXv4xEOd9PT5oKLfWB8vuK04u/12Ipw3UJt0cehEtIxWaEf87v4vZjY3a/E1wLJgeh2wFVgTVobxmj2tgRP9/YOWHe9NDSn8uf64upI9fH/Hq2Qd5APwyfeey9WLZ4656Gc3O91+1QI+t/m5qv7XXm3SxTNwInp11vtZLb8LUjrm7uG9eLrwb85o6jns7lODaQO6B+ZzbLsKWAWQSCRa2tvbC8qQTCZpamoqaNsjx3p5pfsYw71HMUt/AMye1sCUhtpB2w38B5DKse286Y001Q/9zB0pa3/K+eVrbwx6PTPDsvYRN2PeGY001Mbzf4PjMJ73dUCu7ylmxtvfMnnIh2uhipGzVIqVtT/lnOhPURePFe19zBbF9zVsYeRsa2vb7u6t2cvLdnLX3d3Mhv3Ucfe1wFqA1tZWX7ZsWUH72bp1K4Vs25XsYeldT3C8d/gCWhc3Hvuz9zA/MXnU29XGjSc/9Z6cR2EjZd3xymG+9uNtvNHTd3JZY32c3r4UJ/pPvY2TamP8dMUloR/lFfq+Zsr1PU2ur+Hb77mAxXOmji9goBg5S0VZw1EtWUuZs9T9+A+a2QyA4OuhEu9/1HK172err4lz9MTgpqDhtquviVFfE+OL/2nxoC6ho23bztV+259yPnP1wqrqY55JbdIi5VHqI/5NwErg88HXjSXe/6g11sXp6c/RQJ8hV5FqrIvT0zf4w6C+xvj6B1tYOHPKyaKcq237TSPsa7j22xVLZnHFordUZa8etUmLlEeY3TkfIH0id7qZ7Qc+Q7rgP2RmtwD7gBvD2v94DHTB9BHqfn3N0KPrgWIeixn0O/Vxw2LG3defz6XnvPnk84brb/2Vtkkj5hq4kGj3q0cAY+HM9EdFNfQxH041XRwlMlGE2avn5mFWLQ9rn8Ww5+Ab/Hl7JyMd65vBHVcvONn7pCvZw+5Xj7B6/Q56+k61t7sZj956yaBzAAC7Xz1C9im32liME3n+wwD4yZ7XJ1wvmGr+4BKpRrpyN8P9T+7j9o27Riz6AO5w5/ef44qFbzlZiGNmg4o+QH08NuQcwMbOA3z8wU76s05r96bSvTBGoiszRaQYIl34B654bayLs+EX+/nqj18e9bb9KWf3q0dOFuJcTvSnOHKsl65kD81N9XQle1i9fseQog9w+5ULiB//9Yj73P3qkZNdSAdkXpmpK3hFZDQiW/gH2uOBYQv3SPpSzne27cNy9NM/rTZObypFfyrFh+//xckmmTObG4lbDBj8X0BDbZxFs6bQ/dLIebObkuDUCWZdCCUioxXJYZkHNZkUUPQH/HD3IY5lN+/UxLj7hvOIGfSlGHTXpsa6OP05zhin3EfswjiQd0hTUnCCGSjaXaI0fILIxBfJwj+aPvqFuuPqBcw5vZG6+OALuOIxo/OVw1yTdRQeM/jrG0buwpgr72m1cb7+wVZWLJlVtLtEjWfcH31giFSPSDb1zJ7WwO9P9OV/4hg11sVZNHMKjXVxft87+PWP9vRz+yPPDvkPoTYeY+n86cO+ZleyhyPHTgwZMyiFs3Dmm4Zdn32NQb72//GcOFYzk0h1iWTh7z56It0ns8jjFPW7s+vAEe7c/By5emZmF32AuvipI/Njvf0nTwTDQLv+TuIxozfrjPCNrbMHde1MOdTEoKG2ZsiFUJmF+UR/P7e2nc373/XWQQW90CF91dNIpPpErvBv7DzAJ7+7g/5UcYt+XU2M269cwJ2bdw9pix/Jif4Uuw4c4Y/W/ow/e0cvf37XE9x9/fksnT+dv/jujiEFf8CDT+3ngZ+/Qm+/nyy49TUxvvKBC1k4802DhoXILsxffPxX/G3HHu64egGLZk5h9rSGgodP0BjwItUnUm38A0XwxDDFdDy++v4L2N/9+zEVfYC+/hR/+f3dHO9N0e9+8sTsz156fdiiD9DTlxqyvi4eY0pDbc4j+Vzbf/rhXbz/60+y9K4n+Ome1wu6t6zG2xGpPpE64t/96pFx9eIZyS3f2l7Qdv0O/VkFPB4zXk+eGPNr5Sq4uQpzpoELzFZv2MlP11zGT9dcNqZrATTejkj1iUzhv//JfXz6kV3ljjEqR3v66T56gpoYOW/kMpwVOW7uMlCYP5njGoBMA80zi+dMHXPR1ng7ItUlEk091VT0B9zzxB6uu3AWtWP4CT3S+WrO7pQrlsziX29bzicuP4f6mhiN9UPvFTDe5pnmpvqCPjREpPQm/BF/f8r57Obnyh2jIA89Pbb759bGbdiTqs1N9Xxkebo3z/7uY+w6cITPPfqcmmdEImjCF/4T/SlOjKW9pIr1p0a+AhhOjYS5eM7Uqh3HX0TGZ8IX/teOHC93hNCdVpfuxz/Wo3YNhywSTRO68N//5D6SPX1U27c50K4/Ugekxvo4/Snn9qtO9cVXEReR0aiuijgGXckePv3ILj5xXrmTjN2X/ugCLj6rmY+1P8P/29M1aF08Zty5YiGLZqnYi0hhJmzhT9+esPp88OK3ctXimQD844cu4ulfd/FI56vUxeHCM5u5+KxmFXsRGZcJW/g/eN9T5Y4wSMygoS5OT28/jg0ZMuLdZ53OOYljfOQPBv+L0jqvmdZ5zaWMKiITXFkKv5ldAdwDxIFvuPvny5EjbLUxw8z4zIoFXLHwVA8aSP9HcqD7GD19KS6ZP535icls3bq1vIFFJBJKXvjNLA58Bbgc2A88ZWab3L1one3LPSZ8PAZr/uPbedfbmge1w2c20Vx6zpvLFU9EIq4cR/zvBPa4+8sAZtYOXAMUrfBf8lf/XKyXGrXL3/FmLnv7m5k1rYGFM6eoHV5EKpZ5kcekz7tDsxuAK9z9Q8H8nwDvcvdbs563ClgFkEgkWtrb20e9j2cPnDqxm2iAg2O7EdWIDE6OgJkK3ruG2jjxmI284Sgkk0mamprG/TqlUC1ZqyUnKGtYqiVrGDnb2tq2u3tr9vKKPbnr7muBtQCtra2+bNmyUW976x2PMjC45SfO6+OLzxb2bSYm1/Jf3j2P5smTmNt8GrU18VC7UG7dupWxfJ/lVC1ZqyUnKGtYqiVrKXOWo/AfAOZkzM8OlhXNrjuvZO5tjxa07aKZk7n0nDO47oLZzE9MLmYsEZGKUI7C/xRwtpnNI13wbwLeX+yd7P38lSy6Y+Tif26ikXefNZ1zEpOZNe20QXeuEhGZqEpe+N29z8xuBX5Eujvnfe6+O4x97brzSrZu3creDywL4+VFRKpSWdr43f0x4LFy7FtEJOoicSMWERE5RYVfRCRiVPhFRCJGhV9EJGJKfuVuIczst8C+AjefDrxexDhhUtbiq5acoKxhqZasYeQ8093PyF5YFYV/PMzs6VyXLFciZS2+askJyhqWaslaypxq6hERiRgVfhGRiIlC4V9b7gBjoKzFVy05QVnDUi1ZS5Zzwrfxi4jIYFE44hcRkQwq/CIiETOhC7+ZXWFmL5jZHjO7rcxZ7jOzQ2a2K2PZ6Wb2uJm9GHydFiw3M/tykHunmV1Y4qxzzKzDzJ4zs91m9tFKzWtmk8zs52a2I8j62WD5PDPbFmR60MzqguX1wfyeYP3cUmUN9h83s2fMbHOF59xrZs+aWaeZPR0sq7iff7D/qWa23sx+aWbPm9nFlZjVzM4N3s+Bx+/M7GNlyeruE/JBesjnl4C3AXXADmBBGfNcClwI7MpYdjdwWzB9G3BXMP0+4Aek7/R4EbCtxFlnABcG05OBXwELKjFvsM+mYLoW2BZkeAi4KVj+NeC/B9P/A/haMH0T8GCJ39uPA98BNgfzlZpzLzA9a1nF/fyD/a8DPhRM1wFTKzVrRuY48BpwZjmylvwbLuEbezHwo4z5TwGfKnOmuVmF/wVgRjA9A3ghmP574OZczytT7o3A5ZWeFzgN+AXwLtJXQNZk/y6Qvg/ExcF0TfA8K1G+2cAW4DJgc/AHXXE5g33mKvwV9/MHpgC/zn5vKjFrVr73Aj8tV9aJ3NQzC3glY35/sKySJNz9N8H0a0AimK6Y7EETwwWkj6QrMm/QfNIJHAIeJ/2f3mF378uR52TWYP0RoLlEUf8PsBpIBfPNFZoTwIF/MrPtZrYqWFaJP/95wG+BbwZNaN8ws8YKzZrpJuCBYLrkWSdy4a8qnv5Ir6i+tWbWBGwAPubuv8tcV0l53b3f3ZeQPqJ+J/D28iYaysyuAg65+/ZyZxmlS9z9QuAPgQ+b2aWZKyvo519Dugn1q+5+AXCUdHPJSRWUFYDgPM4K4LvZ60qVdSIX/tBv6l4EB81sBkDw9VCwvOzZzayWdNG/392/Fyyu2LwA7n4Y6CDdZDLVzAbuMJeZ52TWYP0UoKsE8ZYCK8xsL9BOurnnngrMCYC7Hwi+HgIeJv2BWok///3AfnffFsyvJ/1BUIlZB/wh8At3PxjMlzzrRC78J2/qHnzC3gRsKnOmbJuAlcH0StJt6QPLPxic1b8IOJLxr2DozMyAe4Hn3f1vKjmvmZ1hZlOD6QbS5yKeJ/0BcMMwWQe+hxuAJ4KjrFC5+6fcfba7zyX9u/iEu3+g0nICmFmjmU0emCbdHr2LCvz5u/trwCtmdm6waDnwXCVmzXAzp5p5BjKVNmupT2qU+ATK+0j3SHkJ+HSZszwA/AboJX2UcgvpNtstwIvAPwOnB8814CtB7meB1hJnvYT0v5s7gc7g8b5KzAucDzwTZN0F3BEsfxvwc2AP6X+p64Plk4L5PcH6t5Xhd2EZp3r1VFzOINOO4LF74G+nEn/+wf6XAE8HvwOPANMqOGsj6f/cpmQsK3lWDdkgIhIxE7mpR0REclDhFxGJGBV+EZGIUeEXEYkYFX4RkYhR4RfJYmZuZt/OmK8xs9/aqRE1E2a22dIjgj5nZo8Fy+daMPqqmZ1mZvdbeoTLXWb2k+BKaJGyq8n/FJHIOQosMrMGdz9G+qKwzCsm7wQed/d7AMzs/Byv8VHgoLufFzznXNLXcIiUnY74RXJ7DLgymM6+0nIG6YvwAHD3nTm2n0HGh4W7v+DuPSHkFBkzFX6R3NqBm8xsEumrg7dlrPsKcK+lb1bzaTObmWP7+4A1ZvYzM/vfZnZ2CTKLjIoKv0gOwVH8XNJH+49lrfsR6WENvk56JNBnzOyMrOd0Bs/5a+B04Ckze0fowUVGQW38IsPbBHyB9Ng6g8bCd/d/J30nre8EJ30vBbZnPScJfA/4npmlSI939Hz4sUVGpiN+keHdB3zW3Z/NXGhml5nZacH0ZOAs4N+ynrM0496pdaRvXbmvJKlF8tARv8gw3H0/8OUcq1qAvzWzPtIHT99w96ds8A3RzwK+GgxxHQMeJX1/A5Gy0+icIiIRo6YeEZGIUeEXEYkYFX4RkYhR4RcRiRgVfhGRiFHhFxGJGBV+EZGI+f8bmVGLMkg5mgAAAABJRU5ErkJggg==\n", + "image/png": "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\n", "text/plain": [ "
" ] diff --git a/pts/dataset/__init__.py b/pts/dataset/__init__.py new file mode 100644 index 0000000..2f7e766 --- /dev/null +++ b/pts/dataset/__init__.py @@ -0,0 +1 @@ +from .loader import TransformedIterableDataset \ No newline at end of file diff --git a/pts/dataset/loader.py b/pts/dataset/loader.py new file mode 100644 index 0000000..4a21409 --- /dev/null +++ b/pts/dataset/loader.py @@ -0,0 +1,35 @@ +from typing import Callable, Iterable, Iterator, List, Optional +from torch.utils import data + +from torch.utils.data import IterableDataset + +from gluonts.dataset.common import Dataset +from gluonts.transform import Transformation, TransformedDataset +from gluonts.itertools import cyclic, pseudo_shuffled + + +class TransformedIterableDataset(IterableDataset): + def __init__( + self, + dataset: Dataset, + transform: Transformation, + is_train: bool = True, + shuffle_buffer_length: Optional[int] = None, + ): + super().__init__() + self.shuffle_buffer_length = shuffle_buffer_length + + self.transformed_dataset = TransformedDataset( + cyclic(dataset), + transform, + is_train=is_train, + ) + + def __iter__(self): + if self.shuffle_buffer_length is None: + return iter(self.transformed_dataset) + else: + return pseudo_shuffled( + iter(self.transformed_dataset), + shuffle_buffer_length=self.shuffle_buffer_length, + ) diff --git a/pts/model/estimator.py b/pts/model/estimator.py index 631b913..9ac8bd7 100644 --- a/pts/model/estimator.py +++ b/pts/model/estimator.py @@ -5,10 +5,11 @@ import numpy as np import torch import torch.nn as nn +from torch.utils import data +from torch.utils.data import DataLoader from gluonts.core.component import validated from gluonts.dataset.common import Dataset -from gluonts.dataset.loader import TrainDataLoader, ValidationDataLoader from gluonts.model.estimator import Estimator from gluonts.torch.model.predictor import PyTorchPredictor from gluonts.torch.batchify import batchify @@ -16,6 +17,7 @@ from gluonts.transform import SelectFields, Transformation from pts import Trainer from pts.model import get_module_forward_input_names +from pts.dataset.loader import TransformedIterableDataset class TrainOutput(NamedTuple): @@ -78,7 +80,7 @@ class PyTorchEstimator(Estimator): training_data: Dataset, validation_data: Optional[Dataset] = None, num_workers: Optional[int] = None, - num_prefetch: Optional[int] = None, + prefetch_factor: Optional[int] = 2, shuffle_buffer_length: Optional[int] = None, **kwargs, ) -> TrainOutput: @@ -88,32 +90,33 @@ class PyTorchEstimator(Estimator): input_names = get_module_forward_input_names(trained_net) - training_data_loader = TrainDataLoader( + training_iter_dataset = TransformedIterableDataset( dataset=training_data, transform=transformation + SelectFields(input_names), - batch_size=self.trainer.batch_size, - stack_fn=partial( - batchify, - device=self.trainer.device, - ), - num_workers=num_workers, - num_prefetch=num_prefetch, + is_train=True, shuffle_buffer_length=shuffle_buffer_length, + ) + + training_data_loader = DataLoader( + training_iter_dataset, + batch_size=self.trainer.batch_size, + num_workers=num_workers, + prefetch_factor=prefetch_factor, **kwargs, ) validation_data_loader = None if validation_data is not None: - validation_data_loader = ValidationDataLoader( + validation_iter_dataset = TransformedIterableDataset( dataset=validation_data, transform=transformation + SelectFields(input_names), + is_train=True, + ) + validation_data_loader = DataLoader( + validation_iter_dataset, batch_size=self.trainer.batch_size, - stack_fn=partial( - batchify, - device=self.trainer.device, - ), num_workers=num_workers, - num_prefetch=num_prefetch, + prefetch_factor=prefetch_factor, **kwargs, ) @@ -128,7 +131,7 @@ class PyTorchEstimator(Estimator): trained_net=trained_net, predictor=self.create_predictor( transformation, trained_net, self.trainer.device - ), + ) ) def train( diff --git a/pts/trainer.py b/pts/trainer.py index af9a166..f7431a8 100644 --- a/pts/trainer.py +++ b/pts/trainer.py @@ -5,9 +5,9 @@ from tqdm import tqdm import torch import torch.nn as nn +from torch.utils.data import DataLoader from gluonts.core.component import validated -from gluonts.dataset.loader import TrainDataLoader, ValidationDataLoader class Trainer: @@ -35,8 +35,8 @@ class Trainer: def __call__( self, net: nn.Module, - train_iter: TrainDataLoader, - validation_iter: Optional[ValidationDataLoader] = None, + train_iter: DataLoader, + validation_iter: Optional[DataLoader] = None, ) -> None: optimizer = torch.optim.Adam( net.parameters(), lr=self.learning_rate, weight_decay=self.weight_decay @@ -50,9 +50,9 @@ class Trainer: with tqdm(train_iter) as it: for batch_no, data_entry in enumerate(it, start=1): optimizer.zero_grad() - #inputs = [data_entry[k].to(self.device) for k in input_names] + inputs = [v.to(self.device) for v in data_entry.values()] - output = net(*data_entry.values()) + output = net(*inputs) if isinstance(output, (list, tuple)): loss = output[0] else: @@ -67,7 +67,7 @@ class Trainer: refresh=False, ) n_iter = epoch_no * self.num_batches_per_epoch + batch_no - #.add_scalar("Loss/train", loss.item(), n_iter) + # .add_scalar("Loss/train", loss.item(), n_iter) loss.backward() optimizer.step() @@ -82,4 +82,4 @@ class Trainer: # mark epoch end time and log time cost of current epoch toc = time.time() - #writer.close() + # writer.close()