def create_test_network_8():
  """Aligned network for test, including an intermediate addition.

  The graph is similar to create_test_network_1(), except that it includes a few
  more layers on top. The added layers compose two different branches whose
  receptive fields are different. This makes this test case more challenging; in
  particular, this test fails if a naive DFS-like algorithm is used for RF
  computation.

  Returns:
    g: Tensorflow graph object (Graph proto).
  """
  g = ops.Graph()
  with g.as_default():
    # An input test image with unknown spatial resolution.
    x = array_ops.placeholder(
        dtypes.float32, (None, None, None, 1), name='input_image')
    # Left branch before first addition.
    l1 = slim.conv2d(x, 1, [1, 1], stride=4, scope='L1', padding='VALID')
    # Right branch before first addition.
    l2_pad = array_ops.pad(x, [[0, 0], [1, 0], [1, 0], [0, 0]])
    l2 = slim.conv2d(l2_pad, 1, [3, 3], stride=2, scope='L2', padding='VALID')
    l3 = slim.conv2d(l2, 1, [1, 1], stride=2, scope='L3', padding='VALID')
    # First addition.
    l4 = nn.relu(l1 + l3)
    # Left branch after first addition.
    l5 = slim.conv2d(l4, 1, [1, 1], stride=2, scope='L5', padding='VALID')
    # Right branch after first addition.
    l6_pad = array_ops.pad(l4, [[0, 0], [1, 0], [1, 0], [0, 0]])
    l6 = slim.conv2d(l6_pad, 1, [3, 3], stride=2, scope='L6', padding='VALID')
    # Final addition.
    nn.relu(l5 + l6, name='output')

  return g
Esempio n. 2
0
 def testPaddingsDim2(self):
   with self.session(use_gpu=True):
     with self.assertRaises(ValueError):
       array_ops.pad(array_ops.reshape(
           [1, 2], shape=[1, 2]),
                     array_ops.reshape(
                         [1, 2], shape=[2, 1]))
Esempio n. 3
0
  def get_observation_model(self, times):
    """Construct observation model matrix from VARMA parameters.

    Args:
      times: A [batch size] vector indicating the times observation models are
          requested for. Unused.
    Returns:
      the observation model matrix. It has shape
        [self.num_features, self.state_dimension].
    """
    del times  # StateSpaceModel will broadcast along the batch dimension
    if self.ar_order > self.ma_order or self.state_num_blocks < 2:
      return array_ops.pad(
          linalg_ops.eye(self.num_features, dtype=self.dtype),
          [[0, 0], [0, self.num_features * (self.state_num_blocks - 1)]],
          name="observation_model")
    else:
      # Add a second observed component which "catches" the accumulated moving
      # average errors as they reach the end of the state. If ar_order >
      # ma_order, this is unnecessary, since accumulated errors cycle naturally.
      return array_ops.concat(
          [
              array_ops.pad(
                  linalg_ops.eye(self.num_features, dtype=self.dtype),
                  [[0, 0], [0,
                            self.num_features * (self.state_num_blocks - 2)]]),
              linalg_ops.eye(self.num_features, dtype=self.dtype)
          ],
          axis=1,
          name="observation_model")
Esempio n. 4
0
 def testInputDims(self):
   with self.test_session(use_gpu=True):
     with self.assertRaises(ValueError):
       array_ops.pad(array_ops.reshape(
           [1, 2], shape=[1, 2, 1, 1, 1, 1]),
                     array_ops.reshape(
                         [1, 2], shape=[1, 2]))
Esempio n. 5
0
 def testPaddingsDim4(self):
   with self.test_session(use_gpu=True):
     with self.assertRaises(ValueError):
       array_ops.pad(array_ops.reshape(
           [1, 2], shape=[1, 2]),
                     array_ops.reshape(
                         [1, 2, 3, 4, 5, 6], shape=[3, 2]))
Esempio n. 6
0
 def testPaddingsNonNegative2(self):
   with self.test_session(use_gpu=True):
     with self.assertRaisesRegexp(ValueError, "must be non-negative"):
       array_ops.pad(constant_op.constant(
           [1], shape=[1]),
                     constant_op.constant(
                         [-1, 0], shape=[1, 2]))
  def _makeTridiagonalMatrix(self, superdiag, maindiag, subdiag):
    super_pad = [[0, 0], [0, 1], [1, 0]]
    sub_pad = [[0, 0], [1, 0], [0, 1]]

    super_part = array_ops.pad(array_ops.matrix_diag(superdiag), super_pad)
    main_part = array_ops.matrix_diag(maindiag)
    sub_part = array_ops.pad(array_ops.matrix_diag(subdiag), sub_pad)
    return super_part + main_part + sub_part
 def baseline(self, upper, diag, lower, vec):
   diag_part = array_ops.expand_dims(diag, -1) * vec
   lower_part = array_ops.pad(
       array_ops.expand_dims(lower[:, 1:], -1) * vec[:, :-1, :],
       [[0, 0], [1, 0], [0, 0]])
   upper_part = array_ops.pad(
       array_ops.expand_dims(upper[:, :-1], -1) * vec[:, 1:, :],
       [[0, 0], [0, 1], [0, 0]])
   return lower_part + diag_part + upper_part
Esempio n. 9
0
 def testPaddingsMaximum(self):
     with self.test_session(use_gpu=True):
         with self.assertRaises(Exception):
             array_ops.pad(
                 constant_op.constant([1], shape=[2]), constant_op.constant([2, 0], shape=[1, 2]), mode="REFLECT"
             ).eval()
         with self.assertRaises(Exception):
             array_ops.pad(
                 constant_op.constant([1], shape=[2]), constant_op.constant([0, 3], shape=[1, 2]), mode="SYMMETRIC"
             ).eval()
Esempio n. 10
0
  def testShapeFunctionEdgeCases(self):
    # Unknown paddings shape.
    inp = constant_op.constant(0.0, shape=[4, 4, 4, 4])
    padded = array_ops.pad(inp, array_ops.placeholder(dtypes.int32))
    self.assertEqual([None, None, None, None], padded.get_shape().as_list())

    # Unknown input shape.
    inp = array_ops.placeholder(dtypes.float32)
    padded = array_ops.pad(inp, [[2, 2], [2, 2]])
    self.assertEqual([None, None], padded.get_shape().as_list())

    # Unknown input and paddings shape.
    inp = array_ops.placeholder(dtypes.float32)
    padded = array_ops.pad(inp, array_ops.placeholder(dtypes.int32))
    self.assertAllEqual(None, padded.get_shape().ndims)
def create_test_network():
  """Convolutional neural network for test.

  Returns:
    g: Tensorflow graph object (Graph proto).
  """
  g = ops.Graph()
  with g.as_default():
    # An input test image with unknown spatial resolution.
    x = array_ops.placeholder(
        dtypes.float32, (None, None, None, 1), name='input_image')
    # Left branch before first addition.
    l1 = slim.conv2d(x, 1, [1, 1], stride=4, scope='L1', padding='VALID')
    # Right branch before first addition.
    l2_pad = array_ops.pad(x, [[0, 0], [1, 0], [1, 0], [0, 0]], name='L2_pad')
    l2 = slim.conv2d(l2_pad, 1, [3, 3], stride=2, scope='L2', padding='VALID')
    l3 = slim.max_pool2d(l2, [3, 3], stride=2, scope='L3', padding='SAME')
    # First addition.
    l4 = nn.relu(l1 + l3, name='L4_relu')
    # Left branch after first addition.
    l5 = slim.conv2d(l4, 1, [1, 1], stride=2, scope='L5', padding='SAME')
    # Right branch after first addition.
    l6 = slim.conv2d(l4, 1, [3, 3], stride=2, scope='L6', padding='SAME')
    # Final addition.
    gen_math_ops.add(l5, l6, name='L7_add')

  return g
Esempio n. 12
0
 def testCollapseAdjacentNonPaddedDimensions(self):
   # pyformat: disable
   paddings_values = [[[0, 0], [0, 0], [0, 0], [0, 1]],
                      [[0, 0], [2, 3], [0, 0], [0, 0]],
                      [[0, 0], [0, 0], [0, 0], [0, 0]]]
   # pyformat: enable
   for paddings_value in paddings_values:
     for dtype in [dtypes.float32, dtypes.int32]:
       inp = constant_op.constant(1, shape=[8, 28, 28, 3], dtype=dtype)
       paddings = constant_op.constant(paddings_value, dtype=dtypes.int32)
       padded = array_ops.pad(inp, paddings)
       middle = array_ops.slice(padded, [row[0] for row in paddings_value],
                                [dim.value for dim in inp.shape.dims])
       left = array_ops.slice(padded, [0, 0, 0, 0],
                              [row[0] for row in paddings_value])
       right = array_ops.slice(
           padded,
           [paddings_value[i][0] + inp.shape.dims[i].value for i in range(4)],
           [-1, -1, -1, -1])
       with self.test_session(use_gpu=True):
         self.assertAllEqual(inp.eval(), middle.eval())
         self.assertAllEqual(
             np.zeros([row[0] for row in paddings_value]), left.eval())
         self.assertAllEqual(
             np.zeros([row[1] for row in paddings_value]), right.eval())
Esempio n. 13
0
def frames(signal, frame_length, frame_step, name=None):
  """Frame a signal into overlapping frames.

  May be used in front of spectral functions.

  For example:

  ```python
  pcm = tf.placeholder(tf.float32, [None, 9152])
  frames = tf.contrib.signal.frames(pcm, 512, 180)
  magspec = tf.abs(tf.spectral.rfft(frames, [512]))
  image = tf.expand_dims(magspec, 3)
  ```

  Args:
    signal: A `Tensor` of shape `[batch_size, signal_length]`.
    frame_length: An `int32` or `int64` `Tensor`. The length of each frame.
    frame_step: An `int32` or `int64` `Tensor`. The step between frames.
    name: A name for the operation (optional).

  Returns:
    A `Tensor` of frames with shape `[batch_size, num_frames, frame_length]`.

  Raises:
    ValueError: if signal does not have rank 2.
  """
  with ops.name_scope(name, "frames", [signal, frame_length, frame_step]):
    signal = ops.convert_to_tensor(signal, name="signal")
    frame_length = ops.convert_to_tensor(frame_length, name="frame_length")
    frame_step = ops.convert_to_tensor(frame_step, name="frame_step")

    signal_rank = signal.shape.ndims

    if signal_rank != 2:
      raise ValueError("expected signal to have rank 2 but was " + signal_rank)

    signal_length = array_ops.shape(signal)[1]

    num_frames = math_ops.ceil((signal_length - frame_length) / frame_step)
    num_frames = 1 + math_ops.cast(num_frames, dtypes.int32)

    pad_length = (num_frames - 1) * frame_step + frame_length
    pad_signal = array_ops.pad(signal, [[0, 0], [0,
                                                 pad_length - signal_length]])

    indices_frame = array_ops.expand_dims(math_ops.range(frame_length), 0)
    indices_frames = array_ops.tile(indices_frame, [num_frames, 1])

    indices_step = array_ops.expand_dims(
        math_ops.range(num_frames) * frame_step, 1)
    indices_steps = array_ops.tile(indices_step, [1, frame_length])

    indices = indices_frames + indices_steps

    # TODO(androbin): remove `transpose` when `gather` gets `axis` support
    pad_signal = array_ops.transpose(pad_signal)
    signal_frames = array_ops.gather(pad_signal, indices)
    signal_frames = array_ops.transpose(signal_frames, perm=[2, 0, 1])

    return signal_frames
Esempio n. 14
0
def create_test_network_7():
  """Aligned network for test, with a control dependency.

  The graph is similar to create_test_network_1(), except that it includes an
  assert operation on the left branch.

  Returns:
    g: Tensorflow graph object (Graph proto).
  """
  g = ops.Graph()
  with g.as_default():
    # An 8x8 test image.
    x = array_ops.placeholder(dtypes.float32, (1, 8, 8, 1), name='input_image')
    # Left branch.
    l1 = slim.conv2d(x, 1, [1, 1], stride=4, scope='L1', padding='VALID')
    l1_shape = array_ops.shape(l1)
    assert_op = control_flow_ops.Assert(
        gen_math_ops.equal(l1_shape[1], 2), [l1_shape], summarize=4)
    # Right branch.
    l2_pad = array_ops.pad(x, [[0, 0], [1, 0], [1, 0], [0, 0]])
    l2 = slim.conv2d(l2_pad, 1, [3, 3], stride=2, scope='L2', padding='VALID')
    l3 = slim.conv2d(l2, 1, [1, 1], stride=2, scope='L3', padding='VALID')
    # Addition.
    with ops.control_dependencies([assert_op]):
      nn.relu(l1 + l3, name='output')
  return g
