def build_sequence_input(features, sequence_feature_columns, context_feature_columns, weight_collections=None, scope=None): """Combine sequence and context features into input for an RNN. Args: features: A `dict` containing the input and (optionally) sequence length information and initial state. sequence_feature_columns: An iterable containing all the feature columns describing sequence features. All items in the set should be instances of classes derived from `FeatureColumn`. context_feature_columns: An iterable containing all the feature columns describing context features i.e. features that apply across all time steps. All items in the set should be instances of classes derived from `FeatureColumn`. weight_collections: List of graph collections to which weights are added. scope: Optional scope, passed through to parsing ops. Returns: A `Tensor` of dtype `float32` and shape `[batch_size, padded_length, ?]`. This will be used as input to an RNN. """ features = features.copy() features.update( layers.transform_features( features, list(sequence_feature_columns) + list(context_feature_columns or []))) sequence_input = layers.sequence_input_from_feature_columns( columns_to_tensors=features, feature_columns=sequence_feature_columns, weight_collections=weight_collections, scope=scope) if context_feature_columns is not None: context_input = layers.input_from_feature_columns( columns_to_tensors=features, feature_columns=context_feature_columns, weight_collections=weight_collections, scope=scope) sequence_input = _concatenate_context_input(sequence_input, context_input) return sequence_input
def build_sequence_input(features, sequence_feature_columns, context_feature_columns, weight_collections=None, scope=None): """Combine sequence and context features into input for an RNN. Args: features: A `dict` containing the input and (optionally) sequence length information and initial state. sequence_feature_columns: An iterable containing all the feature columns describing sequence features. All items in the set should be instances of classes derived from `FeatureColumn`. context_feature_columns: An iterable containing all the feature columns describing context features i.e. features that apply across all time steps. All items in the set should be instances of classes derived from `FeatureColumn`. weight_collections: List of graph collections to which weights are added. scope: Optional scope, passed through to parsing ops. Returns: A `Tensor` of dtype `float32` and shape `[batch_size, padded_length, ?]`. This will be used as input to an RNN. """ features = features.copy() features.update(layers.transform_features( features, list(sequence_feature_columns) + list(context_feature_columns or []))) sequence_input = layers.sequence_input_from_feature_columns( columns_to_tensors=features, feature_columns=sequence_feature_columns, weight_collections=weight_collections, scope=scope) if context_feature_columns is not None: context_input = layers.input_from_feature_columns( columns_to_tensors=features, feature_columns=context_feature_columns, weight_collections=weight_collections, scope=scope) sequence_input = _concatenate_context_input(sequence_input, context_input) return sequence_input
def sdca_model_fn(features, labels, mode, params, config=None): """A model_fn for linear models that use the SDCA optimizer. Args: features: A dict of `Tensor` keyed by column name. labels: `Tensor` of shape [batch_size, 1] or [batch_size] labels of dtype `int32` or `int64` with values in the set {0, 1}. mode: Defines whether this is training, evaluation or prediction. See `ModeKeys`. params: A dict of hyperparameters. The following hyperparameters are expected: * head: A `Head` instance. Type must be one of `_BinarySvmHead`, `_RegressionHead` or `_BinaryLogisticHead`. * feature_columns: An iterable containing all the feature columns used by the model. * l1_regularization: Global (across all examples) L1-regularization parameter. * l2_regularization: Global (across all examples) L2-regularization parameter. * num_loss_partitions: Number of partitions of the global loss function optimized by `SDCAOptimizer`. * weight_column_name: A string defining the weight feature column, or None if there are no weights. * update_weights_hook: A `SessionRunHook` object or None. Used to update model weights. config: `RunConfig` object to configure the runtime settings. Returns: A `ModelFnOps` instance. Raises: ValueError: If the type of head is not one of `_BinarySvmHead`, `_RegressionHead` or `_MultiClassHead`. ValueError: If mode is not any of the `ModeKeys`. """ head = params["head"] feature_columns = params["feature_columns"] example_id_column = params["example_id_column"] l1_regularization = params["l1_regularization"] l2_regularization = params["l2_regularization"] num_loss_partitions = params["num_loss_partitions"] weight_column_name = params["weight_column_name"] update_weights_hook = params.get("update_weights_hook", None) partitioner = params["partitioner"] loss_type = None if isinstance(head, head_lib._BinarySvmHead): # pylint: disable=protected-access loss_type = "hinge_loss" elif isinstance(head, head_lib._BinaryLogisticHead): # pylint: disable=protected-access loss_type = "logistic_loss" elif isinstance(head, head_lib._RegressionHead): # pylint: disable=protected-access loss_type = "squared_loss" else: raise ValueError("Unsupported head type: {}".format(type(head))) assert head.logits_dimension == 1, ( "SDCA only applies to logits_dimension=1.") # Update num_loss_partitions based on number of workers. n_loss_partitions = num_loss_partitions or max(1, config.num_worker_replicas) optimizer = sdca_optimizer.SDCAOptimizer( example_id_column=example_id_column, num_loss_partitions=n_loss_partitions, symmetric_l1_regularization=l1_regularization, symmetric_l2_regularization=l2_regularization, partitioner=partitioner) parent_scope = "linear" with variable_scope.variable_scope( values=features.values(), name_or_scope=parent_scope, partitioner=partitioner) as scope: features = features.copy() features.update(layers.transform_features(features, feature_columns)) logits, columns_to_variables, bias = ( layers.weighted_sum_from_feature_columns( columns_to_tensors=features, feature_columns=feature_columns, num_outputs=1, scope=scope)) _add_bias_column(feature_columns, features, bias, columns_to_variables) def _train_op_fn(unused_loss): global_step = training_util.get_global_step() sdca_model, train_op = optimizer.get_train_step( columns_to_variables, weight_column_name, loss_type, features, labels, global_step) if update_weights_hook is not None: update_weights_hook.set_parameters(sdca_model, train_op) return train_op model_fn_ops = head.create_model_fn_ops( features=features, labels=labels, mode=mode, train_op_fn=_train_op_fn, logits=logits) if update_weights_hook is not None: return model_fn_ops._replace(training_chief_hooks=( model_fn_ops.training_chief_hooks + [update_weights_hook])) return model_fn_ops
def _model_fn(features, labels, mode): """Function that returns predictions, training loss, and training op.""" if (isinstance(features, ops.Tensor) or isinstance(features, sparse_tensor.SparseTensor)): features = {'features': features} if feature_columns: features = features.copy() if output_type == ModelBuilderOutputType.MODEL_FN_OPS: features.update(layers.transform_features(features, feature_columns)) else: for fc in feature_columns: tensor = fc_core._transform_features(features, [fc])[fc] # pylint: disable=protected-access features[fc.name] = tensor weights = None if weights_name and weights_name in features: weights = features.pop(weights_name) keys = None if keys_name and keys_name in features: keys = features.pop(keys_name) # If we're doing eval, optionally ignore device_assigner. # Also ignore device assigner if we're exporting (mode == INFER) dev_assn = device_assigner if (mode == model_fn_lib.ModeKeys.INFER or (local_eval and mode == model_fn_lib.ModeKeys.EVAL)): dev_assn = None graph_builder = graph_builder_class(params, device_assigner=dev_assn) logits, tree_paths, regression_variance = graph_builder.inference_graph( features) summary.scalar('average_tree_size', graph_builder.average_size()) # For binary classification problems, convert probabilities to logits. # Includes hack to get around the fact that a probability might be 0 or 1. if not params.regression and params.num_classes == 2: class_1_probs = array_ops.slice(logits, [0, 1], [-1, 1]) logits = math_ops.log( math_ops.maximum(class_1_probs / math_ops.maximum( 1.0 - class_1_probs, EPSILON), EPSILON)) # labels might be None if we're doing prediction (which brings up the # question of why we force everything to adhere to a single model_fn). training_graph = None training_hooks = [] if labels is not None and mode == model_fn_lib.ModeKeys.TRAIN: with ops.control_dependencies([logits.op]): training_graph = control_flow_ops.group( graph_builder.training_graph( features, labels, input_weights=weights, num_trainers=num_trainers, trainer_id=trainer_id), state_ops.assign_add(training_util.get_global_step(), 1)) # Put weights back in if weights is not None: features[weights_name] = weights # TensorForest's training graph isn't calculated directly from the loss # like many other models. def _train_fn(unused_loss): return training_graph # Ops are run in lexigraphical order of their keys. Run the resource # clean-up op last. all_handles = graph_builder.get_all_resource_handles() ops_at_end = { '9: clean up resources': control_flow_ops.group(*[ resource_variable_ops.destroy_resource_op(handle) for handle in all_handles ]) } if report_feature_importances: ops_at_end['1: feature_importances'] = ( graph_builder.feature_importances()) training_hooks = [TensorForestRunOpAtEndHook(ops_at_end)] if output_type == ModelBuilderOutputType.MODEL_FN_OPS: model_ops = model_head.create_model_fn_ops( features=features, labels=labels, mode=mode, train_op_fn=_train_fn, logits=logits, scope=head_scope) if early_stopping_rounds: training_hooks.append( TensorForestLossHook( early_stopping_rounds, early_stopping_loss_threshold=early_stopping_loss_threshold, loss_op=model_ops.loss)) model_ops.training_hooks.extend(training_hooks) if keys is not None: model_ops.predictions[keys_name] = keys if params.inference_tree_paths: model_ops.predictions[TREE_PATHS_PREDICTION_KEY] = tree_paths model_ops.predictions[VARIANCE_PREDICTION_KEY] = regression_variance if include_all_in_serving: # In order to serve the variance we need to add the prediction dict # to output_alternatives dict. if not model_ops.output_alternatives: model_ops.output_alternatives = {} model_ops.output_alternatives[ALL_SERVING_KEY] = ( constants.ProblemType.UNSPECIFIED, model_ops.predictions) return model_ops else: # Estimator spec estimator_spec = model_head.create_estimator_spec( features=features, mode=mode, labels=labels, train_op_fn=_train_fn, logits=logits) if early_stopping_rounds: training_hooks.append( TensorForestLossHook( early_stopping_rounds, early_stopping_loss_threshold=early_stopping_loss_threshold, loss_op=estimator_spec.loss)) estimator_spec = estimator_spec._replace( training_hooks=training_hooks + list(estimator_spec.training_hooks)) if keys is not None: estimator_spec.predictions[keys_name] = keys if params.inference_tree_paths: estimator_spec.predictions[TREE_PATHS_PREDICTION_KEY] = tree_paths estimator_spec.predictions[VARIANCE_PREDICTION_KEY] = regression_variance if include_all_in_serving: outputs = estimator_spec.export_outputs if not outputs: outputs = {} outputs = {ALL_SERVING_KEY: PredictOutput(estimator_spec.predictions)} print(estimator_spec.export_outputs) # In order to serve the variance we need to add the prediction dict # to output_alternatives dict. estimator_spec = estimator_spec._replace(export_outputs=outputs) return estimator_spec
def _model_fn(features, labels, mode): """Function that returns predictions, training loss, and training op.""" if (isinstance(features, ops.Tensor) or isinstance(features, sparse_tensor.SparseTensor)): features = {'features': features} if feature_columns: features = features.copy() features.update( layers.transform_features(features, feature_columns)) weights = None if weights_name and weights_name in features: weights = features.pop(weights_name) keys = None if keys_name and keys_name in features: keys = features.pop(keys_name) # If we're doing eval, optionally ignore device_assigner. # Also ignore device assigner if we're exporting (mode == INFER) dev_assn = device_assigner if (mode == model_fn_lib.ModeKeys.INFER or (local_eval and mode == model_fn_lib.ModeKeys.EVAL)): dev_assn = None graph_builder = graph_builder_class(params, device_assigner=dev_assn) logits, tree_paths, regression_variance = graph_builder.inference_graph( features) summary.scalar('average_tree_size', graph_builder.average_size()) # For binary classification problems, convert probabilities to logits. # Includes hack to get around the fact that a probability might be 0 or 1. if not params.regression and params.num_classes == 2: class_1_probs = array_ops.slice(logits, [0, 1], [-1, 1]) logits = math_ops.log( math_ops.maximum( class_1_probs / math_ops.maximum(1.0 - class_1_probs, EPSILON), EPSILON)) # labels might be None if we're doing prediction (which brings up the # question of why we force everything to adhere to a single model_fn). training_graph = None training_hooks = [] if labels is not None and mode == model_fn_lib.ModeKeys.TRAIN: with ops.control_dependencies([logits.op]): training_graph = control_flow_ops.group( graph_builder.training_graph(features, labels, input_weights=weights, num_trainers=num_trainers, trainer_id=trainer_id), state_ops.assign_add(contrib_framework.get_global_step(), 1)) # Put weights back in if weights is not None: features[weights_name] = weights # TensorForest's training graph isn't calculated directly from the loss # like many other models. def _train_fn(unused_loss): return training_graph model_ops = model_head.create_model_fn_ops(features=features, labels=labels, mode=mode, train_op_fn=_train_fn, logits=logits, scope=head_scope) # Ops are run in lexigraphical order of their keys. Run the resource # clean-up op last. all_handles = graph_builder.get_all_resource_handles() ops_at_end = { '9: clean up resources': control_flow_ops.group(*[ resource_variable_ops.destroy_resource_op(handle) for handle in all_handles ]) } if report_feature_importances: ops_at_end['1: feature_importances'] = ( graph_builder.feature_importances()) training_hooks.append(TensorForestRunOpAtEndHook(ops_at_end)) if early_stopping_rounds: training_hooks.append( TensorForestLossHook( early_stopping_rounds, early_stopping_loss_threshold=early_stopping_loss_threshold, loss_op=model_ops.loss)) model_ops.training_hooks.extend(training_hooks) if keys is not None: model_ops.predictions[keys_name] = keys if params.inference_tree_paths: model_ops.predictions[TREE_PATHS_PREDICTION_KEY] = tree_paths if params.regression: model_ops.predictions[ VARIANCE_PREDICTION_KEY] = regression_variance return model_ops
def _model_fn(features, labels, mode): """Function that returns predictions, training loss, and training op.""" if (isinstance(features, ops.Tensor) or isinstance(features, sparse_tensor.SparseTensor)): features = {'features': features} if feature_columns: features = features.copy() if output_type == ModelBuilderOutputType.MODEL_FN_OPS: features.update( layers.transform_features(features, feature_columns)) else: for fc in feature_columns: tensor = fc_core._transform_features(features, [fc])[fc] # pylint: disable=protected-access features[fc.name] = tensor weights = None if weights_name and weights_name in features: weights = features.pop(weights_name) keys = None if keys_name and keys_name in features: keys = features.pop(keys_name) # If we're doing eval, optionally ignore device_assigner. # Also ignore device assigner if we're exporting (mode == INFER) dev_assn = device_assigner if (mode == model_fn_lib.ModeKeys.INFER or (local_eval and mode == model_fn_lib.ModeKeys.EVAL)): dev_assn = None graph_builder = graph_builder_class(params, device_assigner=dev_assn) logits, tree_paths, regression_variance = graph_builder.inference_graph( features) summary.scalar('average_tree_size', graph_builder.average_size()) # For binary classification problems, convert probabilities to logits. # Includes hack to get around the fact that a probability might be 0 or 1. if not params.regression and params.num_classes == 2: class_1_probs = array_ops.slice(logits, [0, 1], [-1, 1]) logits = math_ops.log( math_ops.maximum( class_1_probs / math_ops.maximum(1.0 - class_1_probs, EPSILON), EPSILON)) # labels might be None if we're doing prediction (which brings up the # question of why we force everything to adhere to a single model_fn). training_graph = None training_hooks = [] if labels is not None and mode == model_fn_lib.ModeKeys.TRAIN: with ops.control_dependencies([logits.op]): training_graph = control_flow_ops.group( graph_builder.training_graph(features, labels, input_weights=weights, num_trainers=num_trainers, trainer_id=trainer_id), state_ops.assign_add(training_util.get_global_step(), 1)) # Put weights back in if weights is not None: features[weights_name] = weights # TensorForest's training graph isn't calculated directly from the loss # like many other models. def _train_fn(unused_loss): return training_graph # Ops are run in lexigraphical order of their keys. Run the resource # clean-up op last. all_handles = graph_builder.get_all_resource_handles() ops_at_end = { '9: clean up resources': control_flow_ops.group(*[ resource_variable_ops.destroy_resource_op(handle) for handle in all_handles ]) } if report_feature_importances: ops_at_end['1: feature_importances'] = ( graph_builder.feature_importances()) training_hooks = [TensorForestRunOpAtEndHook(ops_at_end)] if output_type == ModelBuilderOutputType.MODEL_FN_OPS: model_ops = model_head.create_model_fn_ops(features=features, labels=labels, mode=mode, train_op_fn=_train_fn, logits=logits, scope=head_scope) if early_stopping_rounds: training_hooks.append( TensorForestLossHook(early_stopping_rounds, early_stopping_loss_threshold= early_stopping_loss_threshold, loss_op=model_ops.loss)) model_ops.training_hooks.extend(training_hooks) if keys is not None: model_ops.predictions[keys_name] = keys if params.inference_tree_paths: model_ops.predictions[TREE_PATHS_PREDICTION_KEY] = tree_paths model_ops.predictions[ VARIANCE_PREDICTION_KEY] = regression_variance if include_all_in_serving: # In order to serve the variance we need to add the prediction dict # to output_alternatives dict. if not model_ops.output_alternatives: model_ops.output_alternatives = {} model_ops.output_alternatives[ALL_SERVING_KEY] = ( constants.ProblemType.UNSPECIFIED, model_ops.predictions) return model_ops else: # Estimator spec estimator_spec = model_head.create_estimator_spec( features=features, mode=mode, labels=labels, train_op_fn=_train_fn, logits=logits) if early_stopping_rounds: training_hooks.append( TensorForestLossHook(early_stopping_rounds, early_stopping_loss_threshold= early_stopping_loss_threshold, loss_op=estimator_spec.loss)) estimator_spec = estimator_spec._replace( training_hooks=training_hooks + list(estimator_spec.training_hooks)) if keys is not None: estimator_spec.predictions[keys_name] = keys if params.inference_tree_paths: estimator_spec.predictions[ TREE_PATHS_PREDICTION_KEY] = tree_paths estimator_spec.predictions[ VARIANCE_PREDICTION_KEY] = regression_variance if include_all_in_serving: outputs = estimator_spec.export_outputs if not outputs: outputs = {} outputs = { ALL_SERVING_KEY: PredictOutput(estimator_spec.predictions) } print(estimator_spec.export_outputs) # In order to serve the variance we need to add the prediction dict # to output_alternatives dict. estimator_spec = estimator_spec._replace( export_outputs=outputs) return estimator_spec
def sdca_model_fn(features, labels, mode, params, config=None): """A model_fn for linear models that use the SDCA optimizer. Args: features: A dict of `Tensor` keyed by column name. labels: `Tensor` of shape [batch_size, 1] or [batch_size] labels of dtype `int32` or `int64` with values in the set {0, 1}. mode: Defines whether this is training, evaluation or prediction. See `ModeKeys`. params: A dict of hyperparameters. The following hyperparameters are expected: * head: A `Head` instance. Type must be one of `_BinarySvmHead`, `_RegressionHead` or `_BinaryLogisticHead`. * feature_columns: An iterable containing all the feature columns used by the model. * l1_regularization: Global (across all examples) L1-regularization parameter. * l2_regularization: Global (across all examples) L2-regularization parameter. * num_loss_partitions: Number of partitions of the global loss function optimized by `SDCAOptimizer`. * weight_column_name: A string defining the weight feature column, or None if there are no weights. * update_weights_hook: A `SessionRunHook` object or None. Used to update model weights. config: `RunConfig` object to configure the runtime settings. Returns: A `ModelFnOps` instance. Raises: ValueError: If the type of head is not one of `_BinarySvmHead`, `_RegressionHead` or `_MultiClassHead`. ValueError: If mode is not any of the `ModeKeys`. """ head = params["head"] feature_columns = params["feature_columns"] example_id_column = params["example_id_column"] l1_regularization = params["l1_regularization"] l2_regularization = params["l2_regularization"] num_loss_partitions = params["num_loss_partitions"] weight_column_name = params["weight_column_name"] update_weights_hook = params.get("update_weights_hook", None) loss_type = None if isinstance(head, head_lib._BinarySvmHead): # pylint: disable=protected-access loss_type = "hinge_loss" elif isinstance(head, head_lib._BinaryLogisticHead): # pylint: disable=protected-access loss_type = "logistic_loss" elif isinstance(head, head_lib._RegressionHead): # pylint: disable=protected-access loss_type = "squared_loss" else: raise ValueError("Unsupported head type: {}".format(type(head))) assert head.logits_dimension == 1, ( "SDCA only applies to logits_dimension=1.") # Update num_loss_partitions based on number of workers. n_loss_partitions = num_loss_partitions or max(1, config.num_worker_replicas) optimizer = sdca_optimizer.SDCAOptimizer( example_id_column=example_id_column, num_loss_partitions=n_loss_partitions, symmetric_l1_regularization=l1_regularization, symmetric_l2_regularization=l2_regularization) parent_scope = "linear" with variable_scope.variable_op_scope(features.values(), parent_scope) as scope: features = features.copy() features.update(layers.transform_features(features, feature_columns)) logits, columns_to_variables, bias = ( layers.weighted_sum_from_feature_columns( columns_to_tensors=features, feature_columns=feature_columns, num_outputs=1, scope=scope)) _add_bias_column(feature_columns, features, bias, columns_to_variables) def _train_op_fn(unused_loss): global_step = contrib_variables.get_global_step() sdca_model, train_op = optimizer.get_train_step( columns_to_variables, weight_column_name, loss_type, features, labels, global_step) if update_weights_hook is not None: update_weights_hook.set_parameters(sdca_model, train_op) return train_op model_fn_ops = head.create_model_fn_ops( features=features, labels=labels, mode=mode, train_op_fn=_train_op_fn, logits=logits) if update_weights_hook is not None: return model_fn_ops._replace(training_chief_hooks=( model_fn_ops.training_chief_hooks + [update_weights_hook])) return model_fn_ops
def sdca_model_fn(features, labels, mode, params): """A model_fn for linear models that use the SDCA optimizer. Args: features: A dict of `Tensor` keyed by column name. labels: `Tensor` of shape [batch_size, 1] or [batch_size] labels of dtype `int32` or `int64` in the range `[0, n_classes)`. mode: Defines whether this is training, evaluation or prediction. See `ModeKeys`. params: A dict of hyperparameters. The following hyperparameters are expected: * head: A `Head` instance. Type must be one of `_BinarySvmHead`, `_RegressionHead` or `_BinaryLogisticHead`. * feature_columns: An iterable containing all the feature columns used by the model. * optimizer: An `SDCAOptimizer` instance. * weight_column_name: A string defining the weight feature column, or None if there are no weights. * update_weights_hook: A `SessionRunHook` object or None. Used to update model weights. Returns: A `ModelFnOps` instance. Raises: ValueError: If `optimizer` is not an `SDCAOptimizer` instance. ValueError: If the type of head is neither `_BinarySvmHead`, nor `_RegressionHead` nor `_MultiClassHead`. ValueError: If mode is not any of the `ModeKeys`. """ head = params["head"] feature_columns = params["feature_columns"] optimizer = params["optimizer"] weight_column_name = params["weight_column_name"] update_weights_hook = params.get("update_weights_hook", None) if not isinstance(optimizer, sdca_optimizer.SDCAOptimizer): raise ValueError("Optimizer must be of type SDCAOptimizer") if isinstance(head, head_lib._BinarySvmHead): # pylint: disable=protected-access loss_type = "hinge_loss" elif isinstance(head, head_lib._BinaryLogisticHead): # pylint: disable=protected-access loss_type = "logistic_loss" elif isinstance(head, head_lib._RegressionHead): # pylint: disable=protected-access assert head.logits_dimension == 1, ("SDCA only applies for " "logits_dimension=1.") loss_type = "squared_loss" else: raise ValueError("Unsupported head type: {}".format(head)) parent_scope = "linear" with variable_scope.variable_op_scope(features.values(), parent_scope) as scope: features = features.copy() features.update(layers.transform_features(features, feature_columns)) logits, columns_to_variables, bias = ( layers.weighted_sum_from_feature_columns( columns_to_tensors=features, feature_columns=feature_columns, num_outputs=1, scope=scope)) _add_bias_column(feature_columns, features, bias, columns_to_variables) def _train_op_fn(unused_loss): global_step = contrib_variables.get_global_step() sdca_model, train_op = optimizer.get_train_step( columns_to_variables, weight_column_name, loss_type, features, labels, global_step) if update_weights_hook is not None: update_weights_hook.set_parameters(sdca_model, train_op) return train_op model_fn_ops = head.create_model_fn_ops(features=features, labels=labels, mode=mode, train_op_fn=_train_op_fn, logits=logits) if update_weights_hook is not None: return model_fn_ops._replace( training_chief_hooks=(model_fn_ops.training_chief_hooks + [update_weights_hook])) return model_fn_ops
def sdca_model_fn(features, labels, mode, params): """A model_fn for linear models that use the SDCA optimizer. Args: features: A dict of `Tensor` keyed by column name. labels: `Tensor` of shape [batch_size, 1] or [batch_size] labels of dtype `int32` or `int64` in the range `[0, n_classes)`. mode: Defines whether this is training, evaluation or prediction. See `ModeKeys`. params: A dict of hyperparameters. The following hyperparameters are expected: * head: A `Head` instance. Type must be one of `_BinarySvmHead`, `_RegressionHead` or `_BinaryLogisticHead`. * feature_columns: An iterable containing all the feature columns used by the model. * optimizer: An `SDCAOptimizer` instance. * weight_column_name: A string defining the weight feature column, or None if there are no weights. * update_weights_hook: A `SessionRunHook` object or None. Used to update model weights. Returns: A `ModelFnOps` instance. Raises: ValueError: If `optimizer` is not an `SDCAOptimizer` instance. ValueError: If the type of head is neither `_BinarySvmHead`, nor `_RegressionHead` nor `_MultiClassHead`. ValueError: If mode is not any of the `ModeKeys`. """ head = params["head"] feature_columns = params["feature_columns"] optimizer = params["optimizer"] weight_column_name = params["weight_column_name"] update_weights_hook = params.get("update_weights_hook", None) if not isinstance(optimizer, sdca_optimizer.SDCAOptimizer): raise ValueError("Optimizer must be of type SDCAOptimizer") if isinstance(head, head_lib._BinarySvmHead): # pylint: disable=protected-access loss_type = "hinge_loss" elif isinstance(head, head_lib._BinaryLogisticHead): # pylint: disable=protected-access loss_type = "logistic_loss" elif isinstance(head, head_lib._RegressionHead): # pylint: disable=protected-access assert head.logits_dimension == 1, ("SDCA only applies for " "logits_dimension=1.") loss_type = "squared_loss" else: raise ValueError("Unsupported head type: {}".format(head)) parent_scope = "linear" with variable_scope.variable_op_scope( features.values(), parent_scope) as scope: features = features.copy() features.update(layers.transform_features(features, feature_columns)) logits, columns_to_variables, bias = ( layers.weighted_sum_from_feature_columns( columns_to_tensors=features, feature_columns=feature_columns, num_outputs=1, scope=scope)) _add_bias_column(feature_columns, features, bias, columns_to_variables) def _train_op_fn(unused_loss): global_step = training_util.get_global_step() sdca_model, train_op = optimizer.get_train_step(columns_to_variables, weight_column_name, loss_type, features, labels, global_step) if update_weights_hook is not None: update_weights_hook.set_parameters(sdca_model, train_op) return train_op model_fn_ops = head.create_model_fn_ops( features=features, labels=labels, mode=mode, train_op_fn=_train_op_fn, logits=logits) if update_weights_hook is not None: return model_fn_ops._replace( training_chief_hooks=(model_fn_ops.training_chief_hooks + [update_weights_hook])) return model_fn_ops
def _model_fn(features, labels, mode): """Function that returns predictions, training loss, and training op.""" if (isinstance(features, ops.Tensor) or isinstance(features, sparse_tensor.SparseTensor)): features = {'features': features} if feature_columns: features = features.copy() features.update(layers.transform_features(features, feature_columns)) weights = None if weights_name and weights_name in features: weights = features.pop(weights_name) keys = None if keys_name and keys_name in features: keys = features.pop(keys_name) # If we're doing eval, optionally ignore device_assigner. # Also ignore device assigner if we're exporting (mode == INFER) dev_assn = device_assigner if (mode == model_fn_lib.ModeKeys.INFER or (local_eval and mode == model_fn_lib.ModeKeys.EVAL)): dev_assn = None graph_builder = graph_builder_class(params, device_assigner=dev_assn) logits, tree_paths, regression_variance = graph_builder.inference_graph( features) summary.scalar('average_tree_size', graph_builder.average_size()) # For binary classification problems, convert probabilities to logits. # Includes hack to get around the fact that a probability might be 0 or 1. if not params.regression and params.num_classes == 2: class_1_probs = array_ops.slice(logits, [0, 1], [-1, 1]) logits = math_ops.log( math_ops.maximum(class_1_probs / math_ops.maximum( 1.0 - class_1_probs, EPSILON), EPSILON)) # labels might be None if we're doing prediction (which brings up the # question of why we force everything to adhere to a single model_fn). training_graph = None training_hooks = [] if labels is not None and mode == model_fn_lib.ModeKeys.TRAIN: with ops.control_dependencies([logits.op]): training_graph = control_flow_ops.group( graph_builder.training_graph( features, labels, input_weights=weights, num_trainers=num_trainers, trainer_id=trainer_id), state_ops.assign_add(contrib_framework.get_global_step(), 1)) # Put weights back in if weights is not None: features[weights_name] = weights # TensorForest's training graph isn't calculated directly from the loss # like many other models. def _train_fn(unused_loss): return training_graph model_ops = model_head.create_model_fn_ops( features=features, labels=labels, mode=mode, train_op_fn=_train_fn, logits=logits, scope=head_scope) # Ops are run in lexigraphical order of their keys. Run the resource # clean-up op last. all_handles = graph_builder.get_all_resource_handles() ops_at_end = { '9: clean up resources': control_flow_ops.group( *[resource_variable_ops.destroy_resource_op(handle) for handle in all_handles])} if report_feature_importances: ops_at_end['1: feature_importances'] = ( graph_builder.feature_importances()) training_hooks.append(TensorForestRunOpAtEndHook(ops_at_end)) if early_stopping_rounds: training_hooks.append( TensorForestLossHook( early_stopping_rounds, early_stopping_loss_threshold=early_stopping_loss_threshold, loss_op=model_ops.loss)) model_ops.training_hooks.extend(training_hooks) if keys is not None: model_ops.predictions[keys_name] = keys if params.inference_tree_paths: model_ops.predictions[TREE_PATHS_PREDICTION_KEY] = tree_paths if params.regression: model_ops.predictions[VARIANCE_PREDICTION_KEY] = regression_variance return model_ops