def test_agent_returns_correct_threshold(self):
     env = college_admission.CollegeAdmissionsEnv(
         user_params={
             'gaming':
             False,
             'subsidize':
             False,
             'noise_params':
             params.BoundedGaussian(max=0.3, min=0, sigma=0, mu=0.1),
             'feature_params':
             params.GMM(
                 mix_weight=[0.5, 0.5], mu=[0.5, 0.5], sigma=[0.1, 0.1])
         })
     agent = college_admission_jury.NaiveJury(
         action_space=env.action_space,
         observation_space=env.observation_space,
         reward_fn=(lambda x: 0),
         threshold=0,
         burnin=9,
         freeze_classifier_after_burnin=True)
     test_util.run_test_simulation(env=env,
                                   agent=agent,
                                   num_steps=10,
                                   stackelberg=True)
     learned_threshold = env.history[-1].action['threshold']
     self.assertTrue(np.isclose(learned_threshold, 0.55, atol=1e-2))
Exemple #2
0
class Params(core.Params):
  """College Admissions Params."""
  # Number of applicants that appear each round.
  num_applicants = attr.ib(default=20)  # type: int
  # Min and Max values of the test score for each applicant.
  score_params = attr.ib(default=params.MinMax(max=1,
                                               min=0))  # type: params.MinMax
  # Stopping params.
  # Max steps to run the interaction for.
  max_steps = attr.ib(default=100000)  # type: int

  # Tunable Params.
  # Parameters of the population feature distribution.
  feature_params = attr.ib(
      default=params.GMM(
          mix_weight=[0.6, 0.4], mu=[0.8, 0.6],
          sigma=[0.1, 0.3]))  # type: params.GMM
  # To calculate true thresholds, as mu + factor * mu (factor can be -ve).
  true_threshold_factor = attr.ib(default=0.1)  # type: float
  # Params for the noise ditribution for noise added to threshold.
  noise_params = attr.ib(
      default=params.BoundedGaussian(
          max=0.3, min=-0.3, mu=0.1,
          sigma=0.01))  # type: params.BoundedGaussian

  # Scalar multiplier for cost (of a feature) per group.
  # Note: We codify B's disadvantage by requiring Cost A < Cost B.
  # pylint: disable=g-long-lambda
  group_cost = attr.ib(factory=lambda: {
      0: 0.8,
      1: 1.2
  })  # type: Mapping[int, float]
  # pylint: enable=g-long-lambda
  gaming = attr.ib(default=True)  # type: bool
  # Control amount of gaming. If inf, then allow maximum allowable by cost fn.
  # else if a value in [0, 1], applicant can only change by that many points.
  gaming_control = attr.ib(default=np.inf)  # type: float
  # Whether to subsidize
  subsidize = attr.ib(default=False)  # type: bool
  # Group 2 is subsidized by only allowing it to bear subsidy_beta cost.
  # subsidy_beta can be a value in [0, 1]. Percentage of cost B actually pays,
  # higher this is higher is the cost paid by B.
  subsidy_beta = attr.ib(default=0.8)  # type: float
  # Distribution of noise. One of beta or gaussian.
  noise_dist = attr.ib(default='gaussian')  # type: Text
  # Add noise to unmanipulated features.
  noisy_features = attr.ib(default=False)  # type: bool
  # Add noise to observed threshold.
  noisy_threshold = attr.ib(default=False)  # type: bool
Exemple #3
0
def run_baseline_experiment(feature_mu=None):
  """Run baseline experiment without noise."""
  results = {}
  agent_types = ['fixed', 'static', 'continuous', 'robust']
  thresholds = np.arange(0, 1, THRESHOLD_SPACING)
  if feature_mu is None:
    feature_mu = [0.5, 0.5]
  if len(feature_mu) != 2:
    raise ValueError('Expected feature_mu to be of length 2.')
  env_config_params = copy.deepcopy(ENV_PARAMS)

  env_config_params.update({
      'feature_params':
          params.GMM(mix_weight=[0.5, 0.5], mu=feature_mu,
                     sigma=[0.1, 0.1])
  })

  for agent_type in agent_types:
    results[agent_type] = {}
    for threshold in thresholds:
      results[agent_type][threshold] = {}
      if agent_type != 'fixed' and threshold > 0:
        continue
      num_steps = FIXED_AGENT_NUMSTEPS if agent_type == 'fixed' else FLAGS.num_steps
      college_experiment = college_admission.CollegeExperiment(
          num_steps=num_steps,
          env_config=env_config_params,
          agent_type=agent_type,
          agent_threshold=threshold,
          burnin=FLAGS.burnin,
          epsilon_greedy=FLAGS.epsilon_greedy,
          initial_epsilon_prob=FLAGS.initial_epsilon_prob)
      json_dump = college_experiment.run_experiment()
      exp_result = json.loads(json_dump)
      exp_params = copy.deepcopy(attr.asdict(college_experiment))
      exp_result.update({'exp_params': exp_params})
      if FLAGS.verbose:
        log_results(exp_result)
      with open(
          os.path.join(FLAGS.output_dir, 'experiment_results.json'), 'a+') as f:
        core.to_json(exp_result, f)
        f.write('\n---------------------------------------\n')
      results[agent_type][threshold] = exp_result
  return results, thresholds
Exemple #4
0
from __future__ import division
from __future__ import print_function

import json

from absl.testing import absltest
import params
from experiments import college_admission

import numpy as np

TEST_PARAMS = {
    'num_applicants':
    20,
    'feature_params':
    params.GMM(mix_weight=[0.5, 0.5], mu=[0.5, 0.5], sigma=[0.1, 0.1]),
    'noise_params':
    params.BoundedGaussian(max=0.0, min=-0, mu=0, sigma=0),
    # Scalar multiplier for cost (of a feature) per group.
    # Note: We codify B's disadvantage by requiring Cost A < Cost B.
    'group_cost': {
        0: 5,
        1: 10
    },
    'gaming':
    True,
    'gaming_control':
    np.inf
}

Exemple #5
0
def run_noisy_experiment(noise_dist='gaussian',
                         noisy_features=False,
                         noisy_threshold=False,
                         feature_mu=None,
                         stdevs=None):
  """Noisy experiment runs."""
  results = {}
  deltas = {}
  agent_types = ['fixed', 'static', 'continuous', 'robust']
  thresholds = np.arange(0, 1, THRESHOLD_SPACING)
  if noise_dist == 'beta':
    logging.info('Using Beta Noise Distribution.')
    stdevs = np.arange(2, 9, 1)
    mu = 2
    max_value = 0.7
    min_value = 0
  else:
    logging.info('Using Gaussian Noise Distribution.')
    mu = 0
    max_value = 0.35
    min_value = -0.35
  if feature_mu is None:
    feature_mu = [0.5, 0.5]
  if len(feature_mu) != 2:
    raise ValueError('Expected feature_mu to be of length 2.')
  if stdevs is None:
    stdevs = STDEV_RANGE_DEFAULTS
  for sd in stdevs:
    env_config_params = copy.deepcopy(ENV_PARAMS)
    env_config_params.update({
        'noise_dist':
            noise_dist,
        'noise_params':
            params.BoundedGaussian(
                max=max_value, min=min_value, mu=mu, sigma=sd),
        'noisy_features':
            noisy_features,
        'noisy_threshold':
            noisy_threshold,
        'feature_params':
            params.GMM(mix_weight=[0.5, 0.5], mu=feature_mu, sigma=[0.1, 0.1]),
    })
    logging.info('Stdev %f', sd)
    results[sd] = {}
    for agent_type in agent_types:
      results[sd][agent_type] = {}
      for threshold in thresholds:
        results[sd][agent_type][threshold] = {}
        if agent_type != 'fixed' and threshold > 0:
          continue
        num_steps = FIXED_AGENT_NUMSTEPS if agent_type == 'fixed' else FLAGS.num_steps
        college_experiment = college_admission.CollegeExperiment(
            num_steps=num_steps,
            env_config=env_config_params,
            agent_type=agent_type,
            agent_threshold=threshold,
            burnin=FLAGS.burnin,
            epsilon_greedy=FLAGS.epsilon_greedy,
            initial_epsilon_prob=FLAGS.initial_epsilon_prob)
        json_dump = college_experiment.run_experiment()
        exp_result = json.loads(json_dump)
        exp_params = copy.deepcopy(attr.asdict(college_experiment))
        exp_result.update({'exp_params': exp_params})
        if FLAGS.verbose:
          log_results(exp_result)
        with open(
            os.path.join(FLAGS.output_dir, 'experiment_results.json'),
            'w+') as f:
          core.to_json(exp_result, f)
          f.write('\n---------------------------------------\n')
        results[sd][agent_type][threshold] = exp_result
    deltas[sd] = (
        results[sd]['continuous'][0.0]['metric_results']['final_threshold'] -
        results[sd]['static'][0.0]['metric_results']['final_threshold'])
  return results, thresholds, deltas, stdevs