Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

modify_exception introduces another (nested) exception #4019

Open
BagelOrb opened this issue Apr 2, 2024 · 1 comment
Open

modify_exception introduces another (nested) exception #4019

BagelOrb opened this issue Apr 2, 2024 · 1 comment

Comments

@BagelOrb
Copy link

BagelOrb commented Apr 2, 2024

fastai 2.7.14
fastcore 1.5.29

Describe the bug
When producing some exception from a plain assert, the exception is modified by fastai, but the modify_exception call introduces another error, which leads to a very convoluted stack trace.

When in any callback you have an assert without description, the code which handles the exception and reraises it (i.e. e.args[0]) will itself produce another exception, because it assumes that the exception had arguments, while it didn't. Please apply the fix proposed at the bottom of this issue report.

To Reproduce

# Python
import torch
from torch.utils.data import TensorDataset
from fastai.vision.all import *
from fastai.callback.core import Callback

# Create random noise data
x = torch.randn(100, 28)
y = torch.randint(0, 2, (100,1))

# Create a TensorDataset and then a DataLoader
train_dl = DataLoader(TensorDataset(x, y.float()), batch_size=64, shuffle=True)
dls = DataLoaders(train_dl, train_dl).cuda()

# Define a custom callback
class CustomCallback(Callback):
    def after_fit(self):
        assert False

# Create a learner and train
learn = Learner(dls, torch.nn.Linear(28, 1), loss_func=nn.BCEWithLogitsLoss(), cbs=CustomCallback())
learn.fit(1)

Expected behavior

---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
Cell In[14], [line 22](vscode-notebook-cell:?execution_count=14&line=22)
     [20](vscode-notebook-cell:?execution_count=14&line=20) # Create a learner and train
     [21](vscode-notebook-cell:?execution_count=14&line=21) learn = Learner(dls, torch.nn.Linear(28, 1), loss_func=nn.BCEWithLogitsLoss(), cbs=CustomCallback())
---> [22](vscode-notebook-cell:?execution_count=14&line=22) learn.fit(1)

File [~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/learner.py:264](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/learner.py:264), in Learner.fit(self, n_epoch, lr, wd, cbs, reset_opt, start_epoch)
    [262](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/learner.py:262) self.opt.set_hypers(lr=self.lr if lr is None else lr)
    [263](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/learner.py:263) self.n_epoch = n_epoch
--> [264](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/learner.py:264) self._with_events(self._do_fit, 'fit', CancelFitException, self._end_cleanup)

File [~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/learner.py:201](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/learner.py:201), in Learner._with_events(self, f, event_type, ex, final)
    [199](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/learner.py:199) try: self(f'before_{event_type}');  f()
    [200](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/learner.py:200) except ex: self(f'after_cancel_{event_type}')
--> [201](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/learner.py:201) self(f'after_{event_type}');  final()

File [~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/learner.py:172](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/learner.py:172), in Learner.__call__(self, event_name)
--> [172](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/learner.py:172) def __call__(self, event_name): L(event_name).map(self._call_one)

File [~/miniforge3/envs/dl/lib/python3.11/site-packages/fastcore/foundation.py:156](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastcore/foundation.py:156), in L.map(self, f, *args, **kwargs)
--> [156](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastcore/foundation.py:156) def map(self, f, *args, **kwargs): return self._new(map_ex(self, f, *args, gen=False, **kwargs))

File [~/miniforge3/envs/dl/lib/python3.11/site-packages/fastcore/basics.py:840](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastcore/basics.py:840), in map_ex(iterable, f, gen, *args, **kwargs)
    [838](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastcore/basics.py:838) res = map(g, iterable)
    [839](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastcore/basics.py:839) if gen: return res
--> [840](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastcore/basics.py:840) return list(res)

