That part is clear to me, but i still don’t understand how it is working internally. Sorry 
The code in the SO question is from this PyTorch tutorial, i didn’t changed it.
To make the question clearer:
# Compute Huber loss
loss = F.smooth_l1_loss(state_action_values, expected_state_action_values.unsqueeze(1))

Here the loss is computed from 2 arrays with batch size 8 and 1 column. But we have to predict/learn Q-Values for 2 actions [LEFT|RIGHT] in the cartpole env? How can we do loss.backward() without knowing for which action we do the update?
Does the gather() just return some results or does it somehow internally set/save this index to do the following backward() call?
If so, what happens when i need another gather() call to collect something - like in my code from AGENT module?
    def train(self, SYS):
       	#////////////////////////////////////////////////
    	"""train the agent on a MINIBATCH"""
    	#////////////////////////////////////////////////
       	loss = 0.0
       	#////////////////////////////////////////////////
       	if(self.get_mem_size() <= self.batch_size): return(0)
       	#////////////////////////////////////////////////
       	self.RAM = self.MEM.get_batch(batch_size=self.batch_size)
       	#////////////////////////////////////////////////
       	self.c_states = torch.from_numpy(np.array([item[0] for item in self.RAM], dtype=np.float32))
    	self.actions  = torch.from_numpy(np.array([item[1] for item in self.RAM], dtype=np.int64))
    	self.rewards  = torch.from_numpy(np.array([item[2] for item in self.RAM], dtype=np.float32))
    	self.n_states = torch.from_numpy(np.array([item[3] for item in self.RAM], dtype=np.float32))
    	self.dones    = torch.from_numpy(np.array([item[4] for item in self.RAM], dtype=np.int64))
       	#////////////////////////////////////////////////

       	q_values = self.DQN.predict(self.c_states).gather(1, self.actions.unsqueeze(1)).squeeze(1)
    	dqn_next = self.DQN.predict(self.n_states)
    
    	#////////////////////////////////////////////////
    
    	q_action = torch.argmax(dqn_next, dim=1)    
    	tar_next = self.TAR.predict(self.n_states).gather(1, q_action.unsqueeze(1)).squeeze(1)
    
    	#////////////////////////////////////////////////    
    	q_target = (self.rewards + (self.GAMMA * tar_next * (1 - self.dones)))    
    	#////////////////////////////////////////////////    
    	self.DQN.model.train()    
    	#////////////////////////////////////////////////    
    	loss = self.DQN.fit(current_q=q_values, expected_q=q_target)    
    	#////////////////////////////////////////////////    
    	self.DQN.model.eval()    
    	#////////////////////////////////////////////////    
    	self.update_TAR() # copy DQN to TAR on every N episodes    
    	#////////////////////////////////////////////////    
    	return(loss)

It works fine - but i don’t get how it works.
Thanks again!