def tile_anchors(grid_height,
                 grid_width,
                 scales,
                 aspect_ratios,
                 base_anchor_size,
                 anchor_stride,
                 anchor_offset):
 
  ratio_sqrts = tf.sqrt(aspect_ratios)
  heights = scales / ratio_sqrts * base_anchor_size[0]
  widths = scales * ratio_sqrts * base_anchor_size[1]

  # Get a grid of box centers
  y_centers = tf.cast(tf.range(grid_height), dtype=tf.float32)
  y_centers = y_centers * anchor_stride[0] + anchor_offset[0]
  x_centers = tf.cast(tf.range(grid_width), dtype=tf.float32)
  x_centers = x_centers * anchor_stride[1] + anchor_offset[1]
  x_centers, y_centers = ops.meshgrid(x_centers, y_centers)

  widths_grid, x_centers_grid = ops.meshgrid(widths, x_centers)
  heights_grid, y_centers_grid = ops.meshgrid(heights, y_centers)
  bbox_centers = tf.stack([y_centers_grid, x_centers_grid], axis=3)
  bbox_sizes = tf.stack([heights_grid, widths_grid], axis=3)
  bbox_centers = tf.reshape(bbox_centers, [-1, 2])
  bbox_sizes = tf.reshape(bbox_sizes, [-1, 2])
  bbox_corners = _center_size_bbox_to_corners_bbox(bbox_centers, bbox_sizes)
  return box_list.BoxList(bbox_corners)
Esempio n. 2
0
def tile_anchors(grid_height,
                 grid_width,
                 scales,
                 aspect_ratios,
                 base_anchor_size,
                 anchor_stride,
                 anchor_offset):
  """Create a tiled set of anchors strided along a grid in image space.

  This op creates a set of anchor boxes by placing a "basis" collection of
  boxes with user-specified scales and aspect ratios centered at evenly
  distributed points along a grid.  The basis collection is specified via the
  scale and aspect_ratios arguments.  For example, setting scales=[.1, .2, .2]
  and aspect ratios = [2,2,1/2] means that we create three boxes: one with scale
  .1, aspect ratio 2, one with scale .2, aspect ratio 2, and one with scale .2
  and aspect ratio 1/2.  Each box is multiplied by "base_anchor_size" before
  placing it over its respective center.

  Grid points are specified via grid_height, grid_width parameters as well as
  the anchor_stride and anchor_offset parameters.

  Args:
    grid_height: size of the grid in the y direction (int or int scalar tensor)
    grid_width: size of the grid in the x direction (int or int scalar tensor)
    scales: a 1-d  (float) tensor representing the scale of each box in the
      basis set.
    aspect_ratios: a 1-d (float) tensor representing the aspect ratio of each
      box in the basis set.  The length of the scales and aspect_ratios tensors
      must be equal.
    base_anchor_size: base anchor size as [height, width]
      (float tensor of shape [2])
    anchor_stride: difference in centers between base anchors for adjacent grid
                   positions (float tensor of shape [2])
    anchor_offset: center of the anchor with scale and aspect ratio 1 for the
                   upper left element of the grid, this should be zero for
                   feature networks with only VALID padding and even receptive
                   field size, but may need some additional calculation if other
                   padding is used (float tensor of shape [2])
  Returns:
    a BoxList holding a collection of N anchor boxes
  """
  ratio_sqrts = tf.sqrt(aspect_ratios)
  heights = scales / ratio_sqrts * base_anchor_size[0]
  widths = scales * ratio_sqrts * base_anchor_size[1]

  # Get a grid of box centers
  y_centers = tf.to_float(tf.range(grid_height))
  y_centers = y_centers * anchor_stride[0] + anchor_offset[0]
  x_centers = tf.to_float(tf.range(grid_width))
  x_centers = x_centers * anchor_stride[1] + anchor_offset[1]
  x_centers, y_centers = ops.meshgrid(x_centers, y_centers)

  widths_grid, x_centers_grid = ops.meshgrid(widths, x_centers)
  heights_grid, y_centers_grid = ops.meshgrid(heights, y_centers)
  bbox_centers = tf.stack([y_centers_grid, x_centers_grid], axis=3)
  bbox_sizes = tf.stack([heights_grid, widths_grid], axis=3)
  bbox_centers = tf.reshape(bbox_centers, [-1, 2])
  bbox_sizes = tf.reshape(bbox_sizes, [-1, 2])
  bbox_corners = _center_size_bbox_to_corners_bbox(bbox_centers, bbox_sizes)
  return box_list.BoxList(bbox_corners)
