This file is indexed.

/usr/lib/python3/dist-packages/caffe/coord_map.py is in python3-caffe-cpu 1.0.0~rc4-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
"""
Determine spatial relationships between layers to relate their coordinates.
Coordinates are mapped from input-to-output (forward), but can
be mapped output-to-input (backward) by the inverse mapping too.
This helps crop and align feature maps among other uses.
"""

from __future__ import division
import numpy as np
from caffe import layers as L

PASS_THROUGH_LAYERS = ['AbsVal', 'BatchNorm', 'Bias', 'BNLL', 'Dropout',
                       'Eltwise', 'ELU', 'Log', 'LRN', 'Exp', 'MVN', 'Power',
                       'ReLU', 'PReLU', 'Scale', 'Sigmoid', 'Split', 'TanH',
                       'Threshold']


def conv_params(fn):
    """
    Extract the spatial parameters that determine the coordinate mapping:
    kernel size, stride, padding, and dilation.

    Implementation detail: Convolution, Deconvolution, and Im2col layers
    define these in the convolution_param message, while Pooling has its
    own fields in pooling_param. This method deals with these details to
    extract canonical parameters.
    """
    params = fn.params.get('convolution_param', fn.params)
    axis = params.get('axis', 1)
    ks = np.array(params['kernel_size'], ndmin=1)
    dilation = np.array(params.get('dilation', 1), ndmin=1)
    assert len({'pad_h', 'pad_w', 'kernel_h', 'kernel_w', 'stride_h',
                'stride_w'} & set(fn.params)) == 0, \
        'cropping does not support legacy _h/_w params'
    return (axis, np.array(params.get('stride', 1), ndmin=1),
            (ks - 1) * dilation + 1,
            np.array(params.get('pad', 0), ndmin=1))


def crop_params(fn):
    """
    Extract the crop layer parameters with defaults.
    """
    params = fn.params.get('crop_param', fn.params)
    axis = params.get('axis', 2)  # default to spatial crop for N, C, H, W
    offset = np.array(params.get('offset', 0), ndmin=1)
    return (axis, offset)


class UndefinedMapException(Exception):
    """
    Exception raised for layers that do not have a defined coordinate mapping.
    """
    pass


def coord_map(fn):
    """
    Define the coordinate mapping by its
    - axis
    - scale: output coord[i * scale] <- input_coord[i]
    - shift: output coord[i] <- output_coord[i + shift]
    s.t. the identity mapping, as for pointwise layers like ReLu, is defined by
    (None, 1, 0) since it is independent of axis and does not transform coords.
    """
    if fn.type_name in ['Convolution', 'Pooling', 'Im2col']:
        axis, stride, ks, pad = conv_params(fn)
        return axis, 1 / stride, (pad - (ks - 1) / 2) / stride
    elif fn.type_name == 'Deconvolution':
        axis, stride, ks, pad = conv_params(fn)
        return axis, stride, (ks - 1) / 2 - pad
    elif fn.type_name in PASS_THROUGH_LAYERS:
        return None, 1, 0
    elif fn.type_name == 'Crop':
        axis, offset = crop_params(fn)
        axis -= 1  # -1 for last non-coordinate dim.
        return axis, 1, - offset
    else:
        raise UndefinedMapException


class AxisMismatchException(Exception):
    """
    Exception raised for mappings with incompatible axes.
    """
    pass


def compose(base_map, next_map):
    """
    Compose a base coord map with scale a1, shift b1 with a further coord map
    with scale a2, shift b2. The scales multiply and the further shift, b2,
    is scaled by base coord scale a1.
    """
    ax1, a1, b1 = base_map
    ax2, a2, b2 = next_map
    if ax1 is None:
        ax = ax2
    elif ax2 is None or ax1 == ax2:
        ax = ax1
    else:
        raise AxisMismatchException
    return ax, a1 * a2, a1 * b2 + b1


def inverse(coord_map):
    """
    Invert a coord map by de-scaling and un-shifting;
    this gives the backward mapping for the gradient.
    """
    ax, a, b = coord_map
    return ax, 1 / a, -b / a


def coord_map_from_to(top_from, top_to):
    """
    Determine the coordinate mapping betweeen a top (from) and a top (to).
    Walk the graph to find a common ancestor while composing the coord maps for
    from and to until they meet. As a last step the from map is inverted.
    """
    # We need to find a common ancestor of top_from and top_to.
    # We'll assume that all ancestors are equivalent here (otherwise the graph
    # is an inconsistent state (which we could improve this to check for)).
    # For now use a brute-force algorithm.

    def collect_bottoms(top):
        """
        Collect the bottoms to walk for the coordinate mapping.
        The general rule is that all the bottoms of a layer can be mapped, as
        most layers have the same coordinate mapping for each bottom.
        Crop layer is a notable exception. Only the first/cropped bottom is
        mappable; the second/dimensions bottom is excluded from the walk.
        """
        bottoms = top.fn.inputs
        if top.fn.type_name == 'Crop':
            bottoms = bottoms[:1]
        return bottoms

    # walk back from top_from, keeping the coord map as we go
    from_maps = {top_from: (None, 1, 0)}
    frontier = {top_from}
    while frontier:
        top = frontier.pop()
        try:
            bottoms = collect_bottoms(top)
            for bottom in bottoms:
                from_maps[bottom] = compose(from_maps[top], coord_map(top.fn))
                frontier.add(bottom)
        except UndefinedMapException:
            pass

    # now walk back from top_to until we hit a common blob
    to_maps = {top_to: (None, 1, 0)}
    frontier = {top_to}
    while frontier:
        top = frontier.pop()
        if top in from_maps:
            return compose(to_maps[top], inverse(from_maps[top]))
        try:
            bottoms = collect_bottoms(top)
            for bottom in bottoms:
                to_maps[bottom] = compose(to_maps[top], coord_map(top.fn))
                frontier.add(bottom)
        except UndefinedMapException:
            continue

    # if we got here, we did not find a blob in common
    raise RuntimeError('Could not compute map between tops; are they '
                       'connected by spatial layers?')


def crop(top_from, top_to):
    """
    Define a Crop layer to crop a top (from) to another top (to) by
    determining the coordinate mapping between the two and net spec'ing
    the axis and shift parameters of the crop.
    """
    ax, a, b = coord_map_from_to(top_from, top_to)
    assert (a == 1).all(), 'scale mismatch on crop (a = {})'.format(a)
    assert (b <= 0).all(), 'cannot crop negative offset (b = {})'.format(b)
    assert (np.round(b) == b).all(), 'cannot crop noninteger offset ' \
        '(b = {})'.format(b)
    return L.Crop(top_from, top_to,
                  crop_param=dict(axis=ax + 1,  # +1 for first cropping dim.
                                  offset=list(-np.round(b).astype(int))))