Repository: hand10ryo/PyTorchCML (language: python)

Issue:
Githubactions
I change CI/CD tool from travis to github actions


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml
new file mode 100644
index 0000000..6e9903e
--- /dev/null
+++ b/.github/workflows/python-publish.yml
@@ -0,0 +1,30 @@
+# This workflows will upload a Python Package using Twine when a release is created
+# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
+
+name: Upload Python Package
+
+on:
+  release:
+    types: [created]
+
+jobs:
+  deploy:
+
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@v2
+    - name: Set up Python
+      uses: actions/setup-python@v1
+      with:
+        python-version: '3.x'
+    - name: Install dependencies
+      run: |
+        python -m pip install --upgrade pip
+        pip install poetry poetry-dynamic-versioning twine
+    - name: Build and publish
+      env:
+        TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
+        TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
+      run: |
+        poetry publish --build --username $TWINE_USERNAME --password $TWINE_PASSWORD
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index ed36fd0..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,40 +0,0 @@
-language: python
-python:
-- 3.8
-
-env:
-  global:
-  - secure: "WhbaVui28sHA5HxjHpxB3B7O6HM8gfJDbI7Kq8dLkqmtazKCjSy4mY5fQuwCJRUzX+cvY3Dp7WN90bgFdROANiXFrjO0fdw/7AuDCKx4OFZX/hMOqxg1X8P+Uiy62gXytfscs25fswfm/FrV8fJ19lugcmxM8nxF+/feqOYbMNu6mh9CN/2WkcowA3kxcG6Juwy88rEfml3xZEm4SZ98UPvJDG0aljGWaqUdCcryofRj/1DZohzl11hEtwLYp3z008KFb38LZ0ieIK4g6I8B+xucAwzp5v3B2mEDKWNVjYIhPhP+Bsa1TR2G50NY3x4dZb8lrmzMXScRGJgkB8M/eSEDJu3YaEyeqq2I+TPQhvY5MlxEI9aDSVfRfXodf85tgRFcIKoT+EMKizRAhPd5YxX/hcV0RoqEgOt6v02eVLpxpZdzN7e3RGfL0HuQt9mQ1OvsyppDjbZbxWnaraMOJgMfUdqjE5PLGeFLL1dolGJLfoOYRo3TL/h6QwI1r5MB+b8RQz7TdJCpLoniOcASfcsl0vjGYw4jFiWyQZWuK3lCdS/f6y0Bjh1IP7ygCB6XbABcsAF8ToYFMXby940hm6/qyX9q2NBLfvksAo3YNosuInssgOjl4HM1L1d5HBTKu0T+26QleTbu5E5doOaAIkPkPsMduyI6btN5VdNrv1I="
-  - secure: "Io0pcBECX5Wo/SuPw5j8/FyBKIcTJL7SHPR1mSrezgkhWEISO3RNjZf78RJ4ZftxIs5taskpz+F+DU2UjZuxK/Yl10V9JAA8ljtAm7EARhPt9Y8J+I5xBU6Psi8p0XExQj9HlK2UixUf3hbPulNVnDSthckPkwVhRMHmgm+m0mdwxAKnervUSK16y3TOYlX82mxFHs8wBJ/ZK2ilAniI5Dxev4C3zYTOlMjEODD+vWrbNgrxlff9JygrAk7TNH8fhu15Ef/Bl8rAkSIDbMCTEtbEA92MPZU73eUKrgbkAixLKI4LBfwTd6bQXLCNyRGHO/2bgp1C9bKsWVIx2h08Qdhqh3OXJqA/T1RZ0NyL5h0zml5jT5rs4ikn3QAwEt6XY/8F6YPxA6Ya2LJGoJprkNGfMSSAsYiMSCTSLcMhJjILbbzyPvnic5VGO4VIeSBtBA0OdZ20Awldbl8jnYUL+mVqN4zVoRPHzJ3HA1zzuj5ssOYg8hHp7nj6WpclUsHGmc2249895bwRSB3Ijq4uATYfBJegmieqKs+hrMcx5NrL5Nxnz94UpSV7in7Ug+io9jK6t49oxcp0uAOKNvVIhz52lr4F6yhx2kHV+Fhz5qNF7g9vzmjh5rMaKdqNcYLv9oxEvVthAbxIvdRVUUCcDKVzrK4LYR/QzTjXVarSqFw="
-
-before_install:
-- pip install poetry
-
-install:
-- poetry install
-
-script:
-- poetry run flake8 --ignore=E501 src/PytorchCML tests
-- poetry run python -m unittest discover -b
-
-before_deploy:
-- poetry config repositories.testpypi https://test.pypi.org/legacy/
-- poetry config http-basic.testpypi $MYPYPI_USER $MYPYPI_PASS
-- poetry build -f sdist
-
-deploy:
-  provider: script
-  script: poetry publish -r testpypi
-  #skip_cleanup: true
-  #on:
-  #  tags: true
-
-#- poetry config repositories.mypypi http://mypypi.example.com/simple
-#- poetry config http-basic.mypypi $MYPYPI_USER $MYPYPI_PASS
-#- poetry build -f sdist
-#deploy:
-#  provider: script
-#  script: poetry publish -r mypypi
-#  skip_cleanup: true
-#  on:
-#    tags: true
diff --git a/examples/notebooks/movielens_cml.ipynb b/examples/notebooks/movielens_cml.ipynb
index 2dce0be..750271d 100644
--- a/examples/notebooks/movielens_cml.ipynb
+++ b/examples/notebooks/movielens_cml.ipynb
@@ -32,7 +32,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 3,
+   "execution_count": 2,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -43,7 +43,7 @@
     "movielens.columns = [\"user_id\", \"item_id\", \"rating\", \"timestamp\"]\n",
     "movielens.user_id -= 1\n",
     "movielens.item_id -= 1\n",
-    "movielens.rating = (movielens >= 4).astype(int)\n",
+    "movielens.rating = (movielens.rating >= 4).astype(int)\n",
     "n_user = movielens.user_id.nunique()\n",
     "n_item = movielens.item_id.nunique()\n",
     "\n",
@@ -120,29 +120,29 @@
      "output_type": "stream",
      "name": "stderr",
      "text": [
-      "100%|██████████| 943/943 [00:30<00:00, 30.43it/s]\n",
-      "epoch1 avg_loss:0.962: 100%|██████████| 256/256 [00:09<00:00, 28.20it/s]\n",
-      "epoch2 avg_loss:0.821: 100%|██████████| 256/256 [00:08<00:00, 31.99it/s]\n",
-      "epoch3 avg_loss:0.734: 100%|██████████| 256/256 [00:08<00:00, 28.68it/s]\n",
-      "epoch4 avg_loss:0.680: 100%|██████████| 256/256 [00:08<00:00, 31.42it/s]\n",
-      "epoch5 avg_loss:0.641: 100%|██████████| 256/256 [00:07<00:00, 33.17it/s]\n",
-      "epoch6 avg_loss:0.614: 100%|██████████| 256/256 [00:06<00:00, 38.52it/s]\n",
-      "epoch7 avg_loss:0.588: 100%|██████████| 256/256 [00:07<00:00, 36.17it/s]\n",
-      "epoch8 avg_loss:0.559: 100%|██████████| 256/256 [00:08<00:00, 31.81it/s]\n",
-      "epoch9 avg_loss:0.541: 100%|██████████| 256/256 [00:07<00:00, 34.14it/s]\n",
-      "epoch10 avg_loss:0.521: 100%|██████████| 256/256 [00:08<00:00, 28.69it/s]\n",
-      "100%|██████████| 943/943 [00:32<00:00, 29.28it/s]\n",
-      "epoch11 avg_loss:0.502: 100%|██████████| 256/256 [00:07<00:00, 35.26it/s]\n",
-      "epoch12 avg_loss:0.483: 100%|██████████| 256/256 [00:07<00:00, 34.86it/s]\n",
-      "epoch13 avg_loss:0.464: 100%|██████████| 256/256 [00:07<00:00, 32.53it/s]\n",
-      "epoch14 avg_loss:0.447: 100%|██████████| 256/256 [00:07<00:00, 32.07it/s]\n",
-      "epoch15 avg_loss:0.434: 100%|██████████| 256/256 [00:08<00:00, 30.02it/s]\n",
-      "epoch16 avg_loss:0.420: 100%|██████████| 256/256 [00:04<00:00, 53.49it/s]\n",
-      "epoch17 avg_loss:0.404: 100%|██████████| 256/256 [00:04<00:00, 53.01it/s]\n",
-      "epoch18 avg_loss:0.391: 100%|██████████| 256/256 [00:04<00:00, 57.29it/s]\n",
-      "epoch19 avg_loss:0.378: 100%|██████████| 256/256 [00:04<00:00, 57.08it/s]\n",
-      "epoch20 avg_loss:0.367: 100%|██████████| 256/256 [00:04<00:00, 53.84it/s]\n",
-      "100%|██████████| 943/943 [00:18<00:00, 49.84it/s]\n"
+      "100%|██████████| 943/943 [00:22<00:00, 41.78it/s]\n",
+      "epoch1 avg_loss:0.967: 100%|██████████| 256/256 [00:06<00:00, 37.47it/s]\n",
+      "epoch2 avg_loss:0.824: 100%|██████████| 256/256 [00:05<00:00, 48.58it/s]\n",
+      "epoch3 avg_loss:0.741: 100%|██████████| 256/256 [00:05<00:00, 50.05it/s]\n",
+      "epoch4 avg_loss:0.685: 100%|██████████| 256/256 [00:06<00:00, 42.30it/s]\n",
+      "epoch5 avg_loss:0.646: 100%|██████████| 256/256 [00:09<00:00, 27.20it/s]\n",
+      "epoch6 avg_loss:0.622: 100%|██████████| 256/256 [00:07<00:00, 32.36it/s]\n",
+      "epoch7 avg_loss:0.600: 100%|██████████| 256/256 [00:05<00:00, 44.91it/s]\n",
+      "epoch8 avg_loss:0.581: 100%|██████████| 256/256 [00:05<00:00, 48.92it/s]\n",
+      "epoch9 avg_loss:0.563: 100%|██████████| 256/256 [00:06<00:00, 41.15it/s]\n",
+      "epoch10 avg_loss:0.550: 100%|██████████| 256/256 [00:06<00:00, 42.59it/s]\n",
+      "100%|██████████| 943/943 [00:22<00:00, 41.46it/s]\n",
+      "epoch11 avg_loss:0.532: 100%|██████████| 256/256 [00:06<00:00, 38.52it/s]\n",
+      "epoch12 avg_loss:0.517: 100%|██████████| 256/256 [00:07<00:00, 36.29it/s]\n",
+      "epoch13 avg_loss:0.499: 100%|██████████| 256/256 [00:08<00:00, 31.96it/s]\n",
+      "epoch14 avg_loss:0.480: 100%|██████████| 256/256 [00:05<00:00, 45.09it/s]\n",
+      "epoch15 avg_loss:0.463: 100%|██████████| 256/256 [00:05<00:00, 46.86it/s]\n",
+      "epoch16 avg_loss:0.447: 100%|██████████| 256/256 [00:05<00:00, 45.36it/s]\n",
+      "epoch17 avg_loss:0.424: 100%|██████████| 256/256 [00:07<00:00, 34.68it/s]\n",
+      "epoch18 avg_loss:0.409: 100%|██████████| 256/256 [00:05<00:00, 45.60it/s]\n",
+      "epoch19 avg_loss:0.390: 100%|██████████| 256/256 [00:05<00:00, 44.48it/s]\n",
+      "epoch20 avg_loss:0.375: 100%|██████████| 256/256 [00:06<00:00, 40.54it/s]\n",
+      "100%|██████████| 943/943 [00:23<00:00, 40.68it/s]\n"
      ]
     }
    ],
@@ -160,11 +160,11 @@
      "data": {
       "text/plain": [
        "     nDCG@3     MAP@3  Recall@3    nDCG@5     MAP@5  Recall@5  epoch      loss\n",
-       "0  0.018667  0.033051  0.002104  0.019511  0.040509  0.003674      0       NaN\n",
-       "0  0.079036  0.119477  0.006106  0.078784  0.132808  0.009886     10  0.520977\n",
-       "0  0.240874  0.331478  0.028101  0.244704  0.348947  0.048870     20  0.366803"
+       "0  0.019834  0.036144  0.002331  0.019754  0.042109  0.003795      0       NaN\n",
+       "0  0.055078  0.088017  0.004533  0.057107  0.101432  0.008006     10  0.549945\n",
+       "0  0.274714  0.365323  0.032301  0.271033  0.381550  0.054757     20  0.375043"
       ],
-      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>nDCG@3</th>\n      <th>MAP@3</th>\n      <th>Recall@3</th>\n      <th>nDCG@5</th>\n      <th>MAP@5</th>\n      <th>Recall@5</th>\n      <th>epoch</th>\n      <th>loss</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>0.018667</td>\n      <td>0.033051</td>\n      <td>0.002104</td>\n      <td>0.019511</td>\n      <td>0.040509</td>\n      <td>0.003674</td>\n      <td>0</td>\n      <td>NaN</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.079036</td>\n      <td>0.119477</td>\n      <td>0.006106</td>\n      <td>0.078784</td>\n      <td>0.132808</td>\n      <td>0.009886</td>\n      <td>10</td>\n      <td>0.520977</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.240874</td>\n      <td>0.331478</td>\n      <td>0.028101</td>\n      <td>0.244704</td>\n      <td>0.348947</td>\n      <td>0.048870</td>\n      <td>20</td>\n      <td>0.366803</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
+      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>nDCG@3</th>\n      <th>MAP@3</th>\n      <th>Recall@3</th>\n      <th>nDCG@5</th>\n      <th>MAP@5</th>\n      <th>Recall@5</th>\n      <th>epoch</th>\n      <th>loss</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>0.019834</td>\n      <td>0.036144</td>\n      <td>0.002331</td>\n      <td>0.019754</td>\n      <td>0.042109</td>\n      <td>0.003795</td>\n      <td>0</td>\n      <td>NaN</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.055078</td>\n      <td>0.088017</td>\n      <td>0.004533</td>\n      <td>0.057107</td>\n      <td>0.101432</td>\n      <td>0.008006</td>\n      <td>10</td>\n      <td>0.549945</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.274714</td>\n      <td>0.365323</td>\n      <td>0.032301</td>\n      <td>0.271033</td>\n      <td>0.381550</td>\n      <td>0.054757</td>\n      <td>20</td>\n      <td>0.375043</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
      },
      "metadata": {},
      "execution_count": 5
@@ -183,7 +183,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 3,
+   "execution_count": 6,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -205,7 +205,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 4,
+   "execution_count": 7,
    "metadata": {
     "tags": []
    },
@@ -214,29 +214,29 @@
      "output_type": "stream",
      "name": "stderr",
      "text": [
-      "100%|██████████| 943/943 [00:20<00:00, 45.62it/s]\n",
-      "epoch1 avg_loss:2417.863: 100%|██████████| 256/256 [00:05<00:00, 50.05it/s]\n",
-      "epoch2 avg_loss:2029.371: 100%|██████████| 256/256 [00:05<00:00, 49.94it/s]\n",
-      "epoch3 avg_loss:1785.995: 100%|██████████| 256/256 [00:05<00:00, 48.09it/s]\n",
-      "epoch4 avg_loss:1634.948: 100%|██████████| 256/256 [00:05<00:00, 44.17it/s]\n",
-      "epoch5 avg_loss:1528.421: 100%|██████████| 256/256 [00:05<00:00, 44.09it/s]\n",
-      "epoch6 avg_loss:1447.919: 100%|██████████| 256/256 [00:05<00:00, 49.69it/s]\n",
-      "epoch7 avg_loss:1379.544: 100%|██████████| 256/256 [00:04<00:00, 51.63it/s]\n",
-      "epoch8 avg_loss:1325.176: 100%|██████████| 256/256 [00:05<00:00, 49.94it/s]\n",
-      "epoch9 avg_loss:1263.473: 100%|██████████| 256/256 [00:06<00:00, 38.81it/s]\n",
-      "epoch10 avg_loss:1212.099: 100%|██████████| 256/256 [00:05<00:00, 47.63it/s]\n",
-      "100%|██████████| 943/943 [00:17<00:00, 53.65it/s]\n",
-      "epoch11 avg_loss:1144.911: 100%|██████████| 256/256 [00:06<00:00, 40.40it/s]\n",
-      "epoch12 avg_loss:1094.742: 100%|██████████| 256/256 [00:06<00:00, 38.24it/s]\n",
-      "epoch13 avg_loss:1032.858: 100%|██████████| 256/256 [00:07<00:00, 36.32it/s]\n",
-      "epoch14 avg_loss:978.566: 100%|██████████| 256/256 [00:06<00:00, 39.07it/s]\n",
-      "epoch15 avg_loss:928.560: 100%|██████████| 256/256 [00:05<00:00, 50.46it/s]\n",
-      "epoch16 avg_loss:890.377: 100%|██████████| 256/256 [00:06<00:00, 38.62it/s]\n",
-      "epoch17 avg_loss:843.485: 100%|██████████| 256/256 [00:06<00:00, 42.66it/s]\n",
-      "epoch18 avg_loss:802.504: 100%|██████████| 256/256 [00:07<00:00, 35.83it/s]\n",
-      "epoch19 avg_loss:768.113: 100%|██████████| 256/256 [00:05<00:00, 46.46it/s]\n",
-      "epoch20 avg_loss:738.999: 100%|██████████| 256/256 [00:05<00:00, 46.60it/s]\n",
-      "100%|██████████| 943/943 [00:15<00:00, 59.91it/s]\n"
+      "100%|██████████| 943/943 [00:18<00:00, 51.01it/s]\n",
+      "epoch1 avg_loss:0.949: 100%|██████████| 256/256 [00:09<00:00, 26.99it/s]\n",
+      "epoch2 avg_loss:0.792: 100%|██████████| 256/256 [00:09<00:00, 26.42it/s]\n",
+      "epoch3 avg_loss:0.697: 100%|██████████| 256/256 [00:09<00:00, 25.81it/s]\n",
+      "epoch4 avg_loss:0.636: 100%|██████████| 256/256 [00:09<00:00, 27.21it/s]\n",
+      "epoch5 avg_loss:0.597: 100%|██████████| 256/256 [00:07<00:00, 34.30it/s]\n",
+      "epoch6 avg_loss:0.564: 100%|██████████| 256/256 [00:07<00:00, 34.35it/s]\n",
+      "epoch7 avg_loss:0.538: 100%|██████████| 256/256 [00:07<00:00, 34.95it/s]\n",
+      "epoch8 avg_loss:0.517: 100%|██████████| 256/256 [00:08<00:00, 29.53it/s]\n",
+      "epoch9 avg_loss:0.494: 100%|██████████| 256/256 [00:08<00:00, 28.63it/s]\n",
+      "epoch10 avg_loss:0.471: 100%|██████████| 256/256 [00:07<00:00, 32.86it/s]\n",
+      "100%|██████████| 943/943 [00:23<00:00, 40.65it/s]\n",
+      "epoch11 avg_loss:0.450: 100%|██████████| 256/256 [00:07<00:00, 33.37it/s]\n",
+      "epoch12 avg_loss:0.425: 100%|██████████| 256/256 [00:07<00:00, 33.03it/s]\n",
+      "epoch13 avg_loss:0.405: 100%|██████████| 256/256 [00:09<00:00, 27.11it/s]\n",
+      "epoch14 avg_loss:0.388: 100%|██████████| 256/256 [00:08<00:00, 29.81it/s]\n",
+      "epoch15 avg_loss:0.369: 100%|██████████| 256/256 [00:07<00:00, 33.38it/s]\n",
+      "epoch16 avg_loss:0.350: 100%|██████████| 256/256 [00:08<00:00, 29.23it/s]\n",
+      "epoch17 avg_loss:0.333: 100%|██████████| 256/256 [00:08<00:00, 28.81it/s]\n",
+      "epoch18 avg_loss:0.316: 100%|██████████| 256/256 [00:07<00:00, 33.58it/s]\n",
+      "epoch19 avg_loss:0.301: 100%|██████████| 256/256 [00:07<00:00, 34.74it/s]\n",
+      "epoch20 avg_loss:0.288: 100%|██████████| 256/256 [00:07<00:00, 33.92it/s]\n",
+      "100%|██████████| 943/943 [00:24<00:00, 39.21it/s]\n"
      ]
     }
    ],
