def gen( self, n: int, search_space: Optional[SearchSpace] = None, optimization_config: Optional[OptimizationConfig] = None, pending_observations: Optional[Dict[str, List[ObservationFeatures]]] = None, fixed_features: Optional[ObservationFeatures] = None, model_gen_options: Optional[TConfig] = None, ) -> GeneratorRun: """ Args: n: Number of points to generate search_space: Search space optimization_config: Optimization config pending_observations: A map from metric name to pending observations for that metric. fixed_features: An ObservationFeatures object containing any features that should be fixed at specified values during generation. model_gen_options: A config dictionary that is passed along to the model. """ t_gen_start = time.time() if pending_observations is None: pending_observations = {} if fixed_features is None: fixed_features = ObservationFeatures({}) # Get modifiable versions if search_space is None: search_space = self._model_space search_space = search_space.clone() if optimization_config is None: optimization_config = (self._optimization_config.clone() if self._optimization_config is not None else None) else: optimization_config = optimization_config.clone() # TODO(T34225037): replace deepcopy with native clone() in Lazarus pending_observations = deepcopy(pending_observations) fixed_features = deepcopy(fixed_features) # Transform for t in self.transforms.values(): search_space = t.transform_search_space(search_space) if optimization_config is not None: optimization_config = t.transform_optimization_config( optimization_config=optimization_config, modelbridge=self, fixed_features=fixed_features, ) for metric, po in pending_observations.items(): pending_observations[ metric] = t.transform_observation_features(po) fixed_features = t.transform_observation_features([fixed_features ])[0] # Apply terminal transform and gen observation_features, weights, best_obsf = self._gen( n=n, search_space=search_space, optimization_config=optimization_config, pending_observations=pending_observations, fixed_features=fixed_features, model_gen_options=model_gen_options, ) # Apply reverse transforms # pyre-fixme[6]: Expected `Sequence[_T]` for 1st param but got `ValuesView[Tr... for t in reversed(self.transforms.values()): # noqa T484 observation_features = t.untransform_observation_features( observation_features) if best_obsf is not None: best_obsf = t.untransform_observation_features([best_obsf])[0] best_point_predictions = None try: model_predictions = self.predict(observation_features) if best_obsf is not None: best_point_predictions = extract_arm_predictions( model_predictions=self.predict([best_obsf]), arm_idx=0) except NotImplementedError: # pragma: no cover model_predictions = None best_arm = (None if best_obsf is None else gen_arms( observation_features=[best_obsf], arms_by_signature=self._arms_by_signature, )[0]) gr = GeneratorRun( arms=gen_arms( observation_features=observation_features, arms_by_signature=self._arms_by_signature, ), weights=weights, optimization_config=optimization_config, search_space=search_space, model_predictions=model_predictions, best_arm_predictions=None if best_arm is None else (best_arm, best_point_predictions), fit_time=self.fit_time_since_gen, gen_time=time.time() - t_gen_start, ) self.fit_time_since_gen = 0.0 return gr
def gen( self, n: int, search_space: Optional[SearchSpace] = None, optimization_config: Optional[OptimizationConfig] = None, pending_observations: Optional[Dict[str, List[ObservationFeatures]]] = None, fixed_features: Optional[ObservationFeatures] = None, model_gen_options: Optional[TConfig] = None, ) -> GeneratorRun: """ Args: n: Number of points to generate search_space: Search space optimization_config: Optimization config pending_observations: A map from metric name to pending observations for that metric. fixed_features: An ObservationFeatures object containing any features that should be fixed at specified values during generation. model_gen_options: A config dictionary that is passed along to the model. """ t_gen_start = time.time() # Get modifiable versions if search_space is None: search_space = self._model_space orig_search_space = search_space search_space = search_space.clone() base_gen_args = self._get_transformed_gen_args( search_space=search_space, optimization_config=optimization_config, pending_observations=pending_observations, fixed_features=fixed_features, ) # Apply terminal transform and gen observation_features, weights, best_obsf, gen_metadata = self._gen( n=n, search_space=base_gen_args.search_space, optimization_config=base_gen_args.optimization_config, pending_observations=base_gen_args.pending_observations, fixed_features=base_gen_args.fixed_features, model_gen_options=model_gen_options, ) # Apply reverse transforms for t in reversed(self.transforms.values()): # noqa T484 observation_features = t.untransform_observation_features( observation_features ) if best_obsf is not None: best_obsf = t.untransform_observation_features([best_obsf])[0] # Clamp the untransformed data to the original search space if # we don't fit/gen OOD points if not self._fit_out_of_design: observation_features = clamp_observation_features( observation_features, orig_search_space ) if best_obsf is not None: best_obsf = clamp_observation_features([best_obsf], orig_search_space)[ 0 ] best_point_predictions = None try: model_predictions = self.predict(observation_features) if best_obsf is not None: best_point_predictions = extract_arm_predictions( model_predictions=self.predict([best_obsf]), arm_idx=0 ) except NotImplementedError: # pragma: no cover model_predictions = None if best_obsf is None: best_arm = None else: best_arms, _ = gen_arms( observation_features=[best_obsf], arms_by_signature=self._arms_by_signature, ) best_arm = best_arms[0] arms, candidate_metadata = gen_arms( observation_features=observation_features, arms_by_signature=self._arms_by_signature, ) # If experiment has immutable search space and metrics, no need to # save them on generator runs. immutable = getattr( self, "_experiment_has_immutable_search_space_and_opt_config", False ) optimization_config = None if immutable else base_gen_args.optimization_config gr = GeneratorRun( arms=arms, weights=weights, optimization_config=optimization_config, search_space=None if immutable else base_gen_args.search_space, model_predictions=model_predictions, best_arm_predictions=None if best_arm is None else (best_arm, best_point_predictions), fit_time=self.fit_time_since_gen, gen_time=time.time() - t_gen_start, model_key=self._model_key, model_kwargs=self._model_kwargs, bridge_kwargs=self._bridge_kwargs, gen_metadata=gen_metadata, model_state_after_gen=self._get_serialized_model_state(), candidate_metadata_by_arm_signature=candidate_metadata, ) self.fit_time_since_gen = 0.0 return gr
def gen( self, n: int, search_space: Optional[SearchSpace] = None, optimization_config: Optional[OptimizationConfig] = None, pending_observations: Optional[Dict[str, List[ObservationFeatures]]] = None, fixed_features: Optional[ObservationFeatures] = None, model_gen_options: Optional[TConfig] = None, ) -> GeneratorRun: """ Args: n: Number of points to generate search_space: Search space optimization_config: Optimization config pending_observations: A map from metric name to pending observations for that metric. fixed_features: An ObservationFeatures object containing any features that should be fixed at specified values during generation. model_gen_options: A config dictionary that is passed along to the model. """ t_gen_start = time.time() if pending_observations is None: pending_observations = {} if fixed_features is None: fixed_features = ObservationFeatures({}) # Get modifiable versions if search_space is None: search_space = self._model_space search_space = search_space.clone() if optimization_config is None: optimization_config = ( # pyre-fixme[16]: `Optional` has no attribute `clone`. self._optimization_config.clone() if self._optimization_config is not None else None) else: optimization_config = optimization_config.clone() # TODO(T34225037): replace deepcopy with native clone() in Ax pending_observations = deepcopy(pending_observations) fixed_features = deepcopy(fixed_features) # Transform for t in self.transforms.values(): search_space = t.transform_search_space(search_space) if optimization_config is not None: optimization_config = t.transform_optimization_config( optimization_config=optimization_config, modelbridge=self, fixed_features=fixed_features, ) for metric, po in pending_observations.items(): pending_observations[ metric] = t.transform_observation_features(po) fixed_features = t.transform_observation_features([fixed_features ])[0] # Apply terminal transform and gen observation_features, weights, best_obsf, gen_metadata = self._gen( n=n, search_space=search_space, optimization_config=optimization_config, pending_observations=pending_observations, fixed_features=fixed_features, model_gen_options=model_gen_options, ) # Apply reverse transforms for t in reversed(self.transforms.values()): # noqa T484 observation_features = t.untransform_observation_features( observation_features) if best_obsf is not None: best_obsf = t.untransform_observation_features([best_obsf])[0] best_point_predictions = None try: model_predictions = self.predict(observation_features) if best_obsf is not None: best_point_predictions = extract_arm_predictions( model_predictions=self.predict([best_obsf]), arm_idx=0) except NotImplementedError: # pragma: no cover model_predictions = None if best_obsf is None: best_arm = None else: best_arms, _ = gen_arms( observation_features=[best_obsf], arms_by_signature=self._arms_by_signature, ) best_arm = best_arms[0] arms, candidate_metadata = gen_arms( observation_features=observation_features, arms_by_signature=self._arms_by_signature, ) # If experiment has immutable search space and metrics, no need to # save them on generator runs. immutable = getattr( self, "_experiment_has_immutable_search_space_and_opt_config", False) gr = GeneratorRun( arms=arms, weights=weights, optimization_config=None if immutable else optimization_config, search_space=None if immutable else search_space, model_predictions=model_predictions, best_arm_predictions=None if best_arm is None else (best_arm, best_point_predictions), fit_time=self.fit_time_since_gen, gen_time=time.time() - t_gen_start, model_key=self._model_key, model_kwargs=self._model_kwargs, bridge_kwargs=self._bridge_kwargs, gen_metadata=gen_metadata, model_state_after_gen=self._get_serialized_model_state(), candidate_metadata_by_arm_signature=candidate_metadata, ) self.fit_time_since_gen = 0.0 return gr
def model_best_point( self, search_space: Optional[SearchSpace] = None, optimization_config: Optional[OptimizationConfig] = None, pending_observations: Optional[Dict[str, List[ObservationFeatures]]] = None, fixed_features: Optional[ObservationFeatures] = None, model_gen_options: Optional[TConfig] = None, ) -> Optional[Tuple[Arm, Optional[TModelPredictArm]]]: # Get modifiable versions if search_space is None: search_space = self._model_space search_space = search_space.clone() base_gen_args = self._get_transformed_gen_args( search_space=search_space, optimization_config=optimization_config, pending_observations=pending_observations, fixed_features=fixed_features, ) array_model_gen_args = self._get_transformed_model_gen_args( search_space=base_gen_args.search_space, pending_observations=base_gen_args.pending_observations, fixed_features=base_gen_args.fixed_features, model_gen_options=None, optimization_config=base_gen_args.optimization_config, ) search_space_digest = array_model_gen_args.search_space_digest xbest = self._model_best_point( bounds=search_space_digest.bounds, objective_weights=array_model_gen_args.objective_weights, outcome_constraints=array_model_gen_args.outcome_constraints, linear_constraints=array_model_gen_args.linear_constraints, fixed_features=array_model_gen_args.fixed_features, model_gen_options=model_gen_options, target_fidelities=search_space_digest.target_fidelities, ) if xbest is None: return None best_obsf = ObservationFeatures( parameters={p: float(xbest[i]) for i, p in enumerate(self.parameters)} ) for t in reversed(self.transforms.values()): # noqa T484 best_obsf = t.untransform_observation_features([best_obsf])[0] best_point_predictions = extract_arm_predictions( model_predictions=self.predict([best_obsf]), arm_idx=0 ) best_arms, _ = gen_arms( observation_features=[best_obsf], arms_by_signature=self._arms_by_signature, ) best_arm = best_arms[0] return best_arm, best_point_predictions