-
Notifications
You must be signed in to change notification settings - Fork 15
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
Persist CQT device #19
Persist CQT device #19
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that's cool, apart from this sampling_rate
as arg thingy I like your solution
def __init__(self, | ||
step_size: float, | ||
bins_per_semitone: int = 3, | ||
device: torch.device = torch.device("cpu"), | ||
sampling_rate: int = 44100, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it can be done differently, I'd prefer not having to specify a sampling_rate
(thus calling _init_cqt_layer
) in the __init__
to keep it as lazy as possible. Is this add-on necessary for solving the device issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem with lazy init is that after construction, neither DataProcessor
nor its submodules have any buffers or nn.Parameter
s registered, so any calls to .to()
, .to_empty()
, .cpu()
, .cuda()
, .xpu()
, .ipu()
, or .apply()
will not automatically apply to CQT kernels constructed later. As far as I can see, you have the following choices:
- Override all these methods to update
self.device
. The main downside here is that you will take on the maintenance cost of staying up to date with any future API changes tonn.Module
- Override
.apply()
and store all function pointers on the instance, then apply them in sequence to every newCQT
instance that is constructed. Depending on what is passed to apply, this could be quite brittle. e.g. applying any function that relies on external state. - Create a dummy buffer on
DataProcessor
, and use this to track device changes. This is a bit hacky, but it will let you keep lazy initialisation. - Specify sample rate on construction, immediately registering CQT kernel buffers on the module. IMO this is most idiomatic solution, but of course it comes at the expense of lazy initialisation.
To me, it's not totally clear what is gained by lazy initialisation of the CQT, so 4 makes most sense. But if lazy init is essential then 3 is probably the solution that is least likely to require further maintenance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll probably go for solution 3, I want my code to be as lazy as me
Closes #17
Opted to remove the
device
parameter fromDataProcessor
constructor and let device management take place throughnn.Module
. Sampling rate can now be passed in constructor, and an initial set of CQT kernels are computed. These are updated, with device persisting, whenever sampling rate is changed.