We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Improve "Unit" mixer documentation
We don't have a docstring for this mixer. The challenge here is to eloquently describe what this mixer does (hint: it can be used when encoders themselves are the models, e.g. pretrained language models that receive a single column as input).

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `lightwood/mixer/unit.py`
Content:
```
1 """
2 2021.07.16
3 
4 For encoders that already fine-tune on the targets (namely text)
5 the unity mixer just arg-maxes the output of the encoder.
6 """
7 
8 from typing import List, Optional
9 
10 import torch
11 import pandas as pd
12 
13 from lightwood.helpers.log import log
14 from lightwood.mixer.base import BaseMixer
15 from lightwood.encoder.base import BaseEncoder
16 from lightwood.data.encoded_ds import EncodedDs
17 from lightwood.api.types import PredictionArguments
18 
19 
20 class Unit(BaseMixer):
21     def __init__(self, stop_after: float, target_encoder: BaseEncoder):
22         super().__init__(stop_after)
23         self.target_encoder = target_encoder
24         self.supports_proba = False
25         self.stable = True
26 
27     def fit(self, train_data: EncodedDs, dev_data: EncodedDs) -> None:
28         log.info("Unit Mixer just borrows from encoder")
29 
30     def partial_fit(self, train_data: EncodedDs, dev_data: EncodedDs, args: Optional[dict] = None) -> None:
31         pass
32 
33     def __call__(self, ds: EncodedDs,
34                  args: PredictionArguments = PredictionArguments()) -> pd.DataFrame:
35         if args.predict_proba:
36             # @TODO: depending on the target encoder, this might be enabled
37             log.warning('This model does not output probability estimates')
38 
39         decoded_predictions: List[object] = []
40 
41         for X, _ in ds:
42             decoded_prediction = self.target_encoder.decode(torch.unsqueeze(X, 0))
43             decoded_predictions.extend(decoded_prediction)
44 
45         ydf = pd.DataFrame({"prediction": decoded_predictions})
46         return ydf
47
```

Path: `lightwood/mixer/base.py`
Content:
```
1 from typing import Optional
2 import pandas as pd
3 
4 from lightwood.data.encoded_ds import EncodedDs
5 from lightwood.api.types import PredictionArguments
6 
7 
8 class BaseMixer:
9     """
10     Base class for all mixers.
11 
12     Mixers are the backbone of all Lightwood machine learning models. They intake encoded feature representations for every column, and are tasked with learning to fulfill the predictive requirements stated in a problem definition.
13     
14     There are two important methods for any mixer to work:
15         1. `fit()` contains all logic to train the mixer with the training data that has been encoded by all the (already trained) Lightwood encoders for any given task.
16         2. `__call__()` is executed to generate predictions once the mixer has been trained using `fit()`. 
17     
18     An additional `partial_fit()` method is used to update any mixer that has already been trained.
19 
20     Class Attributes:
21     - stable: If set to `True`, this mixer should always work. Any mixer with `stable=False` can be expected to fail under some circumstances.
22     - fit_data_len: Length of the training data.
23     - supports_proba: For classification tasks, whether the mixer supports yielding per-class scores rather than only returning the predicted label. 
24     - trains_once: If True, the mixer is trained once during learn, using all available input data (`train` and `dev` splits for training, `test` for validation). Otherwise, it trains once with the `train`` split & `dev` for validation, and optionally (depending on the problem definition `fit_on_all` and mixer-wise `fit_on_dev` arguments) a second time after post-training analysis via partial_fit, with `train` and `dev` splits as training subset, and `test` split as validation. Should only be set to True for mixers that don't require post-training analysis, as otherwise actual validation data would be treated as a held-out portion, which is a mistake. 
25     """  # noqa
26     stable: bool
27     fit_data_len: int  # @TODO (Patricio): should this really be in `BaseMixer`?
28     supports_proba: bool
29     trains_once: bool
30 
31     def __init__(self, stop_after: float):
32         """
33         :param stop_after: Time budget to train this mixer.
34         """
35         self.stop_after = stop_after
36         self.supports_proba = False
37         self.trains_once = False
38 
39     def fit(self, train_data: EncodedDs, dev_data: EncodedDs) -> None:
40         """
41         Fits/trains a mixer with training data. 
42          
43         :param train_data: encoded representations of the training data subset. 
44         :param dev_data: encoded representations of the "dev" data subset. This can be used as an internal validation subset (e.g. it is used for early stopping in the default `Neural` mixer). 
45          
46         """  # noqa
47         raise NotImplementedError()
48 
49     def __call__(self, ds: EncodedDs,
50                  args: PredictionArguments = PredictionArguments()) -> pd.DataFrame:
51         """
52         Calls a trained mixer to predict the target column given some input data.
53         
54         :param ds: encoded representations of input data.
55         :param args: a `lightwood.api.types.PredictionArguments` object, including all relevant inference-time arguments to customize the behavior.
56         :return: 
57         """  # noqa
58         raise NotImplementedError()
59 
60     def partial_fit(self, train_data: EncodedDs, dev_data: EncodedDs, adjust_args: Optional[dict] = None) -> None:
61         """
62         Partially fits/trains a mixer with new training data. This is a somewhat experimental method, and it aims at updating pre-existing Lightwood predictors. 
63 
64         :param train_data: encoded representations of the new training data subset. 
65         :param dev_data: encoded representations of new the "dev" data subset. As in `fit()`, this can be used as an internal validation subset. 
66         :param adjust_args: optional arguments to customize the finetuning process.
67 
68         """  # noqa
69         pass
70
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/lightwood/mixer/base.py b/lightwood/mixer/base.py
--- a/lightwood/mixer/base.py
+++ b/lightwood/mixer/base.py
@@ -30,7 +30,7 @@
 
     def __init__(self, stop_after: float):
         """
