src/api/native_tensor_conv.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // native_tensor_conv.cpp — the restored `conv` group, ported from the QuickJS | ||
| 2 | // binding (bro's old src/js/tensor_bindings_conv.cpp). Argument order, optional | ||
| 3 | // arguments and defaults are the old ones; the brotensor call each body makes | ||
| 4 | // is today's `brotensor::` signature, not the old `nngpu::` one. | ||
| 5 | // | ||
| 6 | // Everything here is a free function on `bro.tensor`; js/tensor_conv.js is the | ||
| 7 | // wrapper half that validates arguments and reads the error slot back. | ||
| 8 | |||
| 9 | #include "native_tensor_conv_decl.h" | ||
| 10 | #include "api_internal.h" | ||
| 11 | #include "native_register.h" | ||
| 12 | |||
| 13 | #include <cstring> | ||
| 14 | #include <stdexcept> | ||
| 15 | #include <string> | ||
| 16 | |||
| 17 | using namespace brotensor::api; | ||
| 18 | using brotensor::Tensor; | ||
| 19 | using brotensor::Dtype; | ||
| 20 | |||
| 21 | // Every body checks its operands against the dims first (api_internal.h | ||
| 22 | // "input-size contract"); accumulated gradients are checked like inputs. | ||
| 23 | |||
| 24 | namespace { | ||
| 25 | |||
| 26 | 142 | Tensor* T(void* p) { return toTensor(p); } | |
| 27 | |||
| 28 | // Transposed-conv geometry (torch ConvTranspose2d): positive kernel, stride, | ||
| 29 | // dilation and groups dividing both channel counts; the output extent is | ||
| 30 | // (in-1)*s - 2p + d*(k-1) + op + 1. | ||
| 31 | 10 | bool convTGeom(const char* L, int64_t C_in, int64_t C_out, int64_t H, int64_t W, int64_t kH, int64_t kW, | |
| 32 | int64_t sH, int64_t sW, int64_t pH, int64_t pW, int64_t opH, int64_t opW, int64_t dH, int64_t dW, | ||
| 33 | int64_t groups, int64_t& H_out, int64_t& W_out) { | ||
| 34 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (!needPositive(L, {kH, kW, sH, sW, dH, dW, groups})) return false; |
| 35 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (!needNonNegative(L, {C_in, C_out, H, W, pH, pW, opH, opW})) return false; |
| 36 |
2/4✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
|
10 | if (C_in % groups != 0 || C_out % groups != 0) { |
| 37 | ✗ | setError(std::string(L) + ": groups must divide C_in and C_out"); | |
| 38 | ✗ | return false; | |
| 39 | } | ||
| 40 | 10 | H_out = (H - 1) * sH - 2 * pH + dH * (kH - 1) + opH + 1; | |
| 41 | 10 | W_out = (W - 1) * sW - 2 * pW + dW * (kW - 1) + opW + 1; | |
| 42 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | if (H_out < 0) H_out = 0; |
| 43 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | if (W_out < 0) W_out = 0; |
| 44 | 10 | return true; | |
| 45 | 10 | } | |
| 46 | |||
| 47 | // Idx values address the per-channel H*W input plane on the device: read | ||
| 48 | // them back and range-check them (-1 = "all padding" is skipped by the op). | ||
| 49 | 2 | bool needPoolIndices(const char* L, const Tensor* idx, int64_t n, int64_t plane) { | |
| 50 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (idx->dtype != Dtype::INT32) { |
| 51 | ✗ | setError(std::string(L) + ": Idx must be INT32 (the forward's output)"); | |
| 52 | ✗ | return false; | |
| 53 | } | ||
| 54 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (!needElems(L, "Idx", idx, n)) return false; |
| 55 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (n == 0) return true; |
| 56 | 2 | auto host = idx->to(brotensor::Device::CPU); | |
| 57 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | const auto* v = static_cast<const int32_t*>(host.host_raw()); |
| 58 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | for (int64_t i = 0; i < n; ++i) { |
| 59 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | if (v[i] < -1 || v[i] >= plane) { |
| 60 | ✗ | setError(std::string(L) + ": Idx[" + std::to_string(i) + "] = " + std::to_string(v[i]) + | |
| 61 | ✗ | " is outside the " + std::to_string(plane) + "-pixel input plane"); | |
| 62 | ✗ | return false; | |
| 63 | } | ||
| 64 | 2 | } | |
| 65 | 2 | return true; | |
| 66 | 2 | } | |
| 67 | |||
| 68 | } // namespace | ||
| 69 | |||
| 70 | extern "C" { | ||
| 71 | |||
| 72 | // ---- interp2d backward ----------------------------------------------------- | ||
| 73 | |||
| 74 | 2 | void bro_tensor_interp2dBackward(void* dY, int32_t N, int32_t C, int32_t H_in, int32_t W_in, | |
| 75 | int32_t H_out, int32_t W_out, int32_t mode, void* dX) { | ||
| 76 | 2 | const char* L = "interp2dBackward"; | |
| 77 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!need(L, {dY, dX})) return; |
| 78 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!needNonNegative(L, {N, C, H_in, W_in})) return; |
| 79 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!needElems(L, "dY", T(dY), elems({N, C, H_out, W_out}))) return; |
| 80 | BROTENSOR_API_TRY | ||
| 81 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | brotensor::interp2d_backward(*toTensor(dY), N, C, H_in, W_in, H_out, W_out, mode, *toTensor(dX)); |
| 82 |
0/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
2 | BROTENSOR_API_CATCH(L) |
| 83 | 2 | } | |
| 84 | |||
| 85 | // ---- pad2d / slice2d ------------------------------------------------------- | ||
| 86 | |||
| 87 | 4 | void bro_tensor_pad2dForward(void* X, int32_t N, int32_t C, int32_t H, int32_t W, | |
| 88 | int32_t padT, int32_t padB, int32_t padL, int32_t padR, | ||
| 89 | int32_t mode, void* Y) { | ||
| 90 | 4 | const char* L = "pad2dForward"; | |
| 91 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
|
4 | if (!need(L, {X, Y}) || !needNonNegative(L, {padT, padB, padL, padR})) return; |
| 92 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if (!needElems(L, "X", T(X), elems({N, C, H, W}))) return; |
| 93 | BROTENSOR_API_TRY | ||
| 94 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | brotensor::pad2d_forward(*toTensor(X), N, C, H, W, padT, padB, padL, padR, mode, *toTensor(Y)); |
| 95 |
0/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
2 | BROTENSOR_API_CATCH(L) |
| 96 | 4 | } | |
| 97 | |||
| 98 | 2 | void bro_tensor_pad2dBackward(void* dY, int32_t N, int32_t C, int32_t H, int32_t W, | |
| 99 | int32_t padT, int32_t padB, int32_t padL, int32_t padR, | ||
| 100 | int32_t mode, void* dX) { | ||
| 101 | 2 | const char* L = "pad2dBackward"; | |
| 102 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | if (!need(L, {dY, dX}) || !needNonNegative(L, {N, C, H, W, padT, padB, padL, padR})) return; |
| 103 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
4 | if (!needElems(L, "dY", T(dY), elems({N, C, static_cast<int64_t>(H) + padT + padB, |
| 104 | 2 | static_cast<int64_t>(W) + padL + padR}))) return; | |
| 105 | BROTENSOR_API_TRY | ||
| 106 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | brotensor::pad2d_backward(*toTensor(dY), N, C, H, W, padT, padB, padL, padR, mode, *toTensor(dX)); |
| 107 |
0/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
2 | BROTENSOR_API_CATCH(L) |
| 108 | 2 | } | |
| 109 | |||
| 110 | 2 | void bro_tensor_slice2dForward(void* X, int32_t N, int32_t C, int32_t H, int32_t W, | |
| 111 | int32_t h0, int32_t w0, int32_t H_out, int32_t W_out, void* Y) { | ||
| 112 | 2 | const char* L = "slice2dForward"; | |
| 113 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!need(L, {X, Y})) return; |
| 114 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!needElems(L, "X", T(X), elems({N, C, H, W}))) return; |
| 115 | BROTENSOR_API_TRY | ||
| 116 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | brotensor::slice2d_forward(*toTensor(X), N, C, H, W, h0, w0, H_out, W_out, *toTensor(Y)); |
| 117 |
0/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
2 | BROTENSOR_API_CATCH(L) |
| 118 | 2 | } | |
| 119 | |||
| 120 | 2 | void bro_tensor_slice2dBackward(void* dY, int32_t N, int32_t C, int32_t H, int32_t W, | |
| 121 | int32_t h0, int32_t w0, int32_t H_out, int32_t W_out, void* dX) { | ||
| 122 | 2 | const char* L = "slice2dBackward"; | |
| 123 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!need(L, {dY, dX})) return; |
| 124 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!needElems(L, "dY", T(dY), elems({N, C, H_out, W_out}))) return; |
| 125 | BROTENSOR_API_TRY | ||
| 126 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | brotensor::slice2d_backward(*toTensor(dY), N, C, H, W, h0, w0, H_out, W_out, *toTensor(dX)); |
| 127 |
0/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
2 | BROTENSOR_API_CATCH(L) |
| 128 | 2 | } | |
| 129 | |||
| 130 | // ---- max pool / adaptive average pool -------------------------------------- | ||
| 131 | |||
| 132 | 6 | void bro_tensor_maxPool2dForward(void* X, int32_t N, int32_t C, int32_t H, int32_t W, | |
| 133 | int32_t kH, int32_t kW, int32_t sH, int32_t sW, | ||
| 134 | int32_t padH, int32_t padW, void* Y, void* Idx) { | ||
| 135 | 6 | const char* L = "maxPool2dForward"; | |
| 136 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (!need(L, {X, Y, Idx})) return; |
| 137 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
|
6 | if (!needPositive(L, {kH, kW, sH, sW}) || !needNonNegative(L, {padH, padW})) return; |
| 138 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
|
6 | if (!needElems(L, "X", T(X), elems({N, C, H, W}))) return; |
| 139 | BROTENSOR_API_TRY | ||
| 140 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
8 | brotensor::max_pool2d_forward(*toTensor(X), N, C, H, W, kH, kW, sH, sW, padH, padW, |
| 141 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | *toTensor(Y), *toTensor(Idx)); |
| 142 |
0/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
4 | BROTENSOR_API_CATCH(L) |
| 143 | 6 | } | |
| 144 | |||
| 145 | 2 | void bro_tensor_maxPool2dBackward(void* dY, void* Idx, int32_t N, int32_t C, int32_t H, int32_t W, | |
| 146 | int32_t H_out, int32_t W_out, void* dX) { | ||
| 147 | 2 | const char* L = "maxPool2dBackward"; | |
| 148 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | if (!need(L, {dY, Idx, dX}) || !needNonNegative(L, {N, C, H, W})) return; |
| 149 | 2 | const int64_t n = elems({N, C, H_out, W_out}); | |
| 150 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (!needElems(L, "dY", T(dY), n)) return; |
| 151 | BROTENSOR_API_TRY | ||
| 152 |
4/8✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
|
2 | if (!needPoolIndices(L, T(Idx), n, elems({H, W}))) return; |
| 153 |
4/8✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
|
2 | brotensor::max_pool2d_backward(*toTensor(dY), *toTensor(Idx), N, C, H, W, H_out, W_out, *toTensor(dX)); |
| 154 |
0/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
2 | BROTENSOR_API_CATCH(L) |
| 155 | 2 | } | |
| 156 | |||
| 157 | 4 | void bro_tensor_adaptiveAvgPool2dForward(void* X, int32_t N, int32_t C, int32_t H, int32_t W, | |
| 158 | int32_t H_out, int32_t W_out, void* Y) { | ||
| 159 | 4 | const char* L = "adaptiveAvgPool2dForward"; | |
| 160 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
|
4 | if (!need(L, {X, Y}) || !needPositive(L, {H_out, W_out})) return; |
| 161 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!needElems(L, "X", T(X), elems({N, C, H, W}))) return; |
| 162 | BROTENSOR_API_TRY | ||
| 163 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | brotensor::adaptive_avg_pool2d_forward(*toTensor(X), N, C, H, W, H_out, W_out, *toTensor(Y)); |
| 164 |
0/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
2 | BROTENSOR_API_CATCH(L) |
| 165 | 4 | } | |
| 166 | |||
| 167 | 2 | void bro_tensor_adaptiveAvgPool2dBackward(void* dY, int32_t N, int32_t C, int32_t H, int32_t W, | |
| 168 | int32_t H_out, int32_t W_out, void* dX) { | ||
| 169 | 2 | const char* L = "adaptiveAvgPool2dBackward"; | |
| 170 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
|
2 | if (!need(L, {dY, dX}) || !needPositive(L, {H_out, W_out}) || !needNonNegative(L, {N, C, H, W})) return; |
| 171 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!needElems(L, "dY", T(dY), elems({N, C, H_out, W_out}))) return; |
| 172 | BROTENSOR_API_TRY | ||
| 173 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | brotensor::adaptive_avg_pool2d_backward(*toTensor(dY), N, C, H, W, H_out, W_out, *toTensor(dX)); |
| 174 |
0/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
2 | BROTENSOR_API_CATCH(L) |
| 175 | 2 | } | |
| 176 | |||
| 177 | // ---- transposed conv2d ----------------------------------------------------- | ||
| 178 | |||
| 179 | 6 | void bro_tensor_convTranspose2dForward(void* X, void* Wt, uint64_t bias_bits, | |
| 180 | int32_t N, int32_t C_in, int32_t H, int32_t W, | ||
| 181 | int32_t C_out, int32_t kH, int32_t kW, | ||
| 182 | int32_t sH, int32_t sW, int32_t pH, int32_t pW, | ||
| 183 | int32_t opH, int32_t opW, int32_t dH, int32_t dW, | ||
| 184 | int32_t groups, void* Y) { | ||
| 185 | 6 | const char* L = "convTranspose2dForward"; | |
| 186 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (!need(L, {X, Wt, Y})) return; |
| 187 | 6 | int64_t H_out = 0, W_out = 0; | |
| 188 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if (!convTGeom(L, C_in, C_out, H, W, kH, kW, sH, sW, pH, pW, opH, opW, dH, dW, groups, H_out, W_out)) return; |
| 189 |
6/6✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 4 times.
|
18 | if (!needOperands(L, T(X), {{"X", T(X), elems({N, C_in, H, W})}, |
| 190 | 6 | {"Wt", T(Wt), elems({C_in, C_out / groups, kH, kW})}, | |
| 191 | 6 | {"bias", tensorFromValue(bias_bits), C_out}})) return; | |
| 192 | BROTENSOR_API_TRY | ||
| 193 |
4/8✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
|
8 | brotensor::conv_transpose2d_forward(*toTensor(X), *toTensor(Wt), tensorFromValue(bias_bits), |
| 194 | 4 | N, C_in, H, W, C_out, kH, kW, sH, sW, pH, pW, | |
| 195 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | opH, opW, dH, dW, groups, *toTensor(Y)); |
| 196 |
0/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
4 | BROTENSOR_API_CATCH("convTranspose2dForward") |
| 197 | 6 | } | |
| 198 | |||
| 199 | 2 | void bro_tensor_convTranspose2dBackwardInput(void* Wt, void* dY, | |
| 200 | int32_t N, int32_t C_in, int32_t H, int32_t W, | ||
| 201 | int32_t C_out, int32_t kH, int32_t kW, | ||
| 202 | int32_t sH, int32_t sW, int32_t pH, int32_t pW, | ||
| 203 | int32_t opH, int32_t opW, int32_t dH, int32_t dW, | ||
| 204 | int32_t groups, void* dX) { | ||
| 205 | 2 | const char* L = "convTranspose2dBackwardInput"; | |
| 206 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!need(L, {Wt, dY, dX})) return; |
| 207 | 2 | int64_t H_out = 0, W_out = 0; | |
| 208 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (!convTGeom(L, C_in, C_out, H, W, kH, kW, sH, sW, pH, pW, opH, opW, dH, dW, groups, H_out, W_out)) return; |
| 209 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!needNonNegative(L, {N})) return; |
| 210 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
4 | if (!needOperands(L, T(Wt), {{"Wt", T(Wt), elems({C_in, C_out / groups, kH, kW})}, |
| 211 | 2 | {"dY", T(dY), elems({N, C_out, H_out, W_out})}})) return; | |
| 212 | BROTENSOR_API_TRY | ||
| 213 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
4 | brotensor::conv_transpose2d_backward_input(*toTensor(Wt), *toTensor(dY), |
| 214 | 2 | N, C_in, H, W, C_out, kH, kW, sH, sW, pH, pW, | |
| 215 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | opH, opW, dH, dW, groups, *toTensor(dX)); |
| 216 |
0/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
2 | BROTENSOR_API_CATCH("convTranspose2dBackwardInput") |
| 217 | 2 | } | |
| 218 | |||
| 219 | 2 | void bro_tensor_convTranspose2dBackwardWeight(void* X, void* dY, | |
| 220 | int32_t N, int32_t C_in, int32_t H, int32_t W, | ||
| 221 | int32_t C_out, int32_t kH, int32_t kW, | ||
| 222 | int32_t sH, int32_t sW, int32_t pH, int32_t pW, | ||
| 223 | int32_t opH, int32_t opW, int32_t dH, int32_t dW, | ||
| 224 | int32_t groups, void* dWt) { | ||
| 225 | 2 | const char* L = "convTranspose2dBackwardWeight"; | |
| 226 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!need(L, {X, dY, dWt})) return; |
| 227 | 2 | int64_t H_out = 0, W_out = 0; | |
| 228 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (!convTGeom(L, C_in, C_out, H, W, kH, kW, sH, sW, pH, pW, opH, opW, dH, dW, groups, H_out, W_out)) return; |
| 229 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!needNonNegative(L, {N})) return; |
| 230 | // dWt accumulates — "pre-zeroed by caller". | ||
| 231 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
|
6 | if (!needOperands(L, T(X), {{"X", T(X), elems({N, C_in, H, W})}, |
| 232 | 2 | {"dY", T(dY), elems({N, C_out, H_out, W_out})}, | |
| 233 | 2 | {"dWt", T(dWt), elems({C_in, C_out / groups, kH, kW})}})) return; | |
| 234 | BROTENSOR_API_TRY | ||
| 235 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
4 | brotensor::conv_transpose2d_backward_weight(*toTensor(X), *toTensor(dY), |
| 236 | 2 | N, C_in, H, W, C_out, kH, kW, sH, sW, pH, pW, | |
| 237 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | opH, opW, dH, dW, groups, *toTensor(dWt)); |
| 238 |
0/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
2 | BROTENSOR_API_CATCH("convTranspose2dBackwardWeight") |
| 239 | 2 | } | |
| 240 | |||
| 241 | 4 | void bro_tensor_convTranspose2dBackwardBias(void* dY, int32_t N, int32_t C_out, | |
| 242 | int32_t H_out, int32_t W_out, void* dB) { | ||
| 243 | 4 | const char* L = "convTranspose2dBackwardBias"; | |
| 244 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!need(L, {dY, dB})) return; |
| 245 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!needOperands(L, T(dY), {{"dY", T(dY), elems({N, C_out, H_out, W_out})}, {"dB", T(dB), C_out}})) return; |
| 246 | BROTENSOR_API_TRY | ||
| 247 |
3/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
4 | brotensor::conv_transpose2d_backward_bias(*toTensor(dY), N, C_out, H_out, W_out, *toTensor(dB)); |
| 248 |
0/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
4 | BROTENSOR_API_CATCH("convTranspose2dBackwardBias") |
| 249 | 4 | } | |
| 250 | |||
| 251 | // ---- conv3d (NCTHW) -------------------------------------------------------- | ||
| 252 | |||
| 253 | 6 | void bro_tensor_conv3dForward(void* X, void* Wt, uint64_t bias_bits, | |
| 254 | int32_t N, int32_t C_in, int32_t T, int32_t H, int32_t W, | ||
| 255 | int32_t C_out, int32_t kT, int32_t kH, int32_t kW, | ||
| 256 | int32_t sT, int32_t sH, int32_t sW, | ||
| 257 | int32_t pT, int32_t pH, int32_t pW, | ||
| 258 | int32_t dT, int32_t dH, int32_t dW, | ||
| 259 | int32_t groups, void* Y) { | ||
| 260 | 6 | const char* L = "conv3dForward"; | |
| 261 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (!need(L, {X, Wt, Y})) return; |
| 262 | // conv2d's geometry on (H, W) plus the same rules on T. | ||
| 263 | 6 | int64_t H_out = 0, W_out = 0; | |
| 264 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if (!convGeom2d(L, C_in, C_out, H, W, kH, kW, sH, sW, pH, pW, dH, dW, groups, H_out, W_out)) return; |
| 265 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
|
6 | if (!needPositive(L, {kT, sT, dT}) || !needNonNegative(L, {N, T, pT})) return; |
| 266 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
|
18 | if (!needOperands(L, toTensor(X), {{"X", toTensor(X), elems({N, C_in, T, H, W})}, |
| 267 | 6 | {"Wt", toTensor(Wt), elems({C_out, C_in / groups, kT, kH, kW})}, | |
| 268 | 6 | {"bias", tensorFromValue(bias_bits), C_out}})) return; | |
| 269 | BROTENSOR_API_TRY | ||
| 270 |
4/8✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
|
12 | brotensor::conv3d_forward(*toTensor(X), *toTensor(Wt), tensorFromValue(bias_bits), |
| 271 | 6 | N, C_in, T, H, W, C_out, kT, kH, kW, | |
| 272 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | sT, sH, sW, pT, pH, pW, dT, dH, dW, groups, *toTensor(Y)); |
| 273 |
0/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
6 | BROTENSOR_API_CATCH("conv3dForward") |
| 274 | 6 | } | |
| 275 | |||
| 276 | // ---- window partition / reverse / 2x2 spatial merge ------------------------ | ||
| 277 | |||
| 278 | 4 | void bro_tensor_windowPartitionForward(void* X, int32_t N, int32_t C, int32_t H, int32_t W, | |
| 279 | int32_t window, void* Y) { | ||
| 280 | 4 | const char* L = "windowPartitionForward"; | |
| 281 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
|
4 | if (!need(L, {X, Y}) || !needPositive(L, {window})) return; |
| 282 |
2/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
4 | if (H % window != 0 || W % window != 0) { setError("windowPartitionForward: H and W must be multiples of window"); return; } |
| 283 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!needElems(L, "X", T(X), elems({N, C, H, W}))) return; |
| 284 | BROTENSOR_API_TRY | ||
| 285 |
3/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
4 | brotensor::window_partition_forward(*toTensor(X), N, C, H, W, window, *toTensor(Y)); |
| 286 |
0/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
4 | BROTENSOR_API_CATCH("windowPartitionForward") |
| 287 | 4 | } | |
| 288 | |||
| 289 | 4 | void bro_tensor_windowReverseForward(void* X, int32_t N, int32_t C, int32_t H, int32_t W, | |
| 290 | int32_t window, void* Y) { | ||
| 291 | 4 | const char* L = "windowReverseForward"; | |
| 292 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
|
4 | if (!need(L, {X, Y}) || !needPositive(L, {window})) return; |
| 293 |
2/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
4 | if (H % window != 0 || W % window != 0) { setError("windowReverseForward: H and W must be multiples of window"); return; } |
| 294 | // The windowed batch holds the same N*C*H*W elements, re-tiled. | ||
| 295 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!needElems(L, "X", T(X), elems({N, C, H, W}))) return; |
| 296 | BROTENSOR_API_TRY | ||
| 297 |
3/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
4 | brotensor::window_reverse_forward(*toTensor(X), N, C, H, W, window, *toTensor(Y)); |
| 298 |
0/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
4 | BROTENSOR_API_CATCH("windowReverseForward") |
| 299 | 4 | } | |
| 300 | |||
| 301 | // channelMajor false (the old binding's default) = block-major | ||
| 302 | // c_out = block*C + c_in (Qwen-VL); true = torch pixel_unshuffle ordering. | ||
| 303 | 4 | void bro_tensor_spatialMerge2x2Forward(void* X, int32_t N, int32_t C, int32_t H, int32_t W, | |
| 304 | void* Y, bool channelMajor) { | ||
| 305 | 4 | const char* L = "spatialMerge2x2Forward"; | |
| 306 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!need(L, {X, Y})) return; |
| 307 |
2/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
4 | if (H % 2 != 0 || W % 2 != 0) { setError("spatialMerge2x2Forward: H and W must be even"); return; } |
| 308 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!needElems(L, "X", T(X), elems({N, C, H, W}))) return; |
| 309 | BROTENSOR_API_TRY | ||
| 310 |
3/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
4 | brotensor::spatial_merge_2x2_forward(*toTensor(X), N, C, H, W, channelMajor, *toTensor(Y)); |
| 311 |
0/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
4 | BROTENSOR_API_CATCH("spatialMerge2x2Forward") |
| 312 | 4 | } | |
| 313 | |||
| 314 | // ---- batch norm ------------------------------------------------------------ | ||
| 315 | |||
| 316 | 2 | void bro_tensor_batchNormForward(void* X, void* gamma, void* beta, void* runningMean, void* runningVar, | |
| 317 | int32_t N, int32_t C, int32_t H, int32_t W, | ||
| 318 | double eps, double momentum, void* Y, void* savedMean, void* savedRstd) { | ||
| 319 | 2 | const char* L = "batchNormForward"; | |
| 320 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!need(L, {X, gamma, beta, runningMean, runningVar, Y, savedMean, savedRstd})) return; |
| 321 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
|
6 | if (!needOperands(L, T(X), {{"X", T(X), elems({N, C, H, W})}, {"gamma", T(gamma), C}, {"beta", T(beta), C}, |
| 322 | 4 | {"runningMean", T(runningMean), C}, {"runningVar", T(runningVar), C}})) return; | |
| 323 | BROTENSOR_API_TRY | ||
| 324 |
4/8✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
|
4 | brotensor::batch_norm_forward(*toTensor(X), *toTensor(gamma), *toTensor(beta), |
| 325 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | *toTensor(runningMean), *toTensor(runningVar), |
| 326 | 2 | N, C, H, W, static_cast<float>(eps), static_cast<float>(momentum), | |
| 327 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | *toTensor(Y), *toTensor(savedMean), *toTensor(savedRstd)); |
| 328 |
0/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
2 | BROTENSOR_API_CATCH("batchNormForward") |
| 329 | 2 | } | |
| 330 | |||
| 331 | 2 | void bro_tensor_batchNormBackward(void* X, void* gamma, void* savedMean, void* savedRstd, void* dY, | |
| 332 | int32_t N, int32_t C, int32_t H, int32_t W, | ||
| 333 | void* dX, void* dGamma, void* dBeta) { | ||
| 334 | 2 | const char* L = "batchNormBackward"; | |
| 335 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!need(L, {X, gamma, savedMean, savedRstd, dY, dX, dGamma, dBeta})) return; |
| 336 | 2 | const int64_t n = elems({N, C, H, W}); | |
| 337 | // savedMean/savedRstd are the forward's FP32 caches; dGamma/dBeta accumulate. | ||
| 338 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
|
6 | if (!needOperands(L, T(X), {{"X", T(X), n}, {"dY", T(dY), n}, {"gamma", T(gamma), C}, |
| 339 | 4 | {"dGamma", T(dGamma), C}, {"dBeta", T(dBeta), C}})) return; | |
| 340 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | if (!needMask(L, T(savedMean), C, "savedMean") || !needMask(L, T(savedRstd), C, "savedRstd")) return; |
| 341 | BROTENSOR_API_TRY | ||
| 342 |
4/8✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
|
4 | brotensor::batch_norm_backward(*toTensor(X), *toTensor(gamma), *toTensor(savedMean), |
| 343 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | *toTensor(savedRstd), *toTensor(dY), N, C, H, W, |
| 344 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | *toTensor(dX), *toTensor(dGamma), *toTensor(dBeta)); |
| 345 |
0/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
2 | BROTENSOR_API_CATCH("batchNormBackward") |
| 346 | 2 | } | |
| 347 | |||
| 348 | 4 | void bro_tensor_batchNormInference(void* X, void* gamma, void* beta, void* runningMean, void* runningVar, | |
| 349 | int32_t N, int32_t C, int32_t H, int32_t W, double eps, void* Y) { | ||
| 350 | 4 | const char* L = "batchNormInference"; | |
| 351 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!need(L, {X, gamma, beta, runningMean, runningVar, Y})) return; |
| 352 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
|
12 | if (!needOperands(L, T(X), {{"X", T(X), elems({N, C, H, W})}, {"gamma", T(gamma), C}, {"beta", T(beta), C}, |
| 353 | 8 | {"runningMean", T(runningMean), C}, {"runningVar", T(runningVar), C}})) return; | |
| 354 | BROTENSOR_API_TRY | ||
| 355 |
4/8✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
|
8 | brotensor::batch_norm_inference(*toTensor(X), *toTensor(gamma), *toTensor(beta), |
| 356 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | *toTensor(runningMean), *toTensor(runningVar), |
| 357 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | N, C, H, W, static_cast<float>(eps), *toTensor(Y)); |
| 358 |
0/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
4 | BROTENSOR_API_CATCH("batchNormInference") |
| 359 | 4 | } | |
| 360 | |||
| 361 | // ---- image preprocessing --------------------------------------------------- | ||
| 362 | |||
| 363 | 2 | void bro_tensor_imageNormalize(void* X, void* mean, void* std_, | |
| 364 | int32_t N, int32_t C, int32_t H, int32_t W, void* Y) { | ||
| 365 | 2 | const char* L = "imageNormalize"; | |
| 366 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!need(L, {X, mean, std_, Y})) return; |
| 367 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!needOperands(L, T(X), {{"X", T(X), elems({N, C, H, W})}, {"mean", T(mean), C}, {"std", T(std_), C}})) return; |
| 368 | BROTENSOR_API_TRY | ||
| 369 |
5/10✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
|
2 | brotensor::image_normalize(*toTensor(X), *toTensor(mean), *toTensor(std_), N, C, H, W, *toTensor(Y)); |
| 370 |
0/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
2 | BROTENSOR_API_CATCH("imageNormalize") |
| 371 | 2 | } | |
| 372 | |||
| 373 | // The op reads `src` from the SAME device as Y (the CUDA kernel dereferences | ||
| 374 | // it directly), but a Uint8Array is host memory. On a GPU backend the bytes | ||
| 375 | // are staged through an INT8 device tensor (size_bytes == element count, the | ||
| 376 | // contents uninterpreted) and its device pointer is what the op sees. | ||
| 377 | 10 | void bro_tensor_imageU8ToF32NhwcToNchw(const uint8_t* src, uint32_t src_len, | |
| 378 | int32_t N, int32_t H, int32_t W, int32_t C, | ||
| 379 | double scale, double bias, void* Y) { | ||
| 380 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (!need("imageU8ToF32NhwcToNchw", {Y})) return; |
| 381 | BROTENSOR_API_TRY | ||
| 382 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | if (N < 0 || H < 0 || W < 0 || C < 0) { |
| 383 | ✗ | throw std::runtime_error("negative dimension"); | |
| 384 | } | ||
| 385 | 10 | const int64_t want = static_cast<int64_t>(N) * H * W * C; | |
| 386 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
|
10 | if (static_cast<int64_t>(src_len) < want) { |
| 387 |
6/12✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
|
4 | throw std::runtime_error("src holds " + std::to_string(src_len) + " bytes, need " + |
| 388 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | std::to_string(want)); |
| 389 | } | ||
| 390 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | auto* yt = toTensor(Y); |
| 391 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
8 | const brotensor::Device dev = yt->data ? yt->device : brotensor::default_device(); |
| 392 |
3/6✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
8 | if (dev == brotensor::Device::CPU || want == 0) { |
| 393 | ✗ | brotensor::image_u8_to_f32_nhwc_to_nchw(src, N, H, W, C, static_cast<float>(scale), | |
| 394 | ✗ | static_cast<float>(bias), *yt); | |
| 395 | ✗ | } else { | |
| 396 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | brotensor::Tensor staged = brotensor::Tensor::zeros_on( |
| 397 | 8 | brotensor::Device::CPU, static_cast<int>(want), 1, brotensor::Dtype::INT8); | |
| 398 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | std::memcpy(staged.host_raw_mut(), src, static_cast<size_t>(want)); |
| 399 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | staged = staged.to(dev); |
| 400 |
2/4✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
16 | brotensor::image_u8_to_f32_nhwc_to_nchw(static_cast<const uint8_t*>(staged.data), |
| 401 | 8 | N, H, W, C, static_cast<float>(scale), | |
| 402 | 8 | static_cast<float>(bias), *yt); | |
| 403 | 8 | } | |
| 404 |
5/12✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
10 | BROTENSOR_API_CATCH("imageU8ToF32NhwcToNchw") |
| 405 | 12 | } | |
| 406 | |||
| 407 | } // extern "C" | ||
| 408 | |||
| 409 | namespace brotensor::api { | ||
| 410 | |||
| 411 | 3 | bool registerTensorNatives_conv(std::string* error) { | |
| 412 | using namespace brotensor::api::reg; | ||
| 413 | 3 | bool ok = | |
| 414 | 6 | fn("__bro_native.tensor.interp2dBackward", p(&bro_tensor_interp2dBackward), "void", | |
| 415 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | {kTensorCls, "i32", "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) && |
| 416 | 6 | fn("__bro_native.tensor.pad2dForward", p(&bro_tensor_pad2dForward), "void", | |
| 417 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | {kTensorCls, "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) && |
| 418 | 6 | fn("__bro_native.tensor.pad2dBackward", p(&bro_tensor_pad2dBackward), "void", | |
| 419 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | {kTensorCls, "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) && |
| 420 | 6 | fn("__bro_native.tensor.slice2dForward", p(&bro_tensor_slice2dForward), "void", | |
| 421 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | {kTensorCls, "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) && |
| 422 | 6 | fn("__bro_native.tensor.slice2dBackward", p(&bro_tensor_slice2dBackward), "void", | |
| 423 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | {kTensorCls, "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) && |
| 424 | 6 | fn("__bro_native.tensor.maxPool2dForward", p(&bro_tensor_maxPool2dForward), "void", | |
| 425 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | {kTensorCls, "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls, kTensorCls}, error) && |
| 426 | 6 | fn("__bro_native.tensor.maxPool2dBackward", p(&bro_tensor_maxPool2dBackward), "void", | |
| 427 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | {kTensorCls, kTensorCls, "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) && |
| 428 | 6 | fn("__bro_native.tensor.adaptiveAvgPool2dForward", p(&bro_tensor_adaptiveAvgPool2dForward), "void", | |
| 429 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | {kTensorCls, "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) && |
| 430 | 6 | fn("__bro_native.tensor.adaptiveAvgPool2dBackward", p(&bro_tensor_adaptiveAvgPool2dBackward), "void", | |
| 431 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | {kTensorCls, "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) && |
| 432 | 6 | fn("__bro_native.tensor.convTranspose2dForward", p(&bro_tensor_convTranspose2dForward), "void", | |
| 433 | 3 | {kTensorCls, kTensorCls, kDyn, "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", | |
| 434 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | "i32", "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) && |
| 435 | 6 | fn("__bro_native.tensor.convTranspose2dBackwardInput", p(&bro_tensor_convTranspose2dBackwardInput), "void", | |
| 436 | 3 | {kTensorCls, kTensorCls, "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", | |
| 437 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | "i32", "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) && |
| 438 | 6 | fn("__bro_native.tensor.convTranspose2dBackwardWeight", p(&bro_tensor_convTranspose2dBackwardWeight), "void", | |
| 439 | 3 | {kTensorCls, kTensorCls, "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", | |
| 440 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | "i32", "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) && |
| 441 | 6 | fn("__bro_native.tensor.convTranspose2dBackwardBias", p(&bro_tensor_convTranspose2dBackwardBias), "void", | |
| 442 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | {kTensorCls, "i32", "i32", "i32", "i32", kTensorCls}, error) && |
| 443 | 6 | fn("__bro_native.tensor.conv3dForward", p(&bro_tensor_conv3dForward), "void", | |
| 444 | 3 | {kTensorCls, kTensorCls, kDyn, "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", | |
| 445 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) && |
| 446 | 6 | fn("__bro_native.tensor.windowPartitionForward", p(&bro_tensor_windowPartitionForward), "void", | |
| 447 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | {kTensorCls, "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) && |
| 448 | 6 | fn("__bro_native.tensor.windowReverseForward", p(&bro_tensor_windowReverseForward), "void", | |
| 449 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | {kTensorCls, "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) && |
| 450 | 6 | fn("__bro_native.tensor.spatialMerge2x2Forward", p(&bro_tensor_spatialMerge2x2Forward), "void", | |
| 451 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | {kTensorCls, "i32", "i32", "i32", "i32", kTensorCls, "bool"}, error) && |
| 452 | 6 | fn("__bro_native.tensor.batchNormForward", p(&bro_tensor_batchNormForward), "void", | |
| 453 | 3 | {kTensorCls, kTensorCls, kTensorCls, kTensorCls, kTensorCls, "i32", "i32", "i32", "i32", | |
| 454 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | "f64", "f64", kTensorCls, kTensorCls, kTensorCls}, error) && |
| 455 | 6 | fn("__bro_native.tensor.batchNormBackward", p(&bro_tensor_batchNormBackward), "void", | |
| 456 | 3 | {kTensorCls, kTensorCls, kTensorCls, kTensorCls, kTensorCls, "i32", "i32", "i32", "i32", | |
| 457 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | kTensorCls, kTensorCls, kTensorCls}, error) && |
| 458 | 6 | fn("__bro_native.tensor.batchNormInference", p(&bro_tensor_batchNormInference), "void", | |
| 459 | 3 | {kTensorCls, kTensorCls, kTensorCls, kTensorCls, kTensorCls, "i32", "i32", "i32", "i32", | |
| 460 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | "f64", kTensorCls}, error) && |
| 461 | 6 | fn("__bro_native.tensor.imageNormalize", p(&bro_tensor_imageNormalize), "void", | |
| 462 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
|
6 | {kTensorCls, kTensorCls, kTensorCls, "i32", "i32", "i32", "i32", kTensorCls}, error) && |
| 463 | 6 | fn("__bro_native.tensor.imageU8ToF32NhwcToNchw", p(&bro_tensor_imageU8ToF32NhwcToNchw), "void", | |
| 464 | 3 | {"u8[]", "i32", "i32", "i32", "i32", "f64", "f64", kTensorCls}, error); | |
| 465 | 3 | return ok; | |
| 466 | } | ||
| 467 | |||
| 468 | } // namespace brotensor::api | ||
| 469 |