diff --git a/.github/workflows/ligthtwood.yml b/.github/workflows/ligthtwood.yml index 5b6927079..338319167 100644 --- a/.github/workflows/ligthtwood.yml +++ b/.github/workflows/ligthtwood.yml @@ -13,12 +13,8 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, windows-latest] + os: [ubuntu-latest] python-version: [3.7,3.8,3.9] - exclude: - # exclude combination due to #849 - - os: windows-latest - python-version: 3.9 steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} diff --git a/.gitignore b/.gitignore index 6c7431ab3..c49102985 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,7 @@ test.pickle AI.json AI2.json +# docs assert.sh docssrc/build docssrc/build/* @@ -67,3 +68,4 @@ docs docs/* *.zip docs/* +.ipynb_checkpoints \ No newline at end of file diff --git a/README.md b/README.md index 37cd8a0f2..de6db694f 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,7 @@ pip3 install lightwood However, we recommend creating a python virtual environment. #### Setting up a dev environment - +- Python version should be in the range >=3.7, < 3.10 - Clone lightwood - `cd lightwood && pip install -r requirements.txt && pip install -r requirements_image.txt` - Add it to your python path (e.g. by adding `export PYTHONPATH='/where/you/cloned/lightwood':$PYTHONPATH` as a newline at the end of your `~/.bashrc` file) diff --git a/docssrc/source/tutorials/custom_explainer/custom_explainer.ipynb b/docssrc/source/tutorials/custom_explainer/custom_explainer.ipynb index c37b01701..328502809 100644 --- a/docssrc/source/tutorials/custom_explainer/custom_explainer.ipynb +++ b/docssrc/source/tutorials/custom_explainer/custom_explainer.ipynb @@ -27,7 +27,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": { "execution": { "iopub.execute_input": "2022-02-03T21:29:56.978393Z", @@ -36,24 +36,12 @@ "shell.execute_reply": "2022-02-03T21:29:58.457729Z" } }, - "outputs": [ - { - "data": { - "text/plain": [ - "'22.2.1.0'" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "from typing import Dict, Tuple\n", "import pandas as pd\n", "import lightwood\n", - "lightwood.__version__\n", - "\n" + "lightwood.__version__" ] }, { @@ -71,7 +59,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": { "execution": { "iopub.execute_input": "2022-02-03T21:29:58.461457Z", @@ -100,7 +88,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": { "execution": { "iopub.execute_input": "2022-02-03T21:29:58.588212Z", @@ -109,18 +97,7 @@ "shell.execute_reply": "2022-02-03T21:29:58.589754Z" } }, - "outputs": [ - { - "data": { - "text/plain": [ - "<__main__.ModelCorrelationHeatmap at 0x7f843b004ac0>" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "ModelCorrelationHeatmap()" ] @@ -136,7 +113,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": { "execution": { "iopub.execute_input": "2022-02-03T21:29:58.592434Z", @@ -168,7 +145,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": { "execution": { "iopub.execute_input": "2022-02-03T21:29:58.596282Z", @@ -214,7 +191,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": { "execution": { "iopub.execute_input": "2022-02-03T21:29:58.600174Z", @@ -223,15 +200,7 @@ "shell.execute_reply": "2022-02-03T21:29:58.601837Z" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Overwriting model_correlation.py\n" - ] - } - ], + "outputs": [], "source": [ "%%writefile model_correlation.py\n", "\n", @@ -258,9 +227,9 @@ " all_predictions = []\n", "\n", " for mixer in ns.predictor.mixers:\n", - " predictions = mixer(ns.encoded_val_data).values # retrieve np.ndarray from the returned pd.DataFrame\n", + " predictions = mixer(ns.encoded_val_data)['prediction'].values # retrieve np.ndarray from the returned pd.DataFrame\n", " all_predictions.append(predictions.flatten().astype(int)) # flatten and cast labels to int\n", - " \n", + "\n", " # calculate correlation matrix\n", " corrs = np.corrcoef(np.array(all_predictions))\n", " \n", @@ -311,7 +280,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": { "execution": { "iopub.execute_input": "2022-02-03T21:29:58.604529Z", @@ -320,34 +289,7 @@ "shell.execute_reply": "2022-02-03T21:29:59.210964Z" } }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001B[32mINFO:lightwood-1461893:Dropping features: []\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Analyzing a sample of 222\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:from a total population of 225, this is equivalent to 98.7% of your data.\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Using 7 processes to deduct types.\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Infering type for: Population\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Infering type for: Area (sq. mi.)\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Infering type for: Pop. Density \u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Infering type for: GDP ($ per capita)\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Infering type for: Infant mortality \u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Infering type for: Literacy (%)\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Infering type for: Development Index\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Column Population has data type integer\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Column Area (sq. mi.) has data type integer\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Column GDP ($ per capita) has data type integer\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Column Development Index has data type categorical\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Column Pop. Density has data type float\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Column Literacy (%) has data type float\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Column Infant mortality has data type float\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Starting statistical analysis\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Finished statistical analysis\u001B[0m\n" - ] - } - ], + "outputs": [], "source": [ "from lightwood.api.high_level import ProblemDefinition, json_ai_from_problem, load_custom_module\n", "\n", @@ -382,7 +324,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": { "execution": { "iopub.execute_input": "2022-02-03T21:29:59.213815Z", @@ -391,18 +333,7 @@ "shell.execute_reply": "2022-02-03T21:29:59.214910Z" } }, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'module': 'model_correlation.ModelCorrelationHeatmap', 'args': {}}]" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "json_ai.analysis_blocks" ] @@ -416,7 +347,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": { "execution": { "iopub.execute_input": "2022-02-03T21:29:59.218326Z", @@ -426,1239 +357,7 @@ }, "scrolled": false }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001B[32mINFO:lightwood-1461893:Dropping features: []\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Performing statistical analysis on data\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Starting statistical analysis\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Finished statistical analysis\u001B[0m\n", - "\u001B[37mDEBUG:lightwood-1461893: `analyze_data` runtime: 0.01 seconds\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Cleaning the data\u001B[0m\n", - "\u001B[37mDEBUG:lightwood-1461893: `preprocess` runtime: 0.0 seconds\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Splitting the data into train/test\u001B[0m\n", - "\u001B[37mDEBUG:lightwood-1461893: `split` runtime: 0.01 seconds\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Preparing the encoders\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Encoder prepping dict length of: 1\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Encoder prepping dict length of: 2\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Encoder prepping dict length of: 3\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Encoder prepping dict length of: 4\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Encoder prepping dict length of: 5\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Encoder prepping dict length of: 6\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Encoder prepping dict length of: 7\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Encoding UNKNOWN categories as index 0\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Done running for: Development Index\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Done running for: Population\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Done running for: Area (sq. mi.)\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Done running for: Pop. Density \u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Done running for: GDP ($ per capita)\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Done running for: Literacy (%)\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Done running for: Infant mortality \u001B[0m\n", - "\u001B[37mDEBUG:lightwood-1461893: `prepare` runtime: 0.14 seconds\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Featurizing the data\u001B[0m\n", - "\u001B[37mDEBUG:lightwood-1461893: `featurize` runtime: 0.0 seconds\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Training the mixers\u001B[0m\n", - "Found `num_iterations` in params. Will use it instead of argument\n", - "[LightGBM] [Fatal] GPU Tree Learner was not enabled in this build.\n", - "Please recompile with CMake option -DUSE_GPU=1\n", - "\u001B[33mWARNING:lightwood-1461893:LightGBM running on CPU, this somewhat slower than the GPU version, consider using a GPU instead\u001B[0m\n", - "torch.cuda.amp.GradScaler is enabled, but CUDA is not available. Disabling.\n", - "This overload of addcmul_ is deprecated:\n", - "\taddcmul_(Number value, Tensor tensor1, Tensor tensor2)\n", - "Consider using one of the following signatures instead:\n", - "\taddcmul_(Tensor tensor1, Tensor tensor2, *, Number value) (Triggered internally at ../torch/csrc/utils/python_arg_parser.cpp:1025.)\n", - "\u001B[32mINFO:lightwood-1461893:Loss of 2.2819135189056396 with learning rate 0.0001\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss of 2.268077850341797 with learning rate 0.00014\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss of 2.22404408454895 with learning rate 0.00019599999999999997\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss of 1.7930375337600708 with learning rate 0.00027439999999999995\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss of 2.3550074100494385 with learning rate 0.0003841599999999999\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Found learning rate of: 0.00027439999999999995\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1: 1.8338333368301392\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 2: 1.9395915269851685\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 3: 1.9169485569000244\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 4: 1.8937150239944458\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 5: 1.8695253133773804\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 6: 1.8448940515518188\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 7: 1.7847260236740112\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 8: 1.7597827911376953\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 9: 1.7362204790115356\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 10: 1.7141255140304565\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 11: 1.6933625936508179\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 12: 1.6740318536758423\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 13: 1.631773829460144\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 14: 1.616595983505249\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 15: 1.6023756265640259\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 16: 1.5890617370605469\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 17: 1.5764198303222656\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 18: 1.5641610622406006\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 19: 1.5355865955352783\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 20: 1.5242055654525757\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 21: 1.5129410028457642\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 22: 1.5019261837005615\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 23: 1.4911009073257446\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 24: 1.4801453351974487\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 25: 1.4535717964172363\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 26: 1.4430298805236816\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 27: 1.4326012134552002\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 28: 1.4224668741226196\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 29: 1.4125335216522217\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 30: 1.4025007486343384\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 31: 1.3782844543457031\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 32: 1.36880362033844\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 33: 1.3593981266021729\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 34: 1.3502670526504517\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 35: 1.341304898262024\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 36: 1.332236886024475\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 37: 1.3104350566864014\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 38: 1.301945686340332\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 39: 1.2935556173324585\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 40: 1.2854573726654053\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 41: 1.2775602340698242\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 42: 1.269580602645874\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 43: 1.2506139278411865\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 44: 1.243348240852356\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 45: 1.2362173795700073\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 46: 1.2293823957443237\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 47: 1.2227638959884644\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 48: 1.2160584926605225\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 49: 1.2002323865890503\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 50: 1.1941956281661987\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 51: 1.18826425075531\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 52: 1.1825474500656128\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 53: 1.1769970655441284\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 54: 1.1713104248046875\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 55: 1.1578630208969116\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 56: 1.1526927947998047\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 57: 1.1476008892059326\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 58: 1.142682671546936\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 59: 1.13791823387146\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 60: 1.1329776048660278\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 61: 1.1212589740753174\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 62: 1.116713285446167\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 63: 1.112216830253601\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 64: 1.10784912109375\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 65: 1.1036131381988525\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 66: 1.099169373512268\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 67: 1.0885926485061646\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 68: 1.0844480991363525\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 69: 1.0803428888320923\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 70: 1.0763429403305054\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 71: 1.072467565536499\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 72: 1.0683684349060059\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 73: 1.0586200952529907\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 74: 1.0547847747802734\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 75: 1.0509812831878662\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 76: 1.0472744703292847\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 77: 1.0436888933181763\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 78: 1.0398770570755005\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 79: 1.0308085680007935\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 80: 1.0272282361984253\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 81: 1.0236786603927612\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 82: 1.0202242136001587\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 83: 1.0168994665145874\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 84: 1.0133183002471924\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 85: 1.0047935247421265\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 86: 1.0014185905456543\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 87: 0.9980719685554504\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 88: 0.9948108196258545\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 89: 0.9916836023330688\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 90: 0.9882921576499939\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 91: 0.9802190661430359\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 92: 0.9770156145095825\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 93: 0.9738380908966064\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 94: 0.9707424640655518\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 95: 0.9677847623825073\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 96: 0.9645572900772095\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 97: 0.9569083452224731\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 98: 0.953863799571991\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 99: 0.9508479237556458\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 100: 0.9479116201400757\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 101: 0.9451221227645874\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 102: 0.9420557618141174\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 103: 0.9347625374794006\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 104: 0.9318514466285706\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 105: 0.928968071937561\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 106: 0.9261630177497864\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 107: 0.92351233959198\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 108: 0.9205790162086487\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 109: 0.9136191010475159\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 110: 0.910860538482666\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 111: 0.9081340432167053\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 112: 0.9054849743843079\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 113: 0.9029995799064636\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 114: 0.9002260565757751\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 115: 0.8936280608177185\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 116: 0.8909881711006165\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 117: 0.8883813619613647\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 118: 0.8858553767204285\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 119: 0.8835001587867737\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 120: 0.8808586597442627\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 121: 0.8745760321617126\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 122: 0.8720563650131226\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 123: 0.8695646524429321\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 124: 0.8671509027481079\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 125: 0.8649153709411621\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 126: 0.8623830676078796\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 127: 0.8563555479049683\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 128: 0.8539318442344666\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 129: 0.8515380620956421\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 130: 0.849219560623169\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 131: 0.8470826745033264\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 132: 0.8446440100669861\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 133: 0.8388401865959167\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 134: 0.8364961743354797\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 135: 0.8341687321662903\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 136: 0.8319140672683716\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 137: 0.8298398852348328\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 138: 0.8274626731872559\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 139: 0.8217913508415222\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 140: 0.8195037841796875\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 141: 0.8172513842582703\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 142: 0.8150756359100342\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 143: 0.8130950331687927\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 144: 0.8108086585998535\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 145: 0.8053433299064636\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 146: 0.8031230568885803\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 147: 0.8009352087974548\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 148: 0.798825740814209\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 149: 0.7969179749488831\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 150: 0.794705867767334\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 151: 0.7893958687782288\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 152: 0.7872318625450134\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 153: 0.7850971817970276\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 154: 0.7830415964126587\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 155: 0.7811943292617798\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 156: 0.7790358066558838\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 157: 0.7738635540008545\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 158: 0.771756649017334\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 159: 0.7696824073791504\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 160: 0.7676904201507568\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 161: 0.7659105062484741\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 162: 0.763818621635437\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 163: 0.7588074803352356\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 164: 0.7567644119262695\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 165: 0.7547508478164673\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 166: 0.7528188824653625\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 167: 0.7511032223701477\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 168: 0.7490713596343994\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 169: 0.7442002892494202\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 170: 0.7422056198120117\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 171: 0.7402477264404297\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 172: 0.7383759021759033\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 173: 0.7367259860038757\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 174: 0.7347584366798401\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 175: 0.7300329804420471\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 176: 0.7280873656272888\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 177: 0.7261724472045898\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 178: 0.7243432998657227\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 179: 0.7227376103401184\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 180: 0.7208091616630554\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 181: 0.7161564826965332\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 182: 0.7142320871353149\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 183: 0.7123438715934753\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 184: 0.7105301022529602\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 185: 0.708946704864502\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 186: 0.7070412635803223\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 187: 0.7024452686309814\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 188: 0.7005430459976196\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 189: 0.6986752152442932\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 190: 0.6969003081321716\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 191: 0.6953524947166443\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 192: 0.6934759616851807\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 193: 0.6889737248420715\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 194: 0.687127947807312\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 195: 0.6853359341621399\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 196: 0.6836408972740173\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 197: 0.6821860671043396\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 198: 0.6804044842720032\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 199: 0.6761069893836975\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 200: 0.6743407845497131\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 201: 0.6726113557815552\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 202: 0.6709752082824707\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 203: 0.6695716381072998\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 204: 0.667853832244873\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 205: 0.6637123227119446\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 206: 0.6619883179664612\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 207: 0.6603102684020996\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 208: 0.6587331891059875\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 209: 0.6573932766914368\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 210: 0.6557155847549438\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 211: 0.6516335606575012\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 212: 0.6499212384223938\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 213: 0.648264467716217\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 214: 0.6467220187187195\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 215: 0.6454134583473206\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 216: 0.6437739729881287\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 217: 0.639792263507843\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 218: 0.6381191611289978\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 219: 0.6364969611167908\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 220: 0.6349802613258362\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 221: 0.633699357509613\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 222: 0.6320872902870178\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 223: 0.6281729936599731\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 224: 0.6265391111373901\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 225: 0.6249567866325378\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 226: 0.6234967112541199\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 227: 0.6222765445709229\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 228: 0.6207269430160522\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 229: 0.6170167326927185\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 230: 0.6154746413230896\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 231: 0.6139800548553467\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 232: 0.6126092076301575\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 233: 0.6114787459373474\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 234: 0.6100220084190369\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 235: 0.6064784526824951\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 236: 0.6049811840057373\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 237: 0.6035362482070923\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 238: 0.6022167801856995\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 239: 0.601138174533844\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 240: 0.5997297167778015\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 241: 0.5962938070297241\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 242: 0.5948314666748047\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 243: 0.5934163928031921\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 244: 0.5921292304992676\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 245: 0.591080367565155\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 246: 0.5897043943405151\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 247: 0.586400032043457\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 248: 0.5849910974502563\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 249: 0.5836279988288879\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 250: 0.5823928117752075\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 251: 0.5813853144645691\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 252: 0.5800496339797974\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 253: 0.5767829418182373\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 254: 0.5753887891769409\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 255: 0.574046790599823\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 256: 0.5728410482406616\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 257: 0.571871817111969\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 258: 0.5705804824829102\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 259: 0.567415177822113\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 260: 0.5660616755485535\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 261: 0.5647613406181335\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 262: 0.5635982751846313\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 263: 0.5626671314239502\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 264: 0.5614020824432373\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 265: 0.5582969188690186\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 266: 0.5569714307785034\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 267: 0.5556975603103638\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 268: 0.5545613765716553\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 269: 0.5536586046218872\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 270: 0.5524224042892456\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 271: 0.5493914484977722\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 272: 0.5480868816375732\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 273: 0.5468233227729797\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 274: 0.5456934571266174\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 275: 0.5447929501533508\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 276: 0.5435578227043152\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 277: 0.5405210256576538\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 278: 0.5392289757728577\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 279: 0.5379900336265564\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 280: 0.5368919372558594\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 281: 0.5360122919082642\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 282: 0.5347909927368164\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 283: 0.5317804217338562\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 284: 0.5304879546165466\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 285: 0.5292532444000244\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 286: 0.5281680226325989\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 287: 0.5273048877716064\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 288: 0.5261095762252808\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 289: 0.5231714844703674\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 290: 0.5219141244888306\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 291: 0.5207135081291199\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 292: 0.5196645855903625\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 293: 0.518822431564331\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 294: 0.5176379680633545\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 295: 0.5147155523300171\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 296: 0.5134611129760742\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 297: 0.5122632384300232\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 298: 0.5112261176109314\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 299: 0.5103998780250549\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 300: 0.5092394351959229\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 301: 0.5063633918762207\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 302: 0.5051233172416687\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 303: 0.5039353370666504\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 304: 0.5029172301292419\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 305: 0.5021111965179443\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 306: 0.5009733438491821\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 307: 0.4981614649295807\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 308: 0.49695077538490295\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 309: 0.4957936406135559\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 310: 0.4947971701622009\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 311: 0.49400997161865234\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 312: 0.49289336800575256\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 313: 0.49011069536209106\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 314: 0.48890557885169983\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 315: 0.4877563714981079\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 316: 0.48678499460220337\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 317: 0.48601311445236206\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 318: 0.48491594195365906\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 319: 0.48219168186187744\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 320: 0.48100483417510986\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 321: 0.47987303137779236\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 322: 0.47891053557395935\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 323: 0.47815173864364624\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 324: 0.4770640730857849\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 325: 0.4743644893169403\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 326: 0.4732031226158142\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 327: 0.4720972180366516\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 328: 0.4711661636829376\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 329: 0.47042927145957947\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 330: 0.4693703353404999\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 331: 0.4667303264141083\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 332: 0.46558627486228943\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 333: 0.46449828147888184\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 334: 0.4635781943798065\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 335: 0.46284234523773193\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 336: 0.4617835283279419\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 337: 0.45913901925086975\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 338: 0.45799291133880615\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 339: 0.4569064974784851\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 340: 0.455995112657547\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 341: 0.45527076721191406\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 342: 0.45423007011413574\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 343: 0.4516131579875946\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 344: 0.45047155022621155\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 345: 0.44938918948173523\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 346: 0.44849085807800293\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 347: 0.4477691352367401\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 348: 0.44672891497612\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 349: 0.44410666823387146\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 350: 0.4429699182510376\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 351: 0.441884309053421\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 352: 0.4409779906272888\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 353: 0.44024091958999634\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 354: 0.4391857981681824\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 355: 0.436526358127594\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 356: 0.4353821277618408\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 357: 0.43430009484291077\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 358: 0.4333982765674591\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 359: 0.43265873193740845\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 360: 0.4316176474094391\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 361: 0.42900213599205017\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 362: 0.4278666079044342\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 363: 0.4267772138118744\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 364: 0.4258674681186676\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 365: 0.42510733008384705\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 366: 0.42403706908226013\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 367: 0.4213135838508606\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 368: 0.42014428973197937\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 369: 0.41904160380363464\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 370: 0.4181329309940338\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 371: 0.41738998889923096\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 372: 0.4163818955421448\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 373: 0.41390174627304077\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 374: 0.4128665030002594\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 375: 0.4119027554988861\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 376: 0.41114166378974915\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 377: 0.4105287492275238\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 378: 0.40962955355644226\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 379: 0.40734925866127014\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 380: 0.4063819646835327\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 381: 0.4054622948169708\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 382: 0.4047529697418213\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 383: 0.40418311953544617\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 384: 0.4033387005329132\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 385: 0.4011895954608917\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 386: 0.4002435505390167\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 387: 0.3993578255176544\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 388: 0.39867761731147766\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 389: 0.3981267213821411\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 390: 0.39729800820350647\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 391: 0.39517995715141296\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 392: 0.3942534029483795\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 393: 0.3933902084827423\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 394: 0.39273905754089355\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 395: 0.39221009612083435\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 396: 0.39140641689300537\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 397: 0.3893398642539978\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 398: 0.3884323835372925\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 399: 0.38758882880210876\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 400: 0.3869537115097046\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 401: 0.3864305317401886\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 402: 0.3856410086154938\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 403: 0.38360345363616943\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 404: 0.3827012777328491\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 405: 0.38186633586883545\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 406: 0.38126087188720703\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 407: 0.38075798749923706\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 408: 0.379998117685318\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 409: 0.3780278265476227\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 410: 0.3771553039550781\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 411: 0.3763350248336792\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 412: 0.37574049830436707\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 413: 0.3752466142177582\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 414: 0.37449485063552856\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 415: 0.3725511133670807\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 416: 0.3717007040977478\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 417: 0.37091025710105896\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 418: 0.37033823132514954\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 419: 0.3698543906211853\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 420: 0.36912497878074646\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 421: 0.3672463595867157\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 422: 0.36642131209373474\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 423: 0.3656456470489502\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 424: 0.3651010990142822\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 425: 0.36463841795921326\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 426: 0.363930344581604\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 427: 0.3620816469192505\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 428: 0.3612810969352722\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 429: 0.3605451285839081\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 430: 0.36003461480140686\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 431: 0.3595955967903137\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 432: 0.3589223325252533\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 433: 0.3571457266807556\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 434: 0.3563517928123474\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 435: 0.35562843084335327\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 436: 0.35512831807136536\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 437: 0.35469377040863037\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 438: 0.3540286719799042\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 439: 0.35227662324905396\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 440: 0.35150671005249023\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 441: 0.35079672932624817\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 442: 0.3503190875053406\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 443: 0.34989503026008606\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 444: 0.3492524027824402\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 445: 0.3475427031517029\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 446: 0.346789687871933\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 447: 0.34609442949295044\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 448: 0.34562936425209045\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 449: 0.34521985054016113\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 450: 0.3445984125137329\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 451: 0.34293556213378906\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 452: 0.34220272302627563\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 453: 0.3415302038192749\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 454: 0.34108519554138184\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 455: 0.3406863808631897\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 456: 0.34007930755615234\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 457: 0.3384312689304352\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 458: 0.33769693970680237\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 459: 0.33702585101127625\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 460: 0.3365905284881592\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 461: 0.33619314432144165\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 462: 0.3356013298034668\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 463: 0.33399906754493713\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 464: 0.3332943022251129\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 465: 0.3326497972011566\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 466: 0.3322427272796631\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 467: 0.331872820854187\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 468: 0.3313133716583252\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 469: 0.32978707551956177\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 470: 0.3290964961051941\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 471: 0.3284754157066345\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 472: 0.32808029651641846\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 473: 0.32771772146224976\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 474: 0.32716211676597595\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 475: 0.32564061880111694\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 476: 0.32496336102485657\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 477: 0.32434797286987305\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 478: 0.3239690065383911\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 479: 0.32359933853149414\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 480: 0.323053240776062\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 481: 0.3215439021587372\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 482: 0.3208783268928528\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 483: 0.32027313113212585\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 484: 0.31989654898643494\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 485: 0.3195171356201172\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 486: 0.3189708888530731\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 487: 0.31745874881744385\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 488: 0.31680265069007874\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 489: 0.3161991238594055\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 490: 0.3158281147480011\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 491: 0.3154621720314026\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 492: 0.31493350863456726\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 493: 0.31347063183784485\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 494: 0.31283146142959595\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 495: 0.312252938747406\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 496: 0.31190091371536255\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 497: 0.31154853105545044\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 498: 0.31104403734207153\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 499: 0.3096459209918976\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 500: 0.30903875827789307\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 501: 0.3084825873374939\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 502: 0.3081479072570801\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 503: 0.30780744552612305\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 504: 0.3073202669620514\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 505: 0.3059472441673279\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 506: 0.3053436875343323\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 507: 0.3047831058502197\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 508: 0.3044544756412506\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 509: 0.3041086792945862\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 510: 0.30362385511398315\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 511: 0.3022516667842865\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 512: 0.3016551733016968\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 513: 0.30110564827919006\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 514: 0.3007824718952179\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 515: 0.30042871832847595\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 516: 0.2999516725540161\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 517: 0.29858359694480896\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 518: 0.29798951745033264\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 519: 0.297433078289032\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 520: 0.29710978269577026\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 521: 0.296753853559494\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 522: 0.29628342390060425\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 523: 0.29493027925491333\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 524: 0.2943408489227295\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 525: 0.29380011558532715\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 526: 0.29348886013031006\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 527: 0.29313695430755615\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 528: 0.2926903963088989\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 529: 0.29138824343681335\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 530: 0.2908226549625397\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 531: 0.29030686616897583\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 532: 0.29001614451408386\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 533: 0.2896750867366791\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 534: 0.28923287987709045\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 535: 0.28791752457618713\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 536: 0.2873419523239136\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 537: 0.2868233621120453\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 538: 0.28653883934020996\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 539: 0.2862088680267334\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 540: 0.28579282760620117\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 541: 0.2845540940761566\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 542: 0.2840175926685333\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 543: 0.2835312485694885\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 544: 0.2832719683647156\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 545: 0.28295594453811646\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 546: 0.2825598418712616\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 547: 0.28135454654693604\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 548: 0.28081971406936646\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 549: 0.2803439199924469\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 550: 0.28009751439094543\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 551: 0.27977731823921204\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 552: 0.2793891727924347\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 553: 0.2781972587108612\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 554: 0.2776801288127899\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 555: 0.27721041440963745\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 556: 0.2769736647605896\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 557: 0.27666282653808594\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 558: 0.2762891948223114\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 559: 0.275117963552475\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 560: 0.27458617091178894\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 561: 0.2741158902645111\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 562: 0.273881196975708\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 563: 0.2735636830329895\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 564: 0.2731941342353821\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 565: 0.2720281779766083\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 566: 0.27150797843933105\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 567: 0.2710443139076233\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 568: 0.2708125114440918\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 569: 0.27049899101257324\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 570: 0.27014294266700745\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 571: 0.269002228975296\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 572: 0.26849037408828735\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 573: 0.26802727580070496\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 574: 0.26780617237091064\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 575: 0.26748645305633545\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 576: 0.26713329553604126\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 577: 0.26599934697151184\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 578: 0.26548880338668823\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 579: 0.2650377154350281\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 580: 0.2648222744464874\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 581: 0.2645033299922943\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 582: 0.2641568183898926\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 583: 0.26302865147590637\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 584: 0.26252657175064087\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 585: 0.2620764970779419\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 586: 0.2618556618690491\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 587: 0.2615260183811188\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 588: 0.26118773221969604\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 589: 0.2600741982460022\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 590: 0.25957632064819336\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 591: 0.2591266930103302\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 592: 0.2589070200920105\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 593: 0.25856679677963257\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 594: 0.25822824239730835\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 595: 0.2571201026439667\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 596: 0.25662314891815186\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 597: 0.2561837434768677\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 598: 0.2559761703014374\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 599: 0.255639910697937\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 600: 0.2553357183933258\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 601: 0.2543127238750458\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 602: 0.2538588345050812\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 603: 0.25346022844314575\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 604: 0.25329264998435974\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 605: 0.25299662351608276\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 606: 0.25271835923194885\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 607: 0.25174081325531006\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 608: 0.25129249691963196\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 609: 0.25089871883392334\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 610: 0.25073254108428955\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 611: 0.2504271864891052\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 612: 0.25014540553092957\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 613: 0.24916698038578033\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 614: 0.24872836470603943\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 615: 0.24834077060222626\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 616: 0.2481813132762909\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 617: 0.24787472188472748\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 618: 0.2476009875535965\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 619: 0.24662362039089203\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 620: 0.2461848109960556\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 621: 0.2457941174507141\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 622: 0.2456376701593399\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 623: 0.24532674252986908\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 624: 0.24505697190761566\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 625: 0.24408265948295593\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 626: 0.24363121390342712\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 627: 0.24324923753738403\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 628: 0.24308760464191437\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 629: 0.2427668571472168\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 630: 0.24248948693275452\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 631: 0.2415076196193695\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 632: 0.2410697042942047\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 633: 0.240685373544693\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 634: 0.24051985144615173\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 635: 0.24018718302249908\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 636: 0.23991402983665466\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 637: 0.23894469439983368\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 638: 0.2385166436433792\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 639: 0.23814240097999573\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 640: 0.23798523843288422\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 641: 0.2376604825258255\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 642: 0.2373948097229004\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 643: 0.23642641305923462\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 644: 0.2360105961561203\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 645: 0.23564773797988892\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 646: 0.23549415171146393\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 647: 0.2351592630147934\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 648: 0.23489560186862946\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 649: 0.23394563794136047\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 650: 0.2335258275270462\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 651: 0.2331615835428238\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 652: 0.23301416635513306\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 653: 0.2326730638742447\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 654: 0.23241886496543884\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 655: 0.23147490620613098\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 656: 0.2310548573732376\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 657: 0.23069649934768677\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 658: 0.23053698241710663\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 659: 0.23019519448280334\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 660: 0.22994817793369293\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 661: 0.2290297895669937\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 662: 0.22861114144325256\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 663: 0.2282639741897583\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 664: 0.2281293272972107\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 665: 0.22778987884521484\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 666: 0.22754448652267456\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 667: 0.226625457406044\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 668: 0.226226806640625\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 669: 0.22589191794395447\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 670: 0.2257523089647293\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 671: 0.22541695833206177\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 672: 0.22517435252666473\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 673: 0.22425253689289093\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 674: 0.2238473892211914\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 675: 0.2235213816165924\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 676: 0.22338296473026276\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 677: 0.22303903102874756\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 678: 0.22280530631542206\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 679: 0.22190816700458527\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 680: 0.22150172293186188\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 681: 0.221167653799057\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 682: 0.22102941572666168\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 683: 0.22068534791469574\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 684: 0.2204492688179016\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 685: 0.21955879032611847\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 686: 0.2191656082868576\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 687: 0.2188423126935959\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 688: 0.21870651841163635\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 689: 0.21835653483867645\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 690: 0.21813128888607025\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 691: 0.21727032959461212\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 692: 0.21687473356723785\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 693: 0.21654962003231049\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 694: 0.21641913056373596\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 695: 0.21607187390327454\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 696: 0.21584726870059967\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 697: 0.21497409045696259\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 698: 0.21457524597644806\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 699: 0.21425773203372955\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 700: 0.2141292542219162\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 701: 0.2137850970029831\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 702: 0.21357284486293793\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 703: 0.21273455023765564\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 704: 0.21235430240631104\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 705: 0.2120525985956192\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 706: 0.21193808317184448\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 707: 0.21159718930721283\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 708: 0.21139585971832275\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 709: 0.2105841487646103\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 710: 0.21020253002643585\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 711: 0.2098941206932068\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 712: 0.20976439118385315\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 713: 0.20940746366977692\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 714: 0.20919601619243622\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 715: 0.20836538076400757\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 716: 0.2079954743385315\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 717: 0.20770345628261566\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 718: 0.20759333670139313\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 719: 0.2072395235300064\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 720: 0.20703339576721191\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 721: 0.20620109140872955\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 722: 0.20583172142505646\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 723: 0.20554445683956146\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 724: 0.20543178915977478\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 725: 0.2050722986459732\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 726: 0.20487207174301147\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 727: 0.20406056940555573\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 728: 0.20367954671382904\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 729: 0.2033897489309311\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 730: 0.20327769219875336\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 731: 0.20291240513324738\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 732: 0.20270827412605286\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 733: 0.20188163220882416\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 734: 0.20151542127132416\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 735: 0.20122447609901428\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 736: 0.20111237466335297\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 737: 0.20074665546417236\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 738: 0.20054970681667328\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 739: 0.19975104928016663\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 740: 0.19938381016254425\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 741: 0.19909854233264923\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 742: 0.198989138007164\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 743: 0.198622465133667\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 744: 0.19843125343322754\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 745: 0.19764389097690582\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 746: 0.19726978242397308\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 747: 0.19698049128055573\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 748: 0.19687174260616302\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 749: 0.19649620354175568\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 750: 0.1963028460741043\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 751: 0.1955491453409195\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 752: 0.19520966708660126\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 753: 0.19496993720531464\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 754: 0.1948844939470291\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 755: 0.1945432871580124\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 756: 0.19438916444778442\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 757: 0.19368581473827362\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 758: 0.19336514174938202\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 759: 0.19311563670635223\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 760: 0.19302476942539215\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 761: 0.19268113374710083\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 762: 0.1925283968448639\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 763: 0.19184361398220062\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 764: 0.1915215700864792\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 765: 0.19129693508148193\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 766: 0.19122259318828583\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 767: 0.19087570905685425\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 768: 0.19072267413139343\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 769: 0.1900375932455063\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 770: 0.18972645699977875\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 771: 0.18948645889759064\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 772: 0.1894126981496811\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 773: 0.18906518816947937\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 774: 0.18892161548137665\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 775: 0.18825098872184753\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 776: 0.18792995810508728\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 777: 0.18770238757133484\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 778: 0.1876232922077179\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 779: 0.18727900087833405\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 780: 0.18714240193367004\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 781: 0.1864864081144333\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 782: 0.18618084490299225\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 783: 0.1859503835439682\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 784: 0.18587557971477509\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 785: 0.18552297353744507\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 786: 0.1853824108839035\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 787: 0.18473534286022186\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 788: 0.1844543218612671\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 789: 0.18424466252326965\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 790: 0.1841815561056137\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 791: 0.18383704125881195\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 792: 0.18370643258094788\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 793: 0.18307290971279144\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 794: 0.1827898621559143\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 795: 0.1825866997241974\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 796: 0.18252845108509064\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 797: 0.1821846216917038\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 798: 0.18205790221691132\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 799: 0.1814367175102234\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 800: 0.18115326762199402\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 801: 0.1809460073709488\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 802: 0.18087820708751678\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 803: 0.18052728474140167\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 804: 0.18039420247077942\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 805: 0.17977114021778107\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 806: 0.17948244512081146\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 807: 0.1792750209569931\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 808: 0.17920531332492828\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 809: 0.17884084582328796\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 810: 0.17870114743709564\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 811: 0.17806482315063477\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 812: 0.17777445912361145\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 813: 0.17757007479667664\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 814: 0.17749792337417603\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 815: 0.1771380752325058\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 816: 0.17700853943824768\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 817: 0.17639614641666412\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 818: 0.1760999709367752\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 819: 0.17590440809726715\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 820: 0.17583799362182617\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 821: 0.17547443509101868\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 822: 0.17534150183200836\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 823: 0.17471696436405182\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 824: 0.17443272471427917\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 825: 0.17422544956207275\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 826: 0.17415989935398102\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 827: 0.17379611730575562\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 828: 0.1736701875925064\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 829: 0.17306210100650787\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 830: 0.1727646142244339\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 831: 0.1725703477859497\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 832: 0.17249435186386108\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 833: 0.1721329241991043\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 834: 0.17200683057308197\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 835: 0.17140120267868042\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 836: 0.17110882699489594\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 837: 0.17090784013271332\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 838: 0.1708456128835678\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 839: 0.1704835295677185\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 840: 0.17036767303943634\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 841: 0.16979657113552094\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 842: 0.16952894628047943\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 843: 0.16936704516410828\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 844: 0.16932396590709686\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 845: 0.16896994411945343\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 846: 0.16885186731815338\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 847: 0.1682940423488617\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 848: 0.1680314689874649\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 849: 0.1678612232208252\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 850: 0.16781406104564667\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 851: 0.1674661934375763\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 852: 0.16735295951366425\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 853: 0.16679711639881134\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 854: 0.16652554273605347\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 855: 0.1663580983877182\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 856: 0.1663147658109665\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 857: 0.16596254706382751\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 858: 0.16585031151771545\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 859: 0.16529908776283264\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 860: 0.16503016650676727\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 861: 0.16486726701259613\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 862: 0.16482548415660858\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 863: 0.16446833312511444\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 864: 0.16436466574668884\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 865: 0.1638297438621521\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 866: 0.1635635942220688\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 867: 0.16340802609920502\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 868: 0.16335546970367432\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 869: 0.16300149261951447\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 870: 0.1628970205783844\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 871: 0.1623634248971939\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 872: 0.16211366653442383\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 873: 0.16196788847446442\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 874: 0.16191130876541138\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 875: 0.16154465079307556\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 876: 0.16143573820590973\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 877: 0.16090945899486542\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 878: 0.16065318882465363\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 879: 0.16049401462078094\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 880: 0.1604512631893158\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 881: 0.1600884199142456\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 882: 0.15998728573322296\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 883: 0.15947198867797852\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 884: 0.15922504663467407\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 885: 0.1590813547372818\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 886: 0.15902817249298096\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 887: 0.158669576048851\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 888: 0.15856827795505524\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 889: 0.15804901719093323\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 890: 0.15778835117816925\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 891: 0.1576506644487381\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 892: 0.15762150287628174\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 893: 0.15727031230926514\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 894: 0.15717701613903046\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 895: 0.15670253336429596\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 896: 0.15645290911197662\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 897: 0.15632788836956024\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 898: 0.15629026293754578\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 899: 0.15592601895332336\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 900: 0.1558305323123932\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 901: 0.15536895394325256\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 902: 0.15511445701122284\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 903: 0.15499068796634674\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 904: 0.15495051443576813\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 905: 0.1545879989862442\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 906: 0.154495507478714\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 907: 0.15402771532535553\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 908: 0.1537833958864212\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 909: 0.15365511178970337\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 910: 0.153617262840271\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 911: 0.15326106548309326\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 912: 0.15316994488239288\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 913: 0.1527123600244522\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 914: 0.15249091386795044\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 915: 0.15237043797969818\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 916: 0.15233315527439117\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 917: 0.1519734263420105\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 918: 0.15188083052635193\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 919: 0.1514468789100647\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 920: 0.15123341977596283\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 921: 0.15110723674297333\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 922: 0.1510878950357437\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 923: 0.15071842074394226\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 924: 0.15062107145786285\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 925: 0.15017756819725037\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 926: 0.1499805897474289\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 927: 0.14985769987106323\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 928: 0.1498209536075592\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 929: 0.14945648610591888\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 930: 0.14936883747577667\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 931: 0.1489327996969223\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 932: 0.14871972799301147\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 933: 0.14861342310905457\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 934: 0.14857281744480133\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 935: 0.14821761846542358\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 936: 0.14813095331192017\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 937: 0.14770172536373138\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 938: 0.1474877893924713\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 939: 0.14738579094409943\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 940: 0.14734084904193878\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 941: 0.1469763070344925\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 942: 0.1468857228755951\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 943: 0.14646218717098236\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 944: 0.14624811708927155\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 945: 0.14616495370864868\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 946: 0.14612950384616852\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 947: 0.14576061069965363\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 948: 0.1456744223833084\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 949: 0.1452796906232834\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 950: 0.14507251977920532\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 951: 0.14497172832489014\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 952: 0.14495472609996796\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 953: 0.14459699392318726\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 954: 0.1445019394159317\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 955: 0.14408858120441437\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 956: 0.14390011131763458\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 957: 0.1438179761171341\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 958: 0.14379549026489258\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 959: 0.14343608915805817\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 960: 0.14334601163864136\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 961: 0.1429470032453537\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 962: 0.14273078739643097\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 963: 0.14263798296451569\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 964: 0.1425936073064804\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 965: 0.14224204421043396\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 966: 0.14215460419654846\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 967: 0.14176787436008453\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 968: 0.14157576858997345\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 969: 0.1414913386106491\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 970: 0.14146898686885834\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 971: 0.14111380279064178\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 972: 0.14102962613105774\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 973: 0.14065054059028625\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 974: 0.14044860005378723\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 975: 0.1403597891330719\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 976: 0.14033013582229614\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 977: 0.1399797648191452\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 978: 0.13989633321762085\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 979: 0.13950519263744354\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 980: 0.1393323838710785\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 981: 0.13923272490501404\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 982: 0.13921426236629486\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 983: 0.13885340094566345\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 984: 0.1387699693441391\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 985: 0.1384117752313614\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 986: 0.13822834193706512\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 987: 0.13816219568252563\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 988: 0.13812822103500366\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 989: 0.13775788247585297\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 990: 0.13767434656620026\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 991: 0.13732381165027618\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 992: 0.13714221119880676\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 993: 0.13708624243736267\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 994: 0.1370628923177719\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 995: 0.1367008090019226\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 996: 0.1366138905286789\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 997: 0.13625414669513702\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 998: 0.13607443869113922\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 999: 0.1360229104757309\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1000: 0.1359960436820984\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1001: 0.13564841449260712\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1002: 0.13557107746601105\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1003: 0.13524316251277924\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1004: 0.1350470632314682\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1005: 0.13498546183109283\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1006: 0.13497108221054077\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1007: 0.1346282958984375\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1008: 0.13455112278461456\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1009: 0.1342168152332306\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1010: 0.13401363790035248\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1011: 0.1339607685804367\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1012: 0.133958101272583\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1013: 0.13359545171260834\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1014: 0.13351751863956451\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1015: 0.13319550454616547\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1016: 0.13301455974578857\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1017: 0.13296963274478912\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1018: 0.13294047117233276\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1019: 0.13259004056453705\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1020: 0.13251453638076782\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1021: 0.13218219578266144\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1022: 0.1320246011018753\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1023: 0.13197451829910278\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1024: 0.13195091485977173\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1025: 0.13160207867622375\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1026: 0.13152772188186646\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1027: 0.13120988011360168\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1028: 0.13102275133132935\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1029: 0.13098366558551788\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1030: 0.13098092377185822\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1031: 0.1306348741054535\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1032: 0.13055795431137085\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1033: 0.13025052845478058\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1034: 0.13006563484668732\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1035: 0.13001897931098938\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1036: 0.13002601265907288\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1037: 0.12967275083065033\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1038: 0.12959782779216766\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1039: 0.12929868698120117\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1040: 0.1291237622499466\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1041: 0.1290610134601593\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1042: 0.12906543910503387\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1043: 0.1287267506122589\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1044: 0.12865829467773438\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1045: 0.12837429344654083\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1046: 0.12819665670394897\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1047: 0.12814676761627197\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1048: 0.12814225256443024\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1049: 0.1277996152639389\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1050: 0.12772567570209503\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1051: 0.12743383646011353\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1052: 0.1272655725479126\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1053: 0.12722717225551605\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1054: 0.1272333413362503\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1055: 0.12688274681568146\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1056: 0.12681159377098083\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1057: 0.12654730677604675\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1058: 0.12638169527053833\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1059: 0.1263251006603241\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1060: 0.1263178139925003\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1061: 0.12596845626831055\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1062: 0.12589015066623688\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1063: 0.12560367584228516\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1064: 0.1254383772611618\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1065: 0.12542395293712616\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1066: 0.12543310225009918\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1067: 0.12508022785186768\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1068: 0.12500324845314026\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1069: 0.12472391128540039\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1070: 0.12455829977989197\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1071: 0.1245446503162384\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1072: 0.1245497316122055\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1073: 0.12419974058866501\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1074: 0.12411898374557495\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1075: 0.12382490187883377\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1076: 0.12369026988744736\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1077: 0.12366000562906265\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1078: 0.12366023659706116\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1079: 0.12332223355770111\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1080: 0.12325833737850189\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1081: 0.12299889326095581\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1082: 0.12284953892230988\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1083: 0.12281973659992218\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1084: 0.12282702326774597\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1085: 0.12248411029577255\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1086: 0.12241199612617493\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1087: 0.12215757369995117\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1088: 0.1219959408044815\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1089: 0.12196357548236847\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1090: 0.12197425961494446\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1091: 0.12162546068429947\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1092: 0.12154371291399002\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1093: 0.12131242454051971\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1094: 0.12118753790855408\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1095: 0.1211775466799736\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1096: 0.12116993963718414\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1097: 0.12083249539136887\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1098: 0.12076722085475922\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1099: 0.12055902928113937\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1100: 0.12039589881896973\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1101: 0.12038999795913696\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1102: 0.12041595578193665\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1103: 0.1200793981552124\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1104: 0.12000437080860138\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1105: 0.11976068466901779\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1106: 0.11962639540433884\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1107: 0.11961513757705688\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1108: 0.11962894350290298\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1109: 0.11929349601268768\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1110: 0.11921560764312744\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1111: 0.11894622445106506\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1112: 0.11881450563669205\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1113: 0.11882171034812927\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1114: 0.11884591728448868\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1115: 0.11850479245185852\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1116: 0.11842267960309982\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1117: 0.1181802749633789\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1118: 0.11805929243564606\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1119: 0.11804857105016708\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1120: 0.1180797591805458\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1121: 0.11773641407489777\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1122: 0.1176469549536705\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1123: 0.11740569770336151\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1124: 0.1172703430056572\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1125: 0.11726454645395279\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1126: 0.11731573939323425\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1127: 0.11695796251296997\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1128: 0.11686470359563828\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1129: 0.11663565784692764\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1130: 0.11650222539901733\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1131: 0.11652478575706482\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1132: 0.11653479188680649\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1133: 0.11618591099977493\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1134: 0.11610233038663864\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1135: 0.1158868819475174\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1136: 0.11575379967689514\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1137: 0.11574944853782654\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1138: 0.1158142164349556\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1: 0.07547506019473076\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 2: 0.07226308286190034\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 3: 0.06822720617055893\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 4: 0.07534952759742737\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 5: 0.07029702067375183\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 6: 0.06727935820817947\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 7: 0.07051845788955688\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Started fitting LGBM model\u001B[0m\n", - "Found `num_iterations` in params. Will use it instead of argument\n", - "'verbose_eval' argument is deprecated and will be removed in a future release of LightGBM. Pass 'log_evaluation()' callback via 'callbacks' argument instead.\n", - "\u001B[32mINFO:lightwood-1461893:A single GBM iteration takes 0.1 seconds\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Training GBM () with 175 iterations given 21.959666557312016 seconds constraint\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Lightgbm model contains 600 weak estimators\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Updating lightgbm model with 7.0 iterations\u001B[0m\n", - "Found `num_iterations` in params. Will use it instead of argument\n", - "'verbose_eval' argument is deprecated and will be removed in a future release of LightGBM. Pass 'log_evaluation()' callback via 'callbacks' argument instead.\n", - "\u001B[32mINFO:lightwood-1461893:Model now has a total of 600 weak estimators\u001B[0m\n", - "\u001B[33mWARNING:lightwood-1461893:Exception: Unspported categorical type for regression when training mixer: \u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Ensembling the mixer\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Mixer: Neural got accuracy: 0.9222222222222223\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Mixer: LightGBM got accuracy: 1.0\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Picked best mixer: LightGBM\u001B[0m\n", - "\u001B[37mDEBUG:lightwood-1461893: `fit` runtime: 5.36 seconds\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Analyzing the ensemble of mixers\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:The block ModelCorrelationHeatmap is now running its analyze() method\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:The block ICP is now running its analyze() method\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:The block AccStats is now running its analyze() method\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:The block ConfStats is now running its analyze() method\u001B[0m\n", - "\u001B[37mDEBUG:lightwood-1461893: `analyze_ensemble` runtime: 0.02 seconds\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Adjustment on validation requested.\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Updating the mixers\u001B[0m\n", - "torch.cuda.amp.GradScaler is enabled, but CUDA is not available. Disabling.\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 1: 0.07650255709886551\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 2: 0.07755388915538788\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 3: 0.0752710983157158\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 4: 0.07889281958341599\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Loss @ epoch 5: 0.07823747098445892\u001B[0m\n", - "\u001B[32mINFO:lightwood-1461893:Updating lightgbm model with 7.0 iterations\u001B[0m\n", - "Found `num_iterations` in params. Will use it instead of argument\n", - "'verbose_eval' argument is deprecated and will be removed in a future release of LightGBM. Pass 'log_evaluation()' callback via 'callbacks' argument instead.\n", - "\u001B[32mINFO:lightwood-1461893:Model now has a total of 600 weak estimators\u001B[0m\n", - "\u001B[37mDEBUG:lightwood-1461893: `adjust` runtime: 0.02 seconds\u001B[0m\n", - "\u001B[37mDEBUG:lightwood-1461893: `learn` runtime: 5.58 seconds\u001B[0m\n" - ] - } - ], + "outputs": [], "source": [ "from lightwood.api.high_level import code_from_json_ai, predictor_from_code\n", "\n", @@ -1677,7 +376,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": { "execution": { "iopub.execute_input": "2022-02-03T21:30:04.822276Z", @@ -1686,20 +385,7 @@ "shell.execute_reply": "2022-02-03T21:30:04.861243Z" } }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAR8AAAD4CAYAAADVYeLDAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAASZ0lEQVR4nO3ba3BV9bnH8e+ThDuGjKBoQgbodE+LFESLxKOVMoVB0NOTtjI1DjOKg4NaKFWHVtq+EN6cqZYW7ZFrC0VsaepQWyPHo/VSC7VKiFwEI7qpSEJARi5NCloh4Tkv9gY3MeEiSZ5Afp+ZzOy11n+t9V8k+WbtlWDujohIW8uKnoCIdEyKj4iEUHxEJITiIyIhFB8RCZETPYEo3c08L3oSckZ20yt6CnLGave6+0VNbemw8ckDpkRPQs7IbK6LnoKcsVU7mtuit10iEkLxEZEQio+IhFB8RCSE4iMiIRQfEQmh+IhICMVHREIoPiISQvERkRCKj4iEUHxEJITiIyIhFB8RCaH4iEgIxUdEQig+IhJC8RGREIqPiIRQfEQkhOIjIiEUHxEJofiISAjFR0RCKD4iEkLxEZEQio+IhFB8RCSE4iMiIRQfEQmh+IhICMVHREIoPiISQvERkRCKj4iEUHxEJITiIyIhFB8RCaH4iEgIxUdEQig+IhJC8RGREIqPiIRQfEQkhOIjIiEUHxEJofiISAjFR0RCKD4iEkLxOUcVL1nC9/fs4TubNzc7ZvwjjzA9meTuTZu49Ior2nB2Hdv111/J1q0LSCYXcf/9Ez61vXPnHEpLf0AyuYjXXptD//4XH982c+YEkslFbN26gLFjP/mc3XNPMVu2zGPz5kdZsWIGXbp0apNraU2tGh8zczP7WcbyDDOb1ZrnTJ/nZTMb3trnibRx2TJ+M25cs9sT48dzYSLBLxIJnp4yhRsXLGjD2XVcWVlZzJt3F+PHz+Kyy6Zyyy0jGTSo8IQxkyeP5cCBgyQSdzJ37lM8+OAkAAYNKqSkZCSDB09l3LhZzJ9/N1lZWeTnX8j06V9n+PB7GTJkGtnZ2ZSUjAy4upbV2nc+HwPfMrM+LXlQS+nQd2071qzho/37m93+heJiNi1fDsDOtWvpmpdHz0suaavpdVgjRiTYtm0327fv4ciRekpLV1NcXHTCmOLiIh577EUAVq58hdGjLz++vrR0NYcP1/Pee3vYtm03I0YkAMjJyaJbt85kZ2fRvXsXdu1q/nN/rmjtb+B6YDFwb+MNZnaRmf3BzNalP65Nr59lZjMyxm0xswHpj7fNbDmwBSg0swVmVmFmb5rZ7Fa+lnNKbkEBddXVx5frdu4kt6AgcEYdQ0FBb6qr9x5f3rlzHwUFvZsd09BwlNraQ/TundvEvnspKOjNrl37mTPnj1RVLWX37uXU1h7i+ec3tM0FtaK2uHuYB0w0s16N1j8CzHX3q4CbgF+dxrESwHx3H+zuO4Afu/twYCjwVTMberKdzWxKOlYVH575dYiEyMvrQXFxEQMH3kF+/m306NGViRNHRU/rrLV6fNy9DlgOTG+0aQzwqJltBMqAXDPreYrD7XD31zKWv21m64ENwGDgslPMZbG7D3f34d3P5CLOQXU1NeQWfvKsIbdfP+pqagJn1DHU1OyjsPCTpwz9+vWmpmZfs2Oys7Po1asH+/bVNbFvH2pq9jFmzDC2b9/D3r111Nc38OSTf+eaawa1zQW1orZ6bvIwMBno0ejcV7v7sPRHgbsfJPVWLXNeXTNeHzr2wswGAjOA0e4+FPjfRmM7tLfLyrj81lsB6FdUxMe1tRx8//3gWZ3/1q1LkkjkM2BAXzp1yqGkZCRlZeUnjCkrW8ttt40GYMKEa3nppTfS68spKRlJ5845DBjQl0Qin/LyJFVVH3D11V+kW7cuAIwefTlvvVXNuS6nLU7i7vvN7AlSAVqaXv1n4LvATwHMbJi7bwTeA/4zve5KYGAzh80lFaNaM+sLjAdebp0raH9uWrGCAaNG0b1PH+6rruYvDzxAdqfUr18rFi0i+cwzJG64genbtnHkww956vbbg2fcMTQ0HGXatIU899xssrOzWLr0BSorq5g9eyIVFUmefrqcJUue5/HH7yOZXMT+/QcpKXkIgMrKKp544m9UVs6nvr6BqVMXcvToUcrL32HlyldYv/5h6usb2LDhXRYvfjb4Ss+euXvrHdzsoLv3TL/uC2wHHnL3WenfgM0DBpGK4Gp3v8vMugFPAQXAWuA/SIUFYJW7fynj+MuAa4BqoBYoc/dlZvYyMMPdK5qbW76ZT2nRq5XWNjv1M0nOKateTz+X/ZRWvfM5Fp706z1A94zlvcDNTezzETC2mUN+qdHYSc2cd9SZz1ZE2lKH/lsZEYmj+IhICMVHREIoPiISQvERkRCKj4iEUHxEJITiIyIhFB8RCaH4iEgIxUdEQig+IhJC8RGREIqPiIRQfEQkhOIjIiEUHxEJofiISAjFR0RCKD4iEkLxEZEQio+IhFB8RCSE4iMiIRQfEQmh+IhICMVHREIoPiISQvERkRCKj4iEUHxEJITiIyIhFB8RCaH4iEgIxUdEQig+IhJC8RGREIqPiIRQfEQkhOIjIiEUHxEJofiISAjFR0RCKD4iEkLxEZEQio+IhFB8RCSE4iMiIczdo+cQwizP4broacgZeIBV0VOQMzQbXnf34U1t052PiIRQfEQkhOIjIiEUHxEJofiISAjFR0RCKD4iEkLxEZEQio+IhFB8RCSE4iMiIRQfEQmh+IhICMVHREIoPiISQvERkRCKj4iEUHxEJITiIyIhFB8RCaH4iEgIxUdEQig+IhJC8RGREIqPiIRQfEQkhOIjIiEUHxEJofiISAjFR0RCKD4iEkLxEZEQio+IhFB8RCSE4iMiIRQfEQmh+IhICMVHREIoPiISQvERkRCKj4iEUHxEJITiIyIhFB8RCaH4iEgIxUdEQig+IhJC8RGREIqPiIRQfNq566+/kq1bF5BMLuL++yd8anvnzjmUlv6AZHIRr702h/79Lz6+bebMCSSTi9i6dQFjx15xfP099xSzZcs8Nm9+lBUrZtClS6c2uZaOrnjJEr6/Zw/f2by52THjH3mE6ckkd2/axKVXXNHsuPPBKeNjZgebWHeXmd16iv0mmdmjzWz7UaPlvma2wszeNbPXzexVM/tmetsoM6s1s41m9oaZvWBmF2ecw81sTMaxvpFe9+nv1HNMVlYW8+bdxfjxs7jssqnccstIBg0qPGHM5MljOXDgIInEncyd+xQPPjgJgEGDCikpGcngwVMZN24W8+ffTVZWFvn5FzJ9+tcZPvxehgyZRnZ2NiUlIwOuruPZuGwZvxk3rtntifHjuTCR4BeJBE9PmcKNCxa04eza3me683H3he6+/CzOezw+ZmbAn4DV7v45d/8yUAL0yxi/xt2HuftQYB0wNWPb5vT4Y24BNp3F3NqNESMSbNu2m+3b93DkSD2lpaspLi46YUxxcRGPPfYiACtXvsLo0ZcfX19auprDh+t57709bNu2mxEjEgDk5GTRrVtnsrOz6N69C7t27W/bC+ugdqxZw0f7m/+3/kJxMZuWp76tdq5dS9e8PHpecklbTa/Nfab4mNksM5uRfn1V+o5ko5n91My2ZAzNN7NnzSxpZg+lx/8E6JYe/1vga8Bhd194bCd33+Hu/9PEeQ24ADiQsXoNMMLMOplZT+DzwMbPcl3tTUFBb6qr9x5f3rlzHwUFvZsd09BwlNraQ/TundvEvnspKOjNrl37mTPnj1RVLWX37uXU1h7i+ec3tM0FyUnlFhRQV119fLlu505yCwoCZ9S6WuKZz6+BO919GNDQaNsw4GZgCHCzmRW6+0zgo/SdzERgMLD+FOe4zsw2AlXAGGBpxjYHXgCuB4qBsuYOYmZTzKzCzCrg8Gle3vklL68HxcVFDBx4B/n5t9GjR1cmThwVPS3pgM4qPmaWB1zg7q+mV61oNORFd691938DlUD/0zjmPDPbZGbrMlYfe9tVSCp2DzXarZTUW68S4HfNHdvdF7v7cHcfDp1PNZVwNTX7KCzsc3y5X7/e1NTsa3ZMdnYWvXr1YN++uib27UNNzT7GjBnG9u172Lu3jvr6Bp588u9cc82gtrkgOam6mhpyCz95ppfbrx91NTWBM2pdrf3bro8zXjcAOU2MeRO48tiCu08FRgMXNXPMMuCEJ6TuXk7q7qqPu79zNhNuT9atS5JI5DNgQF86dcqhpGQkZWXlJ4wpK1vLbbeNBmDChGt56aU30uvLKSkZSefOOQwY0JdEIp/y8iRVVR9w9dVfpFu3LgCMHn05b71VjcR7u6yMy29N/R6nX1ERH9fWcvD994Nn1XqaisFpc/d/mtm/zKzI3ddy4oPfkzliZp3c/QjwEvDfZna3ux97vN/9JPt+BfhHE+tnAv8+7cmfAxoajjJt2kKee2422dlZLF36ApWVVcyePZGKiiRPP13OkiXP8/jj95FMLmL//oOUlKRuCisrq3jiib9RWTmf+voGpk5dyNGjRykvf4eVK19h/fqHqa9vYMOGd1m8+NngK+0YblqxggGjRtG9Tx/uq67mLw88QHan1J85VCxaRPKZZ0jccAPTt23jyIcf8tTttwfPuHWZu598gNlRYFfGqp8DucBBd59jZkXAL4GjwF+B4e5+rZlNSr+elj7OKmCOu79sZg8C/wWsd/eJZnYpMBcoAj4ADgEL3f33ZjYKeArYDhhQC9zh7u80PkfGnJcBq9x9ZfPXledw3an+faQdeYBV0VOQMzQbXk895vi0U8bnVMysp7sfTL+eCVzq7t87q4O2AcXn3KP4nHtOFp+zetuVdqOZ/TB9rB3ApBY4poic5846Pu7+e+D3LTAXEelA9H+7RCSE4iMiIRQfEQmh+IhICMVHREIoPiISQvERkRCKj4iEUHxEJITiIyIhFB8RCaH4iEgIxUdEQig+IhJC8RGREIqPiIRQfEQkhOIjIiEUHxEJofiISAjFR0RCKD4iEkLxEZEQio+IhFB8RCSE4iMiIRQfEQmh+IhICMVHREIoPiISQvERkRCKj4iEUHxEJITiIyIhFB8RCaH4iEgIxUdEQig+IhJC8RGREIqPiIRQfEQkhOIjIiEUHxEJofiISAjFR0RCKD4iEkLxEZEQ5u7RcwhhZh8AO6Ln0Ur6AHujJyFn5Hz9nPV394ua2tBh43M+M7MKdx8ePQ85fR3xc6a3XSISQvERkRCKz/lpcfQE5Ix1uM+ZnvmISAjd+YhICMVHREIoPu2QmbmZ/SxjeYaZzWqD875sZh3q172ny8wONrHuLjO79RT7TTKzR5vZ9qNGy33NbIWZvWtmr5vZq2b2zfS2UWZWa2YbzewNM3vBzC7OOIeb2ZiMY30jvW7CZ7netqD4tE8fA98ysz4teVBL0ee8hbj7QndffhaHOB4fMzPgT8Bqd/+cu38ZKAH6ZYxf4+7D3H0osA6YmrFtc3r8MbcAm85ibq1OX4jtUz2p337c23iDmV1kZn8ws3Xpj2vT62eZ2YyMcVvMbED6420zWw5sAQrNbIGZVZjZm2Y2u60u6nyT+W9uZlel70g2mtlPzWxLxtB8M3vWzJJm9lB6/E+AbunxvwW+Bhx294XHdnL3He7+P02c14ALgAMZq9cAI8ysk5n1BD4PbGzhS25Rik/7NQ+YaGa9Gq1/BJjr7lcBNwG/Oo1jJYD57j7Y3XcAP07/Ne1Q4KtmNrQlJ95B/Rq4092HAQ2Ntg0DbgaGADebWaG7zwQ+St/JTAQGA+tPcY7rzGwjUAWMAZZmbHPgBeB6oBgoO6uraQOKTzvl7nXAcmB6o01jgEfTX4RlQG76J93J7HD31zKWv21m64ENpL7oL2uZWXdMZpYHXODur6ZXrWg05EV3r3X3fwOVQP/TOOY8M9tkZusyVh9721VIKnYPNdqtlNRbrxLgd5/hUtpUTvQE5KQeJvXT8NcZ67KAq9NfyMeZWT0n/jDpmvH6UMa4gcAM4Cp3P2BmyxqNlZb3ccbrBpr+vnuT1J0sAO4+Nf3Mr6KZY5YBf8hc4e7lZjYE+NDd30m9O2u/dOfTjrn7fuAJYHLG6j8D3z22YGbD0i/fA65Mr7sSGNjMYXNJxajWzPoC41t00h2Qu/8T+JeZFaVXlZxkeKYjZtYp/foloKuZ3Z2xvftJ9v0K8I8m1s8k40F2e6Y7n/bvZ8C0jOXpwDwze4PU5281cBepn4K3mtmbwFrgnaYO5u6bzGwDsBWoBl5pxbmfT7qb2c6M5Z832j4Z+KWZHQX+CtSexjEXA2+Y2Xp3n2hm3wDmmtkPgA9I/ZC4P2P8sWc+lj7+HY0P6O7/d5rXE07/vUKkBZhZT3c/mH49E7jU3b8XPK12TXc+Ii3jRjP7IanvqR3ApNjptH+68xGREHrgLCIhFB8RCaH4iEgIxUdEQig+IhLi/wGd1zPXtc5EwAAAAABJRU5ErkJggg==\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", @@ -1732,7 +418,7 @@ "source": [ "Nice! We've just added an additional piece of insight regarding the predictor that Lightwood came up with for the task of predicting the Human Development Index of any given country.\n", "\n", - "What this matrix is telling us is whether the predictions of both mixers stored in the ensemble -- Neural and LightGBM -- have a high correlation or not.\n", + "What this matrix is telling us is whether predictions of each pair of the mixers stored in the ensemble have a high correlation or not.\n", "\n", "This is, of course, a very simple example, but it shows the convenience of such an abstraction within the broader pipeline that Lightwood automates.\n", "\n", @@ -1756,7 +442,8 @@ "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6" }, "kernelspec": { - "display_name": "Python 3.8.10 64-bit", + "display_name": "Python 3 (ipykernel)", + "language": "python", "name": "python3" }, "language_info": { @@ -1769,9 +456,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.10" + "version": "3.9.14" } }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} diff --git a/lightwood/__about__.py b/lightwood/__about__.py index 1b32a6e42..a750aab66 100755 --- a/lightwood/__about__.py +++ b/lightwood/__about__.py @@ -1,6 +1,6 @@ __title__ = 'lightwood' __package_name__ = 'lightwood' -__version__ = '22.9.1.0' +__version__ = '22.10.4.0' __description__ = "Lightwood is a toolkit for automatic machine learning model building" __email__ = "community@mindsdb.com" __author__ = 'MindsDB Inc' diff --git a/lightwood/analysis/analyze.py b/lightwood/analysis/analyze.py index 18c982030..3458a5514 100644 --- a/lightwood/analysis/analyze.py +++ b/lightwood/analysis/analyze.py @@ -1,6 +1,7 @@ from typing import Dict, List, Tuple, Optional from lightwood.helpers.log import log +from lightwood.helpers.ts import filter_ds from lightwood.api import dtype from lightwood.ensemble import BaseEnsemble from lightwood.analysis.base import BaseAnalysisBlock @@ -53,8 +54,10 @@ def model_analyzer( # raw predictions for validation dataset args = {} if not is_classification else {"predict_proba": True} + filtered_df = filter_ds(encoded_val_data, tss) + encoded_val_data = EncodedDs(encoded_val_data.encoders, filtered_df, encoded_val_data.target) normal_predictions = predictor(encoded_val_data, args=PredictionArguments.from_dict(args)) - normal_predictions = normal_predictions.set_index(data.index) + normal_predictions = normal_predictions.set_index(encoded_val_data.data_frame.index) # ------------------------- # # Run analysis blocks, both core and user-defined @@ -65,7 +68,7 @@ def model_analyzer( 'input_cols': input_cols, 'dtype_dict': dtype_dict, 'normal_predictions': normal_predictions, - 'data': data, + 'data': filtered_df, 'train_data': train_data, 'encoded_val_data': encoded_val_data, 'is_classification': is_classification, diff --git a/lightwood/analysis/helpers/conf_stats.py b/lightwood/analysis/helpers/conf_stats.py index d6b0d3d21..fb52682e7 100644 --- a/lightwood/analysis/helpers/conf_stats.py +++ b/lightwood/analysis/helpers/conf_stats.py @@ -27,10 +27,10 @@ def analyze(self, info: Dict[str, object], **kwargs) -> Dict[str, object]: possible_labels = ns.stats_info.train_observed_classes self.ordenc.fit([[label] for label in possible_labels]) task_type = 'categorical' - elif ns.is_numerical: - task_type = 'numerical' elif ns.is_multi_ts: task_type = 'multi_ts' + elif ns.is_numerical: + task_type = 'numerical' else: return info @@ -66,14 +66,15 @@ def _get_stats(self, confs, preds, data, target, task_type='categorical'): if task_type == 'categorical': sorted_inp['__mdb_prediction'] = sorted_preds['prediction'] else: - sorted_inp['__mdb_lower'] = confs['lower'] - sorted_inp['__mdb_upper'] = confs['upper'] - if task_type == 'numerical': - sorted_inp['__mdb_hits'] = (sorted_inp['__mdb_lower'] <= sorted_inp[target]) & \ - (sorted_inp[target] <= sorted_inp['__mdb_upper']) - elif task_type == 'multi_ts': - sorted_inp['__mdb_hits'] = (sorted_inp['__mdb_lower'][0] <= sorted_inp[target]) & \ - (sorted_inp[target] <= sorted_inp['__mdb_upper'][0]) + if isinstance(confs['lower'][0], list): + sorted_inp['__mdb_lower'] = confs['lower'].apply(lambda x: x[0]) + sorted_inp['__mdb_upper'] = confs['upper'].apply(lambda x: x[0]) + else: + sorted_inp['__mdb_lower'] = confs['lower'] + sorted_inp['__mdb_upper'] = confs['upper'] + + sorted_inp['__mdb_hits'] = (sorted_inp['__mdb_lower'] <= sorted_inp[target]) & \ + (sorted_inp[target] <= sorted_inp['__mdb_upper']) size = round(len(sorted_inp) / self.ece_bins) bins = [] diff --git a/lightwood/analysis/nc/calibrate.py b/lightwood/analysis/nc/calibrate.py index 3bdd65750..c4705362b 100644 --- a/lightwood/analysis/nc/calibrate.py +++ b/lightwood/analysis/nc/calibrate.py @@ -41,6 +41,11 @@ def analyze(self, info: Dict[str, object], **kwargs) -> Dict[str, object]: data_type = ns.dtype_dict[ns.target] output = {'icp': {'__mdb_active': False}} + if 'confidence' in ns.normal_predictions.columns: + # bypass calibrator if model already outputs confidence + output['result_df'] = ns.normal_predictions[['confidence', 'lower', 'upper']] + return {**info, **output} + fit_params = {'horizon': ns.tss.horizon or 0, 'columns_to_ignore': []} fit_params['columns_to_ignore'].extend([f'timestep_{i}' for i in range(1, fit_params['horizon'])]) @@ -479,6 +484,13 @@ def _formatted(row_insights, global_insights, ns, is_numerical): elif ns.target_dtype in (dtype.short_text, dtype.rich_text, dtype.binary, dtype.categorical): row_insights['prediction'] = row_insights['prediction'].astype(str) + # horizon collapse + if ns.tss.is_timeseries and is_numerical and ns.tss.horizon > 1: + row_insights['prediction_sum'] = row_insights['prediction'].apply(lambda x: sum(x)) + row_insights['lower_sum'] = row_insights['lower'].apply(lambda x: min(x)) + row_insights['upper_sum'] = row_insights['upper'].apply(lambda x: max(x)) + row_insights['confidence_mean'] = row_insights['confidence'].apply(lambda x: np.mean(x)) + return row_insights, global_insights @staticmethod diff --git a/lightwood/api/json_ai.py b/lightwood/api/json_ai.py index f62b9754d..2f19a2b98 100644 --- a/lightwood/api/json_ai.py +++ b/lightwood/api/json_ai.py @@ -11,6 +11,7 @@ ) import inspect from lightwood.helpers.log import log +from lightwood.__about__ import __version__ as lightwood_version # For custom modules, we create a module loader with necessary imports below @@ -39,6 +40,7 @@ from lightwood.ensemble import * from lightwood.helpers.device import * from lightwood.helpers.general import * +from lightwood.helpers.ts import * from lightwood.helpers.log import * from lightwood.helpers.numeric import * from lightwood.helpers.imputers import * @@ -278,6 +280,13 @@ def generate_json_ai( "stop_after": "$problem_definition.seconds_per_mixer", }, }, + { + "module": "RandomForest", + "args": { + "stop_after": "$problem_definition.seconds_per_mixer", + "fit_on_dev": True, + }, + }, ] ) elif tss.is_timeseries and tss.horizon > 1: @@ -372,8 +381,10 @@ def generate_json_ai( accuracy_functions = ["r2_score"] elif output_dtype in [dtype.categorical, dtype.tags, dtype.binary]: accuracy_functions = ["balanced_accuracy_score"] - elif output_dtype in (dtype.num_array, dtype.num_tsarray): - accuracy_functions = ["bounded_ts_accuracy"] + elif output_dtype in (dtype.num_tsarray, ): + accuracy_functions = ["complementary_smape_array_accuracy"] + elif output_dtype in (dtype.num_array, ): + accuracy_functions = ["evaluate_num_array_accuracy"] elif output_dtype in (dtype.cat_array, dtype.cat_tsarray): accuracy_functions = ["evaluate_cat_array_accuracy"] else: @@ -383,7 +394,8 @@ def generate_json_ai( if is_ts: if output_dtype in [dtype.integer, dtype.float]: - accuracy_functions = ["bounded_ts_accuracy"] # forces this acc fn for t+1 time series forecasters # noqa + # forces this acc fn for t+1 time series forecasters + accuracy_functions = ["complementary_smape_array_accuracy"] if output_dtype in (dtype.integer, dtype.float, dtype.num_tsarray): imputers.append({"module": "NumericalImputer", @@ -590,6 +602,12 @@ def _add_implicit_values(json_ai: JsonAI) -> JsonAI: "target_encoder", "$encoders[self.target]" ) + elif mixers[i]["module"] == "RandomForest": + mixers[i]["args"]["target_encoder"] = mixers[i]["args"].get( + "target_encoder", "$encoders[self.target]" + ) + mixers[i]["args"]["use_optuna"] = True + elif mixers[i]["module"] == "LightGBMArray": mixers[i]["args"]["input_cols"] = mixers[i]["args"].get( "input_cols", "$input_cols" @@ -602,7 +620,7 @@ def _add_implicit_values(json_ai: JsonAI) -> JsonAI: mixers[i]["args"]["fit_on_dev"] = mixers[i]["args"].get("fit_on_dev", "True") mixers[i]["args"]["use_stl"] = mixers[i]["args"].get("use_stl", "False") - elif mixers[i]["module"] == "NHitsMixer": + elif mixers[i]["module"] in ("NHitsMixer", "GluonTSMixer"): mixers[i]["args"]["horizon"] = "$problem_definition.timeseries_settings.horizon" mixers[i]["args"]["window"] = "$problem_definition.timeseries_settings.window" mixers[i]["args"]["ts_analysis"] = mixers[i]["args"].get( @@ -980,6 +998,8 @@ def code_from_json_ai(json_ai: JsonAI) -> str: encoded_train_data = enc_data['train'] encoded_dev_data = enc_data['dev'] encoded_test_data = enc_data['test'] +filtered_df = filter_ds(encoded_test_data, self.problem_definition.timeseries_settings) +encoded_test_data = EncodedDs(encoded_test_data.encoders, filtered_df, encoded_test_data.target) log.info('Training the mixers') @@ -1186,6 +1206,7 @@ def __init__(self): self.accuracy_functions = {json_ai.accuracy_functions} self.identifiers = {json_ai.identifiers} self.dtype_dict = {inline_dict(dtype_dict)} + self.lightwood_version = '{lightwood_version}' # Any feature-column dependencies self.dependencies = {inline_dict(json_ai.dependency_dict)} diff --git a/lightwood/api/types.py b/lightwood/api/types.py index 12fd924a9..2453ce05e 100644 --- a/lightwood/api/types.py +++ b/lightwood/api/types.py @@ -62,6 +62,7 @@ class StatisticalAnalysis: in the information. :param nr_rows: Number of rows (samples) in the dataset + :param nr_columns: Number of columns (features) in the dataset :param df_target_stddev: The standard deviation of the target of the dataset :param train_observed_classes: :param target_class_distribution: @@ -77,6 +78,7 @@ class StatisticalAnalysis: """ # noqa nr_rows: int + nr_columns: int df_target_stddev: Optional[float] train_observed_classes: object # Union[None, List[str]] target_class_distribution: object # Dict[str, float] @@ -123,7 +125,7 @@ class TimeseriesSettings: :param target_type: Automatically inferred dtype of the target (e.g. `dtype.integer`, `dtype.float`). :param use_previous_target: Use the previous values of the target column to generate predictions. Defaults to True. :param allow_incomplete_history: whether predictions can be made for rows with incomplete historical context (i.e. less than `window` rows have been observed for the datetime that has to be forecasted). - :param eval_cold_start: whether to include predictions with incomplete history (thus part of the cold start region for certain mixers) when evaluating mixer scores with the validation dataset. + :param eval_incomplete: whether to consider predictions with incomplete history or target information when evaluating mixer accuracy with the validation dataset. :param interval_periods: tuple of tuples with user-provided period lengths for time intervals. Default values will be added for intervals left unspecified. For interval options, check the `timeseries_analyzer.detect_period()` method documentation. e.g.: (('daily', 7),). """ # noqa @@ -139,7 +141,7 @@ class TimeseriesSettings: # @TODO: George: No, I don't think it is, we need to pass this some other way ) allow_incomplete_history: bool = True - eval_cold_start: bool = True + eval_incomplete: bool = False interval_periods: tuple = tuple() @staticmethod @@ -170,7 +172,7 @@ def from_dict(obj: Dict): historical_columns=[], horizon=obj.get("horizon", 1), allow_incomplete_history=obj.get('allow_incomplete_history', True), - eval_cold_start=obj.get('eval_cold_start', True), + eval_incomplete=obj.get('eval_incomplete', False), interval_periods=obj.get('interval_periods', tuple(tuple())) ) for setting in obj: diff --git a/lightwood/data/statistical_analysis.py b/lightwood/data/statistical_analysis.py index 9744ac4ac..2fb48aa35 100644 --- a/lightwood/data/statistical_analysis.py +++ b/lightwood/data/statistical_analysis.py @@ -99,6 +99,7 @@ def statistical_analysis(data: pd.DataFrame, except Exception: order_format = None + nr_columns = len(data.columns) df = cleaner(data, dtypes, problem_definition.pct_invalid, identifiers, problem_definition.target, 'train', tss, problem_definition.anomaly_detection) @@ -204,6 +205,7 @@ def statistical_analysis(data: pd.DataFrame, log.info('Finished statistical analysis') return StatisticalAnalysis( nr_rows=nr_rows, + nr_columns=nr_columns, df_target_stddev=df_std, train_observed_classes=train_observed_classes, target_class_distribution=target_class_distribution, diff --git a/lightwood/data/timeseries_analyzer.py b/lightwood/data/timeseries_analyzer.py index e8abc795f..28d2f7525 100644 --- a/lightwood/data/timeseries_analyzer.py +++ b/lightwood/data/timeseries_analyzer.py @@ -150,7 +150,7 @@ def _pick_ST(tr_subset: pd.Series, dev_subset: pd.Series, sp: list): """ # noqa def _ST_objective(trial: optuna.Trial): - trend_degree = trial.suggest_categorical("trend_degree", [1, 2]) + trend_degree = trial.suggest_categorical("trend_degree", [1]) ds_sp = trial.suggest_categorical("ds_sp", sp) # seasonality period to use in deseasonalizer if min(min(tr_subset), min(dev_subset)) <= 0: decomp_type = trial.suggest_categorical("decomp_type", ['additive']) diff --git a/lightwood/encoder/categorical/autoencoder.py b/lightwood/encoder/categorical/autoencoder.py index 8e9f3dedf..b26e5ca14 100644 --- a/lightwood/encoder/categorical/autoencoder.py +++ b/lightwood/encoder/categorical/autoencoder.py @@ -30,6 +30,7 @@ def __init__( max_encoded_length: int = 100, desired_error: float = 0.01, batch_size: int = 200, + device: str = '', ): """ :param stop_after: Stops training with provided time limit (sec) @@ -37,6 +38,7 @@ def __init__( :param max_encoded_length: Maximum length of vector represented :param desired_error: Threshold for reconstruction accuracy error :param batch_size: Minimum batch size while training + :param device: Name of the device that get_device_from_name will attempt to use """ # noqa super().__init__(is_target) self.is_prepared = False @@ -48,6 +50,7 @@ def __init__( self.encoder = None self.decoder = None self.onehot_encoder = OneHotEncoder(is_target=self.is_target) + self.device_type = device # Training details self.batch_size = batch_size @@ -148,7 +151,7 @@ def _prepare_AE_input( # Prepare a one-hot encoder for CatAE inputs self.onehot_encoder.prepare(priming_data) - self.batch_size = min(self.batch_size, int(len(priming_data) / 50)) + self.batch_size = max(min(self.batch_size, int(len(priming_data) / 50)), 1) train_loader = DataLoader( list(zip(priming_data, priming_data)), @@ -170,7 +173,7 @@ def _prepare_catae(self, train_loader: DataLoader, dev_loader: DataLoader): """ # noqa input_len = self.onehot_encoder.output_size - self.net = DefaultNet(shape=[input_len, self.output_size, input_len]) + self.net = DefaultNet(shape=[input_len, self.output_size, input_len], device=self.device_type) criterion = torch.nn.CrossEntropyLoss() optimizer = Ranger(self.net.parameters()) diff --git a/lightwood/encoder/image/helpers/img_to_vec.py b/lightwood/encoder/image/helpers/img_to_vec.py index 553fbb349..48ef04b57 100644 --- a/lightwood/encoder/image/helpers/img_to_vec.py +++ b/lightwood/encoder/image/helpers/img_to_vec.py @@ -1,6 +1,6 @@ import torch import torch.nn as nn -from lightwood.helpers.device import get_devices +from lightwood.helpers.device import get_device_from_name from lightwood.helpers.torch import LightwoodAutocast from lightwood.helpers.log import log @@ -33,16 +33,17 @@ class Img2Vec(nn.Module): Output is a `self.output_size`-dimensioned vector, generated by taking the output of the Resnext's last convolutional layer and performing an adaptive channel pool average. """ # noqa - def __init__(self): + def __init__(self, device=''): super(Img2Vec, self).__init__() - self.device, _ = get_devices() + self.device = get_device_from_name(device) + self.output_size = 512 self.model = torch.nn.Sequential(*list(models.resnext50_32x4d(pretrained=True).children())[: -1], ChannelPoolAdaptiveAvg1d(output_size=self.output_size)) self.model = self.model.to(self.device) - def to(self, device, available_devices): + def to(self, device, available_devices=1): self.device = device self.model = self.model.to(self.device) return self diff --git a/lightwood/encoder/image/img_2_vec.py b/lightwood/encoder/image/img_2_vec.py index 97fbe5720..30533e1a8 100644 --- a/lightwood/encoder/image/img_2_vec.py +++ b/lightwood/encoder/image/img_2_vec.py @@ -31,6 +31,7 @@ def __init__( scale: Tuple[int, int] = (224, 224), mean: List[float] = [0.485, 0.456, 0.406], std: List[float] = [0.229, 0.224, 0.225], + device: str = '', ): """ :param stop_after: time budget, in seconds. @@ -38,9 +39,11 @@ def __init__( :param scale: Resize scale of image (x, y) :param mean: Mean of pixel values :param std: Standard deviation of pixel values + :param device: Name of the device that get_device_from_name will attempt to use """ # noqa assert not is_target super().__init__(is_target) + self.is_prepared = False self.scale = scale self.mean = mean @@ -56,6 +59,8 @@ def __init__( ]) self.stop_after = stop_after + self.device_name = device + # pil_logger = logging.getLogger('PIL') # noqa # pil_logger.setLevel(logging.ERROR) # noqa @@ -67,11 +72,13 @@ def prepare(self, train_priming_data: Iterable[str], dev_priming_data: Iterable[ if self.is_prepared: raise Exception('You can only call "prepare" once for a given encoder.') - self.model = Img2Vec() + self.model = Img2Vec(device=self.device_name) + self.device = self.model.device + self.device_name = f'{self.device}' self.output_size = self.model.output_size self.is_prepared = True - def to(self, device, available_devices): + def to(self, device, available_devices=1): """ Changes device of model to support CPU/GPU @@ -80,7 +87,7 @@ def to(self, device, available_devices): :return: same object but moved to the target device. """ - self.model.to(device, available_devices) + self.model.to(device, available_devices=1) return self def encode(self, images: List[str]) -> torch.Tensor: diff --git a/lightwood/encoder/text/helpers/rnn_helpers.py b/lightwood/encoder/text/helpers/rnn_helpers.py index 7bda125a9..2d9d3d140 100644 --- a/lightwood/encoder/text/helpers/rnn_helpers.py +++ b/lightwood/encoder/text/helpers/rnn_helpers.py @@ -101,7 +101,7 @@ from lightwood.helpers.torch import LightwoodAutocast from lightwood.helpers.log import log -device = torch.device("cuda" if torch.cuda.is_available() else "cpu") +default_device = torch.device("cuda" if torch.cuda.is_available() else "cpu") ###################################################################### # Loading data files @@ -344,13 +344,22 @@ def prepareData(lang1, lang2, reverse=False): # class EncoderRNN(nn.Module): - def __init__(self, input_size, hidden_size): + def __init__(self, + input_size, + hidden_size, + device=''): super(EncoderRNN, self).__init__() self.hidden_size = hidden_size self.embedding = nn.Embedding(input_size, hidden_size) self.gru = nn.GRU(hidden_size, hidden_size) + if(device == ''): + device = default_device + else: + device = torch.device(device) + self.device = device + def forward(self, input, hidden): with LightwoodAutocast(): embedded = self.embedding(input).view(1, 1, -1) @@ -359,7 +368,7 @@ def forward(self, input, hidden): return output, hidden def initHidden(self): - return torch.zeros(1, 1, self.hidden_size, device=device) + return torch.zeros(1, 1, self.hidden_size, device=self.device) ###################################################################### # The Decoder @@ -390,7 +399,7 @@ def initHidden(self): # class DecoderRNN(nn.Module): - def __init__(self, hidden_size, output_size): + def __init__(self, hidden_size, output_size, device=''): super(DecoderRNN, self).__init__() self.hidden_size = hidden_size @@ -399,6 +408,12 @@ def __init__(self, hidden_size, output_size): self.out = nn.Linear(hidden_size, output_size) self.softmax = nn.LogSoftmax(dim=1) + if(device == ''): + device = default_device + else: + device = torch.device(device) + self.device = device + def forward(self, input, hidden): with LightwoodAutocast(): output = self.embedding(input).view(1, 1, -1) @@ -408,7 +423,7 @@ def forward(self, input, hidden): return output, hidden def initHidden(self): - return torch.zeros(1, 1, self.hidden_size, device=device) + return torch.zeros(1, 1, self.hidden_size, device=self.device) ###################################################################### # I encourage you to train and observe the results of this model, but to @@ -449,7 +464,12 @@ def initHidden(self): # class AttnDecoderRNN(nn.Module): - def __init__(self, hidden_size, output_size, dropout_p=0.1, max_length=MAX_LENGTH): + def __init__(self, + hidden_size, + output_size, + dropout_p=0.1, + max_length=MAX_LENGTH, + device=''): super(AttnDecoderRNN, self).__init__() self.hidden_size = hidden_size self.output_size = output_size @@ -463,6 +483,12 @@ def __init__(self, hidden_size, output_size, dropout_p=0.1, max_length=MAX_LENGT self.gru = nn.GRU(self.hidden_size, self.hidden_size) self.out = nn.Linear(self.hidden_size, self.output_size) + if(device == ''): + device = default_device + else: + device = torch.device(device) + self.device = device + def forward(self, input, hidden, encoder_outputs): with LightwoodAutocast(): embedded = self.embedding(input).view(1, 1, -1) @@ -483,7 +509,7 @@ def forward(self, input, hidden, encoder_outputs): return output, hidden, attn_weights def initHidden(self): - return torch.zeros(1, 1, self.hidden_size, device=device) + return torch.zeros(1, 1, self.hidden_size, device=self.device) ###################################################################### @@ -509,18 +535,12 @@ def indexesFromSentence(lang, sentence): return [lang.word2index[word] if word in lang.word2index else UNK_TOKEN for word in (str(sentence).split(' ') if sentence is not None else [None])] -def tensorFromSentence(lang, sentence): +def tensorFromSentence(lang, sentence, device=default_device): indexes = indexesFromSentence(lang, sentence) indexes.append(EOS_token) return torch.tensor(indexes, dtype=torch.long, device=device).view(-1, 1) -def tensorsFromPair(pair, input_lang, output_lang): - input_tensor = tensorFromSentence(input_lang, pair[0]) - target_tensor = tensorFromSentence(output_lang, pair[1]) - return (input_tensor, target_tensor) - - ###################################################################### # Training the Model # ------------------ @@ -552,7 +572,8 @@ def tensorsFromPair(pair, input_lang, output_lang): def train( input_tensor, target_tensor, encoder, decoder, encoder_optimizer, decoder_optimizer, criterion, - max_length=MAX_LENGTH): + max_length=MAX_LENGTH, device=default_device): + encoder_hidden = encoder.initHidden() encoder_optimizer.zero_grad() @@ -645,8 +666,19 @@ def timeSince(since, percent): # of examples, time so far, estimated time) and average loss. # -def trainIters(encoder, decoder, input_lang, output_lang, input_rows, output_rows, n_iters, print_every=1000, - plot_every=100, learning_rate=0.01, loss_breakpoint=0.0001, max_length=MAX_LENGTH): +def trainIters(encoder, + decoder, + input_lang, + output_lang, + input_rows, + output_rows, + n_iters, + print_every=1000, + plot_every=100, + learning_rate=0.01, + loss_breakpoint=0.0001, + max_length=MAX_LENGTH, + device=default_device): start = time.time() plot_losses = [] print_loss_total = 0 # Reset every print_every @@ -657,8 +689,11 @@ def trainIters(encoder, decoder, input_lang, output_lang, input_rows, output_row random_index = random.randint(0, len(input_rows)) - training_pairs = [[tensorFromSentence(input_lang, input_rows[random_index]), tensorFromSentence( - output_lang, output_rows[random_index])] for i in range(n_iters)] + training_pairs = [ + [ + tensorFromSentence(input_lang, input_rows[random_index], device=device), + tensorFromSentence(output_lang, output_rows[random_index], device=device) + ] for i in range(n_iters) ] criterion = nn.NLLLoss() for iter in range(1, n_iters + 1): @@ -667,7 +702,7 @@ def trainIters(encoder, decoder, input_lang, output_lang, input_rows, output_row target_tensor = training_pair[1] loss = train(input_tensor, target_tensor, encoder, - decoder, encoder_optimizer, decoder_optimizer, criterion, max_length) + decoder, encoder_optimizer, decoder_optimizer, criterion, max_length, device=device) print_loss_total += loss plot_loss_total += loss @@ -705,9 +740,9 @@ def trainIters(encoder, decoder, input_lang, output_lang, input_rows, output_row # attention outputs for display later. # -def evaluate(encoder, decoder, input_lang, output_lang, sentence, max_length=MAX_LENGTH): +def evaluate(encoder, decoder, input_lang, output_lang, sentence, max_length=MAX_LENGTH, device=default_device): with torch.no_grad(): - input_tensor = tensorFromSentence(input_lang, sentence) + input_tensor = tensorFromSentence(input_lang, sentence, device=device) input_length = input_tensor.size()[0] encoder_hidden = encoder.initHidden() @@ -746,12 +781,13 @@ def evaluate(encoder, decoder, input_lang, output_lang, sentence, max_length=MAX # input, target, and output to make some subjective quality judgements: # -def evaluateRandomly(encoder, pairs, decoder, n=10, max_length=MAX_LENGTH): +# this function is never used? +def evaluateRandomly(encoder, pairs, decoder, n=10, max_length=MAX_LENGTH, device=default_device): for i in range(n): pair = random.choice(pairs) log.debug('>', pair[0]) log.debug('=', pair[1]) - output_words, attentions = evaluate(encoder, decoder, pair[0], max_length=MAX_LENGTH) + output_words, attentions = evaluate(encoder, decoder, pair[0], max_length=MAX_LENGTH, device=device) output_sentence = ' '.join(output_words) log.debug('<', output_sentence) log.debug('') diff --git a/lightwood/encoder/text/pretrained.py b/lightwood/encoder/text/pretrained.py index 3ba0815ec..db9e5c320 100644 --- a/lightwood/encoder/text/pretrained.py +++ b/lightwood/encoder/text/pretrained.py @@ -6,7 +6,7 @@ import os import pandas as pd from lightwood.encoder.text.helpers.pretrained_helpers import TextEmbed -from lightwood.helpers.device import get_devices +from lightwood.helpers.device import get_device_from_name from lightwood.encoder.base import BaseEncoder from lightwood.helpers.log import log from lightwood.helpers.torch import LightwoodAutocast @@ -42,6 +42,7 @@ def __init__( epochs: int = 1, output_type: str = None, embed_mode: bool = True, + device: str = '', ): """ :param is_target: Whether this encoder represents the target. NOT functional for text generation yet. @@ -52,6 +53,7 @@ def __init__( :param epochs: number of epochs to train model with :param output_type: Data dtype of the target; if categorical/binary, the option to return logits is possible. :param embed_mode: If True, assumes the output of the encode() step is the CLS embedding (this can be trained or not). If False, returns the logits of the tuned task. + :param device: name of the device that get_device_from_name will attempt to use. """ # noqa super().__init__(is_target) @@ -73,7 +75,8 @@ def __init__( self._pretrained_model_name = "distilbert-base-uncased" self._tokenizer = DistilBertTokenizerFast.from_pretrained(self._pretrained_model_name) - self.device, _ = get_devices() + self.device = get_device_from_name(device) + self.stop_after = stop_after self.embed_mode = embed_mode diff --git a/lightwood/encoder/text/rnn.py b/lightwood/encoder/text/rnn.py index 11f909620..275e58c3e 100644 --- a/lightwood/encoder/text/rnn.py +++ b/lightwood/encoder/text/rnn.py @@ -7,8 +7,13 @@ class RnnEncoder(BaseEncoder): - def __init__(self, encoded_vector_size=256, train_iters=75000, stop_on_error=0.0001, - learning_rate=0.01, is_target=False): + def __init__(self, + encoded_vector_size=256, + train_iters=75000, + stop_on_error=0.0001, + learning_rate=0.01, + is_target=False, + device=''): super().__init__(is_target) self._stop_on_error = stop_on_error self._learning_rate = learning_rate @@ -18,6 +23,11 @@ def __init__(self, encoded_vector_size=256, train_iters=75000, stop_on_error=0.0 self._output_lang = None self._encoder = None self._decoder = None + if(device == ''): + device = default_device + else: + device = torch.device(device) + self.device = device def prepare(self, priming_data): if self.is_prepared: @@ -39,12 +49,21 @@ def prepare(self, priming_data): max_length = max(map(len, no_null_sentences)) hidden_size = self._encoded_vector_size - self._encoder = EncoderRNN(self._input_lang.n_words, hidden_size).to(device) - self._decoder = DecoderRNN(hidden_size, self._output_lang.n_words).to(device) - - trainIters(self._encoder, self._decoder, self._input_lang, self._output_lang, no_null_sentences, - no_null_sentences, self._train_iters, int(log_every), - self._learning_rate, self._stop_on_error, max_length) + self._encoder = EncoderRNN(self._input_lang.n_words, hidden_size).to(self.device) + self._decoder = DecoderRNN(hidden_size, self._output_lang.n_words).to(self.device) + + trainIters(self._encoder, + self._decoder, + self._input_lang, + self._output_lang, + no_null_sentences, + no_null_sentences, + self._train_iters, + print_every=int(log_every), + learning_rate=self._learning_rate, + loss_breakpoint=self._stop_on_error, + max_length=max_length, + device=self.device) self.is_prepared = True @@ -58,10 +77,10 @@ def encode(self, column_data): for row in no_null_sentences: encoder_hidden = self._encoder.initHidden() - input_tensor = tensorFromSentence(self._input_lang, row) + input_tensor = tensorFromSentence(self._input_lang, row, device=self.device) input_length = input_tensor.size(0) - #encoder_outputs = torch.zeros(max_length, encoder.hidden_size, device=device) + #encoder_outputs = torch.zeros(max_length, encoder.hidden_size, device=self.device) loss = 0 @@ -80,9 +99,9 @@ def decode(self, encoded_values_tensor, max_length=100): ret = [] with torch.no_grad(): for decoder_hiddens in encoded_values_tensor: - decoder_hidden = torch.FloatTensor([[decoder_hiddens.tolist()]]).to(device) + decoder_hidden = torch.FloatTensor([[decoder_hiddens.tolist()]]).to(self.device) - decoder_input = torch.tensor([[SOS_token]], device=device) # SOS + decoder_input = torch.tensor([[SOS_token]], device=self.device) # SOS decoded_words = [] diff --git a/lightwood/encoder/text/short.py b/lightwood/encoder/text/short.py index a3c70da63..1fd06fb6c 100644 --- a/lightwood/encoder/text/short.py +++ b/lightwood/encoder/text/short.py @@ -8,7 +8,7 @@ class ShortTextEncoder(BaseEncoder): - def __init__(self, is_target=False, mode=None): + def __init__(self, is_target=False, mode=None, device=''): """ :param is_target: :param mode: @@ -16,6 +16,7 @@ def __init__(self, is_target=False, mode=None): When None, it will be set automatically based on is_target: (is_target) -> 'concat' (not is_target) -> 'mean' + :param device: name of the device that get_device_from_name will attempt to use. """ super().__init__(is_target) @@ -36,7 +37,7 @@ def __init__(self, is_target=False, mode=None): # Defined in self.prepare() self._combine_fn = None self.max_words_per_sent = None - self.cae = CategoricalAutoEncoder(is_target=is_target, max_encoded_length=100) + self.cae = CategoricalAutoEncoder(is_target=is_target, max_encoded_length=100, device=device) self.is_prepared = False def _unexpected_mode(self): diff --git a/lightwood/encoder/time_series/rnn.py b/lightwood/encoder/time_series/rnn.py index a6b76317d..b267fe717 100644 --- a/lightwood/encoder/time_series/rnn.py +++ b/lightwood/encoder/time_series/rnn.py @@ -12,7 +12,7 @@ from lightwood.api import dtype from lightwood.helpers.log import log from lightwood.encoder.base import BaseEncoder -from lightwood.helpers.device import get_devices +from lightwood.helpers.device import get_device_from_name from lightwood.helpers.torch import LightwoodAutocast from lightwood.encoder.datetime import DatetimeNormalizerEncoder from lightwood.encoder.time_series.helpers.rnn_helpers import EncoderRNNNumerical, DecoderRNNNumerical @@ -30,10 +30,16 @@ class TimeSeriesEncoder(BaseEncoder): is_timeseries_encoder: bool = True is_trainable_encoder: bool = True - def __init__(self, stop_after: float, is_target=False, original_type: str = None, target: str = None, - grouped_by: List[str] = [], encoder_type='rnn'): + def __init__(self, + stop_after: float, + is_target: bool = False, + original_type: str = None, + target: str = None, + grouped_by: List[str] = [], + encoder_type: str = 'rnn', + device: str = ''): super().__init__(is_target) - self.device, _ = get_devices() + self.device = get_device_from_name(device) self.target = target self.grouped_by = grouped_by self._learning_rate = 0.01 diff --git a/lightwood/helpers/device.py b/lightwood/helpers/device.py index 528ef8ff1..8b1864231 100644 --- a/lightwood/helpers/device.py +++ b/lightwood/helpers/device.py @@ -36,3 +36,17 @@ def get_devices(): available_devices = 0 return torch.device(device_str), available_devices + + +def get_device_from_name(device_name=''): + """ + Returns the device specified as an argument. + If the argument is left empty it will returns the output of get_devices(). + + :param device_name: name of the device to use (default is an empty string), if is an empty string will use the output of get_devices() instead") + """ # noqa E501 + if(device_name != ''): + device = torch.device(device_name) + else: + device, _ = get_devices() + return device diff --git a/lightwood/helpers/general.py b/lightwood/helpers/general.py index cbec5eaaa..ff54fdfad 100644 --- a/lightwood/helpers/general.py +++ b/lightwood/helpers/general.py @@ -4,6 +4,7 @@ import numpy as np import pandas as pd from sklearn.metrics import r2_score, f1_score, mean_absolute_error, balanced_accuracy_score +from sktime.performance_metrics.forecasting import mean_absolute_percentage_error from lightwood.helpers.numeric import is_nan_numeric from lightwood.helpers.ts import get_group_matches @@ -41,7 +42,9 @@ def evaluate_accuracy(data: pd.DataFrame, gby = ts_analysis.get('tss', {}).group_by if ts_analysis.get('tss', {}).group_by else [] cols = [target] + [f'{target}_timestep_{i}' for i in range(1, horizon)] + gby true_values = data[cols] - predictions = predictions.apply(pd.Series) # split array cells into columns + + true_values = true_values.reset_index(drop=True) + predictions = predictions.apply(pd.Series).reset_index(drop=True) # split array cells into columns if accuracy_function_str == 'evaluate_array_accuracy': acc_fn = evaluate_array_accuracy @@ -49,8 +52,11 @@ def evaluate_accuracy(data: pd.DataFrame, acc_fn = evaluate_num_array_accuracy elif accuracy_function_str == 'evaluate_cat_array_accuracy': acc_fn = evaluate_cat_array_accuracy + elif accuracy_function_str == 'complementary_smape_array_accuracy': + acc_fn = complementary_smape_array_accuracy else: acc_fn = bounded_ts_accuracy + score_dict[accuracy_function_str] = acc_fn(true_values, predictions, data=data[cols], @@ -171,12 +177,6 @@ def evaluate_array_accuracy( base_acc_fn = kwargs.get('base_acc_fn', lambda t, p: max(0, r2_score(t, p))) fh = true_values.shape[1] - ts_analysis = kwargs.get('ts_analysis', None) - - if ts_analysis and ts_analysis.get('tss', False) and not kwargs['ts_analysis']['tss'].eval_cold_start: - # only evaluate accuracy for rows with complete historical context - true_values = true_values[kwargs['ts_analysis']['tss'].window:] - predictions = predictions[kwargs['ts_analysis']['tss'].window:] aggregate = 0.0 for i in range(fh): @@ -238,6 +238,35 @@ def bounded_ts_accuracy( return result / 2 # worse than naive +def complementary_smape_array_accuracy( + true_values: pd.Series, + predictions: pd.Series, + **kwargs +) -> float: + """ + This metric is used in forecasting tasks. It returns ``1 - (sMAPE/2)``, where ``sMAPE`` is the symmetrical mean absolute percentage error of the forecast versus actual measurements in the time series. + + As such, its domain is 0-1 bounded. + """ # noqa + y_true = deepcopy(true_values) + y_pred = deepcopy(predictions) + tss = kwargs.get('ts_analysis', {}).get('tss', False) + if tss and tss.group_by: + [y_true.pop(gby_col) for gby_col in kwargs['ts_analysis']['tss'].group_by] + + # nan check + y_true = y_true.values + y_pred = y_pred.values + if np.isnan(y_true).any(): + # convert all nan indexes to zero pairs that don't contribute to the metric + nans = np.isnan(y_true) + y_true[nans] = 0 + y_pred[nans] = 0 + + smape_score = mean_absolute_percentage_error(y_true, y_pred, symmetric=True) + return 1 - smape_score / 2 + + # ------------------------- # # Helpers # ------------------------- # diff --git a/lightwood/helpers/seed.py b/lightwood/helpers/seed.py index 5398505fe..815fdc121 100644 --- a/lightwood/helpers/seed.py +++ b/lightwood/helpers/seed.py @@ -1,6 +1,7 @@ +import random import torch import numpy as np -import random +import mxnet as mx def seed(seed_nr: int) -> None: @@ -9,3 +10,4 @@ def seed(seed_nr: int) -> None: torch.backends.cudnn.benchmark = False np.random.seed(seed_nr) random.seed(seed_nr) + mx.random.seed(seed_nr) diff --git a/lightwood/helpers/ts.py b/lightwood/helpers/ts.py index 0ace035b3..c660773e1 100644 --- a/lightwood/helpers/ts.py +++ b/lightwood/helpers/ts.py @@ -286,3 +286,24 @@ def min_k(top_k, data): candidate_sps[group] = [1] return candidate_sps + + +def filter_ds(ds, tss, n_rows=1): + """ + This method triggers only for timeseries datasets. + + It returns a dataframe that filters out all but the first ``n_rows`` per group. + """ # noqa + df = ds.data_frame + if tss.is_timeseries: + gby = tss.group_by + if gby is None: + df = df.iloc[[0]] + else: + ndf = pd.DataFrame(columns=df.columns) + for group in get_ts_groups(df, tss): + if group != '__default': + _, subdf = get_group_matches(df, group, tss.group_by) + ndf = pd.concat([ndf, subdf.iloc[:n_rows]]) + df = ndf + return df diff --git a/lightwood/mixer/__init__.py b/lightwood/mixer/__init__.py index 6e8ef88b6..5db41b169 100644 --- a/lightwood/mixer/__init__.py +++ b/lightwood/mixer/__init__.py @@ -1,14 +1,14 @@ -from lightwood.mixer.unit import Unit from lightwood.mixer.base import BaseMixer +from lightwood.mixer.unit import Unit from lightwood.mixer.neural import Neural from lightwood.mixer.neural_ts import NeuralTs from lightwood.mixer.lightgbm import LightGBM +from lightwood.mixer.random_forest import RandomForest from lightwood.mixer.lightgbm_array import LightGBMArray from lightwood.mixer.sktime import SkTime from lightwood.mixer.arima import ARIMAMixer from lightwood.mixer.ets import ETSMixer -from lightwood.mixer.nhits import NHitsMixer -from lightwood.mixer.prophet import ProphetMixer +from lightwood.mixer.gluonts import GluonTSMixer from lightwood.mixer.regression import Regression try: @@ -16,5 +16,15 @@ except Exception: QClassic = None -__all__ = ['BaseMixer', 'Neural', 'NeuralTs', 'LightGBM', 'LightGBMArray', 'Unit', 'Regression', - 'SkTime', 'QClassic', 'ProphetMixer', 'ETSMixer', 'ARIMAMixer', 'NHitsMixer'] +try: + from lightwood.mixer.nhits import NHitsMixer +except Exception: + NHitsMixer = None + +try: + from lightwood.mixer.prophet import ProphetMixer +except Exception: + ProphetMixer = None + +__all__ = ['BaseMixer', 'Neural', 'NeuralTs', 'LightGBM', 'RandomForest', 'LightGBMArray', 'Unit', 'Regression', + 'SkTime', 'QClassic', 'ProphetMixer', 'ETSMixer', 'ARIMAMixer', 'NHitsMixer', 'GluonTSMixer'] diff --git a/lightwood/mixer/gluonts.py b/lightwood/mixer/gluonts.py new file mode 100644 index 000000000..ea448bc78 --- /dev/null +++ b/lightwood/mixer/gluonts.py @@ -0,0 +1,188 @@ +from copy import deepcopy +from typing import Dict, Union + +import numpy as np +import pandas as pd + +from gluonts.dataset.pandas import PandasDataset + +from gluonts.model.deepar import DeepAREstimator # @TODO: support for other estimators +from gluonts.mx import Trainer +from gluonts.mx.trainer.callback import TrainingHistory + +from lightwood.helpers.log import log +from lightwood.mixer.base import BaseMixer +from lightwood.api.types import PredictionArguments +from lightwood.data.encoded_ds import EncodedDs, ConcatedEncodedDs + + +class GluonTSMixer(BaseMixer): + horizon: int + target: str + supports_proba: bool + model_path: str + hyperparam_search: bool + default_config: dict + + def __init__( + self, + stop_after: float, + target: str, + horizon: int, + window: int, + dtype_dict: Dict, + ts_analysis: Dict, + n_epochs: int = 10, + early_stop_patience: int = 3 + ): + """ + Wrapper around GluonTS probabilistic deep learning models. For now, only DeepAR is supported. + + :param stop_after: time budget in seconds. + :param target: column to forecast. + :param horizon: length of forecasted horizon. + :param window: length of input data. + :param dtype_dict: data type of each column in the dataset. + :param ts_analysis: dictionary with miscellaneous time series info, as generated by 'lightwood.data.timeseries_analyzer'. + :param n_epochs: amount of epochs to train the model for. Will perform early stopping automatically if validation loss degrades. + :param early_stop_patience: amount of consecutive epochs with no improvement in the validation loss. + """ # noqa + super().__init__(stop_after) + self.stable = True + self.prepared = False + self.supports_proba = True + self.target = target + self.window = window + self.horizon = horizon + self.n_epochs = n_epochs + self.dtype_dict = dtype_dict + self.ts_analysis = ts_analysis + self.grouped_by = ['__default'] if not ts_analysis['tss'].group_by else ts_analysis['tss'].group_by + self.model = None + self.train_cache = None + self.patience = early_stop_patience + + def fit(self, train_data: EncodedDs, dev_data: EncodedDs) -> None: + """ Fits the model. """ # noqa + log.info('Started fitting GluonTS forecasting model') + + # prepare data + cat_ds = ConcatedEncodedDs([train_data, dev_data]) + train_ds = self._make_initial_ds(cat_ds.data_frame, train=True) + + estimator = DeepAREstimator( + freq=train_ds.freq, + prediction_length=self.horizon, + trainer=Trainer(epochs=self.n_epochs, callbacks=[EarlyStop(patience=self.patience)]) + ) + self.model = estimator.train(train_ds) + log.info('Successfully trained GluonTS forecasting model.') + + def partial_fit(self, train_data: EncodedDs, dev_data: EncodedDs) -> None: + """ + Due to how lightwood implements the `update` procedure, expected inputs for this method are: + + :param dev_data: original `test` split (used to validate and select model if ensemble is `BestOf`). + :param train_data: concatenated original `train` and `dev` splits. + """ # noqa + self.hyperparam_search = False + self.fit(dev_data, train_data) + self.prepared = True + + def __call__(self, ds: Union[EncodedDs, ConcatedEncodedDs], + args: PredictionArguments = PredictionArguments()) -> pd.DataFrame: + """ + Calls the mixer to emit forecasts. + """ # noqa + length = sum(ds.encoded_ds_lenghts) if isinstance(ds, ConcatedEncodedDs) else len(ds) + ydf = pd.DataFrame(0, # zero-filled + index=np.arange(length), + columns=['prediction', 'lower', 'upper'], + dtype=object) + ydf['index'] = ds.data_frame.index + conf = args.fixed_confidence if args.fixed_confidence else 0.9 + ydf['confidence'] = conf + + gby = self.ts_analysis["tss"].group_by if self.ts_analysis["tss"].group_by else [] + groups = ds.data_frame[gby[0]].unique().tolist() if gby else None + + for idx in range(length): + df = ds.data_frame.iloc[:idx] if idx != 0 else None + input_ds = self._make_initial_ds(df, groups=groups) + if not input_ds: + # edge case: new group + for col in ['prediction', 'lower', 'upper']: + ydf.at[idx, col] = [0 for _ in range(self.ts_analysis["tss"].horizon)] + else: + forecasts = list(self.model.predict(input_ds))[0] + ydf.at[idx, 'prediction'] = [entry for entry in forecasts.quantile(0.5)] + ydf.at[idx, 'lower'] = [entry for entry in forecasts.quantile(1 - conf)] + ydf.at[idx, 'upper'] = [entry for entry in forecasts.quantile(conf)] + + return ydf + + def _make_initial_ds(self, df=None, train=False, groups=None): + oby = self.ts_analysis["tss"].order_by + gby = self.ts_analysis["tss"].group_by if self.ts_analysis["tss"].group_by else [] + freq = self.ts_analysis['sample_freqs']['__default'] + keep_cols = [f'__mdb_original_{oby}', self.target] + [col for col in gby] + + if df is None and not train: + df = self.train_cache + if gby: + df = df[df[gby[0]].isin(groups)] + else: + sub_df = df[keep_cols] + df = deepcopy(sub_df) + + if train: + self.train_cache = df + else: + if gby: + cache = self.train_cache[self.train_cache[gby[0]].isin(groups)] + else: + cache = self.train_cache + df = pd.concat([cache, df]).sort_index() + + df = df.drop_duplicates() # .reset_index(drop=True) + + if len(df) == 0: + return None + + if gby: + df = df.groupby(by=gby[0]).resample(freq).sum().reset_index(level=[0]) + # @TODO: multiple group support and remove groups without enough data + else: + df = df.resample(freq).sum() + gby = '__default_group' + df[gby] = '__default_group' + + ds = PandasDataset.from_long_dataframe(df, target=self.target, item_id=gby, freq=freq) + return ds + + +class EarlyStop(TrainingHistory): + def __init__(self, patience=3): + super().__init__() + self.patience = max(1, patience) + self.counter = 0 + + def on_validation_epoch_end( + self, + epoch_no: int, + epoch_loss: float, + training_network, + trainer, + ) -> bool: + super().on_validation_epoch_end(epoch_no, epoch_loss, training_network, trainer) + + if len(self.validation_loss_history) > 1: + if self.validation_loss_history[-1] > self.validation_loss_history[-2]: + self.counter += 1 + else: + self.counter = 0 # reset if not successive + + if self.counter >= self.patience: + return False + else: + return True diff --git a/lightwood/mixer/helpers/default_net.py b/lightwood/mixer/helpers/default_net.py index a62467063..ed738f078 100644 --- a/lightwood/mixer/helpers/default_net.py +++ b/lightwood/mixer/helpers/default_net.py @@ -1,7 +1,7 @@ import math import torch from lightwood.helpers.torch import LightwoodAutocast -from lightwood.helpers.device import get_devices +from lightwood.helpers.device import get_device_from_name from lightwood.helpers.log import log import numpy as np @@ -19,9 +19,11 @@ def __init__(self, shape: list = None, max_params: int = int(3e7), num_hidden: int = 1, - dropout: float = 0) -> None: + dropout: float = 0, + device: str = '') -> None: super(DefaultNet, self).__init__() + if input_size is not None and output_size is not None: self.input_size = input_size self.output_size = output_size @@ -49,7 +51,8 @@ def __init__(self, raise Exception('You must specify other a shape or an input and output size when creating a DefaultNet!') self.net = torch.nn.Sequential(*layers) - self.to(get_devices()[0]) + + self.to(get_device_from_name(device)) def to(self, device: torch.device) -> torch.nn.Module: if 'cuda' not in str(torch.device) == 0: diff --git a/lightwood/mixer/helpers/residual_net.py b/lightwood/mixer/helpers/residual_net.py index d8a738cc5..9a6aba183 100644 --- a/lightwood/mixer/helpers/residual_net.py +++ b/lightwood/mixer/helpers/residual_net.py @@ -2,7 +2,7 @@ import torch from torch import nn from lightwood.helpers.torch import LightwoodAutocast -from lightwood.helpers.device import get_devices +from lightwood.helpers.device import get_device_from_name, get_devices from lightwood.helpers.log import log @@ -38,7 +38,8 @@ def __init__(self, input_size: int = None, output_size: int = None, shape: List[int] = None, - max_params: int = int(3e5)) -> None: + max_params: int = int(3e5), + device: str = '') -> None: super(ResidualNet, self).__init__() self.net = torch.nn.Sequential( * @@ -46,9 +47,15 @@ def __init__(self, [nn.Linear(input_size, max([input_size * 2, output_size * 2, 400])), nn.Linear(max([input_size * 2, output_size * 2, 400]), output_size)])) - self.to(*get_devices()) - def to(self, device: torch.device, available_devices: int) -> torch.nn.Module: + if(device == ''): + device, available_devices = get_devices() + else: + device = get_device_from_name(device) + available_devices = 0 + self.to(device, available_devices) + + def to(self, device: torch.device, available_devices: int = 1) -> torch.nn.Module: self.net = self.net.to(device) if available_devices > 1: self.dp_wrapper_net = torch.nn.DataParallel(self.net) diff --git a/lightwood/mixer/random_forest.py b/lightwood/mixer/random_forest.py new file mode 100644 index 000000000..3a821cd19 --- /dev/null +++ b/lightwood/mixer/random_forest.py @@ -0,0 +1,218 @@ +import time +import math +import torch +import numpy as np +import pandas as pd +import optuna +from typing import Dict, Union +from optuna import trial as trial_module +from sklearn.model_selection import check_cv, cross_val_predict +from sklearn.metrics import mean_squared_error +from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier + +from lightwood.api import dtype +from lightwood.helpers.log import log +from lightwood.encoder.base import BaseEncoder +from lightwood.data.encoded_ds import ConcatedEncodedDs, EncodedDs +from lightwood.mixer.base import BaseMixer +from lightwood.api.types import PredictionArguments + + +class RandomForest(BaseMixer): + model: Union[RandomForestClassifier, RandomForestRegressor] + dtype_dict: dict + target: str + fit_on_dev: bool + use_optuna: bool + supports_proba: bool + + def __init__( + self, + stop_after: float, + target: str, + dtype_dict: Dict[str, str], + fit_on_dev: bool, + use_optuna: bool, + target_encoder: BaseEncoder + ): + """ + The `RandomForest` mixer supports both regression and classification tasks. + It inherits from sklearn.ensemble.RandomForestRegressor and sklearn.ensemble.RandomForestClassifier. + (https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestRegressor.html) + (https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html) + + :param stop_after: time budget in seconds. + :param target: name of the target column that the mixer will learn to predict. + :param dtype_dict: dictionary with dtypes of all columns in the data. + :param fit_on_dev: whether to fit on the dev dataset. + :param use_optuna: whether to activate the automated hyperparameter search (optuna-based). Note that setting this flag to `True` does not guarantee the search will run, rather, the speed criteria will be checked first (i.e., if a single iteration is too slow with respect to the time budget, the search will not take place). + """ # noqa + super().__init__(stop_after) + self.target = target + self.dtype_dict = dtype_dict + self.fit_on_dev = fit_on_dev + self.use_optuna = use_optuna + self.target_encoder = target_encoder + + self.model = None + self.positive_domain = False + self.num_trials = 20 + self.cv = 3 + self.map = {} + + self.cls_dtypes = [dtype.categorical, dtype.binary, dtype.cat_tsarray] + self.float_dtypes = [dtype.float, dtype.quantity, dtype.num_tsarray] + self.num_dtypes = [dtype.integer] + self.float_dtypes + self.supports_proba = dtype_dict[target] in self.cls_dtypes + self.is_classifier = self.supports_proba + + self.stable = True + + def _multi_logloss(self, y_true: np.ndarray, y_pred: np.ndarray, eps: float = 1e-15): + # ('evaluate model effects' not use this function) + y_pred = np.clip(y_pred, eps, 1 - eps) + score = np.mean([-math.log(y_pred[i][self.map[y]]) for i, y in enumerate(y_true)]) + + return score + + def fit(self, train_data: EncodedDs, dev_data: EncodedDs) -> None: + """ + Fits the RandomForest model. + + :param train_data: encoded features for training dataset + :param dev_data: encoded features for dev dataset + """ + started = time.time() + log.info('Started fitting RandomForest model') + + output_dtype = self.dtype_dict[self.target] + + if output_dtype not in self.cls_dtypes + self.num_dtypes: + log.error(f'RandomForest mixer not supported for type: {output_dtype}') + raise Exception(f'RandomForest mixer not supported for type: {output_dtype}') + + # concat the data if fit on dev + if self.fit_on_dev: + train_data = ConcatedEncodedDs([train_data, dev_data]) + + # initialize the model + if self.is_classifier: + X = train_data.get_encoded_data(include_target=False) + Y = train_data.get_column_original_data(self.target) + + self.model = RandomForestClassifier( + n_estimators=50, + max_depth=5, + max_features=1., + bootstrap=True, + n_jobs=-1, + random_state=0 + ) + + self.model.fit(X, Y) # sample_weight + + self.map = {cat: idx for idx, cat in enumerate(self.model.classes_)} # for multi_logloss + else: + X = train_data.get_encoded_data(include_target=False) + Y = train_data.get_encoded_column_data(self.target) + + self.model = RandomForestRegressor( + n_estimators=50, + max_depth=5, + max_features=1., + bootstrap=True, + n_jobs=-1, + random_state=0 + ) + + self.model.fit(X, Y) # sample_weight + + # optimize params + metric, predict_method = (self._multi_logloss, 'predict_proba') if self.is_classifier \ + else (mean_squared_error, 'predict') + + def objective(trial: trial_module.Trial): + criterion = trial.suggest_categorical("criterion", + ["gini", "entropy"]) if self.is_classifier else 'squared_error' + + params = { + 'n_estimators': trial.suggest_int('num_estimators', 2, 512), + 'max_depth': trial.suggest_int('max_depth', 2, 15), + 'min_samples_split': trial.suggest_int("min_samples_split", 2, 20), + 'min_samples_leaf': trial.suggest_int("min_samples_leaf", 1, 20), + 'max_features': trial.suggest_float("max_features", 0.1, 1), + 'criterion': criterion, + } + + self.model.set_params(**params) + + y_pred = cross_val_predict(self.model, X, Y, cv=self.cv, method=predict_method) + cv = check_cv(self.cv, Y, classifier=self.is_classifier) # + score = np.mean([metric(np.array(Y)[val_idx], y_pred[val_idx]) for _, val_idx in cv.split(X, Y)]) + + return score + + elapsed = time.time() - started + num_trials = max(min(int(self.stop_after / elapsed) - 1, self.num_trials), 0) + if self.use_optuna: + log.info(f'The number of trials (Optuna) is {num_trials}.') + + if self.use_optuna and num_trials > 0: + study = optuna.create_study(direction='minimize') + study.optimize(objective, n_trials=num_trials) + log.info(f'RandomForest parameters of the best trial: {study.best_params}') + + # evaluate model effects + if self.fit_on_dev: + log.info(f'RandomForest based correlation of (train data): {self.model.score(X, Y)}') + X = dev_data.get_encoded_data(include_target=False) + if self.is_classifier: + Y = dev_data.get_column_original_data(self.target) + else: + Y = dev_data.get_encoded_column_data(self.target) + log.info(f'RandomForest based correlation of (dev data): {self.model.score(X, Y)}') + else: + log.info(f'RandomForest based correlation of: {self.model.score(X, Y)}') + + def partial_fit(self, train_data: EncodedDs, dev_data: EncodedDs) -> None: + """ + The RandomForest mixer does not support updates. If the model does not exist, a new one will be created and fitted. + + :param train_data: encoded features for (new) training dataset + :param dev_data: encoded features for (new) dev dataset + """ # noqa + if self.model is None: + self.fit(train_data, dev_data) + + def __call__(self, ds: EncodedDs, + args: PredictionArguments = PredictionArguments()) -> pd.DataFrame: + """ + Call a trained RandomForest mixer to output predictions for the target column. + + :param ds: input data with values for all non-target columns. + :param args: inference-time arguments (e.g. whether to output predicted labels or probabilities). + + :return: dataframe with predictions. + """ + data = ds.get_encoded_data(include_target=False) + + if self.is_classifier: + predictions = self.model.predict_proba(data) + decoded_predictions = self.model.classes_.take(np.argmax(predictions, axis=1), axis=0) + else: + predictions = self.model.predict(data) + if predictions.ndim == 1: + decoded_predictions = predictions + else: + decoded_predictions = self.target_encoder.decode(torch.Tensor(predictions)) + + if self.positive_domain: + decoded_predictions = [max(0, p) for p in decoded_predictions] + + ydf = pd.DataFrame({'prediction': decoded_predictions}) + + if args.predict_proba and self.supports_proba: + for idx, label in enumerate(self.model.classes_): + ydf[f'__mdb_proba_{label}'] = predictions[:, idx] + + return ydf diff --git a/lightwood/mixer/sktime.py b/lightwood/mixer/sktime.py index d75046bf3..8f16380c8 100644 --- a/lightwood/mixer/sktime.py +++ b/lightwood/mixer/sktime.py @@ -162,13 +162,16 @@ def _fit(self, data): for k, v in options.items(): kwargs = self._add_forecaster_kwarg(model_class, kwargs, k, v) - model_pipeline = [("forecaster", model_class(**kwargs))] + model_pipeline = [] if self.use_stl and self.ts_analysis['stl_transforms'].get(group, False): model_pipeline.insert(0, ("detrender", self.ts_analysis['stl_transforms'][group]["transformer"].detrender)) model_pipeline.insert(0, ("deseasonalizer", self.ts_analysis['stl_transforms'][group]["transformer"].deseasonalizer)) + kwargs['sp'] = None + + model_pipeline.append(("forecaster", model_class(**kwargs))) self.models[group] = TransformedTargetForecaster(model_pipeline) @@ -260,7 +263,7 @@ def __call__(self, ds: Union[EncodedDs, ConcatedEncodedDs], offset = round(delta / freq) forecaster = self.models[group] ydf = self._call_groupmodel(ydf, forecaster, series, offset=offset) - log.debug(f'[SkTime] Forecasting for group {group}, start at {start_ts} (offset by {offset} for cutoff at {self.cutoffs[group]} (relative {self.models[group].cutoff}))') # noqa + # log.debug(f'[SkTime] Forecasting for group {group}, start at {start_ts} (offset by {offset} for cutoff at {self.cutoffs[group]} (relative {self.models[group].cutoff}))') # noqa else: log.warning(f"Applying naive forecaster for novel group {group}. Performance might not be optimal.") ydf = self._call_default(ydf, series.values, series_idxs) @@ -288,18 +291,22 @@ def _call_groupmodel(self, else: submodel = model - if hasattr(submodel, '_cutoff') and hasattr(submodel, 'd'): + min_offset = -len(submodel._y) + 1 + if hasattr(submodel, 'd'): model_d = 0 if submodel.d is None else submodel.d - cutoff = submodel._cutoff.values[0] if isinstance(submodel._cutoff, pd.Int64Index) else submodel._cutoff - min_offset = -cutoff + model_d + 1 - else: - min_offset = -np.inf + min_offset += model_d start = max(offset, min_offset) - end = series.shape[0] + offset + self.horizon - all_preds = model.predict(np.arange(start, end)).tolist() + end = start + series.shape[0] + self.horizon + + # Workaround for StatsForecastAutoARIMA (see sktime#3600) + if isinstance(submodel, AutoARIMA): + all_preds = model.predict(np.arange(min_offset, end)).tolist()[-(end - start):] + else: + all_preds = model.predict(np.arange(start, end)).tolist() + for true_idx, (idx, _) in enumerate(series.items()): - start_idx = 0 if max(1 + true_idx + offset, min_offset) < 0 else true_idx + start_idx = max(0, true_idx) end_idx = start_idx + self.horizon ydf['prediction'].loc[idx] = all_preds[start_idx:end_idx] return ydf diff --git a/requirements.txt b/requirements.txt index afbea417d..dc8d8fc04 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ schema >=0.6.8 torch >=1.9.0,<1.10.0 requests >=2.0.0 transformers >=4.5.0,<=4.11.3 -lightgbm >=3.2.1,<=3.3.2 +lightgbm >=3.3.0,<=3.3.3 optuna >=2.8.0,<2.10.0 scipy >=1.5.4,<=1.7.1 psutil >=5.7.0 @@ -23,9 +23,9 @@ black >=21.9b0 typing_extensions colorlog ==6.5.0 statsmodels >=0.12.0 -neuralforecast ==0.1.0 -pytorch-lightning>=1.3.0 langid==1.1.6 pydateinfer==0.3.0 shap >= 0.40.0 - +protobuf<3.21.0 +mxnet >=1.6.0, <2.0.0 +gluonts >= 0.10.0, <=0.11.0 diff --git a/requirements_extra_ts.txt b/requirements_extra_ts.txt new file mode 100644 index 000000000..89dcd4cb6 --- /dev/null +++ b/requirements_extra_ts.txt @@ -0,0 +1,4 @@ +pystan==2.19.1.1 +prophet==1.1 +neuralforecast ==0.1.0 +pytorch-lightning>=1.6.0, <1.7.0 diff --git a/requirements_prophet.txt b/requirements_prophet.txt deleted file mode 100644 index 209e74263..000000000 --- a/requirements_prophet.txt +++ /dev/null @@ -1,2 +0,0 @@ -pystan==2.19.1.1 -prophet==1.1 diff --git a/tests/integration/advanced/test_timeseries.py b/tests/integration/advanced/test_timeseries.py index 46d450b83..fc1034eb5 100644 --- a/tests/integration/advanced/test_timeseries.py +++ b/tests/integration/advanced/test_timeseries.py @@ -1,5 +1,6 @@ import random from datetime import datetime +from datetime import timedelta import unittest import numpy as np import pandas as pd @@ -379,6 +380,42 @@ def test_6_time_series_sktime_mixer(self): ps = predictor.predict(test) assert r2_score(test[target].values, ps['prediction'].iloc[0]) >= 0.5 + def test_61_offset(self): + """ Checks __mdb_forecast_offset behavior using sktime mixer """ + data = pd.read_csv('tests/data/house_sales.csv') + data = data[data['type'] == 'house'] + data = data[data['bedrooms'] == 2] + train = data.iloc[0:-1] + test = data.iloc[[-1]] + oby = 'saledate' + pdef = ProblemDefinition.from_dict({'target': 'MA', + 'timeseries_settings': { + 'order_by': oby, + 'window': 5, + 'horizon': 5, + }}) + json_ai = json_ai_from_problem(train, problem_definition=pdef) + json_ai.model['args']['submodels'] = [{"module": "SkTime", "args": {}}] + predictor = predictor_from_code(code_from_json_ai(json_ai)) + train_and_check_time_aim(predictor, train) + + for idx in [-2, -1, 0]: + # Should yield predictions starting on the date of the idx-most recent data point seen at training time. + train['__mdb_forecast_offset'] = idx + ps = predictor.predict(train) + assert len(ps) == 1 + assert ps.iloc[0]['original_index'] == (len(train) - 1 + idx) + + for idx in [1]: + # Should yield predictions starting one period after the most recent timestamp seen at training time. + train['__mdb_forecast_offset'] = idx + ps = predictor.predict(train) + assert len(ps) == 1 + assert ps.iloc[0]['original_index'] == (len(train) - 1) # fixed at the last seen training point + start_predtime = datetime.utcfromtimestamp(ps.iloc[0][f'order_{oby}'][0]) + start_test = datetime.utcfromtimestamp(pd.to_datetime(test.iloc[0][oby]).value // 1e9) + assert start_test - start_predtime <= timedelta(days=2) + def test_7_irregular_series(self): """ Even though the suggestion is to feed regularly sampled series into predictors, this test can still help us @@ -520,3 +557,23 @@ def test_11_output_date_format(self): preds = predictor.predict(test_df.iloc[[-1]], args={'time_format': '%Y'}) self.assertEqual(preds[f'order_{order_by}'].iloc[-1], ['2012', '2012']) + + def test_12_gluonts(self): + """ Tests GluonTS mixer """ + data = pd.read_csv('tests/data/arrivals.csv') + data = data[data['Country'] == 'US'] + order_by = 'T' + train_df, test_df = self.split_arrivals(data, grouped=False) + jai = json_ai_from_problem(train_df, ProblemDefinition.from_dict({'target': 'Traffic', + 'timeseries_settings': { + 'order_by': order_by, + 'window': 4 * 5, + 'horizon': 4 * 2 + }})) + jai.model['args']['submodels'] = [{ + "module": "GluonTSMixer", + "args": {} + }] + predictor = predictor_from_json_ai(jai) + predictor.learn(train_df) + predictor.predict(test_df.iloc[[-1]], args={'time_format': 'infer'}) diff --git a/tests/integration/basic/test_airline.py b/tests/integration/basic/test_airline.py index aa2b1a164..d87f82f31 100644 --- a/tests/integration/basic/test_airline.py +++ b/tests/integration/basic/test_airline.py @@ -14,7 +14,7 @@ def test_0_predict_file_flow(self): target = 'airline_sentiment' predictor = predictor_from_problem(df, ProblemDefinition.from_dict({'target': target, 'time_aim': 80})) - train_and_check_time_aim(predictor, df) + train_and_check_time_aim(predictor, df, ignore_time_aim=True) predictions = predictor.predict(df) # sanity checks diff --git a/tests/integration/basic/test_model_selection.py b/tests/integration/basic/test_model_selection.py index 60a87e6bc..ca270d72b 100644 --- a/tests/integration/basic/test_model_selection.py +++ b/tests/integration/basic/test_model_selection.py @@ -16,14 +16,14 @@ def get_mixers(self, df: pd.DataFrame, target: str, prob_kwargs: dict = None): def test_0_regression_task(self): df = pd.read_csv('tests/data/concrete_strength.csv') target = 'concrete_strength' - expected_mixers = ['Neural', 'LightGBM', 'Regression'] + expected_mixers = ['Neural', 'LightGBM', 'Regression', 'RandomForest'] mixers = self.get_mixers(df, target) self.assertEqual(set(mixers), set(expected_mixers)) def test_1_multiclass_task(self): df = pd.read_csv('tests/data/hdi.csv') target = 'Development Index' - expected_mixers = ['Neural', 'LightGBM', 'Regression'] + expected_mixers = ['Neural', 'LightGBM', 'Regression', 'RandomForest'] mixers = self.get_mixers(df, target) self.assertEqual(set(mixers), set(expected_mixers)) @@ -37,7 +37,7 @@ def test_2_unit_text_task(self): def test_3_complex_text_task(self): df = pd.read_csv('tests/data/wine_reviews_binary_sample.csv') target = 'label' - expected_mixers = ['Neural', 'LightGBM', 'Regression'] + expected_mixers = ['Neural', 'LightGBM', 'Regression', 'RandomForest'] mixers = self.get_mixers(df, target) self.assertEqual(set(mixers), set(expected_mixers)) @@ -53,7 +53,7 @@ def test_4_timeseries_t_plus_1(self): 'window': 5 } } - expected_mixers = ['NeuralTs', 'LightGBM', 'Regression'] + expected_mixers = ['NeuralTs', 'LightGBM', 'Regression', 'RandomForest'] mixers = self.get_mixers(df, target, prob_kwargs=prob_kwargs) self.assertEqual(set(mixers), set(expected_mixers)) diff --git a/tests/integration/basic/test_regression.py b/tests/integration/basic/test_regression.py index 9f01a23f0..8e66799c7 100644 --- a/tests/integration/basic/test_regression.py +++ b/tests/integration/basic/test_regression.py @@ -4,6 +4,7 @@ from sklearn.metrics import r2_score from lightwood.api.types import ProblemDefinition from lightwood.api.high_level import json_ai_from_problem, predictor_from_json_ai +from lightwood import __version__ as lightwood_version class TestBasic(unittest.TestCase): @@ -39,6 +40,8 @@ def test_0_predict_file_flow(self): assert predictor.model_analysis.dtypes[target] == dtype.quantity + assert predictor.lightwood_version == str(lightwood_version) + predictions = predictor.predict(df) # sanity checks diff --git a/tests/unit_tests/encoder/categorical/test_autoencoder.py b/tests/unit_tests/encoder/categorical/test_autoencoder.py index 54f442883..4d6da1b86 100644 --- a/tests/unit_tests/encoder/categorical/test_autoencoder.py +++ b/tests/unit_tests/encoder/categorical/test_autoencoder.py @@ -1,22 +1,47 @@ import unittest from lightwood.encoder.categorical import CategoricalAutoEncoder + import string import random import logging -from sklearn.metrics import accuracy_score + +import numpy as np import pandas as pd -from lightwood.helpers.log import log +from sklearn.metrics import accuracy_score import torch +from lightwood.helpers.log import log + class TestAutoencoder(unittest.TestCase): - def test_autoencoder(self): - """ - Checks reconstruction accuracy above 70% for a set of categories, length 8, for up to 500 unique categories (actual around 468). - """ # noqa - torch.manual_seed(2) - log.setLevel(logging.DEBUG) + def create_test_data(self, + nb_categories=500, + nb_int_categories=50, + max_category_size=50, + test_data_rel_size=0.33): + random.seed(2) + np_random = np.random.default_rng(seed=2) + int_categories = np_random.integers(low=1, high=20, size=nb_int_categories) + str_categories = [ + ''.join(random.choices(string.ascii_uppercase + string.digits, k=random.randint(7, 8))) + for category_i in range(nb_categories - nb_int_categories) + ] + categories = list(int_categories) + str_categories + category_sizes = np_random.integers(low=1, high=max_category_size, size=nb_categories) + category_indexes = np.array(range(nb_categories), dtype=int) + sample_category_indexes = np.repeat(category_indexes, category_sizes) + np_random.shuffle(sample_category_indexes) + samples = [categories[i] for i in sample_category_indexes] + data_size = len(samples) + priming_data = samples + test_data = [] + if(test_data_rel_size > 0.): + test_data_size = round(data_size * test_data_rel_size) + 1 + test_data = priming_data[:test_data_size] + return priming_data, test_data + + def create_test_data_old(self): random.seed(2) cateogries = [''.join(random.choices(string.ascii_uppercase + string.digits, k=random.randint(7, 8))) for x in range(500)] @@ -35,6 +60,17 @@ def test_autoencoder(self): random.shuffle(priming_data) random.shuffle(test_data) + return priming_data, test_data + + def test_autoencoder(self): + """ + Checks reconstruction accuracy above 70% for a set of categories, length 8, for up to 500 unique categories (actual around 468). + """ # noqa + log.setLevel(logging.DEBUG) + + torch.manual_seed(2) + + priming_data, test_data = self.create_test_data() enc = CategoricalAutoEncoder(stop_after=20) enc.desired_error = 3 @@ -46,3 +82,20 @@ def test_autoencoder(self): encoder_accuracy = accuracy_score(list(map(str, test_data)), list(map(str, decoded_data))) print(f'Categorical encoder accuracy for: {encoder_accuracy} on testing dataset') self.assertTrue(encoder_accuracy > 0.70) + + def check_encoder_on_device(self, device): + priming_data, _ = self.create_test_data(nb_categories=8, + nb_int_categories=3, + max_category_size=3, + test_data_rel_size=0.) + + enc = CategoricalAutoEncoder(stop_after=5, device=device) + enc.prepare(pd.Series(priming_data), pd.Series(priming_data)) + self.assertEqual(list(enc.net.parameters())[0].device.type, device) + + def test_encoder_on_cpu(self): + self.check_encoder_on_device('cpu') + + @unittest.skipIf(not torch.cuda.is_available(), 'CUDA unavailable') + def test_encoder_on_cuda(self): + self.check_encoder_on_device('cuda') diff --git a/tests/unit_tests/encoder/images/test_img_2_vec.py b/tests/unit_tests/encoder/images/test_img_2_vec.py index f03e2fa85..2415a889e 100644 --- a/tests/unit_tests/encoder/images/test_img_2_vec.py +++ b/tests/unit_tests/encoder/images/test_img_2_vec.py @@ -1,5 +1,6 @@ import unittest +import torch from torch import Tensor from lightwood.encoder.image import Img2VecEncoder import os @@ -26,3 +27,16 @@ def test_encode(self): # NOTE: this will break when it will possible to choose different # encoding models. self.assertEqual(encoded_images_tensor.size(1), 512) + + def run_test_encoder_on_device(self, device): + enc = Img2VecEncoder(device=device) + enc.prepare([], []) + self.assertEqual(enc.model.device, torch.device(device)) + self.assertEqual(list(enc.model.parameters())[0].device.type, device) + + def test_encoder_on_cpu(self): + self.run_test_encoder_on_device('cpu') + + @unittest.skipIf(not torch.cuda.is_available(), 'CUDA unavailable') + def test_encoder_on_cuda(self): + self.run_test_encoder_on_device('cuda') diff --git a/tests/unit_tests/encoder/text/test_pretrained.py b/tests/unit_tests/encoder/text/test_pretrained.py index 9955ca5c4..3f9484771 100644 --- a/tests/unit_tests/encoder/text/test_pretrained.py +++ b/tests/unit_tests/encoder/text/test_pretrained.py @@ -151,4 +151,18 @@ def test_auto_embed_mode(self): assert(embeddings.shape[0] == test.shape[0]) assert(embeddings.shape[1] == N_embed_dim) + def run_test_encoder_on_device(self, device): + train, _ = create_synthetic_data(20, ptrain=1) + output_enc = BinaryEncoder(is_target=True) + output_enc.prepare(train["label"]) + encoded_target_values = output_enc.encode(train["label"]) + enc = PretrainedLangEncoder(stop_after=10, embed_mode=False, output_type=dtype.binary, device=device) + enc.prepare(train["text"], pd.DataFrame(), encoded_target_values=encoded_target_values) + self.assertEqual(list(enc._model.parameters())[0].device.type, device) + + def test_encoder_on_cpu(self): + self.run_test_encoder_on_device('cpu') + @unittest.skipIf(not torch.cuda.is_available(), 'CUDA unavailable') + def test_encoder_on_cuda(self): + self.run_test_encoder_on_device('cuda') diff --git a/tests/unit_tests/encoder/text/test_rnn.py b/tests/unit_tests/encoder/text/test_rnn.py index 763cda226..1c979eec5 100644 --- a/tests/unit_tests/encoder/text/test_rnn.py +++ b/tests/unit_tests/encoder/text/test_rnn.py @@ -26,3 +26,11 @@ def test_encode_and_decode(self): print('decoded vector') ret2 = encoder.decode(ret) print(ret2) + + @unittest.skip("Currently not using this encoder.") + def test_encoder_on_cpu(self): + pass + + @unittest.skip("Currently not using this encoder.") + def test_encoder_on_cuda(self): + pass diff --git a/tests/unit_tests/encoder/text/test_short.py b/tests/unit_tests/encoder/text/test_short.py index 83ee806ff..9a261513f 100644 --- a/tests/unit_tests/encoder/text/test_short.py +++ b/tests/unit_tests/encoder/text/test_short.py @@ -2,6 +2,7 @@ import unittest from lightwood.encoder.text.short import ShortTextEncoder from lightwood.helpers.text import tokenize_text +import torch VOCAB = [ 'do', 'not', 'remember', 'men', 'pretty', 'break', 'know', 'an', 'forward', 'whose', 'plant', 'decide', 'fit', 'so', @@ -207,3 +208,16 @@ def test_non_smallvocab_non_target_manual_mode(self): [' '.join(x) for x in decoded_data] ): assert x_sent == y_sent + + def check_encoder_on_device(self, device): + priming_data = generate_sentences(2, 6, vocab_size=99) + enc = ShortTextEncoder(is_target=True, device=device) + enc.prepare(priming_data) + self.assertEqual(list(enc.cae.net.parameters())[0].device.type, device) + + def test_encoder_on_cpu(self): + self.check_encoder_on_device('cpu') + + @unittest.skipIf(not torch.cuda.is_available(), 'CUDA unavailable') + def test_encoder_on_cuda(self): + self.check_encoder_on_device('cuda') diff --git a/tests/unit_tests/encoder/time_series/test_timeseries_rnn.py b/tests/unit_tests/encoder/time_series/test_timeseries_rnn.py index 35f9d9de3..ec50562ee 100644 --- a/tests/unit_tests/encoder/time_series/test_timeseries_rnn.py +++ b/tests/unit_tests/encoder/time_series/test_timeseries_rnn.py @@ -84,3 +84,23 @@ def test_overfit(self): preds = torch.reshape(preds, (1, -1)).tolist()[-1] for ans, pred in zip(answer, preds): self.assertGreater(error_margin, abs(pred - ans)) + + def check_encoder_on_device(self, device): + encoder = TimeSeriesEncoder(stop_after=10, device=device) + series = [[1, 2, 3, 4, 5, 6], + [2, 3, 4, 5, 6, 7], + [3, 4, 5, 6, 7, 8], + [4, 5, 6, 7, 8, 9]] + data = series * 5 + batch_size = 1 + encoder._epochs = 1 + encoder.prepare(pd.Series(data), pd.Series(data), + feedback_hoop_function=lambda x: print(x), batch_size=batch_size) + self.assertEqual(list(encoder._encoder.parameters())[0].device.type, device) + + def test_encoder_on_cpu(self): + self.check_encoder_on_device('cpu') + + @unittest.skipIf(not torch.cuda.is_available(), 'CUDA unavailable') + def test_encoder_on_cuda(self): + self.check_encoder_on_device('cuda') diff --git a/tests/unit_tests/mixer/__init__.py b/tests/unit_tests/mixer/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/unit_tests/mixer/test_random_forest.py b/tests/unit_tests/mixer/test_random_forest.py new file mode 100644 index 000000000..5bc2d801d --- /dev/null +++ b/tests/unit_tests/mixer/test_random_forest.py @@ -0,0 +1,64 @@ +import unittest +import numpy as np +import pandas as pd +from sklearn.metrics import balanced_accuracy_score +from lightwood.api.types import ProblemDefinition +from lightwood.api.high_level import json_ai_from_problem, predictor_from_json_ai, JsonAI, code_from_json_ai, predictor_from_code # noqa + + +np.random.seed(42) + + +class TestBasic(unittest.TestCase): + + def get_submodels(self): + submodels = [ + { + 'module': 'RandomForest', + 'args': { + 'stop_after': '$problem_definition.seconds_per_mixer', + 'fit_on_dev': True, + 'target': '$target', + 'dtype_dict': '$dtype_dict', + 'target_encoder': '$encoders[self.target]', + 'use_optuna': True + } + }, + ] + return submodels + + def test_0_regression(self): + df = pd.read_csv('tests/data/concrete_strength.csv')[:500] + target = 'concrete_strength' + + pdef = ProblemDefinition.from_dict({'target': target, 'time_aim': 80}) + jai = json_ai_from_problem(df, pdef) + + jai.model['args']['submodels'] = self.get_submodels() + code = code_from_json_ai(jai) + predictor = predictor_from_code(code) + + predictor.learn(df) + predictor.predict(df) + + def test_1_binary(self): + df = pd.read_csv('tests/data/ionosphere.csv')[:100] + target = 'target' + + pdef = ProblemDefinition.from_dict({'target': target, 'time_aim': 20, 'unbias_target': False}) + jai = json_ai_from_problem(df, pdef) + + jai.model['args']['submodels'] = [ + { + 'module': 'RandomForest', + 'args': {'stop_after': '$problem_definition.seconds_per_mixer', 'fit_on_dev': True}} + ] + code = code_from_json_ai(jai) + predictor = predictor_from_code(code) + + predictor.learn(df) + predictions = predictor.predict(df) + + acc = balanced_accuracy_score(df[target], predictions['prediction']) + self.assertTrue(acc > 0.5) + self.assertTrue(all([0 <= p <= 1 for p in predictions['confidence']]))