-        :param stop_after: Time budget to train this mixer.
+        :param stop_after: Time budget (in seconds) to train this mixer.
         """
         self.stop_after = stop_after
         self.supports_proba = False
diff --git a/lightwood/mixer/unit.py b/lightwood/mixer/unit.py
--- a/lightwood/mixer/unit.py
+++ b/lightwood/mixer/unit.py
@@ -1,10 +1,3 @@
-"""
-2021.07.16
-
-For encoders that already fine-tune on the targets (namely text)
-the unity mixer just arg-maxes the output of the encoder.
-"""
-
 from typing import List, Optional
 
 import torch
@@ -19,19 +12,35 @@
 
 class Unit(BaseMixer):
     def __init__(self, stop_after: float, target_encoder: BaseEncoder):
+        """
+        The "Unit" mixer serves as a simple wrapper around a target encoder, essentially borrowing 
+        the encoder's functionality for predictions. In other words, it simply arg-maxes the output of the encoder
+
+        Used with encoders that already fine-tune on the targets (namely, pre-trained text ML models).
+        
+        Attributes:
+            :param target_encoder: An instance of a Lightwood BaseEncoder. This encoder is used to decode predictions.
+            :param stop_after (float): Time budget (in seconds) to train this mixer. 
+        """  # noqa
         super().__init__(stop_after)
         self.target_encoder = target_encoder
         self.supports_proba = False
         self.stable = True
 
     def fit(self, train_data: EncodedDs, dev_data: EncodedDs) -> None:
-        log.info("Unit Mixer just borrows from encoder")
+        log.info("Unit mixer does not require training, it passes through predictions from its encoders.")
 
     def partial_fit(self, train_data: EncodedDs, dev_data: EncodedDs, args: Optional[dict] = None) -> None:
         pass
 
     def __call__(self, ds: EncodedDs,
                  args: PredictionArguments = PredictionArguments()) -> pd.DataFrame:
+        """
+        Makes predictions using the provided EncodedDs dataset.
+        Mixer decodes predictions using the target encoder and returns them in a pandas DataFrame.
+
+        :returns ydf (pd.DataFrame): a data frame containing the decoded predictions.
+        """
         if args.predict_proba:
             # @TODO: depending on the target encoder, this might be enabled
             log.warning('This model does not output probability estimates')

{"golden_diff": "diff --git a/lightwood/mixer/base.py b/lightwood/mixer/base.py\n--- a/lightwood/mixer/base.py\n+++ b/lightwood/mixer/base.py\n@@ -30,7 +30,7 @@\n \n     def __init__(self, stop_after: float):\n         \"\"\"\n-        :param stop_after: Time budget to train this mixer.\n+        :param stop_after: Time budget (in seconds) to train this mixer.\n         \"\"\"\n         self.stop_after = stop_after\n         self.supports_proba = False\ndiff --git a/lightwood/mixer/unit.py b/lightwood/mixer/unit.py\n--- a/lightwood/mixer/unit.py\n+++ b/lightwood/mixer/unit.py\n@@ -1,10 +1,3 @@\n-\"\"\"\n-2021.07.16\n-\n-For encoders that already fine-tune on the targets (namely text)\n-the unity mixer just arg-maxes the output of the encoder.\n-\"\"\"\n-\n from typing import List, Optional\n \n import torch\n@@ -19,19 +12,35 @@\n \n class Unit(BaseMixer):\n     def __init__(self, stop_after: float, target_encoder: BaseEncoder):\n+        \"\"\"\n+        The \"Unit\" mixer serves as a simple wrapper around a target encoder, essentially borrowing \n+        the encoder's functionality for predictions. In other words, it simply arg-maxes the output of the encoder\n+\n+        Used with encoders that already fine-tune on the targets (namely, pre-trained text ML models).\n+        \n+        Attributes:\n+            :param target_encoder: An instance of a Lightwood BaseEncoder. This encoder is used to decode predictions.\n+            :param stop_after (float): Time budget (in seconds) to train this mixer. \n+        \"\"\"  # noqa\n         super().__init__(stop_after)\n         self.target_encoder = target_encoder\n         self.supports_proba = False\n         self.stable = True\n \n     def fit(self, train_data: EncodedDs, dev_data: EncodedDs) -> None:\n-        log.info(\"Unit Mixer just borrows from encoder\")\n+        log.info(\"Unit mixer does not require training, it passes through predictions from its encoders.\")\n \n     def partial_fit(self, train_data: EncodedDs, dev_data: EncodedDs, args: Optional[dict] = None) -> None:\n         pass\n \n     def __call__(self, ds: EncodedDs,\n                  args: PredictionArguments = PredictionArguments()) -> pd.DataFrame:\n+        \"\"\"\n+        Makes predictions using the provided EncodedDs dataset.\n+        Mixer decodes predictions using the target encoder and returns them in a pandas DataFrame.\n+\n+        :returns ydf (pd.DataFrame): a data frame containing the decoded predictions.\n+        \"\"\"\n         if args.predict_proba:\n             # @TODO: depending on the target encoder, this might be enabled\n             log.warning('This model does not output probability estimates')\n", "issue": "Improve \"Unit\" mixer documentation\nWe don't have a docstring for this mixer. The challenge here is to eloquently describe what this mixer does (hint: it can be used when encoders themselves are the models, e.g. pretrained language models that receive a single column as input).\n", "before_files": [{"content": "\"\"\"\n2021.07.16\n\nFor encoders that already fine-tune on the targets (namely text)\nthe unity mixer just arg-maxes the output of the encoder.\n\"\"\"\n\nfrom typing import List, Optional\n\nimport torch\nimport pandas as pd\n\nfrom lightwood.helpers.log import log\nfrom lightwood.mixer.base import BaseMixer\nfrom lightwood.encoder.base import BaseEncoder\nfrom lightwood.data.encoded_ds import EncodedDs\nfrom lightwood.api.types import PredictionArguments\n\n\nclass Unit(BaseMixer):\n    def __init__(self, stop_after: float, target_encoder: BaseEncoder):\n        super().__init__(stop_after)\n        self.target_encoder = target_encoder\n        self.supports_proba = False\n        self.stable = True\n\n    def fit(self, train_data: EncodedDs, dev_data: EncodedDs) -> None:\n        log.info(\"Unit Mixer just borrows from encoder\")\n\n    def partial_fit(self, train_data: EncodedDs, dev_data: EncodedDs, args: Optional[dict] = None) -> None:\n        pass\n\n    def __call__(self, ds: EncodedDs,\n                 args: PredictionArguments = PredictionArguments()) -> pd.DataFrame:\n        if args.predict_proba:\n            # @TODO: depending on the target encoder, this might be enabled\n            log.warning('This model does not output probability estimates')\n\n        decoded_predictions: List[object] = []\n\n        for X, _ in ds:\n            decoded_prediction = self.target_encoder.decode(torch.unsqueeze(X, 0))\n            decoded_predictions.extend(decoded_prediction)\n\n        ydf = pd.DataFrame({\"prediction\": decoded_predictions})\n        return ydf\n", "path": "lightwood/mixer/unit.py"}, {"content": "from typing import Optional\nimport pandas as pd\n\nfrom lightwood.data.encoded_ds import EncodedDs\nfrom lightwood.api.types import PredictionArguments\n\n\nclass BaseMixer:\n    \"\"\"\n    Base class for all mixers.\n\n    Mixers are the backbone of all Lightwood machine learning models. They intake encoded feature representations for every column, and are tasked with learning to fulfill the predictive requirements stated in a problem definition.\n    \n    There are two important methods for any mixer to work:\n        1. `fit()` contains all logic to train the mixer with the training data that has been encoded by all the (already trained) Lightwood encoders for any given task.\n        2. `__call__()` is executed to generate predictions once the mixer has been trained using `fit()`. \n    \n    An additional `partial_fit()` method is used to update any mixer that has already been trained.\n\n    Class Attributes:\n    - stable: If set to `True`, this mixer should always work. Any mixer with `stable=False` can be expected to fail under some circumstances.\n    - fit_data_len: Length of the training data.\n    - supports_proba: For classification tasks, whether the mixer supports yielding per-class scores rather than only returning the predicted label. \n    - trains_once: If True, the mixer is trained once during learn, using all available input data (`train` and `dev` splits for training, `test` for validation). Otherwise, it trains once with the `train`` split & `dev` for validation, and optionally (depending on the problem definition `fit_on_all` and mixer-wise `fit_on_dev` arguments) a second time after post-training analysis via partial_fit, with `train` and `dev` splits as training subset, and `test` split as validation. Should only be set to True for mixers that don't require post-training analysis, as otherwise actual validation data would be treated as a held-out portion, which is a mistake. \n    \"\"\"  # noqa\n    stable: bool\n    fit_data_len: int  # @TODO (Patricio): should this really be in `BaseMixer`?\n    supports_proba: bool\n    trains_once: bool\n\n    def __init__(self, stop_after: float):\n        \"\"\"\n        :param stop_after: Time budget to train this mixer.\n        \"\"\"\n        self.stop_after = stop_after\n        self.supports_proba = False\n        self.trains_once = False\n\n    def fit(self, train_data: EncodedDs, dev_data: EncodedDs) -> None:\n        \"\"\"\n        Fits/trains a mixer with training data. \n         \n        :param train_data: encoded representations of the training data subset. \n        :param dev_data: encoded representations of the \"dev\" data subset. This can be used as an internal validation subset (e.g. it is used for early stopping in the default `Neural` mixer). \n         \n        \"\"\"  # noqa\n        raise NotImplementedError()\n\n    def __call__(self, ds: EncodedDs,\n                 args: PredictionArguments = PredictionArguments()) -> pd.DataFrame:\n        \"\"\"\n        Calls a trained mixer to predict the target column given some input data.\n        \n        :param ds: encoded representations of input data.\n        :param args: a `lightwood.api.types.PredictionArguments` object, including all relevant inference-time arguments to customize the behavior.\n        :return: \n        \"\"\"  # noqa\n        raise NotImplementedError()\n\n    def partial_fit(self, train_data: EncodedDs, dev_data: EncodedDs, adjust_args: Optional[dict] = None) -> None:\n        \"\"\"\n        Partially fits/trains a mixer with new training data. This is a somewhat experimental method, and it aims at updating pre-existing Lightwood predictors. \n\n        :param train_data: encoded representations of the new training data subset. \n        :param dev_data: encoded representations of new the \"dev\" data subset. As in `fit()`, this can be used as an internal validation subset. \n        :param adjust_args: optional arguments to customize the finetuning process.\n\n        \"\"\"  # noqa\n        pass\n", "path": "lightwood/mixer/base.py"}], "after_files": [{"content": "from typing import List, Optional\n\nimport torch\nimport pandas as pd\n\nfrom lightwood.helpers.log import log\nfrom lightwood.mixer.base import BaseMixer\nfrom lightwood.encoder.base import BaseEncoder\nfrom lightwood.data.encoded_ds import EncodedDs\nfrom lightwood.api.types import PredictionArguments\n\n\nclass Unit(BaseMixer):\n    def __init__(self, stop_after: float, target_encoder: BaseEncoder):\n        \"\"\"\n        The \"Unit\" mixer serves as a simple wrapper around a target encoder, essentially borrowing \n        the encoder's functionality for predictions. In other words, it simply arg-maxes the output of the encoder\n\n        Used with encoders that already fine-tune on the targets (namely, pre-trained text ML models).\n        \n        Attributes:\n            :param target_encoder: An instance of a Lightwood BaseEncoder. This encoder is used to decode predictions.\n            :param stop_after (float): Time budget (in seconds) to train this mixer. \n        \"\"\"  # noqa\n        super().__init__(stop_after)\n        self.target_encoder = target_encoder\n        self.supports_proba = False\n        self.stable = True\n\n    def fit(self, train_data: EncodedDs, dev_data: EncodedDs) -> None:\n        log.info(\"Unit mixer does not require training, it passes through predictions from its encoders.\")\n\n    def partial_fit(self, train_data: EncodedDs, dev_data: EncodedDs, args: Optional[dict] = None) -> None:\n        pass\n\n    def __call__(self, ds: EncodedDs,\n                 args: PredictionArguments = PredictionArguments()) -> pd.DataFrame:\n        \"\"\"\n        Makes predictions using the provided EncodedDs dataset.\n        Mixer decodes predictions using the target encoder and returns them in a pandas DataFrame.\n\n        :returns ydf (pd.DataFrame): a data frame containing the decoded predictions.\n        \"\"\"\n        if args.predict_proba:\n            # @TODO: depending on the target encoder, this might be enabled\n            log.warning('This model does not output probability estimates')\n\n        decoded_predictions: List[object] = []\n\n        for X, _ in ds:\n            decoded_prediction = self.target_encoder.decode(torch.unsqueeze(X, 0))\n            decoded_predictions.extend(decoded_prediction)\n\n        ydf = pd.DataFrame({\"prediction\": decoded_predictions})\n        return ydf\n", "path": "lightwood/mixer/unit.py"}, {"content": "from typing import Optional\nimport pandas as pd\n\nfrom lightwood.data.encoded_ds import EncodedDs\nfrom lightwood.api.types import PredictionArguments\n\n\nclass BaseMixer:\n    \"\"\"\n    Base class for all mixers.\n\n    Mixers are the backbone of all Lightwood machine learning models. They intake encoded feature representations for every column, and are tasked with learning to fulfill the predictive requirements stated in a problem definition.\n    \n    There are two important methods for any mixer to work:\n        1. `fit()` contains all logic to train the mixer with the training data that has been encoded by all the (already trained) Lightwood encoders for any given task.\n        2. `__call__()` is executed to generate predictions once the mixer has been trained using `fit()`. \n    \n    An additional `partial_fit()` method is used to update any mixer that has already been trained.\n\n    Class Attributes:\n    - stable: If set to `True`, this mixer should always work. Any mixer with `stable=False` can be expected to fail under some circumstances.\n    - fit_data_len: Length of the training data.\n    - supports_proba: For classification tasks, whether the mixer supports yielding per-class scores rather than only returning the predicted label. \n    - trains_once: If True, the mixer is trained once during learn, using all available input data (`train` and `dev` splits for training, `test` for validation). Otherwise, it trains once with the `train`` split & `dev` for validation, and optionally (depending on the problem definition `fit_on_all` and mixer-wise `fit_on_dev` arguments) a second time after post-training analysis via partial_fit, with `train` and `dev` splits as training subset, and `test` split as validation. Should only be set to True for mixers that don't require post-training analysis, as otherwise actual validation data would be treated as a held-out portion, which is a mistake. \n    \"\"\"  # noqa\n    stable: bool\n    fit_data_len: int  # @TODO (Patricio): should this really be in `BaseMixer`?\n    supports_proba: bool\n    trains_once: bool\n\n    def __init__(self, stop_after: float):\n        \"\"\"\n        :param stop_after: Time budget (in seconds) to train this mixer.\n        \"\"\"\n        self.stop_after = stop_after\n        self.supports_proba = False\n        self.trains_once = False\n\n    def fit(self, train_data: EncodedDs, dev_data: EncodedDs) -> None:\n        \"\"\"\n        Fits/trains a mixer with training data. \n         \n        :param train_data: encoded representations of the training data subset. \n        :param dev_data: encoded representations of the \"dev\" data subset. This can be used as an internal validation subset (e.g. it is used for early stopping in the default `Neural` mixer). \n         \n        \"\"\"  # noqa\n        raise NotImplementedError()\n\n    def __call__(self, ds: EncodedDs,\n                 args: PredictionArguments = PredictionArguments()) -> pd.DataFrame:\n        \"\"\"\n        Calls a trained mixer to predict the target column given some input data.\n        \n        :param ds: encoded representations of input data.\n        :param args: a `lightwood.api.types.PredictionArguments` object, including all relevant inference-time arguments to customize the behavior.\n        :return: \n        \"\"\"  # noqa\n        raise NotImplementedError()\n\n    def partial_fit(self, train_data: EncodedDs, dev_data: EncodedDs, adjust_args: Optional[dict] = None) -> None:\n        \"\"\"\n        Partially fits/trains a mixer with new training data. This is a somewhat experimental method, and it aims at updating pre-existing Lightwood predictors. \n\n        :param train_data: encoded representations of the new training data subset. \n        :param dev_data: encoded representations of new the \"dev\" data subset. As in `fit()`, this can be used as an internal validation subset. \n        :param adjust_args: optional arguments to customize the finetuning process.\n\n        \"\"\"  # noqa\n        pass\n", "path": "lightwood/mixer/base.py"}]}