Пример #1
0
def _embedded_lattices(calibrated_input_tensor,
                       input_dim,
                       output_dim,
                       interpolation_type,
                       monotonic_num_lattices,
                       monotonic_lattice_rank,
                       monotonic_lattice_size,
                       non_monotonic_num_lattices,
                       non_monotonic_lattice_rank,
                       non_monotonic_lattice_size,
                       linear_embedding_calibration_min,
                       linear_embedding_calibration_max,
                       linear_embedding_calibration_num_keypoints,
                       is_monotone=None,
                       lattice_l1_reg=None,
                       lattice_l2_reg=None,
                       lattice_l1_torsion_reg=None,
                       lattice_l2_torsion_reg=None,
                       lattice_l1_laplacian_reg=None,
                       lattice_l2_laplacian_reg=None):
    """Creates an ensemble of lattices with a linear embedding.

  This function constructs the following deep lattice network:
  calibrated_input -> linear_embedding -> calibration -> ensemble of lattices.
  Then ensemble of lattices' output are averaged and bias term is added to make
  a final prediction.

  ensemble of lattices is consists of two parts: monotonic lattices and
  non-monotonic lattices. The input to the monotonic lattices is an output of
  linear_embedding that contains both monotonic and non-monotonic
  calibrated_input. All inputs to the monotonic lattices are set to be monotonic
  to preserve end-to-end monotonicity in the monotonic feature.
  The input to the non-monotonic lattices is an output of linear_embedding that
  only contains non-monotonic calibrated_input. All inputs to the non-monotonic
  lattices are set to be non-monotonic, since we do not need to guarantee
  monotonicity.

  Args:
    calibrated_input_tensor: [batch_size, input_dim] tensor.
    input_dim: (int) input dimnension.
    output_dim: (int) output dimension.
    interpolation_type: defines whether the lattice will interpolate using the
      full hypercube or only the simplex ("hyper-triangle") around the point
      being evaluated. Valid values: 'hypercube' or 'simplex'
    monotonic_num_lattices: (int) number of monotonic lattices in the ensemble
      lattices layer.
    monotonic_lattice_rank: (int) number of inputs to each monotonic lattice in
      the ensemble lattices layer.
    monotonic_lattice_size: (int) lattice cell size for each monotonic lattice
      in the ensemble lattices layer.
    non_monotonic_num_lattices: (int) number of non monotonic lattices in the
      ensemble lattices layer.
    non_monotonic_lattice_rank: (int) number of inputs to each non monotonic
      lattice in the ensemble lattices layer.
    non_monotonic_lattice_size: (int) lattice cell size for each non monotonic
      lattice in the ensemble lattices layer.
    linear_embedding_calibration_min: (float) a minimum input keypoints value
      for linear_embedding calibration.
    linear_embedding_calibration_max: (float) a maximum input keypoints value
      for linear_embedding calibration.
    linear_embedding_calibration_num_keypoints: (int) a number of eypoints for
      linear_embedding calibration.
    is_monotone: (bool, list of booleans) is_monotone[k] == true then
      calibrated_input_tensor[:, k] is considered to be a monotonic input.
    lattice_l1_reg: (float) lattice l1 regularization amount.
    lattice_l2_reg: (float) lattice l2 regularization amount.
    lattice_l1_torsion_reg: (float) lattice l1 torsion regularization amount.
    lattice_l2_torsion_reg: (float) lattice l2 torsion regularization amount.
    lattice_l1_laplacian_reg: (float) lattice l1 laplacian regularization
      amount.
    lattice_l2_laplacian_reg: (float) lattice l2 laplacian regularization
      amount.
  Returns:
    A tuple of (output_tensor, projection_ops, regularization).
  Raises:
    ValueError: If there is no non-monotonic inputs but
    non_monotonic_num_lattices is not zero.
  """
    projections = []
    regularization = None

    # Explictly assign number of lattices to zero for any empty cases.
    if not monotonic_num_lattices:
        monotonic_num_lattices = 0
    if not non_monotonic_num_lattices:
        non_monotonic_num_lattices = 0

    # Step 1. Create a linear embedding.
    if monotonic_num_lattices:
        monotonic_embedding_dim = monotonic_num_lattices * monotonic_lattice_rank
    else:
        monotonic_num_lattices = 0
        monotonic_embedding_dim = 0
    if non_monotonic_num_lattices:
        non_monotonic_embedding_dim = (non_monotonic_num_lattices *
                                       non_monotonic_lattice_rank)
    else:
        non_monotonic_num_lattices = 0
        non_monotonic_embedding_dim = 0

    if is_monotone is not None:
        is_monotone = tools.cast_to_list(is_monotone, input_dim, 'is_monotone')
    with variable_scope.variable_scope('linear_embedding'):
        packed_results = monotone_linear_layers.split_monotone_linear_layer(
            calibrated_input_tensor,
            input_dim,
            monotonic_embedding_dim,
            non_monotonic_embedding_dim,
            is_monotone=is_monotone)
        (monotonic_output, _, non_monotonic_output, _, proj,
         _) = packed_results
        if proj is not None:
            projections.append(proj)

    # Step 2. Create ensemble of monotonic lattices.
    if monotonic_num_lattices == 0:
        m_lattice_outputs = None
    else:
        with variable_scope.variable_scope('monotonic_lattices'):
            m_lattice_outputs, projs, reg = _ensemble_lattices_layer(
                monotonic_output,
                monotonic_embedding_dim,
                output_dim,
                interpolation_type,
                linear_embedding_calibration_min,
                linear_embedding_calibration_max,
                linear_embedding_calibration_num_keypoints,
                monotonic_num_lattices,
                monotonic_lattice_rank,
                monotonic_lattice_size,
                is_monotone=True,
                l1_reg=lattice_l1_reg,
                l2_reg=lattice_l2_reg,
                l1_torsion_reg=lattice_l1_torsion_reg,
                l2_torsion_reg=lattice_l2_torsion_reg,
                l1_laplacian_reg=lattice_l1_laplacian_reg,
                l2_laplacian_reg=lattice_l2_laplacian_reg)
            if projs:
                projections += projs
            regularization = tools.add_if_not_none(regularization, reg)

    # Step 3. Construct non-monotonic ensembles.
    if non_monotonic_output is None and non_monotonic_num_lattices > 0:
        raise ValueError(
            'All input signals are monotonic but the number of non monotonic '
            'lattices is not zero.')
    if non_monotonic_num_lattices == 0:
        n_lattice_outputs = None
    else:
        with variable_scope.variable_scope('non_monotonic_lattices'):
            n_lattice_outputs, projs, reg = _ensemble_lattices_layer(
                non_monotonic_output,
                non_monotonic_embedding_dim,
                output_dim,
                interpolation_type,
                linear_embedding_calibration_min,
                linear_embedding_calibration_max,
                linear_embedding_calibration_num_keypoints,
                non_monotonic_num_lattices,
                non_monotonic_lattice_rank,
                non_monotonic_lattice_size,
                is_monotone=False,
                l1_reg=lattice_l1_reg,
                l2_reg=lattice_l2_reg,
                l1_torsion_reg=lattice_l1_torsion_reg,
                l2_torsion_reg=lattice_l2_torsion_reg,
                l1_laplacian_reg=lattice_l1_laplacian_reg,
                l2_laplacian_reg=lattice_l2_laplacian_reg)
            if projs:
                projections += projs
            regularization = tools.add_if_not_none(regularization, reg)

    # Step 4. Take average to make a final prediction.
    with variable_scope.variable_scope('ensemble_average'):
        output = variable_scope.get_variable(
            name='ensemble_bias',
            initializer=[0.0] * output_dim,
            dtype=calibrated_input_tensor.dtype)
        if m_lattice_outputs:
            output += math_ops.divide(math_ops.add_n(m_lattice_outputs),
                                      monotonic_num_lattices)
        if n_lattice_outputs is not None:
            output += math_ops.divide(math_ops.add_n(n_lattice_outputs),
                                      non_monotonic_num_lattices)

    return (output, projections, regularization)
