ValueError: math domain error shown when `dls.show_batch()` called?

This is my list of batch transforms-

batch_transforms = [
                    # some transformation classes
                    Saturation(max_lighting=3.0, p=0.75),
                    # some other transformation classes
                    ]

And this is my DataLoading and creating a DataBlock-

db = DataBlock(
    blocks=(ImageBlock, CategoryBlock()),
    getters=[ColReader('fname', pref=TRAIN_DIR),
             ColReader('class')],
    splitter=RandomSplitter(valid_pct=0.15, seed=42),
    item_tfms=Resize(IMG_SIZE),
    batch_tfms=batch_transforms
)

dls = db.dataloaders(train_df, bs=BATCH_SIZE)

When I call dls.show_batch() I get this error-

ValueError: math domain error

Here’s the full error:

Expand full error
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-11-90634fcc3c9e> in <module>()
----> 1 dls.show_batch()

10 frames
/usr/local/lib/python3.7/dist-packages/fastai/data/core.py in show_batch(self, b, max_n, ctxs, show, unique, **kwargs)
    100             old_get_idxs = self.get_idxs
    101             self.get_idxs = lambda: Inf.zeros
--> 102         if b is None: b = self.one_batch()
    103         if not show: return self._pre_show_batch(b, max_n=max_n)
    104         show_batch(*self._pre_show_batch(b, max_n=max_n), ctxs=ctxs, max_n=max_n, **kwargs)

/usr/local/lib/python3.7/dist-packages/fastai/data/load.py in one_batch(self)
    148     def one_batch(self):
    149         if self.n is not None and len(self)==0: raise ValueError(f'This DataLoader does not contain any batches')
--> 150         with self.fake_l.no_multiproc(): res = first(self)
    151         if hasattr(self, 'it'): delattr(self, 'it')
    152         return res

/usr/local/lib/python3.7/dist-packages/fastcore/basics.py in first(x, f, negate, **kwargs)
    545     x = iter(x)
    546     if f: x = filter_ex(x, f=f, negate=negate, gen=True, **kwargs)
--> 547     return next(x, None)
    548 
    549 # Cell

/usr/local/lib/python3.7/dist-packages/fastai/data/load.py in __iter__(self)
    111             if self.device is not None and multiprocessing.get_start_method().lower() == "fork":
    112                 b = to_device(b, self.device)
--> 113             yield self.after_batch(b)
    114         self.after_iter()
    115         if hasattr(self, 'it'): del(self.it)

/usr/local/lib/python3.7/dist-packages/fastcore/transform.py in __call__(self, o)
    196         self.fs.append(t)
    197 
--> 198     def __call__(self, o): return compose_tfms(o, tfms=self.fs, split_idx=self.split_idx)
    199     def __repr__(self): return f"Pipeline: {' -> '.join([f.name for f in self.fs if f.name != 'noop'])}"
    200     def __getitem__(self,i): return self.fs[i]

/usr/local/lib/python3.7/dist-packages/fastcore/transform.py in compose_tfms(x, tfms, is_enc, reverse, **kwargs)
    148     for f in tfms:
    149         if not is_enc: f = f.decode
--> 150         x = f(x, **kwargs)
    151     return x
    152 

/usr/local/lib/python3.7/dist-packages/fastai/vision/augment.py in __call__(self, b, split_idx, **kwargs)
     32 
     33     def __call__(self, b, split_idx=None, **kwargs):
---> 34         self.before_call(b, split_idx=split_idx)
     35         return super().__call__(b, split_idx=split_idx, **kwargs) if self.do else b
     36 

/usr/local/lib/python3.7/dist-packages/fastai/vision/augment.py in before_call(self, b, split_idx)
    680         self.do = True
    681         while isinstance(b, tuple): b = b[0]
--> 682         for t in self.fs: t.before_call(b)
    683 
    684     def compose(self, tfm):

/usr/local/lib/python3.7/dist-packages/fastai/vision/augment.py in before_call(self, x)
    733 
    734     def before_call(self, x):