File [~/miniforge3/envs/dl/lib/python3.11/site-packages/fastcore/basics.py:825](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastcore/basics.py:825), in bind.__call__(self, *args, **kwargs)
    [823](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastcore/basics.py:823)     if isinstance(v,_Arg): kwargs[k] = args.pop(v.i)
    [824](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastcore/basics.py:824) fargs = [args[x.i] if isinstance(x, _Arg) else x for x in self.pargs] + args[self.maxi+1:]
--> [825](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastcore/basics.py:825) return self.func(*fargs, **kwargs)

File [~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/learner.py:176](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/learner.py:176), in Learner._call_one(self, event_name)
    [174](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/learner.py:174) def _call_one(self, event_name):
    [175](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/learner.py:175)     if not hasattr(event, event_name): raise Exception(f'missing {event_name}')
--> [176](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/learner.py:176)     for cb in self.cbs.sorted('order'): cb(event_name)

File [~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/callback/core.py:62](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/callback/core.py:62), in Callback.__call__(self, event_name)
     [60](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/callback/core.py:60)     try: res = getcallable(self, event_name)()
     [61](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/callback/core.py:61)     except (CancelBatchException, CancelBackwardException, CancelEpochException, CancelFitException, CancelStepException, CancelTrainException, CancelValidException): raise
---> [62](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/callback/core.py:62)     except Exception as e: raise modify_exception(e, f'Exception occured in `{self.__class__.__name__}` when calling event `{event_name}`:\n\t{e.args[0]}', replace=True)
     [63](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/callback/core.py:63) if event_name=='after_fit': self.run=True #Reset self.run to True at each end of fit
     [64](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/callback/core.py:64) return res

File [~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/callback/core.py:60](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/callback/core.py:60), in Callback.__call__(self, event_name)
     [58](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/callback/core.py:58) res = None
     [59](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/callback/core.py:59) if self.run and _run: 