Пример #2
0
def calibration_layer(uncalibrated_tensor,
                      num_keypoints,
                      keypoints_initializers=None,
                      keypoints_initializer_fns=None,
                      bound=False,
                      monotonic=None,
                      missing_input_values=None,
                      missing_output_values=None,
                      name=None,
                      **regularizer_amounts):
    """Creates a calibration layer for uncalibrated values.

  Returns a calibrated tensor of the same shape as the uncalibrated continuous
  signals passed in, and a list of projection ops, that must be applied at
  each step (or every so many steps) to project the model to a feasible space:
  used for bounding the outputs or for imposing monotonicity -- the list will be
  empty if bound and monotonic are not set.

  Args:
    uncalibrated_tensor: Tensor of shape [batch_size, ...] with uncalibrated
      values.
    num_keypoints: Number of keypoints to use. Either a scalar value that
      will be used for every uncalibrated signal, or a list of n values,
      per uncalibrated signal -- uncalibrated is first flattened (
      see tf.contrib.layers.flatten) to [batch_size, n], and there should
      be one value in the list per n. If a value of the list is 0 or None
      the correspondent signal won't be calibrated.
    keypoints_initializers: For evaluation or inference (or when resuming
      training from a checkpoint) the values will be loaded from disk, so they
      don't need to be given (leave it as None).
      Otherwise provide either a tuple of two tensors of shape [num_keypoints],
      or a list of n pairs of tensors, each of shape [num_keypoints]. In this
      list there should be one pair per uncalibrated signal, just like
      num_keypoints above. Notice that num_keypoints can be different per
      signal.
    keypoints_initializer_fns: Like keypoints_initializers but using lambda
      initializers. They should be compatible with tf.get_variable. If this is
      set, then keypoints_initializers must be None.
    bound: boolean whether output of calibration must be bound. Alternatively
      a list of n booleans, one per uncalibrated value, like num_keypoints
      above.
    monotonic: whether calibration is monotonic: None or 0 means no
      monotonicity. Positive or negative values mean increasing or decreasing
      monotonicity respectively. Alternatively a list of n monotonic values,
      one per uncalibrated value, like num_keypoints above.
    missing_input_values: If set, and if the input has this value it is assumed
      to be missing and the output will either be calibrated to some value
      between `[calibration_output_min, calibration_output_max]` or set to a
      fixed value set by missing_output_value. Limitation: it only works for
      scalars. Either one value for all inputs, or a list with one value per
      uncalibrated value.
    missing_output_values: Requires missing_input_value also to be set. If set
      if will convert missing input to this value. Either one value for all
      outputs, or a list with one value per uncalibrated value.
    name: Name scope for operations.
    **regularizer_amounts: Keyword args of regularization amounts passed to
      regularizers.calibrator_regularization(). Keyword names should be among
      supported regularizers.CALIBRATOR_REGULARIZERS and values should be
      either float or list of floats. If float, then same value is applied to
      all input signals.

  Returns:
    A tuple of:
    * calibrated tensor of shape [batch_size, ...], the same shape as
      uncalibrated.
    * list of projection ops, that must be applied at each step (or every so
      many steps) to project the model to a feasible space: used for bounding
      the outputs or for imposing monotonicity. Empty if none are requested.
    * None or tensor with regularization loss.

  Raises:
    ValueError: If dimensions don't match.
  """
    with ops.name_scope(name or 'calibration_layer'):
        # Flattening uncalibrated tensor [batch_Size, k1, k2, ..., kn] to
        # [batch_size, k1 * k2 * ... * kn].
        uncalibrated_shape = uncalibrated_tensor.get_shape().as_list()
        n = 1
        for non_batch_dim in uncalibrated_shape[1:]:
            n *= non_batch_dim
        flat_uncalibrated = array_ops.reshape(uncalibrated_tensor,
                                              shape=[-1, n],
                                              name='flat_uncalibrated')

        num_keypoints = tools.cast_to_list(num_keypoints, n, 'num_keypoints')
        keypoints_initializers = tools.cast_to_list(keypoints_initializers, n,
                                                    'keypoints_initializers')
        keypoints_initializer_fns = tools.cast_to_list(
            keypoints_initializer_fns, n, 'keypoints_initializer_fns')
        bound = tools.cast_to_list(bound, n, 'bound')
        monotonic = tools.cast_to_list(monotonic, n, 'monotonic')
        missing_input_values = tools.cast_to_list(missing_input_values, n,
                                                  'missing_input_values')
        missing_output_values = tools.cast_to_list(missing_output_values, n,
                                                   'missing_output_values')
        regularizer_amounts = {
            regularizer_name:
            tools.cast_to_list(regularizer_amounts[regularizer_name], n,
                               regularizer_name)
            for regularizer_name in regularizer_amounts
        }

        signal_names = ['signal_%d' % ii for ii in range(n)]

        uncalibrated_splits = array_ops.unstack(flat_uncalibrated, axis=1)
        calibrated_splits = []
        projection_ops = []
        total_regularization = None
        for ii in range(n):
            if not num_keypoints[ii]:
                # No calibration for this signal.
                calibrated_splits += [uncalibrated_splits[ii]]
            else:
                signal_regularizer_amounts = {
                    regularizer_name: regularizer_amounts[regularizer_name][ii]
                    for regularizer_name in regularizer_amounts
                }
                calibrated, projection, reg = one_dimensional_calibration_layer(
                    uncalibrated_splits[ii],
                    num_keypoints[ii],
                    signal_name=signal_names[ii],
                    keypoints_initializers=keypoints_initializers[ii],
                    keypoints_initializer_fns=keypoints_initializer_fns[ii],
                    bound=bound[ii],
                    monotonic=monotonic[ii],
                    missing_input_value=missing_input_values[ii],
                    missing_output_value=missing_output_values[ii],
                    **signal_regularizer_amounts)
                calibrated_splits += [calibrated]
                if projection is not None:
                    projection_ops += [projection]
                total_regularization = tools.add_if_not_none(
                    total_regularization, reg)
        flat_calibrated = array_ops.stack(calibrated_splits,
                                          axis=1,
                                          name='stack_calibrated')
        reshaped_calibrated = array_ops.reshape(
            flat_calibrated,
            shape=array_ops.shape(uncalibrated_tensor),
            name='reshape_calibrated')
        return reshaped_calibrated, projection_ops, total_regularization