def tile_anchors(grid_height, grid_width, scales, aspect_ratios,
                 base_anchor_size, anchor_stride, anchor_offset):
    """Create a tiled set of anchors strided along a grid in image space.

  This op creates a set of anchor boxes by placing a "basis" collection of
  boxes with user-specified scales and aspect ratios centered at evenly
  distributed points along a grid.  The basis collection is specified via the
  scale and aspect_ratios arguments.  For example, setting scales=[.1, .2, .2]
  and aspect ratios = [2,2,1/2] means that we create three boxes: one with scale
  .1, aspect ratio 2, one with scale .2, aspect ratio 2, and one with scale .2
  and aspect ratio 1/2.  Each box is multiplied by "base_anchor_size" before
  placing it over its respective center.

  Grid points are specified via grid_height, grid_width parameters as well as
  the anchor_stride and anchor_offset parameters.

  Args:
    grid_height: size of the grid in the y direction (int or int scalar tensor)
    grid_width: size of the grid in the x direction (int or int scalar tensor)
    scales: a 1-d  (float) tensor representing the scale of each box in the
      basis set.
    aspect_ratios: a 1-d (float) tensor representing the aspect ratio of each
      box in the basis set.  The length of the scales and aspect_ratios tensors
      must be equal.
    base_anchor_size: base anchor size as [height, width]
      (float tensor of shape [2])
    anchor_stride: difference in centers between base anchors for adjacent grid
                   positions (float tensor of shape [2])
    anchor_offset: center of the anchor with scale and aspect ratio 1 for the
                   upper left element of the grid, this should be zero for
                   feature networks with only VALID padding and even receptive
                   field size, but may need some additional calculation if other
                   padding is used (float tensor of shape [2])
  Returns:
    a BoxList holding a collection of N anchor boxes
  """
    ratio_sqrts = tf.sqrt(aspect_ratios)
    heights = scales / ratio_sqrts * base_anchor_size[0]
    widths = scales * ratio_sqrts * base_anchor_size[1]

    # Get a grid of box centers
    y_centers = tf.cast(tf.range(grid_height), dtype=tf.float32)
    y_centers = y_centers * anchor_stride[0] + anchor_offset[0]
    x_centers = tf.cast(tf.range(grid_width), dtype=tf.float32)
    x_centers = x_centers * anchor_stride[1] + anchor_offset[1]
    x_centers, y_centers = ops.meshgrid(x_centers, y_centers)

    widths_grid, x_centers_grid = ops.meshgrid(widths, x_centers)
    heights_grid, y_centers_grid = ops.meshgrid(heights, y_centers)
    bbox_centers = tf.stack([y_centers_grid, x_centers_grid], axis=3)
    bbox_sizes = tf.stack([heights_grid, widths_grid], axis=3)
    bbox_centers = tf.reshape(bbox_centers, [-1, 2])
    bbox_sizes = tf.reshape(bbox_sizes, [-1, 2])
    bbox_corners = _center_size_bbox_to_corners_bbox(bbox_centers, bbox_sizes)
    c = bbox_corners
    #print(c)
    #with tf.Session() as sess:
    #  print(sess.run(c))
    #  sess.close()
    return box_list.BoxList(bbox_corners)