Esempio n. 15
0
def create_test_network_2():
  """Aligned network for test.

  The graph corresponds to a variation to the example from the second figure in
  go/cnn-rf-computation#arbitrary-computation-graphs. Layers 2 and 3 are changed
  to max-pooling operations. Since the functionality is the same as convolution,
  the network is aligned and the receptive field size is the same as from the
  network created using create_test_network_1().

  Returns:
    g: Tensorflow graph object (Graph proto).
  """
  g = ops.Graph()
  with g.as_default():
    # An input test image with unknown spatial resolution.
    x = array_ops.placeholder(
        dtypes.float32, (None, None, None, 1), name='input_image')
    # Left branch.
    l1 = slim.conv2d(x, 1, [1, 1], stride=4, scope='L1', padding='VALID')
    # Right branch.
    l2_pad = array_ops.pad(x, [[0, 0], [1, 0], [1, 0], [0, 0]])
    l2 = slim.max_pool2d(l2_pad, [3, 3], stride=2, scope='L2', padding='VALID')
    l3 = slim.max_pool2d(l2, [1, 1], stride=2, scope='L3', padding='VALID')
    # Addition.
    nn.relu(l1 + l3, name='output')
  return g
  def testPadWithConstPaddings(self):
    if test.is_gpu_available(cuda_only=True):
      random_seed.set_random_seed(0)
      x = random_ops.truncated_normal([1, 784], seed=0)
      conv = _two_layer_model(x)
      paddings_val = [[1, 2], [3, 4], [5, 6], [7, 8]]
      paddings = constant_op.constant(
          paddings_val, dtype='int32', name='PaddingsConst')
      pad = array_ops.pad(conv, paddings)
      output = array_ops.identity(pad)

      with session.Session() as sess:
        output_val_ref = sess.run(output)

      with session.Session(config=_get_config()) as sess:
        metadata = config_pb2.RunMetadata()
        output_val = sess.run(output, run_metadata=metadata)

      nodes = []
      num_transposes = 0
      for node in metadata.cost_graph.node:
        if node.name.startswith('LayoutOptimizerTranspose'):
          num_transposes += 1
        nodes.append(node.name)

      # Four transposes were initially added in the Expand phase of
      # LayoutOptimizer; two of them are cancelled out in the Collapse phase.
      expected_num_transposes = 2
      self.assertEqual(expected_num_transposes, num_transposes)
      self.assertIn('LayoutOptimizerTransposeNHWCToNCHW-Conv2D-0', nodes)
      self.assertIn('LayoutOptimizerTransposeNCHWToNHWC-Pad-0-0', nodes)
      self.assertIn('LayoutOptimizer-Pad-PaddingsConst', nodes)
      self.assertAllClose(output_val_ref, output_val, atol=1e-3)
Esempio n. 17
0
 def _testPad(self, np_inputs, paddings, mode):
     np_val = self._npPad(np_inputs, paddings, mode=mode)
     with self.test_session(use_gpu=True):
         tf_val = array_ops.pad(np_inputs, paddings, mode=mode)
         out = tf_val.eval()
     self.assertAllEqual(np_val, out)
     self.assertShapeEqual(np_val, tf_val)
Esempio n. 18
0
def _build_multilabel_adjacency(sparse_labels):
  """Builds multilabel adjacency matrix.

  As of March 14th, 2017, there's no op for the dot product between
  two sparse tensors in TF. However, there is `sparse_minimum` op which is
  equivalent to an AND op between two sparse boolean tensors.
  This computes the dot product between two sparse boolean inputs.

  Args:
    sparse_labels: List of 1-D boolean sparse tensors.

  Returns:
    adjacency_matrix: 2-D dense `Tensor`.
  """
  num_pairs = len(sparse_labels)
  adjacency_matrix = array_ops.zeros([num_pairs, num_pairs])
  for i in range(num_pairs):
    for j in range(num_pairs):
      sparse_dot_product = math_ops.to_float(
          sparse_ops.sparse_reduce_sum(sparse_ops.sparse_minimum(
              sparse_labels[i], sparse_labels[j])))
      sparse_dot_product = array_ops.expand_dims(sparse_dot_product, 0)
      sparse_dot_product = array_ops.expand_dims(sparse_dot_product, 1)
      one_hot_matrix = array_ops.pad(sparse_dot_product,
                                     [[i, num_pairs-i-1],
                                      [j, num_pairs-j-1]], 'CONSTANT')
      adjacency_matrix += one_hot_matrix

  return adjacency_matrix
Esempio n. 19
0
def conv2d_same(inputs, num_outputs, kernel_size, stride, rate=1, scope=None):
  """Strided 2-D convolution with 'SAME' padding.

  When stride > 1, then we do explicit zero-padding, followed by conv2d with
  'VALID' padding.

  Note that

     net = conv2d_same(inputs, num_outputs, 3, stride=stride)

  is equivalent to

     net = tf.contrib.layers.conv2d(inputs, num_outputs, 3, stride=1,
     padding='SAME')
     net = subsample(net, factor=stride)

  whereas

     net = tf.contrib.layers.conv2d(inputs, num_outputs, 3, stride=stride,
     padding='SAME')

  is different when the input's height or width is even, which is why we add the
  current function. For more details, see ResnetUtilsTest.testConv2DSameEven().

  Args:
    inputs: A 4-D tensor of size [batch, height_in, width_in, channels].
    num_outputs: An integer, the number of output filters.
    kernel_size: An int with the kernel_size of the filters.
    stride: An integer, the output stride.
    rate: An integer, rate for atrous convolution.
    scope: Scope.

  Returns:
    output: A 4-D tensor of size [batch, height_out, width_out, channels] with
      the convolution output.
  """
  if stride == 1:
    return layers_lib.conv2d(
        inputs,
        num_outputs,
        kernel_size,
        stride=1,
        rate=rate,
        padding='SAME',
        scope=scope)
  else:
    kernel_size_effective = kernel_size + (kernel_size - 1) * (rate - 1)
    pad_total = kernel_size_effective - 1
    pad_beg = pad_total // 2
    pad_end = pad_total - pad_beg
    inputs = array_ops.pad(
        inputs, [[0, 0], [pad_beg, pad_end], [pad_beg, pad_end], [0, 0]])
    return layers_lib.conv2d(
        inputs,
        num_outputs,
        kernel_size,
        stride=stride,
        rate=rate,
        padding='VALID',
        scope=scope)
def create_test_network():
  """Convolutional neural network for test.

  Returns:
    name_to_node: Dict keyed by node name, each entry containing the node's
      NodeDef.
  """
  g = ops.Graph()
  with g.as_default():
    # An input test image with unknown spatial resolution.
    x = array_ops.placeholder(
        dtypes.float32, (None, None, None, 1), name='input_image')
    # Left branch before first addition.
    l1 = slim.conv2d(x, 1, [1, 1], stride=4, scope='L1', padding='VALID')
    # Right branch before first addition.
    l2_pad = array_ops.pad(x, [[0, 0], [1, 0], [1, 0], [0, 0]], name='L2_pad')
    l2 = slim.conv2d(l2_pad, 1, [3, 3], stride=2, scope='L2', padding='VALID')
    l3 = slim.max_pool2d(l2, [3, 3], stride=2, scope='L3', padding='SAME')
    # First addition.
    l4 = nn.relu(l1 + l3, name='L4_relu')
    # Left branch after first addition.
    l5 = slim.conv2d(l4, 1, [1, 1], stride=2, scope='L5', padding='SAME')
    # Right branch after first addition.
    l6 = slim.conv2d(l4, 1, [3, 3], stride=2, scope='L6', padding='SAME')
    # Final addition.
    gen_math_ops.add(l5, l6, name='L7_add')

  name_to_node = graph_compute_order.parse_graph_nodes(g.as_graph_def())
  return name_to_node
  def testFusePadAndConv(self):
    with self.cached_session() as sess:
      inputs = [1, 4, 2, 5, 3, 6, -1, -4, -2, -5, -3, -6]
      input_op = constant_op.constant(
          np.array(inputs), shape=[1, 2, 3, 2], dtype=dtypes.float32)
      pad_op = array_ops.pad(input_op, [[0, 0], [1, 1], [2, 2], [0, 0]],
                             mode="REFLECT")
      weights = [1, 2, 3, 4, 0.1, 0.2, 0.3, 0.4]
      weights_op = constant_op.constant(
          np.array(weights), shape=[1, 2, 2, 2], dtype=dtypes.float32)
      nn_ops.conv2d(
          pad_op, weights_op, [1, 1, 1, 1], padding="VALID", name="output")
      original_graph_def = sess.graph_def
      original_result = sess.run(["output:0"])
    optimized_graph_def = optimize_for_inference_lib.fuse_resize_and_conv(
        original_graph_def, ["output"])

    with self.cached_session() as sess:
      _ = importer.import_graph_def(
          optimized_graph_def, input_map={}, name="optimized")
      optimized_result = sess.run(["optimized/output:0"])

    self.assertAllClose(original_result, optimized_result)

    for node in optimized_graph_def.node:
      self.assertNotEqual("Conv2D", node.op)
      self.assertNotEqual("ResizeBilinear", node.op)
  def pack_uint8_r2_to_uint32(self, test_input):
    num_rows, num_columns = test_input.get_shape().as_list()
    num_output_columns = int(math.ceil(num_columns / 4.0))
    padding_input = array_ops.pad(
        math_ops.cast(test_input, dtype=dtypes.uint8),
        constant_op.constant([[
            0,
            0,
        ], [0, num_output_columns * 4 - num_columns]]))
    output = array_ops.zeros([num_rows, num_output_columns],
                             dtype=dtypes.uint32)
    num_elements_per_pack = 4
    shift_bits = 8

    iota_r1 = math_ops.range(num_output_columns * num_elements_per_pack)

    for p in range(num_elements_per_pack):
      selected_index = math_ops.equal(
          math_ops.mod(iota_r1, num_elements_per_pack), p)
      gather_index = array_ops.boolean_mask(iota_r1, selected_index)
      gathered_input = array_ops.gather(padding_input, gather_index, axis=1)
      total_shift_bits = shift_bits * (num_elements_per_pack - p - 1)
      left_shift_input = bitwise_ops.left_shift(
          math_ops.cast(gathered_input, dtype=dtypes.uint32), total_shift_bits)
      output = bitwise_ops.bitwise_or(output, left_shift_input)
    return output
