I think zeroing out the gradients is a valid approach and you could register hooks to perform this operation, if this would be more convenient, via param.register_hook.
Alternatively, you could also create a trainable nn.Parameter containing the values of [a-i] and recreate the kernel in each iteration e.g. by using torch.cat, torch.scatter, or torch.gather (depending on the actual shape). However, I would prefer the first approach as it sounds simpler and cleaner.