Esempio n. 4
0
  def test_meshgrid_multidimensional(self):
    np.random.seed(18)
    x = np.random.rand(4, 1, 2).astype(np.float32)
    y = np.random.rand(2, 3).astype(np.float32)

    xgrid, ygrid = ops.meshgrid(x, y)

    grid_shape = list(y.shape) + list(x.shape)
    self.assertEqual(xgrid.get_shape().as_list(), grid_shape)
    self.assertEqual(ygrid.get_shape().as_list(), grid_shape)
    with self.test_session() as sess:
      xgrid_output, ygrid_output = sess.run([xgrid, ygrid])

    # Check the shape of the output grids
    self.assertEqual(xgrid_output.shape, tuple(grid_shape))
    self.assertEqual(ygrid_output.shape, tuple(grid_shape))

    # Check a few elements
    test_elements = [((3, 0, 0), (1, 2)),
                     ((2, 0, 1), (0, 0)),
                     ((0, 0, 0), (1, 1))]
    for xind, yind in test_elements:
      # These are float equality tests, but the meshgrid op should not introduce
      # rounding.
      self.assertEqual(xgrid_output[yind + xind], x[xind])
      self.assertEqual(ygrid_output[yind + xind], y[yind])
 def _generate(self, feature_map_shape_list):
     """Generates a collection of bounding boxes to be used as anchors.
     Args:
       feature_map_shape_list: list of pairs of convnet layer resolutions in the
         format [(height_0, width_0)].  For example, setting
         feature_map_shape_list=[(8, 8)] asks for anchors that correspond
         to an 8x8 layer.  For this anchor generator, only lists of length 1 are
         allowed.
     Returns:
       boxes: a BoxList holding a collection of N anchor boxes
     Raises:
       ValueError: if feature_map_shape_list, box_specs_list do not have the same
         length.
       ValueError: if feature_map_shape_list does not consist of pairs of
         integers
     """
     if not (isinstance(feature_map_shape_list, list)
             and len(feature_map_shape_list) == 1):
         raise ValueError(
             'feature_map_shape_list must be a list of length 1.')
     if not all([
             isinstance(list_item, tuple) and len(list_item) == 2
             for list_item in feature_map_shape_list
     ]):
         raise ValueError('feature_map_shape_list must be a list of pairs.')
     grid_height, grid_width = feature_map_shape_list[0]
     scales_grid, aspect_ratios_grid = ops.meshgrid(self._scales,
                                                    self._aspect_ratios)
     scales_grid = tf.reshape(scales_grid, [-1])
     aspect_ratios_grid = tf.reshape(aspect_ratios_grid, [-1])
     return tile_anchors(grid_height, grid_width, scales_grid,
                         aspect_ratios_grid, self._base_anchor_size,
                         self._anchor_stride, self._anchor_offset)
