How to Use Anchor Generators for Object Detection in TensorFlow Models
Anchor generators in TensorFlow Models create pre-defined bounding-box templates tiled over feature-map grids by reading a protobuf configuration, building a concrete generator via the anchor generator builder, and returning BoxList objects at runtime.
The TensorFlow Models repository provides a flexible anchor generation system for object detection that converts static configuration into dynamic anchor boxes. This architecture supports multiple generator types—including grid, SSD, multiscale, and flexible-grid—to accommodate different detection backbones. Understanding how to configure and instantiate these generators is essential for customizing region-proposal networks (RPN) or downstream detection heads.
What Are Anchor Generators?
Anchor generators produce anchor boxes, which are pre-defined bounding-box templates tiled across feature-map grids. In research/object_detection/core/anchor_generator.py, the abstract AnchorGenerator base class defines the public API, including the generate() method and num_anchors_per_location() property. Concrete implementations handle the geometric tiling logic, returning BoxList objects that networks use to propose object locations.
Architecture of the Anchor Generator System
The system follows a three-tier architecture: configuration definition, builder instantiation, and runtime generation.
Proto Configuration (anchor_generator.proto)
The research/object_detection/protos/anchor_generator.proto file declares the one-of options for four generator types: grid, SSD, multiscale, and flexible-grid. This protobuf serves as the single source of truth for anchor scales, aspect ratios, strides, and base sizes. Pipeline configuration files reference this proto to specify anchor behavior without modifying source code.
The Builder Pattern (anchor_generator_builder.py)
The research/object_detection/builders/anchor_generator_builder.py file implements the factory logic that converts protobuf messages into concrete generator instances. The build() function validates the proto, extracts the active one-of field, and maps parameters to the appropriate constructor. When the proto contains a grid_anchor_generator block, the builder instantiates GridAnchorGenerator with the specified scales and strides.
Concrete Implementations
Four main implementations reside in research/object_detection/anchor_generators/:
- GridAnchorGenerator: Classic Faster R-CNN-style anchors with uniform scales and aspect ratios across the grid.
- FlexibleGridAnchorGenerator: Per-layer control over base sizes, strides, and aspect ratios for multi-scale detection.
- MultiscaleAnchorGenerator: Generates anchors at multiple feature-map scales simultaneously.
- SSDAnchorGenerator: SSD-specific anchor schemes with specialized tiling logic.
Building an Anchor Generator from Configuration
To instantiate a generator programmatically, define a protobuf configuration and pass it to the builder.
from object_detection.protos import anchor_generator_pb2
from object_detection.builders import anchor_generator_builder
# Define a GridAnchorGenerator configuration
grid_cfg = anchor_generator_pb2.AnchorGenerator()
grid_cfg.grid_anchor_generator.scales.extend([0.5, 1.0, 2.0])
grid_cfg.grid_anchor_generator.aspect_ratios.extend([0.5, 1.0, 2.0])
grid_cfg.grid_anchor_generator.height = 256
grid_cfg.grid_anchor_generator.width = 256
grid_cfg.grid_anchor_generator.height_stride = 16
grid_cfg.grid_anchor_generator.width_stride = 16
# Build the concrete generator
anchor_gen = anchor_generator_builder.build(grid_cfg)
As implemented in anchor_generator_builder.py (lines 48-60), the builder extracts the grid_anchor_generator fields and constructs the class with matching constructor arguments.
Generating Anchors for Feature Maps
At runtime, models pass feature-map shapes to the generate() method to receive tiled anchors.
# Feature maps from the backbone: 8x8 and 4x4 spatial resolutions
feature_maps = [(8, 8), (4, 4)]
# Generate BoxList objects for each feature map
anchors_per_map = anchor_gen.generate(feature_maps)
# Inspect the first feature map's anchors
first_boxlist = anchors_per_map[0]
print("Anchors on first map:", first_boxlist.num_boxes())
print("First 3 boxes (y1, x1, y2, x2):", first_boxlist.get().numpy()[:3])
Under the hood, GridAnchorGenerator._generate() calls tile_anchors() (see grid_anchor_generator.py lines 82-112) to create the BoxList and appends the feature_map_index field to track spatial origins.
Advanced Usage: Flexible Grid Anchors
For architectures requiring per-layer anchor configurations, use FlexibleGridAnchorGenerator to specify unique parameters for each feature-map level.
from object_detection.protos import anchor_generator_pb2
from object_detection.builders import anchor_generator_builder
flex_cfg = anchor_generator_pb2.AnchorGenerator()
flex_grid = flex_cfg.flexible_grid_anchor_generator
# Layer 0: small objects with fine stride
flex_grid.anchor_grid.add(
base_sizes=[32.0, 64.0, 128.0],
aspect_ratios=[0.5, 1.0],
height_stride=8, width_stride=8,
height_offset=4, width_offset=4)
# Layer 1: large objects with coarse stride
flex_grid.anchor_grid.add(
base_sizes=[256.0, 512.0],
aspect_ratios=[0.5, 1.0, 2.0],
height_stride=16, width_stride=16,
height_offset=8, width_offset=8)
anchor_gen = anchor_generator_builder.build(flex_cfg)
# Generate with normalization for 640x640 images
feature_maps = [(64, 64), (32, 32)]
anchors = anchor_gen.generate(feature_maps, im_height=640, im_width=640)
The flexible generator's _generate() method iterates over each layer configuration, invoking the shared tiling routine and optionally normalizing coordinates to [0, 1] when image dimensions are provided (see flexible_grid_anchor_generator.py lines 82-134).
Summary
- Configuration: Define anchor schemes in
anchor_generator.protousing scales, aspect ratios, and strides. - Instantiation: Use
anchor_generator_builder.build()to convert protobuf configs into concrete generator objects. - Generation: Call
generate(feature_map_shape_list)at runtime to obtainBoxListobjects tiled over each feature-map grid. - Flexibility: Choose
GridAnchorGeneratorfor uniform anchors orFlexibleGridAnchorGeneratorfor per-layer control. - Integration: Generated anchors feed directly into RPN or detection heads via the
BoxListAPI.
Frequently Asked Questions
What is the difference between GridAnchorGenerator and FlexibleGridAnchorGenerator?
GridAnchorGenerator applies uniform scales, aspect ratios, and strides across all feature-map levels, suitable for standard Faster R-CNN architectures. FlexibleGridAnchorGenerator allows independent configuration of base sizes, strides, and aspect ratios for each layer, enabling precise control for multi-scale detectors like feature pyramid networks.
How do I normalize anchor coordinates to the image scale?
Pass the image dimensions (im_height and im_width) as keyword arguments to the generate() method. The flexible grid implementation automatically normalizes coordinates to [0, 1] when these parameters are provided, as implemented in flexible_grid_anchor_generator.py.
Can I use multiple anchor generator types in the same model?
The protobuf uses a one-of constraint, so a single configuration block selects one generator type. However, you can instantiate multiple generator objects programmatically using separate protobuf configs and merge their output BoxList objects manually before feeding them to the detection head.
Where does the builder map proto fields to constructor arguments?
In research/object_detection/builders/anchor_generator_builder.py, the build() function checks which one-of field is populated in the proto (e.g., grid_anchor_generator), then extracts lists of scales and aspect ratios and passes them to the matching class constructor, handling type conversion automatically.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →