Exemplo n.º 1
0
 def test_manipulate_features_no_max_control(self):
     """Tests that features are manipulated as expected no gaming control."""
     env = college_admission.CollegeAdmissionsEnv(
         user_params={
             "num_applicants": 6,
             "gaming": True,
             "gaming_control": np.inf,
             "noise_params": params.BoundedGaussian(max=0, mu=0, min=0, sigma=0),
             "group_cost": {0: 3, 1: 4},
         }
     )
     agent = random_agents.RandomAgent(
         env.action_space,
         None,
         env.observation_space,
         default_action={"threshold": np.array(0.8), "epsilon_prob": np.array(0)},
     )
     env.set_scalar_reward(agent.reward_fn)
     action = agent.initial_action()
     env.step(action)
     env.state.test_scores_x = [0.1, 0.3, 0.6, 0.7, 0.7, 0.9]
     env.state.applicant_groups = [0, 1, 1, 1, 0, 0]
     env.state.true_eligible = [0, 0, 1, 1, 0, 1]
     expected_changed_scores = [0.1, 0.3, 0.8, 0.8, 0.8, 0.9]
     expected_individual_burden = self._return_individual_burden(env, agent)
     changed_scores, individual_burden = env._manipulate_features(env.state, action)
     self.assertTrue(np.all(np.isclose(expected_changed_scores, changed_scores, atol=1e-4)))
     self.assertTrue(
         np.all(np.isclose(individual_burden, expected_individual_burden, atol=1e-4))
     )
 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))
 def error_raised_when_noise_params_wrong(self):
   env = college_admission.CollegeAdmissionsEnv(
       user_params={
           'noise_params':
               params.BoundedGaussian(min=0, max=0.3, mu=0, sigma=0.00001),
       })
   with self.assertRaises(ValueError):
     env._add_noise()
Exemplo n.º 4
0
 def test_one_sided_noise_generated_correctly(self):
     env = college_admission.CollegeAdmissionsEnv(
         user_params={
             "num_applicants": 4,
             "noise_params": params.BoundedGaussian(min=0, max=0.3, mu=0.2, sigma=0.00001),
         }
     )
     noise = env._add_noise(env.state.rng)
     self.assertTrue(np.isclose(0.2, noise, atol=1e-3))
Exemplo n.º 5
0
 def feature_noise_propagates_to_labels(self):
     env = college_admission.CollegeAdmissionsEnv(
         user_params={
             "num_applicants": 10,
             "noise_params": params.BoundedGaussian(min=0.5, max=0.5, mu=0, sigma=1),
         }
     )
     env.state.rng = np.random.RandomState(seed=100)
     env._sample_next_state_vars(env.state)
     scores = np.array(env.state.test_scores_x)
     eligible = np.array(env.state.true_eligible)
     # Check that at least one "eligible" candidate has a lower score than an
     # ineligible one.
     self.assertLess(np.min(scores[eligible == 1]), np.max(scores[eligible == 0]))
Exemplo n.º 6
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
Exemplo n.º 7
0
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
}


class CollegeAdmissionTest(absltest.TestCase):
    def test_experiment_runs_with_default_parameters(self):
Exemplo n.º 8
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