class_docstr: Base implementation of unsupervised GraphSAGE
class_docstr_tok: ["Base","implementation","of","unsupervised","GraphSAGE"]
docstr: At each layer, aggregate hidden representations of neighbors to compute the hidden representations 
      at next layer.
  Args:
      samples: a list of samples of variable hops away for convolving at each layer of the
          network. Length is the number of layers + 1. Each is a vector of node indices.
      input_features: the input features for each sample of various hops away.
      dims: a list of dimensions of the hidden representations from the input layer to the
          final layer. Length is the number of layers + 1.
      num_samples: list of number of samples for each layer.
      support_sizes: the number of nodes to gather information from for each layer.
      batch_size: the number of inputs (different for batch inputs and negative samples).
  Returns:
      The hidden representation at the final layer for all nodes in batch
docstr_tok: ["At","each","layer",",","aggregate","hidden","representations","of","neighbors","to","compute","the","hidden","representations","at","next","layer",".","Args",":","samples",":","a","list","of","samples","of","variable","hops","away","for","convolving","at","each","layer","of","the","network",".","Length","is","the","number","of","layers","+","1",".","Each","is","a","vector","of","node","indices",".","input_features",":","the","input","features","for","each","sample","of","various","hops","away",".","dims",":","a","list","of","dimensions","of","the","hidden","representations","from","the","input","layer","to","the","final","layer",".","Length","is","the","number","of","layers","+","1.","num_samples",":","list","of","number","of","samples","for","each","layer",".","support_sizes",":","the","number","of","nodes","to","gather","information","from","for","each","layer",".","batch_size",":","the","number","of","inputs","(","different","for","batch","inputs","and","negative","samples",")",".","Returns",":","The","hidden","representation","at","the","final","layer","for","all","nodes","in","batch"]
code: def aggregate(
      self,
      samples,
      input_features,
      dims,
      num_samples,
      support_sizes,
      batch_size=None,
      aggregators=None,
      name=None,
      concat=False,
      model_size="small",
  ):
      """At each layer, aggregate hidden representations of neighbors to compute the hidden representations
          at next layer.
      Args:
          samples: a list of samples of variable hops away for convolving at each layer of the
              network. Length is the number of layers + 1. Each is a vector of node indices.
          input_features: the input features for each sample of various hops away.
          dims: a list of dimensions of the hidden representations from the input layer to the
              final layer. Length is the number of layers + 1.
          num_samples: list of number of samples for each layer.
          support_sizes: the number of nodes to gather information from for each layer.
          batch_size: the number of inputs (different for batch inputs and negative samples).
      Returns:
          The hidden representation at the final layer for all nodes in batch
      """
  
      if batch_size is None:
          batch_size = self.batch_size
  
      # length: number of layers + 1
      hidden = [
          tf.nn.embedding_lookup(input_features, node_samples)
          for node_samples in samples
      ]
      new_agg = aggregators is None
      if new_agg:
          aggregators = []
      for layer in range(len(num_samples)):
          if new_agg:
              dim_mult = 2 if concat and (layer != 0) else 1
              # aggregator at current layer
              if layer == len(num_samples) - 1:
                  aggregator = self.aggregator_cls(
                      dim_mult * dims[layer],
                      dims[layer + 1],
                      act=lambda x: x,
                      dropout=self.placeholders["dropout"],
                      name=name,
                      concat=concat,
                      model_size=model_size,
                  )
              else:
                  aggregator = self.aggregator_cls(
                      dim_mult * dims[layer],
                      dims[layer + 1],
                      dropout=self.placeholders["dropout"],
                      name=name,
                      concat=concat,
                      model_size=model_size,
                  )
              aggregators.append(aggregator)
          else:
              aggregator = aggregators[layer]
          # hidden representation at current layer for all support nodes that are various hops away
          next_hidden = []
          # as layer increases, the number of support nodes needed decreases
          for hop in range(len(num_samples) - layer):
              dim_mult = 2 if concat and (layer != 0) else 1
              neigh_dims = [
                  batch_size * support_sizes[hop],
                  num_samples[len(num_samples) - hop - 1],
                  dim_mult * dims[layer],
              ]
              h = aggregator(
                  (hidden[hop], tf.reshape(hidden[hop + 1], neigh_dims))
              )
              next_hidden.append(h)
          hidden = next_hidden
      return hidden[0], aggregators
  
imports: from collections import namedtuple
  import tensorflow
  import math
  import graphsage.layers
  import graphsage.metrics
  from .prediction import BipartiteEdgePredLayer
  from .aggregators import MeanAggregator, MaxPoolingAggregator, MeanPoolingAggregator, SeqAggregator, GCNAggregator
label_desc: Use image node_id 3 for calling the SampleAndAggregate obj's underlying member method code with example usage: obj.aggregate(samples, input_features, dims, num_samples, support_sizes, batch_size, aggregators, name, concat, model_size) and returns: hidden,  aggregators