I’m not sure that what you have here is a multi-output model, per se. Instead, you have a single output model where you would like the output to be as close as possible to two targets as possible.
You have one input x, and you pass it through the same network layers (with identical weights) to produce x1 and x2, which are identical. You then compare this single value (albeit with two different names) to the targets target1 and target2 to calculate loss1 and loss2. Thus, your network is searching for the single set of weights for dense1 and dense2 that will produce a single output value with the lowest loss value on average. It makes sense that when one loss value decreases, the other increases, and vice versa, because if target1 and target2 are different, the network will only be able to predict one at a time (again, because the values x1 and x2 are identical).
Assuming that what you actually want is a network that predicts both targets from a given input:

def forward(self, x):
#neural network arch. forward pass
x = dense1(x)
x1 = dense2a(x)
x2 = dense2b(x)
x1 = F.log_softmax(x1)
x2 = F.log_softmax(x2)
return x1, x2


for some_iterator_over_data:
out1, out2 = model(data)
loss1 = NLLL(out1, target1)
loss2 = NLLL(out2, target2)
loss = loss1+loss2
loss.backward()
optimizer.step() # assuming the target for your optimizer is loss
optimizer.zero_grad()

In this way, different weights will be learned for layers dense2a and dense2b which make them more suitable for predicting target1 and target2, resepectively.
Hope this is what you were looking for!