def _fuse_dilation_conv(gddict):
    """
    A dilated convolution in older tensorflow versions might not be fused in the
    Conv2D or DepthwiseConv2D op, but represented with the following format:

        SpaceToBatchND -> (Depthwise)Conv2D -> BatchToSpaceND

    We try to fuse it back into (Depthwise)Conv2D with the dilation parameter
    set in attribute.
    There are several patterns that exist in tensorflow for breaking up dilation
    convolutions. We detect the following patterns:

      SpaceToBatchND -> ExpandDims -> Conv2D -> Squeeze -> BatchToSpaceND

      SpaceToBatchND -> Conv2D -> BatchToSpaceND

    The first case appears when Conv1D is used, TF expands/squeeze the inputs to
    conform Conv2D pattern.
    The second case is a basic Conv2D pattern.

    """
    for name in list(gddict.keys()):
        if name not in gddict:
            # Node might have been removed from graph during fusion.
            continue
        node = gddict[name]
        if node.op in {"Conv2D", "DepthwiseConv2dNative"}:
            _pattern_match_and_rewrite(gddict, name)

    A dilated convolution in older tensorflow versions might not be fused in the
    Conv2D or DepthwiseConv2D op, but represented with the following format:

        SpaceToBatchND -> (Depthwise)Conv2D -> BatchToSpaceND

    We try to fuse it back into (Depthwise)Conv2D with the dilation parameter
    set in attribute.
    There are several patterns that exist in tensorflow for breaking up dilation
    convolutions. We detect the following patterns:

      SpaceToBatchND -> ExpandDims -> Conv2D -> Squeeze -> BatchToSpaceND

      SpaceToBatchND -> Conv2D -> BatchToSpaceND

    The first case appears when Conv1D is used, TF expands/squeeze the inputs to
    conform Conv2D pattern.
    The second case is a basic Conv2D pattern.

    
coremltools/converters/mil/frontend/tensorflow/tf_graph_pass/fuse_dilation_conv.py