Commit b4303810 authored by peastman's avatar peastman
Browse files

Redesigned Gather layer

parent 73dd9b9b
Loading
Loading
Loading
Loading
+36 −18
Original line number Diff line number Diff line
@@ -301,7 +301,7 @@ class Dense(Layer):
    self.time_series = time_series
    try:
      parent_shape = self.in_layers[0].shape
      self._shape = tuple(parent_shape[:-1] + [out_channels])
      self._shape = tuple(parent_shape[:-1]) + (out_channels,)
    except:
      pass
    self._reuse = False
@@ -518,15 +518,22 @@ class Repeat(Layer):


class Gather(Layer):
  """Gather slices from the input."""
  """Gather elements or slices from the input."""

  def __init__(self, in_layers=None, indices=None, axis=0, **kwargs):
  def __init__(self, in_layers=None, indices=None, **kwargs):
    """Create a Gather layer.

    The slice indices may be specified in two ways.  If the indices are constants,
    you can pass them to this constructor as a list or array.  Alternatively, the
    indices can be calculated by another layer.  In that case, pass None for indices,
    and instead provide them as the second input layer.
    The indices can be viewed as a list of element identifiers, where each
    identifier is itself a length N array specifying the indices of the
    first N dimensions of the input tensor.  Those elements (or slices, depending
    on the shape of the input) are then stacked together.  For example,
    indices=[[0],[2],[4]] will produce [input[0], input[2], input[4]], while
    indices=[[1,2]] will produce [input[1,2]].

    The indices may be specified in two ways.  If they are constants, you can pass
    them to this constructor as a list or array.  Alternatively, the indices can
    be calculated by another layer.  In that case, pass None for indices, and
    instead provide them as the second input layer.

    Parameters
    ----------
@@ -537,19 +544,16 @@ class Gather(Layer):
    indices: array
      the slice indices (if they are constants) or None (if the indices are provided by
      an input)
    axis: int
      the axis along which to select slices.  The indices refer to positions along this axis.
    """
    self.indices = indices
    self.axis = axis
    super(Gather, self).__init__(in_layers, **kwargs)
    try:
      s = list(self.in_layers[0].shape)
      s = tuple(self.in_layers[0].shape)
      if indices is None:
        s[axis] = None
        s2 = self.in_layers[1].shape
        self._shape = (s2[0],) + s[s2[-1]:]
      else:
        s[axis] = len(indices)
      self._shape = tuple(s)
        self._shape = (len(indices),) + s[np.array(indices).shape[-1]:]
    except:
      pass

@@ -564,7 +568,7 @@ class Gather(Layer):
        raise ValueError("Must have one parent")
      indices = self.indices
    parent_tensor = inputs[0]
    out_tensor = tf.gather(parent_tensor, indices, axis=self.axis)
    out_tensor = tf.gather_nd(parent_tensor, indices)
    if set_tensors:
      self.out_tensor = out_tensor
    return out_tensor
@@ -860,6 +864,14 @@ class Variable(Layer):
    return out_tensor


def _max_dimension(x, y):
  if x is None:
    return y
  if y is None:
    return x
  return max(x, y)


class Add(Layer):
  """Compute the (optionally weighted) sum of the input layers."""

@@ -881,7 +893,7 @@ class Add(Layer):
        shape2, shape1 = shape1, shape2
      offset = len(shape1) - len(shape2)
      for i in range(len(shape2)):
        shape1[i + offset] = max(shape1[i + offset], shape2[i])
        shape1[i + offset] = _max_dimension(shape1[i + offset], shape2[i])
      self._shape = tuple(shape1)
    except:
      pass
@@ -916,7 +928,7 @@ class Multiply(Layer):
        shape2, shape1 = shape1, shape2
      offset = len(shape1) - len(shape2)
      for i in range(len(shape2)):
        shape1[i + offset] = max(shape1[i + offset], shape2[i])
        shape1[i + offset] = _max_dimension(shape1[i + offset], shape2[i])
      self._shape = tuple(shape1)
    except:
      pass
@@ -937,7 +949,7 @@ class Log(Layer):
  def __init__(self, in_layers=None, **kwargs):
    super(Log, self).__init__(in_layers, **kwargs)
    try:
      self._shape = in_layers[0].shape
      self._shape = self.in_layers[0].shape
    except:
      pass

@@ -1026,6 +1038,8 @@ class SoftMaxCrossEntropy(Layer):
class ReduceMean(Layer):

  def __init__(self, in_layers=None, axis=None, **kwargs):
    if axis is not None and not isinstance(axis, Sequence):
      axis = [axis]
    self.axis = axis
    super(ReduceMean, self).__init__(in_layers, **kwargs)
    if axis is None:
@@ -1074,6 +1088,8 @@ class ToFloat(Layer):
class ReduceSum(Layer):

  def __init__(self, in_layers=None, axis=None, **kwargs):
    if axis is not None and not isinstance(axis, Sequence):
      axis = [axis]
    self.axis = axis
    super(ReduceSum, self).__init__(in_layers, **kwargs)
    if axis is None:
@@ -1103,6 +1119,8 @@ class ReduceSum(Layer):
class ReduceSquareDifference(Layer):

  def __init__(self, in_layers=None, axis=None, **kwargs):
    if axis is not None and not isinstance(axis, Sequence):
      axis = [axis]
    self.axis = axis
    super(ReduceSquareDifference, self).__init__(in_layers, **kwargs)
    if axis is None:
+4 −4
Original line number Diff line number Diff line
@@ -153,10 +153,10 @@ class TestLayers(test_util.TensorFlowTestCase):
    """Test that Gather can be invoked."""
    in_tensor = np.random.uniform(size=(5, 4)).astype(np.float32)
    with self.test_session() as sess:
      out_tensor = Gather(indices=[2, 3], axis=0)(in_tensor).eval()
      assert np.array_equal(in_tensor[[2, 3]], out_tensor)
      out_tensor = Gather(axis=1)(in_tensor, np.array([1, 3])).eval()
      assert np.array_equal(in_tensor[:, [1, 3]], out_tensor)
      out_tensor = Gather(indices=[[2], [3]])(in_tensor).eval()
      assert np.array_equal([in_tensor[2], in_tensor[3]], out_tensor)
      out_tensor = Gather()(in_tensor, np.array([[1, 1], [0, 3]])).eval()
      assert np.array_equal([in_tensor[1, 1], in_tensor[0, 3]], out_tensor)

  def test_gru(self):
    """Test that GRU can be invoked."""
+1 −1
Original line number Diff line number Diff line
@@ -94,7 +94,7 @@ def test_Repeat_pickle():
def test_Gather_pickle():
  tg = TensorGraph()
  feature = Feature(shape=(tg.batch_size, 1))
  layer = Gather(indices=[0, 2, 3], in_layers=feature)
  layer = Gather(indices=[[0], [2], [3]], in_layers=feature)
  tg.add_output(layer)
  tg.set_loss(layer)
  tg.build()