Repository: autogluon/autogluon

Issue:
TypeError: argument of type 'NoneType' is not iterable
My data has two columns, `[image,labels]` and I load images as follow
df = ImagePredictor.Dataset.from_csv('train.csv', root='train_images')
when I do `df.show_images()` it plot the images. But when I do 
```
predictor = ImagePredictor()
predictor.fit(df, hyperparameters={'epochs': 2})
```
It gives following  error 
```
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-39-e0442c33015a> in <module>
      1 predictor = ImagePredictor()
----> 2 predictor.fit(df, hyperparameters={'epochs': 2})  # you can trust the default config, we reduce the # epoch to save some build time

/opt/conda/lib/python3.7/site-packages/autogluon/vision/configs/presets_configs.py in _call(*args, **kwargs)
     13         def _call(*args, **kwargs):
     14             gargs, gkwargs = set_presets(preset_name, *args, **kwargs)
---> 15             return f(*gargs, **gkwargs)
     16         return _call
     17     return _unpack_inner

/opt/conda/lib/python3.7/site-packages/autogluon/vision/predictor/predictor.py in fit(self, train_data, tuning_data, time_limit, presets, hyperparameters, **kwargs)
    293 
    294         # data sanity check
--> 295         train_data = self._validate_data(train_data)
    296         train_labels = _get_valid_labels(train_data)
    297         self._label_cleaner = LabelCleaner.construct(problem_type=self._problem_type, y=train_labels, y_uncleaned=train_labels)

/opt/conda/lib/python3.7/site-packages/autogluon/vision/predictor/predictor.py in _validate_data(self, data)
    414                 raise TypeError(f"Unable to process dataset of type: {type(data)}")
    415         elif isinstance(data, _ImageClassification.Dataset):
--> 416             assert 'label' in data.columns
    417             assert hasattr(data, 'classes')
    418             # check whether classes are outdated, no action required if all unique labels is subset of `classes`

AssertionError: 
```
which mean that column name should be `label` instead of `labels`
so when I changed column name with `label` as follow
```
df = ImagePredictor.Dataset.from_csv('train.csv', root='train_images')
df.columns=['image','label']
```
and do `df.show_images()` I got following error
```
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-41-741ee22ad2e8> in <module>
----> 1 df.show_images()

/opt/conda/lib/python3.7/site-packages/gluoncv/auto/data/dataset.py in show_images(self, indices, nsample, ncol, shuffle, resize, fontsize)
    132         if 'label' in self.columns:
    133             titles = [self.classes[int(self.at[idx, 'label'])] + ': ' + str(self.at[idx, 'label']) \
--> 134                 for idx in indices if idx < len(self)]
    135         _show_images(images, cols=ncol, titles=titles, fontsize=fontsize)
    136 

/opt/conda/lib/python3.7/site-packages/gluoncv/auto/data/dataset.py in <listcomp>(.0)
    132         if 'label' in self.columns:
    133             titles = [self.classes[int(self.at[idx, 'label'])] + ': ' + str(self.at[idx, 'label']) \
--> 134                 for idx in indices if idx < len(self)]
    135         _show_images(images, cols=ncol, titles=titles, fontsize=fontsize)
    136 

ValueError: invalid literal for int() with base 10: 'frog_eye_leaf_spot'
```
and 
```
predictor = ImagePredictor()
predictor.fit(df, hyperparameters={'epochs': 2})
```
gives following error

```
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-42-e0442c33015a> in <module>
      1 predictor = ImagePredictor()
----> 2 predictor.fit(df, hyperparameters={'epochs': 2})  # you can trust the default config, we reduce the # epoch to save some build time

/opt/conda/lib/python3.7/site-packages/autogluon/vision/configs/presets_configs.py in _call(*args, **kwargs)
     13         def _call(*args, **kwargs):
     14             gargs, gkwargs = set_presets(preset_name, *args, **kwargs)
---> 15             return f(*gargs, **gkwargs)
     16         return _call
     17     return _unpack_inner

/opt/conda/lib/python3.7/site-packages/autogluon/vision/predictor/predictor.py in fit(self, train_data, tuning_data, time_limit, presets, hyperparameters, **kwargs)
    293 
    294         # data sanity check
--> 295         train_data = self._validate_data(train_data)
    296         train_labels = _get_valid_labels(train_data)
    297         self._label_cleaner = LabelCleaner.construct(problem_type=self._problem_type, y=train_labels, y_uncleaned=train_labels)

/opt/conda/lib/python3.7/site-packages/autogluon/vision/predictor/predictor.py in _validate_data(self, data)
    418             # check whether classes are outdated, no action required if all unique labels is subset of `classes`
    419             unique_labels = sorted(data['label'].unique().tolist())
--> 420             if not (all(ulabel in data.classes for ulabel in unique_labels)):
    421                 data = _ImageClassification.Dataset(data, classes=unique_labels)
    422                 logger.log(20, f'Reset labels to {unique_labels}')

/opt/conda/lib/python3.7/site-packages/autogluon/vision/predictor/predictor.py in <genexpr>(.0)
    418             # check whether classes are outdated, no action required if all unique labels is subset of `classes`
    419             unique_labels = sorted(data['label'].unique().tolist())
--> 420             if not (all(ulabel in data.classes for ulabel in unique_labels)):
    421                 data = _ImageClassification.Dataset(data, classes=unique_labels)
    422                 logger.log(20, f'Reset labels to {unique_labels}')

TypeError: argument of type 'NoneType' is not iterable
```
I tried using label encoder but the problem is still there though error changes
TypeError: argument of type 'NoneType' is not iterable
My data has two columns, `[image,labels]` and I load images as follow
df = ImagePredictor.Dataset.from_csv('train.csv', root='train_images')
when I do `df.show_images()` it plot the images. But when I do 
```
predictor = ImagePredictor()
predictor.fit(df, hyperparameters={'epochs': 2})
```
It gives following  error 
```
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-39-e0442c33015a> in <module>
      1 predictor = ImagePredictor()
----> 2 predictor.fit(df, hyperparameters={'epochs': 2})  # you can trust the default config, we reduce the # epoch to save some build time

/opt/conda/lib/python3.7/site-packages/autogluon/vision/configs/presets_configs.py in _call(*args, **kwargs)
     13         def _call(*args, **kwargs):
     14             gargs, gkwargs = set_presets(preset_name, *args, **kwargs)
---> 15             return f(*gargs, **gkwargs)
     16         return _call
     17     return _unpack_inner

/opt/conda/lib/python3.7/site-packages/autogluon/vision/predictor/predictor.py in fit(self, train_data, tuning_data, time_limit, presets, hyperparameters, **kwargs)
    293 
    294         # data sanity check
--> 295         train_data = self._validate_data(train_data)
    296         train_labels = _get_valid_labels(train_data)
    297         self._label_cleaner = LabelCleaner.construct(problem_type=self._problem_type, y=train_labels, y_uncleaned=train_labels)

/opt/conda/lib/python3.7/site-packages/autogluon/vision/predictor/predictor.py in _validate_data(self, data)
    414                 raise TypeError(f"Unable to process dataset of type: {type(data)}")
    415         elif isinstance(data, _ImageClassification.Dataset):
--> 416             assert 'label' in data.columns
    417             assert hasattr(data, 'classes')
    418             # check whether classes are outdated, no action required if all unique labels is subset of `classes`

AssertionError: 
```
which mean that column name should be `label` instead of `labels`
so when I changed column name with `label` as follow
```
df = ImagePredictor.Dataset.from_csv('train.csv', root='train_images')
df.columns=['image','label']
```
and do `df.show_images()` I got following error
```
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-41-741ee22ad2e8> in <module>
----> 1 df.show_images()

/opt/conda/lib/python3.7/site-packages/gluoncv/auto/data/dataset.py in show_images(self, indices, nsample, ncol, shuffle, resize, fontsize)
    132         if 'label' in self.columns:
    133             titles = [self.classes[int(self.at[idx, 'label'])] + ': ' + str(self.at[idx, 'label']) \
--> 134                 for idx in indices if idx < len(self)]
    135         _show_images(images, cols=ncol, titles=titles, fontsize=fontsize)
    136 

/opt/conda/lib/python3.7/site-packages/gluoncv/auto/data/dataset.py in <listcomp>(.0)
    132         if 'label' in self.columns:
    133             titles = [self.classes[int(self.at[idx, 'label'])] + ': ' + str(self.at[idx, 'label']) \
--> 134                 for idx in indices if idx < len(self)]
    135         _show_images(images, cols=ncol, titles=titles, fontsize=fontsize)
    136 

ValueError: invalid literal for int() with base 10: 'frog_eye_leaf_spot'
```
and 
```
predictor = ImagePredictor()
predictor.fit(df, hyperparameters={'epochs': 2})
```
gives following error

```
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-42-e0442c33015a> in <module>
      1 predictor = ImagePredictor()
----> 2 predictor.fit(df, hyperparameters={'epochs': 2})  # you can trust the default config, we reduce the # epoch to save some build time

/opt/conda/lib/python3.7/site-packages/autogluon/vision/configs/presets_configs.py in _call(*args, **kwargs)
     13         def _call(*args, **kwargs):
     14             gargs, gkwargs = set_presets(preset_name, *args, **kwargs)
---> 15             return f(*gargs, **gkwargs)
     16         return _call
     17     return _unpack_inner

/opt/conda/lib/python3.7/site-packages/autogluon/vision/predictor/predictor.py in fit(self, train_data, tuning_data, time_limit, presets, hyperparameters, **kwargs)
    293 
    294         # data sanity check
--> 295         train_data = self._validate_data(train_data)
    296         train_labels = _get_valid_labels(train_data)
    297         self._label_cleaner = LabelCleaner.construct(problem_type=self._problem_type, y=train_labels, y_uncleaned=train_labels)

/opt/conda/lib/python3.7/site-packages/autogluon/vision/predictor/predictor.py in _validate_data(self, data)
    418             # check whether classes are outdated, no action required if all unique labels is subset of `classes`
    419             unique_labels = sorted(data['label'].unique().tolist())
--> 420             if not (all(ulabel in data.classes for ulabel in unique_labels)):
    421                 data = _ImageClassification.Dataset(data, classes=unique_labels)
    422                 logger.log(20, f'Reset labels to {unique_labels}')

/opt/conda/lib/python3.7/site-packages/autogluon/vision/predictor/predictor.py in <genexpr>(.0)
    418             # check whether classes are outdated, no action required if all unique labels is subset of `classes`
    419             unique_labels = sorted(data['label'].unique().tolist())
--> 420             if not (all(ulabel in data.classes for ulabel in unique_labels)):
    421                 data = _ImageClassification.Dataset(data, classes=unique_labels)
    422                 logger.log(20, f'Reset labels to {unique_labels}')

TypeError: argument of type 'NoneType' is not iterable
```
I tried using label encoder but the problem is still there though error changes