Esempio n. 6
0
  def test_meshgrid_multidimensional(self):
    np.random.seed(18)
    x = np.random.rand(4, 1, 2).astype(np.float32)
    y = np.random.rand(2, 3).astype(np.float32)

    xgrid, ygrid = ops.meshgrid(x, y)

    grid_shape = list(y.shape) + list(x.shape)
    self.assertEqual(xgrid.get_shape().as_list(), grid_shape)
    self.assertEqual(ygrid.get_shape().as_list(), grid_shape)
    with self.test_session() as sess:
      xgrid_output, ygrid_output = sess.run([xgrid, ygrid])

    # Check the shape of the output grids
    self.assertEqual(xgrid_output.shape, tuple(grid_shape))
    self.assertEqual(ygrid_output.shape, tuple(grid_shape))

    # Check a few elements
    test_elements = [((3, 0, 0), (1, 2)),
                     ((2, 0, 1), (0, 0)),
                     ((0, 0, 0), (1, 1))]
    for xind, yind in test_elements:
      # These are float equality tests, but the meshgrid op should not introduce
      # rounding.
      self.assertEqual(xgrid_output[yind + xind], x[xind])
      self.assertEqual(ygrid_output[yind + xind], y[yind])
    def _generate(self, feature_map_shape_list):
        """Generates a collection of bounding boxes to be used as anchors.

    Args:
      feature_map_shape_list: list of pairs of convnet layer resolutions in the
        format [(height_0, width_0)].  For example, setting
        feature_map_shape_list=[(8, 8)] asks for anchors that correspond
        to an 8x8 layer.  For this anchor generator, only lists of length 1 are
        allowed.

    Returns:
      boxes_list: a list of BoxLists each holding anchor boxes corresponding to
        the input feature map shapes.

    Raises:
      ValueError: if feature_map_shape_list, box_specs_list do not have the same
        length.
      ValueError: if feature_map_shape_list does not consist of pairs of
        integers
    """
        if not (isinstance(feature_map_shape_list, list)
                and len(feature_map_shape_list) == 1):
            raise ValueError(
                'feature_map_shape_list must be a list of length 1.')
        if not all([
                isinstance(list_item, tuple) and len(list_item) == 2
                for list_item in feature_map_shape_list
        ]):
            raise ValueError('feature_map_shape_list must be a list of pairs.')

        # Create constants in init_scope so they can be created in tf.functions
        # and accessed from outside of the function.
        with tf.init_scope():
            self._base_anchor_size = tf.cast(tf.convert_to_tensor(
                self._base_anchor_size),
                                             dtype=tf.float32)
            self._anchor_stride = tf.cast(tf.convert_to_tensor(
                self._anchor_stride),
                                          dtype=tf.float32)
            self._anchor_offset = tf.cast(tf.convert_to_tensor(
                self._anchor_offset),
                                          dtype=tf.float32)

        grid_height, grid_width = feature_map_shape_list[0]
        scales_grid, aspect_ratios_grid = ops.meshgrid(self._scales,
                                                       self._aspect_ratios)
        scales_grid = tf.reshape(scales_grid, [-1])
        aspect_ratios_grid = tf.reshape(aspect_ratios_grid, [-1])
        anchors = tile_anchors(grid_height, grid_width, scales_grid,
                               aspect_ratios_grid, self._base_anchor_size,
                               self._anchor_stride, self._anchor_offset)

        num_anchors = anchors.num_boxes_static()
        if num_anchors is None:
            num_anchors = anchors.num_boxes()
        anchor_indices = tf.zeros([num_anchors])
        anchors.add_field('feature_map_index', anchor_indices)
        #print(anchors)
        return [anchors]
Esempio n. 8
0
 def test_meshgrid_numpy_comparison(self):
   """Tests meshgrid op with vectors, for which it should match numpy."""
   x = np.arange(4)
   y = np.arange(6)
   exp_xgrid, exp_ygrid = np.meshgrid(x, y)
   xgrid, ygrid = ops.meshgrid(x, y)
   with self.test_session() as sess:
     xgrid_output, ygrid_output = sess.run([xgrid, ygrid])
     self.assertAllEqual(xgrid_output, exp_xgrid)
     self.assertAllEqual(ygrid_output, exp_ygrid)
Esempio n. 9
0
 def test_meshgrid_numpy_comparison(self):
   """Tests meshgrid op with vectors, for which it should match numpy."""
   x = np.arange(4)
   y = np.arange(6)
   exp_xgrid, exp_ygrid = np.meshgrid(x, y)
   xgrid, ygrid = ops.meshgrid(x, y)
   with self.test_session() as sess:
     xgrid_output, ygrid_output = sess.run([xgrid, ygrid])
     self.assertAllEqual(xgrid_output, exp_xgrid)
     self.assertAllEqual(ygrid_output, exp_ygrid)