--> 735         self.change = _draw_mask(x, self._def_draw, draw=self.draw, p=self.p, neutral=1., batch=self.batch)
    736 
    737     def __call__(self, x): return x.mul_(self.change[:,None,None,None])

/usr/local/lib/python3.7/dist-packages/fastai/vision/augment.py in _draw_mask(x, def_draw, draw, p, neutral, batch)
    447     "Creates mask_tensor based on `x` with `neutral` with probability `1-p`. "
    448     if draw is None: draw=def_draw
--> 449     if callable(draw): res=draw(x)
    450     elif is_listy(draw):
    451         assert len(draw)>=x.size(0)

/usr/local/lib/python3.7/dist-packages/fastai/vision/augment.py in _def_draw(self, x)
    728 
    729     def _def_draw(self, x):
--> 730         if not self.batch: res = x.new_empty(x.size(0)).uniform_(math.log(1-self.max_lighting), -math.log(1-self.max_lighting))
    731         else: res = x.new_zeros(x.size(0)) + random.uniform(math.log(1-self.max_lighting), -math.log(1-self.max_lighting))
    732         return torch.exp(res)

ValueError: math domain error

And I am also shown this not-so-helpful error message when I ran the DataLoading cell-

Could not do one pass in your dataloader, there is something wrong in it

Can you shed some light into what’s wrong?

Try doing db.summary(df_train) and post what it says. Likely it’s one of the params you set in your transforms

1 Like

db.summary(train_df) returns-


Setting-up type transforms pipelines
Collecting items from                  file   label
0      XXX_0002.jpg   XXX
...               ...     ...
11497     YYY_0594.jpg      YYY

[11498 rows x 2 columns]
Found 11498 items
2 datasets of sizes 9774,1724
Setting up Pipeline: ColReader -- {'cols': 'file', 'pref': Path('path'), 'suff': '', 'label_delim': None} -> PILBase.create
Setting up Pipeline: ColReader -- {'cols': 'label', 'pref': '', 'suff': '', 'label_delim': None} -> Categorize -- {'vocab': None, 'sort': True, 'add_na': False}

Building one sample
  Pipeline: ColReader -- {'cols': 'file', 'pref': Path('path'), 'suff': '', 'label_delim': None} -> PILBase.create
    starting from
      file     886_0190.jpg
label             886
Name: 8171, dtype: object
    applying ColReader -- {'cols': 'file', 'pref': Path('path'), 'suff': '', 'label_delim': None} gives
      /content/drive/MyDrive/tea/train/886_0190.jpg
    applying PILBase.create gives
      PILImage mode=RGB size=1728x1152
  Pipeline: ColReader -- {'cols': 'label', 'pref': '', 'suff': '', 'label_delim': None} -> Categorize -- {'vocab': None, 'sort': True, 'add_na': False}
    starting from
      file     886_0190.jpg
label             886
Name: 8171, dtype: object
    applying ColReader -- {'cols': 'label', 'pref': '', 'suff': '', 'label_delim': None} gives
       886
    applying Categorize -- {'vocab': None, 'sort': True, 'add_na': False} gives
      TensorCategory(16)

Final sample: (PILImage mode=RGB size=1728x1152, TensorCategory(16))


Collecting items from                  file   label
0      XXX_0002.jpg   XXX
...               ...     ...
11497     YYY_0594.jpg      YYY