Пример #3
0
def monotone_linear_layer(input_tensor,
                          input_dim,
                          output_dim,
                          is_monotone=None,
                          init_weight_mean=2.0,
                          init_weight_stddev=0.5,
                          init_bias=None,
                          l1_reg=None,
                          l2_reg=None):
  """Creates a partially monotonic linear embedding layer.

  Returns an output of partially monotonic linear embedding layer, weights in
  the linear embedding layer, projection ops and regularizers.

    output = input * weight' + bias

  and the kth row is constrained to be non-negative, if is_monotone[k] == True.
  weight is initialized to entrywise Normal random variable (init_weight_mean,
  init_weight_stdev). If init_b is not provided, then the initial bias is
  initialized to -1/2 * init_weight_mean * input_dim. This offset term is used
  to make the initial mean to 0, assuming each input tensor is from the uniform
  distribution [0, 1]:
    E[output] = E[input * weight' + bias] = E[input] * E[weight] + bias
      = 1/2 * init_weight_mean * input_dim + bias
      = 0.

  Args:
    input_tensor: [batch_size, input_dim] tensor.
    input_dim: (int) input dimension.
    output_dim: (int) output dimension.
    is_monotone:  A list of input_dim booleans, a single boolean, or None.
      If None or False, linear layer will not have monotonicity constraints.
      If True, all of inputs are set to be monotonic. In the case of boolean
      list, input_tensor[:, k] is set to be monotonic if is_monotone[k] == True.
    init_weight_mean: (float) A mean for Normal random weight initializer.
    init_weight_stddev: (float) A standard deviation for Normal random weight
      initializer.
    init_bias: (float) initial bias. If not provided,
      -1/2 * init_weight_mean * input_dim is used.
    l1_reg: (float) amount of l1 regularization.
    l2_reg: (float) amount of l2 regularization.

  Returns:
    A tuple of:
    * output tensor of shape [batch_size, output_dim]
    * weight tensor of shape [output_dim, input_dim]
    * None or projection ops, that must be applied at each
      step (or every so many steps) to project the model to a feasible space:
      used for bounding the outputs or for imposing monotonicity.
    * None or a regularization loss, if regularization is configured.

  Raises:
    ValueError: If is_monotone is not None, but its length != input_dim.
  """
  with variable_scope.variable_scope('monotone_linear'):
    # We use [output_dim, input_dim] convention to use broadcasting in
    # projeciton.
    init_weights = random_ops.random_normal(
        [output_dim, input_dim],
        mean=init_weight_mean,
        stddev=init_weight_stddev)
    if init_bias is None:
      init_biases = [-init_weight_mean * 0.5 * input_dim] * output_dim
    else:
      init_biases = [init_bias] * output_dim

    w = variable_scope.get_variable(name='weight',
                                    initializer=init_weights,
                                    dtype=input_tensor.dtype)
    b = variable_scope.get_variable(name='bias',
                                    initializer=init_biases,
                                    dtype=input_tensor.dtype)

    output_tensor = math_ops.matmul(input_tensor, w, transpose_b=True) + b

    # Constructing a projection op.
    projection = None
    if is_monotone:
      with ops.name_scope('monotonic_projection'):
        is_monotone = tools.cast_to_list(is_monotone, input_dim, 'is_monotone')
        if input_dim != len(is_monotone):
          raise ValueError('input_dim (%d) != is_monotone length (%d)' %
                           (input_dim, len(is_monotone)))
        # Construct a multiplicative mask for monotonic dimension
        # selection.
        monotone_mask = array_ops.constant(
            [1.0 if monotone else 0.0 for monotone in is_monotone],
            dtype=w.dtype)
        # Since input_dim is the last dimension of the weight, we can use
        # broadcasting.
        masked_w = math_ops.multiply(w, monotone_mask)
        projected_w = math_ops.maximum(masked_w, 0.0)
        diff = projected_w - masked_w
        projection = w.assign_add(diff)

    # Constructing a regularization op.
    regularizer = None
    if l1_reg is not None or l2_reg is not None:
      with ops.name_scope('linear_regularization'):
        regularizer = regularizers.linear_regularization(w, l1_reg, l2_reg)

    return (output_tensor, w, projection, regularizer)
