class_docstr: Epsilon-Greedy Policy
  
  With probability epsilon, a random action is sampled. Otherwise,
  the highest scoring (greedy) action is chosen.
  
  Call update() to decay the amount of exploration by lowering
  `epsilon` by a factor of `epsilon_decay` (<=1) until we reach
  `minimum_epsilon`
class_docstr_tok: ["Epsilon-Greedy","Policy","With","probability","epsilon",",","a","random","action","is","sampled",".","Otherwise",",","the","highest","scoring","(","greedy",")","action","is","chosen",".","Call","update","(",")","to","decay","the","amount","of","exploration","by","lowering","`","epsilon","`","by","a","factor","of","`","epsilon_decay","`","(","<","=1",")","until","we","reach","`","minimum_epsilon","`"]
code: def sample_action(self, scores: torch.Tensor) -> rlt.ActorOutput:
      assert scores.dim() == 2, (
          "scores dim is %d" % scores.dim()
      )  # batch_size x num_actions
      batch_size, num_actions = scores.shape
  
      argmax = F.one_hot(scores.argmax(dim=1), num_actions).bool()
  
      valid_actions_ind = (scores > INVALID_ACTION_CONSTANT).bool()
      num_valid_actions = valid_actions_ind.float().sum(1, keepdim=True)
  
      # pyre-fixme[58]: `/` is not supported for operand types `float` and `Tensor`.
      rand_prob = self.epsilon / num_valid_actions
      p = torch.zeros_like(scores) + rand_prob
  
      greedy_prob = 1 - self.epsilon + rand_prob
      # pyre-fixme[16]: `float` has no attribute `squeeze`.
      p[argmax] = greedy_prob.squeeze()
  
      p[~valid_actions_ind] = 0.0
      p_sum = p.sum(1)
      assert torch.allclose(p_sum, torch.ones_like(p_sum))
  
      m = torch.distributions.Categorical(probs=p)
      raw_action = m.sample()
      action = F.one_hot(raw_action, num_actions)
      assert action.shape == (batch_size, num_actions)
      log_prob = m.log_prob(raw_action)
      assert log_prob.shape == (batch_size,)
      return rlt.ActorOutput(action=action, log_prob=log_prob)
  
imports: import reagent.core.types
  import torch
  import torch.nn.functional
  from reagent.gym.types import Sampler
  from reagent.models.dqn import INVALID_ACTION_CONSTANT
label_desc: Use image node_id 2 for calling the EpsilonGreedyActionSampler obj's underlying member method code with example usage: obj.sample_action(scores) and returns: rlt