FIFO buffer to enable computation reuse in CNNs with sliding indow input Compute equivalent of .. code-block:: python concat(buffer, data, axis=axis) .slice_axis(axis=axis, begin=data.shape[axis], end=data.shape[axis]+buffer.sha
(data, buffer, axis)
| 27 | |
| 28 | @tvm.te.tag_scope(tag=tag.INJECTIVE + ",fifo_buffer") |
| 29 | def fifo_buffer(data, buffer, axis): |
| 30 | """ |
| 31 | FIFO buffer to enable computation reuse in CNNs with sliding indow input |
| 32 | |
| 33 | Compute equivalent of |
| 34 | |
| 35 | .. code-block:: python |
| 36 | |
| 37 | concat(buffer, data, axis=axis) |
| 38 | .slice_axis(axis=axis, |
| 39 | begin=data.shape[axis], |
| 40 | end=data.shape[axis]+buffer.shape[axis]) |
| 41 | |
| 42 | Useful for |
| 43 | |
| 44 | * Encoding explicit re-use of computation in convolution ops operated on a sliding window input |
| 45 | * Implementing a FIFO queue to cache intermediate results, e.g. as in Fast WaveNet. |
| 46 | |
| 47 | Parameters |
| 48 | ---------- |
| 49 | data : tvm.te.Tensor |
| 50 | The input data |
| 51 | buffer : tvm.te.Tensor |
| 52 | Previous value of the FIFO buffer |
| 53 | axis : int |
| 54 | Specify which axis should be used for buffering |
| 55 | |
| 56 | Returns |
| 57 | ------- |
| 58 | result : tvm.te.Tensor |
| 59 | Updated value for the buffer |
| 60 | """ |
| 61 | assert len(data.shape) == len(buffer.shape), ( |
| 62 | f"buffer and data must have same number of dimensions, " |
| 63 | f"buffer.shape = {buffer.shape}, data.shape = {data.shape}" |
| 64 | ) |
| 65 | assert len(buffer.shape) >= 1, "Zero-dimension tensor not supported" |
| 66 | assert 0 <= axis < len(buffer.shape), "buffer axis out of range" |
| 67 | for i in range(len(data.shape)): |
| 68 | if i == axis: |
| 69 | assert int(str(data.shape[i])) <= int(str(buffer.shape[i])) |
| 70 | else: |
| 71 | assert int(str(data.shape[i])) == int(str(buffer.shape[i])) |
| 72 | |
| 73 | buflen = buffer.shape[axis] |
| 74 | data_size = data.shape[axis] |
| 75 | |
| 76 | # Explicitly write out formula up to 4D, and then use concat+slice combo for 5D and higher |
| 77 | if len(buffer.shape) == 1: |
| 78 | return te.compute( |
| 79 | buffer.shape, |
| 80 | lambda i: tvm.tirx.if_then_else( |
| 81 | i < buflen - data_size, buffer[i + data_size], data[i - buflen + data_size] |
| 82 | ), |
| 83 | name="new_buffer", |
| 84 | ) |
| 85 | if len(buffer.shape) == 2: |
| 86 | if axis == 0: |
nothing calls this directly
no test coverage detected
searching dependent graphs…