We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
LightGBM is not deterministic
* Lightwood version: 0.58.0

Currently, our LightGBM mixer is not deterministic, presenting slight performance differences when trained for the same dataset. We should fix the corresponding random seeds so that this is doesn't happen anymore.


--- 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/mixers/lightgbm.py`
Content:
```
1 import numpy as np
2 import optuna.integration.lightgbm as lgb
3 import lightgbm
4 import optuna
5 import torch
6 import logging
7 import time
8 
9 from lightwood.constants.lightwood import COLUMN_DATA_TYPES
10 from lightwood.helpers.device import get_devices
11 from lightwood.mixers import BaseMixer
12 from sklearn.preprocessing import OrdinalEncoder
13 
14 
15 optuna.logging.set_verbosity(optuna.logging.CRITICAL)
16 
17 
18 def check_gpu_support():
19     try:
20         data = np.random.rand(50, 2)
21         label = np.random.randint(2, size=50)
22         train_data = lightgbm.Dataset(data, label=label)
23         params = {'num_iterations': 1, 'device': 'gpu'}
24         gbm = lightgbm.train(params, train_set=train_data)
25         return True
26     except Exception as e:
27         return False
28 
29 class LightGBMMixer(BaseMixer):
30     def __init__(self, stop_training_after_seconds=None, grid_search=False):
31         super().__init__()
32         self.models = {}
33         self.ord_encs = {}
34         self.label_sets = {}
35         self.stop_training_after_seconds = stop_training_after_seconds
36         self.grid_search = grid_search  # using Optuna
37 
38         # GPU Only available via --install-option=--gpu with opencl-dev and libboost dev (a bunch of them) installed, so let's turn this off for now and we can put it behind some flag later
39         self.device, _ = get_devices()
40         self.device_str = 'cpu' if str(self.device) == 'cpu' else 'gpu'
41         if self.device_str == 'gpu':
42             gpu_works = check_gpu_support()
43             if not gpu_works:
44                 self.device = torch.device('cpu')
45                 self.device_str = 'cpu'
46 
47         self.max_bin = 255  # Default value
48         if self.device_str == 'gpu':
49             self.max_bin = 63  # As recommended by https://lightgbm.readthedocs.io/en/latest/Parameters.html#device_type
50 
51     def _fit(self, train_ds, test_ds=None):
52         """
53         :param train_ds: DataSource
54         :param test_ds: DataSource
55         """
56 
57         data = {
58             'train': {'ds': train_ds, 'data': None, 'label_data': {}},
59             'test': {'ds': test_ds, 'data': None, 'label_data': {}}
60         }
61 
62         # Order is important here
63         for subset_name in ['train','test']:
64             cols = data[subset_name]['ds'].input_feature_names
65             out_cols = data[subset_name]['ds'].output_feature_names
66             for col_name in cols:
67                 if data[subset_name]['data'] is None:
68                     data[subset_name]['data'] = data[subset_name]['ds'].get_encoded_column_data(col_name).to(self.device)
69                 else:
70                     enc_col = data[subset_name]['ds'].get_encoded_column_data(col_name)
71                     data[subset_name]['data'] = torch.cat((data[subset_name]['data'], enc_col.to(self.device)), 1)
72             data[subset_name]['data'] = data[subset_name]['data'].tolist()
73             for col_name in out_cols:
74                 label_data = data[subset_name]['ds'].get_column_original_data(col_name)
75                 if next(item for item in train_ds.output_features if item["name"] == col_name)['type'] == COLUMN_DATA_TYPES.CATEGORICAL:
76                     if subset_name == 'train':
77                         self.ord_encs[col_name] = OrdinalEncoder()
78                         self.label_sets[col_name] = set(label_data)
79                         self.label_sets[col_name].add('__mdb_unknown_cat')
80                         self.ord_encs[col_name].fit(np.array(list(self.label_sets[col_name])).reshape(-1, 1))
81 
82                     label_data = [x if x in self.label_sets[col_name] else '__mdb_unknown_cat' for x in label_data]
83                     label_data = self.ord_encs[col_name].transform(np.array(label_data).reshape(-1, 1)).flatten()
84 
85                 data[subset_name]['label_data'][col_name] = label_data
86 
87         for col_name in train_ds.output_feature_names:
88             dtype = next(item for item in train_ds.output_features if item["name"] == col_name)['type']
89             if dtype not in [COLUMN_DATA_TYPES.NUMERIC, COLUMN_DATA_TYPES.CATEGORICAL]:
90                 logging.info('cannot support {dtype} in lightgbm'.format(dtype=dtype))
91                 continue
92             else:
93                 objective = 'regression' if dtype == COLUMN_DATA_TYPES.NUMERIC else 'multiclass'
94                 metric = 'l2' if dtype == COLUMN_DATA_TYPES.NUMERIC else 'multi_logloss'
95 
96             params = {'objective': objective,
97                       'metric': metric,
98                       'verbose': -1,
99                       'lambda_l1': 0.1,
100                       'lambda_l2': 0.1,
101                       'force_row_wise': True,
102                       'device_type': self.device_str
103                       }
104             if objective == 'multiclass':
105                 self.all_classes = self.ord_encs[col_name].categories_[0]
106                 params['num_class'] = self.all_classes.size
107 
108             num_iterations = 50
109             kwargs = {}
110 
111             if self.stop_training_after_seconds is not None:
112                 train_data = lightgbm.Dataset(data['train']['data'], label=data['train']['label_data'][col_name])
113                 validate_data = lightgbm.Dataset(data['test']['data'], label=data['test']['label_data'][col_name])
114                 start = time.time()
115                 params['num_iterations'] = 1
116                 bst = lightgbm.train(params, train_data, valid_sets=validate_data, verbose_eval=False)
117                 end = time.time()
118                 seconds_for_one_iteration = max(0.1, end - start)
119                 logging.info(f'A single GBM itteration takes {seconds_for_one_iteration} seconds')
120                 max_itt = int(self.stop_training_after_seconds / seconds_for_one_iteration)
121                 num_iterations = max(1, min(num_iterations, max_itt))
122                 # Turn on grid search if training doesn't take too long using it
123                 if max_itt >= num_iterations and seconds_for_one_iteration < 10:
124                     self.grid_search = True
125                     kwargs['time_budget'] = self.stop_training_after_seconds
126 
127             train_data = lightgbm.Dataset(data['train']['data'], label=data['train']['label_data'][col_name])
128             validate_data = lightgbm.Dataset(data['test']['data'], label=data['test']['label_data'][col_name])
129             model = lgb if self.grid_search else lightgbm
130             logging.info(f'Training GBM ({model}) with {num_iterations} iterations given {self.stop_training_after_seconds} seconds constraint')
131             params['num_iterations'] = num_iterations
132             bst = model.train(params, train_data, valid_sets=validate_data, verbose_eval=False, **kwargs)
133 
134             self.models[col_name] = bst
135 
136     def _predict(self, when_data_source, include_extra_data=False):
137         """
138         :param when_data_source: DataSource
139         :param include_extra_data: bool
140         """
141         data = None
142         for col_name in when_data_source.input_feature_names:
143             if data is None:
144                 data = when_data_source.get_encoded_column_data(col_name).to(self.device)
145             else:
146                 data = torch.cat((data, when_data_source.get_encoded_column_data(col_name).to(self.device)), 1)
147         data = data.tolist()
148 
149         ypred = {}
150         for col_name in when_data_source.output_feature_names:
151             col_config = [conf for conf in when_data_source.config['output_features'] if conf['name'] == col_name][0]
152             col_preds = self.models[col_name].predict(data)
153             ypred[col_name] = {}
154             if col_name in self.ord_encs:
155                 ypred[col_name]['class_distribution'] = list(col_preds)
156                 ypred[col_name]['class_labels'] = {i: cls for i, cls in enumerate(self.all_classes)}
157                 col_preds = self.ord_encs[col_name].inverse_transform(np.argmax(col_preds, axis=1).reshape(-1, 1)).flatten()
158             if col_config.get('encoder_attrs', False):
159                 if col_config['encoder_attrs'].get('positive_domain', False):
160                     col_preds = col_preds.clip(0)
161             ypred[col_name]['predictions'] = list(col_preds)
162 
163         return ypred
164
```
--- 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/mixers/lightgbm.py b/lightwood/mixers/lightgbm.py
--- a/lightwood/mixers/lightgbm.py
+++ b/lightwood/mixers/lightgbm.py
@@ -123,6 +123,7 @@
                 if max_itt >= num_iterations and seconds_for_one_iteration < 10:
                     self.grid_search = True
                     kwargs['time_budget'] = self.stop_training_after_seconds
+                    kwargs['optuna_seed'] = 0  # for reproducible grid search results
 
             train_data = lightgbm.Dataset(data['train']['data'], label=data['train']['label_data'][col_name])
             validate_data = lightgbm.Dataset(data['test']['data'], label=data['test']['label_data'][col_name])

{"golden_diff": "diff --git a/lightwood/mixers/lightgbm.py b/lightwood/mixers/lightgbm.py\n--- a/lightwood/mixers/lightgbm.py\n+++ b/lightwood/mixers/lightgbm.py\n@@ -123,6 +123,7 @@\n                 if max_itt >= num_iterations and seconds_for_one_iteration < 10:\n                     self.grid_search = True\n                     kwargs['time_budget'] = self.stop_training_after_seconds\n+                    kwargs['optuna_seed'] = 0  # for reproducible grid search results\n \n             train_data = lightgbm.Dataset(data['train']['data'], label=data['train']['label_data'][col_name])\n             validate_data = lightgbm.Dataset(data['test']['data'], label=data['test']['label_data'][col_name])\n", "issue": "LightGBM is not deterministic\n* Lightwood version: 0.58.0\r\n\r\nCurrently, our LightGBM mixer is not deterministic, presenting slight performance differences when trained for the same dataset. We should fix the corresponding random seeds so that this is doesn't happen anymore.\r\n\n", "before_files": [{"content": "import numpy as np\nimport optuna.integration.lightgbm as lgb\nimport lightgbm\nimport optuna\nimport torch\nimport logging\nimport time\n\nfrom lightwood.constants.lightwood import COLUMN_DATA_TYPES\nfrom lightwood.helpers.device import get_devices\nfrom lightwood.mixers import BaseMixer\nfrom sklearn.preprocessing import OrdinalEncoder\n\n\noptuna.logging.set_verbosity(optuna.logging.CRITICAL)\n\n\ndef check_gpu_support():\n    try:\n        data = np.random.rand(50, 2)\n        label = np.random.randint(2, size=50)\n        train_data = lightgbm.Dataset(data, label=label)\n        params = {'num_iterations': 1, 'device': 'gpu'}\n        gbm = lightgbm.train(params, train_set=train_data)\n        return True\n    except Exception as e:\n        return False\n\nclass LightGBMMixer(BaseMixer):\n    def __init__(self, stop_training_after_seconds=None, grid_search=False):\n        super().__init__()\n        self.models = {}\n        self.ord_encs = {}\n        self.label_sets = {}\n        self.stop_training_after_seconds = stop_training_after_seconds\n        self.grid_search = grid_search  # using Optuna\n\n        # GPU Only available via --install-option=--gpu with opencl-dev and libboost dev (a bunch of them) installed, so let's turn this off for now and we can put it behind some flag later\n        self.device, _ = get_devices()\n        self.device_str = 'cpu' if str(self.device) == 'cpu' else 'gpu'\n        if self.device_str == 'gpu':\n            gpu_works = check_gpu_support()\n            if not gpu_works:\n                self.device = torch.device('cpu')\n                self.device_str = 'cpu'\n\n        self.max_bin = 255  # Default value\n        if self.device_str == 'gpu':\n            self.max_bin = 63  # As recommended by https://lightgbm.readthedocs.io/en/latest/Parameters.html#device_type\n\n    def _fit(self, train_ds, test_ds=None):\n        \"\"\"\n        :param train_ds: DataSource\n        :param test_ds: DataSource\n        \"\"\"\n\n        data = {\n            'train': {'ds': train_ds, 'data': None, 'label_data': {}},\n            'test': {'ds': test_ds, 'data': None, 'label_data': {}}\n        }\n\n        # Order is important here\n        for subset_name in ['train','test']:\n            cols = data[subset_name]['ds'].input_feature_names\n            out_cols = data[subset_name]['ds'].output_feature_names\n            for col_name in cols:\n                if data[subset_name]['data'] is None:\n                    data[subset_name]['data'] = data[subset_name]['ds'].get_encoded_column_data(col_name).to(self.device)\n                else:\n                    enc_col = data[subset_name]['ds'].get_encoded_column_data(col_name)\n                    data[subset_name]['data'] = torch.cat((data[subset_name]['data'], enc_col.to(self.device)), 1)\n            data[subset_name]['data'] = data[subset_name]['data'].tolist()\n            for col_name in out_cols:\n                label_data = data[subset_name]['ds'].get_column_original_data(col_name)\n                if next(item for item in train_ds.output_features if item[\"name\"] == col_name)['type'] == COLUMN_DATA_TYPES.CATEGORICAL:\n                    if subset_name == 'train':\n                        self.ord_encs[col_name] = OrdinalEncoder()\n                        self.label_sets[col_name] = set(label_data)\n                        self.label_sets[col_name].add('__mdb_unknown_cat')\n                        self.ord_encs[col_name].fit(np.array(list(self.label_sets[col_name])).reshape(-1, 1))\n\n                    label_data = [x if x in self.label_sets[col_name] else '__mdb_unknown_cat' for x in label_data]\n                    label_data = self.ord_encs[col_name].transform(np.array(label_data).reshape(-1, 1)).flatten()\n\n                data[subset_name]['label_data'][col_name] = label_data\n\n        for col_name in train_ds.output_feature_names:\n            dtype = next(item for item in train_ds.output_features if item[\"name\"] == col_name)['type']\n            if dtype not in [COLUMN_DATA_TYPES.NUMERIC, COLUMN_DATA_TYPES.CATEGORICAL]:\n                logging.info('cannot support {dtype} in lightgbm'.format(dtype=dtype))\n                continue\n            else:\n                objective = 'regression' if dtype == COLUMN_DATA_TYPES.NUMERIC else 'multiclass'\n                metric = 'l2' if dtype == COLUMN_DATA_TYPES.NUMERIC else 'multi_logloss'\n\n            params = {'objective': objective,\n                      'metric': metric,\n                      'verbose': -1,\n                      'lambda_l1': 0.1,\n                      'lambda_l2': 0.1,\n                      'force_row_wise': True,\n                      'device_type': self.device_str\n                      }\n            if objective == 'multiclass':\n                self.all_classes = self.ord_encs[col_name].categories_[0]\n                params['num_class'] = self.all_classes.size\n\n            num_iterations = 50\n            kwargs = {}\n\n            if self.stop_training_after_seconds is not None:\n                train_data = lightgbm.Dataset(data['train']['data'], label=data['train']['label_data'][col_name])\n                validate_data = lightgbm.Dataset(data['test']['data'], label=data['test']['label_data'][col_name])\n                start = time.time()\n                params['num_iterations'] = 1\n                bst = lightgbm.train(params, train_data, valid_sets=validate_data, verbose_eval=False)\n                end = time.time()\n                seconds_for_one_iteration = max(0.1, end - start)\n                logging.info(f'A single GBM itteration takes {seconds_for_one_iteration} seconds')\n                max_itt = int(self.stop_training_after_seconds / seconds_for_one_iteration)\n                num_iterations = max(1, min(num_iterations, max_itt))\n                # Turn on grid search if training doesn't take too long using it\n                if max_itt >= num_iterations and seconds_for_one_iteration < 10:\n                    self.grid_search = True\n                    kwargs['time_budget'] = self.stop_training_after_seconds\n\n            train_data = lightgbm.Dataset(data['train']['data'], label=data['train']['label_data'][col_name])\n            validate_data = lightgbm.Dataset(data['test']['data'], label=data['test']['label_data'][col_name])\n            model = lgb if self.grid_search else lightgbm\n            logging.info(f'Training GBM ({model}) with {num_iterations} iterations given {self.stop_training_after_seconds} seconds constraint')\n            params['num_iterations'] = num_iterations\n            bst = model.train(params, train_data, valid_sets=validate_data, verbose_eval=False, **kwargs)\n\n            self.models[col_name] = bst\n\n    def _predict(self, when_data_source, include_extra_data=False):\n        \"\"\"\n        :param when_data_source: DataSource\n        :param include_extra_data: bool\n        \"\"\"\n        data = None\n        for col_name in when_data_source.input_feature_names:\n            if data is None:\n                data = when_data_source.get_encoded_column_data(col_name).to(self.device)\n            else:\n                data = torch.cat((data, when_data_source.get_encoded_column_data(col_name).to(self.device)), 1)\n        data = data.tolist()\n\n        ypred = {}\n        for col_name in when_data_source.output_feature_names:\n            col_config = [conf for conf in when_data_source.config['output_features'] if conf['name'] == col_name][0]\n            col_preds = self.models[col_name].predict(data)\n            ypred[col_name] = {}\n            if col_name in self.ord_encs:\n                ypred[col_name]['class_distribution'] = list(col_preds)\n                ypred[col_name]['class_labels'] = {i: cls for i, cls in enumerate(self.all_classes)}\n                col_preds = self.ord_encs[col_name].inverse_transform(np.argmax(col_preds, axis=1).reshape(-1, 1)).flatten()\n            if col_config.get('encoder_attrs', False):\n                if col_config['encoder_attrs'].get('positive_domain', False):\n                    col_preds = col_preds.clip(0)\n            ypred[col_name]['predictions'] = list(col_preds)\n\n        return ypred\n", "path": "lightwood/mixers/lightgbm.py"}], "after_files": [{"content": "import numpy as np\nimport optuna.integration.lightgbm as lgb\nimport lightgbm\nimport optuna\nimport torch\nimport logging\nimport time\n\nfrom lightwood.constants.lightwood import COLUMN_DATA_TYPES\nfrom lightwood.helpers.device import get_devices\nfrom lightwood.mixers import BaseMixer\nfrom sklearn.preprocessing import OrdinalEncoder\n\n\noptuna.logging.set_verbosity(optuna.logging.CRITICAL)\n\n\ndef check_gpu_support():\n    try:\n        data = np.random.rand(50, 2)\n        label = np.random.randint(2, size=50)\n        train_data = lightgbm.Dataset(data, label=label)\n        params = {'num_iterations': 1, 'device': 'gpu'}\n        gbm = lightgbm.train(params, train_set=train_data)\n        return True\n    except Exception as e:\n        return False\n\nclass LightGBMMixer(BaseMixer):\n    def __init__(self, stop_training_after_seconds=None, grid_search=False):\n        super().__init__()\n        self.models = {}\n        self.ord_encs = {}\n        self.label_sets = {}\n        self.stop_training_after_seconds = stop_training_after_seconds\n        self.grid_search = grid_search  # using Optuna\n\n        # GPU Only available via --install-option=--gpu with opencl-dev and libboost dev (a bunch of them) installed, so let's turn this off for now and we can put it behind some flag later\n        self.device, _ = get_devices()\n        self.device_str = 'cpu' if str(self.device) == 'cpu' else 'gpu'\n        if self.device_str == 'gpu':\n            gpu_works = check_gpu_support()\n            if not gpu_works:\n                self.device = torch.device('cpu')\n                self.device_str = 'cpu'\n\n        self.max_bin = 255  # Default value\n        if self.device_str == 'gpu':\n            self.max_bin = 63  # As recommended by https://lightgbm.readthedocs.io/en/latest/Parameters.html#device_type\n\n    def _fit(self, train_ds, test_ds=None):\n        \"\"\"\n        :param train_ds: DataSource\n        :param test_ds: DataSource\n        \"\"\"\n\n        data = {\n            'train': {'ds': train_ds, 'data': None, 'label_data': {}},\n            'test': {'ds': test_ds, 'data': None, 'label_data': {}}\n        }\n\n        # Order is important here\n        for subset_name in ['train','test']:\n            cols = data[subset_name]['ds'].input_feature_names\n            out_cols = data[subset_name]['ds'].output_feature_names\n            for col_name in cols:\n                if data[subset_name]['data'] is None:\n                    data[subset_name]['data'] = data[subset_name]['ds'].get_encoded_column_data(col_name).to(self.device)\n                else:\n                    enc_col = data[subset_name]['ds'].get_encoded_column_data(col_name)\n                    data[subset_name]['data'] = torch.cat((data[subset_name]['data'], enc_col.to(self.device)), 1)\n            data[subset_name]['data'] = data[subset_name]['data'].tolist()\n            for col_name in out_cols:\n                label_data = data[subset_name]['ds'].get_column_original_data(col_name)\n                if next(item for item in train_ds.output_features if item[\"name\"] == col_name)['type'] == COLUMN_DATA_TYPES.CATEGORICAL:\n                    if subset_name == 'train':\n                        self.ord_encs[col_name] = OrdinalEncoder()\n                        self.label_sets[col_name] = set(label_data)\n                        self.label_sets[col_name].add('__mdb_unknown_cat')\n                        self.ord_encs[col_name].fit(np.array(list(self.label_sets[col_name])).reshape(-1, 1))\n\n                    label_data = [x if x in self.label_sets[col_name] else '__mdb_unknown_cat' for x in label_data]\n                    label_data = self.ord_encs[col_name].transform(np.array(label_data).reshape(-1, 1)).flatten()\n\n                data[subset_name]['label_data'][col_name] = label_data\n\n        for col_name in train_ds.output_feature_names:\n            dtype = next(item for item in train_ds.output_features if item[\"name\"] == col_name)['type']\n            if dtype not in [COLUMN_DATA_TYPES.NUMERIC, COLUMN_DATA_TYPES.CATEGORICAL]:\n                logging.info('cannot support {dtype} in lightgbm'.format(dtype=dtype))\n                continue\n            else:\n                objective = 'regression' if dtype == COLUMN_DATA_TYPES.NUMERIC else 'multiclass'\n                metric = 'l2' if dtype == COLUMN_DATA_TYPES.NUMERIC else 'multi_logloss'\n\n            params = {'objective': objective,\n                      'metric': metric,\n                      'verbose': -1,\n                      'lambda_l1': 0.1,\n                      'lambda_l2': 0.1,\n                      'force_row_wise': True,\n                      'device_type': self.device_str\n                      }\n            if objective == 'multiclass':\n                self.all_classes = self.ord_encs[col_name].categories_[0]\n                params['num_class'] = self.all_classes.size\n\n            num_iterations = 50\n            kwargs = {}\n\n            if self.stop_training_after_seconds is not None:\n                train_data = lightgbm.Dataset(data['train']['data'], label=data['train']['label_data'][col_name])\n                validate_data = lightgbm.Dataset(data['test']['data'], label=data['test']['label_data'][col_name])\n                start = time.time()\n                params['num_iterations'] = 1\n                bst = lightgbm.train(params, train_data, valid_sets=validate_data, verbose_eval=False)\n                end = time.time()\n                seconds_for_one_iteration = max(0.1, end - start)\n                logging.info(f'A single GBM itteration takes {seconds_for_one_iteration} seconds')\n                max_itt = int(self.stop_training_after_seconds / seconds_for_one_iteration)\n                num_iterations = max(1, min(num_iterations, max_itt))\n                # Turn on grid search if training doesn't take too long using it\n                if max_itt >= num_iterations and seconds_for_one_iteration < 10:\n                    self.grid_search = True\n                    kwargs['time_budget'] = self.stop_training_after_seconds\n                    kwargs['optuna_seed'] = 0  # for reproducible grid search results\n\n            train_data = lightgbm.Dataset(data['train']['data'], label=data['train']['label_data'][col_name])\n            validate_data = lightgbm.Dataset(data['test']['data'], label=data['test']['label_data'][col_name])\n            model = lgb if self.grid_search else lightgbm\n            logging.info(f'Training GBM ({model}) with {num_iterations} iterations given {self.stop_training_after_seconds} seconds constraint')\n            params['num_iterations'] = num_iterations\n            bst = model.train(params, train_data, valid_sets=validate_data, verbose_eval=False, **kwargs)\n\n            self.models[col_name] = bst\n\n    def _predict(self, when_data_source, include_extra_data=False):\n        \"\"\"\n        :param when_data_source: DataSource\n        :param include_extra_data: bool\n        \"\"\"\n        data = None\n        for col_name in when_data_source.input_feature_names:\n            if data is None:\n                data = when_data_source.get_encoded_column_data(col_name).to(self.device)\n            else:\n                data = torch.cat((data, when_data_source.get_encoded_column_data(col_name).to(self.device)), 1)\n        data = data.tolist()\n\n        ypred = {}\n        for col_name in when_data_source.output_feature_names:\n            col_config = [conf for conf in when_data_source.config['output_features'] if conf['name'] == col_name][0]\n            col_preds = self.models[col_name].predict(data)\n            ypred[col_name] = {}\n            if col_name in self.ord_encs:\n                ypred[col_name]['class_distribution'] = list(col_preds)\n                ypred[col_name]['class_labels'] = {i: cls for i, cls in enumerate(self.all_classes)}\n                col_preds = self.ord_encs[col_name].inverse_transform(np.argmax(col_preds, axis=1).reshape(-1, 1)).flatten()\n            if col_config.get('encoder_attrs', False):\n                if col_config['encoder_attrs'].get('positive_domain', False):\n                    col_preds = col_preds.clip(0)\n            ypred[col_name]['predictions'] = list(col_preds)\n\n        return ypred\n", "path": "lightwood/mixers/lightgbm.py"}]}