@@ -246,27 +246,22 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": 8,
    "metadata": {},
    "outputs": [
     {
      "output_type": "execute_result",
      "data": {
       "text/plain": [
-       "     nDCG@3     MAP@3  Recall@3    nDCG@5     MAP@5  Recall@5  epoch  \\\n",
-       "0  0.015895  0.028455  0.001643  0.015187  0.033086  0.002452      0   \n",
-       "0  0.057471  0.091110  0.004146  0.063293  0.107319  0.008038     10   \n",
-       "0  0.254217  0.345263  0.029643  0.251258  0.355607  0.048304     20   \n",
-       "\n",
-       "          loss  \n",
-       "0          NaN  \n",
-       "0  1212.098991  \n",
-       "0   738.998521  "
+       "     nDCG@3     MAP@3  Recall@3    nDCG@5     MAP@5  Recall@5  epoch      loss\n",
+       "0  0.020385  0.036939  0.001419  0.018477  0.041640  0.002321      0       NaN\n",
+       "0  0.059936  0.091552  0.004546  0.068632  0.110379  0.009836     10  0.471340\n",
+       "0  0.273629  0.369123  0.034714  0.272501  0.385817  0.059150     20  0.287908"
       ],
-      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>nDCG@3</th>\n      <th>MAP@3</th>\n      <th>Recall@3</th>\n      <th>nDCG@5</th>\n      <th>MAP@5</th>\n      <th>Recall@5</th>\n      <th>epoch</th>\n      <th>loss</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>0.015895</td>\n      <td>0.028455</td>\n      <td>0.001643</td>\n      <td>0.015187</td>\n      <td>0.033086</td>\n      <td>0.002452</td>\n      <td>0</td>\n      <td>NaN</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.057471</td>\n      <td>0.091110</td>\n      <td>0.004146</td>\n      <td>0.063293</td>\n      <td>0.107319</td>\n      <td>0.008038</td>\n      <td>10</td>\n      <td>1212.098991</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.254217</td>\n      <td>0.345263</td>\n      <td>0.029643</td>\n      <td>0.251258</td>\n      <td>0.355607</td>\n      <td>0.048304</td>\n      <td>20</td>\n      <td>738.998521</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
+      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>nDCG@3</th>\n      <th>MAP@3</th>\n      <th>Recall@3</th>\n      <th>nDCG@5</th>\n      <th>MAP@5</th>\n      <th>Recall@5</th>\n      <th>epoch</th>\n      <th>loss</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>0.020385</td>\n      <td>0.036939</td>\n      <td>0.001419</td>\n      <td>0.018477</td>\n      <td>0.041640</td>\n      <td>0.002321</td>\n      <td>0</td>\n      <td>NaN</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.059936</td>\n      <td>0.091552</td>\n      <td>0.004546</td>\n      <td>0.068632</td>\n      <td>0.110379</td>\n      <td>0.009836</td>\n      <td>10</td>\n      <td>0.471340</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.273629</td>\n      <td>0.369123</td>\n      <td>0.034714</td>\n      <td>0.272501</td>\n      <td>0.385817</td>\n      <td>0.059150</td>\n      <td>20</td>\n      <td>0.287908</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
      },
      "metadata": {},
-     "execution_count": 5
+     "execution_count": 8
     }
    ],
    "source": [
@@ -282,7 +277,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
+   "execution_count": 9,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -305,36 +300,36 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 7,
+   "execution_count": 10,
    "metadata": {},
    "outputs": [
     {
      "output_type": "stream",
      "name": "stderr",
      "text": [
-      "100%|██████████| 943/943 [00:16<00:00, 58.07it/s]\n",
-      "epoch1 avg_loss:0.949: 100%|██████████| 256/256 [00:06<00:00, 39.48it/s]\n",
-      "epoch2 avg_loss:0.794: 100%|██████████| 256/256 [00:05<00:00, 45.86it/s]\n",
-      "epoch3 avg_loss:0.701: 100%|██████████| 256/256 [00:05<00:00, 45.36it/s]\n",
-      "epoch4 avg_loss:0.635: 100%|██████████| 256/256 [00:06<00:00, 40.16it/s]\n",
-      "epoch5 avg_loss:0.591: 100%|██████████| 256/256 [00:05<00:00, 46.39it/s]\n",
-      "epoch6 avg_loss:0.560: 100%|██████████| 256/256 [00:05<00:00, 46.34it/s]\n",
-      "epoch7 avg_loss:0.529: 100%|██████████| 256/256 [00:05<00:00, 48.27it/s]\n",
-      "epoch8 avg_loss:0.504: 100%|██████████| 256/256 [00:05<00:00, 47.73it/s]\n",
-      "epoch9 avg_loss:0.473: 100%|██████████| 256/256 [00:05<00:00, 46.01it/s]\n",
-      "epoch10 avg_loss:0.448: 100%|██████████| 256/256 [00:05<00:00, 47.51it/s]\n",
-      "100%|██████████| 943/943 [00:16<00:00, 56.99it/s]\n",
-      "epoch11 avg_loss:0.425: 100%|██████████| 256/256 [00:05<00:00, 45.93it/s]\n",
-      "epoch12 avg_loss:0.402: 100%|██████████| 256/256 [00:06<00:00, 41.36it/s]\n",
-      "epoch13 avg_loss:0.380: 100%|██████████| 256/256 [00:05<00:00, 47.21it/s]\n",
-      "epoch14 avg_loss:0.362: 100%|██████████| 256/256 [00:06<00:00, 41.12it/s]\n",
-      "epoch15 avg_loss:0.341: 100%|██████████| 256/256 [00:06<00:00, 41.19it/s]\n",
-      "epoch16 avg_loss:0.329: 100%|██████████| 256/256 [00:05<00:00, 46.64it/s]\n",
-      "epoch17 avg_loss:0.310: 100%|██████████| 256/256 [00:05<00:00, 46.61it/s]\n",
-      "epoch18 avg_loss:0.299: 100%|██████████| 256/256 [00:05<00:00, 47.67it/s]\n",
-      "epoch19 avg_loss:0.287: 100%|██████████| 256/256 [00:06<00:00, 40.60it/s]\n",
-      "epoch20 avg_loss:0.278: 100%|██████████| 256/256 [00:05<00:00, 42.73it/s]\n",
-      "100%|██████████| 943/943 [00:16<00:00, 57.42it/s]\n"
+      "100%|██████████| 943/943 [00:21<00:00, 44.39it/s]\n",
+      "epoch1 avg_loss:0.948: 100%|██████████| 256/256 [00:11<00:00, 21.50it/s]\n",
+      "epoch2 avg_loss:0.794: 100%|██████████| 256/256 [00:07<00:00, 32.35it/s]\n",
+      "epoch3 avg_loss:0.700: 100%|██████████| 256/256 [00:07<00:00, 33.16it/s]\n",
+      "epoch4 avg_loss:0.638: 100%|██████████| 256/256 [00:10<00:00, 23.36it/s]\n",
+      "epoch5 avg_loss:0.598: 100%|██████████| 256/256 [00:07<00:00, 34.20it/s]\n",
+      "epoch6 avg_loss:0.565: 100%|██████████| 256/256 [00:08<00:00, 31.81it/s]\n",
+      "epoch7 avg_loss:0.540: 100%|██████████| 256/256 [00:07<00:00, 32.40it/s]\n",
+      "epoch8 avg_loss:0.516: 100%|██████████| 256/256 [00:07<00:00, 33.46it/s]\n",
+      "epoch9 avg_loss:0.493: 100%|██████████| 256/256 [00:13<00:00, 19.51it/s]\n",
+      "epoch10 avg_loss:0.470: 100%|██████████| 256/256 [00:08<00:00, 31.15it/s]\n",
+      "100%|██████████| 943/943 [00:24<00:00, 38.92it/s]\n",
+      "epoch11 avg_loss:0.449: 100%|██████████| 256/256 [00:08<00:00, 28.90it/s]\n",
+      "epoch12 avg_loss:0.422: 100%|██████████| 256/256 [00:08<00:00, 31.93it/s]\n",
+      "epoch13 avg_loss:0.401: 100%|██████████| 256/256 [00:10<00:00, 23.42it/s]\n",
+      "epoch14 avg_loss:0.377: 100%|██████████| 256/256 [00:08<00:00, 31.57it/s]\n",
+      "epoch15 avg_loss:0.357: 100%|██████████| 256/256 [00:11<00:00, 22.92it/s]\n",
+      "epoch16 avg_loss:0.338: 100%|██████████| 256/256 [00:07<00:00, 33.48it/s]\n",
+      "epoch17 avg_loss:0.318: 100%|██████████| 256/256 [00:08<00:00, 30.68it/s]\n",
+      "epoch18 avg_loss:0.304: 100%|██████████| 256/256 [00:08<00:00, 31.37it/s]\n",
+      "epoch19 avg_loss:0.289: 100%|██████████| 256/256 [00:07<00:00, 33.49it/s]\n",
+      "epoch20 avg_loss:0.281: 100%|██████████| 256/256 [00:13<00:00, 18.94it/s]\n",
+      "100%|██████████| 943/943 [00:24<00:00, 38.13it/s]\n"
      ]
     }
    ],
@@ -344,7 +339,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 8,
+   "execution_count": 11,
    "metadata": {},
    "outputs": [
     {
@@ -352,27 +347,20 @@
      "data": {
       "text/plain": [
        "     nDCG@3     MAP@3  Recall@3    nDCG@5     MAP@5  Recall@5  epoch      loss\n",
-       "0  0.014230  0.025097  0.001684  0.014524  0.030877  0.002610      0       NaN\n",
-       "0  0.074575  0.116472  0.005911  0.080112  0.130880  0.010192     10  0.447714\n",
-       "0  0.274891  0.366826  0.033157  0.272943  0.381603  0.055453     20  0.278262"
+       "0  0.017032  0.029692  0.002178  0.017122  0.036462  0.003362      0       NaN\n",
+       "0  0.074296  0.115500  0.005293  0.075128  0.125672  0.008741     10  0.469893\n",
+       "0  0.276036  0.380877  0.035444  0.276884  0.395498  0.060833     20  0.281246"
       ],
-      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>nDCG@3</th>\n      <th>MAP@3</th>\n      <th>Recall@3</th>\n      <th>nDCG@5</th>\n      <th>MAP@5</th>\n      <th>Recall@5</th>\n      <th>epoch</th>\n      <th>loss</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>0.014230</td>\n      <td>0.025097</td>\n      <td>0.001684</td>\n      <td>0.014524</td>\n      <td>0.030877</td>\n      <td>0.002610</td>\n      <td>0</td>\n      <td>NaN</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.074575</td>\n      <td>0.116472</td>\n      <td>0.005911</td>\n      <td>0.080112</td>\n      <td>0.130880</td>\n      <td>0.010192</td>\n      <td>10</td>\n      <td>0.447714</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.274891</td>\n      <td>0.366826</td>\n      <td>0.033157</td>\n      <td>0.272943</td>\n      <td>0.381603</td>\n      <td>0.055453</td>\n      <td>20</td>\n      <td>0.278262</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
+      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>nDCG@3</th>\n      <th>MAP@3</th>\n      <th>Recall@3</th>\n      <th>nDCG@5</th>\n      <th>MAP@5</th>\n      <th>Recall@5</th>\n      <th>epoch</th>\n      <th>loss</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>0.017032</td>\n      <td>0.029692</td>\n      <td>0.002178</td>\n      <td>0.017122</td>\n      <td>0.036462</td>\n      <td>0.003362</td>\n      <td>0</td>\n      <td>NaN</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.074296</td>\n      <td>0.115500</td>\n      <td>0.005293</td>\n      <td>0.075128</td>\n      <td>0.125672</td>\n      <td>0.008741</td>\n      <td>10</td>\n      <td>0.469893</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.276036</td>\n      <td>0.380877</td>\n      <td>0.035444</td>\n      <td>0.276884</td>\n      <td>0.395498</td>\n      <td>0.060833</td>\n      <td>20</td>\n      <td>0.281246</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
      },
      "metadata": {},
-     "execution_count": 8
+     "execution_count": 11
     }
    ],
    "source": [
     "trainer.valid_scores"
    ]
   },