Esempio n. 23
0
  def inverse_stft_window_fn_inner(frame_length, dtype):
    """Computes a window that can be used in `inverse_stft`.

    Args:
      frame_length: An integer scalar `Tensor`. The window length in samples.
      dtype: Data type of waveform passed to `stft`.

    Returns:
      A window suitable for reconstructing original waveform in `inverse_stft`.

    Raises:
      ValueError: If `frame_length` is not scalar, `forward_window_fn` is not a
      callable that takes a window length and a `dtype` keyword argument and
      returns a `[window_length]` `Tensor` of samples in the provided datatype
      `frame_step` is not scalar, or `frame_step` is not scalar.
    """
    with ops.name_scope(name, 'inverse_stft_window_fn', [forward_window_fn]):
      frame_length = ops.convert_to_tensor(frame_length, name='frame_length')
      frame_length.shape.assert_has_rank(0)

      # Use equation 7 from Griffin + Lim.
      forward_window = forward_window_fn(frame_length, dtype=dtype)
      denom = math_ops.square(forward_window)
      overlaps = -(-frame_length // frame_step)  # Ceiling division.
      denom = array_ops.pad(denom, [(0, overlaps * frame_step - frame_length)])
      denom = array_ops.reshape(denom, [overlaps, frame_step])
      denom = math_ops.reduce_sum(denom, 0, keep_dims=True)
      denom = array_ops.tile(denom, [overlaps, 1])
      denom = array_ops.reshape(denom, [overlaps * frame_step])

      return forward_window / denom[:frame_length]
  def testPadWithNonConstPaddings(self):
    if test.is_gpu_available(cuda_only=True):
      random_seed.set_random_seed(0)
      x = random_ops.truncated_normal([1, 784], seed=0)
      conv = _two_layer_model(x)
      paddings = array_ops.placeholder(dtype='int32')
      pad = array_ops.pad(conv, paddings)
      output = array_ops.identity(pad)

      paddings_val = [[1, 2], [3, 4], [5, 6], [7, 8]]
      with session.Session() as sess:
        output_val_ref = sess.run(output, feed_dict={paddings: paddings_val})

      with session.Session(config=_get_config()) as sess:
        metadata = config_pb2.RunMetadata()
        output_val = sess.run(
            output, run_metadata=metadata, feed_dict={
                paddings: paddings_val
            })

      nodes = []
      num_transposes = 0
      for node in metadata.cost_graph.node:
        if _is_transpose(node.name):
          num_transposes += 1
        nodes.append(node.name)

      # Four transposes were initially added in the Expand phase of
      # LayoutOptimizer; two of them are cancelled out in the Collapse phase.
      expected_num_transposes = 2
      self.assertEqual(expected_num_transposes, num_transposes)
      self._assert_trans_nhwc_to_nchw('Conv2D-0', nodes)
      self._assert_trans_nchw_to_nhwc('Pad-0-0', nodes)
      self._assert_vec_nhwc_to_nchw('Pad-1', nodes)
      self.assertAllClose(output_val_ref, output_val, atol=1e-3)
Esempio n. 25
0
def insert_slice_in_zeros(slice_to_insert, dim, dim_size, position):
  """Inserts slice into a larger tensor of zeros.

  Forms a new tensor which is the same shape as slice_to_insert, except that
  the dimension given by 'dim' is expanded to the size given by 'dim_size'.
  'position' determines the position (index) at which to insert the slice within
  that dimension.

  Assumes slice_to_insert.shape[dim] = 1.

  Args:
    slice_to_insert: The slice to insert.
    dim: The dimension which to expand with zeros.
    dim_size: The new size of the 'dim' dimension.
    position: The position of 'slice_to_insert' in the new tensor.

  Returns:
    The new tensor.

  Raises:
    ValueError: If the slice's shape at the given dim is not 1.
  """
  slice_shape = slice_to_insert.shape
  if slice_shape[dim] != 1:
    raise ValueError("Expected slice_to_insert.shape to have {} dim of 1, but "
                     "was {}".format(dim, slice_to_insert.shape[dim]))

  before = [0] * int(len(slice_shape))
  after = before[:]
  before[dim] = position
  after[dim] = dim_size - position - 1

  return array_ops.pad(slice_to_insert, list(zip(before, after)))
Esempio n. 26
0
  def _forward(self, x):
    # Pad the last dim with a zeros vector. We need this because it lets us
    # infer the scale in the inverse function.
    y = array_ops.expand_dims(x, dim=-1) if self._static_event_ndims == 0 else x
    ndims = (y.get_shape().ndims if y.get_shape().ndims is not None
             else array_ops.rank(y))
    y = array_ops.pad(y,
                      paddings=array_ops.concat(
                          (array_ops.zeros(
                              (ndims - 1, 2), dtype=dtypes.int32), [[0, 1]]),
                          0))

    # Set shape hints.
    if x.get_shape().ndims is not None:
      shape = x.get_shape().as_list()
      if self._static_event_ndims == 0:
        shape += [2]
      elif shape[-1] is not None:
        shape[-1] += 1
      shape = tensor_shape.TensorShape(shape)
      y.get_shape().assert_is_compatible_with(shape)
      y.set_shape(shape)

    # Since we only support event_ndims in [0, 1] and we do padding, we always
    # reduce over the last dimension, i.e., dim=-1 (which is the default).
    return nn_ops.softmax(y)
Esempio n. 27
0
  def testPad(self):
    for dtype in self.numeric_types:
      self._testBinary(
          array_ops.pad,
          np.array(
              [[1, 2, 3], [4, 5, 6]], dtype=dtype),
          np.array(
              [[1, 2], [2, 1]], dtype=np.int32),
          expected=np.array(
              [[0, 0, 0, 0, 0, 0],
               [0, 0, 1, 2, 3, 0],
               [0, 0, 4, 5, 6, 0],
               [0, 0, 0, 0, 0, 0],
               [0, 0, 0, 0, 0, 0]],
              dtype=dtype))

      self._testBinary(
          lambda x, y: array_ops.pad(x, y, constant_values=7),
          np.array(
              [[1, 2, 3], [4, 5, 6]], dtype=dtype),
          np.array(
              [[0, 3], [2, 1]], dtype=np.int32),
          expected=np.array(
              [[7, 7, 1, 2, 3, 7],
               [7, 7, 4, 5, 6, 7],
               [7, 7, 7, 7, 7, 7],
               [7, 7, 7, 7, 7, 7],
               [7, 7, 7, 7, 7, 7]],
              dtype=dtype))
Esempio n. 28
0
 def get_noise_transform(self):
   # transition_power_noise_accumulator makes assumptions about this
   # transformation. If the noise transform is modified or overriden,
   # transition_power_noise_accumulator must be modified as well (or discarded,
   # as it is simply an optimization).
   return array_ops.pad(
       array_ops.ones([1], dtype=self.dtype),
       paddings=[(0, self._periodicity - 2)])[..., None]
Esempio n. 29
0
def _maybe_pad_for_rfft(input_tensor, fft_rank, fft_length, is_reverse=False):
  """Pads `input_tensor` to `fft_length` on its inner-most `fft_rank` dims."""
  fft_shape = _tensor_util.constant_value_as_shape(fft_length)

  # Edge case: skip padding empty tensors.
  if (input_tensor.shape.ndims is not None and
      any(dim.value == 0 for dim in input_tensor.shape.dims)):
    return input_tensor

  # If we know the shapes ahead of time, we can either skip or pre-compute the
  # appropriate paddings. Otherwise, fall back to computing paddings in
  # TensorFlow.
  if fft_shape.is_fully_defined() and input_tensor.shape.ndims is not None:
    # Slice the last FFT-rank dimensions from input_tensor's shape.
    input_fft_shape = input_tensor.shape[-fft_shape.ndims:]

    if input_fft_shape.is_fully_defined():
      # In reverse, we only pad the inner-most dimension to fft_length / 2 + 1.
      if is_reverse:
        fft_shape = fft_shape[:-1].concatenate(
            fft_shape.dims[-1].value // 2 + 1)

      paddings = [[0, max(fft_dim.value - input_dim.value, 0)]
                  for fft_dim, input_dim in zip(
                      fft_shape.dims, input_fft_shape.dims)]
      if any(pad > 0 for _, pad in paddings):
        outer_paddings = [[0, 0]] * max((input_tensor.shape.ndims -
                                         fft_shape.ndims), 0)
        return _array_ops.pad(input_tensor, outer_paddings + paddings)
      return input_tensor

  # If we can't determine the paddings ahead of time, then we have to pad. If
  # the paddings end up as zero, tf.pad has a special-case that does no work.
  input_rank = _array_ops.rank(input_tensor)
  input_fft_shape = _array_ops.shape(input_tensor)[-fft_rank:]
  outer_dims = _math_ops.maximum(0, input_rank - fft_rank)
  outer_paddings = _array_ops.zeros([outer_dims], fft_length.dtype)
  # In reverse, we only pad the inner-most dimension to fft_length / 2 + 1.
  if is_reverse:
    fft_length = _array_ops.concat([fft_length[:-1],
                                    fft_length[-1:] // 2 + 1], 0)
  fft_paddings = _math_ops.maximum(0, fft_length - input_fft_shape)
  paddings = _array_ops.concat([outer_paddings, fft_paddings], 0)
  paddings = _array_ops.stack([_array_ops.zeros_like(paddings), paddings],
                              axis=1)
  return _array_ops.pad(input_tensor, paddings)
Esempio n. 30
0
 def testScalars(self):
   paddings = np.zeros((0, 2), dtype=np.int32)
   inp = np.asarray(7)
   with self.test_session(use_gpu=True):
     tf_val = array_ops.pad(inp, paddings)
     out = tf_val.eval()
   self.assertAllEqual(inp, out)
   self.assertShapeEqual(inp, tf_val)
Esempio n. 31
0
 def _unique(x):
   u = array_ops.unique(x)
   y = array_ops.pad(u.y, [[0, _get_dim(u.idx, 0) - _get_dim(u.y, 0)]])
   y = math_ops.cast(y, dtypes.int64)
   return [y, u.idx]
Esempio n. 32
0
def linear_to_mel_weight_matrix(num_mel_bins=20,
                                num_spectrogram_bins=129,
                                sample_rate=8000,
                                lower_edge_hertz=125.0,
                                upper_edge_hertz=3800.0,
                                dtype=dtypes.float32,
                                name=None):
    r"""Returns a matrix to warp linear scale spectrograms to the [mel scale][mel].

  Returns a weight matrix that can be used to re-weight a `Tensor` containing
  `num_spectrogram_bins` linearly sampled frequency information from
  `[0, sample_rate / 2]` into `num_mel_bins` frequency information from
  `[lower_edge_hertz, upper_edge_hertz]` on the [mel scale][mel].

  This function follows the [Hidden Markov Model Toolkit
  (HTK)](http://htk.eng.cam.ac.uk/) convention, defining the mel scale in
  terms of a frequency in hertz according to the following formula:

      $$\textrm{mel}(f) = 2595 * \textrm{log}_{10}(1 + \frac{f}{700})$$

  In the returned matrix, all the triangles (filterbanks) have a peak value
  of 1.0.

  For example, the returned matrix `A` can be used to right-multiply a
  spectrogram `S` of shape `[frames, num_spectrogram_bins]` of linear
  scale spectrum values (e.g. STFT magnitudes) to generate a "mel spectrogram"
  `M` of shape `[frames, num_mel_bins]`.

      # `S` has shape [frames, num_spectrogram_bins]
      # `M` has shape [frames, num_mel_bins]
      M = tf.matmul(S, A)

  The matrix can be used with `tf.tensordot` to convert an arbitrary rank
  `Tensor` of linear-scale spectral bins into the mel scale.

      # S has shape [..., num_spectrogram_bins].
      # M has shape [..., num_mel_bins].
      M = tf.tensordot(S, A, 1)

  Args:
    num_mel_bins: Python int. How many bands in the resulting mel spectrum.
    num_spectrogram_bins: An integer `Tensor`. How many bins there are in the
      source spectrogram data, which is understood to be `fft_size // 2 + 1`,
      i.e. the spectrogram only contains the nonredundant FFT bins.
    sample_rate: An integer or float `Tensor`. Samples per second of the input
      signal used to create the spectrogram. Used to figure out the frequencies
      corresponding to each spectrogram bin, which dictates how they are mapped
      into the mel scale.
    lower_edge_hertz: Python float. Lower bound on the frequencies to be
      included in the mel spectrum. This corresponds to the lower edge of the
      lowest triangular band.
    upper_edge_hertz: Python float. The desired top edge of the highest
      frequency band.
    dtype: The `DType` of the result matrix. Must be a floating point type.
    name: An optional name for the operation.

  Returns:
    A `Tensor` of shape `[num_spectrogram_bins, num_mel_bins]`.

  Raises:
    ValueError: If `num_mel_bins`/`num_spectrogram_bins`/`sample_rate` are not
      positive, `lower_edge_hertz` is negative, frequency edges are incorrectly
      ordered, `upper_edge_hertz` is larger than the Nyquist frequency.

  [mel]: https://en.wikipedia.org/wiki/Mel_scale
  """
    with ops.name_scope(name, 'linear_to_mel_weight_matrix') as name:
        # Convert Tensor `sample_rate` to float, if possible.
        if isinstance(sample_rate, ops.Tensor):
            maybe_const_val = tensor_util.constant_value(sample_rate)
            if maybe_const_val is not None:
                sample_rate = maybe_const_val

        # Note: As num_spectrogram_bins is passed to `math_ops.linspace`
        # and the validation is already done in linspace (both in shape function
        # and in kernel), there is no need to validate num_spectrogram_bins here.
        _validate_arguments(num_mel_bins, sample_rate, lower_edge_hertz,
                            upper_edge_hertz, dtype)

        # This function can be constant folded by graph optimization since there are
        # no Tensor inputs.
        sample_rate = math_ops.cast(sample_rate, dtype, name='sample_rate')
        lower_edge_hertz = ops.convert_to_tensor(lower_edge_hertz,
                                                 dtype,
                                                 name='lower_edge_hertz')
        upper_edge_hertz = ops.convert_to_tensor(upper_edge_hertz,
                                                 dtype,
                                                 name='upper_edge_hertz')
        zero = ops.convert_to_tensor(0.0, dtype)

        # HTK excludes the spectrogram DC bin.
        bands_to_zero = 1
        nyquist_hertz = sample_rate / 2.0
        linear_frequencies = math_ops.linspace(
            zero, nyquist_hertz, num_spectrogram_bins)[bands_to_zero:]
        spectrogram_bins_mel = array_ops.expand_dims(
            _hertz_to_mel(linear_frequencies), 1)

        # Compute num_mel_bins triples of (lower_edge, center, upper_edge). The
        # center of each band is the lower and upper edge of the adjacent bands.
        # Accordingly, we divide [lower_edge_hertz, upper_edge_hertz] into
        # num_mel_bins + 2 pieces.
        band_edges_mel = shape_ops.frame(math_ops.linspace(
            _hertz_to_mel(lower_edge_hertz), _hertz_to_mel(upper_edge_hertz),
            num_mel_bins + 2),
                                         frame_length=3,
                                         frame_step=1)

        # Split the triples up and reshape them into [1, num_mel_bins] tensors.
        lower_edge_mel, center_mel, upper_edge_mel = tuple(
            array_ops.reshape(t, [1, num_mel_bins])
            for t in array_ops.split(band_edges_mel, 3, axis=1))

        # Calculate lower and upper slopes for every spectrogram bin.
        # Line segments are linear in the mel domain, not Hertz.
        lower_slopes = (spectrogram_bins_mel -
                        lower_edge_mel) / (center_mel - lower_edge_mel)
        upper_slopes = (upper_edge_mel -
                        spectrogram_bins_mel) / (upper_edge_mel - center_mel)

        # Intersect the line segments with each other and zero.
        mel_weights_matrix = math_ops.maximum(
            zero, math_ops.minimum(lower_slopes, upper_slopes))

        # Re-add the zeroed lower bins we sliced out above.
        return array_ops.pad(mel_weights_matrix, [[bands_to_zero, 0], [0, 0]],
                             name=name)
Esempio n. 33
0
 def loop_fn(i):
     x1 = array_ops.gather(x, i)
     return array_ops.pad(x1, padding, mode="CONSTANT")
Esempio n. 34
0
def dct(input, type=2, n=None, axis=-1, norm=None, name=None):  # pylint: disable=redefined-builtin
  """Computes the 1D [Discrete Cosine Transform (DCT)][dct] of `input`.

  Currently only Types II and III are supported. Type II is implemented using a
  length `2N` padded `tf.spectral.rfft`, as described here:
  https://dsp.stackexchange.com/a/10606. Type III is a fairly straightforward
  inverse of Type II (i.e. using a length `2N` padded `tf.spectral.irfft`).

  @compatibility(scipy)
  Equivalent to scipy.fftpack.dct for Type-II and Type-III DCT.
  https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.fftpack.dct.html
  @end_compatibility

  Args:
    input: A `[..., samples]` `float32` `Tensor` containing the signals to
      take the DCT of.
    type: The DCT type to perform. Must be 2 or 3.
    n: For future expansion. The length of the transform. Must be `None`.
    axis: For future expansion. The axis to compute the DCT along. Must be `-1`.
    norm: The normalization to apply. `None` for no normalization or `'ortho'`
      for orthonormal normalization.
    name: An optional name for the operation.

  Returns:
    A `[..., samples]` `float32` `Tensor` containing the DCT of `input`.

  Raises:
    ValueError: If `type` is not `2` or `3`, `n` is not `None, `axis` is not
      `-1`, or `norm` is not `None` or `'ortho'`.

  [dct]: https://en.wikipedia.org/wiki/Discrete_cosine_transform
  """
  _validate_dct_arguments(type, n, axis, norm)
  with _ops.name_scope(name, "dct", [input]):
    # We use the RFFT to compute the DCT and TensorFlow only supports float32
    # for FFTs at the moment.
    input = _ops.convert_to_tensor(input, dtype=_dtypes.float32)

    axis_dim = input.shape[-1].value or _array_ops.shape(input)[-1]
    axis_dim_float = _math_ops.to_float(axis_dim)
    if type == 2:
      scale = 2.0 * _math_ops.exp(
          _math_ops.complex(
              0.0, -_math_ops.range(axis_dim_float) * _math.pi * 0.5 /
              axis_dim_float))

      # TODO(rjryan): Benchmark performance and memory usage of the various
      # approaches to computing a DCT via the RFFT.
      dct2 = _math_ops.real(
          rfft(input, fft_length=[2 * axis_dim])[..., :axis_dim] * scale)

      if norm == "ortho":
        n1 = 0.5 * _math_ops.rsqrt(axis_dim_float)
        n2 = n1 * _math_ops.sqrt(2.0)
        # Use tf.pad to make a vector of [n1, n2, n2, n2, ...].
        weights = _array_ops.pad(
            _array_ops.expand_dims(n1, 0), [[0, axis_dim - 1]],
            constant_values=n2)
        dct2 *= weights

      return dct2

    elif type == 3:
      if norm == "ortho":
        n1 = _math_ops.sqrt(axis_dim_float)
        n2 = n1 * _math_ops.sqrt(0.5)
        # Use tf.pad to make a vector of [n1, n2, n2, n2, ...].
        weights = _array_ops.pad(
            _array_ops.expand_dims(n1, 0), [[0, axis_dim - 1]],
            constant_values=n2)
        input *= weights
      else:
        input *= axis_dim_float
      scale = 2.0 * _math_ops.exp(
          _math_ops.complex(
              0.0,
              _math_ops.range(axis_dim_float) * _math.pi * 0.5 /
              axis_dim_float))
      dct3 = _math_ops.real(
          irfft(
              scale * _math_ops.complex(input, 0.0),
              fft_length=[2 * axis_dim]))[..., :axis_dim]

      return dct3
Esempio n. 35
0
def frame(signal,
          frame_length,
          frame_step,
          pad_end=False,
          pad_value=0,
          axis=-1,
          name=None):
    """Expands `signal`'s `axis` dimension into frames of `frame_length`.

  Slides a window of size `frame_length` over `signal`'s `axis` dimension
  with a stride of `frame_step`, replacing the `axis` dimension with
  `[frames, frame_length]` frames.

  If `pad_end` is True, window positions that are past the end of the `axis`
  dimension are padded with `pad_value` until the window moves fully past the
  end of the dimension. Otherwise, only window positions that fully overlap the
  `axis` dimension are produced.

  For example:

  ```python
  pcm = tf.compat.v1.placeholder(tf.float32, [None, 9152])
  frames = tf.signal.frame(pcm, 512, 180)
  magspec = tf.abs(tf.signal.rfft(frames, [512]))
  image = tf.expand_dims(magspec, 3)
  ```

  Args:
    signal: A `[..., samples, ...]` `Tensor`. The rank and dimensions
      may be unknown. Rank must be at least 1.
    frame_length: The frame length in samples. An integer or scalar `Tensor`.
    frame_step: The frame hop size in samples. An integer or scalar `Tensor`.
    pad_end: Whether to pad the end of `signal` with `pad_value`.
    pad_value: An optional scalar `Tensor` to use where the input signal
      does not exist when `pad_end` is True.
    axis: A scalar integer `Tensor` indicating the axis to frame. Defaults to
      the last axis. Supports negative values for indexing from the end.
    name: An optional name for the operation.

  Returns:
    A `Tensor` of frames with shape `[..., frames, frame_length, ...]`.

  Raises:
    ValueError: If `frame_length`, `frame_step`, `pad_value`, or `axis` are not
      scalar.
  """
    with ops.name_scope(name, "frame",
                        [signal, frame_length, frame_step, pad_value]):
        signal = ops.convert_to_tensor(signal, name="signal")
        frame_length = ops.convert_to_tensor(frame_length, name="frame_length")
        frame_step = ops.convert_to_tensor(frame_step, name="frame_step")
        axis = ops.convert_to_tensor(axis, name="axis")

        signal.shape.with_rank_at_least(1)
        frame_length.shape.assert_has_rank(0)
        frame_step.shape.assert_has_rank(0)
        axis.shape.assert_has_rank(0)

        result_shape = _infer_frame_shape(signal, frame_length, frame_step,
                                          pad_end, axis)

        # Axis can be negative. Convert it to positive.
        signal_rank = array_ops.rank(signal)
        axis = math_ops.range(signal_rank)[axis]

        signal_shape = array_ops.shape(signal)
        outer_dimensions, length_samples, inner_dimensions = array_ops.split(
            signal_shape, [axis, 1, signal_rank - 1 - axis])
        length_samples = array_ops.reshape(length_samples, [])
        num_outer_dimensions = array_ops.size(outer_dimensions)
        num_inner_dimensions = array_ops.size(inner_dimensions)

        # If padding is requested, pad the input signal tensor with pad_value.
        if pad_end:
            pad_value = ops.convert_to_tensor(pad_value, signal.dtype)
            pad_value.shape.assert_has_rank(0)

            # Calculate number of frames, using double negatives to round up.
            num_frames = -(-length_samples // frame_step)

            # Pad the signal by up to frame_length samples based on how many samples
            # are remaining starting from last_frame_position.
            pad_samples = math_ops.maximum(
                0,
                frame_length + frame_step * (num_frames - 1) - length_samples)

            # Pad the inner dimension of signal by pad_samples.
            paddings = array_ops.concat([
                array_ops.zeros([num_outer_dimensions, 2],
                                dtype=pad_samples.dtype), [[0, pad_samples]],
                array_ops.zeros([num_inner_dimensions, 2],
                                dtype=pad_samples.dtype)
            ], 0)
            signal = array_ops.pad(signal, paddings, constant_values=pad_value)

            signal_shape = array_ops.shape(signal)
            length_samples = signal_shape[axis]
        else:
            num_frames = math_ops.maximum(
                0, 1 + (length_samples - frame_length) // frame_step)

        subframe_length = util_ops.gcd(frame_length, frame_step)
        subframes_per_frame = frame_length // subframe_length
        subframes_per_hop = frame_step // subframe_length
        num_subframes = length_samples // subframe_length

        slice_shape = array_ops.concat([
            outer_dimensions, [num_subframes * subframe_length],
            inner_dimensions
        ], 0)
        subframe_shape = array_ops.concat([
            outer_dimensions, [num_subframes, subframe_length],
            inner_dimensions
        ], 0)
        subframes = array_ops.reshape(
            array_ops.strided_slice(signal, array_ops.zeros_like(signal_shape),
                                    slice_shape), subframe_shape)

        # frame_selector is a [num_frames, subframes_per_frame] tensor
        # that indexes into the appropriate frame in subframes. For example:
        # [[0, 0, 0, 0], [2, 2, 2, 2], [4, 4, 4, 4]]
        frame_selector = array_ops.reshape(
            math_ops.range(num_frames) * subframes_per_hop, [num_frames, 1])

        # subframe_selector is a [num_frames, subframes_per_frame] tensor
        # that indexes into the appropriate subframe within a frame. For example:
        # [[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]
        subframe_selector = array_ops.reshape(
            math_ops.range(subframes_per_frame), [1, subframes_per_frame])

        # Adding the 2 selector tensors together produces a [num_frames,
        # subframes_per_frame] tensor of indices to use with tf.gather to select
        # subframes from subframes. We then reshape the inner-most
        # subframes_per_frame dimension to stitch the subframes together into
        # frames. For example: [[0, 1, 2, 3], [2, 3, 4, 5], [4, 5, 6, 7]].
        selector = frame_selector + subframe_selector

        frames = array_ops.reshape(
            array_ops.gather(subframes, selector, axis=axis),
            array_ops.concat([
                outer_dimensions, [num_frames, frame_length], inner_dimensions
            ], 0))

        if result_shape:
            frames.set_shape(result_shape)
        return frames
Esempio n. 36
0
 def my_pad(x, padding):
     return array_ops.pad(x, padding)
Esempio n. 37
0
    def call(self, inputs):
        inputs = self._preprocess(inputs)

        # If we're not doing any output processing, return right away.
        if self._output_mode is None:
            return inputs

        # The table lookup ops don't natively support ragged tensors, so if we have
        # a RT we need to use map_flat_values to look up every element.
        if ragged_tensor.is_ragged(inputs):
            indexed_data = ragged_functional_ops.map_flat_values(
                self._table.lookup, inputs)
        else:
            indexed_data = self._table.lookup(inputs)

        if self._output_mode == INT:
            # Once we have the dense tensor, we can return it if we weren't given a
            # fixed output sequence length. If we were, though, we have to dynamically
            # choose whether to pad or trim it based on each tensor.

            # We need to convert to dense if we have a ragged tensor.
            if ragged_tensor.is_ragged(indexed_data):
                dense_data = indexed_data.to_tensor(default_value=0)
            else:
                dense_data = indexed_data

            if self._output_sequence_length is None:
                return dense_data
            else:
                sequence_len = K.shape(dense_data)[1]
                pad_amt = self._output_sequence_length - sequence_len
                pad_fn = lambda: array_ops.pad(dense_data, [[0, 0],
                                                            [0, pad_amt]])
                slice_fn = lambda: dense_data[:, :self._output_sequence_length]
                return control_flow_ops.cond(
                    sequence_len < self._output_sequence_length,
                    true_fn=pad_fn,
                    false_fn=slice_fn)

        out_depth = self._max_tokens if self._pad_to_max else math_ops.cast(
            (self._get_table_size() + self._reserved_values), dtypes.int32)

        if self._output_mode == BINARY:
            bool_one_hot_data = array_ops.one_hot(indexed_data,
                                                  depth=out_depth,
                                                  on_value=True,
                                                  off_value=False)
            reduced_bool_data = math_ops.reduce_any(bool_one_hot_data, axis=1)
            binary_data = math_ops.cast(reduced_bool_data, dtypes.int64)
            return binary_data

        one_hot_data = array_ops.one_hot(indexed_data, depth=out_depth)
        counts = math_ops.reduce_sum(one_hot_data, axis=1)
        if self._output_mode == COUNT:
            return math_ops.cast(counts, dtypes.int64)

        tf_idf_data = math_ops.multiply(counts, self._tf_idf_weights)
        if self._output_mode == TFIDF:
            return tf_idf_data

        # We can only get here if we didn't recognize the passed mode.
        raise ValueError("Unknown output mode %s" % self._output_mode)
def csiszar_vimco_helper(logu, name=None):
    """Helper to `csiszar_vimco`; computes `log_avg_u`, `log_sooavg_u`.

  `axis = 0` of `logu` is presumed to correspond to iid samples from `q`, i.e.,

  ```none
  logu[j] = log(u[j])
  u[j] = p(x, h[j]) / q(h[j] | x)
  h[j] iid~ q(H | x)
  ```

  Args:
    logu: Floating-type `Tensor` representing `log(p(x, h) / q(h | x))`.
    name: Python `str` name prefixed to Ops created by this function.

  Returns:
    log_avg_u: `logu.dtype` `Tensor` corresponding to the natural-log of the
      average of `u`. The sum of the gradient of `log_avg_u` is `1`.
    log_sooavg_u: `logu.dtype` `Tensor` characterized by the natural-log of the
      average of `u`` except that the average swaps-out `u[i]` for the
      leave-`i`-out Geometric-average. The mean of the gradient of
      `log_sooavg_u` is `1`. Mathematically `log_sooavg_u` is,
      ```none
      log_sooavg_u[i] = log(Avg{h[j ; i] : j=0, ..., m-1})
      h[j ; i] = { u[j]                              j!=i
                 { GeometricAverage{u[k] : k != i}   j==i
      ```

  """
    with ops.name_scope(name, "csiszar_vimco_helper", [logu]):
        logu = ops.convert_to_tensor(logu, name="logu")

        n = logu.shape.with_rank_at_least(1)[0].value
        if n is None:
            n = array_ops.shape(logu)[0]
            log_n = math_ops.log(math_ops.cast(n, dtype=logu.dtype))
            nm1 = math_ops.cast(n - 1, dtype=logu.dtype)
        else:
            log_n = np.log(n).astype(logu.dtype.as_numpy_dtype)
            nm1 = np.asarray(n - 1, dtype=logu.dtype.as_numpy_dtype)

        # Throughout we reduce across axis=0 since this is presumed to be iid
        # samples.

        log_max_u = math_ops.reduce_max(logu, axis=0)
        log_sum_u_minus_log_max_u = math_ops.reduce_logsumexp(logu - log_max_u,
                                                              axis=0)

        # log_loosum_u[i] =
        # = logsumexp(logu[j] : j != i)
        # = log( exp(logsumexp(logu)) - exp(logu[i]) )
        # = log( exp(logsumexp(logu - logu[i])) exp(logu[i])  - exp(logu[i]))
        # = logu[i] + log(exp(logsumexp(logu - logu[i])) - 1)
        # = logu[i] + log(exp(logsumexp(logu) - logu[i]) - 1)
        # = logu[i] + softplus_inverse(logsumexp(logu) - logu[i])
        d = log_sum_u_minus_log_max_u + (log_max_u - logu)
        # We use `d != 0` rather than `d > 0.` because `d < 0.` should never
        # happens; if it does we want to complain loudly (which `softplus_inverse`
        # will).
        d_ok = math_ops.not_equal(d, 0.)
        safe_d = array_ops.where(d_ok, d, array_ops.ones_like(d))
        d_ok_result = logu + distribution_util.softplus_inverse(safe_d)

        inf = np.array(np.inf, dtype=logu.dtype.as_numpy_dtype)

        # When not(d_ok) and is_positive_and_largest then we manually compute the
        # log_loosum_u. (We can efficiently do this for any one point but not all,
        # hence we still need the above calculation.) This is good because when
        # this condition is met, we cannot use the above calculation; its -inf.
        # We now compute the log-leave-out-max-sum, replicate it to every
        # point and make sure to select it only when we need to.
        is_positive_and_largest = math_ops.logical_and(
            logu > 0., math_ops.equal(logu, log_max_u[array_ops.newaxis, ...]))
        log_lomsum_u = math_ops.reduce_logsumexp(array_ops.where(
            is_positive_and_largest, array_ops.fill(array_ops.shape(logu),
                                                    -inf), logu),
                                                 axis=0,
                                                 keep_dims=True)
        log_lomsum_u = array_ops.tile(
            log_lomsum_u,
            multiples=1 +
            array_ops.pad([n - 1], [[0, array_ops.rank(logu) - 1]]))

        d_not_ok_result = array_ops.where(
            is_positive_and_largest, log_lomsum_u,
            array_ops.fill(array_ops.shape(d), -inf))

        log_loosum_u = array_ops.where(d_ok, d_ok_result, d_not_ok_result)

        # The swap-one-out-sum ("soosum") is n different sums, each of which
        # replaces the i-th item with the i-th-left-out average, i.e.,
        # soo_sum_u[i] = [exp(logu) - exp(logu[i])] + exp(mean(logu[!=i]))
        #              =  exp(log_loosum_u[i])      + exp(looavg_logu[i])
        looavg_logu = (math_ops.reduce_sum(logu, axis=0) - logu) / nm1
        log_soosum_u = math_ops.reduce_logsumexp(array_ops.stack(
            [log_loosum_u, looavg_logu]),
                                                 axis=0)

        log_avg_u = log_sum_u_minus_log_max_u + log_max_u - log_n
        log_sooavg_u = log_soosum_u - log_n

        log_avg_u.set_shape(logu.shape.with_rank_at_least(1)[1:])
        log_sooavg_u.set_shape(logu.shape)

        return log_avg_u, log_sooavg_u
Esempio n. 39
0
    def _power_sum_array(self, max_remaining_steps):
        r"""Computes \sum_{i=0}^{N-1} A^i B (A^i)^T for N=0..max_remaining_steps.

    A is the transition matrix and B is the noise covariance.

    This is more efficient in practice than math_utils.power_sums_tensor, since
    each A^i B (A^i)^T term has a closed-form expression not depending on i - 1.
    Thus vectorization can replace explicit looping.

    Uses a cumulative sum on the following expression:

      (transition^p * transition_covariance * (transition^p)^T)_{i, j}
        = (-1)^(i + j) * sin^2(pi * p) / num_latent_values^2
          * (1/sin(pi / num_latent_values * (p - i))
             + 1/sin(pi / num_latent_values * (p - i - 1)))
          * (1/sin(pi / num_latent_values * (p - j))
             + 1/sin(pi / num_latent_values * (p - j - 1)))

    The expression being derived from the eigenvectors and eigenvalues given in
    the class docstring (and as with CycleStateSpaceModel taking advantage of
    the sparsity of the transition covariance).

    Args:
      max_remaining_steps: A scalar integer Tensor indicating the number of
        non-trivial values to compute.
    Returns:
      A [max_remaining_steps + 1, self._num_latent_values - 1,
      self._num_latent_values - 1] floating point Tensor S with cumulative power
      sums.

      S[N] = \sum_{i=0}^{N-1} A^i B (A^i)^T
        S[0] is the zero matrix
        S[1] is B
        S[2] is A B A^T + B

    """
        num_latent_values_float = math_ops.cast(self._num_latent_values,
                                                self.dtype)
        latent_values_per_period = (
            num_latent_values_float /
            math_ops.cast(self._true_periodicity, dtype=self.dtype))
        original_matrix_powers = (
            math_ops.cast(math_ops.range(max_remaining_steps), self.dtype) *
            latent_values_per_period)
        matrix_dimension_range = math_ops.range(self._num_latent_values -
                                                1)[None, ...]
        matrix_dimension_range_float = math_ops.cast(matrix_dimension_range,
                                                     self.dtype)

        def _cosecant_with_freq(coefficient):
            return 1. / math_ops.sin(
                numpy.pi / num_latent_values_float * coefficient)

        power_minus_index = (original_matrix_powers[..., None] -
                             matrix_dimension_range_float)
        mesh_values = (_cosecant_with_freq(power_minus_index) +
                       _cosecant_with_freq(power_minus_index - 1.))
        meshed = mesh_values[..., None, :] * mesh_values[..., None]
        full_matrix_alternating = math_ops.cast(
            1 - 2 * ((matrix_dimension_range[..., None, :] +
                      matrix_dimension_range[..., None]) % 2), self.dtype)

        def _sine_discontinuity(value):
            """A special case for dealing with discontinuities.

      Decides whether `value`  is close to an integer, and if so computes:

        lim x->n |sin(x * pi)| / sin(x * pi) = sign(sin(n * pi))
                                             = cos(n * pi)

      Args:
        value: The floating point Tensor value which may lead to a
            discontinuity.
      Returns:
        A tuple of (is_discontinuous, sign):
          is_discontinuous: A boolean Tensor of the same shape as `value`,
              indicating whether it is near an integer.
          sign: A floating point Tensor indicating the sign of the discontinuity
            (being near 1 or -1 when `is_discontinuous` is True), of the same
            shape and type as `value`.
      """
            normalized = value / num_latent_values_float
            is_discontinuous = self._close_to_integer(normalized)
            sign = math_ops.cos(normalized * numpy.pi)
            return is_discontinuous, sign

        index_discontinuous, index_sign = _sine_discontinuity(
            original_matrix_powers[..., None] - matrix_dimension_range_float)
        index_minus_discontinuous, index_minus_sign = _sine_discontinuity(
            original_matrix_powers[..., None] - matrix_dimension_range_float -
            1)
        ones_mask_vector = math_ops.logical_or(index_discontinuous,
                                               index_minus_discontinuous)
        ones_sign_vector = array_ops.where(index_discontinuous, index_sign,
                                           index_minus_sign)
        ones_mask = math_ops.logical_and(ones_mask_vector[..., None],
                                         ones_mask_vector[..., None, :])
        zeros_mask = self._close_to_integer(original_matrix_powers)
        zeroed = array_ops.where(zeros_mask, array_ops.zeros_like(meshed),
                                 meshed)
        global_coefficient = (math_ops.sin(numpy.pi * original_matrix_powers) /
                              num_latent_values_float)
        masked_meshed = array_ops.where(
            ones_mask,
            ones_sign_vector[..., None] * ones_sign_vector[..., None, :],
            zeroed * global_coefficient[..., None, None]**2)
        powers_above_zero = full_matrix_alternating * masked_meshed
        return array_ops.pad(math_ops.cumsum(powers_above_zero),
                             [(1, 0), (0, 0), (0, 0)])
 def pad_fn(value):
   shape = array_ops.shape(value)
   left = array_ops.zeros_like(shape)
   right = padded_shape - shape
   return array_ops.pad(
       value, array_ops.stack([left, right], 1), constant_values=padding_value)
Esempio n. 41
0
def overlap_and_add(signal, frame_step, name=None):
    """Reconstructs a signal from a framed representation.

  Adds potentially overlapping frames of a signal with shape
  `[..., frames, frame_length]`, offsetting subsequent frames by `frame_step`.
  The resulting tensor has shape `[..., output_size]` where

      output_size = (frames - 1) * frame_step + frame_length

  Args:
    signal: A [..., frames, frame_length] `Tensor`. All dimensions may be
      unknown, and rank must be at least 2.
    frame_step: An integer or scalar `Tensor` denoting overlap offsets. Must be
      less than or equal to `frame_length`.
    name: An optional name for the operation.

  Returns:
    A `Tensor` with shape `[..., output_size]` containing the overlap-added
    frames of `signal`'s inner-most two dimensions.

  Raises:
    ValueError: If `signal`'s rank is less than 2, or `frame_step` is not a
      scalar integer.
  """
    with ops.name_scope(name, "overlap_and_add", [signal, frame_step]):
        signal = ops.convert_to_tensor(signal, name="signal")
        signal.shape.with_rank_at_least(2)
        frame_step = ops.convert_to_tensor(frame_step, name="frame_step")
        frame_step.shape.assert_has_rank(0)
        if not frame_step.dtype.is_integer:
            raise ValueError("frame_step must be an integer. Got %s" %
                             frame_step.dtype)

        signal_shape = array_ops.shape(signal)

        # All dimensions that are not part of the overlap-and-add. Can be empty for
        # rank 2 inputs.
        outer_dimensions = signal_shape[:-2]
        outer_rank = array_ops.size(outer_dimensions)

        def full_shape(inner_shape):
            return array_ops.concat([outer_dimensions, inner_shape], 0)

        frame_length = signal_shape[-1]
        frames = signal_shape[-2]

        # Compute output length.
        output_length = frame_length + frame_step * (frames - 1)

        # If frame_length is equal to frame_step, there's no overlap so just
        # reshape the tensor.
        frame_step_static = tensor_util.constant_value(frame_step)
        if (frame_step_static is not None
                and frame_step_static == signal.shape.dims[-1].value):
            output_shape = full_shape([output_length])
            return array_ops.reshape(signal, output_shape, name="fast_path")

        # The following code is documented using this example:
        #
        # frame_step = 2
        # signal.shape = (3, 5)
        # a b c d e
        # f g h i j
        # k l m n o

        # Compute the number of segments, per frame.
        segments = -(-frame_length // frame_step)  # Divide and round up.

        # Pad the frame_length dimension to a multiple of the frame step.
        # Pad the frames dimension by `segments` so that signal.shape = (6, 6)
        # a b c d e 0
        # f g h i j 0
        # k l m n o 0
        # 0 0 0 0 0 0
        # 0 0 0 0 0 0
        # 0 0 0 0 0 0
        paddings = [[0, segments], [0, segments * frame_step - frame_length]]
        outer_paddings = array_ops.zeros([outer_rank, 2], dtypes.int32)
        paddings = array_ops.concat([outer_paddings, paddings], 0)
        signal = array_ops.pad(signal, paddings)

        # Reshape so that signal.shape = (3, 6, 2)
        # ab cd e0
        # fg hi j0
        # kl mn o0
        # 00 00 00
        # 00 00 00
        # 00 00 00
        shape = full_shape([frames + segments, segments, frame_step])
        signal = array_ops.reshape(signal, shape)

        # Transpose dimensions so that signal.shape = (3, 6, 2)
        # ab fg kl 00 00 00
        # cd hi mn 00 00 00
        # e0 j0 o0 00 00 00
        perm = array_ops.concat(
            [math_ops.range(outer_rank), outer_rank + [1, 0, 2]], 0)
        signal = array_ops.transpose(signal, perm)

        # Reshape so that signal.shape = (18, 2)
        # ab fg kl 00 00 00 cd hi mn 00 00 00 e0 j0 o0 00 00 00
        shape = full_shape([(frames + segments) * segments, frame_step])
        signal = array_ops.reshape(signal, shape)

        # Truncate so that signal.shape = (15, 2)
        # ab fg kl 00 00 00 cd hi mn 00 00 00 e0 j0 o0
        signal = signal[..., :(frames + segments - 1) * segments, :]

        # Reshape so that signal.shape = (3, 5, 2)
        # ab fg kl 00 00
        # 00 cd hi mn 00
        # 00 00 e0 j0 o0
        shape = full_shape([segments, (frames + segments - 1), frame_step])
        signal = array_ops.reshape(signal, shape)

        # Now, reduce over the columns, to achieve the desired sum.
        signal = math_ops.reduce_sum(signal, -3)

        # Flatten the array.
        shape = full_shape([(frames + segments - 1) * frame_step])
        signal = array_ops.reshape(signal, shape)

        # Truncate to final length.
        signal = signal[..., :output_length]

        return signal
Esempio n. 42
0
 def testInputDims(self):
     with self.test_session(use_gpu=True):
         with self.assertRaises(ValueError):
             array_ops.pad(
                 array_ops.reshape([1, 2], shape=[1, 2, 1, 1, 1, 1]),
                 array_ops.reshape([1, 2], shape=[1, 2]))
Esempio n. 43
0
 def testPaddingsNonNegative2(self):
     with self.test_session(use_gpu=True):
         with self.assertRaisesRegexp(ValueError, "must be non-negative"):
             array_ops.pad(constant_op.constant([1], shape=[1]),
                           constant_op.constant([-1, 0], shape=[1, 2]))
Esempio n. 44
0
    def run_test_sample_consistent_log_prob(self,
                                            sess_run_fn,
                                            dist,
                                            num_samples=int(1e5),
                                            num_threshold=int(1e3),
                                            seed=42,
                                            batch_size=None,
                                            rtol=1e-2,
                                            atol=0.):
        """Tests that sample/log_prob are consistent with each other.

    "Consistency" means that `sample` and `log_prob` correspond to the same
    distribution.

    Note: this test only verifies a necessary condition for consistency--it does
    does not verify sufficiency hence does not prove `sample`, `log_prob` truly
    are consistent.

    Args:
      sess_run_fn: Python `callable` taking `list`-like of `Tensor`s and
        returning a list of results after running one "step" of TensorFlow
        computation, typically set to `sess.run`.
      dist: Distribution instance or object which implements `sample`,
        `log_prob`, `event_shape_tensor` and `batch_shape_tensor`.
      num_samples: Python `int` scalar indicating the number of Monte-Carlo
        samples to draw from `dist`.
      num_threshold: Python `int` scalar indicating the number of samples a
        bucket must contain before being compared to the probability.
        Default value: 1e3; must be at least 1.
        Warning, set too high will cause test to falsely pass but setting too
        low will cause the test to falsely fail.
      seed: Python `int` indicating the seed to use when sampling from `dist`.
        In general it is not recommended to use `None` during a test as this
        increases the likelihood of spurious test failure.
      batch_size: Hint for unpacking result of samples. Default: `None` means
        batch_size is inferred.
      rtol: Python `float`-type indicating the admissible relative error between
        analytical and sample statistics.
      atol: Python `float`-type indicating the admissible absolute error between
        analytical and sample statistics.

    Raises:
      ValueError: if `num_threshold < 1`.
    """
        if num_threshold < 1:
            raise ValueError(
                "num_threshold({}) must be at least 1.".format(num_threshold))
        # Histogram only supports vectors so we call it once per batch coordinate.
        y = dist.sample(num_samples, seed=seed)
        y = array_ops.reshape(y, shape=[num_samples, -1])
        if batch_size is None:
            batch_size = math_ops.reduce_prod(dist.batch_shape_tensor())
        batch_dims = array_ops.shape(dist.batch_shape_tensor())[0]
        edges_expanded_shape = 1 + array_ops.pad([-2],
                                                 paddings=[[0, batch_dims]])
        for b, x in enumerate(array_ops.unstack(y, num=batch_size, axis=1)):
            counts, edges = self.histogram(x)
            edges = array_ops.reshape(edges, edges_expanded_shape)
            probs = math_ops.exp(dist.log_prob(edges))
            probs = array_ops.reshape(probs, shape=[-1, batch_size])[:, b]

            [counts_, probs_] = sess_run_fn([counts, probs])
            valid = counts_ > num_threshold
            probs_ = probs_[valid]
            counts_ = counts_[valid]
            self.assertAllClose(probs_,
                                counts_ / num_samples,
                                rtol=rtol,
                                atol=atol)
Esempio n. 45
0
 def my_net(a, b, c):
     a = array_ops.broadcast_to(a, shape=[1024])
     b = array_ops.strided_slice(b, [0], [8192], [8])
     c = array_ops.pad(c, paddings=[[256, 256]])
     out = a + b + c
     return [out]
Esempio n. 46
0
def frame(signal,
          frame_length,
          frame_step,
          pad_end=False,
          pad_value=0,
          axis=-1,
          name=None):
    """Expands `signal`'s `axis` dimension into frames of `frame_length`.

  Slides a window of size `frame_length` over `signal`'s `axis` dimension
  with a stride of `frame_step`, replacing the `axis` dimension with
  `[frames, frame_length]` frames.

  If `pad_end` is True, window positions that are past the end of the `axis`
  dimension are padded with `pad_value` until the window moves fully past the
  end of the dimension. Otherwise, only window positions that fully overlap the
  `axis` dimension are produced.

  For example:

  >>> # A batch size 3 tensor of 9152 audio samples.
  >>> audio = tf.random.normal([3, 9152])
  >>> 
  >>> # Compute overlapping frames of length 512 with a step of 180 (frames overlap
  >>> # by 332 samples). By default, only 49 frames are generated since a frame
  >>> # with start position j*180 for j > 48 would overhang the end.
  >>> frames = tf.signal.frame(audio, 512, 180)
  >>> frames.shape.assert_is_compatible_with([3, 49, 512])
  >>> 
  >>> # When pad_end is enabled, the final two frames are kept (padded with zeros).
  >>> frames = tf.signal.frame(audio, 512, 180, pad_end=True)
  >>> frames.shape.assert_is_compatible_with([3, 51, 512])
  
  If the dimension along `axis` is N, and `pad_end=False`, the number of frames
  can be computed by:
   ```python
   num_frames = 1 + (N - frame_size) // frame_step
   ```
   If `pad_end=True`, the number of frames can be computed by:
  ```python
  num_frames = -(-N // frame_step) # ceiling division
  ```

  Args:
    signal: A `[..., samples, ...]` `Tensor`. The rank and dimensions
      may be unknown. Rank must be at least 1.
    frame_length: The frame length in samples. An integer or scalar `Tensor`.
    frame_step: The frame hop size in samples. An integer or scalar `Tensor`.
    pad_end: Whether to pad the end of `signal` with `pad_value`.
    pad_value: An optional scalar `Tensor` to use where the input signal
      does not exist when `pad_end` is True.
    axis: A scalar integer `Tensor` indicating the axis to frame. Defaults to
      the last axis. Supports negative values for indexing from the end.
    name: An optional name for the operation.

  Returns:
    A `Tensor` of frames with shape `[..., num_frames, frame_length, ...]`.

  Raises:
    ValueError: If `frame_length`, `frame_step`, `pad_value`, or `axis` are not
      scalar.
  """
    with ops.name_scope(name, "frame",
                        [signal, frame_length, frame_step, pad_value]):
        signal = ops.convert_to_tensor(signal, name="signal")
        frame_length = ops.convert_to_tensor(frame_length, name="frame_length")
        frame_step = ops.convert_to_tensor(frame_step, name="frame_step")
        axis = ops.convert_to_tensor(axis, name="axis")

        signal.shape.with_rank_at_least(1)
        frame_length.shape.assert_has_rank(0)
        frame_step.shape.assert_has_rank(0)
        axis.shape.assert_has_rank(0)

        result_shape = _infer_frame_shape(signal, frame_length, frame_step,
                                          pad_end, axis)

        def maybe_constant(val):
            val_static = tensor_util.constant_value(val)
            return (val_static, True) if val_static is not None else (val,
                                                                      False)

        signal_shape, signal_shape_is_static = maybe_constant(
            array_ops.shape(signal))
        axis, axis_is_static = maybe_constant(axis)

        if signal_shape_is_static and axis_is_static:
            # Axis can be negative. Convert it to positive.
            axis = range(len(signal_shape))[axis]
            outer_dimensions, length_samples, inner_dimensions = np.split(
                signal_shape, indices_or_sections=[axis, axis + 1])
            length_samples = length_samples.item()
        else:
            signal_rank = array_ops.rank(signal)
            # Axis can be negative. Convert it to positive.
            axis = math_ops.range(signal_rank)[axis]
            outer_dimensions, length_samples, inner_dimensions = array_ops.split(
                signal_shape, [axis, 1, signal_rank - 1 - axis])
            length_samples = array_ops.reshape(length_samples, [])
        num_outer_dimensions = array_ops.size(outer_dimensions)
        num_inner_dimensions = array_ops.size(inner_dimensions)

        # If padding is requested, pad the input signal tensor with pad_value.
        if pad_end:
            pad_value = ops.convert_to_tensor(pad_value, signal.dtype)
            pad_value.shape.assert_has_rank(0)

            # Calculate number of frames, using double negatives to round up.
            num_frames = -(-length_samples // frame_step)

            # Pad the signal by up to frame_length samples based on how many samples
            # are remaining starting from last_frame_position.
            pad_samples = math_ops.maximum(
                0,
                frame_length + frame_step * (num_frames - 1) - length_samples)

            # Pad the inner dimension of signal by pad_samples.
            paddings = array_ops.concat([
                array_ops.zeros([num_outer_dimensions, 2],
                                dtype=pad_samples.dtype),
                ops.convert_to_tensor([[0, pad_samples]]),
                array_ops.zeros([num_inner_dimensions, 2],
                                dtype=pad_samples.dtype)
            ], 0)
            signal = array_ops.pad(signal, paddings, constant_values=pad_value)

            signal_shape = array_ops.shape(signal)
            length_samples = signal_shape[axis]
        else:
            num_frames = math_ops.maximum(
                0, 1 + (length_samples - frame_length) // frame_step)

        subframe_length, _ = maybe_constant(
            util_ops.gcd(frame_length, frame_step))
        subframes_per_frame = frame_length // subframe_length
        subframes_per_hop = frame_step // subframe_length
        num_subframes = length_samples // subframe_length

        slice_shape = array_ops.concat([
            outer_dimensions, [num_subframes * subframe_length],
            inner_dimensions
        ], 0)
        subframe_shape = array_ops.concat([
            outer_dimensions, [num_subframes, subframe_length],
            inner_dimensions
        ], 0)
        subframes = array_ops.reshape(
            array_ops.strided_slice(signal, array_ops.zeros_like(signal_shape),
                                    slice_shape), subframe_shape)

        # frame_selector is a [num_frames, subframes_per_frame] tensor
        # that indexes into the appropriate frame in subframes. For example:
        # [[0, 0, 0, 0], [2, 2, 2, 2], [4, 4, 4, 4]]
        frame_selector = array_ops.reshape(
            math_ops.range(num_frames) * subframes_per_hop, [num_frames, 1])

        # subframe_selector is a [num_frames, subframes_per_frame] tensor
        # that indexes into the appropriate subframe within a frame. For example:
        # [[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]
        subframe_selector = array_ops.reshape(
            math_ops.range(subframes_per_frame), [1, subframes_per_frame])

        # Adding the 2 selector tensors together produces a [num_frames,
        # subframes_per_frame] tensor of indices to use with tf.gather to select
        # subframes from subframes. We then reshape the inner-most
        # subframes_per_frame dimension to stitch the subframes together into
        # frames. For example: [[0, 1, 2, 3], [2, 3, 4, 5], [4, 5, 6, 7]].
        selector = frame_selector + subframe_selector

        frames = array_ops.reshape(
            array_ops.gather(subframes, selector, axis=axis),
            array_ops.concat([
                outer_dimensions, [num_frames, frame_length], inner_dimensions
            ], 0))

        if result_shape:
            frames.set_shape(result_shape)
        return frames
Esempio n. 47
0
 def body_fn(i, array):
   return i + 1, array_ops.pad(
       array,
       padding,
       constant_values=kernel[start + i, start + i])
Esempio n. 48
0
def inverse_stft(stfts,
                 frame_length,
                 frame_step,
                 fft_length=None,
                 window_fn=window_ops.hann_window,
                 name=None):
    """Computes the inverse [Short-time Fourier Transform][stft] of `stfts`.

  To reconstruct an original waveform, a complementary window function should
  be used with `inverse_stft`. Such a window function can be constructed with
  `tf.signal.inverse_stft_window_fn`.
  Example:

  ```python
  frame_length = 400
  frame_step = 160
  waveform = tf.random.normal(dtype=tf.float32, shape=[1000])
  stft = tf.signal.stft(waveform, frame_length, frame_step)
  inverse_stft = tf.signal.inverse_stft(
      stft, frame_length, frame_step,
      window_fn=tf.signal.inverse_stft_window_fn(frame_step))
  ```

  If a custom `window_fn` is used with `tf.signal.stft`, it must be passed to
  `tf.signal.inverse_stft_window_fn`:

  ```python
  frame_length = 400
  frame_step = 160
  window_fn = tf.signal.hamming_window
  waveform = tf.random.normal(dtype=tf.float32, shape=[1000])
  stft = tf.signal.stft(
      waveform, frame_length, frame_step, window_fn=window_fn)
  inverse_stft = tf.signal.inverse_stft(
      stft, frame_length, frame_step,
      window_fn=tf.signal.inverse_stft_window_fn(
         frame_step, forward_window_fn=window_fn))
  ```

  Implemented with TPU/GPU-compatible ops and supports gradients.

  Args:
    stfts: A `complex64`/`complex128` `[..., frames, fft_unique_bins]`
      `Tensor` of STFT bins representing a batch of `fft_length`-point STFTs
      where `fft_unique_bins` is `fft_length // 2 + 1`
    frame_length: An integer scalar `Tensor`. The window length in samples.
    frame_step: An integer scalar `Tensor`. The number of samples to step.
    fft_length: An integer scalar `Tensor`. The size of the FFT that produced
      `stfts`. If not provided, uses the smallest power of 2 enclosing
      `frame_length`.
    window_fn: A callable that takes a window length and a `dtype` keyword
      argument and returns a `[window_length]` `Tensor` of samples in the
      provided datatype. If set to `None`, no windowing is used.
    name: An optional name for the operation.

  Returns:
    A `[..., samples]` `Tensor` of `float32`/`float64` signals representing
    the inverse STFT for each input STFT in `stfts`.

  Raises:
    ValueError: If `stfts` is not at least rank 2, `frame_length` is not scalar,
      `frame_step` is not scalar, or `fft_length` is not scalar.

  [stft]: https://en.wikipedia.org/wiki/Short-time_Fourier_transform
  """
    with ops.name_scope(name, 'inverse_stft', [stfts]):
        stfts = ops.convert_to_tensor(stfts, name='stfts')
        stfts.shape.with_rank_at_least(2)
        frame_length = ops.convert_to_tensor(frame_length, name='frame_length')
        frame_length.shape.assert_has_rank(0)
        frame_step = ops.convert_to_tensor(frame_step, name='frame_step')
        frame_step.shape.assert_has_rank(0)
        if fft_length is None:
            fft_length = _enclosing_power_of_two(frame_length)
        else:
            fft_length = ops.convert_to_tensor(fft_length, name='fft_length')
            fft_length.shape.assert_has_rank(0)

        real_frames = fft_ops.irfft(stfts, [fft_length])

        # frame_length may be larger or smaller than fft_length, so we pad or
        # truncate real_frames to frame_length.
        frame_length_static = tensor_util.constant_value(frame_length)
        # If we don't know the shape of real_frames's inner dimension, pad and
        # truncate to frame_length.
        if (frame_length_static is None or real_frames.shape.ndims is None
                or real_frames.shape.as_list()[-1] is None):
            real_frames = real_frames[..., :frame_length]
            real_frames_rank = array_ops.rank(real_frames)
            real_frames_shape = array_ops.shape(real_frames)
            paddings = array_ops.concat([
                array_ops.zeros([real_frames_rank - 1, 2],
                                dtype=frame_length.dtype),
                [[
                    0,
                    math_ops.maximum(0, frame_length - real_frames_shape[-1])
                ]]
            ], 0)
            real_frames = array_ops.pad(real_frames, paddings)
        # We know real_frames's last dimension and frame_length statically. If they
        # are different, then pad or truncate real_frames to frame_length.
        elif real_frames.shape.as_list()[-1] > frame_length_static:
            real_frames = real_frames[..., :frame_length_static]
        elif real_frames.shape.as_list()[-1] < frame_length_static:
            pad_amount = frame_length_static - real_frames.shape.as_list()[-1]
            real_frames = array_ops.pad(
                real_frames,
                [[0, 0]] * (real_frames.shape.ndims - 1) + [[0, pad_amount]])

        # The above code pads the inner dimension of real_frames to frame_length,
        # but it does so in a way that may not be shape-inference friendly.
        # Restore shape information if we are able to.
        if frame_length_static is not None and real_frames.shape.ndims is not None:
            real_frames.set_shape([None] * (real_frames.shape.ndims - 1) +
                                  [frame_length_static])

        # Optionally window and overlap-add the inner 2 dimensions of real_frames
        # into a single [samples] dimension.
        if window_fn is not None:
            window = window_fn(frame_length, dtype=stfts.dtype.real_dtype)
            real_frames *= window
        return reconstruction_ops.overlap_and_add(real_frames, frame_step)
Esempio n. 49
0
def linear_to_mel_weight_matrix(num_mel_bins=20,
                                num_spectrogram_bins=129,
                                sample_rate=8000,
                                lower_edge_hertz=125.0,
                                upper_edge_hertz=3800.0,
                                dtype=dtypes.float32,
                                name=None):
  """Returns a matrix to warp linear scale spectrograms to the [mel scale][mel].

  Returns a weight matrix that can be used to re-weight a `Tensor` containing
  `num_spectrogram_bins` linearly sampled frequency information from
  `[0, sample_rate / 2]` into `num_mel_bins` frequency information from
  `[lower_edge_hertz, upper_edge_hertz]` on the [mel scale][mel].

  For example, the returned matrix `A` can be used to right-multiply a
  spectrogram `S` of shape `[frames, num_spectrogram_bins]` of linear
  scale spectrum values (e.g. STFT magnitudes) to generate a "mel spectrogram"
  `M` of shape `[frames, num_mel_bins]`.

      # `S` has shape [frames, num_spectrogram_bins]
      # `M` has shape [frames, num_mel_bins]
      M = tf.matmul(S, A)

  The matrix can be used with @{tf.tensordot} to convert an arbitrary rank
  `Tensor` of linear-scale spectral bins into the mel scale.

      # S has shape [..., num_spectrogram_bins].
      # M has shape [..., num_mel_bins].
      M = tf.tensordot(S, A, 1)
      # tf.tensordot does not support shape inference for this case yet.
      M.set_shape(S.shape[:-1].concatenate(A.shape[-1:]))

  Args:
    num_mel_bins: Python int. How many bands in the resulting mel spectrum.
    num_spectrogram_bins: Python int. How many bins there are in the source
      spectrogram data, which is understood to be `fft_size // 2 + 1`, i.e. the
      spectrogram only contains the nonredundant FFT bins.
    sample_rate: Python float. Samples per second of the input signal used to
      create the spectrogram. We need this to figure out the actual frequencies
      for each spectrogram bin, which dictates how they are mapped into the mel
      scale.
    lower_edge_hertz: Python float. Lower bound on the frequencies to be
      included in the mel spectrum. This corresponds to the lower edge of the
      lowest triangular band.
    upper_edge_hertz: Python float. The desired top edge of the highest
      frequency band.
    dtype: The `DType` of the result matrix. Must be a floating point type.
    name: An optional name for the operation.

  Returns:
    A `Tensor` of shape `[num_spectrogram_bins, num_mel_bins]`.

  Raises:
    ValueError: If num_mel_bins/num_spectrogram_bins/sample_rate are not
      positive, lower_edge_hertz is negative, or frequency edges are incorrectly
      ordered.

  [mel]: https://en.wikipedia.org/wiki/Mel_scale
  """
  with ops.name_scope(name, 'linear_to_mel_weight_matrix') as name:
    _validate_arguments(num_mel_bins, num_spectrogram_bins, sample_rate,
                        lower_edge_hertz, upper_edge_hertz, dtype)

    # To preserve accuracy, we compute the matrix at float64 precision and then
    # cast to `dtype` at the end. This function can be constant folded by graph
    # optimization since there are no Tensor inputs.
    sample_rate = ops.convert_to_tensor(
        sample_rate, dtypes.float64, name='sample_rate')
    lower_edge_hertz = ops.convert_to_tensor(
        lower_edge_hertz, dtypes.float64, name='lower_edge_hertz')
    upper_edge_hertz = ops.convert_to_tensor(
        upper_edge_hertz, dtypes.float64, name='upper_edge_hertz')
    zero_float64 = ops.convert_to_tensor(0.0, dtypes.float64)

    # HTK excludes the spectrogram DC bin.
    bands_to_zero = 1
    nyquist_hertz = sample_rate / 2.0
    linear_frequencies = math_ops.linspace(
        zero_float64, nyquist_hertz, num_spectrogram_bins)[bands_to_zero:]
    spectrogram_bins_mel = array_ops.expand_dims(
        _hertz_to_mel(linear_frequencies), 1)

    # Compute num_mel_bins triples of (lower_edge, center, upper_edge). The
    # center of each band is the lower and upper edge of the adjacent bands.
    # Accordingly, we divide [lower_edge_hertz, upper_edge_hertz] into
    # num_mel_bins + 2 pieces.
    band_edges_mel = shape_ops.frame(
        math_ops.linspace(_hertz_to_mel(lower_edge_hertz),
                          _hertz_to_mel(upper_edge_hertz),
                          num_mel_bins + 2), frame_length=3, frame_step=1)

    # Split the triples up and reshape them into [1, num_mel_bins] tensors.
    lower_edge_mel, center_mel, upper_edge_mel = tuple(array_ops.reshape(
        t, [1, num_mel_bins]) for t in array_ops.split(
            band_edges_mel, 3, axis=1))

    # Calculate lower and upper slopes for every spectrogram bin.
    # Line segments are linear in the mel domain, not Hertz.
    lower_slopes = (spectrogram_bins_mel - lower_edge_mel) / (
        center_mel - lower_edge_mel)
    upper_slopes = (upper_edge_mel - spectrogram_bins_mel) / (
        upper_edge_mel - center_mel)

    # Intersect the line segments with each other and zero.
    mel_weights_matrix = math_ops.maximum(
        zero_float64, math_ops.minimum(lower_slopes, upper_slopes))

    # Re-add the zeroed lower bins we sliced out above.
    mel_weights_matrix = array_ops.pad(
        mel_weights_matrix, [[bands_to_zero, 0], [0, 0]])

    # Cast to the desired type.
    return math_ops.cast(mel_weights_matrix, dtype, name=name)
Esempio n. 50
0
    def call(self, inputs):
        inputs = ops.convert_to_tensor(inputs, dtype=self.dtype)
        input_shape = array_ops.shape(inputs)
        outputs = inputs

        # First, perform any requested padding.
        if self.padding in ("same_zeros", "same_reflect"):
            padding = padding_ops.same_padding_for_kernel(
                self.kernel_support, self.corr, self.strides_up)
            if self.data_format == "channels_last":
                padding = [[0, 0]] + list(padding) + [[0, 0]]
            else:
                padding = [[0, 0], [0, 0]] + list(padding)
            outputs = array_ops.pad(outputs, padding, self._pad_mode)

        # Now, perform valid convolutions/correlations.

        # Not for all possible combinations of (`kernel_support`, `corr`,
        # `strides_up`, `strides_down`) TF ops exist. We implement some additional
        # combinations by manipulating the kernels and toggling `corr`.
        kernel = self.kernel
        corr = self.corr

        # If a convolution with no upsampling is desired, we flip the kernels and
        # use cross correlation to implement it, provided the kernels are odd-length
        # in every dimension (with even-length kernels, the boundary handling
        # would have to change, so we'll throw an error instead).
        if (not corr and all(s == 1 for s in self.strides_up)
                and all(s % 2 == 1 for s in self.kernel_support)):
            corr = True
            slices = self._rank * (slice(None, None,
                                         -1), ) + 2 * (slice(None), )
            kernel = kernel[slices]

        # Similarly, we can implement a cross correlation with no downsampling using
        # convolutions. However, we do this only if upsampling is requested, as we
        # are wasting computation in the boundaries whenever we call the transpose
        # convolution ops.
        if (corr and all(s == 1 for s in self.strides_down)
                and any(s != 1 for s in self.strides_up)
                and all(s % 2 == 1 for s in self.kernel_support)):
            corr = False
            slices = self._rank * (slice(None, None,
                                         -1), ) + 2 * (slice(None), )
            kernel = kernel[slices]

        data_format = utils.convert_data_format(self.data_format,
                                                self._rank + 2)
        if (corr and self.channel_separable and self._rank == 2
                and all(s == 1 for s in self.strides_up)
                and all(s == self.strides_down[0] for s in self.strides_down)):
            # `nn.depthwise_conv2d_native` performs channel-separable correlations
            # followed by optional downsampling.
            outputs = nn.depthwise_conv2d_native(outputs,
                                                 kernel,
                                                 strides=self._pad_strides(
                                                     self.strides_down),
                                                 padding="VALID",
                                                 data_format=data_format)
        elif (corr and all(s == 1 for s in self.strides_up)
              and not self.channel_separable):
            # `nn.convolution` performs correlations followed by optional
            # downsampling.
            outputs = nn.convolution(outputs,
                                     kernel,
                                     strides=self.strides_down,
                                     padding="VALID",
                                     data_format=data_format)
        elif (not corr and all(s == 1 for s in self.strides_down)
              and ((not self.channel_separable and 1 <= self._rank <= 3) or
                   (self.channel_separable and self.filters == 1
                    and self._rank == 2 and all(s == self.strides_up[0]
                                                for s in self.strides_up)))):
            # `nn.conv?d_transpose` perform convolutions, preceded by optional
            # upsampling. Generally, they increase the spatial support of their
            # inputs, so in order to implement 'valid', we need to crop their outputs.

            # Transpose convolutions expect the output and input channels in reversed
            # order. We implement this by swapping those dimensions of the kernel.
            # For channel separable convolutions, we can't currently perform anything
            # other than one filter per channel, so the last dimension needs to be of
            # length one. Since this happens to be the format that the op expects it,
            # we can skip the transpose in that case.
            if not self.channel_separable:
                kernel = array_ops.transpose(
                    kernel,
                    list(range(self._rank)) + [self._rank + 1, self._rank])

            # Compute shape of temporary.
            pad_shape = array_ops.shape(outputs)
            temp_shape = [pad_shape[0]] + (self._rank + 1) * [None]
            if self.data_format == "channels_last":
                spatial_axes = range(1, self._rank + 1)
                if self.channel_separable:
                    temp_shape[-1] = input_shape[-1]
                else:
                    temp_shape[-1] = self.filters
            else:
                spatial_axes = range(2, self._rank + 2)
                if self.channel_separable:
                    temp_shape[1] = input_shape[1]
                else:
                    temp_shape[1] = self.filters
            if self.extra_pad_end:
                get_length = lambda l, s, k: l * s + (k - 1)
            else:
                get_length = lambda l, s, k: l * s + (k - s)
            for i, a in enumerate(spatial_axes):
                temp_shape[a] = get_length(pad_shape[a], self.strides_up[i],
                                           self.kernel_support[i])

            # Compute convolution.
            if self._rank == 1 and not self.channel_separable:
                # There's no 1D transpose convolution op, so we insert an extra
                # dimension and use 2D.
                extradim = {
                    "channels_first": 2,
                    "channels_last": 1
                }[self.data_format]
                strides = self._pad_strides(self.strides_up)
                temp = array_ops.squeeze(
                    nn.conv2d_transpose(
                        array_ops.expand_dims(outputs, extradim),
                        array_ops.expand_dims(kernel, 0),
                        temp_shape[:extradim] + [1] + temp_shape[extradim:],
                        strides=strides[:extradim] + (1, ) +
                        strides[extradim:],
                        padding="VALID",
                        data_format=data_format.replace("W", "HW")),
                    [extradim])
            elif self._rank == 2 and self.channel_separable:
                temp = nn.depthwise_conv2d_native_backprop_input(
                    temp_shape,
                    kernel,
                    outputs,
                    strides=self._pad_strides(self.strides_up),
                    padding="VALID",
                    data_format=data_format)
            elif self._rank == 2 and not self.channel_separable:
                temp = nn.conv2d_transpose(outputs,
                                           kernel,
                                           temp_shape,
                                           strides=self._pad_strides(
                                               self.strides_up),
                                           padding="VALID",
                                           data_format=data_format)
            elif self._rank == 3 and not self.channel_separable:
                temp = nn.conv3d_transpose(outputs,
                                           kernel,
                                           temp_shape,
                                           strides=self._pad_strides(
                                               self.strides_up),
                                           padding="VALID",
                                           data_format=data_format)
            else:
                assert False  # Should never reach this.

            # Perform crop.
            slices = [slice(None)] * (self._rank + 2)
            if self.padding == "valid":
                # Take `kernel_support - 1` samples away from both sides. This leaves
                # just samples computed without padding.
                for i, a in enumerate(spatial_axes):
                    slices[a] = slice(
                        self.kernel_support[i] - 1,
                        None if self.kernel_support[i] == 1 else 1 -
                        self.kernel_support[i])
            else:
                # Take `kernel_support // 2` plus the padding away from beginning, and
                # crop end to input length multiplied by upsampling factor.
                for i, a in enumerate(spatial_axes):
                    offset = padding[a][0] * self.strides_up[i]
                    offset += self.kernel_support[i] // 2
                    length = get_length(input_shape[a], self.strides_up[i],
                                        offset + 1)
                    slices[a] = slice(offset, length)
            outputs = temp[slices]
        else:
            raise NotImplementedError(
                "The provided combination of SignalConv arguments is not currently "
                "implemented (kernel_support={}, corr={}, strides_down={}, "
                "strides_up={}, channel_separable={}, filters={}). "
                "Try using odd-length kernels or turning off separability?".
                format(self.kernel_support, self.corr, self.strides_down,
                       self.strides_up, self.channel_separable, self.filters))

        # Now, add bias if requested.
        if self.bias is not None:
            if self.data_format == "channels_first":
                # As of Mar 2017, direct addition is significantly slower than
                # bias_add when computing gradients.
                if self._rank == 1:
                    # nn.bias_add does not accept a 1D input tensor.
                    outputs = array_ops.expand_dims(outputs, 2)
                    outputs = nn.bias_add(outputs,
                                          self.bias,
                                          data_format="NCHW")
                    outputs = array_ops.squeeze(outputs, [2])
                elif self._rank == 2:
                    outputs = nn.bias_add(outputs,
                                          self.bias,
                                          data_format="NCHW")
                elif self._rank >= 3:
                    shape = array_ops.shape(outputs)
                    outputs = array_ops.reshape(outputs, shape[:3] + [-1])
                    outputs = nn.bias_add(outputs,
                                          self.bias,
                                          data_format="NCHW")
                    outputs = array_ops.reshape(outputs, shape)
            else:
                outputs = nn.bias_add(outputs, self.bias)

        # Finally, pass through activation function if requested.
        if self.activation is not None:
            outputs = self.activation(outputs)  # pylint:disable=not-callable

        # Aid shape inference, for some reason shape info is not always available.
        if not context.executing_eagerly():
            outputs.set_shape(self.compute_output_shape(inputs.shape))

        return outputs
Esempio n. 51
0
def conv2d_same(inputs, num_outputs, kernel_size, stride, rate=1, scope=None):
  """Strided 2-D convolution with 'SAME' padding.

  When stride > 1, then we do explicit zero-padding, followed by conv2d with
  'VALID' padding.

  Note that

     net = conv2d_same(inputs, num_outputs, 3, stride=stride)

  is equivalent to

     net = tf.contrib.layers.conv2d(inputs, num_outputs, 3, stride=1,
     padding='SAME')
     net = subsample(net, factor=stride)

  whereas

     net = tf.contrib.layers.conv2d(inputs, num_outputs, 3, stride=stride,
     padding='SAME')

  is different when the input's height or width is even, which is why we add the
  current function. For more details, see ResnetUtilsTest.testConv2DSameEven().

  Args:
    inputs: A 4-D tensor of size [batch, height_in, width_in, channels].
    num_outputs: An integer, the number of output filters.
    kernel_size: An int with the kernel_size of the filters.
    stride: An integer, the output stride.
    rate: An integer, rate for atrous convolution.
    scope: Scope.

  Returns:
    output: A 4-D tensor of size [batch, height_out, width_out, channels] with
      the convolution output.
  """
  if stride == 1:
    return layers_lib.conv2d(
        inputs,
        num_outputs,
        kernel_size,
        stride=1,
        rate=rate,
        padding='SAME',
        scope=scope)
  else:
    pad_beg = range(2)
    pad_end = range(2)
    for i in range(2):
      kernel_size_effective = kernel_size[i] + (kernel_size[i] - 1) * (rate - 1)
      pad_total = kernel_size_effective - 1
      pad_beg[i] = pad_total // 2
      pad_end[i] = pad_total - pad_beg[i]
    inputs = array_ops.pad(
        inputs, [[0, 0], [pad_beg[0], pad_end[0]], [pad_beg[1], pad_end[1]], [0, 0]])
    return layers_lib.conv2d(
        inputs,
        num_outputs,
        kernel_size,
        stride=stride,
        rate=rate,
        padding='VALID',
        scope=scope)
Esempio n. 52
0
 def testPaddingsDim4(self):
     with self.test_session(use_gpu=True):
         with self.assertRaises(ValueError):
             array_ops.pad(
                 array_ops.reshape([1, 2], shape=[1, 2]),
                 array_ops.reshape([1, 2, 3, 4, 5, 6], shape=[3, 2]))
Esempio n. 53
0
 def pad(x):
     return array_ops.pad(x,
                          ops.convert_to_tensor(a, paddings_dtype),
                          mode=mode,
                          constant_values=constant_values)
Esempio n. 54
0
def _RightShift(x):
  """Shifts next-to-last dimension to the right, adding zero on the left."""
  rank = array_ops.rank(x)
  zeros = array_ops.zeros((rank - 2, 2), dtype=dtypes.int32)
  pad = array_ops.concat([zeros, array_ops.constant([[1, 0], [0, 0]])], axis=0)
  return array_ops.pad(x[..., :-1, :], pad)
Esempio n. 55
0
 def testInvalid(self):
     with self.cached_session():
         x = [[1, 2, 3], [4, 5, 6]]
         with self.assertRaisesRegex(ValueError, "Unknown padding mode"):
             self.evaluate(array_ops.pad(x, [[1, 0], [2, 1]], mode="weird"))
Esempio n. 56
0
  def predict(self, features):
    """Computes predictions multiple steps into the future.

    Args:
      features: A dictionary with the following key/value pairs:
        PredictionFeatures.TIMES: A [batch size, predict window size]
          integer Tensor of times, after the window of data indicated by
          `STATE_TUPLE`, to make predictions for.
        PredictionFeatures.STATE_TUPLE: A tuple of (times, values), times with
          shape [batch size, self.input_window_size], values with shape [batch
          size, self.input_window_size, self.num_features] representing a
          segment of the time series before `TIMES`. This data is used
          to start of the autoregressive computation. This should have data for
          at least self.input_window_size timesteps.
        And any exogenous features, with shapes prefixed by shape of `TIMES`.
    Returns:
      A dictionary with keys, "mean", "covariance". The
      values are Tensors of shape [batch_size, predict window size,
      num_features] and correspond to the values passed in `TIMES`.
    """
    if not self._graph_initialized:
      self.initialize_graph()
    predict_times = math_ops.cast(
        ops.convert_to_tensor(features[PredictionFeatures.TIMES]), dtypes.int32)
    exogenous_regressors = self._process_exogenous_features(
        times=predict_times,
        features={key: value for key, value in features.items()
                  if key not in [TrainEvalFeatures.TIMES,
                                 TrainEvalFeatures.VALUES,
                                 PredictionFeatures.STATE_TUPLE]})
    with ops.control_dependencies(
        [check_ops.assert_equal(array_ops.shape(predict_times)[1],
                                array_ops.shape(exogenous_regressors)[1])]):
      exogenous_regressors = array_ops.identity(exogenous_regressors)
    batch_size = array_ops.shape(predict_times)[0]
    num_predict_values = array_ops.shape(predict_times)[1]
    prediction_iterations = ((num_predict_values + self.output_window_size - 1)
                             // self.output_window_size)
    # Pad predict_times and exogenous regressors so as to have exact multiple of
    # self.output_window_size values per example.
    padding_size = (prediction_iterations * self.output_window_size -
                    num_predict_values)
    predict_times = array_ops.pad(
        predict_times, [[0, 0], [0, padding_size]])
    exogenous_regressors = array_ops.pad(
        exogenous_regressors, [[0, 0], [0, padding_size], [0, 0]])
    state = features[PredictionFeatures.STATE_TUPLE]
    (state_times, state_values, state_exogenous_regressors) = state
    state_times = math_ops.cast(
        ops.convert_to_tensor(state_times), dtypes.int32)
    state_values = ops.convert_to_tensor(state_values, dtype=self.dtype)
    state_exogenous_regressors = ops.convert_to_tensor(
        state_exogenous_regressors, dtype=self.dtype)

    initial_input_times = predict_times[:, :self.output_window_size]
    initial_input_exogenous_regressors = (
        exogenous_regressors[:, :self.output_window_size, :])
    if self.input_window_size > 0:
      initial_input_times = array_ops.concat(
          [state_times[:, -self.input_window_size:], initial_input_times], 1)
      values_size = array_ops.shape(state_values)[1]
      times_size = array_ops.shape(state_times)[1]
      with ops.control_dependencies([
          check_ops.assert_greater_equal(values_size, self.input_window_size),
          check_ops.assert_equal(values_size, times_size)
      ]):
        initial_input_values = state_values[:, -self.input_window_size:, :]
        initial_input_exogenous_regressors = array_ops.concat(
            [state_exogenous_regressors[:, -self.input_window_size:, :],
             initial_input_exogenous_regressors[
                 :, :self.output_window_size, :]],
            axis=1)
    else:
      initial_input_values = 0

    # Iterate over the predict_times, predicting self.output_window_size values
    # in each iteration.
    def _while_condition(iteration_number, *unused_args):
      return math_ops.less(iteration_number, prediction_iterations)

    def _while_body(iteration_number, input_times, input_values,
                    input_exogenous_regressors, mean_ta, covariance_ta):
      """Predict self.output_window_size values."""
      prediction_ops = self.prediction_ops(
          input_times, input_values, input_exogenous_regressors)
      predicted_mean = prediction_ops["mean"]
      predicted_covariance = prediction_ops["covariance"]
      offset = self.output_window_size * gen_math_ops.minimum(
          iteration_number + 1, prediction_iterations - 1)
      if self.input_window_size > 0:
        if self.output_window_size < self.input_window_size:
          new_input_values = array_ops.concat(
              [input_values[:, self.output_window_size:, :], predicted_mean], 1)
          new_input_exogenous_regressors = array_ops.concat(
              [input_exogenous_regressors[:, -self.input_window_size:, :],
               exogenous_regressors[
                   :, offset:offset + self.output_window_size, :]],
              axis=1)
          new_input_times = array_ops.concat([
              input_times[:, -self.input_window_size:],
              predict_times[:, offset:offset + self.output_window_size]
          ], 1)
        else:
          new_input_values = predicted_mean[:, -self.input_window_size:, :]
          new_input_exogenous_regressors = exogenous_regressors[
              :,
              offset - self.input_window_size:offset + self.output_window_size,
              :]
          new_input_times = predict_times[
              :,
              offset - self.input_window_size:offset + self.output_window_size]
      else:
        new_input_values = input_values
        new_input_exogenous_regressors = exogenous_regressors[
            :, offset:offset + self.output_window_size, :]
        new_input_times = predict_times[:,
                                        offset:offset + self.output_window_size]
      new_input_times.set_shape(initial_input_times.get_shape())
      new_input_exogenous_regressors.set_shape(
          initial_input_exogenous_regressors.get_shape())
      new_mean_ta = mean_ta.write(iteration_number, predicted_mean)
      if isinstance(covariance_ta, tensor_array_ops.TensorArray):
        new_covariance_ta = covariance_ta.write(iteration_number,
                                                predicted_covariance)
      else:
        new_covariance_ta = covariance_ta
      return (iteration_number + 1,
              new_input_times,
              new_input_values,
              new_input_exogenous_regressors,
              new_mean_ta,
              new_covariance_ta)

    # Note that control_flow_ops.while_loop doesn't seem happy with None. Hence
    # using 0 for cases where we don't want to predict covariance.
    covariance_ta_init = (tensor_array_ops.TensorArray(
        dtype=self.dtype, size=prediction_iterations)
                          if self.loss != ARModel.SQUARED_LOSS else 0.)
    mean_ta_init = tensor_array_ops.TensorArray(
        dtype=self.dtype, size=prediction_iterations)
    _, _, _, _, mean_ta, covariance_ta = control_flow_ops.while_loop(
        _while_condition, _while_body, [
            0,
            initial_input_times,
            initial_input_values,
            initial_input_exogenous_regressors,
            mean_ta_init,
            covariance_ta_init
        ])

    def _parse_ta(values_ta):
      """Helper function to parse the returned TensorArrays."""

      if not isinstance(values_ta, tensor_array_ops.TensorArray):
        return None
      predictions_length = prediction_iterations * self.output_window_size
      # Shape [prediction_iterations, batch_size, self.output_window_size,
      #        self.num_features]
      values_packed = values_ta.stack()
      # Transpose to move batch dimension outside.
      output_values = array_ops.reshape(
          array_ops.transpose(values_packed, [1, 0, 2, 3]),
          array_ops.stack([batch_size, predictions_length, -1]))
      # Clip to desired size
      return output_values[:, :num_predict_values, :]

    predicted_mean = _parse_ta(mean_ta)
    predicted_covariance = _parse_ta(covariance_ta)
    if predicted_covariance is None:
      predicted_covariance = array_ops.ones_like(predicted_mean)

    # Transform and scale the mean and covariance appropriately.
    predicted_mean = self._scale_back_data(predicted_mean)
    predicted_covariance = self._scale_back_variance(predicted_covariance)

    return {"mean": predicted_mean,
            "covariance": predicted_covariance}
Esempio n. 57
0
 def testMirrorPad(self):
     mirror_pad = lambda t, paddings: array_ops.pad(t, paddings, "REFLECT")
     for dtype in self.numeric_types:
         self._testBinary(
             mirror_pad,
             np.array(
                 [
                     [1, 2, 3],  #
                     [4, 5, 6],  #
                 ],
                 dtype=dtype),
             np.array([[
                 1,
                 1,
             ], [2, 2]], dtype=np.int32),
             expected=np.array(
                 [
                     [6, 5, 4, 5, 6, 5, 4],  #
                     [3, 2, 1, 2, 3, 2, 1],  #
                     [6, 5, 4, 5, 6, 5, 4],  #
                     [3, 2, 1, 2, 3, 2, 1]
                 ],
                 dtype=dtype))
         self._testBinary(mirror_pad,
                          np.array([[1, 2, 3], [4, 5, 6]], dtype=dtype),
                          np.array([[0, 0], [0, 0]], dtype=np.int32),
                          expected=np.array([[1, 2, 3], [4, 5, 6]],
                                            dtype=dtype))
         self._testBinary(
             mirror_pad,
             np.array(
                 [
                     [1, 2, 3],  #
                     [4, 5, 6],  #
                     [7, 8, 9]
                 ],
                 dtype=dtype),
             np.array([[2, 2], [0, 0]], dtype=np.int32),
             expected=np.array(
                 [
                     [7, 8, 9],  #
                     [4, 5, 6],  #
                     [1, 2, 3],  #
                     [4, 5, 6],  #
                     [7, 8, 9],  #
                     [4, 5, 6],  #
                     [1, 2, 3]
                 ],
                 dtype=dtype))
         self._testBinary(
             mirror_pad,
             np.array([
                 [[1, 2, 3], [4, 5, 6]],
                 [[7, 8, 9], [10, 11, 12]],
             ],
                      dtype=dtype),
             np.array([[0, 0], [1, 1], [1, 1]], dtype=np.int32),
             expected=np.array(
                 [
                     [
                         [5, 4, 5, 6, 5],  #
                         [2, 1, 2, 3, 2],  #
                         [5, 4, 5, 6, 5],  #
                         [2, 1, 2, 3, 2],  #
                     ],
                     [
                         [11, 10, 11, 12, 11],  #
                         [8, 7, 8, 9, 8],  #
                         [11, 10, 11, 12, 11],  #
                         [8, 7, 8, 9, 8],  #
                     ]
                 ],
                 dtype=dtype))