Пример #4
0
def _lattice_laplacian(lattice_param,
                       lattice_sizes,
                       l1_reg=None,
                       l2_reg=None,
                       name='lattice_laplacian'):
  """Returns a lattice laplacian regularization.

  Laplacian regularizers penalize the difference between adjacent vertices in
  multi-cell lattice. See Lattice Regression, NIPS, 2009 for the details, but
  we provide a 2d example in here.

  Consider a 3 x 2 lattice:
    3-------4--------5
    |       |        |
    |       |        |
    0-------1--------2
  where the number at each node represents the parameter index.
  In this case, the laplacian l1 regularizer is defined as

  reg = l1_reg[0] * (|param[1] - param[0]| + |param[2] - param[1]|
                     + |param[4] - param[3]| + |param[5] - param[4]|)
        + l1_reg[1] * (|param[3] - param[0]| + |param[4] - param[1]|
                       + |param[5] - param[2]})
  where param is a lattice_param tensor assuming one output.
  In l2 case, the absolute value is replaced with a square.

  If num_outputs > 1, the op is
    total_reg = sum_{d=1}^{output_dim} reg(lattice_param[d, :])
  i.e., a sum across all output dimensions.

  Args:
    lattice_param: (Rank-2 tensor with shape [num_outputs, num_parameters])
      lattice model's parameter.
    lattice_sizes: (list of integers) lattice size of each dimension.
    l1_reg: (list of floats or float) l1 regularization amount per each
      lattice dimension. If float, a same number will be accrossed to all
      lattice dimensions.
    l2_reg: (list of floats or float) l2 regularization amount per each
      lattice dimension. If float, a same number will be accrossed to all
      lattice dimensions.
    name: name scope of lattice laplacian regularizer.

  Returns:
    A rank-0 tensor (scalar) that contains regularizer or None if there is no
    regularization. This can happen if l1_reg and l2_reg amounts are not set.

  Raises:
    ValueError: * lattice_param is not rank-2 tensor.
                * output_dim or param_dim is unknown.
  """
  dims = lattice_param.shape.as_list()
  if len(dims) != 2:
    raise ValueError(
        'lattice_laplacian expects lattice_param as a '
        'rank-2 tensor but got dimensions: ', dims)
  output_dim = dims[0]
  param_dim = dims[1]
  if output_dim is None or param_dim is None:
    raise ValueError(
        'lattice_laplacian expects all the dimensions in '
        'lattice_param to be known, but got dimensions: ', dims)

  l1_reg = tools.cast_to_list(l1_reg, len(lattice_sizes), 'laplacian_l1_reg')
  l2_reg = tools.cast_to_list(l2_reg, len(lattice_sizes), 'laplacian_l2_reg')

  # Collect all dimensions that has non-trivial regularization amount.
  reg_dims = []
  lattice_rank = len(lattice_sizes)
  for dim in range(lattice_rank):
    if l1_reg[dim] or l2_reg[dim]:
      reg_dims.append(dim)

  if not reg_dims:
    return None

  regularization = None

  with tf.name_scope(name):
    for dim in reg_dims:
      slice_size = lattice_sizes[dim] - 1
      per_dim_upper = tools.lattice_1d_slice(
          lattice_param,
          lattice_sizes=lattice_sizes,
          lattice_axis=dim,
          begin=1,
          size=slice_size)
      per_dim_lower = tools.lattice_1d_slice(
          lattice_param,
          lattice_sizes=lattice_sizes,
          lattice_axis=dim,
          begin=0,
          size=slice_size)
      per_dim_diff = per_dim_upper - per_dim_lower
      if l1_reg[dim]:
        regularization = tools.add_if_not_none(
            regularization, l1_reg[dim] * tf.reduce_sum(tf.abs(per_dim_diff)))
      if l2_reg[dim]:
        regularization = tools.add_if_not_none(
            regularization,
            l2_reg[dim] * tf.reduce_sum(tf.square(per_dim_diff)))

  return regularization