Esempio n. 10
0
  def _generate(self, feature_map_shape_list):
    """Generates a collection of bounding boxes to be used as anchors.

    Args:
      feature_map_shape_list: list of pairs of convnet layer resolutions in the
        format [(height_0, width_0)].  For example, setting
        feature_map_shape_list=[(8, 8)] asks for anchors that correspond
        to an 8x8 layer.  For this anchor generator, only lists of length 1 are
        allowed.

    Returns:
      boxes_list: a list of BoxLists each holding anchor boxes corresponding to
        the input feature map shapes.

    Raises:
      ValueError: if feature_map_shape_list, box_specs_list do not have the same
        length.
      ValueError: if feature_map_shape_list does not consist of pairs of
        integers
    """
    if not (isinstance(feature_map_shape_list, list)
            and len(feature_map_shape_list) == 1):
      raise ValueError('feature_map_shape_list must be a list of length 1.')
    if not all([isinstance(list_item, tuple) and len(list_item) == 2
                for list_item in feature_map_shape_list]):
      raise ValueError('feature_map_shape_list must be a list of pairs.')
    self._base_anchor_size = tf.to_float(tf.convert_to_tensor(
        self._base_anchor_size))
    self._anchor_stride = tf.to_float(tf.convert_to_tensor(
        self._anchor_stride))
    self._anchor_offset = tf.to_float(tf.convert_to_tensor(
        self._anchor_offset))

    grid_height, grid_width = feature_map_shape_list[0]
    scales_grid, aspect_ratios_grid = ops.meshgrid(self._scales,
                                                   self._aspect_ratios)
    scales_grid = tf.reshape(scales_grid, [-1])
    aspect_ratios_grid = tf.reshape(aspect_ratios_grid, [-1])
    anchors = tile_anchors(grid_height,
                           grid_width,
                           scales_grid,
                           aspect_ratios_grid,
                           self._base_anchor_size,
                           self._anchor_stride,
                           self._anchor_offset)

    num_anchors = anchors.num_boxes_static()
    if num_anchors is None:
      num_anchors = anchors.num_boxes()
    anchor_indices = tf.zeros([num_anchors])
    anchors.add_field('feature_map_index', anchor_indices)
    return [anchors]
  def _generate(self, feature_map_shape_list):
    """Generates a collection of bounding boxes to be used as anchors.

    Args:
      feature_map_shape_list: list of pairs of convnet layer resolutions in the
        format [(height_0, width_0)].  For example, setting
        feature_map_shape_list=[(8, 8)] asks for anchors that correspond
        to an 8x8 layer.  For this anchor generator, only lists of length 1 are
        allowed.

    Returns:
      boxes: a BoxList holding a collection of N anchor boxes.  Additionally
        this BoxList also holds a `feature_map_index` field which is set to 0
        for each anchor; this field exists for interchangeability reasons with
        the MultipleGridAnchorGenerator (see the docstring for the corresponding
        `_generate` function in multiple_grid_anchor_generator.py)
    Raises:
      ValueError: if feature_map_shape_list, box_specs_list do not have the same
        length.
      ValueError: if feature_map_shape_list does not consist of pairs of
        integers
    """
    if not (isinstance(feature_map_shape_list, list)
            and len(feature_map_shape_list) == 1):
      raise ValueError('feature_map_shape_list must be a list of length 1.')
    if not all([isinstance(list_item, tuple) and len(list_item) == 2
                for list_item in feature_map_shape_list]):
      raise ValueError('feature_map_shape_list must be a list of pairs.')
    grid_height, grid_width = feature_map_shape_list[0]
    scales_grid, aspect_ratios_grid = ops.meshgrid(self._scales,
                                                   self._aspect_ratios)
    scales_grid = tf.reshape(scales_grid, [-1])
    aspect_ratios_grid = tf.reshape(aspect_ratios_grid, [-1])
    anchors = tile_anchors(grid_height,
                           grid_width,
                           scales_grid,
                           aspect_ratios_grid,
                           self._base_anchor_size,
                           self._anchor_stride,
                           self._anchor_offset)

    num_anchors = anchors.num_boxes_static()
    if num_anchors is None:
      num_anchors = anchors.num_boxes()
    anchor_indices = tf.zeros([num_anchors])
    anchors.add_field('feature_map_index', anchor_indices)
    return anchors
  def _generate(self, feature_map_shape_list):
    
    if not (isinstance(feature_map_shape_list, list)
            and len(feature_map_shape_list) == 1):
      raise ValueError('feature_map_shape_list must be a list of length 1.')
    if not all([isinstance(list_item, tuple) and len(list_item) == 2
                for list_item in feature_map_shape_list]):
      raise ValueError('feature_map_shape_list must be a list of pairs.')

    # Create constants in init_scope so they can be created in tf.functions
    # and accessed from outside of the function.
    with tf.init_scope():
      self._base_anchor_size = tf.cast(tf.convert_to_tensor(
          self._base_anchor_size), dtype=tf.float32)
      self._anchor_stride = tf.cast(tf.convert_to_tensor(
          self._anchor_stride), dtype=tf.float32)
      self._anchor_offset = tf.cast(tf.convert_to_tensor(
          self._anchor_offset), dtype=tf.float32)

    grid_height, grid_width = feature_map_shape_list[0]
    scales_grid, aspect_ratios_grid = ops.meshgrid(self._scales,
                                                   self._aspect_ratios)
    scales_grid = tf.reshape(scales_grid, [-1])
    aspect_ratios_grid = tf.reshape(aspect_ratios_grid, [-1])
    anchors = tile_anchors(grid_height,
                           grid_width,
                           scales_grid,
                           aspect_ratios_grid,
                           self._base_anchor_size,
                           self._anchor_stride,
                           self._anchor_offset)

    num_anchors = anchors.num_boxes_static()
    if num_anchors is None:
      num_anchors = anchors.num_boxes()
    anchor_indices = tf.zeros([num_anchors])
    anchors.add_field('feature_map_index', anchor_indices)
    return [anchors]
