We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Stop using pickle
Apparently torch 1.5 will no longer support pickling, thus we'll have to switch to `torch.save` instead.

--- 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/api/predictor.py`
Content:
```
1 import traceback
2 import time
3 
4 import dill
5 import pickle
6 import pandas
7 import numpy as np
8 import torch
9 
10 from lightwood.api.data_source import DataSource
11 from lightwood.data_schemas.predictor_config import predictor_config_schema
12 from lightwood.config.config import CONFIG
13 from lightwood.constants.lightwood import COLUMN_DATA_TYPES
14 from lightwood.helpers.device import get_devices
15 from lightwood.logger import log
16 
17 
18 class Predictor:
19     def __init__(self, config=None, output=None, load_from_path=None):
20         """
21         :param config: dict
22         :param output: list, the columns you want to predict, ludwig will try to generate a config
23         :param load_from_path: str, the path to load the predictor from
24         """
25         if load_from_path is not None:
26             with open(load_from_path, 'rb') as pickle_in:
27                 self_dict = pickle.load(pickle_in)
28             self.__dict__ = self_dict
29             self.convert_to_device()
30             return
31 
32         if output is None and config is None:
33             raise ValueError('You must provide either `output` or `config`')
34 
35         if config is not None and output is None:
36             try:
37                 self.config = predictor_config_schema.validate(config)
38             except Exception:
39                 error = traceback.format_exc(1)
40                 raise ValueError('[BAD DEFINITION] argument has errors: {err}'.format(err=error))
41 
42         # this is if we need to automatically generate a configuration variable
43         self._generate_config = True if output is not None or self.config is None else False
44 
45         self._output_columns = output
46         self._input_columns = None
47         self.train_accuracy = None
48 
49         self._mixer = None
50 
51     def convert_to_device(self, device_str=None):
52         if hasattr(self._mixer, 'to') and callable(self._mixer.to):
53             if device_str is not None:
54                 device = torch.device(device_str)
55                 available_devices = 1
56                 if device_str == 'cuda':
57                     available_devices = torch.cuda.device_count()
58             else:
59                 device, available_devices = get_devices()
60 
61             self._mixer.to(device, available_devices)
62 
63     def _type_map(self, from_data, col_name):
64         """
65         This is a helper function that will help us auto-determine roughly what data types are in each column
66         NOTE: That this assumes the data is clean and will only return types for 'CATEGORICAL', 'NUMERIC' and 'TEXT'
67         """
68 
69         col_pd_type = from_data[col_name].dtype
70         col_pd_type = str(col_pd_type)
71 
72         if col_pd_type in ['int64', 'float64', 'timedelta']:
73             return COLUMN_DATA_TYPES.NUMERIC
74         elif col_pd_type in ['bool', 'category']:
75             return COLUMN_DATA_TYPES.CATEGORICAL
76         else:
77             # if the number of uniques is less than 100 or less
78             # than 10% of the total number of rows then keep it as categorical
79             unique = from_data[col_name].nunique()
80             if unique < 100 or unique < len(from_data[col_name]) / 10:
81                 return COLUMN_DATA_TYPES.CATEGORICAL
82             else:
83                 return COLUMN_DATA_TYPES.TEXT
84 
85     def learn(self, from_data, test_data=None):
86         """
87         Train and save a model (you can use this to retrain model from data).
88 
89         :param from_data: DataFrame or DataSource
90             The data to learn from
91 
92         :param test_data: DataFrame or DataSource
93             The data to test accuracy and learn_error from
94         """
95         device, _available_devices = get_devices()
96         log.info(f'Computing device used: {device}')
97         # generate the configuration and set the order for the input and output columns
98         if self._generate_config is True:
99             self._input_columns = [col for col in from_data if col not in self._output_columns]
100             self.config = {
101                 'input_features': [{'name': col, 'type': self._type_map(from_data, col)} for col in self._input_columns],
102                 'output_features': [{'name': col, 'type': self._type_map(from_data, col)} for col in self._output_columns]
103             }
104             self.config = predictor_config_schema.validate(self.config)
105             log.info('Automatically generated a configuration')
106             log.info(self.config)
107         else:
108             self._output_columns = [col['name'] for col in self.config['output_features']]
109             self._input_columns = [col['name'] for col in self.config['input_features']]
110 
111         if isinstance(from_data, pandas.DataFrame):
112             train_ds = DataSource(from_data, self.config)
113         elif isinstance(from_data, DataSource):
114             train_ds = from_data
115         else:
116             raise TypeError(':from_data: must be either DataFrame or DataSource')
117 
118         nr_subsets = 3 if len(train_ds) > 100 else 1
119 
120         if test_data is None:
121             test_ds = train_ds.subset(0.1)
122         elif isinstance(test_data, pandas.DataFrame):
123             test_ds = train_ds.make_child(test_data)
124         elif isinstance(test_data, DataSource):
125             test_ds = test_data
126         else:
127             raise TypeError(':test_data: must be either DataFrame or DataSource')
128 
129         train_ds.create_subsets(nr_subsets)
130         test_ds.create_subsets(nr_subsets)
131 
132         train_ds.train()
133         test_ds.train()
134 
135         mixer_class = self.config['mixer']['class']
136         mixer_kwargs = self.config['mixer']['kwargs']
137         self._mixer = mixer_class(**mixer_kwargs)
138         self._mixer.fit(train_ds=train_ds, test_ds=test_ds)
139         self.train_accuracy = self._mixer.calculate_accuracy(test_ds)
140 
141         return self
142 
143     def predict(self, when_data=None, when=None):
144         """
145         Predict given when conditions.
146 
147         :param when_data: pandas.DataFrame
148         :param when: dict
149 
150         :return: pandas.DataFrame
151         """
152         device, _available_devices = get_devices()
153         log.info(f'Computing device used: {device}')
154         if when is not None:
155             when_dict = {key: [when[key]] for key in when}
156             when_data = pandas.DataFrame(when_dict)
157 
158         when_data_ds = DataSource(when_data, self.config, prepare_encoders=False)
159 
160         when_data_ds.eval()
161 
162         kwargs = {'include_extra_data': self.config.get('include_extra_data', False)}
163 
164         return self._mixer.predict(when_data_ds, **kwargs)
165 
166     def calculate_accuracy(self, from_data):
167         """
168         calculates the accuracy of the model
169         :param from_data:a dataframe
170         :return accuracies: dictionaries of accuracies
171         """
172 
173         if self._mixer is None:
174             log.error("Please train the model before calculating accuracy")
175             return
176 
177         ds = from_data if isinstance(from_data, DataSource) else DataSource(from_data, self.config, prepare_encoders=False)
178         predictions = self._mixer.predict(ds, include_extra_data=True)
179         accuracies = {}
180 
181         for output_column in self._output_columns:
182 
183             col_type = ds.get_column_config(output_column)['type']
184 
185             if col_type == COLUMN_DATA_TYPES.MULTIPLE_CATEGORICAL:
186                 real = list(map(tuple, ds.get_column_original_data(output_column)))
187                 predicted = list(map(tuple, predictions[output_column]['predictions']))
188             else:
189                 real = list(map(str,ds.get_column_original_data(output_column)))
190                 predicted = list(map(str,predictions[output_column]['predictions']))
191 
192             weight_map = None
193             if 'weights' in ds.get_column_config(output_column):
194                 weight_map = ds.get_column_config(output_column)['weights']
195 
196             accuracy = self.apply_accuracy_function(ds.get_column_config(output_column)['type'],
197                                                     real,
198                                                     predicted,
199                                                     weight_map=weight_map,
200                                                     encoder=ds.encoders[output_column])
201 
202             if ds.get_column_config(output_column)['type'] == COLUMN_DATA_TYPES.NUMERIC:
203                 ds.encoders[output_column].decode_log = True
204                 predicted = ds.get_decoded_column_data(output_column, predictions[output_column]['encoded_predictions'])
205 
206                 alternative_accuracy = self.apply_accuracy_function(ds.get_column_config(output_column)['type'], real, predicted,weight_map=weight_map)
207 
208                 if alternative_accuracy['value'] > accuracy['value']:
209                     accuracy = alternative_accuracy
210                 else:
211                     ds.encoders[output_column].decode_log = False
212 
213             accuracies[output_column] = accuracy
214 
215         return accuracies
216 
217     def save(self, path_to):
218         """
219         Save trained model to a file.
220 
221         :param path_to: str, full path of file, where we store results
222         """
223         with open(path_to, 'wb') as f:
224             # Null out certain object we don't want to store
225             if hasattr(self._mixer, '_nonpersistent'):
226                 self._mixer._nonpersistent = {}
227             self.config['mixer']['kwargs']['callback_on_iter'] = None
228 
229 
230             # Dump everything relevant to cpu before saving
231             self.convert_to_device("cpu")
232             pickle.dump(self.__dict__, f)
233             self.convert_to_device()
234
```
--- 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/api/predictor.py b/lightwood/api/predictor.py
--- a/lightwood/api/predictor.py
+++ b/lightwood/api/predictor.py
@@ -1,8 +1,6 @@
 import traceback
 import time
 
-import dill
-import pickle
 import pandas
 import numpy as np
 import torch
@@ -24,7 +22,7 @@
         """
         if load_from_path is not None:
             with open(load_from_path, 'rb') as pickle_in:
-                self_dict = pickle.load(pickle_in)
+                self_dict = torch.load(pickle_in)
             self.__dict__ = self_dict
             self.convert_to_device()
             return
@@ -229,5 +227,5 @@
 
             # Dump everything relevant to cpu before saving
             self.convert_to_device("cpu")
-            pickle.dump(self.__dict__, f)
+            torch.save(self.__dict__, f)
             self.convert_to_device()

{"golden_diff": "diff --git a/lightwood/api/predictor.py b/lightwood/api/predictor.py\n--- a/lightwood/api/predictor.py\n+++ b/lightwood/api/predictor.py\n@@ -1,8 +1,6 @@\n import traceback\n import time\n \n-import dill\n-import pickle\n import pandas\n import numpy as np\n import torch\n@@ -24,7 +22,7 @@\n         \"\"\"\n         if load_from_path is not None:\n             with open(load_from_path, 'rb') as pickle_in:\n-                self_dict = pickle.load(pickle_in)\n+                self_dict = torch.load(pickle_in)\n             self.__dict__ = self_dict\n             self.convert_to_device()\n             return\n@@ -229,5 +227,5 @@\n \n             # Dump everything relevant to cpu before saving\n             self.convert_to_device(\"cpu\")\n-            pickle.dump(self.__dict__, f)\n+            torch.save(self.__dict__, f)\n             self.convert_to_device()\n", "issue": "Stop using pickle\nApparently torch 1.5 will no longer support pickling, thus we'll have to switch to `torch.save` instead.\n", "before_files": [{"content": "import traceback\nimport time\n\nimport dill\nimport pickle\nimport pandas\nimport numpy as np\nimport torch\n\nfrom lightwood.api.data_source import DataSource\nfrom lightwood.data_schemas.predictor_config import predictor_config_schema\nfrom lightwood.config.config import CONFIG\nfrom lightwood.constants.lightwood import COLUMN_DATA_TYPES\nfrom lightwood.helpers.device import get_devices\nfrom lightwood.logger import log\n\n\nclass Predictor:\n    def __init__(self, config=None, output=None, load_from_path=None):\n        \"\"\"\n        :param config: dict\n        :param output: list, the columns you want to predict, ludwig will try to generate a config\n        :param load_from_path: str, the path to load the predictor from\n        \"\"\"\n        if load_from_path is not None:\n            with open(load_from_path, 'rb') as pickle_in:\n                self_dict = pickle.load(pickle_in)\n            self.__dict__ = self_dict\n            self.convert_to_device()\n            return\n\n        if output is None and config is None:\n            raise ValueError('You must provide either `output` or `config`')\n\n        if config is not None and output is None:\n            try:\n                self.config = predictor_config_schema.validate(config)\n            except Exception:\n                error = traceback.format_exc(1)\n                raise ValueError('[BAD DEFINITION] argument has errors: {err}'.format(err=error))\n\n        # this is if we need to automatically generate a configuration variable\n        self._generate_config = True if output is not None or self.config is None else False\n\n        self._output_columns = output\n        self._input_columns = None\n        self.train_accuracy = None\n\n        self._mixer = None\n\n    def convert_to_device(self, device_str=None):\n        if hasattr(self._mixer, 'to') and callable(self._mixer.to):\n            if device_str is not None:\n                device = torch.device(device_str)\n                available_devices = 1\n                if device_str == 'cuda':\n                    available_devices = torch.cuda.device_count()\n            else:\n                device, available_devices = get_devices()\n\n            self._mixer.to(device, available_devices)\n\n    def _type_map(self, from_data, col_name):\n        \"\"\"\n        This is a helper function that will help us auto-determine roughly what data types are in each column\n        NOTE: That this assumes the data is clean and will only return types for 'CATEGORICAL', 'NUMERIC' and 'TEXT'\n        \"\"\"\n\n        col_pd_type = from_data[col_name].dtype\n        col_pd_type = str(col_pd_type)\n\n        if col_pd_type in ['int64', 'float64', 'timedelta']:\n            return COLUMN_DATA_TYPES.NUMERIC\n        elif col_pd_type in ['bool', 'category']:\n            return COLUMN_DATA_TYPES.CATEGORICAL\n        else:\n            # if the number of uniques is less than 100 or less\n            # than 10% of the total number of rows then keep it as categorical\n            unique = from_data[col_name].nunique()\n            if unique < 100 or unique < len(from_data[col_name]) / 10:\n                return COLUMN_DATA_TYPES.CATEGORICAL\n            else:\n                return COLUMN_DATA_TYPES.TEXT\n\n    def learn(self, from_data, test_data=None):\n        \"\"\"\n        Train and save a model (you can use this to retrain model from data).\n\n        :param from_data: DataFrame or DataSource\n            The data to learn from\n\n        :param test_data: DataFrame or DataSource\n            The data to test accuracy and learn_error from\n        \"\"\"\n        device, _available_devices = get_devices()\n        log.info(f'Computing device used: {device}')\n        # generate the configuration and set the order for the input and output columns\n        if self._generate_config is True:\n            self._input_columns = [col for col in from_data if col not in self._output_columns]\n            self.config = {\n                'input_features': [{'name': col, 'type': self._type_map(from_data, col)} for col in self._input_columns],\n                'output_features': [{'name': col, 'type': self._type_map(from_data, col)} for col in self._output_columns]\n            }\n            self.config = predictor_config_schema.validate(self.config)\n            log.info('Automatically generated a configuration')\n            log.info(self.config)\n        else:\n            self._output_columns = [col['name'] for col in self.config['output_features']]\n            self._input_columns = [col['name'] for col in self.config['input_features']]\n\n        if isinstance(from_data, pandas.DataFrame):\n            train_ds = DataSource(from_data, self.config)\n        elif isinstance(from_data, DataSource):\n            train_ds = from_data\n        else:\n            raise TypeError(':from_data: must be either DataFrame or DataSource')\n\n        nr_subsets = 3 if len(train_ds) > 100 else 1\n\n        if test_data is None:\n            test_ds = train_ds.subset(0.1)\n        elif isinstance(test_data, pandas.DataFrame):\n            test_ds = train_ds.make_child(test_data)\n        elif isinstance(test_data, DataSource):\n            test_ds = test_data\n        else:\n            raise TypeError(':test_data: must be either DataFrame or DataSource')\n\n        train_ds.create_subsets(nr_subsets)\n        test_ds.create_subsets(nr_subsets)\n\n        train_ds.train()\n        test_ds.train()\n\n        mixer_class = self.config['mixer']['class']\n        mixer_kwargs = self.config['mixer']['kwargs']\n        self._mixer = mixer_class(**mixer_kwargs)\n        self._mixer.fit(train_ds=train_ds, test_ds=test_ds)\n        self.train_accuracy = self._mixer.calculate_accuracy(test_ds)\n\n        return self\n\n    def predict(self, when_data=None, when=None):\n        \"\"\"\n        Predict given when conditions.\n\n        :param when_data: pandas.DataFrame\n        :param when: dict\n\n        :return: pandas.DataFrame\n        \"\"\"\n        device, _available_devices = get_devices()\n        log.info(f'Computing device used: {device}')\n        if when is not None:\n            when_dict = {key: [when[key]] for key in when}\n            when_data = pandas.DataFrame(when_dict)\n\n        when_data_ds = DataSource(when_data, self.config, prepare_encoders=False)\n\n        when_data_ds.eval()\n\n        kwargs = {'include_extra_data': self.config.get('include_extra_data', False)}\n\n        return self._mixer.predict(when_data_ds, **kwargs)\n\n    def calculate_accuracy(self, from_data):\n        \"\"\"\n        calculates the accuracy of the model\n        :param from_data:a dataframe\n        :return accuracies: dictionaries of accuracies\n        \"\"\"\n\n        if self._mixer is None:\n            log.error(\"Please train the model before calculating accuracy\")\n            return\n\n        ds = from_data if isinstance(from_data, DataSource) else DataSource(from_data, self.config, prepare_encoders=False)\n        predictions = self._mixer.predict(ds, include_extra_data=True)\n        accuracies = {}\n\n        for output_column in self._output_columns:\n\n            col_type = ds.get_column_config(output_column)['type']\n\n            if col_type == COLUMN_DATA_TYPES.MULTIPLE_CATEGORICAL:\n                real = list(map(tuple, ds.get_column_original_data(output_column)))\n                predicted = list(map(tuple, predictions[output_column]['predictions']))\n            else:\n                real = list(map(str,ds.get_column_original_data(output_column)))\n                predicted = list(map(str,predictions[output_column]['predictions']))\n\n            weight_map = None\n            if 'weights' in ds.get_column_config(output_column):\n                weight_map = ds.get_column_config(output_column)['weights']\n\n            accuracy = self.apply_accuracy_function(ds.get_column_config(output_column)['type'],\n                                                    real,\n                                                    predicted,\n                                                    weight_map=weight_map,\n                                                    encoder=ds.encoders[output_column])\n\n            if ds.get_column_config(output_column)['type'] == COLUMN_DATA_TYPES.NUMERIC:\n                ds.encoders[output_column].decode_log = True\n                predicted = ds.get_decoded_column_data(output_column, predictions[output_column]['encoded_predictions'])\n\n                alternative_accuracy = self.apply_accuracy_function(ds.get_column_config(output_column)['type'], real, predicted,weight_map=weight_map)\n\n                if alternative_accuracy['value'] > accuracy['value']:\n                    accuracy = alternative_accuracy\n                else:\n                    ds.encoders[output_column].decode_log = False\n\n            accuracies[output_column] = accuracy\n\n        return accuracies\n\n    def save(self, path_to):\n        \"\"\"\n        Save trained model to a file.\n\n        :param path_to: str, full path of file, where we store results\n        \"\"\"\n        with open(path_to, 'wb') as f:\n            # Null out certain object we don't want to store\n            if hasattr(self._mixer, '_nonpersistent'):\n                self._mixer._nonpersistent = {}\n            self.config['mixer']['kwargs']['callback_on_iter'] = None\n\n\n            # Dump everything relevant to cpu before saving\n            self.convert_to_device(\"cpu\")\n            pickle.dump(self.__dict__, f)\n            self.convert_to_device()\n", "path": "lightwood/api/predictor.py"}], "after_files": [{"content": "import traceback\nimport time\n\nimport pandas\nimport numpy as np\nimport torch\n\nfrom lightwood.api.data_source import DataSource\nfrom lightwood.data_schemas.predictor_config import predictor_config_schema\nfrom lightwood.config.config import CONFIG\nfrom lightwood.constants.lightwood import COLUMN_DATA_TYPES\nfrom lightwood.helpers.device import get_devices\nfrom lightwood.logger import log\n\n\nclass Predictor:\n    def __init__(self, config=None, output=None, load_from_path=None):\n        \"\"\"\n        :param config: dict\n        :param output: list, the columns you want to predict, ludwig will try to generate a config\n        :param load_from_path: str, the path to load the predictor from\n        \"\"\"\n        if load_from_path is not None:\n            with open(load_from_path, 'rb') as pickle_in:\n                self_dict = torch.load(pickle_in)\n            self.__dict__ = self_dict\n            self.convert_to_device()\n            return\n\n        if output is None and config is None:\n            raise ValueError('You must provide either `output` or `config`')\n\n        if config is not None and output is None:\n            try:\n                self.config = predictor_config_schema.validate(config)\n            except Exception:\n                error = traceback.format_exc(1)\n                raise ValueError('[BAD DEFINITION] argument has errors: {err}'.format(err=error))\n\n        # this is if we need to automatically generate a configuration variable\n        self._generate_config = True if output is not None or self.config is None else False\n\n        self._output_columns = output\n        self._input_columns = None\n        self.train_accuracy = None\n\n        self._mixer = None\n\n    def convert_to_device(self, device_str=None):\n        if hasattr(self._mixer, 'to') and callable(self._mixer.to):\n            if device_str is not None:\n                device = torch.device(device_str)\n                available_devices = 1\n                if device_str == 'cuda':\n                    available_devices = torch.cuda.device_count()\n            else:\n                device, available_devices = get_devices()\n\n            self._mixer.to(device, available_devices)\n\n    def _type_map(self, from_data, col_name):\n        \"\"\"\n        This is a helper function that will help us auto-determine roughly what data types are in each column\n        NOTE: That this assumes the data is clean and will only return types for 'CATEGORICAL', 'NUMERIC' and 'TEXT'\n        \"\"\"\n\n        col_pd_type = from_data[col_name].dtype\n        col_pd_type = str(col_pd_type)\n\n        if col_pd_type in ['int64', 'float64', 'timedelta']:\n            return COLUMN_DATA_TYPES.NUMERIC\n        elif col_pd_type in ['bool', 'category']:\n            return COLUMN_DATA_TYPES.CATEGORICAL\n        else:\n            # if the number of uniques is less than 100 or less\n            # than 10% of the total number of rows then keep it as categorical\n            unique = from_data[col_name].nunique()\n            if unique < 100 or unique < len(from_data[col_name]) / 10:\n                return COLUMN_DATA_TYPES.CATEGORICAL\n            else:\n                return COLUMN_DATA_TYPES.TEXT\n\n    def learn(self, from_data, test_data=None):\n        \"\"\"\n        Train and save a model (you can use this to retrain model from data).\n\n        :param from_data: DataFrame or DataSource\n            The data to learn from\n\n        :param test_data: DataFrame or DataSource\n            The data to test accuracy and learn_error from\n        \"\"\"\n        device, _available_devices = get_devices()\n        log.info(f'Computing device used: {device}')\n        # generate the configuration and set the order for the input and output columns\n        if self._generate_config is True:\n            self._input_columns = [col for col in from_data if col not in self._output_columns]\n            self.config = {\n                'input_features': [{'name': col, 'type': self._type_map(from_data, col)} for col in self._input_columns],\n                'output_features': [{'name': col, 'type': self._type_map(from_data, col)} for col in self._output_columns]\n            }\n            self.config = predictor_config_schema.validate(self.config)\n            log.info('Automatically generated a configuration')\n            log.info(self.config)\n        else:\n            self._output_columns = [col['name'] for col in self.config['output_features']]\n            self._input_columns = [col['name'] for col in self.config['input_features']]\n\n        if isinstance(from_data, pandas.DataFrame):\n            train_ds = DataSource(from_data, self.config)\n        elif isinstance(from_data, DataSource):\n            train_ds = from_data\n        else:\n            raise TypeError(':from_data: must be either DataFrame or DataSource')\n\n        nr_subsets = 3 if len(train_ds) > 100 else 1\n\n        if test_data is None:\n            test_ds = train_ds.subset(0.1)\n        elif isinstance(test_data, pandas.DataFrame):\n            test_ds = train_ds.make_child(test_data)\n        elif isinstance(test_data, DataSource):\n            test_ds = test_data\n        else:\n            raise TypeError(':test_data: must be either DataFrame or DataSource')\n\n        train_ds.create_subsets(nr_subsets)\n        test_ds.create_subsets(nr_subsets)\n\n        train_ds.train()\n        test_ds.train()\n\n        mixer_class = self.config['mixer']['class']\n        mixer_kwargs = self.config['mixer']['kwargs']\n        self._mixer = mixer_class(**mixer_kwargs)\n        self._mixer.fit(train_ds=train_ds, test_ds=test_ds)\n        self.train_accuracy = self._mixer.calculate_accuracy(test_ds)\n\n        return self\n\n    def predict(self, when_data=None, when=None):\n        \"\"\"\n        Predict given when conditions.\n\n        :param when_data: pandas.DataFrame\n        :param when: dict\n\n        :return: pandas.DataFrame\n        \"\"\"\n        device, _available_devices = get_devices()\n        log.info(f'Computing device used: {device}')\n        if when is not None:\n            when_dict = {key: [when[key]] for key in when}\n            when_data = pandas.DataFrame(when_dict)\n\n        when_data_ds = DataSource(when_data, self.config, prepare_encoders=False)\n\n        when_data_ds.eval()\n\n        kwargs = {'include_extra_data': self.config.get('include_extra_data', False)}\n\n        return self._mixer.predict(when_data_ds, **kwargs)\n\n    def calculate_accuracy(self, from_data):\n        \"\"\"\n        calculates the accuracy of the model\n        :param from_data:a dataframe\n        :return accuracies: dictionaries of accuracies\n        \"\"\"\n\n        if self._mixer is None:\n            log.error(\"Please train the model before calculating accuracy\")\n            return\n\n        ds = from_data if isinstance(from_data, DataSource) else DataSource(from_data, self.config, prepare_encoders=False)\n        predictions = self._mixer.predict(ds, include_extra_data=True)\n        accuracies = {}\n\n        for output_column in self._output_columns:\n\n            col_type = ds.get_column_config(output_column)['type']\n\n            if col_type == COLUMN_DATA_TYPES.MULTIPLE_CATEGORICAL:\n                real = list(map(tuple, ds.get_column_original_data(output_column)))\n                predicted = list(map(tuple, predictions[output_column]['predictions']))\n            else:\n                real = list(map(str,ds.get_column_original_data(output_column)))\n                predicted = list(map(str,predictions[output_column]['predictions']))\n\n            weight_map = None\n            if 'weights' in ds.get_column_config(output_column):\n                weight_map = ds.get_column_config(output_column)['weights']\n\n            accuracy = self.apply_accuracy_function(ds.get_column_config(output_column)['type'],\n                                                    real,\n                                                    predicted,\n                                                    weight_map=weight_map,\n                                                    encoder=ds.encoders[output_column])\n\n            if ds.get_column_config(output_column)['type'] == COLUMN_DATA_TYPES.NUMERIC:\n                ds.encoders[output_column].decode_log = True\n                predicted = ds.get_decoded_column_data(output_column, predictions[output_column]['encoded_predictions'])\n\n                alternative_accuracy = self.apply_accuracy_function(ds.get_column_config(output_column)['type'], real, predicted,weight_map=weight_map)\n\n                if alternative_accuracy['value'] > accuracy['value']:\n                    accuracy = alternative_accuracy\n                else:\n                    ds.encoders[output_column].decode_log = False\n\n            accuracies[output_column] = accuracy\n\n        return accuracies\n\n    def save(self, path_to):\n        \"\"\"\n        Save trained model to a file.\n\n        :param path_to: str, full path of file, where we store results\n        \"\"\"\n        with open(path_to, 'wb') as f:\n            # Null out certain object we don't want to store\n            if hasattr(self._mixer, '_nonpersistent'):\n                self._mixer._nonpersistent = {}\n            self.config['mixer']['kwargs']['callback_on_iter'] = None\n\n\n            # Dump everything relevant to cpu before saving\n            self.convert_to_device(\"cpu\")\n            torch.save(self.__dict__, f)\n            self.convert_to_device()\n", "path": "lightwood/api/predictor.py"}]}