Пример #5
0
def ensemble_lattices_layer(input_tensor,
                            lattice_sizes,
                            structure_indices,
                            is_monotone=None,
                            output_dim=1,
                            interpolation_type='hypercube',
                            lattice_initializers=None,
                            l1_reg=None,
                            l2_reg=None,
                            l1_torsion_reg=None,
                            l2_torsion_reg=None,
                            l1_laplacian_reg=None,
                            l2_laplacian_reg=None):
    """Creates a ensemble of lattices layer.

  Returns a list of output of lattices, lattice parameters, and projection ops.

  Args:
    input_tensor: [batch_size, input_dim] tensor.
    lattice_sizes: A list of lattice sizes of each dimension.
    structure_indices: A list of list of ints. structure_indices[k] is a list
    of indices that belongs to kth lattices.
    is_monotone: A list of input_dim booleans, boolean or None. If None or
      False, lattice will not have monotonicity constraints. If
      is_monotone[k] == True, then the lattice output has the non-decreasing
      monotonicity with respect to input_tensor[?, k] (the kth coordinate). If
      True, all the input coordinate will have the non-decreasing monotonicity.
    output_dim: Number of outputs.
    interpolation_type: 'hypercube' or 'simplex'.
    lattice_initializers: (Optional) A list of initializer for each lattice
      parameter vectors. lattice_initializer[k] is a 2D tensor
      [output_dim, parameter_dim[k]], where parameter_dim[k] is the number of
      parameter in the kth lattice. If None, lattice_param_as_linear initializer
      will be used with
      linear_weights=[1 if monotone else 0 for monotone in is_monotone].
    l1_reg: (float) l1 regularization amount.
    l2_reg: (float) l2 regularization amount.
    l1_torsion_reg: (float) l1 torsion regularization amount.
    l2_torsion_reg: (float) l2 torsion regularization amount.
    l1_laplacian_reg: (list of floats or float) list of L1 Laplacian
       regularization amount per each dimension. If a single float value is
       provided, then all diemnsion will get the same value.
    l2_laplacian_reg: (list of floats or float) list of L2 Laplacian
       regularization amount per each dimension. If a single float value is
       provided, then all diemnsion will get the same value.

  Returns:
    A tuple of:
    * a list of output tensors, [batch_size, output_dim], with length
      len(structure_indices), i.e., one for each lattice.
    * a list of parameter tensors shape [output_dim, parameter_dim]
    * None or projection ops, that must be applied at each
      step (or every so many steps) to project the model to a feasible space:
      used for bounding the outputs or for imposing monotonicity.
    * None or a regularization loss, if regularization is configured.

  """
    num_lattices = len(structure_indices)
    lattice_initializers = tools.cast_to_list(lattice_initializers,
                                              num_lattices,
                                              'lattice initializers')
    if l1_laplacian_reg is not None:
        l1_laplacian_reg = tools.cast_to_list(l1_laplacian_reg,
                                              len(lattice_sizes),
                                              'l1_laplacian_reg')
    if l2_laplacian_reg is not None:
        l2_laplacian_reg = tools.cast_to_list(l2_laplacian_reg,
                                              len(lattice_sizes),
                                              'l2_laplacian_reg')
    # input_slices[k] = input_tensor[:, k].
    input_slices = array_ops.unstack(input_tensor, axis=1)

    output_tensors = []
    param_tensors = []
    projections = []
    regularization = None
    if is_monotone:
        is_monotone = tools.cast_to_list(is_monotone, len(lattice_sizes),
                                         'is_monotone')
    # Now iterate through structure_indices to construct lattices.
    for (cnt, structure) in enumerate(structure_indices):
        with variable_scope.variable_scope('lattice_%d' % cnt):
            sub_lattice_sizes = [lattice_sizes[idx] for idx in structure]
            sub_is_monotone = None
            if is_monotone:
                sub_is_monotone = [is_monotone[idx] for idx in structure]

            sub_input_tensor_list = [input_slices[idx] for idx in structure]
            sub_input_tensor = array_ops.stack(sub_input_tensor_list, axis=1)

            if l1_laplacian_reg is not None:
                sub_l1_laplacian_reg = [
                    l1_laplacian_reg[idx] for idx in structure
                ]
            else:
                sub_l1_laplacian_reg = None

            if l2_laplacian_reg is not None:
                sub_l2_laplacian_reg = [
                    l2_laplacian_reg[idx] for idx in structure
                ]
            else:
                sub_l2_laplacian_reg = None

            packed_results = lattice_layer(
                sub_input_tensor,
                sub_lattice_sizes,
                sub_is_monotone,
                output_dim=output_dim,
                interpolation_type=interpolation_type,
                lattice_initializer=lattice_initializers[cnt],
                l1_reg=l1_reg,
                l2_reg=l2_reg,
                l1_torsion_reg=l1_torsion_reg,
                l2_torsion_reg=l2_torsion_reg,
                l1_laplacian_reg=sub_l1_laplacian_reg,
                l2_laplacian_reg=sub_l2_laplacian_reg)
            (sub_output, sub_param, sub_proj, sub_reg) = packed_results

            output_tensors.append(sub_output)
            param_tensors.append(sub_param)
            if sub_proj:
                projections += sub_proj
            regularization = tools.add_if_not_none(regularization, sub_reg)

    return (output_tensors, param_tensors, projections, regularization)
