src/api/native_tensor_ops.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "native_tensor_decl.h" | ||
| 2 | #include "api_internal.h" | ||
| 3 | #include "brotensor/detail/dispatch.h" | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | |||
| 7 | using namespace brotensor::api; | ||
| 8 | using brotensor::Tensor; | ||
| 9 | |||
| 10 | // Every body checks its operands against the dims before brotensor sees them | ||
| 11 | // (api_internal.h "input-size contract") and runs under BROTENSOR_API_TRY: | ||
| 12 | // an op that throws records the message for the wrapper's chk(). | ||
| 13 | // | ||
| 14 | // Outputs an op resizes are not checked; outputs it ACCUMULATES into (the | ||
| 15 | // dW / dB of a backward, "caller zeros") are, because the op writes them at | ||
| 16 | // the size the dims say. | ||
| 17 | |||
| 18 | namespace { | ||
| 19 | |||
| 20 | // A unary map: y = f(x). The op resizes y. | ||
| 21 | template <class Op> | ||
| 22 | 10 | void unary(const char* L, void* x, void* y, Op op) { | |
| 23 | 10 | auto* xt = toTensor(x); | |
| 24 | 10 | auto* yt = toTensor(y); | |
| 25 |
3/20✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ 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.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✓ Branch 19 taken 6 times.
|
10 | if (!need(L, {xt, yt})) return; |
| 26 | BROTENSOR_API_TRY | ||
| 27 |
3/20✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ 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.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 6 times.
✗ Branch 19 not taken.
|
10 | op(*xt, *yt); |
| 28 |
0/120✗ 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.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 66 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 69 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
✗ Branch 72 not taken.
✗ Branch 73 not taken.
✗ Branch 74 not taken.
✗ Branch 75 not taken.
✗ Branch 76 not taken.
✗ Branch 77 not taken.
✗ Branch 78 not taken.
✗ Branch 79 not taken.
✗ Branch 80 not taken.
✗ Branch 81 not taken.
✗ Branch 82 not taken.
✗ Branch 83 not taken.
✗ Branch 84 not taken.
✗ Branch 85 not taken.
✗ Branch 86 not taken.
✗ Branch 87 not taken.
✗ Branch 88 not taken.
✗ Branch 89 not taken.
✗ Branch 90 not taken.
✗ Branch 91 not taken.
✗ Branch 92 not taken.
✗ Branch 93 not taken.
✗ Branch 94 not taken.
✗ Branch 95 not taken.
✗ Branch 96 not taken.
✗ Branch 97 not taken.
✗ Branch 98 not taken.
✗ Branch 99 not taken.
✗ Branch 100 not taken.
✗ Branch 101 not taken.
✗ Branch 102 not taken.
✗ Branch 103 not taken.
✗ Branch 104 not taken.
✗ Branch 105 not taken.
✗ Branch 106 not taken.
✗ Branch 107 not taken.
✗ Branch 108 not taken.
✗ Branch 109 not taken.
✗ Branch 110 not taken.
✗ Branch 111 not taken.
✗ Branch 112 not taken.
✗ Branch 113 not taken.
✗ Branch 114 not taken.
✗ Branch 115 not taken.
✗ Branch 116 not taken.
✗ Branch 117 not taken.
✗ Branch 118 not taken.
✗ Branch 119 not taken.
|
10 | BROTENSOR_API_CATCH(L) |
| 29 | 10 | } | |
| 30 | |||
| 31 | // Its backward: dX = f'(a) * dY, `a` being the forward input or output. | ||
| 32 | template <class Op> | ||
| 33 | 8 | void unaryBackward(const char* L, void* a, void* dY, void* dX, Op op) { | |
| 34 | 8 | auto* at = toTensor(a); | |
| 35 | 8 | auto* dyt = toTensor(dY); | |
| 36 | 8 | auto* dxt = toTensor(dX); | |
| 37 |
4/16✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 2 times.
|
8 | if (!need(L, {at, dyt, dxt})) return; |
| 38 |
4/16✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 2 times.
|
8 | if (!needPair(L, "dY", dyt, at)) return; |
| 39 | BROTENSOR_API_TRY | ||
| 40 | ✗ | op(*at, *dyt, *dxt); | |
| 41 | ✗ | BROTENSOR_API_CATCH(L) | |
| 42 | 8 | } | |
| 43 | |||
| 44 | // A gated unit's input is (B, 2*D): an even last dim. | ||
| 45 | ✗ | bool needGatedInput(const char* L, const Tensor* xt) { | |
| 46 | ✗ | if (xt->cols % 2 != 0) { | |
| 47 | ✗ | setError(std::string(L) + ": X must be (B, 2*D) — an even column count"); | |
| 48 | ✗ | return false; | |
| 49 | } | ||
| 50 | ✗ | return true; | |
| 51 | ✗ | } | |
| 52 | |||
| 53 | template <class Op> | ||
| 54 | ✗ | void gatedForward(const char* L, void* X, void* Y, Op op) { | |
| 55 | ✗ | auto* xt = toTensor(X); | |
| 56 | ✗ | auto* yt = toTensor(Y); | |
| 57 | ✗ | if (!need(L, {xt, yt})) return; | |
| 58 | ✗ | if (!needGatedInput(L, xt)) return; | |
| 59 | BROTENSOR_API_TRY | ||
| 60 | ✗ | op(*xt, *yt); | |
| 61 | ✗ | BROTENSOR_API_CATCH(L) | |
| 62 | ✗ | } | |
| 63 | |||
| 64 | template <class Op> | ||
| 65 | ✗ | void gatedBackward(const char* L, void* X, void* dY, void* dX, Op op) { | |
| 66 | ✗ | auto* xt = toTensor(X); | |
| 67 | ✗ | auto* dyt = toTensor(dY); | |
| 68 | ✗ | auto* dxt = toTensor(dX); | |
| 69 | ✗ | if (!need(L, {xt, dyt, dxt})) return; | |
| 70 | ✗ | if (!needGatedInput(L, xt)) return; | |
| 71 | ✗ | if (!needElems(L, "dY", dyt, elems({xt->rows, xt->cols / 2}))) return; | |
| 72 | ✗ | if (!needSameDtype(L, "dY", dyt, xt)) return; | |
| 73 | BROTENSOR_API_TRY | ||
| 74 | ✗ | op(*xt, *dyt, *dxt); | |
| 75 | ✗ | BROTENSOR_API_CATCH(L) | |
| 76 | ✗ | } | |
| 77 | |||
| 78 | // An NCHW resample X:(N, C*H*W) -> Y. The op resizes Y. | ||
| 79 | template <class Op> | ||
| 80 | 4 | void nchwMap(const char* L, void* X, int32_t N, int32_t C, int32_t H, int32_t W, void* Y, Op op) { | |
| 81 | 4 | auto* xt = toTensor(X); | |
| 82 | 4 | auto* yt = toTensor(Y); | |
| 83 |
2/20✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ 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 taken 2 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
|
4 | if (!need(L, {xt, yt})) return; |
| 84 |
2/20✓ Branch 0 taken 2 times.
✗ 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 taken 2 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
|
4 | if (!needElems(L, "X", xt, elems({N, C, H, W}))) return; |
| 85 | BROTENSOR_API_TRY | ||
| 86 | ✗ | op(*xt, *yt); | |
| 87 | ✗ | BROTENSOR_API_CATCH(L) | |
| 88 | 4 | } | |
| 89 | |||
| 90 | // downsample_avg_2x wants an even plane. | ||
| 91 | 2 | bool needEvenPlane(const char* L, int32_t H, int32_t W) { | |
| 92 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
2 | if (H % 2 != 0 || W % 2 != 0) { |
| 93 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | setError(std::string(L) + ": H and W must be even"); |
| 94 | 2 | return false; | |
| 95 | } | ||
| 96 | ✗ | return true; | |
| 97 | 2 | } | |
| 98 | |||
| 99 | } // namespace | ||
| 100 | |||
| 101 | extern "C" { | ||
| 102 | |||
| 103 | 4 | void bro_tensor_linearForward(void* W, void* b, void* x, void* y) { | |
| 104 | 4 | const char* L = "linearForward"; | |
| 105 | 4 | auto* wt = toTensor(W); | |
| 106 | 4 | auto* bt = toTensor(b); | |
| 107 | 4 | auto* xt = toTensor(x); | |
| 108 | 4 | auto* yt = toTensor(y); | |
| 109 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!need(L, {wt, bt, xt, yt})) return; |
| 110 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
4 | if (!needElems(L, "b", bt, wt->rows) || !needElems(L, "x", xt, wt->cols)) return; |
| 111 | ✗ | if (!needSameDtype(L, "b", bt, wt) || !needSameDtype(L, "x", xt, wt)) return; | |
| 112 | BROTENSOR_API_TRY | ||
| 113 | ✗ | brotensor::linear_forward(*wt, *bt, *xt, *yt); | |
| 114 | ✗ | BROTENSOR_API_CATCH(L) | |
| 115 | 4 | } | |
| 116 | |||
| 117 | 2 | void bro_tensor_linearBackward(void* W, void* x, void* dY, void* dX, void* dW, void* dB) { | |
| 118 | 2 | const char* L = "linearBackward"; | |
| 119 | 2 | auto* wt = toTensor(W); | |
| 120 | 2 | auto* xt = toTensor(x); | |
| 121 | 2 | auto* dyt = toTensor(dY); | |
| 122 | 2 | auto* dxt = toTensor(dX); | |
| 123 | 2 | auto* dwt = toTensor(dW); | |
| 124 | 2 | auto* dbt = toTensor(dB); | |
| 125 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!need(L, {wt, xt, dyt, dxt, dwt, dbt})) return; |
| 126 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | if (!needElems(L, "x", xt, wt->cols) || !needElems(L, "dY", dyt, wt->rows)) return; |
| 127 | // dW / dB accumulate at the forward's size — "caller zeros". | ||
| 128 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | if (!needElems(L, "dW", dwt, elems({wt->rows, wt->cols})) || !needElems(L, "dB", dbt, wt->rows)) return; |
| 129 | ✗ | for (const Tensor* t : {xt, dyt, dwt, dbt}) { | |
| 130 | ✗ | if (!needSameDtype(L, "every operand", t, wt)) return; | |
| 131 | } | ||
| 132 | BROTENSOR_API_TRY | ||
| 133 | ✗ | brotensor::linear_backward(*wt, *xt, *dyt, *dxt, *dwt, *dbt); | |
| 134 | ✗ | BROTENSOR_API_CATCH(L) | |
| 135 | 2 | } | |
| 136 | |||
| 137 | 2 | void bro_tensor_reluForward(void* x, void* y) { | |
| 138 | 4 | unary("reluForward", x, y, [](const Tensor& a, Tensor& b) { brotensor::relu_forward(a, b); }); | |
| 139 | 2 | } | |
| 140 | |||
| 141 | 2 | void bro_tensor_reluBackward(void* x, void* dY, void* dX) { | |
| 142 | 2 | unaryBackward("reluBackward", x, dY, dX, | |
| 143 | ✗ | [](const Tensor& a, const Tensor& g, Tensor& o) { brotensor::relu_backward(a, g, o); }); | |
| 144 | 2 | } | |
| 145 | |||
| 146 | 2 | void bro_tensor_tanhForward(void* x, void* y) { | |
| 147 | 4 | unary("tanhForward", x, y, [](const Tensor& a, Tensor& b) { brotensor::tanh_forward(a, b); }); | |
| 148 | 2 | } | |
| 149 | |||
| 150 | 2 | void bro_tensor_tanhBackward(void* y, void* dY, void* dX) { | |
| 151 | 2 | unaryBackward("tanhBackward", y, dY, dX, | |
| 152 | ✗ | [](const Tensor& a, const Tensor& g, Tensor& o) { brotensor::tanh_backward(a, g, o); }); | |
| 153 | 2 | } | |
| 154 | |||
| 155 | ✗ | void bro_tensor_sigmoidForward(void* x, void* y) { | |
| 156 | ✗ | unary("sigmoidForward", x, y, [](const Tensor& a, Tensor& b) { brotensor::sigmoid_forward(a, b); }); | |
| 157 | ✗ | } | |
| 158 | |||
| 159 | ✗ | void bro_tensor_sigmoidBackward(void* y, void* dY, void* dX) { | |
| 160 | ✗ | unaryBackward("sigmoidBackward", y, dY, dX, | |
| 161 | ✗ | [](const Tensor& a, const Tensor& g, Tensor& o) { brotensor::sigmoid_backward(a, g, o); }); | |
| 162 | ✗ | } | |
| 163 | |||
| 164 | 6 | void bro_tensor_addInplace(void* y, void* x) { | |
| 165 | 6 | const char* L = "addInplace"; | |
| 166 | 6 | auto* yt = toTensor(y); | |
| 167 | 6 | auto* xt = toTensor(x); | |
| 168 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (!need(L, {yt, xt})) return; |
| 169 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
|
6 | if (!needPair(L, "x", xt, yt)) return; |
| 170 | BROTENSOR_API_TRY | ||
| 171 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | brotensor::add_inplace(*yt, *xt); |
| 172 |
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) |
| 173 | 6 | } | |
| 174 | |||
| 175 | ✗ | void bro_tensor_addScalarInplace(void* y, double s) { | |
| 176 | ✗ | const char* L = "addScalarInplace"; | |
| 177 | ✗ | auto* yt = toTensor(y); | |
| 178 | ✗ | if (!need(L, {yt})) return; | |
| 179 | BROTENSOR_API_TRY | ||
| 180 | ✗ | brotensor::add_scalar_inplace(*yt, static_cast<float>(s)); | |
| 181 | ✗ | BROTENSOR_API_CATCH(L) | |
| 182 | ✗ | } | |
| 183 | |||
| 184 | 2 | void bro_tensor_scaleInplace(void* y, double s) { | |
| 185 | 2 | const char* L = "scaleInplace"; | |
| 186 | 2 | auto* yt = toTensor(y); | |
| 187 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!need(L, {yt})) return; |
| 188 | BROTENSOR_API_TRY | ||
| 189 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | brotensor::scale_inplace(*yt, static_cast<float>(s)); |
| 190 |
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) |
| 191 | 2 | } | |
| 192 | |||
| 193 | 2 | void bro_tensor_mulInplace(void* y, void* x) { | |
| 194 | 2 | const char* L = "mulInplace"; | |
| 195 | 2 | auto* yt = toTensor(y); | |
| 196 | 2 | auto* xt = toTensor(x); | |
| 197 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!need(L, {yt, xt})) return; |
| 198 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!needPair(L, "x", xt, yt)) return; |
| 199 | BROTENSOR_API_TRY | ||
| 200 | ✗ | brotensor::mul_inplace(*yt, *xt); | |
| 201 | ✗ | BROTENSOR_API_CATCH(L) | |
| 202 | 2 | } | |
| 203 | |||
| 204 | 2 | void bro_tensor_clamp(void* y, double lo, double hi) { | |
| 205 | 2 | const char* L = "clamp"; | |
| 206 | 2 | auto* yt = toTensor(y); | |
| 207 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!need(L, {yt})) return; |
| 208 | BROTENSOR_API_TRY | ||
| 209 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | brotensor::clamp(*yt, static_cast<float>(lo), static_cast<float>(hi)); |
| 210 |
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) |
| 211 | 2 | } | |
| 212 | |||
| 213 | ✗ | void bro_tensor_siluForward(void* x, void* y) { | |
| 214 | ✗ | unary("siluForward", x, y, [](const Tensor& a, Tensor& b) { brotensor::silu_forward(a, b); }); | |
| 215 | ✗ | } | |
| 216 | |||
| 217 | 2 | void bro_tensor_siluBackward(void* x, void* dY, void* dX) { | |
| 218 | 2 | unaryBackward("siluBackward", x, dY, dX, | |
| 219 | ✗ | [](const Tensor& a, const Tensor& g, Tensor& o) { brotensor::silu_backward(a, g, o); }); | |
| 220 | 2 | } | |
| 221 | |||
| 222 | ✗ | void bro_tensor_geluForward(void* x, void* y) { | |
| 223 | ✗ | unary("geluForward", x, y, [](const Tensor& a, Tensor& b) { brotensor::gelu_forward(a, b); }); | |
| 224 | ✗ | } | |
| 225 | |||
| 226 | ✗ | void bro_tensor_geluBackward(void* x, void* dY, void* dX) { | |
| 227 | ✗ | unaryBackward("geluBackward", x, dY, dX, | |
| 228 | ✗ | [](const Tensor& a, const Tensor& g, Tensor& o) { brotensor::gelu_backward(a, g, o); }); | |
| 229 | ✗ | } | |
| 230 | |||
| 231 | ✗ | void bro_tensor_geluExactForward(void* x, void* y) { | |
| 232 | ✗ | unary("geluExactForward", x, y, [](const Tensor& a, Tensor& b) { brotensor::gelu_exact_forward(a, b); }); | |
| 233 | ✗ | } | |
| 234 | |||
| 235 | ✗ | void bro_tensor_geluExactBackward(void* x, void* dY, void* dX) { | |
| 236 | ✗ | unaryBackward("geluExactBackward", x, dY, dX, | |
| 237 | ✗ | [](const Tensor& a, const Tensor& g, Tensor& o) { brotensor::gelu_exact_backward(a, g, o); }); | |
| 238 | ✗ | } | |
| 239 | |||
| 240 | ✗ | void bro_tensor_quickGeluForward(void* x, void* y) { | |
| 241 | ✗ | unary("quickGeluForward", x, y, [](const Tensor& a, Tensor& b) { brotensor::quick_gelu_forward(a, b); }); | |
| 242 | ✗ | } | |
| 243 | |||
| 244 | ✗ | void bro_tensor_quickGeluBackward(void* x, void* dY, void* dX) { | |
| 245 | ✗ | unaryBackward("quickGeluBackward", x, dY, dX, | |
| 246 | ✗ | [](const Tensor& a, const Tensor& g, Tensor& o) { brotensor::quick_gelu_backward(a, g, o); }); | |
| 247 | ✗ | } | |
| 248 | |||
| 249 | ✗ | void bro_tensor_swigluForward(void* X, void* Y) { | |
| 250 | ✗ | gatedForward("swigluForward", X, Y, [](const Tensor& a, Tensor& b) { brotensor::swiglu_forward(a, b); }); | |
| 251 | ✗ | } | |
| 252 | |||
| 253 | ✗ | void bro_tensor_swigluBackward(void* X, void* dY, void* dX) { | |
| 254 | ✗ | gatedBackward("swigluBackward", X, dY, dX, | |
| 255 | ✗ | [](const Tensor& a, const Tensor& g, Tensor& o) { brotensor::swiglu_backward(a, g, o); }); | |
| 256 | ✗ | } | |
| 257 | |||
| 258 | ✗ | void bro_tensor_gegluForward(void* X, void* Y) { | |
| 259 | ✗ | gatedForward("gegluForward", X, Y, [](const Tensor& a, Tensor& b) { brotensor::geglu_forward(a, b); }); | |
| 260 | ✗ | } | |
| 261 | |||
| 262 | ✗ | void bro_tensor_gegluBackward(void* X, void* dY, void* dX) { | |
| 263 | ✗ | gatedBackward("gegluBackward", X, dY, dX, | |
| 264 | ✗ | [](const Tensor& a, const Tensor& g, Tensor& o) { brotensor::geglu_backward(a, g, o); }); | |
| 265 | ✗ | } | |
| 266 | |||
| 267 | ✗ | void bro_tensor_gegluExactForward(void* X, void* Y) { | |
| 268 | ✗ | gatedForward("gegluExactForward", X, Y, [](const Tensor& a, Tensor& b) { brotensor::geglu_exact_forward(a, b); }); | |
| 269 | ✗ | } | |
| 270 | |||
| 271 | ✗ | void bro_tensor_gegluExactBackward(void* X, void* dY, void* dX) { | |
| 272 | ✗ | gatedBackward("gegluExactBackward", X, dY, dX, | |
| 273 | ✗ | [](const Tensor& a, const Tensor& g, Tensor& o) { brotensor::geglu_exact_backward(a, g, o); }); | |
| 274 | ✗ | } | |
| 275 | |||
| 276 | ✗ | void bro_tensor_softmaxForward(void* logits, void* probs, double temp) { | |
| 277 | ✗ | const char* L = "softmaxForward"; | |
| 278 | ✗ | auto* lt = toTensor(logits); | |
| 279 | ✗ | auto* pt = toTensor(probs); | |
| 280 | ✗ | if (!need(L, {lt, pt})) return; | |
| 281 | BROTENSOR_API_TRY | ||
| 282 | ✗ | if (temp != 1.0 && temp > 0.0) { | |
| 283 | ✗ | auto scaled = lt->clone(); | |
| 284 | ✗ | brotensor::scale_inplace(scaled, static_cast<float>(1.0 / temp)); | |
| 285 | ✗ | brotensor::softmax_forward(scaled, *pt); | |
| 286 | ✗ | } else { | |
| 287 | ✗ | brotensor::softmax_forward(*lt, *pt); | |
| 288 | } | ||
| 289 | ✗ | BROTENSOR_API_CATCH(L) | |
| 290 | ✗ | } | |
| 291 | |||
| 292 | 2 | void bro_tensor_softmaxBackward(void* probs, void* dProbs, void* dLogits) { | |
| 293 | 2 | unaryBackward("softmaxBackward", probs, dProbs, dLogits, | |
| 294 | ✗ | [](const Tensor& a, const Tensor& g, Tensor& o) { brotensor::softmax_backward(a, g, o); }); | |
| 295 | 2 | } | |
| 296 | |||
| 297 | 4 | void bro_tensor_matmul(void* A, void* B, void* C) { | |
| 298 | 4 | const char* L = "matmul"; | |
| 299 | 4 | auto* at = toTensor(A); | |
| 300 | 4 | auto* bt = toTensor(B); | |
| 301 | 4 | auto* ct = toTensor(C); | |
| 302 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!need(L, {at, bt, ct})) return; |
| 303 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if (at->cols != bt->rows) { |
| 304 |
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 | setError("matmul: A is (" + std::to_string(at->rows) + "," + std::to_string(at->cols) + |
| 305 |
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.
|
2 | "), B is (" + std::to_string(bt->rows) + "," + std::to_string(bt->cols) + "); A.cols must equal B.rows"); |
| 306 | 2 | return; | |
| 307 | } | ||
| 308 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (!needSameDtype(L, "B", bt, at)) return; |
| 309 | BROTENSOR_API_TRY | ||
| 310 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | brotensor::matmul(*at, *bt, *ct); |
| 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.
|
2 | BROTENSOR_API_CATCH(L) |
| 312 | 4 | } | |
| 313 | |||
| 314 | ✗ | void bro_tensor_matmulBackward(void* A, void* B, void* dC, void* dA, void* dB) { | |
| 315 | ✗ | const char* L = "matmulBackward"; | |
| 316 | ✗ | auto* at = toTensor(A); | |
| 317 | ✗ | auto* bt = toTensor(B); | |
| 318 | ✗ | auto* dct = toTensor(dC); | |
| 319 | ✗ | auto* dat = toTensor(dA); | |
| 320 | ✗ | auto* dbt = toTensor(dB); | |
| 321 | ✗ | if (!need(L, {at, bt, dct, dat, dbt})) return; | |
| 322 | ✗ | if (at->cols != bt->rows) { | |
| 323 | ✗ | setError("matmulBackward: A.cols must equal B.rows"); | |
| 324 | ✗ | return; | |
| 325 | } | ||
| 326 | ✗ | if (!needElems(L, "dC", dct, elems({at->rows, bt->cols}))) return; | |
| 327 | // dA / dB accumulate — "caller pre-sizes and zeros". | ||
| 328 | ✗ | if (!needSameSize(L, "dA", dat, at) || !needSameSize(L, "dB", dbt, bt)) return; | |
| 329 | ✗ | for (const Tensor* t : {bt, dct, dat, dbt}) { | |
| 330 | ✗ | if (!needSameDtype(L, "every operand", t, at)) return; | |
| 331 | } | ||
| 332 | BROTENSOR_API_TRY | ||
| 333 | ✗ | brotensor::matmul_backward(*at, *bt, *dct, *dat, *dbt); | |
| 334 | ✗ | BROTENSOR_API_CATCH(L) | |
| 335 | ✗ | } | |
| 336 | |||
| 337 | 8 | void bro_tensor_conv2dForward(void* X, void* Wt, uint64_t bias_bits, int32_t N, int32_t C_in, int32_t H, int32_t W, int32_t C_out, int32_t kH, int32_t kW, int32_t sH, int32_t sW, int32_t pH, int32_t pW, int32_t dH, int32_t dW, int32_t groups, void* Y) { | |
| 338 | 8 | const char* L = "conv2dForward"; | |
| 339 | 8 | auto* xt = toTensor(X); | |
| 340 | 8 | auto* wt = toTensor(Wt); | |
| 341 | 8 | auto* yt = toTensor(Y); | |
| 342 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (!need(L, {xt, wt, yt})) return; |
| 343 | 8 | const Tensor* bias_t = tensorFromValue(bias_bits); | |
| 344 | 8 | int64_t H_out = 0, W_out = 0; | |
| 345 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
|
8 | if (!convGeom2d(L, C_in, C_out, H, W, kH, kW, sH, sW, pH, pW, dH, dW, groups, H_out, W_out)) return; |
| 346 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!needNonNegative(L, {N})) return; |
| 347 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if (!needElems(L, "X", xt, elems({N, C_in, H, W}))) return; |
| 348 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (!needElems(L, "Wt", wt, elems({C_out, C_in / groups, kH, kW}))) return; |
| 349 | ✗ | if (!needSameDtype(L, "Wt", wt, xt)) return; | |
| 350 | ✗ | if (bias_t && (!needElems(L, "bias", bias_t, C_out) || !needSameDtype(L, "bias", bias_t, xt))) return; | |
| 351 | BROTENSOR_API_TRY | ||
| 352 | ✗ | brotensor::conv2d_forward(*xt, *wt, bias_t, N, C_in, H, W, C_out, kH, kW, sH, sW, pH, pW, dH, dW, groups, *yt); | |
| 353 | ✗ | BROTENSOR_API_CATCH(L) | |
| 354 | 8 | } | |
| 355 | |||
| 356 | ✗ | void bro_tensor_conv2dBackwardInput(void* Wt, void* dY, int32_t N, int32_t C_in, int32_t H, int32_t W, int32_t C_out, int32_t kH, int32_t kW, int32_t sH, int32_t sW, int32_t pH, int32_t pW, int32_t dH, int32_t dW, int32_t groups, void* dX) { | |
| 357 | ✗ | const char* L = "conv2dBackwardInput"; | |
| 358 | ✗ | auto* wt = toTensor(Wt); | |
| 359 | ✗ | auto* dyt = toTensor(dY); | |
| 360 | ✗ | auto* dxt = toTensor(dX); | |
| 361 | ✗ | if (!need(L, {wt, dyt, dxt})) return; | |
| 362 | ✗ | int64_t H_out = 0, W_out = 0; | |
| 363 | ✗ | if (!convGeom2d(L, C_in, C_out, H, W, kH, kW, sH, sW, pH, pW, dH, dW, groups, H_out, W_out)) return; | |
| 364 | ✗ | if (!needNonNegative(L, {N})) return; | |
| 365 | ✗ | if (!needElems(L, "Wt", wt, elems({C_out, C_in / groups, kH, kW}))) return; | |
| 366 | ✗ | if (!needElems(L, "dY", dyt, elems({N, C_out, H_out, W_out}))) return; | |
| 367 | ✗ | if (!needSameDtype(L, "dY", dyt, wt)) return; | |
| 368 | BROTENSOR_API_TRY | ||
| 369 | ✗ | brotensor::conv2d_backward_input(*wt, *dyt, N, C_in, H, W, C_out, kH, kW, sH, sW, pH, pW, dH, dW, groups, *dxt); | |
| 370 | ✗ | BROTENSOR_API_CATCH(L) | |
| 371 | ✗ | } | |
| 372 | |||
| 373 | ✗ | void bro_tensor_conv2dBackwardWeight(void* X, void* dY, int32_t N, int32_t C_in, int32_t H, int32_t W, int32_t C_out, int32_t kH, int32_t kW, int32_t sH, int32_t sW, int32_t pH, int32_t pW, int32_t dH, int32_t dW, int32_t groups, void* dWt) { | |
| 374 | ✗ | const char* L = "conv2dBackwardWeight"; | |
| 375 | ✗ | auto* xt = toTensor(X); | |
| 376 | ✗ | auto* dyt = toTensor(dY); | |
| 377 | ✗ | auto* dwt = toTensor(dWt); | |
| 378 | ✗ | if (!need(L, {xt, dyt, dwt})) return; | |
| 379 | ✗ | int64_t H_out = 0, W_out = 0; | |
| 380 | ✗ | if (!convGeom2d(L, C_in, C_out, H, W, kH, kW, sH, sW, pH, pW, dH, dW, groups, H_out, W_out)) return; | |
| 381 | ✗ | if (!needNonNegative(L, {N})) return; | |
| 382 | ✗ | if (!needElems(L, "X", xt, elems({N, C_in, H, W}))) return; | |
| 383 | ✗ | if (!needElems(L, "dY", dyt, elems({N, C_out, H_out, W_out}))) return; | |
| 384 | // dWt accumulates — "caller zeros". | ||
| 385 | ✗ | if (!needElems(L, "dWt", dwt, elems({C_out, C_in / groups, kH, kW}))) return; | |
| 386 | ✗ | if (!needSameDtype(L, "dY", dyt, xt) || !needSameDtype(L, "dWt", dwt, xt)) return; | |
| 387 | BROTENSOR_API_TRY | ||
| 388 | ✗ | brotensor::conv2d_backward_weight(*xt, *dyt, N, C_in, H, W, C_out, kH, kW, sH, sW, pH, pW, dH, dW, groups, *dwt); | |
| 389 | ✗ | BROTENSOR_API_CATCH(L) | |
| 390 | ✗ | } | |
| 391 | |||
| 392 | ✗ | void bro_tensor_conv2dBackwardBias(void* dY, int32_t N, int32_t C_out, int32_t H_out, int32_t W_out, void* dB) { | |
| 393 | ✗ | const char* L = "conv2dBackwardBias"; | |
| 394 | ✗ | auto* dyt = toTensor(dY); | |
| 395 | ✗ | auto* dbt = toTensor(dB); | |
| 396 | ✗ | if (!need(L, {dyt, dbt})) return; | |
| 397 | ✗ | if (!needElems(L, "dY", dyt, elems({N, C_out, H_out, W_out}))) return; | |
| 398 | ✗ | if (!needElems(L, "dB", dbt, C_out) || !needSameDtype(L, "dB", dbt, dyt)) return; | |
| 399 | BROTENSOR_API_TRY | ||
| 400 | ✗ | brotensor::conv2d_backward_bias(*dyt, N, C_out, H_out, W_out, *dbt); | |
| 401 | ✗ | BROTENSOR_API_CATCH(L) | |
| 402 | ✗ | } | |
| 403 | |||
| 404 | 2 | void bro_tensor_upsampleNearest2xForward(void* X, int32_t N, int32_t C, int32_t H, int32_t W, void* Y) { | |
| 405 | 4 | nchwMap("upsampleNearest2xForward", X, N, C, H, W, Y, | |
| 406 | 2 | [&](const Tensor& x, Tensor& y) { brotensor::upsample_nearest_2x(x, N, C, H, W, y); }); | |
| 407 | 2 | } | |
| 408 | |||
| 409 | // The 2x backwards take the INPUT dims; dY is the upsampled (N, C*2H*2W). | ||
| 410 | ✗ | void bro_tensor_upsampleNearest2xBackward(void* dY, int32_t N, int32_t C, int32_t H, int32_t W, void* dX) { | |
| 411 | ✗ | const char* L = "upsampleNearest2xBackward"; | |
| 412 | ✗ | auto* dyt = toTensor(dY); | |
| 413 | ✗ | auto* dxt = toTensor(dX); | |
| 414 | ✗ | if (!need(L, {dyt, dxt})) return; | |
| 415 | ✗ | if (!needNonNegative(L, {N, C, H, W})) return; | |
| 416 | ✗ | if (!needElems(L, "dY", dyt, elems({N, C, 2 * static_cast<int64_t>(H), 2 * static_cast<int64_t>(W)}))) return; | |
| 417 | BROTENSOR_API_TRY | ||
| 418 | ✗ | brotensor::upsample_nearest_2x_backward(*dyt, N, C, H, W, *dxt); | |
| 419 | ✗ | BROTENSOR_API_CATCH(L) | |
| 420 | ✗ | } | |
| 421 | |||
| 422 | ✗ | void bro_tensor_upsampleBilinear2xForward(void* X, int32_t N, int32_t C, int32_t H, int32_t W, void* Y) { | |
| 423 | ✗ | nchwMap("upsampleBilinear2xForward", X, N, C, H, W, Y, | |
| 424 | ✗ | [&](const Tensor& x, Tensor& y) { brotensor::upsample_bilinear_2x(x, N, C, H, W, y); }); | |
| 425 | ✗ | } | |
| 426 | |||
| 427 | 2 | void bro_tensor_upsampleBilinear2xBackward(void* dY, int32_t N, int32_t C, int32_t H, int32_t W, void* dX) { | |
| 428 | 2 | const char* L = "upsampleBilinear2xBackward"; | |
| 429 | 2 | auto* dyt = toTensor(dY); | |
| 430 | 2 | auto* dxt = toTensor(dX); | |
| 431 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!need(L, {dyt, dxt})) return; |
| 432 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!needNonNegative(L, {N, C, H, W})) return; |
| 433 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (!needElems(L, "dY", dyt, elems({N, C, 2 * static_cast<int64_t>(H), 2 * static_cast<int64_t>(W)}))) return; |
| 434 | BROTENSOR_API_TRY | ||
| 435 | ✗ | brotensor::upsample_bilinear_2x_backward(*dyt, N, C, H, W, *dxt); | |
| 436 | ✗ | BROTENSOR_API_CATCH(L) | |
| 437 | 2 | } | |
| 438 | |||
| 439 | 2 | void bro_tensor_downsampleAvg2xForward(void* X, int32_t N, int32_t C, int32_t H, int32_t W, void* Y) { | |
| 440 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (!needEvenPlane("downsampleAvg2xForward", H, W)) return; |
| 441 | ✗ | nchwMap("downsampleAvg2xForward", X, N, C, H, W, Y, | |
| 442 | ✗ | [&](const Tensor& x, Tensor& y) { brotensor::downsample_avg_2x(x, N, C, H, W, y); }); | |
| 443 | 2 | } | |
| 444 | |||
| 445 | ✗ | void bro_tensor_downsampleAvg2xBackward(void* dY, int32_t N, int32_t C, int32_t H, int32_t W, void* dX) { | |
| 446 | ✗ | const char* L = "downsampleAvg2xBackward"; | |
| 447 | ✗ | auto* dyt = toTensor(dY); | |
| 448 | ✗ | auto* dxt = toTensor(dX); | |
| 449 | ✗ | if (!need(L, {dyt, dxt})) return; | |
| 450 | ✗ | if (!needNonNegative(L, {N, C, H, W}) || !needEvenPlane(L, H, W)) return; | |
| 451 | ✗ | if (!needElems(L, "dY", dyt, elems({N, C, H / 2, W / 2}))) return; | |
| 452 | BROTENSOR_API_TRY | ||
| 453 | ✗ | brotensor::downsample_avg_2x_backward(*dyt, N, C, H, W, *dxt); | |
| 454 | ✗ | BROTENSOR_API_CATCH(L) | |
| 455 | ✗ | } | |
| 456 | |||
| 457 | ✗ | void bro_tensor_sumRows(void* X, void* Y) { | |
| 458 | ✗ | unary("sumRows", X, Y, [](const Tensor& a, Tensor& b) { brotensor::sum_rows(a, b); }); | |
| 459 | ✗ | } | |
| 460 | |||
| 461 | ✗ | void bro_tensor_sumCols(void* X, void* Y) { | |
| 462 | ✗ | unary("sumCols", X, Y, [](const Tensor& a, Tensor& b) { brotensor::sum_cols(a, b); }); | |
| 463 | ✗ | } | |
| 464 | |||
| 465 | 6 | void bro_tensor_argmaxRows(void* X, void* Idx) { | |
| 466 | 12 | unary("argmaxRows", X, Idx, [](const Tensor& a, Tensor& b) { brotensor::argmax_rows(a, b); }); | |
| 467 | 6 | } | |
| 468 | |||
| 469 | // A flat element copy between two tensors of one dtype on one device. Both | ||
| 470 | // ranges are checked against their tensor: this is a raw memcpy. | ||
| 471 | 10 | void bro_tensor_copyD2D(void* src, int32_t srcOff, void* dst, int32_t dstOff, int32_t n) { | |
| 472 | 10 | const char* L = "copyD2D"; | |
| 473 | 10 | auto* s = toTensor(src); | |
| 474 | 10 | auto* d = toTensor(dst); | |
| 475 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (!need(L, {s, d})) return; |
| 476 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8 times.
|
10 | if (!needNonNegative(L, {srcOff, dstOff, n})) return; |
| 477 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (n == 0) return; |
| 478 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
|
8 | if (!needSameDtype(L, "dst", d, s)) return; |
| 479 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (s->device != d->device) { |
| 480 | ✗ | setError("copyD2D: src and dst live on different devices"); | |
| 481 | ✗ | return; | |
| 482 | } | ||
| 483 | 6 | const int64_t srcEnd = static_cast<int64_t>(srcOff) + n; | |
| 484 | 6 | const int64_t dstEnd = static_cast<int64_t>(dstOff) + n; | |
| 485 |
4/4✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
|
6 | if (srcEnd > static_cast<int64_t>(s->size()) || dstEnd > static_cast<int64_t>(d->size())) { |
| 486 |
7/14✓ 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.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
|
12 | setError("copyD2D: [" + std::to_string(srcOff) + ", " + std::to_string(srcEnd) + ") of a " + |
| 487 |
7/14✓ 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.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
|
12 | std::to_string(s->size()) + "-element src into [" + std::to_string(dstOff) + ", " + |
| 488 |
6/12✓ 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.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
|
8 | std::to_string(dstEnd) + ") of a " + std::to_string(d->size()) + "-element dst is out of range"); |
| 489 | 4 | return; | |
| 490 | } | ||
| 491 | 2 | int elemSize = brotensor::dtype_size_bytes(s->dtype); | |
| 492 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (elemSize <= 0) elemSize = 4; |
| 493 | 2 | const std::size_t bytes = static_cast<std::size_t>(n) * elemSize; | |
| 494 | 2 | const std::size_t s_byte_offset = static_cast<std::size_t>(srcOff) * elemSize; | |
| 495 | 2 | const std::size_t d_byte_offset = static_cast<std::size_t>(dstOff) * elemSize; | |
| 496 | BROTENSOR_API_TRY | ||
| 497 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | if (s->is_host()) { |
| 498 | ✗ | std::memmove(reinterpret_cast<char*>(d->data) + d_byte_offset, | |
| 499 | ✗ | reinterpret_cast<const char*>(s->data) + s_byte_offset, | |
| 500 | ✗ | bytes); | |
| 501 | ✗ | } else { | |
| 502 |
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::detail::alloc_for(d->device).memcpy_d2d( |
| 503 | 2 | reinterpret_cast<char*>(d->data) + d_byte_offset, | |
| 504 | 2 | reinterpret_cast<const char*>(s->data) + s_byte_offset, | |
| 505 | 2 | bytes, d->device.index); | |
| 506 | } | ||
| 507 |
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) |
| 508 | 10 | } | |
| 509 | |||
| 510 | ✗ | void bro_tensor_nchwToSequence(void* X, int32_t N, int32_t C, int32_t H, int32_t W, void* Y) { | |
| 511 | ✗ | nchwMap("nchwToSequence", X, N, C, H, W, Y, | |
| 512 | ✗ | [&](const Tensor& x, Tensor& y) { brotensor::nchw_to_sequence(x, N, C, H, W, y); }); | |
| 513 | ✗ | } | |
| 514 | |||
| 515 | ✗ | void bro_tensor_sequenceToNchw(void* X, int32_t N, int32_t C, int32_t H, int32_t W, void* Y) { | |
| 516 | ✗ | nchwMap("sequenceToNchw", X, N, C, H, W, Y, | |
| 517 | ✗ | [&](const Tensor& x, Tensor& y) { brotensor::sequence_to_nchw(x, N, C, H, W, y); }); | |
| 518 | ✗ | } | |
| 519 | |||
| 520 | 2 | void bro_tensor_interp2dForward(void* X, int32_t N, int32_t C, int32_t H_in, int32_t W_in, int32_t H_out, int32_t W_out, int32_t mode, void* Y) { | |
| 521 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!needNonNegative("interp2dForward", {H_out, W_out})) return; |
| 522 | 4 | nchwMap("interp2dForward", X, N, C, H_in, W_in, Y, | |
| 523 | 2 | [&](const Tensor& x, Tensor& y) { brotensor::interp2d_forward(x, N, C, H_in, W_in, H_out, W_out, mode, y); }); | |
| 524 | 2 | } | |
| 525 | |||
| 526 | ✗ | void bro_tensor_interp2dAlignCornersForward(void* X, int32_t N, int32_t C, int32_t H_in, int32_t W_in, int32_t H_out, int32_t W_out, int32_t mode, void* Y) { | |
| 527 | ✗ | if (!needNonNegative("interp2dAlignCornersForward", {H_out, W_out})) return; | |
| 528 | ✗ | nchwMap("interp2dAlignCornersForward", X, N, C, H_in, W_in, Y, | |
| 529 | ✗ | [&](const Tensor& x, Tensor& y) { brotensor::interp2d_align_corners_forward(x, N, C, H_in, W_in, H_out, W_out, mode, y); }); | |
| 530 | ✗ | } | |
| 531 | |||
| 532 | ✗ | void bro_tensor_unfold2dForward(void* X, int32_t N, int32_t C, int32_t H, int32_t W, int32_t kH, int32_t kW, int32_t sH, int32_t sW, int32_t padT, int32_t padB, int32_t padL, int32_t padR, int32_t mode, void* Y) { | |
| 533 | ✗ | const char* L = "unfold2dForward"; | |
| 534 | ✗ | if (!needPositive(L, {kH, kW, sH, sW}) || !needNonNegative(L, {padT, padB, padL, padR})) return; | |
| 535 | ✗ | nchwMap(L, X, N, C, H, W, Y, | |
| 536 | ✗ | [&](const Tensor& x, Tensor& y) { brotensor::unfold2d_forward(x, N, C, H, W, kH, kW, sH, sW, padT, padB, padL, padR, mode, y); }); | |
| 537 | ✗ | } | |
| 538 | |||
| 539 | ✗ | void bro_tensor_l2NormalizeNchwForward(void* X, int32_t N, int32_t C, int32_t H, int32_t W, double eps, void* Y) { | |
| 540 | ✗ | nchwMap("l2NormalizeNchwForward", X, N, C, H, W, Y, | |
| 541 | ✗ | [&](const Tensor& x, Tensor& y) { brotensor::l2_normalize_nchw_forward(x, N, C, H, W, static_cast<float>(eps), y); }); | |
| 542 | ✗ | } | |
| 543 | |||
| 544 | ✗ | void bro_tensor_convexUpsampleForward(void* X, void* Mask, int32_t N, int32_t C, int32_t H, int32_t W, int32_t scale, void* Y) { | |
| 545 | ✗ | const char* L = "convexUpsampleForward"; | |
| 546 | ✗ | auto* mt = toTensor(Mask); | |
| 547 | ✗ | if (!need(L, {mt})) return; | |
| 548 | ✗ | if (!needPositive(L, {scale})) return; | |
| 549 | // Mask is (N, 9*scale*scale*H*W) and shares X's dtype. | ||
| 550 | ✗ | if (!needElems(L, "Mask", mt, elems({N, 9, scale, scale, H, W}))) return; | |
| 551 | ✗ | if (auto* xt = toTensor(X); xt && !needSameDtype(L, "Mask", mt, xt)) return; | |
| 552 | ✗ | nchwMap(L, X, N, C, H, W, Y, | |
| 553 | ✗ | [&](const Tensor& x, Tensor& y) { brotensor::convex_upsample_forward(x, *mt, N, C, H, W, scale, y); }); | |
| 554 | ✗ | } | |
| 555 | |||
| 556 | 2 | double bro_tensor_mseVecForward(void* pred, void* target) { | |
| 557 | 2 | const char* L = "mseVecForward"; | |
| 558 | 2 | auto* pt = toTensor(pred); | |
| 559 | 2 | auto* tt = toTensor(target); | |
| 560 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!need(L, {pt, tt})) return 0.0; |
| 561 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!needPair(L, "target", tt, pt)) return 0.0; |
| 562 | BROTENSOR_API_TRY | ||
| 563 | ✗ | return static_cast<double>(brotensor::mse_vec_forward(*pt, *tt)); | |
| 564 | ✗ | BROTENSOR_API_CATCH(L) | |
| 565 | ✗ | return 0.0; | |
| 566 | 2 | } | |
| 567 | |||
| 568 | ✗ | void bro_tensor_mseVecBackward(void* pred, void* target, void* dPred) { | |
| 569 | ✗ | const char* L = "mseVecBackward"; | |
| 570 | ✗ | auto* pt = toTensor(pred); | |
| 571 | ✗ | auto* tt = toTensor(target); | |
| 572 | ✗ | auto* dpt = toTensor(dPred); | |
| 573 | ✗ | if (!need(L, {pt, tt, dpt})) return; | |
| 574 | ✗ | if (!needPair(L, "target", tt, pt)) return; | |
| 575 | BROTENSOR_API_TRY | ||
| 576 | ✗ | brotensor::mse_vec_backward(*pt, *tt, *dpt); | |
| 577 | ✗ | BROTENSOR_API_CATCH(L) | |
| 578 | ✗ | } | |
| 579 | |||
| 580 | ✗ | void bro_tensor_mseVecPerSample(void* pred, void* target, void* dPred, void* lossPerSample) { | |
| 581 | ✗ | const char* L = "mseVecPerSample"; | |
| 582 | ✗ | auto* pt = toTensor(pred); | |
| 583 | ✗ | auto* tt = toTensor(target); | |
| 584 | ✗ | auto* dpt = toTensor(dPred); | |
| 585 | ✗ | auto* lt = toTensor(lossPerSample); | |
| 586 | ✗ | if (!need(L, {pt, tt, dpt, lt})) return; | |
| 587 | ✗ | if (!needPair(L, "target", tt, pt)) return; | |
| 588 | BROTENSOR_API_TRY | ||
| 589 | ✗ | brotensor::mse_vec_per_sample(*pt, *tt, *dpt, *lt); | |
| 590 | ✗ | BROTENSOR_API_CATCH(L) | |
| 591 | ✗ | } | |
| 592 | |||
| 593 | } // extern "C" | ||
| 594 |