No problem!
The direct analog is to just have torch.autograd.backward(df_da(x, y), inputs=(y,)). Not specifying the inputs parameter should also be OK , though that would lead to the gradients also be accumulated for the other input (x), which is a bit of extra computation. Then assuming you have your optimizer configured to update y, optimizer.step() should just work, i.e., it does something like y <- y + lr * y.grad