Пример #6
0
def lattice_layer(input_tensor,
                  lattice_sizes,
                  is_monotone=None,
                  output_dim=1,
                  interpolation_type='hypercube',
                  lattice_initializer=None,
                  l1_reg=None,
                  l2_reg=None,
                  l1_torsion_reg=None,
                  l2_torsion_reg=None,
                  l1_laplacian_reg=None,
                  l2_laplacian_reg=None):
    """Creates a lattice layer.

  Returns an output of lattice, lattice parameters, and projection ops.

  Args:
    input_tensor: [batch_size, input_dim] tensor.
    lattice_sizes: A list of lattice sizes of each dimension.
    is_monotone: A list of input_dim booleans, boolean or None. If None or
      False, lattice will not have monotonicity constraints. If
      is_monotone[k] == True, then the lattice output has the non-decreasing
      monotonicity with respect to input_tensor[?, k] (the kth coordinate). If
      True, all the input coordinate will have the non-decreasing monotonicity.
    output_dim: Number of outputs.
    interpolation_type: 'hypercube' or 'simplex'.
    lattice_initializer: (Optional) Initializer for lattice parameter vectors,
      a 2D tensor [output_dim, parameter_dim] (where parameter_dim ==
      lattice_sizes[0] * ... * lattice_sizes[input_dim - 1]). If None,
      lattice_param_as_linear initializer will be used with
      linear_weights=[1 if monotone else 0 for monotone in is_monotone].
    l1_reg: (float) l1 regularization amount.
    l2_reg: (float) l2 regularization amount.
    l1_torsion_reg: (float) l1 torsion regularization amount.
    l2_torsion_reg: (float) l2 torsion regularization amount.
    l1_laplacian_reg: (list of floats or float) list of L1 Laplacian
       regularization amount per each dimension. If a single float value is
       provided, then all diemnsion will get the same value.
    l2_laplacian_reg: (list of floats or float) list of L2 Laplacian
       regularization amount per each dimension. If a single float value is
       provided, then all diemnsion will get the same value.

  Returns:
    A tuple of:
    * output tensor of shape [batch_size, output_dim]
    * parameter tensor of shape [output_dim, parameter_dim]
    * None or projection ops, that must be applied at each
      step (or every so many steps) to project the model to a feasible space:
      used for bounding the outputs or for imposing monotonicity.
    * None or a regularization loss, if regularization is configured.

  Raises:
    ValueError: for invalid parameters.
  """
    if interpolation_type not in _VALID_INTERPOLATION_TYPES:
        raise ValueError('interpolation_type should be one of {}'.format(
            _VALID_INTERPOLATION_TYPES))

    if lattice_initializer is None:
        if is_monotone:
            is_monotone = tools.cast_to_list(is_monotone, len(lattice_sizes),
                                             'is_monotone')
            linear_weights = [
                1.0 if monotonic else 0.0 for monotonic in is_monotone
            ]
        else:
            linear_weights = [0.0] * len(lattice_sizes)
        lattice_initializer = lattice_param_as_linear(
            lattice_sizes, output_dim, linear_weights=linear_weights)

    parameter_tensor = variable_scope.get_variable(
        interpolation_type + '_lattice_parameters',
        initializer=lattice_initializer)

    output_tensor = lattice_ops.lattice(input_tensor,
                                        parameter_tensor,
                                        lattice_sizes,
                                        interpolation_type=interpolation_type)

    with ops.name_scope('lattice_monotonic_projection'):
        if is_monotone:
            is_monotone = tools.cast_to_list(is_monotone, len(lattice_sizes),
                                             'is_monotone')
            projected_parameter_tensor = monotone_lattice(
                parameter_tensor,
                lattice_sizes=lattice_sizes,
                is_monotone=is_monotone)
            delta = projected_parameter_tensor - parameter_tensor
            projection_ops = [parameter_tensor.assign_add(delta)]
        else:
            projection_ops = None

    with ops.name_scope('lattice_regularization'):
        reg = regularizers.lattice_regularization(
            parameter_tensor,
            lattice_sizes,
            l1_reg=l1_reg,
            l2_reg=l2_reg,
            l1_torsion_reg=l1_torsion_reg,
            l2_torsion_reg=l2_torsion_reg,
            l1_laplacian_reg=l1_laplacian_reg,
            l2_laplacian_reg=l2_laplacian_reg)

    return (output_tensor, parameter_tensor, projection_ops, reg)