-  {
-   "cell_type": "code",
-   "execution_count": 3,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  },
   {
    "source": [
     "## Two Stage"
@@ -382,7 +370,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 32,
+   "execution_count": 3,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -394,7 +382,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 36,
+   "execution_count": 4,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -422,36 +410,36 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 37,
+   "execution_count": 5,
    "metadata": {},
    "outputs": [
     {
      "output_type": "stream",
      "name": "stderr",
      "text": [
-      "100%|██████████| 943/943 [00:17<00:00, 55.23it/s]\n",
-      "epoch1 avg_loss:1.502: 100%|██████████| 256/256 [00:07<00:00, 32.20it/s]\n",
-      "epoch2 avg_loss:1.321: 100%|██████████| 256/256 [00:07<00:00, 33.57it/s]\n",
-      "epoch3 avg_loss:1.211: 100%|██████████| 256/256 [00:08<00:00, 30.25it/s]\n",
-      "epoch4 avg_loss:1.147: 100%|██████████| 256/256 [00:07<00:00, 33.68it/s]\n",
-      "epoch5 avg_loss:1.111: 100%|██████████| 256/256 [00:07<00:00, 33.29it/s]\n",
-      "epoch6 avg_loss:1.083: 100%|██████████| 256/256 [00:09<00:00, 26.92it/s]\n",
-      "epoch7 avg_loss:1.071: 100%|██████████| 256/256 [00:07<00:00, 33.93it/s]\n",
-      "epoch8 avg_loss:1.061: 100%|██████████| 256/256 [00:07<00:00, 32.92it/s]\n",
-      "epoch9 avg_loss:1.053: 100%|██████████| 256/256 [00:08<00:00, 31.70it/s]\n",
-      "epoch10 avg_loss:1.044: 100%|██████████| 256/256 [00:08<00:00, 31.08it/s]\n",
-      "100%|██████████| 943/943 [00:16<00:00, 57.75it/s]\n",
-      "epoch11 avg_loss:1.040: 100%|██████████| 256/256 [00:07<00:00, 32.89it/s]\n",
-      "epoch12 avg_loss:1.032: 100%|██████████| 256/256 [00:09<00:00, 28.05it/s]\n",
-      "epoch13 avg_loss:1.029: 100%|██████████| 256/256 [00:07<00:00, 32.40it/s]\n",
-      "epoch14 avg_loss:1.025: 100%|██████████| 256/256 [00:08<00:00, 28.82it/s]\n",
-      "epoch15 avg_loss:1.019: 100%|██████████| 256/256 [00:09<00:00, 25.82it/s]\n",
-      "epoch16 avg_loss:1.016: 100%|██████████| 256/256 [00:09<00:00, 26.78it/s]\n",
-      "epoch17 avg_loss:1.013: 100%|██████████| 256/256 [00:09<00:00, 26.46it/s]\n",
-      "epoch18 avg_loss:1.010: 100%|██████████| 256/256 [00:08<00:00, 29.98it/s]\n",
-      "epoch19 avg_loss:1.006: 100%|██████████| 256/256 [00:09<00:00, 26.39it/s]\n",
-      "epoch20 avg_loss:1.006: 100%|██████████| 256/256 [00:07<00:00, 32.96it/s]\n",
-      "100%|██████████| 943/943 [00:16<00:00, 58.30it/s]\n"
+      "100%|██████████| 943/943 [00:27<00:00, 34.76it/s]\n",
+      "epoch1 avg_loss:1.495: 100%|██████████| 256/256 [00:08<00:00, 31.49it/s]\n",
+      "epoch2 avg_loss:1.321: 100%|██████████| 256/256 [00:07<00:00, 36.29it/s]\n",
+      "epoch3 avg_loss:1.207: 100%|██████████| 256/256 [00:06<00:00, 37.32it/s]\n",
+      "epoch4 avg_loss:1.144: 100%|██████████| 256/256 [00:16<00:00, 15.77it/s]\n",
+      "epoch5 avg_loss:1.108: 100%|██████████| 256/256 [00:11<00:00, 22.04it/s]\n",
+      "epoch6 avg_loss:1.084: 100%|██████████| 256/256 [00:12<00:00, 20.87it/s]\n",
+      "epoch7 avg_loss:1.074: 100%|██████████| 256/256 [00:08<00:00, 28.55it/s]\n",
+      "epoch8 avg_loss:1.060: 100%|██████████| 256/256 [00:06<00:00, 38.29it/s]\n",
+      "epoch9 avg_loss:1.050: 100%|██████████| 256/256 [00:06<00:00, 37.60it/s]\n",
+      "epoch10 avg_loss:1.044: 100%|██████████| 256/256 [00:05<00:00, 43.88it/s]\n",
+      "100%|██████████| 943/943 [00:22<00:00, 42.64it/s]\n",
+      "epoch11 avg_loss:1.036: 100%|██████████| 256/256 [00:06<00:00, 40.12it/s]\n",
+      "epoch12 avg_loss:1.030: 100%|██████████| 256/256 [00:06<00:00, 39.84it/s]\n",
+      "epoch13 avg_loss:1.028: 100%|██████████| 256/256 [00:08<00:00, 30.95it/s]\n",
+      "epoch14 avg_loss:1.024: 100%|██████████| 256/256 [00:06<00:00, 41.29it/s]\n",
+      "epoch15 avg_loss:1.020: 100%|██████████| 256/256 [00:06<00:00, 36.79it/s]\n",
+      "epoch16 avg_loss:1.018: 100%|██████████| 256/256 [00:06<00:00, 38.61it/s]\n",
+      "epoch17 avg_loss:1.014: 100%|██████████| 256/256 [00:06<00:00, 38.05it/s]\n",
+      "epoch18 avg_loss:1.011: 100%|██████████| 256/256 [00:08<00:00, 30.10it/s]\n",
+      "epoch19 avg_loss:1.008: 100%|██████████| 256/256 [00:06<00:00, 39.79it/s]\n",
+      "epoch20 avg_loss:1.001: 100%|██████████| 256/256 [00:06<00:00, 39.21it/s]\n",
+      "100%|██████████| 943/943 [00:22<00:00, 41.77it/s]\n"
      ]
     }
    ],
@@ -461,7 +449,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 38,
+   "execution_count": 6,
    "metadata": {},
    "outputs": [
     {
@@ -469,14 +457,14 @@
      "data": {
       "text/plain": [
        "     nDCG@3     MAP@3  Recall@3    nDCG@5     MAP@5  Recall@5  epoch      loss\n",
-       "0  0.017962  0.034023  0.001885  0.017329  0.040703  0.003181      0       NaN\n",
-       "0  0.225361  0.311594  0.023387  0.219194  0.322207  0.038719     10  1.044481\n",
-       "0  0.378223  0.525097  0.057584  0.339713  0.521593  0.078961     20  1.006334"
+       "0  0.012986  0.022004  0.001167  0.013278  0.028190  0.002582      0       NaN\n",
+       "0  0.207166  0.293655  0.019897  0.200064  0.305768  0.033076     10  1.043901\n",
+       "0  0.356546  0.484093  0.052573  0.326033  0.484409  0.074481     20  1.001474"
       ],
-      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>nDCG@3</th>\n      <th>MAP@3</th>\n      <th>Recall@3</th>\n      <th>nDCG@5</th>\n      <th>MAP@5</th>\n      <th>Recall@5</th>\n      <th>epoch</th>\n      <th>loss</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>0.017962</td>\n      <td>0.034023</td>\n      <td>0.001885</td>\n      <td>0.017329</td>\n      <td>0.040703</td>\n      <td>0.003181</td>\n      <td>0</td>\n      <td>NaN</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.225361</td>\n      <td>0.311594</td>\n      <td>0.023387</td>\n      <td>0.219194</td>\n      <td>0.322207</td>\n      <td>0.038719</td>\n      <td>10</td>\n      <td>1.044481</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.378223</td>\n      <td>0.525097</td>\n      <td>0.057584</td>\n      <td>0.339713</td>\n      <td>0.521593</td>\n      <td>0.078961</td>\n      <td>20</td>\n      <td>1.006334</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
+      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>nDCG@3</th>\n      <th>MAP@3</th>\n      <th>Recall@3</th>\n      <th>nDCG@5</th>\n      <th>MAP@5</th>\n      <th>Recall@5</th>\n      <th>epoch</th>\n      <th>loss</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>0.012986</td>\n      <td>0.022004</td>\n      <td>0.001167</td>\n      <td>0.013278</td>\n      <td>0.028190</td>\n      <td>0.002582</td>\n      <td>0</td>\n      <td>NaN</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.207166</td>\n      <td>0.293655</td>\n      <td>0.019897</td>\n      <td>0.200064</td>\n      <td>0.305768</td>\n      <td>0.033076</td>\n      <td>10</td>\n      <td>1.043901</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.356546</td>\n      <td>0.484093</td>\n      <td>0.052573</td>\n      <td>0.326033</td>\n      <td>0.484409</td>\n      <td>0.074481</td>\n      <td>20</td>\n      <td>1.001474</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
      },
      "metadata": {},
-     "execution_count": 38
+     "execution_count": 6
     }
    ],
    "source": [
@@ -635,9 +623,8 @@
  ],
  "metadata": {
   "kernelspec": {
-   "name": "python386jvsc74a57bd0a5a0c39373d96a87cc399fa7087b287d0958347ac1f7dfc9bbd735675b2536e2",
-   "display_name": "Python 3.8.6 64-bit ('pytorchcml-MJCCLiEQ-py3.8': venv)",
-   "language": "python"
+   "name": "python386jvsc74a57bd01a6e8c4c71356cfd7f7f45384d81183fdca12e98ad893ee020bd76249bbd6be9",
+   "display_name": "Python 3.8.6 64-bit ('pytorchcml-MJCCLiEQ-py3.8': poetry)"
   },
   "language_info": {
    "codemirror_mode": {
diff --git a/examples/notebooks/movielens_mf.ipynb b/examples/notebooks/movielens_mf.ipynb
index 909de9d..f979b01 100644
--- a/examples/notebooks/movielens_mf.ipynb
+++ b/examples/notebooks/movielens_mf.ipynb
@@ -11,11 +11,10 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 2,
+   "execution_count": 1,
    "metadata": {},
    "outputs": [],
    "source": [
-    "\n",
     "import sys\n",
     "sys.path.append(\"../../src/\")\n",
     "\n",
@@ -33,24 +32,32 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 3,
+   "execution_count": 2,
    "metadata": {},
    "outputs": [],
    "source": [
-    "def svd_init(M, dim):\n",
+    "def svd_init(X, dim):\n",
+    "    \"\"\"\n",
+    "    Args :\n",
+    "        X : csr_matrix which element is 0 or 1.\n",
+    "        dim : number of dimention\n",
+    "    \"\"\"\n",
     "    svd = TruncatedSVD(n_components=10)\n",
-    "    U_ = svd.fit_transform(M)\n",
+    "    U_ = svd.fit_transform(X)\n",
     "    V_ = svd.components_\n",
-    "    S = np.diag(svd.singular_values_)\n",
-    "    U = np.dot(U_, np.sqrt(S))\n",
-    "    V = np.dot(np.sqrt(S), V_)\n",
     "\n",
-    "    return U, V"
+    "    s = (U_.sum(axis=1).mean() + V_.sum(axis=0).mean()) / 2\n",
+    "    U = 2 ** 0.5 * U_ - (1 / n_dim) ** 0.5 * s * np.ones_like(U_)\n",
+    "    V = 2 ** 0.5 * V_ + (1 / n_dim) ** 0.5 / s * np.ones_like(V_)\n",
+    "    ub = -(2 / n_dim) ** 0.5 * U_.sum(axis=1) / s\n",
+    "    vb = (2 / n_dim) ** 0.5 * V_.sum(axis=0) * s\n",
+    "\n",
+    "    return U, V, ub, vb"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 4,
+   "execution_count": 3,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -61,11 +68,11 @@
     "movielens.columns = [\"user_id\", \"item_id\", \"rating\", \"timestamp\"]\n",
     "movielens.user_id -= 1\n",
     "movielens.item_id -= 1\n",
-    "movielens.rating = (movielens >= 4).astype(int)\n",
+    "movielens.rating = (movielens.rating >= 4).astype(int)\n",
     "n_user = movielens.user_id.nunique()\n",
     "n_item = movielens.item_id.nunique()\n",
     "\n",
-    "train, test = train_test_split(movielens)\n",
+    "train, test = train_test_split(movielens.copy())\n",
     "\n",
     "\n",
     "# all user item pairs\n",
@@ -92,12 +99,17 @@
     "\n",
     "# numpy array\n",
     "train_set = train[train.rating == 1][[\"user_id\", \"item_id\"]].values\n",
-    "test_set = test[[\"user_id\", \"item_id\", \"rating\"]].values\n"
+    "test_set = test[[\"user_id\", \"item_id\", \"rating\"]].values\n",
+    "\n",
+    "# to torch.Tensor\n",
+    "device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n",
+    "train_set = torch.LongTensor(train_set).to(device)\n",
+    "test_set = torch.LongTensor(test_set).to(device)\n"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 22,
+   "execution_count": 4,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -106,17 +118,19 @@
     "    (np.ones(train_set.shape[0]), (train_set[:,0], train_set[:,1])),\n",
     "    shape=[n_user, n_item]\n",
     ")\n",
-    "U_, V_ = svd_init(X, n_dim) \n",
-    "s = (U_.sum(axis=1).mean() + V_.sum(axis=0).mean()) / 2\n",
-    "U = 2 ** 0.5 * U_ - (1 / n_dim) ** 0.5 * s * np.ones_like(U_)\n",
-    "V = 2 ** 0.5 * V_ + (1 / n_dim) ** 0.5 / s * np.ones_like(V_)\n",
-    "ub = -(2 / n_dim) ** 0.5 * U_.sum(axis=1) / s\n",
-    "vb = (2 / n_dim) ** 0.5 * V_.sum(axis=0) * s"
+    "U, V, ub, vb = svd_init(X, n_dim)"
    ]
   },
+  {
+   "source": [
+    "# Naive MF"
+   ],
+   "cell_type": "markdown",
+   "metadata": {}
+  },
   {
    "cell_type": "code",
-   "execution_count": 23,
+   "execution_count": 5,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -146,32 +160,146 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 24,
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [
+    {
+     "output_type": "stream",
+     "name": "stderr",
+     "text": [
+      "100%|██████████| 943/943 [00:15<00:00, 59.02it/s]\n",
+      "epoch1 avg_loss:0.483: 100%|██████████| 50/50 [00:01<00:00, 29.97it/s]\n",
+      "epoch2 avg_loss:0.432: 100%|██████████| 50/50 [00:01<00:00, 28.96it/s]\n",
+      "epoch3 avg_loss:0.397: 100%|██████████| 50/50 [00:01<00:00, 27.35it/s]\n",
+      "epoch4 avg_loss:0.374: 100%|██████████| 50/50 [00:01<00:00, 29.84it/s]\n",
+      "epoch5 avg_loss:0.356: 100%|██████████| 50/50 [00:01<00:00, 27.78it/s]\n",
+      "100%|██████████| 943/943 [00:16<00:00, 56.00it/s]\n",
+      "epoch6 avg_loss:0.342: 100%|██████████| 50/50 [00:01<00:00, 30.99it/s]\n",
+      "epoch7 avg_loss:0.333: 100%|██████████| 50/50 [00:01<00:00, 25.26it/s]\n",
+      "epoch8 avg_loss:0.323: 100%|██████████| 50/50 [00:02<00:00, 22.10it/s]\n",
+      "epoch9 avg_loss:0.316: 100%|██████████| 50/50 [00:04<00:00, 10.34it/s]\n",
+      "epoch10 avg_loss:0.309: 100%|██████████| 50/50 [00:02<00:00, 17.51it/s]\n",
+      "100%|██████████| 943/943 [00:18<00:00, 50.22it/s]\n",
+      "epoch11 avg_loss:0.305: 100%|██████████| 50/50 [00:01<00:00, 26.74it/s]\n",
+      "epoch12 avg_loss:0.300: 100%|██████████| 50/50 [00:02<00:00, 23.22it/s]\n",
+      "epoch13 avg_loss:0.296: 100%|██████████| 50/50 [00:02<00:00, 23.00it/s]\n",
+      "epoch14 avg_loss:0.293: 100%|██████████| 50/50 [00:02<00:00, 19.72it/s]\n",
+      "epoch15 avg_loss:0.290: 100%|██████████| 50/50 [00:02<00:00, 22.30it/s]\n",
+      "100%|██████████| 943/943 [00:20<00:00, 46.42it/s]\n"
+     ]
+    }
+   ],
+   "source": [
+    "trainer.fit(n_batch=50, n_epoch=15, valid_evaluator = evaluator, valid_per_epoch=5)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [
+    {
+     "output_type": "execute_result",
+     "data": {
+      "text/plain": [
+       "     nDCG@3     MAP@3  Recall@3  epoch      loss\n",
+       "0  0.404477  0.545157  0.111933      0       NaN\n",
+       "0  0.408631  0.549399  0.115896      5  0.356066\n",
+       "0  0.399501  0.540827  0.115340     10  0.308907\n",
+       "0  0.395533  0.534553  0.116172     15  0.289745"
+      ],
+      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>nDCG@3</th>\n      <th>MAP@3</th>\n      <th>Recall@3</th>\n      <th>epoch</th>\n      <th>loss</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>0.404477</td>\n      <td>0.545157</td>\n      <td>0.111933</td>\n      <td>0</td>\n      <td>NaN</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.408631</td>\n      <td>0.549399</td>\n      <td>0.115896</td>\n      <td>5</td>\n      <td>0.356066</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.399501</td>\n      <td>0.540827</td>\n      <td>0.115340</td>\n      <td>10</td>\n      <td>0.308907</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.395533</td>\n      <td>0.534553</td>\n      <td>0.116172</td>\n      <td>15</td>\n      <td>0.289745</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
+     },
+     "metadata": {},
+     "execution_count": 7
+    }
+   ],
+   "source": [
+    "trainer.valid_scores"
+   ]
+  },
+  {
+   "source": [
+    "# RelMF"
+   ],
+   "cell_type": "markdown",
+   "metadata": {}
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "train[\"popularity\"] = train.groupby(\"item_id\").rating.transform(sum)\n",
+    "train[\"pscore\"] = 1 / (train.popularity / train.popularity.max()) ** 0.5"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n",
+    "lr = 1e-3\n",
+    "n_dim = 10\n",
+    "\n",
+    "train_set = train[train.rating == 1][[\"user_id\", \"item_id\", \"pscore\"]].values\n",
+    "train_set = torch.LongTensor(train_set).to(device)\n",
+    "\n",
+    "model = models.LogitMatrixFactorization(\n",
+    "    n_user, n_item, n_dim, max_norm=5,max_bias=3,\n",
+    "    user_embedding_init = torch.Tensor(U), \n",
+    "    item_embedding_init = torch.Tensor(V.T),\n",
+    "    user_bias_init = torch.Tensor(ub), \n",
+    "    item_bias_init = torch.Tensor(vb)\n",
+    ").to(device)\n",
+    "\n",
+    "optimizer = optim.Adam(model.parameters(), lr=lr)\n",
+    "criterion = losses.RelevancePairwiseLoss(delta=\"rmse\").to(device)\n",
+    "sampler = samplers.BaseSampler(train_set, n_user, n_item, device=device,n_neg_samples=5, batch_size=1024)\n",
+    "\n",
+    "score_function_dict = {\n",
+    "    \"nDCG\" : evaluators.ndcg,\n",
+    "    \"MAP\" : evaluators.average_precision,\n",
+    "    \"Recall\": evaluators.recall\n",
+    "}\n",
+    "evaluator = evaluators.UserwiseEvaluator(torch.LongTensor(test_set).to(device), score_function_dict, ks=[3])\n",
+    "trainer = trainers.MFTrainer(\n",
+    "    model, optimizer, criterion, sampler, \n",
+    "    column_names={\"user_id\":0, \"item_id\":1, \"pscore\":2}\n",
+    ")\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
    "metadata": {},
    "outputs": [
     {
      "output_type": "stream",
      "name": "stderr",
      "text": [
-      "100%|██████████| 943/943 [00:20<00:00, 45.43it/s]\n",
-      "epoch1 avg_loss:15.768: 100%|██████████| 50/50 [00:02<00:00, 18.48it/s]\n",
-      "epoch2 avg_loss:13.333: 100%|██████████| 50/50 [00:02<00:00, 18.78it/s]\n",
-      "epoch3 avg_loss:11.214: 100%|██████████| 50/50 [00:02<00:00, 17.09it/s]\n",
-      "epoch4 avg_loss:9.704: 100%|██████████| 50/50 [00:02<00:00, 17.77it/s]\n",
-      "epoch5 avg_loss:8.523: 100%|██████████| 50/50 [00:02<00:00, 16.83it/s]\n",
-      "100%|██████████| 943/943 [00:20<00:00, 45.32it/s]\n",
-      "epoch6 avg_loss:7.387: 100%|██████████| 50/50 [00:02<00:00, 18.58it/s]\n",
-      "epoch7 avg_loss:6.422: 100%|██████████| 50/50 [00:03<00:00, 15.65it/s]\n",
-      "epoch8 avg_loss:5.676: 100%|██████████| 50/50 [00:02<00:00, 17.20it/s]\n",
-      "epoch9 avg_loss:4.968: 100%|██████████| 50/50 [00:02<00:00, 16.85it/s]\n",
-      "epoch10 avg_loss:4.467: 100%|██████████| 50/50 [00:03<00:00, 16.44it/s]\n",
-      "100%|██████████| 943/943 [00:20<00:00, 45.37it/s]\n",
-      "epoch11 avg_loss:4.027: 100%|██████████| 50/50 [00:03<00:00, 16.60it/s]\n",
-      "epoch12 avg_loss:3.579: 100%|██████████| 50/50 [00:03<00:00, 15.75it/s]\n",
-      "epoch13 avg_loss:3.187: 100%|██████████| 50/50 [00:02<00:00, 17.06it/s]\n",
-      "epoch14 avg_loss:2.907: 100%|██████████| 50/50 [00:02<00:00, 17.03it/s]\n",
-      "epoch15 avg_loss:2.631: 100%|██████████| 50/50 [00:02<00:00, 17.32it/s]\n",
-      "100%|██████████| 943/943 [00:20<00:00, 45.30it/s]\n"
+      "100%|██████████| 943/943 [00:15<00:00, 60.70it/s]\n",
+      "epoch1 avg_loss:0.873: 100%|██████████| 50/50 [00:02<00:00, 17.79it/s]\n",
+      "epoch2 avg_loss:0.575: 100%|██████████| 50/50 [00:01<00:00, 26.68it/s]\n",
+      "epoch3 avg_loss:0.441: 100%|██████████| 50/50 [00:01<00:00, 28.20it/s]\n",
+      "epoch4 avg_loss:0.358: 100%|██████████| 50/50 [00:01<00:00, 26.18it/s]\n",
+      "epoch5 avg_loss:0.308: 100%|██████████| 50/50 [00:01<00:00, 26.51it/s]\n",
+      "100%|██████████| 943/943 [00:19<00:00, 49.52it/s]\n",
+      "epoch6 avg_loss:0.267: 100%|██████████| 50/50 [00:01<00:00, 27.11it/s]\n",
+      "epoch7 avg_loss:0.240: 100%|██████████| 50/50 [00:01<00:00, 30.29it/s]\n",
+      "epoch8 avg_loss:0.222: 100%|██████████| 50/50 [00:01<00:00, 26.68it/s]\n",
+      "epoch9 avg_loss:0.206: 100%|██████████| 50/50 [00:01<00:00, 28.12it/s]\n",
+      "epoch10 avg_loss:0.187: 100%|██████████| 50/50 [00:01<00:00, 29.63it/s]\n",
+      "100%|██████████| 943/943 [00:22<00:00, 42.35it/s]\n",
+      "epoch11 avg_loss:0.175: 100%|██████████| 50/50 [00:02<00:00, 19.32it/s]\n",
+      "epoch12 avg_loss:0.169: 100%|██████████| 50/50 [00:02<00:00, 21.09it/s]\n",
+      "epoch13 avg_loss:0.160: 100%|██████████| 50/50 [00:02<00:00, 21.26it/s]\n",
+      "epoch14 avg_loss:0.150: 100%|██████████| 50/50 [00:02<00:00, 24.38it/s]\n",
+      "epoch15 avg_loss:0.146: 100%|██████████| 50/50 [00:02<00:00, 23.80it/s]\n",
+      "100%|██████████| 943/943 [00:18<00:00, 50.99it/s]\n"
      ]
     }
    ],
@@ -181,7 +309,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 25,
+   "execution_count": 14,
    "metadata": {},
    "outputs": [
     {
@@ -189,15 +317,15 @@
      "data": {
       "text/plain": [
        "     nDCG@3     MAP@3  Recall@3  epoch      loss\n",
-       "0  0.462963  0.594910  0.072043      0       NaN\n",
-       "0  0.463308  0.596501  0.071748      5  8.522911\n",
-       "0  0.468768  0.600919  0.073734     10  4.467164\n",
-       "0  0.466005  0.599417  0.071033     15  2.630981"
+       "0  0.404477  0.545157  0.111933      0       NaN\n",
+       "0  0.398088  0.544185  0.112874      5  0.308484\n",
+       "0  0.392882  0.537027  0.112438     10  0.186894\n",
+       "0  0.393925  0.533581  0.112751     15  0.145944"
       ],
-      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>nDCG@3</th>\n      <th>MAP@3</th>\n      <th>Recall@3</th>\n      <th>epoch</th>\n      <th>loss</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>0.462963</td>\n      <td>0.594910</td>\n      <td>0.072043</td>\n      <td>0</td>\n      <td>NaN</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.463308</td>\n      <td>0.596501</td>\n      <td>0.071748</td>\n      <td>5</td>\n      <td>8.522911</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.468768</td>\n      <td>0.600919</td>\n      <td>0.073734</td>\n      <td>10</td>\n      <td>4.467164</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.466005</td>\n      <td>0.599417</td>\n      <td>0.071033</td>\n      <td>15</td>\n      <td>2.630981</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
+      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>nDCG@3</th>\n      <th>MAP@3</th>\n      <th>Recall@3</th>\n      <th>epoch</th>\n      <th>loss</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>0.404477</td>\n      <td>0.545157</td>\n      <td>0.111933</td>\n      <td>0</td>\n      <td>NaN</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.398088</td>\n      <td>0.544185</td>\n      <td>0.112874</td>\n      <td>5</td>\n      <td>0.308484</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.392882</td>\n      <td>0.537027</td>\n      <td>0.112438</td>\n      <td>10</td>\n      <td>0.186894</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>0.393925</td>\n      <td>0.533581</td>\n      <td>0.112751</td>\n      <td>15</td>\n      <td>0.145944</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
      },
      "metadata": {},
-     "execution_count": 25
+     "execution_count": 14
     }
    ],
    "source": [
@@ -214,8 +342,8 @@
  ],
  "metadata": {
   "kernelspec": {
-   "name": "python386jvsc74a57bd098b0a9b7b4eaaa670588a142fd0a9b87eaafe866f1db4228be72b4211d12040f",
-   "display_name": "Python 3.8.6 64-bit ('base': conda)"
+   "name": "python386jvsc74a57bd01a6e8c4c71356cfd7f7f45384d81183fdca12e98ad893ee020bd76249bbd6be9",
+   "display_name": "Python 3.8.6 64-bit ('pytorchcml-MJCCLiEQ-py3.8': poetry)"
   },
   "language_info": {
    "codemirror_mode": {
diff --git a/poetry.lock b/poetry.lock
index bb8c59a..d7f8014 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -16,7 +16,7 @@ python-versions = "*"
 
 [[package]]
 name = "autopep8"
-version = "1.5.6"
+version = "1.5.7"
 description = "A tool that automatically formats Python code to conform to the PEP 8 style guide"
 category = "dev"
 optional = false
@@ -36,7 +36,7 @@ python-versions = "*"
 
 [[package]]
 name = "black"
-version = "21.4b2"
+version = "21.7b0"
 description = "The uncompromising code formatter."
 category = "dev"
 optional = false
@@ -48,18 +48,19 @@ click = ">=7.1.2"
 mypy-extensions = ">=0.4.3"
 pathspec = ">=0.8.1,<1"
 regex = ">=2020.1.8"
-toml = ">=0.10.1"
+tomli = ">=0.2.6,<2.0.0"
 typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\""}
 typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""}
 
 [package.extras]
 colorama = ["colorama (>=0.4.3)"]
-d = ["aiohttp (>=3.3.2)", "aiohttp-cors"]
+d = ["aiohttp (>=3.6.0)", "aiohttp-cors (>=0.4.0)"]
 python2 = ["typed-ast (>=1.4.2)"]
+uvloop = ["uvloop (>=0.15.2)"]
 
 [[package]]
 name = "cffi"
-version = "1.14.5"
+version = "1.14.6"
 description = "Foreign Function Interface for Python calling C code."
 category = "dev"
 optional = false
@@ -70,31 +71,43 @@ pycparser = "*"
 
 [[package]]
 name = "click"
-version = "7.1.2"
+version = "8.0.1"
 description = "Composable command line interface toolkit"
 category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = ">=3.6"
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
 
 [[package]]
 name = "colorama"
 version = "0.4.4"
 description = "Cross-platform colored terminal text."
-category = "dev"
+category = "main"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
 
 [[package]]
 name = "decorator"
-version = "5.0.7"
+version = "5.0.9"
 description = "Decorators for Humans"
 category = "dev"
 optional = false
 python-versions = ">=3.5"
 
+[[package]]
+name = "entrypoints"
+version = "0.3"
+description = "Discover and load entry points from installed packages."
+category = "dev"
+optional = false
+python-versions = ">=2.7"
+
 [[package]]
 name = "flake8"
-version = "3.9.1"
+version = "3.9.2"
 description = "the modular source code checker: pep8 pyflakes and co"
 category = "dev"
 optional = false
@@ -108,7 +121,7 @@ pyflakes = ">=2.3.0,<2.4.0"
 
 [[package]]
 name = "importlib-metadata"
-version = "4.0.1"
+version = "4.6.4"
 description = "Read metadata from Python packages"
 category = "dev"
 optional = false
@@ -120,11 +133,12 @@ zipp = ">=0.5"
 
 [package.extras]
 docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
-testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
+perf = ["ipython"]
+testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
 
 [[package]]
 name = "ipykernel"
-version = "5.5.3"
+version = "5.5.5"
 description = "IPython Kernel for Jupyter"
 category = "dev"
 optional = false
@@ -142,7 +156,7 @@ test = ["pytest (!=5.3.4)", "pytest-cov", "flaky", "nose", "jedi (<=0.17.2)"]
 
 [[package]]
 name = "ipython"
-version = "7.22.0"
+version = "7.26.0"
 description = "IPython: Productive Interactive Computing"
 category = "dev"
 optional = false
@@ -154,6 +168,7 @@ backcall = "*"
 colorama = {version = "*", markers = "sys_platform == \"win32\""}
 decorator = "*"
 jedi = ">=0.16"
+matplotlib-inline = "*"
 pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""}
 pickleshare = "*"
 prompt-toolkit = ">=2.0.0,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.1.0"
@@ -161,7 +176,7 @@ pygments = "*"
 traitlets = ">=4.2"
 
 [package.extras]
-all = ["Sphinx (>=1.3)", "ipykernel", "ipyparallel", "ipywidgets", "nbconvert", "nbformat", "nose (>=0.10.1)", "notebook", "numpy (>=1.16)", "pygments", "qtconsole", "requests", "testpath"]
+all = ["Sphinx (>=1.3)", "ipykernel", "ipyparallel", "ipywidgets", "nbconvert", "nbformat", "nose (>=0.10.1)", "notebook", "numpy (>=1.17)", "pygments", "qtconsole", "requests", "testpath"]
 doc = ["Sphinx (>=1.3)"]
 kernel = ["ipykernel"]
 nbconvert = ["nbconvert"]
@@ -169,7 +184,7 @@ nbformat = ["nbformat"]
 notebook = ["notebook", "ipywidgets"]
 parallel = ["ipyparallel"]
 qtconsole = ["qtconsole"]
-test = ["nose (>=0.10.1)", "requests", "testpath", "pygments", "nbformat", "ipykernel", "numpy (>=1.16)"]
+test = ["nose (>=0.10.1)", "requests", "testpath", "pygments", "nbformat", "ipykernel", "numpy (>=1.17)"]
 
 [[package]]
 name = "ipython-genutils"
@@ -181,16 +196,17 @@ python-versions = "*"
 
 [[package]]
 name = "isort"
-version = "5.8.0"
+version = "5.9.3"
 description = "A Python utility / library to sort Python imports."
 category = "dev"
 optional = false
-python-versions = ">=3.6,<4.0"
+python-versions = ">=3.6.1,<4.0"
 
 [package.extras]
 pipfile_deprecated_finder = ["pipreqs", "requirementslib"]
 requirements_deprecated_finder = ["pipreqs", "pip-api"]
 colors = ["colorama (>=0.4.3,<0.5.0)"]
+plugins = ["setuptools"]
 
 [[package]]
 name = "jedi"
@@ -217,13 +233,14 @@ python-versions = ">=3.6"
 
 [[package]]
 name = "jupyter-client"
-version = "6.2.0"
+version = "7.0.1"
 description = "Jupyter protocol implementation and client libraries"
 category = "dev"
 optional = false
 python-versions = ">=3.6.1"
 
 [package.dependencies]
+entrypoints = "*"
 jupyter-core = ">=4.6.0"
 nest-asyncio = ">=1.5"
 python-dateutil = ">=2.1"
@@ -232,8 +249,8 @@ tornado = ">=4.1"
 traitlets = "*"
 
 [package.extras]
-doc = ["sphinx (>=1.3.6)", "sphinx-rtd-theme", "sphinxcontrib-github-alt"]
-test = ["async-generator", "ipykernel", "ipython", "mock", "pytest-asyncio", "pytest-timeout", "pytest", "mypy", "pre-commit", "jedi (<0.18)"]
+doc = ["myst-parser", "sphinx (>=1.3.6)", "sphinx-rtd-theme", "sphinxcontrib-github-alt"]
+test = ["codecov", "coverage", "ipykernel", "ipython", "mock", "mypy", "pre-commit", "pytest", "pytest-asyncio", "pytest-cov", "pytest-timeout", "jedi (<0.18)"]
 
 [[package]]
 name = "jupyter-core"
@@ -247,6 +264,17 @@ python-versions = ">=3.6"
 pywin32 = {version = ">=1.0", markers = "sys_platform == \"win32\""}
 traitlets = "*"
 
+[[package]]
+name = "matplotlib-inline"
+version = "0.1.2"
+description = "Inline Matplotlib backend for Jupyter"
+category = "dev"
+optional = false
+python-versions = ">=3.5"
+
+[package.dependencies]
+traitlets = "*"
+
 [[package]]
 name = "mccabe"
 version = "0.6.1"
@@ -289,27 +317,27 @@ python-versions = ">=3.5"
 
 [[package]]
 name = "numpy"
-version = "1.20.2"
+version = "1.21.2"
 description = "NumPy is the fundamental package for array computing with Python."
 category = "main"
 optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.7,<3.11"
 
 [[package]]
 name = "pandas"
-version = "1.2.4"
+version = "1.3.2"
 description = "Powerful data structures for data analysis, time series, and statistics"
 category = "main"
 optional = false
 python-versions = ">=3.7.1"
 
 [package.dependencies]
-numpy = ">=1.16.5"
+numpy = ">=1.17.3"
 python-dateutil = ">=2.7.3"
 pytz = ">=2017.3"
 
 [package.extras]
-test = ["pytest (>=5.0.1)", "pytest-xdist", "hypothesis (>=3.58)"]
+test = ["hypothesis (>=3.58)", "pytest (>=6.0)", "pytest-xdist"]
 
 [[package]]
 name = "parso"
@@ -325,11 +353,11 @@ testing = ["docopt", "pytest (<6.0.0)"]
 
 [[package]]
 name = "pathspec"
-version = "0.8.1"
+version = "0.9.0"
 description = "Utility library for gitignore style pattern matching of file paths."
 category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
 
 [[package]]
 name = "pexpect"
@@ -352,11 +380,11 @@ python-versions = "*"
 
 [[package]]
 name = "prompt-toolkit"
-version = "3.0.18"
+version = "3.0.20"
 description = "Library for building powerful interactive command lines in Python"
 category = "dev"
 optional = false
-python-versions = ">=3.6.1"
+python-versions = ">=3.6.2"
 
 [package.dependencies]
 wcwidth = "*"
@@ -403,7 +431,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
 [[package]]
 name = "pygments"
-version = "2.8.1"
+version = "2.10.0"
 description = "Pygments is a syntax highlighting package written in Python."
 category = "dev"
 optional = false
@@ -411,7 +439,7 @@ python-versions = ">=3.5"
 
 [[package]]
 name = "python-dateutil"
-version = "2.8.1"
+version = "2.8.2"
 description = "Extensions to the standard Python datetime module"
 category = "main"
 optional = false
@@ -430,7 +458,7 @@ python-versions = "*"
 
 [[package]]
 name = "pywin32"
-version = "300"
+version = "301"
 description = "Python for Window Extensions"
 category = "dev"
 optional = false
@@ -438,7 +466,7 @@ python-versions = "*"
 
 [[package]]
 name = "pyzmq"
-version = "22.0.3"
+version = "22.2.1"
 description = "Python bindings for 0MQ"
 category = "dev"
 optional = false
@@ -450,7 +478,7 @@ py = {version = "*", markers = "implementation_name == \"pypy\""}
 
 [[package]]
 name = "regex"
-version = "2021.4.4"
+version = "2021.8.21"
 description = "Alternative regular expression module, to replace re."
 category = "dev"
 optional = false
@@ -474,7 +502,7 @@ alldeps = ["numpy (>=1.11.0)", "scipy (>=0.17.0)"]
 
 [[package]]
 name = "scipy"
-version = "1.6.3"
+version = "1.7.1"
 description = "SciPy: Scientific Library for Python"
 category = "main"
 optional = false
@@ -485,7 +513,7 @@ numpy = ">=1.16.5,<1.23.0"
 
 [[package]]
 name = "six"
-version = "1.15.0"
+version = "1.16.0"
 description = "Python 2 and 3 compatibility utilities"
 category = "main"
 optional = false
@@ -499,16 +527,23 @@ category = "dev"
 optional = false
 python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
 
+[[package]]
+name = "tomli"
+version = "1.2.1"
+description = "A lil' TOML parser"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
 [[package]]
 name = "torch"
-version = "1.8.1"
+version = "1.9.0"
 description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration"
 category = "main"
 optional = false
 python-versions = ">=3.6.2"
 
 [package.dependencies]
-numpy = "*"
 typing-extensions = "*"
 
 [[package]]
@@ -521,12 +556,15 @@ python-versions = ">= 3.5"
 
 [[package]]
 name = "tqdm"
-version = "4.60.0"
+version = "4.62.2"
 description = "Fast, Extensible Progress Meter"
 category = "main"
 optional = false
 python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
 
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+
 [package.extras]
 dev = ["py-make (>=0.1.0)", "twine", "wheel"]
 notebook = ["ipywidgets (>=6)"]
@@ -556,7 +594,7 @@ python-versions = "*"
 
 [[package]]
 name = "typing-extensions"
-version = "3.7.4.3"
+version = "3.10.0.0"
 description = "Backported and Experimental Type Hints for Python 3.5+"
 category = "main"
 optional = false
@@ -572,7 +610,7 @@ python-versions = "*"
 
 [[package]]
 name = "zipp"
-version = "3.4.1"
+version = "3.5.0"
 description = "Backport of pathlib-compatible object wrapper for zip files"
 category = "dev"
 optional = false
@@ -580,7 +618,7 @@ python-versions = ">=3.6"
 
 [package.extras]
 docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
-testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
+testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
 
 [metadata]
 lock-version = "1.1"
@@ -597,91 +635,103 @@ appnope = [
     {file = "appnope-0.1.2.tar.gz", hash = "sha256:dd83cd4b5b460958838f6eb3000c660b1f9caf2a5b1de4264e941512f603258a"},
 ]
 autopep8 = [
-    {file = "autopep8-1.5.6-py2.py3-none-any.whl", hash = "sha256:f01b06a6808bc31698db907761e5890eb2295e287af53f6693b39ce55454034a"},
-    {file = "autopep8-1.5.6.tar.gz", hash = "sha256:5454e6e9a3d02aae38f866eec0d9a7de4ab9f93c10a273fb0340f3d6d09f7514"},
+    {file = "autopep8-1.5.7-py2.py3-none-any.whl", hash = "sha256:aa213493c30dcdac99537249ee65b24af0b2c29f2e83cd8b3f68760441ed0db9"},
+    {file = "autopep8-1.5.7.tar.gz", hash = "sha256:276ced7e9e3cb22e5d7c14748384a5cf5d9002257c0ed50c0e075b68011bb6d0"},
 ]
 backcall = [
     {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"},
     {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"},
 ]
 black = [
-    {file = "black-21.4b2-py3-none-any.whl", hash = "sha256:bff7067d8bc25eb21dcfdbc8c72f2baafd9ec6de4663241a52fb904b304d391f"},
-    {file = "black-21.4b2.tar.gz", hash = "sha256:fc9bcf3b482b05c1f35f6a882c079dc01b9c7795827532f4cc43c0ec88067bbc"},
+    {file = "black-21.7b0-py3-none-any.whl", hash = "sha256:1c7aa6ada8ee864db745b22790a32f94b2795c253a75d6d9b5e439ff10d23116"},
+    {file = "black-21.7b0.tar.gz", hash = "sha256:c8373c6491de9362e39271630b65b964607bc5c79c83783547d76c839b3aa219"},
 ]
 cffi = [
-    {file = "cffi-1.14.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991"},
-    {file = "cffi-1.14.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1"},
-    {file = "cffi-1.14.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:99cd03ae7988a93dd00bcd9d0b75e1f6c426063d6f03d2f90b89e29b25b82dfa"},
-    {file = "cffi-1.14.5-cp27-cp27m-win32.whl", hash = "sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3"},
-    {file = "cffi-1.14.5-cp27-cp27m-win_amd64.whl", hash = "sha256:51182f8927c5af975fece87b1b369f722c570fe169f9880764b1ee3bca8347b5"},
-    {file = "cffi-1.14.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482"},
-    {file = "cffi-1.14.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6"},
-    {file = "cffi-1.14.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045"},
-    {file = "cffi-1.14.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:a465da611f6fa124963b91bf432d960a555563efe4ed1cc403ba5077b15370aa"},
-    {file = "cffi-1.14.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406"},
-    {file = "cffi-1.14.5-cp35-cp35m-win32.whl", hash = "sha256:72d8d3ef52c208ee1c7b2e341f7d71c6fd3157138abf1a95166e6165dd5d4369"},
-    {file = "cffi-1.14.5-cp35-cp35m-win_amd64.whl", hash = "sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315"},
-    {file = "cffi-1.14.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892"},
-    {file = "cffi-1.14.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058"},
-    {file = "cffi-1.14.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5"},
-    {file = "cffi-1.14.5-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:9e93e79c2551ff263400e1e4be085a1210e12073a31c2011dbbda14bda0c6132"},
-    {file = "cffi-1.14.5-cp36-cp36m-win32.whl", hash = "sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53"},
-    {file = "cffi-1.14.5-cp36-cp36m-win_amd64.whl", hash = "sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813"},
-    {file = "cffi-1.14.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73"},
-    {file = "cffi-1.14.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06"},
-    {file = "cffi-1.14.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1"},
-    {file = "cffi-1.14.5-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49"},
-    {file = "cffi-1.14.5-cp37-cp37m-win32.whl", hash = "sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62"},
-    {file = "cffi-1.14.5-cp37-cp37m-win_amd64.whl", hash = "sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4"},
-    {file = "cffi-1.14.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8b198cec6c72df5289c05b05b8b0969819783f9418e0409865dac47288d2a053"},
-    {file = "cffi-1.14.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:ad17025d226ee5beec591b52800c11680fca3df50b8b29fe51d882576e039ee0"},
-    {file = "cffi-1.14.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e"},
-    {file = "cffi-1.14.5-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8ae6299f6c68de06f136f1f9e69458eae58f1dacf10af5c17353eae03aa0d827"},
-    {file = "cffi-1.14.5-cp38-cp38-win32.whl", hash = "sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e"},
-    {file = "cffi-1.14.5-cp38-cp38-win_amd64.whl", hash = "sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396"},
-    {file = "cffi-1.14.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea"},
-    {file = "cffi-1.14.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9de2e279153a443c656f2defd67769e6d1e4163952b3c622dcea5b08a6405322"},
-    {file = "cffi-1.14.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c"},
-    {file = "cffi-1.14.5-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee"},
-    {file = "cffi-1.14.5-cp39-cp39-win32.whl", hash = "sha256:afb29c1ba2e5a3736f1c301d9d0abe3ec8b86957d04ddfa9d7a6a42b9367e396"},
-    {file = "cffi-1.14.5-cp39-cp39-win_amd64.whl", hash = "sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d"},
-    {file = "cffi-1.14.5.tar.gz", hash = "sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c"},
+    {file = "cffi-1.14.6-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:22b9c3c320171c108e903d61a3723b51e37aaa8c81255b5e7ce102775bd01e2c"},
+    {file = "cffi-1.14.6-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:f0c5d1acbfca6ebdd6b1e3eded8d261affb6ddcf2186205518f1428b8569bb99"},
+    {file = "cffi-1.14.6-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:99f27fefe34c37ba9875f224a8f36e31d744d8083e00f520f133cab79ad5e819"},
+    {file = "cffi-1.14.6-cp27-cp27m-win32.whl", hash = "sha256:55af55e32ae468e9946f741a5d51f9896da6b9bf0bbdd326843fec05c730eb20"},
+    {file = "cffi-1.14.6-cp27-cp27m-win_amd64.whl", hash = "sha256:7bcac9a2b4fdbed2c16fa5681356d7121ecabf041f18d97ed5b8e0dd38a80224"},
+    {file = "cffi-1.14.6-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ed38b924ce794e505647f7c331b22a693bee1538fdf46b0222c4717b42f744e7"},
+    {file = "cffi-1.14.6-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e22dcb48709fc51a7b58a927391b23ab37eb3737a98ac4338e2448bef8559b33"},
+    {file = "cffi-1.14.6-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:aedb15f0a5a5949ecb129a82b72b19df97bbbca024081ed2ef88bd5c0a610534"},
+    {file = "cffi-1.14.6-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:48916e459c54c4a70e52745639f1db524542140433599e13911b2f329834276a"},
+    {file = "cffi-1.14.6-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f627688813d0a4140153ff532537fbe4afea5a3dffce1f9deb7f91f848a832b5"},
+    {file = "cffi-1.14.6-cp35-cp35m-win32.whl", hash = "sha256:f0010c6f9d1a4011e429109fda55a225921e3206e7f62a0c22a35344bfd13cca"},
+    {file = "cffi-1.14.6-cp35-cp35m-win_amd64.whl", hash = "sha256:57e555a9feb4a8460415f1aac331a2dc833b1115284f7ded7278b54afc5bd218"},
+    {file = "cffi-1.14.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e8c6a99be100371dbb046880e7a282152aa5d6127ae01783e37662ef73850d8f"},
+    {file = "cffi-1.14.6-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:19ca0dbdeda3b2615421d54bef8985f72af6e0c47082a8d26122adac81a95872"},
+    {file = "cffi-1.14.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d950695ae4381ecd856bcaf2b1e866720e4ab9a1498cba61c602e56630ca7195"},
+    {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9dc245e3ac69c92ee4c167fbdd7428ec1956d4e754223124991ef29eb57a09d"},
+    {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8661b2ce9694ca01c529bfa204dbb144b275a31685a075ce123f12331be790b"},
+    {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b315d709717a99f4b27b59b021e6207c64620790ca3e0bde636a6c7f14618abb"},
+    {file = "cffi-1.14.6-cp36-cp36m-win32.whl", hash = "sha256:80b06212075346b5546b0417b9f2bf467fea3bfe7352f781ffc05a8ab24ba14a"},
+    {file = "cffi-1.14.6-cp36-cp36m-win_amd64.whl", hash = "sha256:a9da7010cec5a12193d1af9872a00888f396aba3dc79186604a09ea3ee7c029e"},
+    {file = "cffi-1.14.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4373612d59c404baeb7cbd788a18b2b2a8331abcc84c3ba40051fcd18b17a4d5"},
+    {file = "cffi-1.14.6-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f10afb1004f102c7868ebfe91c28f4a712227fe4cb24974350ace1f90e1febbf"},
+    {file = "cffi-1.14.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fd4305f86f53dfd8cd3522269ed7fc34856a8ee3709a5e28b2836b2db9d4cd69"},
+    {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d6169cb3c6c2ad50db5b868db6491a790300ade1ed5d1da29289d73bbe40b56"},
+    {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d4b68e216fc65e9fe4f524c177b54964af043dde734807586cf5435af84045c"},
+    {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33791e8a2dc2953f28b8d8d300dde42dd929ac28f974c4b4c6272cb2955cb762"},
+    {file = "cffi-1.14.6-cp37-cp37m-win32.whl", hash = "sha256:0c0591bee64e438883b0c92a7bed78f6290d40bf02e54c5bf0978eaf36061771"},
+    {file = "cffi-1.14.6-cp37-cp37m-win_amd64.whl", hash = "sha256:8eb687582ed7cd8c4bdbff3df6c0da443eb89c3c72e6e5dcdd9c81729712791a"},
+    {file = "cffi-1.14.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba6f2b3f452e150945d58f4badd92310449876c4c954836cfb1803bdd7b422f0"},
+    {file = "cffi-1.14.6-cp38-cp38-manylinux1_i686.whl", hash = "sha256:64fda793737bc4037521d4899be780534b9aea552eb673b9833b01f945904c2e"},
+    {file = "cffi-1.14.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:9f3e33c28cd39d1b655ed1ba7247133b6f7fc16fa16887b120c0c670e35ce346"},
+    {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26bb2549b72708c833f5abe62b756176022a7b9a7f689b571e74c8478ead51dc"},
+    {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb687a11f0a7a1839719edd80f41e459cc5366857ecbed383ff376c4e3cc6afd"},
+    {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2ad4d668a5c0645d281dcd17aff2be3212bc109b33814bbb15c4939f44181cc"},
+    {file = "cffi-1.14.6-cp38-cp38-win32.whl", hash = "sha256:487d63e1454627c8e47dd230025780e91869cfba4c753a74fda196a1f6ad6548"},
+    {file = "cffi-1.14.6-cp38-cp38-win_amd64.whl", hash = "sha256:c33d18eb6e6bc36f09d793c0dc58b0211fccc6ae5149b808da4a62660678b156"},
+    {file = "cffi-1.14.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:06c54a68935738d206570b20da5ef2b6b6d92b38ef3ec45c5422c0ebaf338d4d"},
+    {file = "cffi-1.14.6-cp39-cp39-manylinux1_i686.whl", hash = "sha256:f174135f5609428cc6e1b9090f9268f5c8935fddb1b25ccb8255a2d50de6789e"},
+    {file = "cffi-1.14.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f3ebe6e73c319340830a9b2825d32eb6d8475c1dac020b4f0aa774ee3b898d1c"},
+    {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c8d896becff2fa653dc4438b54a5a25a971d1f4110b32bd3068db3722c80202"},
+    {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4922cd707b25e623b902c86188aca466d3620892db76c0bdd7b99a3d5e61d35f"},
+    {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9e005e9bd57bc987764c32a1bee4364c44fdc11a3cc20a40b93b444984f2b87"},
+    {file = "cffi-1.14.6-cp39-cp39-win32.whl", hash = "sha256:eb9e2a346c5238a30a746893f23a9535e700f8192a68c07c0258e7ece6ff3728"},
+    {file = "cffi-1.14.6-cp39-cp39-win_amd64.whl", hash = "sha256:818014c754cd3dba7229c0f5884396264d51ffb87ec86e927ef0be140bfdb0d2"},
+    {file = "cffi-1.14.6.tar.gz", hash = "sha256:c9a875ce9d7fe32887784274dd533c57909b7b1dcadcc128a2ac21331a9765dd"},
 ]
 click = [
-    {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"},
-    {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"},
+    {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"},
+    {file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"},
 ]
 colorama = [
     {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
     {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
 ]
 decorator = [
-    {file = "decorator-5.0.7-py3-none-any.whl", hash = "sha256:945d84890bb20cc4a2f4a31fc4311c0c473af65ea318617f13a7257c9a58bc98"},
-    {file = "decorator-5.0.7.tar.gz", hash = "sha256:6f201a6c4dac3d187352661f508b9364ec8091217442c9478f1f83c003a0f060"},
+    {file = "decorator-5.0.9-py3-none-any.whl", hash = "sha256:6e5c199c16f7a9f0e3a61a4a54b3d27e7dad0dbdde92b944426cb20914376323"},
+    {file = "decorator-5.0.9.tar.gz", hash = "sha256:72ecfba4320a893c53f9706bebb2d55c270c1e51a28789361aa93e4a21319ed5"},
+]
+entrypoints = [
+    {file = "entrypoints-0.3-py2.py3-none-any.whl", hash = "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19"},
+    {file = "entrypoints-0.3.tar.gz", hash = "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"},
 ]
 flake8 = [
-    {file = "flake8-3.9.1-py2.py3-none-any.whl", hash = "sha256:3b9f848952dddccf635be78098ca75010f073bfe14d2c6bda867154bea728d2a"},
-    {file = "flake8-3.9.1.tar.gz", hash = "sha256:1aa8990be1e689d96c745c5682b687ea49f2e05a443aff1f8251092b0014e378"},
+    {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"},
+    {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"},
 ]
 importlib-metadata = [
-    {file = "importlib_metadata-4.0.1-py3-none-any.whl", hash = "sha256:d7eb1dea6d6a6086f8be21784cc9e3bcfa55872b52309bc5fad53a8ea444465d"},
-    {file = "importlib_metadata-4.0.1.tar.gz", hash = "sha256:8c501196e49fb9df5df43833bdb1e4328f64847763ec8a50703148b73784d581"},
+    {file = "importlib_metadata-4.6.4-py3-none-any.whl", hash = "sha256:ed5157fef23a4bc4594615a0dd8eba94b2bb36bf2a343fa3d8bb2fa0a62a99d5"},
+    {file = "importlib_metadata-4.6.4.tar.gz", hash = "sha256:7b30a78db2922d78a6f47fb30683156a14f3c6aa5cc23f77cc8967e9ab2d002f"},
 ]
 ipykernel = [
-    {file = "ipykernel-5.5.3-py3-none-any.whl", hash = "sha256:21abd584543759e49010975a4621603b3cf871b1039cb3879a14094717692614"},
-    {file = "ipykernel-5.5.3.tar.gz", hash = "sha256:a682e4f7affd86d9ce9b699d21bcab6d5ec9fbb2bfcb194f2706973b252bc509"},
+    {file = "ipykernel-5.5.5-py3-none-any.whl", hash = "sha256:29eee66548ee7c2edb7941de60c0ccf0a7a8dd957341db0a49c5e8e6a0fcb712"},
+    {file = "ipykernel-5.5.5.tar.gz", hash = "sha256:e976751336b51082a89fc2099fb7f96ef20f535837c398df6eab1283c2070884"},
 ]
 ipython = [
-    {file = "ipython-7.22.0-py3-none-any.whl", hash = "sha256:c0ce02dfaa5f854809ab7413c601c4543846d9da81010258ecdab299b542d199"},
-    {file = "ipython-7.22.0.tar.gz", hash = "sha256:9c900332d4c5a6de534b4befeeb7de44ad0cc42e8327fa41b7685abde58cec74"},
+    {file = "ipython-7.26.0-py3-none-any.whl", hash = "sha256:892743b65c21ed72b806a3a602cca408520b3200b89d1924f4b3d2cdb3692362"},
+    {file = "ipython-7.26.0.tar.gz", hash = "sha256:0cff04bb042800129348701f7bd68a430a844e8fb193979c08f6c99f28bb735e"},
 ]
 ipython-genutils = [
     {file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"},
     {file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"},
 ]
 isort = [
-    {file = "isort-5.8.0-py3-none-any.whl", hash = "sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"},
-    {file = "isort-5.8.0.tar.gz", hash = "sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6"},
+    {file = "isort-5.9.3-py3-none-any.whl", hash = "sha256:e17d6e2b81095c9db0a03a8025a957f334d6ea30b26f9ec70805411e5c7c81f2"},
+    {file = "isort-5.9.3.tar.gz", hash = "sha256:9c2ea1e62d871267b78307fe511c0838ba0da28698c5732d54e2790bf3ba9899"},
 ]
 jedi = [
     {file = "jedi-0.18.0-py2.py3-none-any.whl", hash = "sha256:18456d83f65f400ab0c2d3319e48520420ef43b23a086fdc05dff34132f0fb93"},
@@ -692,13 +742,17 @@ joblib = [
     {file = "joblib-1.0.1.tar.gz", hash = "sha256:9c17567692206d2f3fb9ecf5e991084254fe631665c450b443761c4186a613f7"},
 ]
 jupyter-client = [
-    {file = "jupyter_client-6.2.0-py3-none-any.whl", hash = "sha256:9715152067e3f7ea3b56f341c9a0f9715c8c7cc316ee0eb13c3c84f5ca0065f5"},
-    {file = "jupyter_client-6.2.0.tar.gz", hash = "sha256:e2ab61d79fbf8b56734a4c2499f19830fbd7f6fefb3e87868ef0545cb3c17eb9"},
+    {file = "jupyter_client-7.0.1-py3-none-any.whl", hash = "sha256:07b9566979546004c089afe7c9bf9e96224ec5f8421fe0ae460759fa593c6b1d"},
+    {file = "jupyter_client-7.0.1.tar.gz", hash = "sha256:48822a93d9d75daa5fde235c35cf7a92fc979384735962501d4eb60b197fb43a"},
 ]
 jupyter-core = [
     {file = "jupyter_core-4.7.1-py3-none-any.whl", hash = "sha256:8c6c0cac5c1b563622ad49321d5ec47017bd18b94facb381c6973a0486395f8e"},
     {file = "jupyter_core-4.7.1.tar.gz", hash = "sha256:79025cb3225efcd36847d0840f3fc672c0abd7afd0de83ba8a1d3837619122b4"},
 ]
+matplotlib-inline = [
+    {file = "matplotlib-inline-0.1.2.tar.gz", hash = "sha256:f41d5ff73c9f5385775d5c0bc13b424535c8402fe70ea8210f93e11f3683993e"},
+    {file = "matplotlib_inline-0.1.2-py3-none-any.whl", hash = "sha256:5cf1176f554abb4fa98cb362aa2b55c500147e4bdbb07e3fda359143e1da0811"},
+]
 mccabe = [
     {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
     {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
@@ -736,56 +790,65 @@ nest-asyncio = [
     {file = "nest_asyncio-1.5.1.tar.gz", hash = "sha256:afc5a1c515210a23c461932765691ad39e8eba6551c055ac8d5546e69250d0aa"},
 ]
 numpy = [
-    {file = "numpy-1.20.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e9459f40244bb02b2f14f6af0cd0732791d72232bbb0dc4bab57ef88e75f6935"},
-    {file = "numpy-1.20.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:a8e6859913ec8eeef3dbe9aed3bf475347642d1cdd6217c30f28dee8903528e6"},
-    {file = "numpy-1.20.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:9cab23439eb1ebfed1aaec9cd42b7dc50fc96d5cd3147da348d9161f0501ada5"},
-    {file = "numpy-1.20.2-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:9c0fab855ae790ca74b27e55240fe4f2a36a364a3f1ebcfd1fb5ac4088f1cec3"},
-    {file = "numpy-1.20.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:61d5b4cf73622e4d0c6b83408a16631b670fc045afd6540679aa35591a17fe6d"},
-    {file = "numpy-1.20.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:d15007f857d6995db15195217afdbddfcd203dfaa0ba6878a2f580eaf810ecd6"},
-    {file = "numpy-1.20.2-cp37-cp37m-win32.whl", hash = "sha256:d76061ae5cab49b83a8cf3feacefc2053fac672728802ac137dd8c4123397677"},
-    {file = "numpy-1.20.2-cp37-cp37m-win_amd64.whl", hash = "sha256:bad70051de2c50b1a6259a6df1daaafe8c480ca98132da98976d8591c412e737"},
-    {file = "numpy-1.20.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:719656636c48be22c23641859ff2419b27b6bdf844b36a2447cb39caceb00935"},
-    {file = "numpy-1.20.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:aa046527c04688af680217fffac61eec2350ef3f3d7320c07fd33f5c6e7b4d5f"},
-    {file = "numpy-1.20.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2428b109306075d89d21135bdd6b785f132a1f5a3260c371cee1fae427e12727"},
-    {file = "numpy-1.20.2-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:e8e4fbbb7e7634f263c5b0150a629342cc19b47c5eba8d1cd4363ab3455ab576"},
-    {file = "numpy-1.20.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:edb1f041a9146dcf02cd7df7187db46ab524b9af2515f392f337c7cbbf5b52cd"},
-    {file = "numpy-1.20.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:c73a7975d77f15f7f68dacfb2bca3d3f479f158313642e8ea9058eea06637931"},
-    {file = "numpy-1.20.2-cp38-cp38-win32.whl", hash = "sha256:6c915ee7dba1071554e70a3664a839fbc033e1d6528199d4621eeaaa5487ccd2"},
-    {file = "numpy-1.20.2-cp38-cp38-win_amd64.whl", hash = "sha256:471c0571d0895c68da309dacee4e95a0811d0a9f9f532a48dc1bea5f3b7ad2b7"},
-    {file = "numpy-1.20.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4703b9e937df83f5b6b7447ca5912b5f5f297aba45f91dbbbc63ff9278c7aa98"},
-    {file = "numpy-1.20.2-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:abc81829c4039e7e4c30f7897938fa5d4916a09c2c7eb9b244b7a35ddc9656f4"},
-    {file = "numpy-1.20.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:377751954da04d4a6950191b20539066b4e19e3b559d4695399c5e8e3e683bf6"},
-    {file = "numpy-1.20.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:6e51e417d9ae2e7848314994e6fc3832c9d426abce9328cf7571eefceb43e6c9"},
-    {file = "numpy-1.20.2-cp39-cp39-win32.whl", hash = "sha256:780ae5284cb770ade51d4b4a7dce4faa554eb1d88a56d0e8b9f35fca9b0270ff"},
-    {file = "numpy-1.20.2-cp39-cp39-win_amd64.whl", hash = "sha256:924dc3f83de20437de95a73516f36e09918e9c9c18d5eac520062c49191025fb"},
-    {file = "numpy-1.20.2-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:97ce8b8ace7d3b9288d88177e66ee75480fb79b9cf745e91ecfe65d91a856042"},
-    {file = "numpy-1.20.2.zip", hash = "sha256:878922bf5ad7550aa044aa9301d417e2d3ae50f0f577de92051d739ac6096cee"},
+    {file = "numpy-1.21.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52a664323273c08f3b473548bf87c8145b7513afd63e4ebba8496ecd3853df13"},
+    {file = "numpy-1.21.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51a7b9db0a2941434cd930dacaafe0fc9da8f3d6157f9d12f761bbde93f46218"},
+    {file = "numpy-1.21.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9f2dc79c093f6c5113718d3d90c283f11463d77daa4e83aeeac088ec6a0bda52"},
+    {file = "numpy-1.21.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a55e4d81c4260386f71d22294795c87609164e22b28ba0d435850fbdf82fc0c5"},
+    {file = "numpy-1.21.2-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:426a00b68b0d21f2deb2ace3c6d677e611ad5a612d2c76494e24a562a930c254"},
+    {file = "numpy-1.21.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:298156f4d3d46815eaf0fcf0a03f9625fc7631692bd1ad851517ab93c3168fc6"},
+    {file = "numpy-1.21.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:09858463db6dd9f78b2a1a05c93f3b33d4f65975771e90d2cf7aadb7c2f66edf"},
+    {file = "numpy-1.21.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:805459ad8baaf815883d0d6f86e45b3b0b67d823a8f3fa39b1ed9c45eaf5edf1"},
+    {file = "numpy-1.21.2-cp37-cp37m-win32.whl", hash = "sha256:f545c082eeb09ae678dd451a1b1dbf17babd8a0d7adea02897a76e639afca310"},
+    {file = "numpy-1.21.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b160b9a99ecc6559d9e6d461b95c8eec21461b332f80267ad2c10394b9503496"},
+    {file = "numpy-1.21.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a5109345f5ce7ddb3840f5970de71c34a0ff7fceb133c9441283bb8250f532a3"},
+    {file = "numpy-1.21.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:209666ce9d4a817e8a4597cd475b71b4878a85fa4b8db41d79fdb4fdee01dde2"},
+    {file = "numpy-1.21.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c01b59b33c7c3ba90744f2c695be571a3bd40ab2ba7f3d169ffa6db3cfba614f"},
+    {file = "numpy-1.21.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e42029e184008a5fd3d819323345e25e2337b0ac7f5c135b7623308530209d57"},
+    {file = "numpy-1.21.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7fdc7689daf3b845934d67cb221ba8d250fdca20ac0334fea32f7091b93f00d3"},
+    {file = "numpy-1.21.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:550564024dc5ceee9421a86fc0fb378aa9d222d4d0f858f6669eff7410c89bef"},
+    {file = "numpy-1.21.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bf75d5825ef47aa51d669b03ce635ecb84d69311e05eccea083f31c7570c9931"},
+    {file = "numpy-1.21.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a9da45b748caad72ea4a4ed57e9cd382089f33c5ec330a804eb420a496fa760f"},
+    {file = "numpy-1.21.2-cp38-cp38-win32.whl", hash = "sha256:e167b9805de54367dcb2043519382be541117503ce99e3291cc9b41ca0a83557"},
+    {file = "numpy-1.21.2-cp38-cp38-win_amd64.whl", hash = "sha256:466e682264b14982012887e90346d33435c984b7fead7b85e634903795c8fdb0"},
+    {file = "numpy-1.21.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:dd0e3651d210068d13e18503d75aaa45656eef51ef0b261f891788589db2cc38"},
+    {file = "numpy-1.21.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:92a0ab128b07799dd5b9077a9af075a63467d03ebac6f8a93e6440abfea4120d"},
+    {file = "numpy-1.21.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fde50062d67d805bc96f1a9ecc0d37bfc2a8f02b937d2c50824d186aa91f2419"},
+    {file = "numpy-1.21.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:640c1ccfd56724f2955c237b6ccce2e5b8607c3bc1cc51d3933b8c48d1da3723"},
+    {file = "numpy-1.21.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5de64950137f3a50b76ce93556db392e8f1f954c2d8207f78a92d1f79aa9f737"},
+    {file = "numpy-1.21.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b342064e647d099ca765f19672696ad50c953cac95b566af1492fd142283580f"},
+    {file = "numpy-1.21.2-cp39-cp39-win32.whl", hash = "sha256:30fc68307c0155d2a75ad19844224be0f2c6f06572d958db4e2053f816b859ad"},
+    {file = "numpy-1.21.2-cp39-cp39-win_amd64.whl", hash = "sha256:b5e8590b9245803c849e09bae070a8e1ff444f45e3f0bed558dd722119eea724"},
+    {file = "numpy-1.21.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d96a6a7d74af56feb11e9a443150216578ea07b7450f7c05df40eec90af7f4a7"},
+    {file = "numpy-1.21.2.zip", hash = "sha256:423216d8afc5923b15df86037c6053bf030d15cc9e3224206ef868c2d63dd6dc"},
 ]
 pandas = [
-    {file = "pandas-1.2.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c601c6fdebc729df4438ec1f62275d6136a0dd14d332fc0e8ce3f7d2aadb4dd6"},
-    {file = "pandas-1.2.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:8d4c74177c26aadcfb4fd1de6c1c43c2bf822b3e0fc7a9b409eeaf84b3e92aaa"},
-    {file = "pandas-1.2.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:b730add5267f873b3383c18cac4df2527ac4f0f0eed1c6cf37fcb437e25cf558"},
-    {file = "pandas-1.2.4-cp37-cp37m-win32.whl", hash = "sha256:2cb7e8f4f152f27dc93f30b5c7a98f6c748601ea65da359af734dd0cf3fa733f"},
-    {file = "pandas-1.2.4-cp37-cp37m-win_amd64.whl", hash = "sha256:2111c25e69fa9365ba80bbf4f959400054b2771ac5d041ed19415a8b488dc70a"},
-    {file = "pandas-1.2.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:167693a80abc8eb28051fbd184c1b7afd13ce2c727a5af47b048f1ea3afefff4"},
-    {file = "pandas-1.2.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:612add929bf3ba9d27b436cc8853f5acc337242d6b584203f207e364bb46cb12"},
-    {file = "pandas-1.2.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:971e2a414fce20cc5331fe791153513d076814d30a60cd7348466943e6e909e4"},
-    {file = "pandas-1.2.4-cp38-cp38-win32.whl", hash = "sha256:68d7baa80c74aaacbed597265ca2308f017859123231542ff8a5266d489e1858"},
-    {file = "pandas-1.2.4-cp38-cp38-win_amd64.whl", hash = "sha256:bd659c11a4578af740782288cac141a322057a2e36920016e0fc7b25c5a4b686"},
-    {file = "pandas-1.2.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9db70ffa8b280bb4de83f9739d514cd0735825e79eef3a61d312420b9f16b758"},
-    {file = "pandas-1.2.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:298f0553fd3ba8e002c4070a723a59cdb28eda579f3e243bc2ee397773f5398b"},
-    {file = "pandas-1.2.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:52d2472acbb8a56819a87aafdb8b5b6d2b3386e15c95bde56b281882529a7ded"},
-    {file = "pandas-1.2.4-cp39-cp39-win32.whl", hash = "sha256:d0877407359811f7b853b548a614aacd7dea83b0c0c84620a9a643f180060950"},
-    {file = "pandas-1.2.4-cp39-cp39-win_amd64.whl", hash = "sha256:2b063d41803b6a19703b845609c0b700913593de067b552a8b24dd8eeb8c9895"},
-    {file = "pandas-1.2.4.tar.gz", hash = "sha256:649ecab692fade3cbfcf967ff936496b0cfba0af00a55dfaacd82bdda5cb2279"},
+    {file = "pandas-1.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ba7ceb8abc6dbdb1e34612d1173d61e4941f1a1eb7e6f703b2633134ae6a6c89"},
+    {file = "pandas-1.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcb71b1935249de80e3a808227189eee381d4d74a31760ced2df21eedc92a8e3"},
+    {file = "pandas-1.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa54dc1d3e5d004a09ab0b1751473698011ddf03e14f1f59b84ad9a6ac630975"},
+    {file = "pandas-1.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34ced9ce5d5b17b556486da7256961b55b471d64a8990b56e67a84ebeb259416"},
+    {file = "pandas-1.3.2-cp37-cp37m-win32.whl", hash = "sha256:a56246de744baf646d1f3e050c4653d632bc9cd2e0605f41051fea59980e880a"},
+    {file = "pandas-1.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:53b17e4debba26b7446b1e4795c19f94f0c715e288e08145e44bdd2865e819b3"},
+    {file = "pandas-1.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f07a9745ca075ae73a5ce116f5e58f691c0dc9de0bff163527858459df5c176f"},
+    {file = "pandas-1.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9e8e0ce5284ebebe110efd652c164ed6eab77f5de4c3533abc756302ee77765"},
+    {file = "pandas-1.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59a78d7066d1c921a77e3306aa0ebf6e55396c097d5dfcc4df8defe3dcecb735"},
+    {file = "pandas-1.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:132def05e73d292c949b02e7ef873debb77acc44a8b119d215921046f0c3a91d"},
+    {file = "pandas-1.3.2-cp38-cp38-win32.whl", hash = "sha256:69e1b2f5811f46827722fd641fdaeedb26002bd1e504eacc7a8ec36bdc25393e"},
+    {file = "pandas-1.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:7996d311413379136baf0f3cf2a10e331697657c87ced3f17ac7c77f77fe34a3"},
+    {file = "pandas-1.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1738154049062156429a5cf2fd79a69c9f3fa4f231346a7ec6fd156cd1a9a621"},
+    {file = "pandas-1.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cce01f6d655b4add966fcd36c32c5d1fe84628e200626b3f5e2f40db2d16a0f"},
+    {file = "pandas-1.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1099e2a0cd3a01ec62cca183fc1555833a2d43764950ef8cb5948c8abfc51014"},
+    {file = "pandas-1.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0cd5776be891331a3e6b425b5abeab9596abea18435c5982191356f9b24ae731"},
+    {file = "pandas-1.3.2-cp39-cp39-win32.whl", hash = "sha256:66a95361b81b4ba04b699ecd2416b0591f40cd1e24c60a8bfe0d19009cfa575a"},
+    {file = "pandas-1.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:89f40e5d21814192802421df809f948247d39ffe171e45fe2ab4abf7bd4279d8"},
+    {file = "pandas-1.3.2.tar.gz", hash = "sha256:cbcb84d63867af3411fa063af3de64902665bb5b3d40b25b2059e40603594e87"},
 ]
 parso = [
     {file = "parso-0.8.2-py2.py3-none-any.whl", hash = "sha256:a8c4922db71e4fdb90e0d0bc6e50f9b273d3397925e5e60a717e719201778d22"},
     {file = "parso-0.8.2.tar.gz", hash = "sha256:12b83492c6239ce32ff5eed6d3639d6a536170723c6f3f1506869f1ace413398"},
 ]
 pathspec = [
-    {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"},
-    {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"},
+    {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"},
+    {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
 ]
 pexpect = [
     {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"},
@@ -796,8 +859,8 @@ pickleshare = [
     {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"},
 ]
 prompt-toolkit = [
-    {file = "prompt_toolkit-3.0.18-py3-none-any.whl", hash = "sha256:bf00f22079f5fadc949f42ae8ff7f05702826a97059ffcc6281036ad40ac6f04"},
-    {file = "prompt_toolkit-3.0.18.tar.gz", hash = "sha256:e1b4f11b9336a28fa11810bc623c357420f69dfdb6d2dac41ca2c21a55c033bc"},
+    {file = "prompt_toolkit-3.0.20-py3-none-any.whl", hash = "sha256:6076e46efae19b1e0ca1ec003ed37a933dc94b4d20f486235d436e64771dcd5c"},
+    {file = "prompt_toolkit-3.0.20.tar.gz", hash = "sha256:eb71d5a6b72ce6db177af4a7d4d7085b99756bf656d98ffcc4fecd36850eea6c"},
 ]
 ptyprocess = [
     {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"},
@@ -820,105 +883,110 @@ pyflakes = [
     {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"},
 ]
 pygments = [
-    {file = "Pygments-2.8.1-py3-none-any.whl", hash = "sha256:534ef71d539ae97d4c3a4cf7d6f110f214b0e687e92f9cb9d2a3b0d3101289c8"},
-    {file = "Pygments-2.8.1.tar.gz", hash = "sha256:2656e1a6edcdabf4275f9a3640db59fd5de107d88e8663c5d4e9a0fa62f77f94"},
+    {file = "Pygments-2.10.0-py3-none-any.whl", hash = "sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380"},
+    {file = "Pygments-2.10.0.tar.gz", hash = "sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6"},
 ]
 python-dateutil = [
-    {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"},
-    {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"},
+    {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
+    {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
 ]
 pytz = [
     {file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"},
     {file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"},
 ]
 pywin32 = [
-    {file = "pywin32-300-cp35-cp35m-win32.whl", hash = "sha256:1c204a81daed2089e55d11eefa4826c05e604d27fe2be40b6bf8db7b6a39da63"},
-    {file = "pywin32-300-cp35-cp35m-win_amd64.whl", hash = "sha256:350c5644775736351b77ba68da09a39c760d75d2467ecec37bd3c36a94fbed64"},
-    {file = "pywin32-300-cp36-cp36m-win32.whl", hash = "sha256:a3b4c48c852d4107e8a8ec980b76c94ce596ea66d60f7a697582ea9dce7e0db7"},
-    {file = "pywin32-300-cp36-cp36m-win_amd64.whl", hash = "sha256:27a30b887afbf05a9cbb05e3ffd43104a9b71ce292f64a635389dbad0ed1cd85"},
-    {file = "pywin32-300-cp37-cp37m-win32.whl", hash = "sha256:d7e8c7efc221f10d6400c19c32a031add1c4a58733298c09216f57b4fde110dc"},
-    {file = "pywin32-300-cp37-cp37m-win_amd64.whl", hash = "sha256:8151e4d7a19262d6694162d6da85d99a16f8b908949797fd99c83a0bfaf5807d"},
-    {file = "pywin32-300-cp38-cp38-win32.whl", hash = "sha256:fbb3b1b0fbd0b4fc2a3d1d81fe0783e30062c1abed1d17c32b7879d55858cfae"},
-    {file = "pywin32-300-cp38-cp38-win_amd64.whl", hash = "sha256:60a8fa361091b2eea27f15718f8eb7f9297e8d51b54dbc4f55f3d238093d5190"},
-    {file = "pywin32-300-cp39-cp39-win32.whl", hash = "sha256:638b68eea5cfc8def537e43e9554747f8dee786b090e47ead94bfdafdb0f2f50"},
-    {file = "pywin32-300-cp39-cp39-win_amd64.whl", hash = "sha256:b1609ce9bd5c411b81f941b246d683d6508992093203d4eb7f278f4ed1085c3f"},
+    {file = "pywin32-301-cp35-cp35m-win32.whl", hash = "sha256:93367c96e3a76dfe5003d8291ae16454ca7d84bb24d721e0b74a07610b7be4a7"},
+    {file = "pywin32-301-cp35-cp35m-win_amd64.whl", hash = "sha256:9635df6998a70282bd36e7ac2a5cef9ead1627b0a63b17c731312c7a0daebb72"},
+    {file = "pywin32-301-cp36-cp36m-win32.whl", hash = "sha256:c866f04a182a8cb9b7855de065113bbd2e40524f570db73ef1ee99ff0a5cc2f0"},
+    {file = "pywin32-301-cp36-cp36m-win_amd64.whl", hash = "sha256:dafa18e95bf2a92f298fe9c582b0e205aca45c55f989937c52c454ce65b93c78"},
+    {file = "pywin32-301-cp37-cp37m-win32.whl", hash = "sha256:98f62a3f60aa64894a290fb7494bfa0bfa0a199e9e052e1ac293b2ad3cd2818b"},
+    {file = "pywin32-301-cp37-cp37m-win_amd64.whl", hash = "sha256:fb3b4933e0382ba49305cc6cd3fb18525df7fd96aa434de19ce0878133bf8e4a"},
+    {file = "pywin32-301-cp38-cp38-win32.whl", hash = "sha256:88981dd3cfb07432625b180f49bf4e179fb8cbb5704cd512e38dd63636af7a17"},
+    {file = "pywin32-301-cp38-cp38-win_amd64.whl", hash = "sha256:8c9d33968aa7fcddf44e47750e18f3d034c3e443a707688a008a2e52bbef7e96"},
+    {file = "pywin32-301-cp39-cp39-win32.whl", hash = "sha256:595d397df65f1b2e0beaca63a883ae6d8b6df1cdea85c16ae85f6d2e648133fe"},
+    {file = "pywin32-301-cp39-cp39-win_amd64.whl", hash = "sha256:87604a4087434cd814ad8973bd47d6524bd1fa9e971ce428e76b62a5e0860fdf"},
 ]
 pyzmq = [
-    {file = "pyzmq-22.0.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c0cde362075ee8f3d2b0353b283e203c2200243b5a15d5c5c03b78112a17e7d4"},
-    {file = "pyzmq-22.0.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:ff1ea14075bbddd6f29bf6beb8a46d0db779bcec6b9820909584081ec119f8fd"},
-    {file = "pyzmq-22.0.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:26380487eae4034d6c2a3fb8d0f2dff6dd0d9dd711894e8d25aa2d1938950a33"},
-    {file = "pyzmq-22.0.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:3e29f9cf85a40d521d048b55c63f59d6c772ac1c4bf51cdfc23b62a62e377c33"},
-    {file = "pyzmq-22.0.3-cp36-cp36m-win32.whl", hash = "sha256:4f34a173f813b38b83f058e267e30465ed64b22cd0cf6bad21148d3fa718f9bb"},
-    {file = "pyzmq-22.0.3-cp36-cp36m-win_amd64.whl", hash = "sha256:30df70f81fe210506aa354d7fd486a39b87d9f7f24c3d3f4f698ec5d96b8c084"},
-    {file = "pyzmq-22.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7026f0353977431fc884abd4ac28268894bd1a780ba84bb266d470b0ec26d2ed"},
-    {file = "pyzmq-22.0.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6d4163704201fff0f3ab0cd5d7a0ea1514ecfffd3926d62ec7e740a04d2012c7"},
-    {file = "pyzmq-22.0.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:763c175294d861869f18eb42901d500eda7d3fa4565f160b3b2fd2678ea0ebab"},
-    {file = "pyzmq-22.0.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:61e4bb6cd60caf1abcd796c3f48395e22c5b486eeca6f3a8797975c57d94b03e"},
-    {file = "pyzmq-22.0.3-cp37-cp37m-win32.whl", hash = "sha256:b25e5d339550a850f7e919fe8cb4c8eabe4c917613db48dab3df19bfb9a28969"},
-    {file = "pyzmq-22.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:3ef50d74469b03725d781a2a03c57537d86847ccde587130fe35caafea8f75c6"},
-    {file = "pyzmq-22.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:60e63577b85055e4cc43892fecd877b86695ee3ef12d5d10a3c5d6e77a7cc1a3"},
-    {file = "pyzmq-22.0.3-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:f5831eff6b125992ec65d973f5151c48003b6754030094723ac4c6e80a97c8c4"},
-    {file = "pyzmq-22.0.3-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:9221783dacb419604d5345d0e097bddef4459a9a95322de6c306bf1d9896559f"},
-    {file = "pyzmq-22.0.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:b62ea18c0458a65ccd5be90f276f7a5a3f26a6dea0066d948ce2fa896051420f"},
-    {file = "pyzmq-22.0.3-cp38-cp38-win32.whl", hash = "sha256:81e7df0da456206201e226491aa1fc449da85328bf33bbeec2c03bb3a9f18324"},
-    {file = "pyzmq-22.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:f52070871a0fd90a99130babf21f8af192304ec1e995bec2a9533efc21ea4452"},
-    {file = "pyzmq-22.0.3-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:c5e29fe4678f97ce429f076a2a049a3d0b2660ada8f2c621e5dc9939426056dd"},
-    {file = "pyzmq-22.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d18ddc6741b51f3985978f2fda57ddcdae359662d7a6b395bc8ff2292fca14bd"},
-    {file = "pyzmq-22.0.3-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4231943514812dfb74f44eadcf85e8dd8cf302b4d0bce450ce1357cac88dbfdc"},
-    {file = "pyzmq-22.0.3-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:23a74de4b43c05c3044aeba0d1f3970def8f916151a712a3ac1e5cd9c0bc2902"},
-    {file = "pyzmq-22.0.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:532af3e6dddea62d9c49062ece5add998c9823c2419da943cf95589f56737de0"},
-    {file = "pyzmq-22.0.3-cp39-cp39-win32.whl", hash = "sha256:33acd2b9790818b9d00526135acf12790649d8d34b2b04d64558b469c9d86820"},
-    {file = "pyzmq-22.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:a558c5bc89d56d7253187dccc4e81b5bb0eac5ae9511eb4951910a1245d04622"},
-    {file = "pyzmq-22.0.3-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:581787c62eaa0e0db6c5413cedc393ebbadac6ddfd22e1cf9a60da23c4f1a4b2"},
-    {file = "pyzmq-22.0.3-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:38e3dca75d81bec4f2defa14b0a65b74545812bb519a8e89c8df96bbf4639356"},
-    {file = "pyzmq-22.0.3-pp36-pypy36_pp73-win32.whl", hash = "sha256:2f971431aaebe0a8b54ac018e041c2f0b949a43745444e4dadcc80d0f0ef8457"},
-    {file = "pyzmq-22.0.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:da7d4d4c778c86b60949d17531e60c54ed3726878de8a7f8a6d6e7f8cc8c3205"},
-    {file = "pyzmq-22.0.3-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:13465c1ff969cab328bc92f7015ce3843f6e35f8871ad79d236e4fbc85dbe4cb"},
-    {file = "pyzmq-22.0.3-pp37-pypy37_pp73-win32.whl", hash = "sha256:279cc9b51db48bec2db146f38e336049ac5a59e5f12fb3a8ad864e238c1c62e3"},
-    {file = "pyzmq-22.0.3.tar.gz", hash = "sha256:f7f63ce127980d40f3e6a5fdb87abf17ce1a7c2bd8bf2c7560e1bbce8ab1f92d"},
+    {file = "pyzmq-22.2.1-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:d60a407663b7c2af781ab7f49d94a3d379dd148bb69ea8d9dd5bc69adf18097c"},
+    {file = "pyzmq-22.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:631f932fb1fa4b76f31adf976f8056519bc6208a3c24c184581c3dd5be15066e"},
+    {file = "pyzmq-22.2.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0471d634c7fe48ff7d3849798da6c16afc71676dd890b5ae08eb1efe735c6fec"},
+    {file = "pyzmq-22.2.1-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f520e9fee5d7a2e09b051d924f85b977c6b4e224e56c0551c3c241bbeeb0ad8d"},
+    {file = "pyzmq-22.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1b6619ceb33a8907f1cb82ff8afc8a133e7a5f16df29528e919734718600426"},
+    {file = "pyzmq-22.2.1-cp310-cp310-win32.whl", hash = "sha256:31c5dfb6df5148789835128768c01bf6402eb753d06f524f12f6786caf96fb44"},
+    {file = "pyzmq-22.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:4842a8263cbaba6fce401bbe4e2b125321c401a01714e42624dabc554bfc2629"},
+    {file = "pyzmq-22.2.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b921758f8b5098faa85f341bbdd5e36d5339de5e9032ca2b07d8c8e7bec5069b"},
+    {file = "pyzmq-22.2.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:240b83b3a8175b2f616f80092cbb019fcd5c18598f78ffc6aa0ae9034b300f14"},
+    {file = "pyzmq-22.2.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:da7f7f3bb08bcf59a6b60b4e53dd8f08bb00c9e61045319d825a906dbb3c8fb7"},
+    {file = "pyzmq-22.2.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e66025b64c4724ba683d6d4a4e5ee23de12fe9ae683908f0c7f0f91b4a2fd94e"},
+    {file = "pyzmq-22.2.1-cp36-cp36m-win32.whl", hash = "sha256:50d007d5702171bc810c1e74498fa2c7bc5b50f9750697f7fd2a3e71a25aad91"},
+    {file = "pyzmq-22.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b4a51c7d906dc263a0cc5590761e53e0a68f2c2fefe549cbef21c9ee5d2d98a4"},
+    {file = "pyzmq-22.2.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:93705cb90baa9d6f75e8448861a1efd3329006f79095ab18846bd1eaa342f7c3"},
+    {file = "pyzmq-22.2.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:620b0abb813958cb3ecb5144c177e26cde92fee6f43c4b9de6b329515532bf27"},
+    {file = "pyzmq-22.2.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2dd3896b3c952cf6c8013deda53c1df16bf962f355b5503d23521e0f6403ae3d"},
+    {file = "pyzmq-22.2.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6e9c030222893afa86881d7485d3e841969760a16004bd23e9a83cca28b42778"},
+    {file = "pyzmq-22.2.1-cp37-cp37m-win32.whl", hash = "sha256:262f470e7acde18b7217aac78d19d2e29ced91a5afbeb7d98521ebf26461aa7e"},
+    {file = "pyzmq-22.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:246f27b88722cfa729bb04881e94484e40b085720d728c1b05133b3f331b0b7b"},
+    {file = "pyzmq-22.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0d17bac19e934e9f547a8811b7c2a32651a7840f38086b924e2e3dcb2fae5c3a"},
+    {file = "pyzmq-22.2.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5933d1f4087de6e52906f72d92e1e4dcc630d371860b92c55d7f7a4b815a664c"},
+    {file = "pyzmq-22.2.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ac4497e4b7d134ee53ce5532d9cc3b640d6e71806a55062984e0c99a2f88f465"},
+    {file = "pyzmq-22.2.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:66375a6094af72a6098ed4403b15b4db6bf00013c6febc1baa832e7abda827f4"},
+    {file = "pyzmq-22.2.1-cp38-cp38-win32.whl", hash = "sha256:b2c16d20bd0aef8e57bc9505fdd80ea0d6008020c3740accd96acf1b3d1b5347"},
+    {file = "pyzmq-22.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:ff345d48940c834168f81fa1d4724675099f148f1ab6369748c4d712ed71bf7c"},
+    {file = "pyzmq-22.2.1-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:f5c84c5de9a773bbf8b22c51e28380999ea72e5e85b4db8edf5e69a7a0d4d9f9"},
+    {file = "pyzmq-22.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2534a036b777f957bd6b89b55fb2136775ca2659fb0f1c85036ba78d17d86fd5"},
+    {file = "pyzmq-22.2.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a649065413ba4eab92a783a7caa4de8ce14cf46ba8a2a09951426143f1298adb"},
+    {file = "pyzmq-22.2.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c9cb0bd3a3cb7ccad3caa1d7b0d18ba71ed3a4a3610028e506a4084371d4d223"},
+    {file = "pyzmq-22.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4428302c389fffc0c9c07a78cad5376636b9d096f332acfe66b321ae9ff2c63"},
+    {file = "pyzmq-22.2.1-cp39-cp39-win32.whl", hash = "sha256:6a5b4566f66d953601d0d47d4071897f550a265bafd52ebcad5ac7aad3838cbb"},
+    {file = "pyzmq-22.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:89200ab6ef9081c72a04ed84c52a50b60dcb0655375aeedb40689bc7c934715e"},
+    {file = "pyzmq-22.2.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ed67df4eaa99a20d162d76655bda23160abdf8abf82a17f41dfd3962e608dbcc"},
+    {file = "pyzmq-22.2.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:021e22a8c58ab294bd4b96448a2ca4e716e1d76600192ff84c33d71edb1fbd37"},
+    {file = "pyzmq-22.2.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:200ac096cee5499964c90687306a7244b79ef891f773ed4cf15019fd1f3df330"},
+    {file = "pyzmq-22.2.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:b3f57bee62e36be5c97712de32237c5589caee0d1154c2ad01a888accfae20bc"},
+    {file = "pyzmq-22.2.1.tar.gz", hash = "sha256:6d18c76676771fd891ca8e0e68da0bbfb88e30129835c0ade748016adb3b6242"},
 ]
 regex = [
-    {file = "regex-2021.4.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:619d71c59a78b84d7f18891fe914446d07edd48dc8328c8e149cbe0929b4e000"},
-    {file = "regex-2021.4.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:47bf5bf60cf04d72bf6055ae5927a0bd9016096bf3d742fa50d9bf9f45aa0711"},
-    {file = "regex-2021.4.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:281d2fd05555079448537fe108d79eb031b403dac622621c78944c235f3fcf11"},
-    {file = "regex-2021.4.4-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bd28bc2e3a772acbb07787c6308e00d9626ff89e3bfcdebe87fa5afbfdedf968"},
-    {file = "regex-2021.4.4-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:7c2a1af393fcc09e898beba5dd59196edaa3116191cc7257f9224beaed3e1aa0"},
-    {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c38c71df845e2aabb7fb0b920d11a1b5ac8526005e533a8920aea97efb8ec6a4"},
-    {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:96fcd1888ab4d03adfc9303a7b3c0bd78c5412b2bfbe76db5b56d9eae004907a"},
-    {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:ade17eb5d643b7fead300a1641e9f45401c98eee23763e9ed66a43f92f20b4a7"},
-    {file = "regex-2021.4.4-cp36-cp36m-win32.whl", hash = "sha256:e8e5b509d5c2ff12f8418006d5a90e9436766133b564db0abaec92fd27fcee29"},
-    {file = "regex-2021.4.4-cp36-cp36m-win_amd64.whl", hash = "sha256:11d773d75fa650cd36f68d7ca936e3c7afaae41b863b8c387a22aaa78d3c5c79"},
-    {file = "regex-2021.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d3029c340cfbb3ac0a71798100ccc13b97dddf373a4ae56b6a72cf70dfd53bc8"},
-    {file = "regex-2021.4.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:18c071c3eb09c30a264879f0d310d37fe5d3a3111662438889ae2eb6fc570c31"},
-    {file = "regex-2021.4.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:4c557a7b470908b1712fe27fb1ef20772b78079808c87d20a90d051660b1d69a"},
-    {file = "regex-2021.4.4-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:01afaf2ec48e196ba91b37451aa353cb7eda77efe518e481707e0515025f0cd5"},
-    {file = "regex-2021.4.4-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:3a9cd17e6e5c7eb328517969e0cb0c3d31fd329298dd0c04af99ebf42e904f82"},
-    {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:90f11ff637fe8798933fb29f5ae1148c978cccb0452005bf4c69e13db951e765"},
-    {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:919859aa909429fb5aa9cf8807f6045592c85ef56fdd30a9a3747e513db2536e"},
-    {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:339456e7d8c06dd36a22e451d58ef72cef293112b559010db3d054d5560ef439"},
-    {file = "regex-2021.4.4-cp37-cp37m-win32.whl", hash = "sha256:67bdb9702427ceddc6ef3dc382455e90f785af4c13d495f9626861763ee13f9d"},
-    {file = "regex-2021.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:32e65442138b7b76dd8173ffa2cf67356b7bc1768851dded39a7a13bf9223da3"},
-    {file = "regex-2021.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1e1c20e29358165242928c2de1482fb2cf4ea54a6a6dea2bd7a0e0d8ee321500"},
-    {file = "regex-2021.4.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:314d66636c494ed9c148a42731b3834496cc9a2c4251b1661e40936814542b14"},
-    {file = "regex-2021.4.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6d1b01031dedf2503631d0903cb563743f397ccaf6607a5e3b19a3d76fc10480"},
-    {file = "regex-2021.4.4-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:741a9647fcf2e45f3a1cf0e24f5e17febf3efe8d4ba1281dcc3aa0459ef424dc"},
-    {file = "regex-2021.4.4-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:4c46e22a0933dd783467cf32b3516299fb98cfebd895817d685130cc50cd1093"},
-    {file = "regex-2021.4.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e512d8ef5ad7b898cdb2d8ee1cb09a8339e4f8be706d27eaa180c2f177248a10"},
-    {file = "regex-2021.4.4-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:980d7be47c84979d9136328d882f67ec5e50008681d94ecc8afa8a65ed1f4a6f"},
-    {file = "regex-2021.4.4-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:ce15b6d103daff8e9fee13cf7f0add05245a05d866e73926c358e871221eae87"},
-    {file = "regex-2021.4.4-cp38-cp38-win32.whl", hash = "sha256:a91aa8619b23b79bcbeb37abe286f2f408d2f2d6f29a17237afda55bb54e7aac"},
-    {file = "regex-2021.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:c0502c0fadef0d23b128605d69b58edb2c681c25d44574fc673b0e52dce71ee2"},
-    {file = "regex-2021.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:598585c9f0af8374c28edd609eb291b5726d7cbce16be6a8b95aa074d252ee17"},
-    {file = "regex-2021.4.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:ee54ff27bf0afaf4c3b3a62bcd016c12c3fdb4ec4f413391a90bd38bc3624605"},
-    {file = "regex-2021.4.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7d9884d86dd4dd489e981d94a65cd30d6f07203d90e98f6f657f05170f6324c9"},
-    {file = "regex-2021.4.4-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:bf5824bfac591ddb2c1f0a5f4ab72da28994548c708d2191e3b87dd207eb3ad7"},
-    {file = "regex-2021.4.4-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:563085e55b0d4fb8f746f6a335893bda5c2cef43b2f0258fe1020ab1dd874df8"},
-    {file = "regex-2021.4.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9c3db21af35e3b3c05764461b262d6f05bbca08a71a7849fd79d47ba7bc33ed"},
-    {file = "regex-2021.4.4-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3916d08be28a1149fb97f7728fca1f7c15d309a9f9682d89d79db75d5e52091c"},
-    {file = "regex-2021.4.4-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:fd45ff9293d9274c5008a2054ecef86a9bfe819a67c7be1afb65e69b405b3042"},
-    {file = "regex-2021.4.4-cp39-cp39-win32.whl", hash = "sha256:fa4537fb4a98fe8fde99626e4681cc644bdcf2a795038533f9f711513a862ae6"},
-    {file = "regex-2021.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:97f29f57d5b84e73fbaf99ab3e26134e6687348e95ef6b48cfd2c06807005a07"},
-    {file = "regex-2021.4.4.tar.gz", hash = "sha256:52ba3d3f9b942c49d7e4bc105bb28551c44065f139a65062ab7912bef10c9afb"},
+    {file = "regex-2021.8.21-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b0c211c55d4aac4309c3209833c803fada3fc21cdf7b74abedda42a0c9dc3ce"},
+    {file = "regex-2021.8.21-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d5209c3ba25864b1a57461526ebde31483db295fc6195fdfc4f8355e10f7376"},
+    {file = "regex-2021.8.21-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c835c30f3af5c63a80917b72115e1defb83de99c73bc727bddd979a3b449e183"},
+    {file = "regex-2021.8.21-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:615fb5a524cffc91ab4490b69e10ae76c1ccbfa3383ea2fad72e54a85c7d47dd"},
+    {file = "regex-2021.8.21-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9966337353e436e6ba652814b0a957a517feb492a98b8f9d3b6ba76d22301dcc"},
+    {file = "regex-2021.8.21-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a49f85f0a099a5755d0a2cc6fc337e3cb945ad6390ec892332c691ab0a045882"},
+    {file = "regex-2021.8.21-cp310-cp310-win32.whl", hash = "sha256:f93a9d8804f4cec9da6c26c8cfae2c777028b4fdd9f49de0302e26e00bb86504"},
+    {file = "regex-2021.8.21-cp310-cp310-win_amd64.whl", hash = "sha256:a795829dc522227265d72b25d6ee6f6d41eb2105c15912c230097c8f5bfdbcdc"},
+    {file = "regex-2021.8.21-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:bca14dfcfd9aae06d7d8d7e105539bd77d39d06caaae57a1ce945670bae744e0"},
+    {file = "regex-2021.8.21-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41acdd6d64cd56f857e271009966c2ffcbd07ec9149ca91f71088574eaa4278a"},
+    {file = "regex-2021.8.21-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96f0c79a70642dfdf7e6a018ebcbea7ea5205e27d8e019cad442d2acfc9af267"},
+    {file = "regex-2021.8.21-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:45f97ade892ace20252e5ccecdd7515c7df5feeb42c3d2a8b8c55920c3551c30"},
+    {file = "regex-2021.8.21-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f9974826aeeda32a76648fc677e3125ade379869a84aa964b683984a2dea9f1"},
+    {file = "regex-2021.8.21-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea9753d64cba6f226947c318a923dadaf1e21cd8db02f71652405263daa1f033"},
+    {file = "regex-2021.8.21-cp36-cp36m-win32.whl", hash = "sha256:ef9326c64349e2d718373415814e754183057ebc092261387a2c2f732d9172b2"},
+    {file = "regex-2021.8.21-cp36-cp36m-win_amd64.whl", hash = "sha256:6dbd51c3db300ce9d3171f4106da18fe49e7045232630fe3d4c6e37cb2b39ab9"},
+    {file = "regex-2021.8.21-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a89ca4105f8099de349d139d1090bad387fe2b208b717b288699ca26f179acbe"},
+    {file = "regex-2021.8.21-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6c2b1d78ceceb6741d703508cd0e9197b34f6bf6864dab30f940f8886e04ade"},
+    {file = "regex-2021.8.21-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a34ba9e39f8269fd66ab4f7a802794ffea6d6ac500568ec05b327a862c21ce23"},
+    {file = "regex-2021.8.21-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ecb6e7c45f9cd199c10ec35262b53b2247fb9a408803ed00ee5bb2b54aa626f5"},
+    {file = "regex-2021.8.21-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:330836ad89ff0be756b58758878409f591d4737b6a8cef26a162e2a4961c3321"},
+    {file = "regex-2021.8.21-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:71a904da8c9c02aee581f4452a5a988c3003207cb8033db426f29e5b2c0b7aea"},
+    {file = "regex-2021.8.21-cp37-cp37m-win32.whl", hash = "sha256:b511c6009d50d5c0dd0bab85ed25bc8ad6b6f5611de3a63a59786207e82824bb"},
+    {file = "regex-2021.8.21-cp37-cp37m-win_amd64.whl", hash = "sha256:93f9f720081d97acee38a411e861d4ce84cbc8ea5319bc1f8e38c972c47af49f"},
+    {file = "regex-2021.8.21-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3a195e26df1fbb40ebee75865f9b64ba692a5824ecb91c078cc665b01f7a9a36"},
+    {file = "regex-2021.8.21-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06ba444bbf7ede3890a912bd4904bb65bf0da8f0d8808b90545481362c978642"},
+    {file = "regex-2021.8.21-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b8d551f1bd60b3e1c59ff55b9e8d74607a5308f66e2916948cafd13480b44a3"},
+    {file = "regex-2021.8.21-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ebbceefbffae118ab954d3cd6bf718f5790db66152f95202ebc231d58ad4e2c2"},
+    {file = "regex-2021.8.21-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccd721f1d4fc42b541b633d6e339018a08dd0290dc67269df79552843a06ca92"},
+    {file = "regex-2021.8.21-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ae87ab669431f611c56e581679db33b9a467f87d7bf197ac384e71e4956b4456"},
+    {file = "regex-2021.8.21-cp38-cp38-win32.whl", hash = "sha256:38600fd58c2996829480de7d034fb2d3a0307110e44dae80b6b4f9b3d2eea529"},
+    {file = "regex-2021.8.21-cp38-cp38-win_amd64.whl", hash = "sha256:61e734c2bcb3742c3f454dfa930ea60ea08f56fd1a0eb52d8cb189a2f6be9586"},
+    {file = "regex-2021.8.21-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b091dcfee169ad8de21b61eb2c3a75f9f0f859f851f64fdaf9320759a3244239"},
+    {file = "regex-2021.8.21-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:640ccca4d0a6fcc6590f005ecd7b16c3d8f5d52174e4854f96b16f34c39d6cb7"},
+    {file = "regex-2021.8.21-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac95101736239260189f426b1e361dc1b704513963357dc474beb0f39f5b7759"},
+    {file = "regex-2021.8.21-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b79dc2b2e313565416c1e62807c7c25c67a6ff0a0f8d83a318df464555b65948"},
+    {file = "regex-2021.8.21-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8b623fc429a38a881ab2d9a56ef30e8ea20c72a891c193f5ebbddc016e083ee"},
+    {file = "regex-2021.8.21-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8021dee64899f993f4b5cca323aae65aabc01a546ed44356a0965e29d7893c94"},
+    {file = "regex-2021.8.21-cp39-cp39-win32.whl", hash = "sha256:d6ec4ae13760ceda023b2e5ef1f9bc0b21e4b0830458db143794a117fdbdc044"},
+    {file = "regex-2021.8.21-cp39-cp39-win_amd64.whl", hash = "sha256:03840a07a402576b8e3a6261f17eb88abd653ad4e18ec46ef10c9a63f8c99ebd"},
+    {file = "regex-2021.8.21.tar.gz", hash = "sha256:faf08b0341828f6a29b8f7dd94d5cf8cc7c39bfc3e67b78514c54b494b66915a"},
 ]
 scikit-learn = [
     {file = "scikit-learn-0.22.2.post1.tar.gz", hash = "sha256:57538d138ba54407d21e27c306735cbd42a6aae0df6a5a30c7a6edde46b0017d"},
@@ -944,51 +1012,57 @@ scikit-learn = [
     {file = "scikit_learn-0.22.2.post1-cp38-cp38-win_amd64.whl", hash = "sha256:672ea38eb59b739a8907ec063642b486bcb5a2073dda5b72b7983eeaf1fd67c1"},
 ]
 scipy = [
-    {file = "scipy-1.6.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2a799714bf1f791fb2650d73222b248d18d53fd40d6af2df2c898db048189606"},
-    {file = "scipy-1.6.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:9e3302149a369697c6aaea18b430b216e3c88f9a61b62869f6104881e5f9ef85"},
-    {file = "scipy-1.6.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:b79104878003487e2b4639a20b9092b02e1bad07fc4cf924b495cf413748a777"},
-    {file = "scipy-1.6.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:44d452850f77e65e25b1eb1ac01e25770323a782bfe3a1a3e43847ad4266d93d"},
-    {file = "scipy-1.6.3-cp37-cp37m-win32.whl", hash = "sha256:b30280fbc1fd8082ac822994a98632111810311a9ece71a0e48f739df3c555a2"},
-    {file = "scipy-1.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:10dbcc7de03b8d635a1031cb18fd3eaa997969b64fdf78f99f19ac163a825445"},
-    {file = "scipy-1.6.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b21c6e0dc97b1762590b70dee0daddb291271be0580384d39f02c480b78290a"},
-    {file = "scipy-1.6.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1caade0ede6967cc675e235c41451f9fb89ae34319ddf4740194094ab736b88d"},
-    {file = "scipy-1.6.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:19aeac1ad3e57338723f4657ac8520f41714804568f2e30bd547d684d72c392e"},
-    {file = "scipy-1.6.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:ad7269254de06743fb4768f658753de47d8b54e4672c5ebe8612a007a088bd48"},
-    {file = "scipy-1.6.3-cp38-cp38-win32.whl", hash = "sha256:d647757373985207af3343301d89fe738d5a294435a4f2aafb04c13b4388c896"},
-    {file = "scipy-1.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:33d1677d46111cfa1c84b87472a0274dde9ef4a7ef2e1f155f012f5f1e995d8f"},
-    {file = "scipy-1.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d449d40e830366b4c612692ad19fbebb722b6b847f78a7b701b1e0d6cda3cc13"},
-    {file = "scipy-1.6.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:23995dfcf269ec3735e5a8c80cfceaf384369a47699df111a6246b83a55da582"},
-    {file = "scipy-1.6.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:fdf606341cd798530b05705c87779606fcdfaf768a8129c348ea94441da15b04"},
-    {file = "scipy-1.6.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f68eb46b86b2c246af99fcaa6f6e37c7a7a413e1084a794990b877f2ff71f7b6"},
-    {file = "scipy-1.6.3-cp39-cp39-win32.whl", hash = "sha256:01b38dec7e9f897d4db04f8de4e20f0f5be3feac98468188a0f47a991b796055"},
-    {file = "scipy-1.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:3274ce145b5dc416c49c0cf8b6119f787f0965cd35e22058fe1932c09fe15d77"},
-    {file = "scipy-1.6.3.tar.gz", hash = "sha256:a75b014d3294fce26852a9d04ea27b5671d86736beb34acdfc05859246260707"},
+    {file = "scipy-1.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2a0eeaab01258e0870c4022a6cd329aef3b7c6c2b606bd7cf7bb2ba9820ae561"},
+    {file = "scipy-1.7.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f52470e0548cdb74fb8ddf06773ffdcca7c97550f903b1c51312ec19243a7f7"},
+    {file = "scipy-1.7.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:787749110a23502031fb1643c55a2236c99c6b989cca703ea2114d65e21728ef"},
+    {file = "scipy-1.7.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3304bd5bc32e00954ac4b3f4cc382ca8824719bf348aacbec6347337d6b125fe"},
+    {file = "scipy-1.7.1-cp37-cp37m-win32.whl", hash = "sha256:d1388fbac9dd591ea630da75c455f4cc637a7ca5ecb31a6b6cef430914749cde"},
+    {file = "scipy-1.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:d648aa85dd5074b1ed83008ae987c3fbb53d68af619fce1dee231f4d8bd40e2f"},
+    {file = "scipy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bc61e3e5ff92d2f32bb263621d54a9cff5e3f7c420af3d1fa122ce2529de2bd9"},
+    {file = "scipy-1.7.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a496b42dbcd04ea9924f5e92be63af3d8e0f43a274b769bfaca0a297327d54ee"},
+    {file = "scipy-1.7.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d13f31457f2216e5705304d9f28e2826edf75487410a57aa99263fa4ffd792c2"},
+    {file = "scipy-1.7.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:90c07ba5f34f33299a428b0d4fa24c30d2ceba44d63f8385b2b05be460819fcb"},
+    {file = "scipy-1.7.1-cp38-cp38-win32.whl", hash = "sha256:efdd3825d54c58df2cc394366ca4b9166cf940a0ebddeb87b6c10053deb625ea"},
+    {file = "scipy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:71cfc96297617eab911e22216e8a8597703202e95636d9406df9af5c2ac99a2b"},
+    {file = "scipy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4ee952f39a4a4c7ba775a32b664b1f4b74818548b65f765987adc14bb78f5802"},
+    {file = "scipy-1.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:611f9cb459d0707dd8e4de0c96f86e93f61aac7475fcb225e9ec71fecdc5cebf"},
+    {file = "scipy-1.7.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e101bceeb9e65a90dadbc5ca31283403a2d4667b9c178db29109750568e8d112"},
+    {file = "scipy-1.7.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4729b41a4cdaf4cd011aeac816b532f990bdf97710cef59149d3e293115cf467"},
+    {file = "scipy-1.7.1-cp39-cp39-win32.whl", hash = "sha256:c9951e3746b68974125e5e3445008a4163dd6d20ae0bbdae22b38cb8951dc11b"},
+    {file = "scipy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:da9c6b336e540def0b7fd65603da8abeb306c5fc9a5f4238665cbbb5ff95cf58"},
+    {file = "scipy-1.7.1.tar.gz", hash = "sha256:6b47d5fa7ea651054362561a28b1ccc8da9368a39514c1bbf6c0977a1c376764"},
 ]
 six = [
-    {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"},
-    {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"},
+    {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
+    {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
 ]
 toml = [
     {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
     {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
 ]
+tomli = [
+    {file = "tomli-1.2.1-py3-none-any.whl", hash = "sha256:8dd0e9524d6f386271a36b41dbf6c57d8e32fd96fd22b6584679dc569d20899f"},
+    {file = "tomli-1.2.1.tar.gz", hash = "sha256:a5b75cb6f3968abb47af1b40c1819dc519ea82bcc065776a866e8d74c5ca9442"},
+]
 torch = [
-    {file = "torch-1.8.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:f23eeb1a48cc39209d986c418ad7e02227eee973da45c0c42d36b1aec72f4940"},
-    {file = "torch-1.8.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:4ace9c5bb94d5a7b9582cd089993201658466e9c59ff88bd4e9e08f6f072d1cf"},
-    {file = "torch-1.8.1-cp36-cp36m-win_amd64.whl", hash = "sha256:6ffa1e7ae079c7cb828712cb0cdaae5cc4fb87c16a607e6d14526b62c20bcc17"},
-    {file = "torch-1.8.1-cp36-none-macosx_10_9_x86_64.whl", hash = "sha256:16f2630d9604c4ee28ea7d6e388e2264cd7bc6031c6ecd796bae3f56b5efa9a3"},
-    {file = "torch-1.8.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:95b7bbbacc3f28fe438f418392ceeae146a01adc03b29d44917d55214ac234c9"},
-    {file = "torch-1.8.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:55137feb2f5a0dc7aced5bba690dcdb7652054ad3452b09a2bbb59f02a11e9ff"},
-    {file = "torch-1.8.1-cp37-cp37m-win_amd64.whl", hash = "sha256:8ad2252bf09833dcf46a536a78544e349b8256a370e03a98627ebfb118d9555b"},
-    {file = "torch-1.8.1-cp37-none-macosx_10_9_x86_64.whl", hash = "sha256:1388b30fbd262c1a053d6c9ace73bb0bd8f5871b4892b6f3e02d1d7bc9768563"},
-    {file = "torch-1.8.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:e7ad1649adb7dc2a450e70a3e51240b84fa4746c69c8f98989ce0c254f9fba3a"},
-    {file = "torch-1.8.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:3e4190c04dfd89c59bad06d5fe451446643a65e6d2607cc989eb1001ee76e12f"},
-    {file = "torch-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:5c2e9a33d44cdb93ebd739b127ffd7da786bf5f740539539195195b186a05f6c"},
-    {file = "torch-1.8.1-cp38-none-macosx_10_9_x86_64.whl", hash = "sha256:c6ede2ae4dcd8214b63e047efabafa92493605205a947574cf358216ca4e440a"},
-    {file = "torch-1.8.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:ce7d435426f3dd14f95710d779aa46e9cd5e077d512488e813f7589fdc024f78"},
-    {file = "torch-1.8.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:a50ea8ed900927fb30cadb63aa7a32fdd59c7d7abe5012348dfbe35a8355c083"},
-    {file = "torch-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:dac4d10494e74f7e553c92d7263e19ea501742c4825ddd26c4decfa27be95981"},
-    {file = "torch-1.8.1-cp39-none-macosx_10_9_x86_64.whl", hash = "sha256:225ee4238c019b28369c71977327deeeb2bd1c6b8557e6fcf631b8866bdc5447"},
+    {file = "torch-1.9.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:3a2d070cf28860d285d4ab156f3954c0c1d12f4c037aa312a7c029227c0d106b"},
+    {file = "torch-1.9.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:b296e65e25081af147af936f1e3a1f17f583a9afacfa5309742678ffef728ace"},
+    {file = "torch-1.9.0-cp36-cp36m-win_amd64.whl", hash = "sha256:117098d4924b260a24a47c6b3fe37f2ae41f04a2ea2eff9f553ae9210b12fa54"},
+    {file = "torch-1.9.0-cp36-none-macosx_10_9_x86_64.whl", hash = "sha256:d6103b9a634993bd967337a1149f9d8b23922f42a3660676239399e15c1b4515"},
+    {file = "torch-1.9.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:0164673908e6b291ace592d382eba3e258b3bad009b8078cad8f3b9e00d8f23e"},
+    {file = "torch-1.9.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:52548b45efff772fe3810fe91daf34f981ac0ca1a7227f6226fd5693f53b5b88"},
+    {file = "torch-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62c0a7e433681d0861494d1ede96d2485e4dbb3ea8fd867e8419addebf5de1af"},
+    {file = "torch-1.9.0-cp37-none-macosx_10_9_x86_64.whl", hash = "sha256:d88333091fd1627894bbf0d6dcef58a90e36bdf0d90a5d4675b5e07e72075511"},
+    {file = "torch-1.9.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:1d8139dcc864f48dc316376384f50e47a459284ad1cb84449242f4964e25aaec"},
+    {file = "torch-1.9.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:0aa4cca3f16fab40cb8dae6a49d0eccdc8f4ead9d1a6428cd9ba12befe082b2a"},
+    {file = "torch-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:646de1bef85d6c7590e98f8ea52e47acdcf58330982e4f5d73f5ca28dea2d552"},
+    {file = "torch-1.9.0-cp38-none-macosx_10_9_x86_64.whl", hash = "sha256:e596f0105f748cf09d4763152d8157aaf58d5231232eaf2c5673d4562ba86ad3"},
+    {file = "torch-1.9.0-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:ecc7193fff7741ced3db1f760666c8454d6664956288c54d1b49613b987a42f4"},
+    {file = "torch-1.9.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:95eeec3a6c42fd35aca552777b7d9979ed489760423de97c0118a45e849a61f4"},
+    {file = "torch-1.9.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:8a2b2012b3c7d6019e189496688fa77de7029a220840b406d8302d1c8021a11c"},
+    {file = "torch-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:7e2b14fe5b3a8266cbe2f6740c0195497507974ced7bc21e99971561913a0c28"},
+    {file = "torch-1.9.0-cp39-none-macosx_10_9_x86_64.whl", hash = "sha256:0a9e74b5057463ce4e55d9332a5670993fc9e1299c52e1740e505eda106fb355"},
+    {file = "torch-1.9.0-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:569ead6ae6bb0e636df0fc8af660ef03260e630dc5f2f4cf3198027e7b6bb481"},
 ]
 tornado = [
     {file = "tornado-6.1-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32"},
@@ -1034,8 +1108,8 @@ tornado = [
     {file = "tornado-6.1.tar.gz", hash = "sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791"},
 ]
 tqdm = [
-    {file = "tqdm-4.60.0-py2.py3-none-any.whl", hash = "sha256:daec693491c52e9498632dfbe9ccfc4882a557f5fa08982db1b4d3adbe0887c3"},
-    {file = "tqdm-4.60.0.tar.gz", hash = "sha256:ebdebdb95e3477ceea267decfc0784859aa3df3e27e22d23b83e9b272bf157ae"},
+    {file = "tqdm-4.62.2-py2.py3-none-any.whl", hash = "sha256:80aead664e6c1672c4ae20dc50e1cdc5e20eeff9b14aa23ecd426375b28be588"},
+    {file = "tqdm-4.62.2.tar.gz", hash = "sha256:a4d6d112e507ef98513ac119ead1159d286deab17dffedd96921412c2d236ff5"},
 ]
 traitlets = [
     {file = "traitlets-5.0.5-py3-none-any.whl", hash = "sha256:69ff3f9d5351f31a7ad80443c2674b7099df13cc41fc5fa6e2f6d3b0330b0426"},
@@ -1074,15 +1148,15 @@ typed-ast = [
     {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"},
 ]
 typing-extensions = [
-    {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"},
-    {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"},
-    {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"},
+    {file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"},
+    {file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"},
+    {file = "typing_extensions-3.10.0.0.tar.gz", hash = "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342"},
 ]
 wcwidth = [
     {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"},
     {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"},
 ]
 zipp = [
-    {file = "zipp-3.4.1-py3-none-any.whl", hash = "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"},
-    {file = "zipp-3.4.1.tar.gz", hash = "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76"},
+    {file = "zipp-3.5.0-py3-none-any.whl", hash = "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3"},
+    {file = "zipp-3.5.0.tar.gz", hash = "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4"},
 ]
diff --git a/pyproject.toml b/pyproject.toml
index d7a5a0e..e4e6492 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,10 +1,16 @@
 [tool.poetry]
 name = "PytorchCML"
-version = "0.1.3"
+version = "0.0.0"
 description = "Collaborative Metric Learning implemented by Pytorch"
 authors = ["hand10ryo <hand10ryo@yahoo.co.jp>"]
 license = "MIT"
 readme = "README.md"
+homepage = "https://github.com/hand10ryo/PytorchCML"
+repository = "https://github.com/hand10ryo/PytorchCML"
+
+[tool.poetry-dynamic-versioning]
+enable = true
+style = "pep440"
 
 [tool.poetry.dependencies]
 python = ">=3.7.10,<3.10"
diff --git a/src/PytorchCML/losses/BasePairwiseLoss.py b/src/PytorchCML/losses/BasePairwiseLoss.py
index 7c3a80d..cd0a082 100644
--- a/src/PytorchCML/losses/BasePairwiseLoss.py
+++ b/src/PytorchCML/losses/BasePairwiseLoss.py
@@ -10,22 +10,13 @@ def __init__(self, regularizers: list = []):
         self.regularizers = regularizers
 
     def forward(
-        self,
-        user_emb: torch.Tensor,
-        pos_item_emb: torch.Tensor,
-        neg_item_emb: torch.Tensor,
-        user_bias: torch.Tensor,
-        pos_item_bias: torch.Tensor,
-        neg_item_bias: torch.Tensor,
+        self, embeddings_dict: dict, batch: torch.Tensor, column_names: dict
     ) -> torch.Tensor:
         """
         Args:
-            user_emb : embeddings of user size (n_batch, d)
-            pos_item_emb : embeddings of positive item size (n_batch, d)
-            neg_item_emb : embeddings of negative item size (n_batch, n_neg_samples, d)
-            user_bias : bias of user size (n_batch, 1)
-            pos_item_bias : bias of positive item size (n_batch, 1)
-            neg_item_bias : bias of negative item size (n_batch, n_neg_samples, 1)
+            embeddings_dict (dict): A dictionary of embddings which has following key and values.
+            batch (torch.Tensor) : A tensor of batch, size (n_batch, *).
+            column_names (dict) : A dictionary that maps names to indices of rows of batch.
 
         Raises:
             NotImplementedError: [description]
@@ -35,18 +26,18 @@ def forward(
 
          ---   example code   ---
 
-        embeddings_dict = {
-            "user_emb": user_emb,
-            "pos_item_emb": pos_item_emb,
-            "neg_item_emb": neg_item_emb,
-            "user_bias": user_bias,
-            "pos_item_bias": pos_item_bias,
-            "neg_item_bias": neg_item_bias,
-        }
-
-        # loss = loss_function(embeddings_dict)
-        # reg = self.regularize(embeddings_dict)
-        # return loss + reg
+        # embeddings_dict = {
+        #   "user_embedding": user_emb,
+        #    "pos_item_embedding": pos_item_emb,
+        #    "neg_item_embedding": neg_item_emb,
+        #    "user_bias": user_bias,
+        #    "pos_item_bias": pos_item_bias,
+        #    "neg_item_bias": neg_item_bias,
+        #}
+
+        loss = loss_function(embeddings_dict, batch, column_names)
+        reg = self.regularize(embeddings_dict)
+        return loss + reg
         """
 
         raise NotImplementedError
diff --git a/src/PytorchCML/losses/BaseTripletLoss.py b/src/PytorchCML/losses/BaseTripletLoss.py
index 667ecea..932c91b 100644
--- a/src/PytorchCML/losses/BaseTripletLoss.py
+++ b/src/PytorchCML/losses/BaseTripletLoss.py
@@ -18,17 +18,14 @@ def __init__(self, margin: float = 1, regularizers: list = []):
         self.regularizers = regularizers
 
     def forward(
-        self,
-        user_emb: torch.Tensor,
-        pos_item_emb: torch.Tensor,
-        neg_item_emb: torch.Tensor,
+        self, embeddings_dict: dict, batch: torch.Tensor, column_names: dict
     ) -> torch.Tensor:
         """Method of forward
 
         Args:
-            user_emb : embeddings of user size (n_batch, 1, d)
-            pos_item_emb : embeddings of positive item size (n_batch, 1, d)
-            neg_item_emb : embeddings of negative item size (n_batch, n_neg_samples, d)
+            embeddings_dict (dict): A dictionary of embddings which has following key and values.
+            batch (torch.Tensor) : A tensor of batch, size (n_batch, *).
+            column_names (dict) : A dictionary that maps names to indices of rows of batch.
 
         Raises:
             NotImplementedError: [description]
@@ -39,14 +36,13 @@ def forward(
 
         ---- example code ---
 
-        embeddings_dict = {
-            "user_emb": user_emb,
-            "pos_item_emb": pos_item_emb,
-            "neg_item_emb": neg_item_emb,
-        }
+        # embeddings_dict = {
+        #   "user_embedding": user_emb,
+        #    "pos_item_embedding": pos_item_emb,
+        #    "neg_item_embedding": neg_item_emb,
+        #}
 
-
-        loss = some_function(user_emb, pos_item_emb, neg_item_emb)
+        loss = some_function(embeddings_dict, batch, column_names)
         reg = self.regularize(embeddings_dict)
         return loss + reg
 
diff --git a/src/PytorchCML/losses/LogitPairwiseLoss.py b/src/PytorchCML/losses/LogitPairwiseLoss.py
index 31cbd96..6e515bf 100644
--- a/src/PytorchCML/losses/LogitPairwiseLoss.py
+++ b/src/PytorchCML/losses/LogitPairwiseLoss.py
@@ -12,42 +12,44 @@ def __init__(self, regularizers: list = []):
         self.LogSigmoid = nn.LogSigmoid()
 
     def forward(
-        self,
-        user_emb: torch.Tensor,
-        pos_item_emb: torch.Tensor,
-        neg_item_emb: torch.Tensor,
-        user_bias: torch.Tensor,
-        pos_item_bias: torch.Tensor,
-        neg_item_bias: torch.Tensor,
+        self, embeddings_dict: dict, batch: torch.Tensor, column_names: dict
     ) -> torch.Tensor:
-        """
+        """Method of forwarding loss
+
         Args:
-            user_emb : embeddings of user size (n_batch, d)
-            pos_item_emb : embeddings of positive item size (n_batch, d)
-            neg_item_emb : embeddings of negative item size (n_batch, n_neg_samples, d)
-            user_bias : bias of user size (n_batch, 1)
-            pos_item_bias : bias of positive item size (n_batch, 1)
-            neg_item_bias : bias of negative item size (n_batch, n_neg_samples, 1)
+            embeddings_dict (dict): A dictionary of embddings which has following key and values.
+                user_embedding : embeddings of user, size (n_batch, d)
+                pos_item_embedding : embeddings of positive item, size (n_batch, d)
+                neg_item_embedding : embeddings of negative item, size (n_batch, n_neg_samples, d)
+                user_bias : bias of user, size (n_batch, 1)
+                pos_item_bias : bias of positive item, size (n_batch, 1)
+                neg_item_bias : bias of negative item, size (n_batch, n_neg_samples)
+
+            batch (torch.Tensor) : A tensor of batch, size (n_batch, *).
+            column_names (dict) : A dictionary that maps names to indices of rows of batch.
         """
-        embeddings_dict = {
-            "user_emb": user_emb,  # (B, d)
-            "pos_item_emb": pos_item_emb,  # (B, d)
-            "neg_item_emb": neg_item_emb,  # (B, N, d)
-            "user_bias": user_bias,  # (B, 1)
-            "pos_item_bias": pos_item_bias,  # (B, 1)
-            "neg_item_bias": neg_item_bias,  # (B, N, 1)
-        }
-
-        n_batch = user_emb.shape[0]
+
+        n_batch = embeddings_dict["user_embedding"].shape[0]
+        n_neg = embeddings_dict["neg_item_bias"].shape[1]
         n_pos = 1
-        n_neg = neg_item_emb.shape[1]
-        neg_item_bias = neg_item_bias.reshape(n_batch, n_neg)
 
-        pos_inner = torch.einsum("nd,nd->n", user_emb, pos_item_emb)
-        neg_inner = torch.einsum("nd,njd->nj", user_emb, neg_item_emb)
+        pos_inner = torch.einsum(
+            "nd,nd->n",
+            embeddings_dict["user_embedding"],
+            embeddings_dict["pos_item_embedding"],
+        )
+
+        neg_inner = torch.einsum(
+            "nd,njd->nj",
+            embeddings_dict["user_embedding"],
+            embeddings_dict["neg_item_embedding"],
+        )
+
+        pos_bias = embeddings_dict["user_bias"] + embeddings_dict["pos_item_bias"]
+        pos_y_hat = pos_inner + pos_bias.reshape(-1)
 
-        pos_y_hat = pos_inner + (user_bias + pos_item_bias).reshape(-1)
-        neg_y_hat = neg_inner + user_bias + neg_item_bias
+        neg_bias = embeddings_dict["user_bias"] + embeddings_dict["neg_item_bias"]
+        neg_y_hat = neg_inner + neg_bias
 
         pos_loss = -nn.LogSigmoid()(pos_y_hat).sum()
         neg_loss = -nn.LogSigmoid()(-neg_y_hat).sum()
diff --git a/src/PytorchCML/losses/MSEPairwiseLoss.py b/src/PytorchCML/losses/MSEPairwiseLoss.py
new file mode 100644
index 0000000..3a99e3c
--- /dev/null
+++ b/src/PytorchCML/losses/MSEPairwiseLoss.py
@@ -0,0 +1,58 @@
+import torch
+
+from .BasePairwiseLoss import BasePairwiseLoss
+
+
+class MSEPairwiseLoss(BasePairwiseLoss):
+    """Class of loss for MSE in implicit feedback"""
+
+    def forward(
+        self, embeddings_dict: dict, batch: torch.Tensor, column_names: dict
+    ) -> torch.Tensor:
+        """Method of forwarding loss
+
+        Args:
+            embeddings_dict (dict): A dictionary of embddings which has following key and values.
+                "user_embedding" : embeddings of user, size (n_batch, d)
+                "pos_item_embedding" : embeddings of positive item, size (n_batch, d)
+                "neg_item_embedding" : embeddings of negative item, size (n_batch, n_neg_samples, d)
+                "user_bias" : bias of user, size (n_batch, 1)
+                "pos_item_bias" : bias of positive item, size (n_batch, 1)
+                "neg_item_bias" : bias of negative item, size (n_batch, n_neg_samples)
+
+            batch (torch.Tensor) : A tensor of batch, size (n_batch, *).
+            column_names (dict) : A dictionary that maps names to indices of rows of batch which has following key and values.
+                "user_id" : user id
+                "item_id" : item id
+                "pscore" : propensity score
+        """
+
+        n_batch = embeddings_dict["user_embedding"].shape[0]
+        n_neg = embeddings_dict["neg_item_bias"].shape[1]
+        n_pos = 1
+
+        pos_inner = torch.einsum(
+            "nd,nd->n",
+            embeddings_dict["user_embedding"],
+            embeddings_dict["pos_item_embedding"],
+        )
+
+        neg_inner = torch.einsum(
+            "nd,njd->nj",
+            embeddings_dict["user_embedding"],
+            embeddings_dict["neg_item_embedding"],
+        )
+
+        pos_bias = embeddings_dict["user_bias"] + embeddings_dict["pos_item_bias"]
+        neg_bias = embeddings_dict["user_bias"] + embeddings_dict["neg_item_bias"]
+
+        pos_r_hat = pos_inner + pos_bias.reshape(-1)
+        neg_r_hat = neg_inner + neg_bias
+
+        pos_loss = ((1 - torch.sigmoid(pos_r_hat)) ** 2).sum()
+        neg_loss = (torch.sigmoid(neg_r_hat) ** 2).sum()
+
+        loss = (pos_loss + neg_loss) / (n_batch * (n_pos + n_neg))
+        reg = self.regularize(embeddings_dict)
+
+        return loss + reg
diff --git a/src/PytorchCML/losses/MinTripletLoss.py b/src/PytorchCML/losses/MinTripletLoss.py
index 667b20b..c8337a9 100644
--- a/src/PytorchCML/losses/MinTripletLoss.py
+++ b/src/PytorchCML/losses/MinTripletLoss.py
@@ -9,28 +9,30 @@ def __init__(self, margin: float = 1, regularizers: list = []):
         super().__init__(margin, regularizers)
 
     def forward(
-        self,
-        user_emb: torch.Tensor,
-        pos_item_emb: torch.Tensor,
-        neg_item_emb: torch.Tensor,
+        self, embeddings_dict: dict, batch: torch.Tensor, column_names: dict
     ) -> torch.Tensor:
-        """
+        """Method of forwarding loss
+
         Args:
-            user_emb : embeddings of user size (n_batch, 1, d)
-            pos_item_emb : embeddings of positive item size (n_batch, 1, d)
-            neg_item_emb : embeddings of negative item size (n_batch, n_neg_samples, d)
+            embeddings_dict (dict): A dictionary of embddings which has following key and values.
+                user_embedding : embeddings of user, size (n_batch, d)
+                pos_item_embedding : embeddings of positive item, size (n_batch, d)
+                neg_item_embedding : embeddings of negative item, size (n_batch, n_neg_samples, d)
+
+            batch (torch.Tensor) : A tensor of batch, size (n_batch, *).
+            column_names (dict) : A dictionary that maps names to indices of rows of batch.
 
         Return:
-            loss : L = Σ [m + pos_dist^2 - min(neg_dist)^2]
+            torch.Tensor: loss,  L = Σ [m + pos_dist^2 - min(neg_dist)^2]
         """
-        embeddings_dict = {
-            "user_emb": user_emb,
-            "pos_item_emb": pos_item_emb,
-            "neg_item_emb": neg_item_emb,
-        }
-
-        pos_dist = torch.cdist(user_emb, pos_item_emb)
-        neg_dist = torch.cdist(user_emb, neg_item_emb)
+
+        pos_dist = torch.cdist(
+            embeddings_dict["user_embedding"], embeddings_dict["pos_item_embedding"]
+        )
+
+        neg_dist = torch.cdist(
+            embeddings_dict["user_embedding"], embeddings_dict["neg_item_embedding"]
+        )
 
         min_neg_dist = torch.min(neg_dist, axis=2)
         pairwiseloss = self.ReLU(self.margin + pos_dist ** 2 - min_neg_dist.values ** 2)
diff --git a/src/PytorchCML/losses/RelevancePairwiseLoss.py b/src/PytorchCML/losses/RelevancePairwiseLoss.py
new file mode 100644
index 0000000..a4e3e01
--- /dev/null
+++ b/src/PytorchCML/losses/RelevancePairwiseLoss.py
@@ -0,0 +1,84 @@
+import torch
+from torch import nn
+
+from .BasePairwiseLoss import BasePairwiseLoss
+
+
+class RelevancePairwiseLoss(BasePairwiseLoss):
+    """Class of loss for Relevance Matrix Factorization
+
+    See below reference for detail.
+
+    Y. Saito, S. Yaginuma, Y. Nishino, H. Sakata, and K. Nakata,
+    “Unbiased recommender learning from missing-not-at-random implicit feedback,” in WSDM, 2020
+
+    """
+
+    def __init__(self, regularizers: list = [], delta: str = "logistic"):
+        super().__init__(regularizers)
+        self.LogSigmoid = nn.LogSigmoid()
+        if delta == "logistic":
+            self.delta_pos = lambda x: -nn.LogSigmoid()(x)
+            self.delta_neg = lambda x: -nn.LogSigmoid()(-x)
+
+        elif delta == "mse":
+            self.delta_pos = lambda x: (1 - torch.sigmoid(x)) ** 2
+            self.delta_neg = lambda x: torch.sigmoid(x) ** 2
+
+        else:
+            raise NotImplementedError
+
+    def forward(
+        self, embeddings_dict: dict, batch: torch.Tensor, column_names: dict
+    ) -> torch.Tensor:
+        """Method of forwarding loss
+
+        Args:
+            embeddings_dict (dict): A dictionary of embddings which has following key and values.
+                "user_embedding" : embeddings of user, size (n_batch, d)
+                "pos_item_embedding" : embeddings of positive item, size (n_batch, d)
+                "neg_item_embedding" : embeddings of negative item, size (n_batch, n_neg_samples, d)
+                "user_bias" : bias of user, size (n_batch, 1)
+                "pos_item_bias" : bias of positive item, size (n_batch, 1)
+                "neg_item_bias" : bias of negative item, size (n_batch, n_neg_samples)
+
+            batch (torch.Tensor) : A tensor of batch, size (n_batch, *).
+            column_names (dict) : A dictionary that maps names to indices of rows of batch which has following key and values.
+                "user_id" : user id
+                "item_id" : item id
+                "pscore" : propensity score
+        """
+
+        n_batch = embeddings_dict["user_embedding"].shape[0]
+        n_neg = embeddings_dict["neg_item_bias"].shape[1]
+        n_pos = 1
+        pscore = batch[:, column_names["pscore"]]
+
+        pos_inner = torch.einsum(
+            "nd,nd->n",
+            embeddings_dict["user_embedding"],
+            embeddings_dict["pos_item_embedding"],
+        )
+
+        neg_inner = torch.einsum(
+            "nd,njd->nj",
+            embeddings_dict["user_embedding"],
+            embeddings_dict["neg_item_embedding"],
+        )
+
+        pos_bias = embeddings_dict["user_bias"] + embeddings_dict["pos_item_bias"]
+        neg_bias = embeddings_dict["user_bias"] + embeddings_dict["neg_item_bias"]
+
+        pos_r_hat = pos_inner + pos_bias.reshape(-1)
+        neg_r_hat = neg_inner + neg_bias
+
+        pos_loss_pos = self.delta_pos(pos_r_hat) / pscore
+        pos_loss_neg = 1 - self.delta_neg(pos_r_hat) / pscore
+        pos_loss = (pos_loss_pos + pos_loss_neg).sum()
+
+        neg_loss = self.delta_neg(neg_r_hat).sum()
+
+        loss = (pos_loss + neg_loss) / (n_batch * (n_pos + n_neg))
+        reg = self.regularize(embeddings_dict)
+
+        return loss + reg
diff --git a/src/PytorchCML/losses/SumTripletLoss.py b/src/PytorchCML/losses/SumTripletLoss.py
index fc0586c..633bf82 100644
--- a/src/PytorchCML/losses/SumTripletLoss.py
+++ b/src/PytorchCML/losses/SumTripletLoss.py
@@ -10,28 +10,29 @@ def __init__(self, margin: float = 1, regularizers: list = []):
         super().__init__(margin, regularizers)
 
     def forward(
-        self,
-        user_emb: torch.Tensor,
-        pos_item_emb: torch.Tensor,
-        neg_item_emb: torch.Tensor,
+        self, embeddings_dict: dict, batch: torch.Tensor, column_names: dict
     ) -> torch.Tensor:
-        """
+        """Method of forwarding loss
+
         Args:
-            user_emb : embeddings of user size (n_batch, 1, d)
-            pos_item_emb : embeddings of positive item size (n_batch, 1, d)
-            neg_item_emb : embeddings of negative item size (n_batch, n_neg_samples, d)
+            embeddings_dict (dict): A dictionary of embddings which has following key and values
+                user_embedding : embeddings of user, size (n_batch, d)
+                pos_item_embedding : embeddings of positive item, size (n_batch, d)
+                neg_item_embedding : embeddings of negative item, size (n_batch, n_neg_samples, d)
+
+            batch (torch.Tensor) : A tensor of batch, size (n_batch, *).
+            column_names (dict) : A dictionary that maps names to indices of rows of batch.
 
         Return:
-            loss : L = Σ [m + pos_dist^2 - min(neg_dist)^2]
+            torch.Tensor : loss, L = Σ [m + pos_dist^2 - min(neg_dist)^2]
         """
-        embeddings_dict = {
-            "user_emb": user_emb,
-            "pos_item_emb": pos_item_emb,
-            "neg_item_emb": neg_item_emb,
-        }
-
-        pos_dist = torch.cdist(user_emb, pos_item_emb)
-        neg_dist = torch.cdist(user_emb, neg_item_emb)
+        pos_dist = torch.cdist(
+            embeddings_dict["user_embedding"], embeddings_dict["pos_item_embedding"]
+        )
+
+        neg_dist = torch.cdist(
+            embeddings_dict["user_embedding"], embeddings_dict["neg_item_embedding"]
+        )
 
         tripletloss = self.ReLU(self.margin + pos_dist ** 2 - neg_dist ** 2)
         loss = torch.mean(tripletloss)
diff --git a/src/PytorchCML/losses/__init__.py b/src/PytorchCML/losses/__init__.py
index 05ec6b2..9a2e7ce 100644
--- a/src/PytorchCML/losses/__init__.py
+++ b/src/PytorchCML/losses/__init__.py
@@ -4,3 +4,5 @@
 from .SumTripletLoss import SumTripletLoss
 from .BasePairwiseLoss import BasePairwiseLoss
 from .LogitPairwiseLoss import LogitPairwiseLoss
+from .RelevancePairwiseLoss import RelevancePairwiseLoss
+from .MSEPairwiseLoss import MSEPairwiseLoss
diff --git a/src/PytorchCML/models/BaseEmbeddingModel.py b/src/PytorchCML/models/BaseEmbeddingModel.py
index e3920e3..ebf5a4b 100644
--- a/src/PytorchCML/models/BaseEmbeddingModel.py
+++ b/src/PytorchCML/models/BaseEmbeddingModel.py
@@ -51,7 +51,7 @@ def __init__(
 
     def forward(
         self, users: torch.Tensor, pos_items: torch.Tensor, neg_items: torch.Tensor
-    ) -> torch.Tensor:
+    ) -> dict:
         """Method of forwarding which returns embeddings
 
         Args:
@@ -63,7 +63,7 @@ def forward(
             NotImplementedError: [description]
 
         Returns:
-            torch.Tensor: [description]
+            dict: [description]
         """
         raise NotImplementedError
 
diff --git a/src/PytorchCML/models/CollaborativeMetricLearning.py b/src/PytorchCML/models/CollaborativeMetricLearning.py
index 33d3128..102754b 100644
--- a/src/PytorchCML/models/CollaborativeMetricLearning.py
+++ b/src/PytorchCML/models/CollaborativeMetricLearning.py
@@ -6,27 +6,25 @@
 class CollaborativeMetricLearning(BaseEmbeddingModel):
     def forward(
         self, users: torch.Tensor, pos_items: torch.Tensor, neg_items: torch.Tensor
-    ) -> torch.Tensor:
+    ) -> dict:
         """
         Args:
-            users : tensor of user indices size (n_batch, 1).
-            pos_items : tensor of item indices size (n_batch, 1),
+            users : tensor of user indices size (n_batch).
+            pos_items : tensor of item indices size (n_batch, 1)
             neg_items : tensor of item indices size (n_batch, n_neg_samples)
 
         Returns:
-            user_emb : embeddings of user size (n_batch, 1, d)
-            pos_item_emb : embeddings of positive items size (n_batch, 1, d)
-            neg_item_emb : embeddings of negative items size (n_batch, n_neg_samples, d)
+            dict: A dictionary of embeddings.
         """
 
         # get enmbeddigs
-        user_emb = self.user_embedding(users)
-        pos_item_emb = self.item_embedding(pos_items)
-        neg_item_emb = self.item_embedding(neg_items)
+        embeddings_dict = {
+            "user_embedding": self.user_embedding(users),
+            "pos_item_embedding": self.item_embedding(pos_items),
+            "neg_item_embedding": self.item_embedding(neg_items),
+        }
 
-        # compute distance  dist = torch.cdist(u_emb, i_emb)
-
-        return user_emb, pos_item_emb, neg_item_emb
+        return embeddings_dict
 
     def spreadout_distance(self, pos_items: torch.Tensor, neg_itmes: torch.Tensor):
         """
diff --git a/src/PytorchCML/models/MatrixFactorization.py b/src/PytorchCML/models/MatrixFactorization.py
index 568f1d4..671a47c 100644
--- a/src/PytorchCML/models/MatrixFactorization.py
+++ b/src/PytorchCML/models/MatrixFactorization.py
@@ -59,34 +59,29 @@ def __init__(
 
     def forward(
         self, users: torch.Tensor, pos_items: torch.Tensor, neg_items: torch.Tensor
-    ) -> torch.Tensor:
-        """
+    ) -> dict:
+        """Method of forwarding embeddings
+
         Args:
             users : tensor of user indices size (n_batch).
             pos_items : tensor of item indices size (n_batch, 1)
             neg_items : tensor of item indices size (n_batch, n_neg_samples)
 
         Returns:
-            inner : inner product for each users and item pair
-                   pos_pairs -> size (n_batch, 1),
-                   neg_pairs -> size (n_batch, n_neg_samples)
-
+            dict: A dictionary of embeddings.
         """
 
         # get enmbeddigs
-        u_emb = self.user_embedding(users)  # batch_size × dim
-        ip_emb = self.item_embedding(pos_items)  # batch_size × dim
-        in_emb = self.item_embedding(neg_items)  # batch_size × n_samples × dim
-
-        # get bias
-        ub = self.user_bias(users)  # batch_size × 1
-        ipb = self.item_bias(pos_items)  # batch_size × 1
-        inb = self.item_bias(neg_items)  # batch_size × n_samples × 1
-
-        # compute inner product
-        # inner = torch.einsum('nd,njd->nj', u_emb, i_emb)
-
-        return u_emb, ip_emb, in_emb, ub, ipb, inb
+        embeddings_dict = {
+            "user_embedding": self.user_embedding(users),
+            "pos_item_embedding": self.item_embedding(pos_items),
+            "neg_item_embedding": self.item_embedding(neg_items),
+            "user_bias": self.user_bias(users),
+            "pos_item_bias": self.item_bias(pos_items),
+            "neg_item_bias": self.item_bias(neg_items)[:, :, 0],
+        }
+
+        return embeddings_dict
 
     def predict(self, pairs: torch.Tensor) -> torch.Tensor:
         """Method of predicting relevance for each pair of user and item.
diff --git a/src/PytorchCML/regularizers/BaseRegularizer.py b/src/PytorchCML/regularizers/BaseRegularizer.py
index de57556..2477132 100644
--- a/src/PytorchCML/regularizers/BaseRegularizer.py
+++ b/src/PytorchCML/regularizers/BaseRegularizer.py
@@ -3,11 +3,12 @@
 
 
 class BaseRegularizer(nn.Module):
-    def __init__(self):
+    def __init__(self, weight=1e-2):
         super().__init__()
+        self.weight = weight
 
     def forward(self, embeddings_dict: dict) -> torch.Tensor:
-        """ method of forwarding
+        """method of forwarding
 
         Args:
             embeddings_dict (dict): dictionary of embbedings which will be used.
diff --git a/src/PytorchCML/regularizers/GlobalOrthogonalRegularizer.py b/src/PytorchCML/regularizers/GlobalOrthogonalRegularizer.py
index 0662c5e..541a674 100644
--- a/src/PytorchCML/regularizers/GlobalOrthogonalRegularizer.py
+++ b/src/PytorchCML/regularizers/GlobalOrthogonalRegularizer.py
@@ -5,16 +5,14 @@
 
 
 class GlobalOrthogonalRegularizer(BaseRegularizer):
-    """ Class of Global Orthogonal Regularization
-    """
+    """Class of Global Orthogonal Regularization"""
 
     def __init__(self, weight: float = 1e-2):
-        super().__init__()
+        super().__init__(weight)
         self.ReLU = nn.ReLU()
-        self.weight = weight
 
     def forward(self, embeddings_dict: dict) -> torch.Tensor:
-        """ Method of comuting regularize term
+        """Method of comuting regularize term
 
         Args:
             embeddings_dict (dict): dictionary of embeddings which has pos_item_emb and neg_item_emb
@@ -23,8 +21,8 @@ def forward(self, embeddings_dict: dict) -> torch.Tensor:
             torch.Tensor: term of regularize
         """
 
-        pos_item_emb = embeddings_dict["pos_item_emb"]
-        neg_item_emb = embeddings_dict["neg_item_emb"]
+        pos_item_emb = embeddings_dict["pos_item_embedding"]
+        neg_item_emb = embeddings_dict["neg_item_embedding"]
 
         B, N, d = neg_item_emb.shape
         Q = B * N
diff --git a/src/PytorchCML/regularizers/L2Regularizer.py b/src/PytorchCML/regularizers/L2Regularizer.py
new file mode 100644
index 0000000..d5412d9
--- /dev/null
+++ b/src/PytorchCML/regularizers/L2Regularizer.py
@@ -0,0 +1,28 @@
+import torch
+
+from .BaseRegularizer import BaseRegularizer
+
+
+class L2Regularizer(BaseRegularizer):
+    """Class of L2 Regularization"""
+
+    def forward(self, embeddings_dict: dict) -> torch.Tensor:
+        """Method of comuting regularize term
+
+        Args:
+            embeddings_dict (dict): dictionary of embeddings which has pos_item_emb and neg_item_emb
+
+        Returns:
+            torch.Tensor: term of regularize
+        """
+
+        user_emb = embeddings_dict["user_embedding"]
+        pos_item_emb = embeddings_dict["pos_item_embedding"]
+        neg_item_emb = embeddings_dict["neg_item_embedding"]
+
+        user_norm = (user_emb ** 2).sum()
+        pos_item_norm = (pos_item_emb ** 2).sum()
+        neg_item_norm = (neg_item_emb ** 2).sum()
+
+        norm = user_norm + pos_item_norm + neg_item_norm
+        return self.weight * norm
diff --git a/src/PytorchCML/regularizers/__init__.py b/src/PytorchCML/regularizers/__init__.py
index 672328a..12d5434 100644
--- a/src/PytorchCML/regularizers/__init__.py
+++ b/src/PytorchCML/regularizers/__init__.py
@@ -1,3 +1,4 @@
 # flake8: noqa
 from .BaseRegularizer import BaseRegularizer
 from .GlobalOrthogonalRegularizer import GlobalOrthogonalRegularizer
+from .L2Regularizer import L2Regularizer
diff --git a/src/PytorchCML/samplers/BaseSampler.py b/src/PytorchCML/samplers/BaseSampler.py
index 43a7cac..a8359ac 100644
--- a/src/PytorchCML/samplers/BaseSampler.py
+++ b/src/PytorchCML/samplers/BaseSampler.py
@@ -20,6 +20,7 @@ def __init__(
         batch_size: int = 256,
         n_neg_samples: int = 10,
         strict_negative: bool = False,
+        neutral: torch.Tensor = torch.Tensor([]),
     ):
         """Class of Base Sampler for get positive and negative batch.
         Args:
@@ -37,15 +38,15 @@ def __init__(
             NotImplementedError: [description]
             NotImplementedError: [description]
         """
-
+        # set positive pairs
         self.train_set = train_set
-        train_set_cpu = train_set.cpu()
-        self.train_matrix = csr_matrix(
-            (np.ones(train_set.shape[0]), (train_set_cpu[:, 0], train_set_cpu[:, 1])),
-            [n_user, n_item],
-        )
+
+        # set some hyperparameters
         self.n_neg_samples = n_neg_samples
         self.batch_size = batch_size
+        self.strict_negative = strict_negative
+        self.two_stage = False
+
         if n_user is None:
             self.n_user = np.unique(train_set[:, 0].cpu()).shape[0]
         else:
@@ -55,13 +56,23 @@ def __init__(
             self.n_item = np.unique(train_set[:, 1].cpu()).shape[0]
         else:
             self.n_item = n_item
-        self.device = device
-        self.strict_negative = strict_negative
-        self.two_stage = False
+
+        # set flag matrix whose element indicates the pair is not negative.
+        train_set_cpu = train_set.cpu()
+        neutral_cpu = neutral.cpu()
+        not_negative = torch.cat([train_set_cpu, neutral_cpu])
+        self.not_negative_flag = csr_matrix(
+            (np.ones(not_negative.shape[0]), (not_negative[:, 0], not_negative[:, 1])),
+            [n_user, n_item],
+        )
+        self.not_negative_flag.sum_duplicates()
+        self.not_negative_flag.data[:] = 1
 
         # device
         if device is None:
-            device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
+            self.device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
+        else:
+            self.device = device
 
         # set pos weight
         if pos_weight is not None:  # weighted
@@ -80,13 +91,13 @@ def __init__(
         else:  # uniform
             pos_weight_pair = torch.ones(train_set.shape[0])
 
-        self.pos_weight_pair = torch.Tensor(pos_weight_pair).to(device)
+        self.pos_weight_pair = torch.Tensor(pos_weight_pair).to(self.device)
         self.pos_sampler = Categorical(probs=self.pos_weight_pair)
 
         # set neg weight
-        if neg_weight is None:  # uniorm
+        if neg_weight is None:  # uniform
             self.negative_weighted_by_model = False
-            self.neg_item_weight = torch.ones(self.n_item).to(device)
+            self.neg_item_weight = torch.ones(self.n_item).to(self.device)
 
         elif isinstance(neg_weight, BaseEmbeddingModel):  # user-item weighted
             self.negative_weighted_by_model = True
@@ -94,7 +105,7 @@ def __init__(
 
         elif len(neg_weight) == self.n_item:  # item weighted
             self.negative_weighted_by_model = False
-            self.neg_item_weight = torch.Tensor(neg_weight).to(device)
+            self.neg_item_weight = torch.Tensor(neg_weight).to(self.device)
 
         else:
             raise NotImplementedError
@@ -120,11 +131,10 @@ def get_neg_batch(self, users: torch.Tensor) -> torch.Tensor:
         """
 
         if self.negative_weighted_by_model and self.strict_negative:
-            pos_item_flag = torch.Tensor(self.train_matrix[users.to("cpu")].A)
-            mask = 1 - pos_item_flag.to(self.device)
+            flag = torch.Tensor(self.not_negative_flag[users.to("cpu")].A)
+            mask = 1 - flag.to(self.device)
             weight = self.neg_weight_model.get_item_weight(users)
             weight *= mask
-
             neg_sampler = Categorical(probs=weight)
             neg_samples = neg_sampler.sample([self.n_neg_samples]).T
 
@@ -134,8 +144,8 @@ def get_neg_batch(self, users: torch.Tensor) -> torch.Tensor:
             neg_samples = neg_sampler.sample([self.n_neg_samples]).T
 
         elif not self.negative_weighted_by_model and self.strict_negative:
-            pos_item_flag = torch.Tensor(self.train_matrix[users.to("cpu")].A)
-            mask = 1 - pos_item_flag.to(self.device)
+            flag = torch.Tensor(self.not_negative_flag[users.to("cpu")].A)
+            mask = 1 - flag.to(self.device)
             weight = mask * self.neg_item_weight
             neg_sampler = Categorical(probs=weight)
             neg_samples = neg_sampler.sample([self.n_neg_samples]).T
diff --git a/src/PytorchCML/samplers/TwoStageSampler.py b/src/PytorchCML/samplers/TwoStageSampler.py
index 6022377..06089be 100644
--- a/src/PytorchCML/samplers/TwoStageSampler.py
+++ b/src/PytorchCML/samplers/TwoStageSampler.py
@@ -111,7 +111,7 @@ def get_neg_batch(self, users: torch.Tensor) -> torch.Tensor:
         """
 
         if self.strict_negative:
-            pos_item_mask = torch.Tensor(self.train_matrix[users.to("cpu")].A)
+            pos_item_mask = torch.Tensor(self.not_negative_flag[users.to("cpu")].A)
             pos_item_mask_candidate = pos_item_mask[:, self.candidates]
             weight = (1 - pos_item_mask_candidate) * self.candidates_weight
             zero_indices = weight.sum(axis=1) <= 1e-10
diff --git a/src/PytorchCML/trainers/BaseTrainer.py b/src/PytorchCML/trainers/BaseTrainer.py
index 1b4330e..0f70467 100644
--- a/src/PytorchCML/trainers/BaseTrainer.py
+++ b/src/PytorchCML/trainers/BaseTrainer.py
@@ -17,6 +17,7 @@ def __init__(
         optimizer: optim,
         criterion: Union[BasePairwiseLoss, BaseTripletLoss],
         sampler: BaseSampler,
+        column_names: Optional[dict] = None,
     ):
         """Set components for learning recommend system.
 
@@ -25,12 +26,18 @@ def __init__(
             optimizer (optim): pytorch optimizer
             criterion (Union[BasePairwiseLoss, BaseTripletLoss]): loss function
             sampler (BaseSampler): sampler
+            column_names (Optional[dict]): sampler
         """
         self.model = model
         self.optimizer = optimizer
         self.criterion = criterion
         self.sampler = sampler
 
+        if column_names is not None:
+            self.column_names = column_names
+        else:
+            self.column_names = {"user_id": 0, "item_id": 1}
+
     def fit(
         self,
         n_batch: int = 500,
diff --git a/src/PytorchCML/trainers/CMLTrainer.py b/src/PytorchCML/trainers/CMLTrainer.py
index 33d40f0..89b5f96 100644
--- a/src/PytorchCML/trainers/CMLTrainer.py
+++ b/src/PytorchCML/trainers/CMLTrainer.py
@@ -33,8 +33,8 @@ def fit(
                 for b in pbar:
                     # batch sampling
                     batch = self.sampler.get_pos_batch()
-                    users = batch[:, 0:1]
-                    pos_items = batch[:, 1:]
+                    users = batch[:, self.column_names["user_id"]].reshape(-1, 1)
+                    pos_items = batch[:, self.column_names["item_id"]].reshape(-1, 1)
 
                     if self.sampler.two_stage:
                         neg_candidates = self.sampler.get_and_set_candidates()
@@ -47,12 +47,10 @@ def fit(
                     self.model.zero_grad()
 
                     # compute distance
-                    user_emb, pos_item_emb, neg_item_emb = self.model(
-                        users, pos_items, neg_items
-                    )
+                    embeddings_dict = self.model(users, pos_items, neg_items)
 
                     # compute loss
-                    loss = self.criterion(user_emb, pos_item_emb, neg_item_emb)
+                    loss = self.criterion(embeddings_dict, batch, self.column_names)
                     accum_loss += loss.item()
 
                     # gradient of loss
diff --git a/src/PytorchCML/trainers/MFTrainer.py b/src/PytorchCML/trainers/MFTrainer.py
index 0128b92..fe321f2 100644
--- a/src/PytorchCML/trainers/MFTrainer.py
+++ b/src/PytorchCML/trainers/MFTrainer.py
@@ -33,20 +33,18 @@ def fit(
                 for b in pbar:
                     # batch sampling
                     batch = self.sampler.get_pos_batch()
-                    users = batch[:, 0]
-                    pos_items = batch[:, 1]
+                    users = batch[:, self.column_names["user_id"]]
+                    pos_items = batch[:, self.column_names["item_id"]]
                     neg_items = self.sampler.get_neg_batch(users)
 
                     # initialize gradient
                     self.model.zero_grad()
 
                     # look up embeddings
-                    u_emb, ip_emb, in_emb, ub, ipb, inb = self.model(
-                        users, pos_items, neg_items
-                    )
+                    embeddings_dict = self.model(users, pos_items, neg_items)
 
                     # compute loss
-                    loss = self.criterion(u_emb, ip_emb, in_emb, ub, ipb, inb)
+                    loss = self.criterion(embeddings_dict, batch, self.column_names)
                     accum_loss += loss.item()
 
                     # gradient of loss


Test patch:
diff --git a/.github/workflows/python-test.yml b/.github/workflows/python-test.yml
new file mode 100644
index 0000000..9f1018a
--- /dev/null
+++ b/.github/workflows/python-test.yml
@@ -0,0 +1,32 @@
+name: Test
+
+on: 
+  push:
+  pull_request:
+
+jobs:
+  build:
+
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        python-version: [3.7, 3.8]
+
+    if: github.repository == 'hand10ryo/PytorchCML'
+
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v2
+
+      - name: Setup Python${{ matrix.python-version }}
+        uses: actions/setup-python@v2
+        with:
+          python-version: ${{ matrix.python-version }}
+
+      - name: Install
+        run: |
+          python -m pip install --upgrade pip
+          pip install poetry
+          poetry install
+          poetry run flake8 --ignore=E501 src/PytorchCML tests
+          poetry run python -m unittest discover -b
diff --git a/tests/losses/test_LogitPairwiseLoss.py b/tests/losses/test_LogitPairwiseLoss.py
index 32f4a64..eeea208 100644
--- a/tests/losses/test_LogitPairwiseLoss.py
+++ b/tests/losses/test_LogitPairwiseLoss.py
@@ -28,20 +28,20 @@ def test_forward(self):
         loss = [[10], [1]]
         avg_loss = 5.5
         """
-        user_emb = torch.ones(3, 5)
-        pos_item_emb = torch.ones(3, 5) * 2
-        neg_item_emb = torch.ones(3, 2, 5)
-
-        user_bias = torch.zeros(3, 1)
-        pos_item_bias = torch.zeros(3, 1) * 2
-        neg_item_bias = torch.zeros(3, 2, 1)
+        embeddings_dict = {
+            "user_embedding": torch.ones(3, 5),
+            "pos_item_embedding": torch.ones(3, 5) * 2,
+            "neg_item_embedding": torch.ones(3, 2, 5),
+            "user_bias": torch.zeros(3, 1),
+            "pos_item_bias": torch.zeros(3, 1) * 2,
+            "neg_item_bias": torch.zeros(3, 2),
+        }
+        batch = torch.ones([3, 2])
+        column_names = {"user_id": 0, "item_id": 1}
 
         # without regularizer
         criterion = LogitPairwiseLoss()
-        loss = criterion(
-            user_emb, pos_item_emb, neg_item_emb,
-            user_bias, pos_item_bias, neg_item_bias
-        ).item()
+        loss = criterion(embeddings_dict, batch, column_names).item()
 
         self.assertGreater(loss, 0)
         self.assertAlmostEqual(loss, 3.3378, places=3)
@@ -49,13 +49,10 @@ def test_forward(self):
         # with regularizer
         regs = [SampleRegularizer()]
         criterion = LogitPairwiseLoss(regularizers=regs)
-        loss = criterion(
-            user_emb, pos_item_emb, neg_item_emb,
-            user_bias, pos_item_bias, neg_item_bias
-        ).item()
+        loss = criterion(embeddings_dict, batch, column_names).item()
         self.assertGreater(loss, 0)
         self.assertAlmostEqual(loss, 6.3378, places=3)
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     unittest.main()
diff --git a/tests/losses/test_MSEPairwiseLoss.py b/tests/losses/test_MSEPairwiseLoss.py
new file mode 100644
index 0000000..f90db62
--- /dev/null
+++ b/tests/losses/test_MSEPairwiseLoss.py
@@ -0,0 +1,59 @@
+import unittest
+
+import torch
+from torch import nn
+
+from PytorchCML.losses import MSEPairwiseLoss
+
+
+class SampleRegularizer(nn.Module):
+    def forward(self, embeding_dict: dict) -> torch.Tensor:
+        return torch.ones(3).sum()
+
+
+class TestMSEPairwiseLoss(unittest.TestCase):
+    """Test LogitPairwiseLoss"""
+
+    def test_forward(self):
+        """
+        test forward
+
+        pos_inner = [[10], [10], [10]]
+        neg_inner = [[-5, -5], [-5, -5], [-5, -5]]
+        pos_bias = [3, 3, 3]
+        neg_bias = [0, 0, 0]
+
+        pos_r_hat = [13, 13, 13]
+        neg_r_hat = [[-5, -5], [-5, -5], [-5, -5]]
+        pos_loss = [-24, -24, -24]
+        neg_loss = [[25, 25], [25, 25], [25, 25]]
+        avg_loss = 26 / 3
+        """
+        embeddings_dict = {
+            "user_embedding": torch.zeros(3, 5),
+            "pos_item_embedding": torch.zeros(3, 5) * 2,
+            "neg_item_embedding": -torch.zeros(3, 2, 5),
+            "user_bias": torch.zeros(3, 1),
+            "pos_item_bias": torch.zeros(3, 1) * 2,
+            "neg_item_bias": -torch.zeros(3, 2),
+        }
+        batch = torch.ones([3, 2])
+        column_names = {"user_id": 0, "item_id": 1}
+
+        # without regularizer
+        criterion = MSEPairwiseLoss()
+        loss = criterion(embeddings_dict, batch, column_names).item()
+
+        self.assertGreater(loss, 0)
+        self.assertAlmostEqual(loss, 0.25, places=3)
+
+        # with regularizer
+        regs = [SampleRegularizer()]
+        criterion = MSEPairwiseLoss(regularizers=regs)
+        loss = criterion(embeddings_dict, batch, column_names).item()
+        self.assertGreater(loss, 0)
+        self.assertAlmostEqual(loss, 3.25, places=3)
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/tests/losses/test_MinTripletLoss.py b/tests/losses/test_MinTripletLoss.py
index b87f846..6e1c85b 100644
--- a/tests/losses/test_MinTripletLoss.py
+++ b/tests/losses/test_MinTripletLoss.py
@@ -18,23 +18,28 @@ def test_forward(self):
         """
         test forward
         """
-        user_emb = torch.ones(3, 1, 5)
-        pos_item_emb = torch.ones(3, 1, 5) * 2
-        neg_item_emb = torch.ones(3, 1, 5)
+        embeddings_dict = {
+            "user_embedding": torch.ones(3, 1, 5),
+            "pos_item_embedding": torch.ones(3, 1, 5) * 2,
+            "neg_item_embedding": torch.ones(3, 1, 5),
+        }
+
+        batch = torch.ones([3, 2])
+        column_names = {"user_id": 0, "item_id": 1}
 
         # without regularizer
         criterion = MinTripletLoss(margin=1)
-        loss = criterion(user_emb, pos_item_emb, neg_item_emb).item()
+        loss = criterion(embeddings_dict, batch, column_names).item()
         self.assertGreater(loss, 0)
         self.assertEqual(loss, 6)
 
         # with regularizer
         regs = [SampleRegularizer()]
         criterion = MinTripletLoss(margin=1, regularizers=regs)
-        loss = criterion(user_emb, pos_item_emb, neg_item_emb).item()
+        loss = criterion(embeddings_dict, batch, column_names).item()
         self.assertGreater(loss, 0)
         self.assertEqual(loss, 9)
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     unittest.main()
diff --git a/tests/losses/test_RelevancePairwiseLoss.py b/tests/losses/test_RelevancePairwiseLoss.py
new file mode 100644
index 0000000..14d1390
--- /dev/null
+++ b/tests/losses/test_RelevancePairwiseLoss.py
@@ -0,0 +1,59 @@
+import unittest
+
+import torch
+from torch import nn
+
+from PytorchCML.losses import RelevancePairwiseLoss
+
+
+class SampleRegularizer(nn.Module):
+    def forward(self, embeding_dict: dict) -> torch.Tensor:
+        return torch.ones(3).sum()
+
+
+class TestRelevancePairwiseLoss(unittest.TestCase):
+    """Test LogitPairwiseLoss"""
+
+    def test_forward(self):
+        """
+        test forward
+
+        pos_inner = [[10], [10], [10]]
+        neg_inner = [[-5, -5], [-5, -5], [-5, -5]]
+        pos_bias = [3, 3, 3]
+        neg_bias = [0, 0, 0]
+
+        pos_r_hat = [13, 13, 13]
+        neg_r_hat = [[-5, -5], [-5, -5], [-5, -5]]
+        pos_loss = [-24, -24, -24]
+        neg_loss = [[25, 25], [25, 25], [25, 25]]
+        avg_loss = 26 / 3
+        """
+        embeddings_dict = {
+            "user_embedding": torch.zeros(3, 5),
+            "pos_item_embedding": torch.zeros(3, 5) * 2,
+            "neg_item_embedding": -torch.zeros(3, 2, 5),
+            "user_bias": torch.zeros(3, 1),
+            "pos_item_bias": torch.zeros(3, 1) * 2,
+            "neg_item_bias": -torch.zeros(3, 2),
+        }
+        batch = torch.ones([3, 3])
+        column_names = {"user_id": 0, "item_id": 1, "pscore": 2}
+
+        # without regularizer
+        criterion = RelevancePairwiseLoss(delta="mse")
+        loss = criterion(embeddings_dict, batch, column_names).item()
+
+        self.assertGreater(loss, 0)
+        self.assertAlmostEqual(loss, 0.5, places=3)
+
+        # with regularizer
+        regs = [SampleRegularizer()]
+        criterion = RelevancePairwiseLoss(regularizers=regs, delta="mse")
+        loss = criterion(embeddings_dict, batch, column_names).item()
+        self.assertGreater(loss, 0)
+        self.assertAlmostEqual(loss, 3.5, places=3)
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/tests/losses/test_SumTripletLoss.py b/tests/losses/test_SumTripletLoss.py
index c0f412c..6afd724 100644
--- a/tests/losses/test_SumTripletLoss.py
+++ b/tests/losses/test_SumTripletLoss.py
@@ -18,23 +18,27 @@ def test_forward(self):
         """
         test forward
         """
-        user_emb = torch.ones(3, 1, 5)
-        pos_item_emb = torch.ones(3, 1, 5) * 2
-        neg_item_emb = torch.ones(3, 1, 5)
+        embeddings_dict = {
+            "user_embedding": torch.ones(3, 1, 5),
+            "pos_item_embedding": torch.ones(3, 1, 5) * 2,
+            "neg_item_embedding": torch.ones(3, 1, 5),
+        }
+        batch = torch.ones([3, 2])
+        column_names = {"user_id": 0, "item_id": 1}
 
         # without regularizer
         criterion = SumTripletLoss(margin=1)
-        loss = criterion(user_emb, pos_item_emb, neg_item_emb).item()
+        loss = criterion(embeddings_dict, batch, column_names).item()
         self.assertGreater(loss, 0)
         self.assertEqual(loss, 6)
 
         # with regularizer
         regs = [SampleRegularizer()]
         criterion = SumTripletLoss(margin=1, regularizers=regs)
-        loss = criterion(user_emb, pos_item_emb, neg_item_emb).item()
+        loss = criterion(embeddings_dict, batch, column_names).item()
         self.assertGreater(loss, 0)
         self.assertEqual(loss, 9)
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     unittest.main()
diff --git a/tests/models/test_CollaborativeMetricLearning.py b/tests/models/test_CollaborativeMetricLearning.py
index ae9bd17..2736e6f 100644
--- a/tests/models/test_CollaborativeMetricLearning.py
+++ b/tests/models/test_CollaborativeMetricLearning.py
@@ -6,38 +6,41 @@
 
 
 class TestCollaborativeMetricLearning(unittest.TestCase):
-
     def test_forward(self):
         users = torch.LongTensor([[0], [1]])
         pos_items = torch.LongTensor([[2], [3]])
         neg_items = torch.LongTensor([[1, 3, 4], [0, 1, 2]])
 
         model = CollaborativeMetricLearning(
-            n_user=3, n_item=5, n_dim=10,
+            n_user=3,
+            n_item=5,
+            n_dim=10,
         )
 
-        user_emb, pos_item_emb, neg_item_emb = model(
-            users, pos_items, neg_items
-        )
+        embedding_dict = model(users, pos_items, neg_items)
+
+        user_embedding = embedding_dict["user_embedding"]
+        pos_item_embedding = embedding_dict["pos_item_embedding"]
+        neg_item_embedding = embedding_dict["neg_item_embedding"]
 
         # user_emb shape
-        shape = user_emb.shape
+        shape = user_embedding.shape
         self.assertEqual(shape, (2, 1, 10))
 
         # pos_item_emb shape
-        shape = pos_item_emb.shape
+        shape = pos_item_embedding.shape
         self.assertEqual(shape, (2, 1, 10))
 
         # item_emb shape
-        shape = neg_item_emb.shape
+        shape = neg_item_embedding.shape
         self.assertEqual(shape, (2, 3, 10))
 
     def test_predict(self):
-        user_item_pairs = torch.LongTensor([
-            [0, 0], [1, 1], [2, 2]
-        ])
+        user_item_pairs = torch.LongTensor([[0, 0], [1, 1], [2, 2]])
         model = CollaborativeMetricLearning(
-            n_user=3, n_item=5, n_dim=10,
+            n_user=3,
+            n_item=5,
+            n_dim=10,
         )
 
         y_hat = model.predict(user_item_pairs)
@@ -51,7 +54,9 @@ def test_spreadout_distance(self):
         neg_items = torch.LongTensor([0, 1, 4])
 
         model = CollaborativeMetricLearning(
-            n_user=3, n_item=5, n_dim=10,
+            n_user=3,
+            n_item=5,
+            n_dim=10,
         )
 
         so_dist = model.spreadout_distance(pos_items, neg_items)
diff --git a/tests/models/test_MatrixFactorization.py b/tests/models/test_MatrixFactorization.py
index ec8776e..67aca90 100644
--- a/tests/models/test_MatrixFactorization.py
+++ b/tests/models/test_MatrixFactorization.py
@@ -17,31 +17,38 @@ def test_forward(self):
             n_dim=10,
         )
 
-        u_emb, ip_emb, in_emb, ub, ipb, inb = model(users, pos_items, neg_items)
+        embeddings_dict = model(users, pos_items, neg_items)
+
+        user_embedding = embeddings_dict["user_embedding"]
+        pos_item_embedding = embeddings_dict["pos_item_embedding"]
+        neg_item_embedding = embeddings_dict["neg_item_embedding"]
+        user_bias = embeddings_dict["user_bias"]
+        pos_item_bias = embeddings_dict["pos_item_bias"]
+        neg_item_bias = embeddings_dict["neg_item_bias"]
 
         # user_emb shape
-        shape = u_emb.shape
+        shape = user_embedding.shape
         self.assertEqual(shape, (2, 10))
 
         # pos_item_emb shape
-        shape = ip_emb.shape
+        shape = pos_item_embedding.shape
         self.assertEqual(shape, (2, 10))
 
         # neg_item_emb shape
-        shape = in_emb.shape
+        shape = neg_item_embedding.shape
         self.assertEqual(shape, (2, 3, 10))
 
         # user_bias shape
-        shape = ub.shape
+        shape = user_bias.shape
         self.assertEqual(shape, (2, 1))
 
         # pos_item_bias shape
-        shape = ipb.shape
+        shape = pos_item_bias.shape
         self.assertEqual(shape, (2, 1))
 
         # neg_item_bias shape
-        shape = inb.shape
-        self.assertEqual(shape, (2, 3, 1))
+        shape = neg_item_bias.shape
+        self.assertEqual(shape, (2, 3))
 
     def test_predict(self):
         user_item_pairs = torch.LongTensor([[0, 0], [1, 1], [2, 2]])
diff --git a/tests/regularizers/test_GlobalOrthogonalRegularizer.py b/tests/regularizers/test_GlobalOrthogonalRegularizer.py
index 9044ca5..26bfa8b 100644
--- a/tests/regularizers/test_GlobalOrthogonalRegularizer.py
+++ b/tests/regularizers/test_GlobalOrthogonalRegularizer.py
@@ -6,15 +6,15 @@
 
 
 class TestGlobalOrthogonalRegularizer(unittest.TestCase):
-    """ Test for Global Orthogonal Regularizer"""
+    """Test for Global Orthogonal Regularizer"""
 
     def test_forward(self):
         """
         test forward
         """
         embeddings_dict = {
-            "pos_item_emb": torch.ones(2, 1, 5),
-            "neg_item_emb": torch.ones(2, 3, 5)
+            "pos_item_embedding": torch.ones(2, 1, 5),
+            "neg_item_embedding": torch.ones(2, 3, 5),
         }
 
         regularizer = GlobalOrthogonalRegularizer(weight=1)
@@ -24,5 +24,5 @@ def test_forward(self):
         self.assertAlmostEqual(reg, 49.8, places=2)
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     unittest.main()
diff --git a/tests/regularizers/test_L2Regularizer.py b/tests/regularizers/test_L2Regularizer.py
new file mode 100644
index 0000000..33bd2aa
--- /dev/null
+++ b/tests/regularizers/test_L2Regularizer.py
@@ -0,0 +1,29 @@
+import unittest
+
+import torch
+
+from PytorchCML.regularizers import L2Regularizer
+
+
+class TestL2Regularizer(unittest.TestCase):
+    """Test for Global Orthogonal Regularizer"""
+
+    def test_forward(self):
+        """
+        test forward
+        """
+        embeddings_dict = {
+            "user_embedding": torch.ones(2, 1, 5),
+            "pos_item_embedding": torch.ones(2, 1, 5),
+            "neg_item_embedding": torch.ones(2, 3, 5),
+        }
+
+        regularizer = L2Regularizer(weight=1)
+
+        reg = regularizer(embeddings_dict).item()
+
+        self.assertEqual(reg, 50)
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/tests/samplers/test_TwoStageSampler.py b/tests/samplers/test_TwoStageSampler.py
index 17f6f71..54fef51 100644
--- a/tests/samplers/test_TwoStageSampler.py
+++ b/tests/samplers/test_TwoStageSampler.py
@@ -85,10 +85,10 @@ def test_get_neg_batch(self):
         sampler = TwoStageSampler(
             train_set,
             n_user=3,
-            n_item=5,
+            n_item=15,
             batch_size=3,
             n_neg_samples=2,
-            n_neg_candidates=3,
+            n_neg_candidates=5,
             strict_negative=True,
         )
         pos_batch = sampler.get_pos_batch()
@@ -96,7 +96,7 @@ def test_get_neg_batch(self):
 
         # two stage
         sampler.get_and_set_candidates()
-        dist = torch.ones(3, 3)
+        dist = torch.ones(3, 5)
         sampler.set_candidates_weight(dist, 3)
         neg_batch = sampler.get_neg_batch(users.reshape(-1))
 
@@ -109,7 +109,7 @@ def test_get_neg_batch(self):
         item_id_min = neg_batch.min().item()
         item_id_max = neg_batch.max().item()
         self.assertGreaterEqual(item_id_min, 0)
-        self.assertGreaterEqual(5, item_id_max)
+        self.assertGreaterEqual(15, item_id_max)
 
         # strict negative
         for k, u in enumerate(users):