class_docstr: A head is the final part of the network. It takes the embedding from the middleware embedder and passes it through
  a neural network to produce the output of the network. There can be multiple heads in a network, and each one has
  an assigned loss function. The heads are algorithm dependent.
docstr: Creates a target placeholder and loss function for each loss_type and regularization
  :param loss_type: a tensorflow loss function
  :param scope: the name scope to include the tensors in
  :return: None
docstr_tok: ["Creates","a","target","placeholder","and","loss","function","for","each","loss_type","and","regularization",":","param","loss_type",":","a","tensorflow","loss","function",":","param","scope",":","the","name","scope","to","include","the","tensors","in",":","return",":","None"]
code: def set_loss(self):
      """
      Creates a target placeholder and loss function for each loss_type and regularization
      :param loss_type: a tensorflow loss function
      :param scope: the name scope to include the tensors in
      :return: None
      """
  
      # there are heads that define the loss internally, but we need to create additional placeholders for them
      for idx in range(len(self.loss)):
          importance_weight = tf.placeholder(
              "float",
              [None] + [1] * (len(self.target[idx].shape) - 1),
              "{}_importance_weight".format(self.get_name()),
          )
          self.importance_weight.append(importance_weight)
  
      # add losses and target placeholder
      for idx in range(len(self.loss_type)):
          # create target placeholder
          target = tf.placeholder(
              "float",
              self.output[idx].shape,
              "{}_target".format(self.get_name()),
          )
          self.target.append(target)
  
          # create importance sampling weights placeholder
          num_target_dims = len(self.target[idx].shape)
          importance_weight = tf.placeholder(
              "float",
              [None] + [1] * (num_target_dims - 1),
              "{}_importance_weight".format(self.get_name()),
          )
          self.importance_weight.append(importance_weight)
  
          # compute the weighted loss. importance_weight weights over the samples in the batch, while self.loss_weight
          # weights the specific loss of this head against other losses in this head or in other heads
          loss_weight = self.loss_weight[idx] * importance_weight
          loss = self.loss_type[idx](
              self.target[-1],
              self.output[idx],
              scope=self.get_name(),
              reduction=Reduction.NONE,
              loss_collection=None,
          )
  
          # the loss is first summed over each sample in the batch and then the mean over the batch is taken
          loss = tf.reduce_mean(
              loss_weight
              * tf.reduce_sum(
                  loss, axis=list(range(1, num_target_dims))
              )
          )
  
          # we add the loss to the losses collection and later we will extract it in general_network
          tf.losses.add_loss(loss)
          self.loss.append(loss)
  
      # add regularizations
      for regularization in self.regularizations:
          self.loss.append(regularization)
          tf.losses.add_loss(regularization)
  
imports: import numpy
  import tensorflow
  from tensorflow.python.ops.losses.losses_impl import Reduction
  from rl_coach.architectures.tensorflow_components.layers import Dense, convert_layer_class
  from rl_coach.base_parameters import AgentParameters
  from rl_coach.spaces import SpacesDefinition
  from rl_coach.utils import force_list
  from rl_coach.architectures.tensorflow_components.utils import squeeze_tensor
label_desc: Use image node_id 6 for calling the Head obj's underlying member method code with example usage: obj.set_loss() without return types