[11498 rows x 2 columns]
Found 11498 items
2 datasets of sizes 9774,1724
Setting up Pipeline: ColReader -- {'cols': 'file', 'pref': Path('path'), 'suff': '', 'label_delim': None} -> PILBase.create
Setting up Pipeline: ColReader -- {'cols': 'label', 'pref': '', 'suff': '', 'label_delim': None} -> Categorize -- {'vocab': None, 'sort': True, 'add_na': False}
Setting up after_item: Pipeline: Resize -- {'size': (450, 450), 'method': 'crop', 'pad_mode': 'reflection', 'resamples': (2, 0), 'p': 1.0} -> ToTensor
Setting up before_batch: Pipeline: 
Setting up after_batch: Pipeline: DihedralItem -- {'p': 1.0} -> IntToFloatTensor -- {'div': 255.0, 'div_mask': 1} -> DeterministicDihedral -- {'size': None, 'mode': 'bilinear', 'pad_mode': 'reflection', 'mode_mask': 'nearest', 'align_corners': None, 'p': 1.0} -> Rotate -- {'size': None, 'mode': 'bilinear', 'pad_mode': 'reflection', 'mode_mask': 'nearest', 'align_corners': True, 'p': 1.0} -> Zoom -- {'size': None, 'mode': 'bilinear', 'pad_mode': 'reflection', 'mode_mask': 'nearest', 'align_corners': True, 'p': 1.0} -> RandomResizedCropGPU -- {'size': (300, 300), 'min_scale': 0.8, 'ratio': (0.75, 1.3333333333333333), 'mode': 'bilinear', 'valid_scale': 1.0, 'max_scale': 1.0, 'p': 1.0} -> Brightness -- {'max_lighting': 0.75, 'p': 1.0, 'draw': None, 'batch': False} -> Contrast -- {'max_lighting': 1.0, 'p': 1.0, 'draw': None, 'batch': False} -> Saturation -- {'max_lighting': 3.0, 'p': 1.0, 'draw': None, 'batch': False} -> Normalize -- {'mean': tensor([[[[0.4850]],

         [[0.4560]],

         [[0.4060]]]], device='cuda:0'), 'std': tensor([[[[0.2290]],

         [[0.2240]],

         [[0.2250]]]], device='cuda:0'), 'axes': (0, 2, 3)}
Could not do one pass in your dataloader, there is something wrong in it

Building one batch
Applying item_tfms to the first sample:
  Pipeline: Resize -- {'size': (450, 450), 'method': 'crop', 'pad_mode': 'reflection', 'resamples': (2, 0), 'p': 1.0} -> ToTensor
    starting from
      (PILImage mode=RGB size=1728x1152, TensorCategory(16))
    applying Resize -- {'size': (450, 450), 'method': 'crop', 'pad_mode': 'reflection', 'resamples': (2, 0), 'p': 1.0} gives
      (PILImage mode=RGB size=450x450, TensorCategory(16))
    applying ToTensor gives
      (TensorImage of size 3x450x450, TensorCategory(16))

Adding the next 3 samples

No before_batch transform to apply

Collating items in a batch

