I think the issue becomes more clear if we write down what each function depends on:
output1 = model1(model1_params, input_1)
loss1 = loss1_fn(output1, A)
output2 = model2(model2_params, model1(input2))
loss2 = loss2_fn(output2)
output3 = model2(input3)
loss3 = loss1_fn(output3)
Note that while A is part of the optimization algorithm of model1, it is not actually explicitly in the function of loss3. So I don’t think its gradient should be updated on loss3.backward(). For example, we would also not expect the parameters of optimizer1 such as the learning rate to have a gradient computed, even though model1’s params also “depend” on them.