Пример #7
0
def ensemble_lattices_layer(input_tensor,
                            lattice_sizes,
                            structure_indices,
                            is_monotone=None,
                            output_dim=1,
                            interpolation_type='hypercube',
                            lattice_initializers=None,
                            **regularizer_amounts):
    """Creates a ensemble of lattices layer.

  Returns a list of output of lattices, lattice parameters, and projection ops.

  Args:
    input_tensor: [batch_size, input_dim] tensor.
    lattice_sizes: A list of lattice sizes of each dimension.
    structure_indices: A list of list of ints. structure_indices[k] is a list of
      indices that belongs to kth lattices.
    is_monotone: A list of input_dim booleans, boolean or None. If None or
      False, lattice will not have monotonicity constraints. If is_monotone[k]
      == True, then the lattice output has the non-decreasing monotonicity with
      respect to input_tensor[?, k] (the kth coordinate). If True, all the input
      coordinate will have the non-decreasing monotonicity.
    output_dim: Number of outputs.
    interpolation_type: 'hypercube' or 'simplex'.
    lattice_initializers: (Optional) A list of initializer for each lattice
      parameter vectors. lattice_initializer[k] is a 2D tensor [output_dim,
      parameter_dim[k]], where parameter_dim[k] is the number of parameter in
      the kth lattice. If None, lattice_param_as_linear initializer will be used
      with linear_weights=[1 if monotone else 0 for monotone in is_monotone].
    **regularizer_amounts: Keyword args of regularization amounts passed to
      regularizers.lattice_regularization(). Keyword names should be among
      regularizers.LATTICE_ONE_DIMENSIONAL_REGULARIZERS or
      regularizers.LATTICE_MULTI_DIMENSIONAL_REGULARIZERS. For multi-dimensional
      regularizers the value should be float. For one-dimensional regularizers
      the values should be float or list of floats. If a single float value is
      provided, then all dimensions will get the same value.

  Returns:
    A tuple of:
    * a list of output tensors, [batch_size, output_dim], with length
      len(structure_indices), i.e., one for each lattice.
    * a list of parameter tensors shape [output_dim, parameter_dim]
    * None or projection ops, that must be applied at each
      step (or every so many steps) to project the model to a feasible space:
      used for bounding the outputs or for imposing monotonicity.
    * None or a regularization loss, if regularization is configured.
  """
    num_lattices = len(structure_indices)
    lattice_initializers = tools.cast_to_list(lattice_initializers,
                                              num_lattices,
                                              'lattice initializers')
    one_dimensional_regularizers = \
      regularizers.LATTICE_ONE_DIMENSIONAL_REGULARIZERS
    for regularizer_name in regularizer_amounts:
        if regularizer_name in one_dimensional_regularizers:
            regularizer_amounts[regularizer_name] = tools.cast_to_list(
                regularizer_amounts[regularizer_name], len(lattice_sizes),
                regularizer_name)

    # input_slices[k] = input_tensor[:, k].
    input_slices = tf.unstack(input_tensor, axis=1)

    output_tensors = []
    param_tensors = []
    projections = []
    regularization = None
    if is_monotone:
        is_monotone = tools.cast_to_list(is_monotone, len(lattice_sizes),
                                         'is_monotone')
    # Now iterate through structure_indices to construct lattices.
    get_indices = lambda indices, iterable: [
        iterable[index] for index in indices
    ]
    for (cnt, structure) in enumerate(structure_indices):
        with tf.compat.v1.variable_scope('lattice_%d' % cnt):
            sub = functools.partial(get_indices, structure)
            sub_lattice_sizes = sub(lattice_sizes)
            sub_is_monotone = None
            if is_monotone:
                sub_is_monotone = sub(is_monotone)

            sub_input_tensor_list = sub(input_slices)
            sub_input_tensor = tf.stack(sub_input_tensor_list, axis=1)

            sub_regularizer_amounts = {}
            for regularizer_name in regularizer_amounts:
                if regularizer_name in one_dimensional_regularizers:
                    sub_regularizer_amounts[regularizer_name] = sub(
                        regularizer_amounts[regularizer_name])
                else:
                    sub_regularizer_amounts[
                        regularizer_name] = regularizer_amounts[
                            regularizer_name]

            packed_results = lattice_layer(
                sub_input_tensor,
                sub_lattice_sizes,
                sub_is_monotone,
                output_dim=output_dim,
                interpolation_type=interpolation_type,
                lattice_initializer=lattice_initializers[cnt],
                **sub_regularizer_amounts)
            (sub_output, sub_param, sub_proj, sub_reg) = packed_results

            output_tensors.append(sub_output)
            param_tensors.append(sub_param)
            if sub_proj:
                projections += sub_proj
            regularization = tools.add_if_not_none(regularization, sub_reg)

    return (output_tensors, param_tensors, projections, regularization)
