prompt: 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()
  
  ```
  
golden_diff: 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')
  
verification_info: {"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"}]}