I could not understand this point (Most likely because you also remove other code like the wrapping in the  nn.Parameter()  for  data_phrases  that disconnects data_phrases from data_words.)  I dont remove any thing indeed, exactly same code but instead of passing:
self.optimizer.add_param_group({“params”: data_phrases})
self.optimizer.add_param_group({“params”: data_words})
I pass
self.optimizer.add_param_group({“params”: data_words})
What is remarkable is that If i change the order with respect to the first case:
self.optimizer.add_param_group({“params”: data_words})
self.optimizer.add_param_group({“params”: data_phrases})
only (data_words) will be updated and (data_phrases) will give None, unlike the first case, which made me doubt about these 2 lines and how they are passed to the optimizer.  I feel confused!
actually it is possible to ignore (data_phrases) and not pass it to the optimiser as you mentioned. but the point is that it is a softmax process for phrases (not for words), i.e., I can try to update only the tensor (data_words) and use the updated words to produce phrases. BUT, the loss function in this case will have as input the tensor (data_phrases) and not (data_words), which takes us back to your argument about optimizing a tensor not involved in the calculation of loss.
What do you think?