Пример #8
0
def lattice_layer(input_tensor,
                  lattice_sizes,
                  is_monotone=None,
                  output_min=None,
                  output_max=None,
                  output_dim=1,
                  interpolation_type='hypercube',
                  lattice_initializer=None,
                  **regularizer_amounts):
    """Creates a lattice layer.

  Returns an output of lattice, lattice parameters, and projection ops.

  Args:
    input_tensor: [batch_size, input_dim] tensor.
    lattice_sizes: A list of lattice sizes of each dimension.
    is_monotone: A list of input_dim booleans, boolean or None. If None or
      False, lattice will not have monotonicity constraints. If is_monotone[k]
      == True, then the lattice output has the non-decreasing monotonicity with
      respect to input_tensor[?, k] (the kth coordinate). If True, all the input
      coordinate will have the non-decreasing monotonicity.
    output_min: Optional output lower bound.
    output_max: Optional output upper bound.
    output_dim: Number of outputs.
    interpolation_type: 'hypercube' or 'simplex'.
    lattice_initializer: (Optional) Initializer for lattice parameter vectors, a
      2D tensor [output_dim, parameter_dim] (where parameter_dim ==
      lattice_sizes[0] * ... * lattice_sizes[input_dim - 1]). If None,
      lattice_param_as_linear initializer will be used with linear_weights=[1] *
      len(lattice_sizes).
    **regularizer_amounts: Keyword args of regularization amounts passed to
      regularizers.lattice_regularization(). Keyword names should be among
      regularizers.LATTICE_ONE_DIMENSIONAL_REGULARIZERS or
      regularizers.LATTICE_MULTI_DIMENSIONAL_REGULARIZERS. For multi-dimensional
      regularizers the value should be float. For one-dimensional regularizers
      the values should be float or list of floats. If a single float value is
      provided, then all dimensions will get the same value.

  Returns:
    A tuple of:
    * output tensor of shape [batch_size, output_dim]
    * parameter tensor of shape [output_dim, parameter_dim]
    * None or projection ops, that must be applied at each
      step (or every so many steps) to project the model to a feasible space:
      used for bounding the outputs or for imposing monotonicity.
    * None or a regularization loss, if regularization is configured.

  Raises:
    ValueError: for invalid parameters.
  """
    if interpolation_type not in _VALID_INTERPOLATION_TYPES:
        raise ValueError('interpolation_type should be one of {}'.format(
            _VALID_INTERPOLATION_TYPES))

    if lattice_initializer is None:
        linear_weights = [1.0] * len(lattice_sizes)
        lattice_initializer = lattice_param_as_linear(
            lattice_sizes, output_dim, linear_weights=linear_weights)

    parameter_tensor = tf.compat.v1.get_variable(
        interpolation_type + '_lattice_parameters',
        initializer=lattice_initializer)

    output_tensor = lattice_ops.lattice(input_tensor,
                                        parameter_tensor,
                                        lattice_sizes,
                                        interpolation_type=interpolation_type)

    with tf.name_scope('lattice_monotonic_projection'):
        if is_monotone or output_min is not None or output_max is not None:
            projected_parameter_tensor = parameter_tensor
            if is_monotone:
                is_monotone = tools.cast_to_list(is_monotone,
                                                 len(lattice_sizes),
                                                 'is_monotone')
                projected_parameter_tensor = monotone_lattice(
                    projected_parameter_tensor,
                    lattice_sizes=lattice_sizes,
                    is_monotone=is_monotone)

            if output_min is not None:
                projected_parameter_tensor = tf.maximum(
                    projected_parameter_tensor, output_min)

            if output_max is not None:
                projected_parameter_tensor = tf.minimum(
                    projected_parameter_tensor, output_max)

            delta = projected_parameter_tensor - parameter_tensor
            projection_ops = [parameter_tensor.assign_add(delta)]
        else:
            projection_ops = None

    with tf.name_scope('lattice_regularization'):
        reg = regularizers.lattice_regularization(parameter_tensor,
                                                  lattice_sizes,
                                                  **regularizer_amounts)

    return (output_tensor, parameter_tensor, projection_ops, reg)