Discussion:
solution is that we need to change label of csv file first, then save it and then load it again. also need to perform encoding
i also tried to specify column name, but it did not work 
predictor = ImagePredictor(label="labels")

Here is[ colab notebook ](https://colab.research.google.com/drive/1UJw6Hvl7B-B9gdH5yMKt0jmY8bJt_wHa?usp=sharing)
solution is that we need to change label of csv file first, then save it and then load it again. also need to perform encoding
i also tried to specify column name, but it did not work 
predictor = ImagePredictor(label="labels")

Here is[ colab notebook ](https://colab.research.google.com/drive/1UJw6Hvl7B-B9gdH5yMKt0jmY8bJt_wHa?usp=sharing)

Resolving patch:
diff --git a/vision/src/autogluon/vision/predictor/predictor.py b/vision/src/autogluon/vision/predictor/predictor.py
--- a/vision/src/autogluon/vision/predictor/predictor.py
+++ b/vision/src/autogluon/vision/predictor/predictor.py
@@ -363,6 +363,12 @@ def fit(self,
             config['early_stop_baseline'] = -np.Inf
         if 'early_stop_max_value' not in config or config['early_stop_max_value'] == None:
             config['early_stop_max_value'] = np.Inf
+        # batch size cannot be larger than dataset size
+        bs = min(config.get('batch_size', 16), len(train_data))
+        config['batch_size'] = bs
+        if ngpus_per_trial is not None and ngpus_per_trial > 1 and bs < ngpus_per_trial:
+            # batch size must be larger than # gpus
+            config['ngpus_per_trial'] = bs
         # verbosity
         if log_level > logging.INFO:
             logging.getLogger('gluoncv.auto.tasks.image_classification').propagate = False
@@ -420,9 +426,13 @@ def _validate_data(self, data):
         elif isinstance(data, _ImageClassification.Dataset):
             assert 'label' in data.columns
             assert hasattr(data, 'classes')
+            orig_classes = data.classes
+            if not isinstance(data.classes, (tuple, list)):
+                # consider it as an invalid dataset without proper label, try to reconstruct as a normal DataFrame
+                orig_classes = []
             # check whether classes are outdated, no action required if all unique labels is subset of `classes`
             unique_labels = sorted(data['label'].unique().tolist())
-            if not (all(ulabel in data.classes for ulabel in unique_labels)):
+            if not (all(ulabel in orig_classes for ulabel in unique_labels)):
                 data = _ImageClassification.Dataset(data, classes=unique_labels)
                 logger.log(20, f'Reset labels to {unique_labels}')
         if len(data) < 1:


Test patch:
diff --git a/vision/tests/unittests/test_image_classification.py b/vision/tests/unittests/test_image_classification.py
--- a/vision/tests/unittests/test_image_classification.py
+++ b/vision/tests/unittests/test_image_classification.py
@@ -1,4 +1,6 @@
 from autogluon.vision import ImagePredictor as Task
+import autogluon.core as ag
+import os
 import pandas as pd
 import numpy as np
 import copy
@@ -47,3 +49,11 @@ def test_task_label_remap():
     score_accuracy = accuracy(y_true=test_dataset['label'], y_pred=pred)
     score_log_loss = log_loss(y_true=test_dataset['label'].replace(label_remap_inverse), y_pred=pred_proba.to_numpy())
     assert score_accuracy > 0.2  # relax
+
+def test_invalid_image_dataset():
+    ImagePredictor = Task
+    invalid_test = ag.download('https://autogluon.s3-us-west-2.amazonaws.com/miscs/test_autogluon_invalid_dataset.zip')
+    invalid_test = ag.unzip(invalid_test)
+    df = ImagePredictor.Dataset.from_csv(os.path.join(invalid_test, 'train.csv'), root=os.path.join(invalid_test, 'train_images'))
+    predictor = ImagePredictor(label="labels")
+    predictor.fit(df, df.copy(), time_limit=60)