Esempio n. 13
0
  def _generate(self, feature_map_shape_list):
    """Generates a collection of bounding boxes to be used as anchors.

    Args:
      feature_map_shape_list: list of pairs of convnet layer resolutions in the
        format [(height_0, width_0)].  For example, setting
        feature_map_shape_list=[(8, 8)] asks for anchors that correspond
        to an 8x8 layer.  For this anchor generator, only lists of length 1 are
        allowed.

    Returns:
      boxes: a BoxList holding a collection of N anchor boxes
    Raises:
      ValueError: if feature_map_shape_list, box_specs_list do not have the same
        length.
      ValueError: if feature_map_shape_list does not consist of pairs of
        integers
    """
    if not (isinstance(feature_map_shape_list, list)
            and len(feature_map_shape_list) == 1):
      raise ValueError('feature_map_shape_list must be a list of length 1.')
    if not all([isinstance(list_item, tuple) and len(list_item) == 2
                for list_item in feature_map_shape_list]):
      raise ValueError('feature_map_shape_list must be a list of pairs.')
    grid_height, grid_width = feature_map_shape_list[0]
    scales_grid, aspect_ratios_grid = ops.meshgrid(self._scales,
                                                   self._aspect_ratios)
    scales_grid = tf.reshape(scales_grid, [-1])
    aspect_ratios_grid = tf.reshape(aspect_ratios_grid, [-1])
    return tile_anchors(grid_height,
                        grid_width,
                        scales_grid,
                        aspect_ratios_grid,
                        self._base_anchor_size,
                        self._anchor_stride,
                        self._anchor_offset)
    def _generate(self, feature_map_shape_list, im_height=1, im_width=1):
        """Generates a collection of bounding boxes to be used as anchors.

    The number of anchors generated for a single grid with shape MxM where we
    place k boxes over each grid center is k*M^2 and thus the total number of
    anchors is the sum over all grids.

    Args:
      feature_map_shape_list: list of a pair of convnet layer resolutions in the
        format [(height, width)]. For example,
        setting feature_map_shape=[(8, 8)] asks for anchors that
        correspond to an 8x8 layer.
      im_height: the height of the image to generate the grid for. If both
        im_height and im_width are 1, the generated anchors default to
        normalized coordinates, otherwise absolute coordinates are used for the
        grid.
      im_width: the width of the image to generate the grid for. If both
        im_height and im_width are 1, the generated anchors default to
        normalized coordinates, otherwise absolute coordinates are used for the
        grid.

    Returns:
      boxes: a BoxList holding a collection of N anchor boxes
    Raises:
      ValueError: if feature_map_shape_list, box_specs_list do not have the same
        length.
      ValueError: if feature_map_shape_list does not consist of pairs of
        integers
    """
        if len(feature_map_shape_list) != 1 or len(
                feature_map_shape_list[0]) != 2:
            raise ValueError('feature_map_shape_list must be a list of a pair')

        # Yolo has only one feature_map. so [0] mean the only map which is first.
        feature_map_shape = feature_map_shape_list[0]
        im_height = tf.to_float(im_height)
        im_width = tf.to_float(im_width)

        if not self._anchor_stride:
            anchor_stride = (1.0 / tf.to_float(feature_map_shape[0]),
                             1.0 / tf.to_float(feature_map_shape[1]))
        else:
            anchor_stride = (tf.to_float(self._anchor_stride[0]) / im_height,
                             tf.to_float(self._anchor_stride[1]) / im_width)

        if not self._anchor_offset:
            anchor_offset = (0.5 * anchor_stride[0], 0.5 * anchor_stride[1])
        else:
            anchor_offset = (tf.to_float(self._anchor_offset[0]) / im_height,
                             tf.to_float(self._anchor_offset[1]) / im_width)

        if (anchor_stride and len(anchor_stride) != 2):
            raise ValueError('anchor_stride must be a pair.')

        if (anchor_offset and len(anchor_offset) != 2):
            raise ValueError('anchor_offset must be a pair.')

        # Anchors are devided into size of feature map to make the size of anchors within (0 ~ 1)
        anchor_widths = [
            anchor[0] / feature_map_shape[0] for anchor in self._anchors
        ]
        anchor_heights = [
            anchor[1] / feature_map_shape[1] for anchor in self._anchors
        ]
        heights = anchor_heights * self._base_anchor_size[0]
        widths = anchor_widths * self._base_anchor_size[1]

        x_centers = tf.to_float(tf.range(feature_map_shape[0]))
        x_centers = x_centers * anchor_stride[0] + anchor_offset[0]
        y_centers = tf.to_float(tf.range(feature_map_shape[1]))
        y_centers = y_centers * anchor_stride[1] + anchor_offset[1]
        x_centers, y_centers = ops.meshgrid(x_centers, y_centers)

        widths_grid, x_centers_grid = ops.meshgrid(widths, x_centers)
        heights_grid, y_centers_grid = ops.meshgrid(heights, y_centers)
        bbox_centers = tf.stack([y_centers_grid, x_centers_grid], axis=3)
        bbox_sizes = tf.stack([heights_grid, widths_grid], axis=3)
        bbox_centers = tf.reshape(bbox_centers, [-1, 2])
        bbox_sizes = tf.reshape(bbox_sizes, [-1, 2])
        bbox_corners = grid_anchor_generator._center_size_bbox_to_corners_bbox(
            bbox_centers, bbox_sizes)
        anchors = box_list.BoxList(bbox_corners)

        num_anchors = anchors.num_boxes_static()
        if num_anchors is None:
            num_anchors = anchors.num_boxes()
        stddevs_tensor = 0.01 * tf.ones(
            [num_anchors, 4], dtype=tf.float32, name='stddevs')
        anchors.add_field('stddev', stddevs_tensor)

        return anchors