Applying batch_tfms to the batch built
  Pipeline: DihedralItem -- {'p': 1.0} -> IntToFloatTensor -- {'div': 255.0, 'div_mask': 1} -> DeterministicDihedral -- {'size': None, 'mode': 'bilinear', 'pad_mode': 'reflection', 'mode_mask': 'nearest', 'align_corners': None, 'p': 1.0} -> Rotate -- {'size': None, 'mode': 'bilinear', 'pad_mode': 'reflection', 'mode_mask': 'nearest', 'align_corners': True, 'p': 1.0} -> Zoom -- {'size': None, 'mode': 'bilinear', 'pad_mode': 'reflection', 'mode_mask': 'nearest', 'align_corners': True, 'p': 1.0} -> RandomResizedCropGPU -- {'size': (300, 300), 'min_scale': 0.8, 'ratio': (0.75, 1.3333333333333333), 'mode': 'bilinear', 'valid_scale': 1.0, 'max_scale': 1.0, 'p': 1.0} -> Brightness -- {'max_lighting': 0.75, 'p': 1.0, 'draw': None, 'batch': False} -> Contrast -- {'max_lighting': 1.0, 'p': 1.0, 'draw': None, 'batch': False} -> Saturation -- {'max_lighting': 3.0, 'p': 1.0, 'draw': None, 'batch': False} -> Normalize -- {'mean': tensor([[[[0.4850]],

         [[0.4560]],

         [[0.4060]]]], device='cuda:0'), 'std': tensor([[[[0.2290]],

         [[0.2240]],

         [[0.2250]]]], device='cuda:0'), 'axes': (0, 2, 3)}
    starting from
      (TensorImage of size 4x3x450x450, TensorCategory([16,  3,  4,  9], device='cuda:0'))
    applying DihedralItem -- {'p': 1.0} gives
      (TensorImage of size 4x3x450x450, TensorCategory([16,  3,  4,  9], device='cuda:0'))
    applying IntToFloatTensor -- {'div': 255.0, 'div_mask': 1} gives
      (TensorImage of size 4x3x450x450, TensorCategory([16,  3,  4,  9], device='cuda:0'))
    applying DeterministicDihedral -- {'size': None, 'mode': 'bilinear', 'pad_mode': 'reflection', 'mode_mask': 'nearest', 'align_corners': None, 'p': 1.0} gives
      (TensorImage of size 4x3x450x450, TensorCategory([16,  3,  4,  9], device='cuda:0'))
    applying Rotate -- {'size': None, 'mode': 'bilinear', 'pad_mode': 'reflection', 'mode_mask': 'nearest', 'align_corners': True, 'p': 1.0} gives
      (TensorImage of size 4x3x450x450, TensorCategory([16,  3,  4,  9], device='cuda:0'))
    applying Zoom -- {'size': None, 'mode': 'bilinear', 'pad_mode': 'reflection', 'mode_mask': 'nearest', 'align_corners': True, 'p': 1.0} gives
      (TensorImage of size 4x3x450x450, TensorCategory([16,  3,  4,  9], device='cuda:0'))
    applying RandomResizedCropGPU -- {'size': (300, 300), 'min_scale': 0.8, 'ratio': (0.75, 1.3333333333333333), 'mode': 'bilinear', 'valid_scale': 1.0, 'max_scale': 1.0, 'p': 1.0} gives
      (TensorImage of size 4x3x300x300, TensorCategory([16,  3,  4,  9], device='cuda:0'))
    applying Brightness -- {'max_lighting': 0.75, 'p': 1.0, 'draw': None, 'batch': False} gives
      (TensorImage of size 4x3x300x300, TensorCategory([16,  3,  4,  9], device='cuda:0'))
    applying Contrast -- {'max_lighting': 1.0, 'p': 1.0, 'draw': None, 'batch': False} failed.
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-13-fc1414bb97f0> in <module>()
----> 1 db.summary(train_df)

7 frames
/usr/local/lib/python3.7/dist-packages/fastai/vision/augment.py in _def_draw(self, x)
    728 
    729     def _def_draw(self, x):
--> 730         if not self.batch: res = x.new_empty(x.size(0)).uniform_(math.log(1-self.max_lighting), -math.log(1-self.max_lighting))
    731         else: res = x.new_zeros(x.size(0)) + random.uniform(math.log(1-self.max_lighting), -math.log(1-self.max_lighting))
    732         return torch.exp(res)

ValueError: math domain error

@muellerzr I think I am getting a ZeroDivisionError here-

draw can be specified if you want to customize the magnitude that is picked when the transform is applied (default is a random float taken with the log uniform distribution between (1-max_lighting) and 1/(1-max_lighting) . Each can be a float, a list of floats (which then should have a length equal to or greater than the size of the batch) or a callable that returns a float tensor.

From https://docs.fast.ai/vision.augment.html#Contrast

So the denominator of 1/(1-max_lighting) gives zero when 1.0 is randomly chosen as the max_lighting.

Saturation(max_lighting=3.0, p=0.75)

is the root of the error. I changed the value passed as max_lighting to 0.9 and it works fine.

I was mistaken as it says in the documentation that you can set the saturation scale by using the draw parameter, and not the max_lighting parameter.

The latter must be within 1.0, where the value(s) in draw is not constrained.

Some of my images in the batch are just all black pixels or very near to them!

image