code: def run_q_learning_optimizer(
      self,
      input_param,
      obj_func,
      batch_size,
      n_generations,
      repeats,
  ):
      results = []
      for r in range(repeats):
          print(f"\n\n**** QLearning Optimizer, Repeat={r} ****")
          ql_optimizer = QLearningOptimizer(
              input_param,
              obj_func,
              batch_size=batch_size,
              anneal_rate=0.997,
          )
          for i in range(n_generations):
              # non-exploration at the last generation
              if i == n_generations - 1:
                  ql_optimizer.temp = GREEDY_TEMP
  
              temp = ql_optimizer.temp
              (
                  sampled_solutions,
                  reward,
              ) = ql_optimizer.optimize_step()
              mean_reward_ql_optimizer = torch.mean(reward.data)
              min_reward_ql_optimizer = torch.min(reward.data)
              print(
                  f"Generation={i}, mean_reward={mean_reward_ql_optimizer}, "
                  f"min_reward={min_reward_ql_optimizer}, "
                  f"temp={temp}"
              )
          results.append(mean_reward_ql_optimizer)
  
      return results
  
imports: import random
  import unittest
  from collections import defaultdict
  from typing import Dict
  import nevergrad
  import numpy
  import torch
  import torch.nn
  from reagent.lite.optimizer import BayesianByBackpropOptimizer, BayesianMLPEnsemblerOptimizer, BayesianOptimizerBase, GREEDY_TEMP, GumbelSoftmaxOptimizer, NeverGradOptimizer, PolicyGradientOptimizer, QLearningOptimizer, RandomSearchOptimizer, sol_to_tensors
label_desc: Use image node_id 10 for calling the TestComboOptimizer obj's underlying member method code with example usage: obj.run_q_learning_optimizer(input_param, obj_func, batch_size, n_generations, repeats) and returns: results