---> [60](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/callback/core.py:60)     try: res = getcallable(self, event_name)()
     [61](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/callback/core.py:61)     except (CancelBatchException, CancelBackwardException, CancelEpochException, CancelFitException, CancelStepException, CancelTrainException, CancelValidException): raise
     [62](https://file+.vscode-resource.vscode-cdn.net/home/tim.kuipers/dev/deeplearning/projects/iris_drone_classification/pipeline_2023_fastai2/~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/callback/core.py:62)     except Exception as e: raise modify_exception(e, f'Exception occured in `{self.__class__.__name__}` when calling event `{event_name}`:\n\t{e.args[0]}', replace=True)

Cell In[14], [line 18](vscode-notebook-cell:?execution_count=14&line=18)
     [17](vscode-notebook-cell:?execution_count=14&line=17) def after_fit(self):
---> [18](vscode-notebook-cell:?execution_count=14&line=18)     assert False, "SDg"

AssertionError: Exception occured in `CustomCallback` when calling event `after_fit`

Actual behavior

{
	"name": "IndexError",
	"message": "tuple index out of range",
	"stack": "---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
File ~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/callback/core.py:60, in Callback.__call__(self, event_name)
     59 if self.run and _run: 
---> 60     try: res = getcallable(self, event_name)()
     61     except (CancelBatchException, CancelBackwardException, CancelEpochException, CancelFitException, CancelStepException, CancelTrainException, CancelValidException): raise

Cell In[15], line 18, in CustomCallback.after_fit(self)
     17 def after_fit(self):
---> 18     assert False

AssertionError: 

During handling of the above exception, another exception occurred:

IndexError                                Traceback (most recent call last)
Cell In[15], line 22
     20 # Create a learner and train
     21 learn = Learner(dls, torch.nn.Linear(28, 1), loss_func=nn.BCEWithLogitsLoss(), cbs=CustomCallback())
---> 22 learn.fit(1)

File ~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/learner.py:264, in Learner.fit(self, n_epoch, lr, wd, cbs, reset_opt, start_epoch)
    262 self.opt.set_hypers(lr=self.lr if lr is None else lr)
    263 self.n_epoch = n_epoch
--> 264 self._with_events(self._do_fit, 'fit', CancelFitException, self._end_cleanup)

File ~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/learner.py:201, in Learner._with_events(self, f, event_type, ex, final)
    199 try: self(f'before_{event_type}');  f()
    200 except ex: self(f'after_cancel_{event_type}')
--> 201 self(f'after_{event_type}');  final()

File ~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/learner.py:172, in Learner.__call__(self, event_name)
--> 172 def __call__(self, event_name): L(event_name).map(self._call_one)

File ~/miniforge3/envs/dl/lib/python3.11/site-packages/fastcore/foundation.py:156, in L.map(self, f, *args, **kwargs)
--> 156 def map(self, f, *args, **kwargs): return self._new(map_ex(self, f, *args, gen=False, **kwargs))

File ~/miniforge3/envs/dl/lib/python3.11/site-packages/fastcore/basics.py:840, in map_ex(iterable, f, gen, *args, **kwargs)
    838 res = map(g, iterable)
    839 if gen: return res
--> 840 return list(res)

File ~/miniforge3/envs/dl/lib/python3.11/site-packages/fastcore/basics.py:825, in bind.__call__(self, *args, **kwargs)
    823     if isinstance(v,_Arg): kwargs[k] = args.pop(v.i)
    824 fargs = [args[x.i] if isinstance(x, _Arg) else x for x in self.pargs] + args[self.maxi+1:]
--> 825 return self.func(*fargs, **kwargs)

File ~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/learner.py:176, in Learner._call_one(self, event_name)
    174 def _call_one(self, event_name):
    175     if not hasattr(event, event_name): raise Exception(f'missing {event_name}')
--> 176     for cb in self.cbs.sorted('order'): cb(event_name)

File ~/miniforge3/envs/dl/lib/python3.11/site-packages/fastai/callback/core.py:62, in Callback.__call__(self, event_name)
     60     try: res = getcallable(self, event_name)()
     61     except (CancelBatchException, CancelBackwardException, CancelEpochException, CancelFitException, CancelStepException, CancelTrainException, CancelValidException): raise
---> 62     except Exception as e: raise modify_exception(e, f'Exception occured in `{self.__class__.__name__}` when calling event `{event_name}`:\
\\t{e.args[0]}', replace=True)
     63 if event_name=='after_fit': self.run=True #Reset self.run to True at each end of fit
     64 return res

IndexError: tuple index out of range"
}

Additional context
Fix the following code in core.py:

# %% ../../nbs/13_callback.core.ipynb 16
@funcs_kwargs(as_method=True)
class Callback(Stateful,GetAttr):
[...]
    def __call__(self, event_name):
        "Call `self.{event_name}` if it's defined"
        _run = (event_name not in _inner_loop or (self.run_train and getattr(self, 'training', True)) or
               (self.run_valid and not getattr(self, 'training', False)))
        res = None
        if self.run and _run: 
            try: res = getcallable(self, event_name)()
            except (CancelBatchException, CancelBackwardException, CancelEpochException, CancelFitException, CancelStepException, CancelTrainException, CancelValidException): raise
            except Exception as e: raise modify_exception(e, f'Exception occured in `{self.__class__.__name__}` when calling event `{event_name}`:\n\t{e.args[0]}', replace=True)

Code fix suggested by GPT:

try: 
    res = getcallable(self, event_name)()
except (CancelBatchException, CancelBackwardException, CancelEpochException, CancelFitException, CancelStepException, CancelTrainException, CancelValidException): 
    raise
except Exception as e: 
    error_message = e.args[0] if e.args else str(e)
    raise modify_exception(e, f'Exception occured in `{self.__class__.__name__}` when calling event `{event_name}`:\n\t{error_message}', replace=True)
@BagelOrb
Copy link
Author

BagelOrb commented Apr 2, 2024

In my current project I am hitting an assert failure from fastai itself: assert self.monitor in self.recorder.metric_names[1:]. However, my debugger is not able to follow the exception, because of the issue described in this ticket. This means I cannot debug the issue.

Besides fixing this ticket, you might also want to check all your asserts to see if they have a message associated with them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant