已合并
docs:modify document合入 nn 仓9.0.0 aclnn 英文 #11183
liujing987913创建于 9月24日
docs:modify document合入 nn 仓9.0.0 aclnn 英文 #11183
已合并
共 382 个文件变更+181113-1
| @@ -0,0 +1,667 @@ | |||
| 1 | +# aclnnCelu&aclnnInplaceCelu | ||
| 2 | + | ||
| 3 | +[📄 View source code](https://gitcode.com/cann/ops-nn/tree/master/activation/celu_v2) | ||
| 4 | + | ||
| 5 | +## Supported Products | ||
| 6 | + | ||
| 7 | +|Product | Supported | | ||
| 8 | +|:-------------------------|:----------:| | ||
| 9 | +| Ascend 950PR/Ascend 950DT | × | | ||
| 10 | +| <term>Atlas A3 training products/Atlas A3 inference products</term> | √ | | ||
| 11 | +| <term>Atlas A2 training products/Atlas A2 inference products</term> | √ | | ||
| 12 | +| <term>Atlas 200I/500 A2 inference products</term> | × | | ||
| 13 | +| <term>Atlas inference products</term> | × | | ||
| 14 | +| <term>Atlas training products</term> | √ | | ||
| 15 | + | ||
| 16 | +## Function | ||
| 17 | + | ||
| 18 | +- Description: **aclnnCelu** applies the Continuously Differentiable Exponential Linear Unit (CELU) function for each element **x** in the input tensor **self**, and stores the obtained result in **out**. **aclnnInplaceCelu** applies the CELU function for each element **x** in the input tensor **selfRef**, and stores the obtained result in **selfRef**. | ||
| 19 | + | ||
| 20 | +- Formula: | ||
| 21 | + | ||
| 22 | +$$ | ||
| 23 | +CELU(x) = max(0, x) + min(0, \alpha \ast (exp(x / \alpha) - 1)) | ||
| 24 | +$$ | ||
| 25 | + | ||
| 26 | +## Prototype | ||
| 27 | + | ||
| 28 | +- **aclnnCelu** and **aclnnInplaceCelu** implement the same function in different ways. Select a proper operator based on your requirements. | ||
| 29 | + | ||
| 30 | + - **aclnnCelu**: An output tensor object needs to be created to store the computation result. | ||
| 31 | + - **aclnnInplaceCelu**: No output tensor object needs to be created, and the computation result is stored in the memory of the input tensor. | ||
| 32 | + | ||
| 33 | +- Each operator has [two-phase API](../../../docs/en/context/two_phase_api.md) calls. First, **aclnnCeluGetWorkspaceSize** or **aclnnInplaceCeluGetWorkspaceSize** is called to obtain the workspace size required for computation and the executor that contains the operator computation process. Then, **aclnnCelu** or **aclnnInplaceCelu** is called to perform computation. | ||
| 34 | + | ||
| 35 | +```Cpp | ||
| 36 | +aclnnStatus aclnnCeluGetWorkspaceSize( | ||
| 37 | + const aclTensor* self, | ||
| 38 | + const aclScalar* alpha, | ||
| 39 | + aclTensor* out, | ||
| 40 | + uint64_t* workspaceSize, | ||
| 41 | + aclOpExecutor** executor) | ||
| 42 | +``` | ||
| 43 | + | ||
| 44 | +```Cpp | ||
| 45 | +aclnnStatus aclnnCelu( | ||
| 46 | + void* workspace, | ||
| 47 | + uint64_t workspaceSize, | ||
| 48 | + aclOpExecutor* executor, | ||
| 49 | + aclrtStream stream) | ||
| 50 | +``` | ||
| 51 | + | ||
| 52 | +```Cpp | ||
| 53 | +aclnnStatus aclnnInplaceCeluGetWorkspaceSize( | ||
| 54 | + aclTensor* selfRef, | ||
| 55 | + const aclScalar* alpha, | ||
| 56 | + uint64_t* workspaceSize, | ||
| 57 | + aclOpExecutor** executor) | ||
| 58 | +``` | ||
| 59 | + | ||
| 60 | +```Cpp | ||
| 61 | +aclnnStatus aclnnInplaceCelu( | ||
| 62 | + void* workspace, | ||
| 63 | + uint64_t workspaceSize, | ||
| 64 | + aclOpExecutor* executor, | ||
| 65 | + aclrtStream stream) | ||
| 66 | +``` | ||
| 67 | + | ||
| 68 | +## aclnnCeluGetWorkspaceSize | ||
| 69 | + | ||
| 70 | +- **Parameters:** | ||
| 71 | + | ||
| 72 | + <table style="undefined;table-layout: fixed; width: 1370px"><colgroup> | ||
| 73 | + <col style="width: 271px"> | ||
| 74 | + <col style="width: 115px"> | ||
| 75 | + <col style="width: 220px"> | ||
| 76 | + <col style="width: 200px"> | ||
| 77 | + <col style="width: 177px"> | ||
| 78 | + <col style="width: 104px"> | ||
| 79 | + <col style="width: 138px"> | ||
| 80 | + <col style="width: 145px"> | ||
| 81 | + </colgroup> | ||
| 82 | + <thead> | ||
| 83 | + <tr> | ||
| 84 | + <th>Name</th> | ||
| 85 | + <th>Input/Output</th> | ||
| 86 | + <th>Description</th> | ||
| 87 | + <th>Precaution</th> | ||
| 88 | + <th>Data Type</th> | ||
| 89 | + <th>Data Format</th> | ||
| 90 | + <th>Dimension (Shape)</th> | ||
| 91 | + <th>Non-contiguous Tensor</th> | ||
| 92 | + </tr></thead> | ||
| 93 | + <tbody> | ||
| 94 | + <tr> | ||
| 95 | + <td>self (aclTensor*) </td> | ||
| 96 | + <td>Input</td> | ||
| 97 | + <td>Input of the CELU activation function, corresponding to x in the formula.</td> | ||
| 98 | + <td>Empty tensors are supported.</td> | ||
| 99 | + <td>FLOAT, FLOAT16, BFLOAT16</td> | ||
| 100 | + <td>ND</td> | ||
| @@ -0,0 +1,475 @@ | |||
| 1 | +# aclnnClippedSwiglu | ||
| 2 | + | ||
| 3 | +[📄 View source code](https://gitcode.com/cann/ops-nn/tree/master/activation/clipped_swiglu) | ||
| 4 | + | ||
| 5 | +## Product Support | ||
| 6 | + | ||
| 7 | +|Product | Supported | | ||
| 8 | +|:-------------------------|:----------:| | ||
| 9 | +| Ascend 950PR/Ascend 950DT | × | | ||
| 10 | +| <term>Atlas A3 training products/Atlas A3 inference products</term> | √ | | ||
| 11 | +| <term>Atlas A2 training products/Atlas A2 inference products</term> | √ | | ||
| 12 | +| <term>Atlas 200I/500 A2 inference products</term> | × | | ||
| 13 | +| <term>Atlas inference products</term> | × | | ||
| 14 | +| <term>Atlas training products</term> | × | | ||
| 15 | + | ||
| 16 | +## Function | ||
| 17 | + | ||
| 18 | +- Description: Serves as a clipped Swish-gated linear unit (SwiGLU) activation function that computes the clipped SwiGLU of input tensor x. Compared with **aclnnSwiGlu**, this API introduces additional parameters — **groupIndex**, **alpha**, **limit**, **bias**, and **interleaved** — to support the SwiGLU variant used in GPT-OSS models and grouped scenarios in MoE models. | ||
| 19 | + | ||
| 20 | +- Formula: | ||
| 21 | + | ||
| 22 | + For a given input tensor **x** with shape [a,b,c,d,e,f,g…], **aclnnClippedSwiglu** performs the following operations: | ||
| 23 | + | ||
| 24 | + 1. The x is combined along the axis specified by the input parameter dim. The dimension after combination is [pre, cut, after]. The `cut` axis represents the axis that needs to be split into two tensors, following either front-back splitting or odd-even splitting. The dimensions of `pre` and `after` can equal 1. For example, when dim is 3, the dimension of x after combination is [a*b*c, d, e*f*g*...]. Since elements along the **after** axis are contiguous and operations are element-wise, the **cut** and **after** axes are further merged, resulting in a final shape of **[pre,cut]**. | ||
| 25 | + | ||
| 26 | + 2. Filter the **pre** axis of **x** based on the input parameter **group_index** using the following formula: | ||
| 27 | + | ||
| 28 | + $$ | ||
| 29 | + sum = \text{Sum}(group\_index) | ||
| 30 | + $$ | ||
| 31 | + | ||
| 32 | + $$ | ||
| 33 | + x = x[ : sum, : ] | ||
| 34 | + $$ | ||
| 35 | + | ||
| 36 | + Where **sum** is the sum of all elements in **group_index**. This step is skipped when **group_index** is not provided. | ||
| 37 | + | ||
| 38 | + 3. Split **x** based on the input parameter **interleaved** using the following formula: | ||
| 39 | + | ||
| 40 | + When **interleaved** is set to **true**, it indicates odd-even split: | ||
| 41 | + | ||
| 42 | + $$ | ||
| 43 | + A = x[ : , : : 2] | ||
| 44 | + $$ | ||
| 45 | + | ||
| 46 | + $$ | ||
| 47 | + B = x[ : , 1 : : 2] | ||
| 48 | + $$ | ||
| 49 | + | ||
| 50 | + When **interleaved** is set to **false**, it indicates front-back split: | ||
| 51 | + | ||
| 52 | + $$ | ||
| 53 | + h = x.shape[1] // 2 | ||
| 54 | + $$ | ||
| 55 | + | ||
| 56 | + $$ | ||
| 57 | + A = x[ : , : h] | ||
| 58 | + $$ | ||
| 59 | + | ||
| 60 | + $$ | ||
| 61 | + B = x[ : , h : ] | ||
| 62 | + $$ | ||
| 63 | + 4. Compute the clipped SwiGLU variant based on the input parameters **alpha**, **limit**, and **bias** using the following formula: | ||
| 64 | + | ||
| 65 | + $$ | ||
| 66 | + A = A.clamp(min=None, max=limit) | ||
| 67 | + $$ | ||
| 68 | + | ||
| 69 | + $$ | ||
| 70 | + B = B.clamp(min=-limit, max=limit) | ||
| 71 | + $$ | ||
| 72 | + | ||
| 73 | + $$ | ||
| 74 | + y\_glu = A * sigmoid(alpha * A) | ||
| 75 | + $$ | ||
| 76 | + | ||
| 77 | + $$ | ||
| 78 | + y = y\_glu * (B + bias) | ||
| 79 | + $$ | ||
| 80 | + 5. Reshape the output tensor **y** to match the original number of dimensions of **x**. The size along the **dim** axis is half that of **x**, while all other dimensions remain the same as **x**. | ||
| 81 | + | ||
| 82 | +## Prototype | ||
| 83 | + | ||
| 84 | +Each operator has [two-phase API](../../../docs/en/context/two_phase_api.md) calls. First, **aclnnClippedSwigluGetWorkspaceSize** is called to obtain the workspace size required for computation and the executor that contains the operator computation flow. Then, **aclnnClippedSwiglu** is called to perform computation. | ||
| 85 | + | ||
| 86 | +```Cpp | ||
| 87 | +aclnnStatus aclnnClippedSwigluGetWorkspaceSize( | ||
| 88 | + const aclTensor *x, | ||
| 89 | + const aclTensor *groupIndexOptional, | ||
| 90 | + int64_t dim, | ||
| 91 | + double alpha, | ||
| 92 | + double limit, | ||
| 93 | + double bias, | ||
| 94 | + bool interleaved, | ||
| 95 | + const aclTensor *out, | ||
| 96 | + uint64_t *workspaceSize, | ||
| 97 | + aclOpExecutor **executor) | ||
| 98 | +``` | ||
| 99 | + | ||
| 100 | +```Cpp | ||
| 101 | +aclnnStatus aclnnClippedSwiglu( | ||
| 102 | + void *workspace, | ||
| 103 | + uint64_t workspaceSize, | ||
| 104 | + aclOpExecutor *executor, | ||
| 105 | + aclrtStream stream) | ||
| 106 | +``` | ||
| 107 | + | ||
| 108 | +## aclnnClippedSwigluGetWorkspaceSize | ||
| 109 | + | ||
| 110 | +- **Parameters** | ||
| 111 | + <table style="undefined;table-layout: fixed; width: 1567px"><colgroup> | ||
| 112 | + <col style="width: 270px"> | ||
| 113 | + <col style="width: 120px"> | ||
| 114 | + <col style="width: 300px"> | ||
| 115 | + <col style="width: 330px"> | ||
| 116 | + <col style="width: 212px"> | ||
| 117 | + <col style="width: 100px"> | ||
| 118 | + <col style="width: 90px"> | ||
| 119 | + <col style="width: 145px"> | ||
| 120 | + </colgroup> | ||
| 121 | + <thead> | ||
| 122 | + <tr> | ||
| 123 | + <th>Name</th> | ||
| 124 | + <th>Input/Output</th> | ||
| 125 | + <th>Description</th> | ||
| 126 | + <th>Usage Notes</th> | ||
| 127 | + <th>Data Type</th> | ||
| 128 | + <th>Data Format</th> | ||
| 129 | + <th>Shape</th> | ||
| 130 | + <th>Non-contiguous Tensor</th> | ||
| 131 | + </tr></thead> | ||
| 132 | + <tbody> | ||
| 133 | + <tr> | ||
| 134 | + <td>x (aclTensor*) </td> | ||
| 135 | + <td>Input</td> | ||
| 136 | + <td>x in the formula.</td> | ||
| 137 | + <td>Null pointers are not supported. The dimension must be greater than 0, and the shape must be an even number in the dimension corresponding to the input parameter dim.</td> | ||
| 138 | + <td>FLOAT, FLOAT16, BFLOAT16</td> | ||
| 139 | + <td>ND</td> | ||
| 140 | + <td>1-8</td> | ||
| 141 | + <td>-</td> | ||
| 142 | + </tr> | ||
| 143 | + <tr> | ||
| 144 | + <td>groupIndexOptional (aclTensor*) </td> | ||
| 145 | + <td>Input</td> | ||
| 146 | + <td>group_index in the formula, indicating how the input is grouped.</td> | ||
| 147 | + <td>Null pointers are supported. If the pointer is not null, the tensor must be a 1D tensor with non-negative elements. The i-th element indicates the batch size of x to be processed for the i-th group.</td> | ||
| 148 | + <td>INT64</td> | ||
| 149 | + <td>ND</td> | ||
| 150 | + <td>1</td> | ||
| 151 | + <td>-</td> | ||
| 152 | + </tr> | ||
| 153 | + <tr> | ||
| 154 | + <td>dim (int64_t) </td> | ||
| 155 | + <td>Input</td> | ||
| 156 | + <td>dim in the formula, indicating the dimension index used to merge and split tensor x.</td> | ||
| 157 | + <td>The value range is [–x.dim(), x.dim() – 1].</td> | ||
| 158 | + <td>-</td> | ||
| 159 | + <td>-</td> | ||
| 160 | + <td>-</td> | ||
| 161 | + <td>-</td> | ||
| 162 | + </tr> | ||
| 163 | + <tr> | ||
| 164 | + <td>alpha (double) </td> | ||
| 165 | + <td>Input</td> | ||
| 166 | + <td>alpha in the formula, indicating the scaling factor used in the variant SwiGLU computation.</td> | ||
| 167 | + <td>The recommended value is 1.702.</td> | ||
| 168 | + <td>-</td> | ||
| 169 | + <td>-</td> | ||
| 170 | + <td>-</td> | ||
| 171 | + <td>-</td> | ||
| 172 | + </tr> | ||
| 173 | + <tr> | ||
| 174 | + <td>limit (double) </td> | ||
| 175 | + <td>Input</td> | ||
| 176 | + <td>limit in the formula, indicating the clipping threshold used in the variant SwiGLU computation.</td> | ||
| 177 | + <td>The recommended value is 7.0.</td> | ||
| 178 | + <td>-</td> | ||
| 179 | + <td>-</td> | ||
| 180 | + <td>-</td> | ||
| 181 | + <td>-</td> | ||
| 182 | + </tr> | ||
| 183 | + <tr> | ||
| 184 | + <td>bias (double) </td> | ||
| 185 | + <td>Input</td> | ||
| 186 | + <td>bias in the formula, indicating the bias parameter used in the variant SwiGLU computation.</td> | ||
| 187 | + <td>The recommended value is 1.0.</td> | ||
| 188 | + <td>-</td> | ||
| 189 | + <td>-</td> | ||
| 190 | + <td>-</td> | ||
| 191 | + <td>-</td> | ||
| 192 | + </tr> | ||
| 193 | + <tr> | ||
| 194 | + <td>interleaved (bool) </td> | ||
| 195 | + <td>Input</td> | ||
| 196 | + <td>interleaved in the formula, specifying the split mode for x.</td> | ||
| 197 | + <td>true: even-odd split; false: front-back split.</td> | ||
| 198 | + <td>-</td> | ||
| 199 | + <td>-</td> | ||
| 200 | + <td>-</td> | ||
| 201 | + <td>-</td> | ||
| 202 | + </tr> | ||
| 203 | + <tr> | ||
| 204 | + <td>out (aclTensor*) </td> | ||
| 205 | + <td>Output</td> | ||
| 206 | + <td>y in the formula.</td> | ||
| 207 | + <td>Null pointers are not supported. The shape is half of x in the dimension corresponding to the input parameter dim, and is the same as that of x in other dimensions.</td> | ||
| 208 | + <td>FLOAT, FLOAT16, BFLOAT16</td> | ||
| 209 | + <td>ND</td> | ||
| 210 | + <td>1-8</td> | ||
| 211 | + <td>-</td> | ||
| 212 | + </tr> | ||
| 213 | + <tr> | ||
| 214 | + <td>workspaceSize (uint64_t*) </td> | ||
| 215 | + <td>Output</td> | ||
| 216 | + <td>Size of the workspace to be allocated on the device.</td> | ||
| 217 | + <td>-</td> | ||
| 218 | + <td>-</td> | ||
| 219 | + <td>-</td> | ||
| 220 | + <td>-</td> | ||
| 221 | + <td>-</td> | ||
| 222 | + </tr> | ||
| 223 | + <tr> | ||
| 224 | + <td>executor (aclOpExecutor**) </td> | ||
| 225 | + <td>Output</td> | ||
| 226 | + <td>Operator executor, containing the operator computation flow.</td> | ||
| 227 | + <td>-</td> | ||
| 228 | + <td>-</td> | ||
| 229 | + <td>-</td> | ||
| 230 | + <td>-</td> | ||
| 231 | + <td>-</td> | ||
| 232 | + </tr> | ||
| 233 | + </tbody> | ||
| 234 | + </table> | ||
| 235 | + | ||
| 236 | +- **Returns** | ||
| 237 | + | ||
| 238 | + `aclnnStatus`: status code. For details, see aclnn Return Cod](../../../docs/en/context/aclnn_return_code.md). | ||
| 239 | + | ||
| 240 | + The first-phase API implements input parameter verification. The following errors may be thrown. | ||
| 241 | + | ||
| 242 | + <table style="undefined;table-layout: fixed;width: 979px"><colgroup> | ||
| 243 | + <col style="width: 272px"> | ||
| 244 | + <col style="width: 103px"> | ||
| 245 | + <col style="width: 604px"> | ||
| 246 | + </colgroup> | ||
| 247 | + <thead> | ||
| 248 | + <tr> | ||
| 249 | + <th>Return code</th> | ||
| 250 | + <th>Error Code</th> | ||
| 251 | + <th>Description</th> | ||
| 252 | + </tr> | ||
| 253 | + </thead> | ||
| 254 | + <tbody> | ||
| 255 | + <tr> | ||
| 256 | + <td>ACLNN_ERR_PARAM_NULLPTR</td> | ||
| 257 | + <td>161001</td> | ||
| 258 | + <td>The passed x or y is a null pointer.</td> | ||
| 259 | + </tr> | ||
| 260 | + <tr> | ||
| 261 | + <td rowspan="8">ACLNN_ERR_PARAM_INVALID</td> | ||
| 262 | + <td rowspan="8">161002</td> | ||
| 263 | + <td>The input or output data type is not supported.</td> | ||
| 264 | + </tr> | ||
| 265 | + <tr> | ||
| 266 | + <td>The input or output tensor rank is not supported.</td> | ||
| 267 | + </tr> | ||
| 268 | + <tr> | ||
| 269 | + <td>dim is out of the valid range.</td> | ||
| 270 | + </tr> | ||
| 271 | + </tbody> | ||
| 272 | + </table> | ||
| 273 | + | ||
| 274 | +## aclnnClippedSwiglu | ||
| 275 | + | ||
| 276 | +- **Parameters** | ||
| 277 | + <table style="undefined;table-layout: fixed; width: 953px"><colgroup> | ||
| 278 | + <col style="width: 173px"> | ||
| 279 | + <col style="width: 112px"> | ||
| 280 | + <col style="width: 668px"> | ||
| 281 | + </colgroup> | ||
| 282 | + <thead> | ||
| 283 | + <tr> | ||
| 284 | + <th>Name</th> | ||
| 285 | + <th>Input/Output</th> | ||
| 286 | + <th>Description</th> | ||
| 287 | + </tr></thead> | ||
| 288 | + <tbody> | ||
| 289 | + <tr> | ||
| 290 | + <td>workspace</td> | ||
| 291 | + <td>Input</td> | ||
| 292 | + <td>Address of the workspace to be allocated on the device.</td> | ||
| 293 | + </tr> | ||
| 294 | + <tr> | ||
| 295 | + <td>workspaceSize</td> | ||
| 296 | + <td>Input</td> | ||
| 297 | + <td>Size of the workspace to be allocated on the device, obtained by calling the first-phase API aclnnClippedSwigluGetWorkspaceSize.</td> | ||
| 298 | + </tr> | ||
| 299 | + <tr> | ||
| 300 | + <td>executor</td> | ||
| 301 | + <td>Input</td> | ||
| 302 | + <td>Operator executor, containing the operator computation flow.</td> | ||
| 303 | + </tr> | ||
| 304 | + <tr> | ||
| 305 | + <td>stream</td> | ||
| 306 | + <td>Input</td> | ||
| 307 | + <td>Stream for executing the task.</td> | ||
| 308 | + </tr> | ||
| 309 | + </tbody> | ||
| 310 | + </table> | ||
| 311 | + | ||
| 312 | +- **Returns** | ||
| 313 | + | ||
| 314 | + `aclnnStatus`: status code. For details, see aclnn Return Cod](../../../docs/en/context/aclnn_return_code.md). | ||
| 315 | + | ||
| 316 | +## Constraints | ||
| 317 | + | ||
| 318 | +Deterministic computation: **aclnnClippedSwiglu** defaults to a deterministic implementation. The non-deterministic implementation is not supported, and configuration changes via deterministic computation settings will not take effect. | ||
| 319 | + | ||
| 320 | +## Example | ||
| 321 | + | ||
| 322 | +The following example is for reference only. For details, see [Compile and Run Sample](../../../docs/en/context/compile_and_run_sample.md). | ||
| 323 | + | ||
| 324 | +```Cpp | ||
| 325 | +#include <iostream> | ||
| 326 | +#include <vector> | ||
| 327 | +#include "acl/acl.h" | ||
| 328 | +#include "aclnnop/aclnn_clipped_swiglu.h" | ||
| 329 | + | ||
| 330 | +#define CHECK_RET(cond, return_expr) \ | ||
| 331 | + do { \ | ||
| 332 | + if (!(cond)) { \ | ||
| 333 | + return_expr; \ | ||
| 334 | + } \ | ||
| 335 | + } while (0) | ||
| 336 | + | ||
| 337 | +#define LOG_PRINT(message, ...) \ | ||
| 338 | + do { \ | ||
| 339 | + printf(message, ##__VA_ARGS__); \ | ||
| 340 | + } while (0) | ||
| 341 | + | ||
| 342 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 343 | +{ | ||
| 344 | + int64_t shapeSize = 1; | ||
| 345 | + for (auto i : shape) { | ||
| 346 | + shapeSize *= i; | ||
| 347 | + } | ||
| 348 | + return shapeSize; | ||
| 349 | +} | ||
| 350 | + | ||
| 351 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 352 | +{ | ||
| 353 | + // (Boilerplate) Initialize ACL. | ||
| 354 | + auto ret = aclInit(nullptr); | ||
| 355 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 356 | + ret = aclrtSetDevice(deviceId); | ||
| 357 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 358 | + ret = aclrtCreateStream(stream); | ||
| 359 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 360 | + return 0; | ||
| 361 | +} | ||
| 362 | + | ||
| 363 | +template <typename T> | ||
| 364 | +int CreateAclTensor( | ||
| 365 | + const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, aclDataType dataType, | ||
| 366 | + aclTensor** tensor) | ||
| 367 | +{ | ||
| 368 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 369 | + // Call aclrtMalloc to allocate memory on the device. | ||
| 370 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 371 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 372 | + // Call aclrtMemcpy to copy the data on the host to the memory on the device. | ||
| 373 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 374 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 375 | + | ||
| 376 | + // Calculate the strides of the contiguous tensor. | ||
| 377 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 378 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 379 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 380 | + } | ||
| 381 | + | ||
| 382 | + // Call aclCreateTensor to create an aclTensor. | ||
| 383 | + *tensor = aclCreateTensor( | ||
| 384 | + shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), | ||
| 385 | + *deviceAddr); | ||
| 386 | + return 0; | ||
| 387 | +} | ||
| 388 | + | ||
| 389 | +int main() | ||
| 390 | +{ | ||
| 391 | + // 1. (Boilerplate) Initialize the device and stream. For details, see the ACL API manual. | ||
| 392 | + // Set the device ID (deviceId) based on the actual device. | ||
| 393 | + int32_t deviceId = 0; | ||
| 394 | + aclrtStream stream; | ||
| 395 | + auto ret = Init(deviceId, &stream); | ||
| 396 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 397 | + | ||
| 398 | + // 2. Construct inputs and outputs based on API definitions. | ||
| 399 | + std::vector<int64_t> xShape = {2, 32}; | ||
| 400 | + std::vector<int64_t> groupIndexShape = {1}; | ||
| 401 | + std::vector<int64_t> outShape = {2, 16}; | ||
| 402 | + void* xDeviceAddr = nullptr; | ||
| 403 | + void* groupIndexDeviceAddr = nullptr; | ||
| 404 | + void* outDeviceAddr = nullptr; | ||
| 405 | + aclTensor* x = nullptr; | ||
| 406 | + aclTensor* groupIndex = nullptr; | ||
| 407 | + aclTensor* out = nullptr; | ||
| 408 | + std::vector<float> xHostData = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | ||
| 409 | + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, | ||
| 410 | + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}; | ||
| 411 | + std::vector<int64_t> groupIndexData = {1}; | ||
| 412 | + std::vector<float> outHostData = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 413 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 414 | + | ||
| 415 | + int dim = -1; | ||
| 416 | + float alpha = 1.0; | ||
| 417 | + float limit = 7.0; | ||
| 418 | + float bias = 1.702; | ||
| 419 | + bool interleaved = true; | ||
| 420 | + // Create an x aclTensor. | ||
| 421 | + ret = CreateAclTensor(xHostData, xShape, &xDeviceAddr, aclDataType::ACL_FLOAT, &x); | ||
| 422 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 423 | + // Create a groupIndex aclTensor. | ||
| 424 | + ret = CreateAclTensor(groupIndexData, groupIndexShape, &groupIndexDeviceAddr, aclDataType::ACL_INT64, &groupIndex); | ||
| 425 | + // Create an out aclTensor. | ||
| 426 | + ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out); | ||
| 427 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 428 | + // 3. Call the CANN operator library API. Modify the API as required. | ||
| 429 | + uint64_t workspaceSize = 0; | ||
| 430 | + aclOpExecutor* executor; | ||
| 431 | + // Call the first-phase API of aclnnClippedSwiglu. | ||
| 432 | + ret = aclnnClippedSwigluGetWorkspaceSize( | ||
| 433 | + x, groupIndex, dim, alpha, limit, bias, interleaved, out, &workspaceSize, &executor); | ||
| 434 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnClippedSwigluGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 435 | + // Allocate device memory based on workspaceSize computed by the first-phase API. | ||
| 436 | + void* workspaceAddr = nullptr; | ||
| 437 | + if (workspaceSize > 0) { | ||
| 438 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 439 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 440 | + } | ||
| 441 | + // Call the second-phase API of aclnnClippedSwiglu. | ||
| 442 | + ret = aclnnClippedSwiglu(workspaceAddr, workspaceSize, executor, stream); | ||
| 443 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnClippedSwiglu failed. ERROR: %d\n", ret); return ret); | ||
| 444 | + | ||
| 445 | + // 4. (Boilerplate) Synchronize the stream and wait for task completion. | ||
| 446 | + ret = aclrtSynchronizeStream(stream); | ||
| 447 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 448 | + | ||
| 449 | + // 5. Obtain the output value and copy the result from the device to the host. Modify the code based on the API definition. | ||
| 450 | + auto size = GetShapeSize(outShape); | ||
| 451 | + std::vector<float> resultData(size, 0); | ||
| 452 | + ret = aclrtMemcpy( | ||
| 453 | + resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, size * sizeof(resultData[0]), | ||
| 454 | + ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 455 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 456 | + for (int64_t i = 0; i < size; i++) { | ||
| 457 | + LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]); | ||
| 458 | + } | ||
| 459 | + // 6. Destroy aclTensor and aclScalar. Modify the code based on the API definition. | ||
| 460 | + aclDestroyTensor(x); | ||
| 461 | + aclDestroyTensor(groupIndex); | ||
| 462 | + aclDestroyTensor(out); | ||
| 463 | + // 7. Release device resources. Modify the code based on the API definition. | ||
| 464 | + aclrtFree(xDeviceAddr); | ||
| 465 | + aclrtFree(groupIndexDeviceAddr); | ||
| 466 | + aclrtFree(outDeviceAddr); | ||
| 467 | + if (workspaceSize > 0) { | ||
| 468 | + aclrtFree(workspaceAddr); | ||
| 469 | + } | ||
| 470 | + aclrtDestroyStream(stream); | ||
| 471 | + aclrtResetDevice(deviceId); | ||
| 472 | + aclFinalize(); | ||
| 473 | + return 0; | ||
| 474 | +} | ||
| 475 | +``` | ||
| @@ -0,0 +1,452 @@ | |||
| 1 | +# aclnnEluBackward | ||
| 2 | + | ||
| 3 | +[📄 View source code](https://gitcode.com/cann/ops-nn/tree/master/activation/elu_grad_v2) | ||
| 4 | + | ||
| 5 | +## Product Support | ||
| 6 | + | ||
| 7 | +|Product | Supported | | ||
| 8 | +|:-------------------------|:----------:| | ||
| 9 | +| Ascend 950PR/Ascend 950DT | √ | | ||
| 10 | +| <term>Atlas A3 training products/Atlas A3 inference products</term> | √ | | ||
| 11 | +| <term>Atlas A2 training products/Atlas A2 inference products</term> | √ | | ||
| 12 | +| <term>Atlas 200I/500 A2 inference products</term> | × | | ||
| 13 | +| <term>Atlas inference products</term> | √ | | ||
| 14 | +| <term>Atlas training products</term> | √ | | ||
| 15 | + | ||
| 16 | +## Function | ||
| 17 | + | ||
| 18 | +- Description: Performs backward computation of the [aclnnElu](../../elu/docs/aclnnElu&aclnnInplaceElu_en.md) activation function and outputs the gradient of the forward input of the ELU activation function. | ||
| 19 | + | ||
| 20 | +- Formula: **x** denotes an element in **selfOrResult**. | ||
| 21 | + | ||
| 22 | + - When **isResult** is **True**: | ||
| 23 | + | ||
| 24 | + $$ | ||
| 25 | + gradInput = gradOutput * | ||
| 26 | + \begin{cases} | ||
| 27 | + scale, \quad x > 0\\ | ||
| 28 | + inputScale \ast (x + \alpha \ast scale), \quad x \leq 0 | ||
| 29 | + \end{cases} | ||
| 30 | + $$ | ||
| 31 | + | ||
| 32 | + - When **isResult** is **False**: | ||
| 33 | + | ||
| 34 | + $$ | ||
| 35 | + gradInput = gradOutput * | ||
| 36 | + \begin{cases} | ||
| 37 | + scale, \quad x > 0\\ | ||
| 38 | + inputScale \ast \alpha \ast scale \ast exp(x \ast inputScale), \quad x \leq 0 | ||
| 39 | + \end{cases} | ||
| 40 | + $$ | ||
| 41 | + | ||
| 42 | +## Prototype | ||
| 43 | + | ||
| 44 | +Each operator has [two-phase API](../../../docs/en/context/two_phase_api.md) calls. First, **aclnnEluBackwardGetWorkspaceSize** is called to obtain the workspace size required for computation and the executor that contains the operator computation flow. Then, **aclnnEluBackward** is called to perform computation. | ||
| 45 | + | ||
| 46 | +```Cpp | ||
| 47 | +aclnnStatus aclnnEluBackwardGetWorkspaceSize( | ||
| 48 | + const aclTensor* gradOutput, | ||
| 49 | + const aclScalar* alpha, | ||
| 50 | + const aclScalar* scale, | ||
| 51 | + const aclScalar* inputScale, | ||
| 52 | + bool isResult, | ||
| 53 | + const aclTensor* selfOrResult, | ||
| 54 | + aclTensor* gradInput, | ||
| 55 | + uint64_t* workspaceSize, | ||
| 56 | + aclOpExecutor** executor) | ||
| 57 | +``` | ||
| 58 | + | ||
| 59 | +```Cpp | ||
| 60 | +aclnnStatus aclnnEluBackward( | ||
| 61 | + void* workspace, | ||
| 62 | + uint64_t workspaceSize, | ||
| 63 | + aclOpExecutor* executor, | ||
| 64 | + aclrtStream stream) | ||
| 65 | +``` | ||
| 66 | + | ||
| 67 | +## aclnnEluBackwardGetWorkspaceSize | ||
| 68 | + | ||
| 69 | +- **Parameters** | ||
| 70 | + | ||
| 71 | + <table style="undefined;table-layout: fixed; width: 1370px"><colgroup> | ||
| 72 | + <col style="width: 271px"> | ||
| 73 | + <col style="width: 115px"> | ||
| 74 | + <col style="width: 220px"> | ||
| 75 | + <col style="width: 200px"> | ||
| 76 | + <col style="width: 177px"> | ||
| 77 | + <col style="width: 104px"> | ||
| 78 | + <col style="width: 138px"> | ||
| 79 | + <col style="width: 145px"> | ||
| 80 | + </colgroup> | ||
| 81 | + <thead> | ||
| 82 | + <tr> | ||
| 83 | + <th>Name</th> | ||
| 84 | + <th>Input/Output</th> | ||
| 85 | + <th>Description</th> | ||
| 86 | + <th>Usage Notes</th> | ||
| 87 | + <th>Data Type</th> | ||
| 88 | + <th>Data Format</th> | ||
| 89 | + <th>Shape</th> | ||
| 90 | + <th>Non-contiguous Tensor</th> | ||
| 91 | + </tr></thead> | ||
| 92 | + <tbody> | ||
| 93 | + <tr> | ||
| 94 | + <td>gradOutput (aclTensor*) </td> | ||
| 95 | + <td>Input</td> | ||
| 96 | + <td>Gradient of the forward output of the ELU activation function, corresponding to gradInput in the formula.</td> | ||
| 97 | + <td>Empty tensors are supported.</td> | ||
| 98 | + <td>FLOAT, FLOAT16, BFLOAT16</td> | ||
| 99 | + <td>ND</td> | ||
| 100 | + <td>0-8</td> | ||
| 101 | + <td>√</td> | ||
| 102 | + </tr> | ||
| 103 | + <tr> | ||
| 104 | + <td>alpha (aclScalar*) </td> | ||
| 105 | + <td>Input</td> | ||
| 106 | + <td>Activation coefficient of the ELU activation function, corresponding to \alpha in the formula.</td> | ||
| 107 | + <td><ul><li>If isResult is true, \alpha must be greater than or equal to 0. </li><li>The data type must be convertible to FLOAT (see <a href="../../../docs/en/context/conversion_relationship.md" target="_blank">conversion relationship</a>).</li></ul></td> | ||
| 108 | + <td>-</td> | ||
| 109 | + <td>-</td> | ||
| 110 | + <td>-</td> | ||
| 111 | + <td>-</td> | ||
| 112 | + </tr> | ||
| 113 | + <tr> | ||
| 114 | + <td>scale (aclScalar*) </td> | ||
| 115 | + <td>Input</td> | ||
| 116 | + <td>Scaling factor of the ELU activation function, corresponding to scale in the formula.</td> | ||
| 117 | + <td>The data type must be convertible to FLOAT (see <a href="../../../docs/en/context/conversion_relationship.md" target="_blank">conversion relationship</a>).</td> | ||
| 118 | + <td>-</td> | ||
| 119 | + <td>-</td> | ||
| 120 | + <td>-</td> | ||
| 121 | + <td>-</td> | ||
| 122 | + </tr> | ||
| 123 | + <tr> | ||
| 124 | + <td>inputScale (aclScalar*) </td> | ||
| 125 | + <td>Input</td> | ||
| 126 | + <td>Input scaling factor of the ELU activation function, corresponding to inputScale in the formula.</td> | ||
| 127 | + <td>The data type must be convertible to FLOAT (see <a href="../../../docs/en/context/conversion_relationship.md" target="_blank">conversion relationship</a>).</td> | ||
| 128 | + <td>-</td> | ||
| 129 | + <td>-</td> | ||
| 130 | + <td>-</td> | ||
| 131 | + <td>-</td> | ||
| 132 | + </tr> | ||
| 133 | + <tr> | ||
| 134 | + <td>isResult (bool) </td> | ||
| 135 | + <td>Input</td> | ||
| 136 | + <td>Whether the input for ELU backward computation is the forward output of the ELU operator.</td> | ||
| 137 | + <td>-</td> | ||
| 138 | + <td>-</td> | ||
| 139 | + <td>-</td> | ||
| 140 | + <td>-</td> | ||
| 141 | + <td>-</td> | ||
| 142 | + </tr> | ||
| 143 | + <tr> | ||
| 144 | + <td>selfOrResult (aclTensor*) </td> | ||
| 145 | + <td>Input</td> | ||
| 146 | + <td><ul><li>Forward output of the ELU activation function when isResult is true. </li><li>Forward input of the ELU activation function when isResult is false.</li></ul></td> | ||
| 147 | + <td><ul><li>The data type must be the same as that of gradOutput. </li><li>The shape must be the same as that of gradOutput. </li><li>Empty tensors are supported.</li></ul></td> | ||
| 148 | + <td>FLOAT, FLOAT16, BFLOAT16</td> | ||
| 149 | + <td>ND</td> | ||
| 150 | + <td>0-8</td> | ||
| 151 | + <td>√</td> | ||
| 152 | + </tr> | ||
| 153 | + <tr> | ||
| 154 | + <td>gradInput (aclTensor*) </td> | ||
| 155 | + <td>Output</td> | ||
| 156 | + <td>Gradient of the forward input of the ELU activation function, that is, the derivative of the input, corresponding to gradOutput in the formula.</td> | ||
| 157 | + <td><ul><li>The data type must be convertible from that of gradOutput (see <a href="../../../docs/en/context/conversion_relationship.md" target="_blank">conversion relationship</a>). </li><li>The shape must be the same as that of gradOutput.</li></ul></td> | ||
| 158 | + <td>FLOAT, FLOAT16, BFLOAT16</td> | ||
| 159 | + <td>ND</td> | ||
| 160 | + <td>0-8</td> | ||
| 161 | + <td>√</td> | ||
| 162 | + </tr> | ||
| 163 | + <tr> | ||
| 164 | + <td>workspaceSize (uint64_t*) </td> | ||
| 165 | + <td>Output</td> | ||
| 166 | + <td>Size of the workspace to be allocated on the device.</td> | ||
| 167 | + <td>-</td> | ||
| 168 | + <td>-</td> | ||
| 169 | + <td>-</td> | ||
| 170 | + <td>-</td> | ||
| 171 | + <td>-</td> | ||
| 172 | + </tr> | ||
| 173 | + <tr> | ||
| 174 | + <td>executor (aclOpExecutor**) </td> | ||
| 175 | + <td>Output</td> | ||
| 176 | + <td>Operator executor, containing the operator computation flow.</td> | ||
| 177 | + <td>-</td> | ||
| 178 | + <td>-</td> | ||
| 179 | + <td>-</td> | ||
| 180 | + <td>-</td> | ||
| 181 | + <td>-</td> | ||
| 182 | + </tr> | ||
| 183 | + </tbody> | ||
| 184 | + </table> | ||
| 185 | + - <term>Atlas inference products</term> and <term>Atlas training products</term>: The data type can be FLOAT or FLOAT16. | ||
| 186 | + | ||
| 187 | +- **Returns** | ||
| 188 | + | ||
| 189 | + `aclnnStatus`: status code. For details, see [aclnn Return Code](../../../docs/en/context/aclnn_return_code.md). | ||
| 190 | + | ||
| 191 | + The first-phase API implements input parameter verification. The following errors may be thrown. | ||
| 192 | + | ||
| 193 | + <table style="undefined;table-layout: fixed;width: 979px"><colgroup> | ||
| 194 | + <col style="width: 272px"> | ||
| 195 | + <col style="width: 103px"> | ||
| 196 | + <col style="width: 604px"> | ||
| 197 | + </colgroup> | ||
| 198 | + <thead> | ||
| 199 | + <tr> | ||
| 200 | + <th>Return Code</th> | ||
| 201 | + <th>Error Code</th> | ||
| 202 | + <th>Description</th> | ||
| 203 | + </tr> | ||
| 204 | + </thead> | ||
| 205 | + <tbody> | ||
| 206 | + <tr> | ||
| 207 | + <td>ACLNN_ERR_PARAM_NULLPTR</td> | ||
| 208 | + <td>161001</td> | ||
| 209 | + <td>The gradOutput, alpha, scale, inputScale, selfOrResult, or gradInput parameter is a null pointer.</td> | ||
| 210 | + </tr> | ||
| 211 | + <tr> | ||
| 212 | + <td rowspan="8">ACLNN_ERR_PARAM_INVALID</td> | ||
| 213 | + <td rowspan="8">161002</td> | ||
| 214 | + <td>The data type of gradOutput or selfOrResult is not supported.</td> | ||
| 215 | + </tr> | ||
| 216 | + <tr> | ||
| 217 | + <td>The data types of gradOutput and selfOrResult are inconsistent.</td> | ||
| 218 | + </tr> | ||
| 219 | + <tr> | ||
| 220 | + <td>The data type of alpha, scale, or inputScale cannot be converted to FLOAT.</td> | ||
| 221 | + </tr> | ||
| 222 | + <tr> | ||
| 223 | + <td>The data type of gradInput is not convertible from that of gradOutput.</td> | ||
| 224 | + </tr> | ||
| 225 | + <tr> | ||
| 226 | + <td>The shapes of gradOutput, selfOrResult, and gradInput do not match.</td> | ||
| 227 | + </tr> | ||
| 228 | + <tr> | ||
| 229 | + <td>gradOutput, selfOrResult, or gradInput has more than eight dimensions.</td> | ||
| 230 | + </tr> | ||
| 231 | + <tr> | ||
| 232 | + <td>When isResult is set to True, alpha is negative.</td> | ||
| 233 | + </tr> | ||
| 234 | + </tbody></table> | ||
| 235 | + | ||
| 236 | +## aclnnEluBackward | ||
| 237 | + | ||
| 238 | +- **Parameters** | ||
| 239 | + | ||
| 240 | + <table style="undefined;table-layout: fixed; width: 953px"><colgroup> | ||
| 241 | + <col style="width: 173px"> | ||
| 242 | + <col style="width: 112px"> | ||
| 243 | + <col style="width: 668px"> | ||
| 244 | + </colgroup> | ||
| 245 | + <thead> | ||
| 246 | + <tr> | ||
| 247 | + <th>Name</th> | ||
| 248 | + <th>Input/Output</th> | ||
| 249 | + <th>Description</th> | ||
| 250 | + </tr></thead> | ||
| 251 | + <tbody> | ||
| 252 | + <tr> | ||
| 253 | + <td>workspace</td> | ||
| 254 | + <td>Input</td> | ||
| 255 | + <td>Address of the workspace to be allocated on the device.</td> | ||
| 256 | + </tr> | ||
| 257 | + <tr> | ||
| 258 | + <td>workspaceSize</td> | ||
| 259 | + <td>Input</td> | ||
| 260 | + <td>Size of the workspace to be allocated on the device, which is obtained by calling the first-phase API aclnnEluBackwardGetWorkspaceSize.</td> | ||
| 261 | + </tr> | ||
| 262 | + <tr> | ||
| 263 | + <td>executor</td> | ||
| 264 | + <td>Input</td> | ||
| 265 | + <td>Operator executor, containing the operator computation flow.</td> | ||
| 266 | + </tr> | ||
| 267 | + <tr> | ||
| 268 | + <td>stream</td> | ||
| 269 | + <td>Input</td> | ||
| 270 | + <td>Stream for executing the task.</td> | ||
| 271 | + </tr> | ||
| 272 | + </tbody> | ||
| 273 | + </table> | ||
| 274 | + | ||
| 275 | +- **Returns** | ||
| 276 | + | ||
| 277 | + `aclnnStatus`: status code. For details, see [aclnn Return Code](../../../docs/en/context/aclnn_return_code.md). | ||
| 278 | + | ||
| 279 | +## Constraints | ||
| 280 | + | ||
| 281 | +- Deterministic computation: | ||
| 282 | + - **aclnnEluBackward** defaults to a deterministic implementation. | ||
| 283 | + | ||
| 284 | +## Example | ||
| 285 | + | ||
| 286 | +The following example is for reference only. For details, see [Compile and Run Sample](../../../docs/en/context/compile_and_run_sample.md). | ||
| 287 | + | ||
| 288 | +```Cpp | ||
| 289 | +#include <iostream> | ||
| 290 | +#include <vector> | ||
| 291 | +#include "acl/acl.h" | ||
| 292 | +#include "aclnnop/aclnn_elu_backward.h" | ||
| 293 | + | ||
| 294 | +#define CHECK_RET(cond, return_expr) \ | ||
| 295 | + do { \ | ||
| 296 | + if (!(cond)) { \ | ||
| 297 | + return_expr; \ | ||
| 298 | + } \ | ||
| 299 | + } while (0) | ||
| 300 | + | ||
| 301 | +#define LOG_PRINT(message, ...) \ | ||
| 302 | + do { \ | ||
| 303 | + printf(message, ##__VA_ARGS__); \ | ||
| 304 | + } while (0) | ||
| 305 | + | ||
| 306 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) { | ||
| 307 | + int64_t shapeSize = 1; | ||
| 308 | + for (auto i : shape) { | ||
| 309 | + shapeSize *= i; | ||
| 310 | + } | ||
| 311 | + return shapeSize; | ||
| 312 | +} | ||
| 313 | + | ||
| 314 | +int Init(int32_t deviceId, aclrtStream* stream) { | ||
| 315 | + // (Boilerplate) Initialize resources. | ||
| 316 | + auto ret = aclInit(nullptr); | ||
| 317 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 318 | + ret = aclrtSetDevice(deviceId); | ||
| 319 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 320 | + ret = aclrtCreateStream(stream); | ||
| 321 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 322 | + return 0; | ||
| 323 | +} | ||
| 324 | + | ||
| 325 | +template <typename T> | ||
| 326 | +int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 327 | + aclDataType dataType, aclTensor** selfOrResult) { | ||
| 328 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 329 | + // Call aclrtMalloc to allocate memory on the device. | ||
| 330 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 331 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 332 | + | ||
| 333 | + // Call aclrtMemcpy to copy the data on the host to the memory on the device. | ||
| 334 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 335 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 336 | + | ||
| 337 | + // Compute the strides of the contiguous selfOrResult. | ||
| 338 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 339 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 340 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 341 | + } | ||
| 342 | + | ||
| 343 | + // Call aclCreateTensor to create an aclTensor. | ||
| 344 | + *selfOrResult = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 345 | + shape.data(), shape.size(), *deviceAddr); | ||
| 346 | + return 0; | ||
| 347 | +} | ||
| 348 | + | ||
| 349 | +int main() { | ||
| 350 | + // 1. (Fixed writing) Initialize the device and stream. For details, see the ACL API manual. | ||
| 351 | + // Set the device ID (deviceId) based on the actual device. | ||
| 352 | + int32_t deviceId = 0; | ||
| 353 | + aclrtStream stream; | ||
| 354 | + auto ret = Init(deviceId, &stream); | ||
| 355 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 356 | + | ||
| 357 | + // 2. Construct inputs and outputs based on API definitions. | ||
| 358 | + std::vector<int64_t> gradOutputShape = {2, 2}; | ||
| 359 | + std::vector<int64_t> selfOrResultShape = {2, 2}; | ||
| 360 | + std::vector<int64_t> gradInputShape = {2, 2}; | ||
| 361 | + void* gradOutputDeviceAddr = nullptr; | ||
| 362 | + void* selfOrResultDeviceAddr = nullptr; | ||
| 363 | + void* gradInputDeviceAddr = nullptr; | ||
| 364 | + aclTensor* gradOutput = nullptr; | ||
| 365 | + aclScalar* alpha = nullptr; | ||
| 366 | + aclScalar* scale = nullptr; | ||
| 367 | + aclScalar* inputScale = nullptr; | ||
| 368 | + aclTensor* selfOrResult = nullptr; | ||
| 369 | + aclTensor* gradInput = nullptr; | ||
| 370 | + std::vector<float> gradOutputHostData = {-2, -1, 0, 1}; | ||
| 371 | + std::vector<float> selfOrResultHostData = {-2, -1, 0, 1}; | ||
| 372 | + std::vector<float> gradInputHostData = {0, 0, 0, 0}; | ||
| 373 | + float alphaValue = 1.0f; | ||
| 374 | + float scaleValue = 1.0f; | ||
| 375 | + float inputScaleValue = 1.0f; | ||
| 376 | + bool isResult = true; | ||
| 377 | + // Create a gradOutput aclTensor. | ||
| 378 | + ret = CreateAclTensor(gradOutputHostData, gradOutputShape, &gradOutputDeviceAddr, aclDataType::ACL_FLOAT, | ||
| 379 | + &gradOutput); | ||
| 380 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 381 | + // Create an alpha aclScalar. | ||
| 382 | + alpha = aclCreateScalar(&alphaValue, aclDataType::ACL_FLOAT); | ||
| 383 | + CHECK_RET(alpha != nullptr, return ret); | ||
| 384 | + // Create a scale aclScalar. | ||
| 385 | + scale = aclCreateScalar(&scaleValue, aclDataType::ACL_FLOAT); | ||
| 386 | + CHECK_RET(scale != nullptr, return ret); | ||
| 387 | + // Create an inputScale aclScalar. | ||
| 388 | + inputScale = aclCreateScalar(&inputScaleValue, aclDataType::ACL_FLOAT); | ||
| 389 | + CHECK_RET(inputScale != nullptr, return ret); | ||
| 390 | + // Create a selfOrResult aclTensor. | ||
| 391 | + ret = CreateAclTensor(selfOrResultHostData, selfOrResultShape, &selfOrResultDeviceAddr, aclDataType::ACL_FLOAT, | ||
| 392 | + &selfOrResult); | ||
| 393 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 394 | + // Create a gradInput aclTensor. | ||
| 395 | + ret = CreateAclTensor(gradInputHostData, gradInputShape, &gradInputDeviceAddr, aclDataType::ACL_FLOAT, &gradInput); | ||
| 396 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 397 | + | ||
| 398 | + uint64_t workspaceSize = 0; | ||
| 399 | + aclOpExecutor* executor; | ||
| 400 | + | ||
| 401 | + // aclnnEluBackward API call example | ||
| 402 | + // 3. Call the CANN operator library API. Modify the API as required. | ||
| 403 | + // Call the first-phase API of aclnnEluBackward. | ||
| 404 | + ret = aclnnEluBackwardGetWorkspaceSize(gradOutput, alpha, scale, inputScale, isResult, selfOrResult, gradInput, | ||
| 405 | + &workspaceSize, &executor); | ||
| 406 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnEluBackwardGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 407 | + // Allocate device memory based on workspaceSize computed by the first-phase API. | ||
| 408 | + void* workspaceAddr = nullptr; | ||
| 409 | + if (workspaceSize > 0) { | ||
| 410 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 411 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 412 | + } | ||
| 413 | + // Call the second-phase API of aclnnEluBackward. | ||
| 414 | + ret = aclnnEluBackward(workspaceAddr, workspaceSize, executor, stream); | ||
| 415 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnEluBackward failed. ERROR: %d\n", ret); return ret); | ||
| 416 | + | ||
| 417 | + // 4. (Boilerplate) Synchronize the stream and wait for task completion. | ||
| 418 | + ret = aclrtSynchronizeStream(stream); | ||
| 419 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 420 | + | ||
| 421 | + // 5. Obtain the output value and copy the result from the device to the host. Modify the code based on the API definition. | ||
| 422 | + auto size = GetShapeSize(gradInputShape); | ||
| 423 | + std::vector<float> resultData(size, 0); | ||
| 424 | + ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), gradInputDeviceAddr, | ||
| 425 | + size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 426 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 427 | + for (int64_t i = 0; i < size; i++) { | ||
| 428 | + LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]); | ||
| 429 | + } | ||
| 430 | + | ||
| 431 | + // 6. Destroy aclTensor and aclScalar. Modify the code based on the API definition. | ||
| 432 | + aclDestroyTensor(gradOutput); | ||
| 433 | + aclDestroyScalar(alpha); | ||
| 434 | + aclDestroyScalar(scale); | ||
| 435 | + aclDestroyScalar(inputScale); | ||
| 436 | + aclDestroyTensor(selfOrResult); | ||
| 437 | + aclDestroyTensor(gradInput); | ||
| 438 | + | ||
| 439 | + // 7. Release device resources. Modify the code based on the API definition. | ||
| 440 | + aclrtFree(gradOutputDeviceAddr); | ||
| 441 | + aclrtFree(selfOrResultDeviceAddr); | ||
| 442 | + aclrtFree(gradInputDeviceAddr); | ||
| 443 | + if (workspaceSize > 0) { | ||
| 444 | + aclrtFree(workspaceAddr); | ||
| 445 | + } | ||
| 446 | + aclrtDestroyStream(stream); | ||
| 447 | + aclrtResetDevice(deviceId); | ||
| 448 | + aclFinalize(); | ||
| 449 | + | ||
| 450 | + return 0; | ||
| 451 | +} | ||
| 452 | +``` | ||
| @@ -0,0 +1,523 @@ | |||
| 1 | +# aclnnErfinv&aclnnInplaceErfinv | ||
| 2 | + | ||
| 3 | +[📄 View source code](https://gitcode.com/cann/ops-nn/tree/master/activation/erfinv) | ||
| 4 | + | ||
| 5 | +## Supported Products | ||
| 6 | + | ||
| 7 | +|Product | Supported | | ||
| 8 | +|:-------------------------|:----------:| | ||
| 9 | +| Ascend 950PR/Ascend 950DT | √ | | ||
| 10 | +| <term>Atlas A3 training products/Atlas A3 inference products</term> | √ | | ||
| 11 | +| <term>Atlas A2 training products/Atlas A2 inference products</term> | √ | | ||
| 12 | +| <term>Atlas 200I/500 A2 inference products</term> | × | | ||
| 13 | +| <term>Atlas inference products</term> | × | | ||
| 14 | +| <term>Atlas training products</term> | √ | | ||
| 15 | + | ||
| 16 | +## Function | ||
| 17 | + | ||
| 18 | +- Function: The erfinv function is the inverse function of the Gaussian error function erf. It returns the quantile of each element in the input tensor in the standard normal distribution function. | ||
| 19 | +- Formula: | ||
| 20 | + | ||
| 21 | + $$ | ||
| 22 | + y = erfinv(x) \\ | ||
| 23 | + x = erf(y)=\frac{2}{\sqrt{\pi } } \int_{0}^{y} e^{-t^{2} } \mathrm{d}t | ||
| 24 | + $$ | ||
| 25 | + | ||
| 26 | +## Prototype | ||
| 27 | + | ||
| 28 | +- **aclnnErfinv** and **aclnnInplaceErfinv** implement the same function. Select the appropriate operator based on actual service scenarios. | ||
| 29 | + - **aclnnErfinv**: An output tensor object must be created to store the computation result. | ||
| 30 | + - **aclnnInplaceErfinv**: No output tensor object needs to be created, and the computation result is stored in the memory of the input tensor. | ||
| 31 | +- Each operator has [two-phase API](../../../docs/en/context/two_phase_api.md) calls. First, **aclnnErfinvGetWorkspaceSize** or **aclnnInplaceErfinvGetWorkspaceSize** is called to obtain the workspace size required for computation and the executor that contains the operator computation flow. Then, **aclnnErfinv** or **aclnnInplaceErfinv** is called to perform computation. | ||
| 32 | + | ||
| 33 | +```Cpp | ||
| 34 | +aclnnStatus aclnnErfinvGetWorkspaceSize( | ||
| 35 | + const aclTensor* self, | ||
| 36 | + aclTensor* out, | ||
| 37 | + uint64_t* workspaceSize, | ||
| 38 | + aclOpExecutor** executor) | ||
| 39 | +``` | ||
| 40 | + | ||
| 41 | +```Cpp | ||
| 42 | +aclnnStatus aclnnErfinv( | ||
| 43 | + void* workspace, | ||
| 44 | + uint64_t workspaceSize, | ||
| 45 | + aclOpExecutor* executor, | ||
| 46 | + const aclrtStream stream) | ||
| 47 | +``` | ||
| 48 | + | ||
| 49 | +```Cpp | ||
| 50 | +aclnnStatus aclnnInplaceErfinvGetWorkspaceSize( | ||
| 51 | + const aclTensor* selfRef, | ||
| 52 | + uint64_t* workspaceSize, | ||
| 53 | + aclOpExecutor** executor) | ||
| 54 | +``` | ||
| 55 | + | ||
| 56 | +```Cpp | ||
| 57 | +aclnnStatus aclnnInplaceErfinv( | ||
| 58 | + void* workspace, | ||
| 59 | + uint64_t workspaceSize, | ||
| 60 | + aclOpExecutor* executor, | ||
| 61 | + aclrtStream stream) | ||
| 62 | +``` | ||
| 63 | + | ||
| 64 | +## aclnnErfinvGetWorkspaceSize | ||
| 65 | + | ||
| 66 | +- **Parameters** | ||
| 67 | + | ||
| 68 | + <table style="undefined;table-layout: fixed; width: 1370px"><colgroup> | ||
| 69 | + <col style="width: 271px"> | ||
| 70 | + <col style="width: 115px"> | ||
| 71 | + <col style="width: 220px"> | ||
| 72 | + <col style="width: 200px"> | ||
| 73 | + <col style="width: 177px"> | ||
| 74 | + <col style="width: 104px"> | ||
| 75 | + <col style="width: 138px"> | ||
| 76 | + <col style="width: 145px"> | ||
| 77 | + </colgroup> | ||
| 78 | + <thead> | ||
| 79 | + <tr> | ||
| 80 | + <th>Name</th> | ||
| 81 | + <th>Input/Output</th> | ||
| 82 | + <th>Description</th> | ||
| 83 | + <th>Usage</th> | ||
| 84 | + <th>Data Type</th> | ||
| 85 | + <th>Data Format</th> | ||
| 86 | + <th>Dimension (Shape)</th> | ||
| 87 | + <th>Non-contiguous Tensor</th> | ||
| 88 | + </tr></thead> | ||
| 89 | + <tbody> | ||
| 90 | + <tr> | ||
| 91 | + <td>self (aclTensor*) </td> | ||
| 92 | + <td>Input</td> | ||
| 93 | + <td>Input tensor for erfinv computation. $x$ in the formulas.</td> | ||
| 94 | + <td><ul><li>The shape must be the same as that of out. </li><li>Empty tensors are supported.</li></ul></td> | ||
| 95 | + <td>FLOAT, FLOAT16, BFLOAT16, BOOL, INT8, INT16, INT32, INT64, UINT8</td> | ||
| 96 | + <td>ND</td> | ||
| 97 | + <td>0-8</td> | ||
| 98 | + <td>√</td> | ||
| 99 | + </tr> | ||
| 100 | + <tr> | ||
| @@ -0,0 +1,340 @@ | |||
| 1 | +# aclnnFastGelu | ||
| 2 | + | ||
| 3 | +[📄 View source code](https://gitcode.com/cann/ops-nn/tree/master/activation/fast_gelu) | ||
| 4 | + | ||
| 5 | +## Product Support | ||
| 6 | + | ||
| 7 | +| Product | Supported| | ||
| 8 | +| :----------------------------------------------------------- | :------: | | ||
| 9 | +| Ascend 950PR/Ascend 950DT | √ | | ||
| 10 | +| <term>Atlas A3 training products/Atlas A3 inference products</term> | √ | | ||
| 11 | +| <term>Atlas A2 training products/Atlas A2 inference products</term> | √ | | ||
| 12 | +| <term>Atlas 200I/500 A2 inference products</term> | × | | ||
| 13 | +| <term>Atlas inference products</term> | × | | ||
| 14 | +| <term>Atlas training products</term> | × | | ||
| 15 | + | ||
| 16 | +## Function | ||
| 17 | + | ||
| 18 | +Description: Computes the fast Gaussian error linear unit (GELU) activation function. | ||
| 19 | +**FastGelu** is defined as follows: | ||
| 20 | + | ||
| 21 | +$$ | ||
| 22 | +FastGelu(x_i) = \frac {x_i} {1 + e^{-1.702 x_i}} | ||
| 23 | +$$ | ||
| 24 | + | ||
| 25 | +Where $x_{i}$ is the input element. | ||
| 26 | + | ||
| 27 | +## Prototype | ||
| 28 | + | ||
| 29 | +Each operator has [two-phase API](../../../docs/en/context/two_phase_api.md) calls. First, **aclnnFastGeluGetWorkspaceSize** is called to obtain the workspace size required for computation and the executor that contains the operator computation flow. Then, **aclnnFastGelu** is called to perform computation. | ||
| 30 | + | ||
| 31 | +```Cpp | ||
| 32 | +aclnnStatus aclnnFastGeluGetWorkspaceSize( | ||
| 33 | + const aclTensor *self, | ||
| 34 | + aclTensor *out, | ||
| 35 | + uint64_t *workspaceSize, | ||
| 36 | + aclOpExecutor **executor) | ||
| 37 | +``` | ||
| 38 | + | ||
| 39 | +```Cpp | ||
| 40 | +aclnnStatus aclnnFastGelu( | ||
| 41 | + void *workspace, | ||
| 42 | + uint64_t workspaceSize, | ||
| 43 | + aclOpExecutor *executor, | ||
| 44 | + aclrtStream stream) | ||
| 45 | +``` | ||
| 46 | + | ||
| 47 | +## aclnnFastGeluGetWorkspaceSize | ||
| 48 | + | ||
| 49 | +- **Parameters** | ||
| 50 | + | ||
| 51 | + <table style="undefined;table-layout: fixed; width: 1420px"><colgroup> | ||
| 52 | + <col style="width: 271px"> | ||
| 53 | + <col style="width: 115px"> | ||
| 54 | + <col style="width: 220px"> | ||
| 55 | + <col style="width: 250px"> | ||
| 56 | + <col style="width: 177px"> | ||
| 57 | + <col style="width: 104px"> | ||
| 58 | + <col style="width: 138px"> | ||
| 59 | + <col style="width: 145px"> | ||
| 60 | + </colgroup> | ||
| 61 | + <thead> | ||
| 62 | + <tr> | ||
| 63 | + <th>Name</th> | ||
| 64 | + <th>Input/Output</th> | ||
| 65 | + <th>Description</th> | ||
| 66 | + <th>Usage Notes</th> | ||
| 67 | + <th>Data Type</th> | ||
| 68 | + <th>Data Format</th> | ||
| 69 | + <th>Shape</th> | ||
| 70 | + <th>Non-contiguous Tensor</th> | ||
| 71 | + </tr></thead> | ||
| 72 | + <tbody> | ||
| 73 | + <tr> | ||
| 74 | + <td>self (aclTensor*) </td> | ||
| 75 | + <td>Input</td> | ||
| 76 | + <td>Input tensor, corresponding to x_{i} in the formula.</td> | ||
| 77 | + <td><ul><li>The data format must be the same as that of out. </li><li>The shape must be the same as that of out. </li><li>The data type must be the same as that of out.</li></ul></td> | ||
| 78 | + <td>FLOAT16, FLOAT32, BFLOAT16</td> | ||
| 79 | + <td>ND</td> | ||
| 80 | + <td>0–8</td> | ||
| 81 | + <td>√</td> | ||
| 82 | + </tr> | ||
| 83 | + <tr> | ||
| 84 | + <td>out (aclTensor*) </td> | ||
| 85 | + <td>Output</td> | ||
| 86 | + <td>Output tensor, corresponding to FastGelu(x_i) in the formula.</td> | ||
| 87 | + <td><ul><li>The data format must be the same as that of self. </li><li>The shape must be the same as that of self. </li><li>The data format must be the same as that of self.</li></ul></td> | ||
| 88 | + <td>FLOAT16, FLOAT32, BFLOAT16</td> | ||
| 89 | + <td>ND</td> | ||
| 90 | + <td>0–8</td> | ||
| 91 | + <td>√</td> | ||
| 92 | + </tr> | ||
| 93 | + <tr> | ||
| 94 | + <td>workspaceSize (uint64_t*) </td> | ||
| 95 | + <td>Output</td> | ||
| 96 | + <td>Size of the workspace required to be allocated on the device.</td> | ||
| 97 | + <td>-</td> | ||
| 98 | + <td>-</td> | ||
| 99 | + <td>-</td> | ||
| 100 | + <td>-</td> | ||
| 101 | + <td>-</td> | ||
| 102 | + </tr> | ||
| 103 | + <tr> | ||
| 104 | + <td>executor (aclOpExecutor**) </td> | ||
| 105 | + <td>Output</td> | ||
| 106 | + <td>Operator executor, containing the operator computation flow.</td> | ||
| 107 | + <td>-</td> | ||
| 108 | + <td>-</td> | ||
| 109 | + <td>-</td> | ||
| 110 | + <td>-</td> | ||
| 111 | + <td>-</td> | ||
| 112 | + </tr> | ||
| 113 | + </tbody> | ||
| 114 | + </table> | ||
| 115 | + | ||
| 116 | +- **Returns** | ||
| 117 | + | ||
| 118 | + `aclnnStatus`: status code. For details, see [aclnn Return Code](../../../docs/en/context/aclnn_return_code.md). | ||
| 119 | + | ||
| 120 | + The first-phase API implements input parameter verification. The following errors may be thrown. | ||
| 121 | + | ||
| 122 | + <table style="undefined;table-layout: fixed;width: 979px"><colgroup> | ||
| 123 | + <col style="width: 272px"> | ||
| 124 | + <col style="width: 103px"> | ||
| 125 | + <col style="width: 604px"> | ||
| 126 | + </colgroup> | ||
| 127 | + <thead> | ||
| 128 | + <tr> | ||
| 129 | + <th>Return Code</th> | ||
| 130 | + <th>Error Code</th> | ||
| 131 | + <th>Description</th> | ||
| 132 | + </tr> | ||
| 133 | + </thead> | ||
| 134 | + <tbody> | ||
| 135 | + <tr> | ||
| 136 | + <td>ACLNN_ERR_PARAM_NULLPTR</td> | ||
| 137 | + <td>161001</td> | ||
| 138 | + <td>self or out is a null pointer.</td> | ||
| 139 | + </tr> | ||
| 140 | + <tr> | ||
| 141 | + <td rowspan="8">ACLNN_ERR_PARAM_INVALID</td> | ||
| 142 | + <td rowspan="8">161002</td> | ||
| 143 | + <td>The data types or data formats of self and out do not match.</td> | ||
| 144 | + </tr> | ||
| 145 | + <tr> | ||
| 146 | + <td>The data type of self or out is not supported.</td> | ||
| 147 | + </tr> | ||
| 148 | + <tr> | ||
| 149 | + <td>The shapes of self and out do not match.</td> | ||
| 150 | + </tr> | ||
| 151 | + <tr> | ||
| 152 | + <td>self has more than 8 dimensions.</td> | ||
| 153 | + </tr> | ||
| 154 | + </tbody></table> | ||
| 155 | + | ||
| 156 | +## aclnnFastGelu | ||
| 157 | + | ||
| 158 | +- **Parameters** | ||
| 159 | + | ||
| 160 | + <table style="undefined;table-layout: fixed; width: 953px"><colgroup> | ||
| 161 | + <col style="width: 173px"> | ||
| 162 | + <col style="width: 112px"> | ||
| 163 | + <col style="width: 668px"> | ||
| 164 | + </colgroup> | ||
| 165 | + <thead> | ||
| 166 | + <tr> | ||
| 167 | + <th>Name</th> | ||
| 168 | + <th>Input/Output</th> | ||
| 169 | + <th>Description</th> | ||
| 170 | + </tr></thead> | ||
| 171 | + <tbody> | ||
| 172 | + <tr> | ||
| 173 | + <td>workspace</td> | ||
| 174 | + <td>Input</td> | ||
| 175 | + <td>Address of the workspace to be allocated on the device.</td> | ||
| 176 | + </tr> | ||
| 177 | + <tr> | ||
| 178 | + <td>workspaceSize</td> | ||
| 179 | + <td>Input</td> | ||
| 180 | + <td>Size of the workspace to be allocated on the device, which is obtained by calling the first-phase API aclnnFastGeluGetWorkspaceSize.</td> | ||
| 181 | + </tr> | ||
| 182 | + <tr> | ||
| 183 | + <td>executor</td> | ||
| 184 | + <td>Input</td> | ||
| 185 | + <td>Operator executor, containing the operator computation flow.</td> | ||
| 186 | + </tr> | ||
| 187 | + <tr> | ||
| 188 | + <td>stream</td> | ||
| 189 | + <td>Input</td> | ||
| 190 | + <td>Stream for executing the task.</td> | ||
| 191 | + </tr> | ||
| 192 | + </tbody> | ||
| 193 | + </table> | ||
| 194 | + | ||
| 195 | +- **Returns** | ||
| 196 | + | ||
| 197 | + `aclnnStatus`: status code. For details, see [aclnn Return Code](../../../docs/en/context/aclnn_return_code.md). | ||
| 198 | + | ||
| 199 | +## Constraints | ||
| 200 | + | ||
| 201 | +- Deterministic computation: | ||
| 202 | + - **aclnnFastGelu** defaults to a deterministic implementation. | ||
| 203 | + | ||
| 204 | +## Example | ||
| 205 | + | ||
| 206 | +The following example is for reference only. For details, see [Compile and Run Sample](../../../docs/en/context/compile_and_run_sample.md). | ||
| 207 | + | ||
| 208 | +```Cpp | ||
| 209 | +#include <iostream> | ||
| 210 | +#include <vector> | ||
| 211 | +#include "acl/acl.h" | ||
| 212 | +#include "aclnnop/aclnn_fast_gelu.h" | ||
| 213 | + | ||
| 214 | +#define CHECK_RET(cond, return_expr) \ | ||
| 215 | + do { \ | ||
| 216 | + if (!(cond)) { \ | ||
| 217 | + return_expr; \ | ||
| 218 | + } \ | ||
| 219 | + } while (0) | ||
| 220 | + | ||
| 221 | +#define LOG_PRINT(message, ...) \ | ||
| 222 | + do { \ | ||
| 223 | + printf(message, ##__VA_ARGS__); \ | ||
| 224 | + } while (0) | ||
| 225 | + | ||
| 226 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 227 | +{ | ||
| 228 | + int64_t shapeSize = 1; | ||
| 229 | + for (auto i : shape) { | ||
| 230 | + shapeSize *= i; | ||
| 231 | + } | ||
| 232 | + return shapeSize; | ||
| 233 | +} | ||
| 234 | + | ||
| 235 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 236 | +{ | ||
| 237 | + // (Boilerplate) Initialize resources. | ||
| 238 | + auto ret = aclInit(nullptr); | ||
| 239 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 240 | + ret = aclrtSetDevice(deviceId); | ||
| 241 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 242 | + ret = aclrtCreateStream(stream); | ||
| 243 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 244 | + return 0; | ||
| 245 | +} | ||
| 246 | + | ||
| 247 | +template <typename T> | ||
| 248 | +int CreateAclTensor( | ||
| 249 | + const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, aclDataType dataType, | ||
| 250 | + aclTensor** tensor) | ||
| 251 | +{ | ||
| 252 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 253 | + // Call aclrtMalloc to allocate memory on the device. | ||
| 254 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 255 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 256 | + // Call aclrtMemcpy to copy the data on the host to the memory on the device. | ||
| 257 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 258 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 259 | + | ||
| 260 | + // Compute the strides of the contiguous tensor. | ||
| 261 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 262 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 263 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 264 | + } | ||
| 265 | + | ||
| 266 | + // Call aclCreateTensor to create an aclTensor. | ||
| 267 | + *tensor = aclCreateTensor( | ||
| 268 | + shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), | ||
| 269 | + *deviceAddr); | ||
| 270 | + return 0; | ||
| 271 | +} | ||
| 272 | + | ||
| 273 | +int main() | ||
| 274 | +{ | ||
| 275 | + // 1. (Boilerplate) Initialize the device and stream. For details, see the ACL API manual. | ||
| 276 | + // Set the device ID (deviceId) based on the actual device. | ||
| 277 | + int32_t deviceId = 0; | ||
| 278 | + aclrtStream stream; | ||
| 279 | + auto ret = Init(deviceId, &stream); | ||
| 280 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 281 | + // 2. Construct inputs and outputs based on API definitions. | ||
| 282 | + std::vector<int64_t> selfShape = {3, 3}; | ||
| 283 | + std::vector<int64_t> outShape = {3, 3}; | ||
| 284 | + void* selfDeviceAddr = nullptr; | ||
| 285 | + aclTensor* self = nullptr; | ||
| 286 | + void* outDeviceAddr = nullptr; | ||
| 287 | + aclTensor* out = nullptr; | ||
| 288 | + std::vector<float> selfHostData(9, 0); | ||
| 289 | + std::vector<float> outHostData(9, 0); | ||
| 290 | + // Create self and out aclTensors. | ||
| 291 | + ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self); | ||
| 292 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 293 | + ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out); | ||
| 294 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 295 | + | ||
| 296 | + // 3. Call the CANN operator library API. Modify the API as required. | ||
| 297 | + uint64_t workspaceSize = 0; | ||
| 298 | + aclOpExecutor* executor; | ||
| 299 | + // Call the first-phase API of aclnnFastGelu. | ||
| 300 | + ret = aclnnFastGeluGetWorkspaceSize(self, out, &workspaceSize, &executor); | ||
| 301 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnFastGeluGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 302 | + // Allocate device memory based on workspaceSize computed by the first-phase API. | ||
| 303 | + void* workspaceAddr = nullptr; | ||
| 304 | + if (workspaceSize > 0) { | ||
| 305 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 306 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 307 | + } | ||
| 308 | + // Call the second-phase API of aclnnFastGelu. | ||
| 309 | + ret = aclnnFastGelu(workspaceAddr, workspaceSize, executor, stream); | ||
| 310 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnFastGelu failed. ERROR: %d\n", ret); return ret); | ||
| 311 | + // 4. (Boilerplate) Synchronize the stream and wait for task completion. | ||
| 312 | + ret = aclrtSynchronizeStream(stream); | ||
| 313 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 314 | + // 5. Obtain the output value and copy the result from the device to the host. Modify the code based on the API definition. | ||
| 315 | + auto size = GetShapeSize(outShape); | ||
| 316 | + std::vector<float> resultData(size, 0); | ||
| 317 | + ret = aclrtMemcpy( | ||
| 318 | + resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, size * sizeof(resultData[0]), | ||
| 319 | + ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 320 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 321 | + for (int64_t i = 0; i < size; i++) { | ||
| 322 | + LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]); | ||
| 323 | + } | ||
| 324 | + | ||
| 325 | + // 6. Destroy aclTensor. Modify the code based on the API definition. | ||
| 326 | + aclDestroyTensor(self); | ||
| 327 | + aclDestroyTensor(out); | ||
| 328 | + | ||
| 329 | + // 7. Release device resources. Modify the code based on the API definition. | ||
| 330 | + aclrtFree(selfDeviceAddr); | ||
| 331 | + aclrtFree(outDeviceAddr); | ||
| 332 | + if (workspaceSize > 0) { | ||
| 333 | + aclrtFree(workspaceAddr); | ||
| 334 | + } | ||
| 335 | + aclrtDestroyStream(stream); | ||
| 336 | + aclrtResetDevice(deviceId); | ||
| 337 | + aclFinalize(); | ||
| 338 | + return 0; | ||
| 339 | +} | ||
| 340 | +``` | ||
| @@ -0,0 +1,350 @@ | |||
| 1 | +# aclnnFastGeluBackward | ||
| 2 | + | ||
| 3 | +[📄 View source code](https://gitcode.com/cann/ops-nn/tree/master/activation/fast_gelu_grad) | ||
| 4 | + | ||
| 5 | +## Product Support | ||
| 6 | + | ||
| 7 | +| Product | Supported| | ||
| 8 | +| :----------------------------------------------------------- | :------: | | ||
| 9 | +| Ascend 950PR/Ascend 950DT | √ | | ||
| 10 | +| <term>Atlas A3 training products/Atlas A3 inference products</term> | √ | | ||
| 11 | +| <term>Atlas A2 training products/Atlas A2 inference products</term> | √ | | ||
| 12 | +| <term>Atlas 200I/500 A2 inference products</term> | × | | ||
| 13 | +| <term>Atlas inference products</term> | × | | ||
| 14 | +| <term>Atlas training products</term> | × | | ||
| 15 | + | ||
| 16 | +## Function | ||
| 17 | + | ||
| 18 | +Description: Computes the backward pass of [FastGelu](../../fast_gelu/docs/aclnnFastGelu_en.md). | ||
| 19 | +**FastGeluBackward** is defined as follows: | ||
| 20 | + | ||
| 21 | +$$ | ||
| 22 | +dx = dy * ((\frac{1}{e^{-1.702 x}+1} - 1) * -1.702x + 1) * \frac{1}{(e^{-1.702 x}+1)} | ||
| 23 | +$$ | ||
| 24 | + | ||
| 25 | +## Prototype | ||
| 26 | + | ||
| 27 | +Each operator has [two-phase API](../../../docs/en/context/two_phase_api.md) calls. First, **aclnnFastGeluBackwardGetWorkspaceSize** is called to obtain the workspace size required for computation and the executor that contains the operator computation flow. Then, **aclnnFastGeluBackward** is called to perform computation. | ||
| 28 | + | ||
| 29 | +```Cpp | ||
| 30 | +aclnnStatus aclnnFastGeluBackwardGetWorkspaceSize( | ||
| 31 | + const aclTensor *gradOutput, | ||
| 32 | + const aclTensor *self, | ||
| 33 | + aclTensor *gradInput, | ||
| 34 | + uint64_t *workspaceSize, | ||
| 35 | + aclOpExecutor **executor) | ||
| 36 | +``` | ||
| 37 | + | ||
| 38 | +```Cpp | ||
| 39 | +aclnnStatus aclnnFastGeluBackward( | ||
| 40 | + void *workspace, | ||
| 41 | + uint64_t workspaceSize, | ||
| 42 | + aclOpExecutor *executor, | ||
| 43 | + aclrtStream stream) | ||
| 44 | +``` | ||
| 45 | + | ||
| 46 | +## aclnnFastGeluBackwardGetWorkspaceSize | ||
| 47 | + | ||
| 48 | +- **Parameters** | ||
| 49 | + | ||
| 50 | + <table style="undefined;table-layout: fixed; width: 1450px"><colgroup> | ||
| 51 | + <col style="width: 271px"> | ||
| 52 | + <col style="width: 115px"> | ||
| 53 | + <col style="width: 220px"> | ||
| 54 | + <col style="width: 280px"> | ||
| 55 | + <col style="width: 177px"> | ||
| 56 | + <col style="width: 104px"> | ||
| 57 | + <col style="width: 138px"> | ||
| 58 | + <col style="width: 145px"> | ||
| 59 | + </colgroup> | ||
| 60 | + <thead> | ||
| 61 | + <tr> | ||
| 62 | + <th>Name</th> | ||
| 63 | + <th>Input/Output</th> | ||
| 64 | + <th>Description</th> | ||
| 65 | + <th>Usage Notes</th> | ||
| 66 | + <th>Data Type</th> | ||
| 67 | + <th>Data Format</th> | ||
| 68 | + <th>Shape</th> | ||
| 69 | + <th>Non-contiguous Tensor</th> | ||
| 70 | + </tr></thead> | ||
| 71 | + <tbody> | ||
| 72 | + <tr> | ||
| 73 | + <td>gradOutput (aclTensor*) </td> | ||
| 74 | + <td>Input</td> | ||
| 75 | + <td>Gradient for the backward pass, corresponding to dy in the formula.</td> | ||
| 76 | + <td><ul><li>The data format must be the same as that of self and gradInput. </li><li>The shape must be the same as that of self and gradInput. </li><li>The data type must be the same as that of self and gradInput.</li></ul></td> | ||
| 77 | + <td>FLOAT16, FLOAT32, BFLOAT16</td> | ||
| 78 | + <td>ND</td> | ||
| 79 | + <td>0–8</td> | ||
| 80 | + <td>√</td> | ||
| 81 | + </tr> | ||
| 82 | + <tr> | ||
| 83 | + <td>self (aclTensor*) </td> | ||
| 84 | + <td>Input</td> | ||
| 85 | + <td>Input tensor, corresponding to x in the formula. It is the same as self in the forward pass.</td> | ||
| 86 | + <td><ul><li>The data format must be the same as that of gradOutput and gradInput. </li><li>The shape must be the same as that of gradOutput and gradInput. </li><li>The data type must be the same as that of gradOutput and gradInput.</li></ul></td> | ||
| 87 | + <td>FLOAT16, FLOAT32, BFLOAT16</td> | ||
| 88 | + <td>ND</td> | ||
| 89 | + <td>0–8</td> | ||
| 90 | + <td>√</td> | ||
| 91 | + </tr> | ||
| 92 | + <tr> | ||
| 93 | + <td>gradInput (aclTensor*) </td> | ||
| 94 | + <td>Output</td> | ||
| 95 | + <td>Output tensor, corresponding to dx in the formula.</td> | ||
| 96 | + <td><ul><li>The data format must be the same as that of gradOutput and self. </li><li>The shape must be the same as that of gradOutput and self. </li><li>The data type must be the same as that of gradOutput and self.</li></ul></td> | ||
| 97 | + <td>FLOAT16, FLOAT32, BFLOAT16</td> | ||
| 98 | + <td>ND</td> | ||
| 99 | + <td>0–8</td> | ||
| 100 | + <td>√</td> | ||
| 101 | + </tr> | ||
| 102 | + <tr> | ||
| 103 | + <td>workspaceSize (uint64_t*) </td> | ||
| 104 | + <td>Output</td> | ||
| 105 | + <td>Size of the workspace required to be allocated on the device.</td> | ||
| 106 | + <td>-</td> | ||
| 107 | + <td>-</td> | ||
| 108 | + <td>-</td> | ||
| 109 | + <td>-</td> | ||
| 110 | + <td>-</td> | ||
| 111 | + </tr> | ||
| 112 | + <tr> | ||
| 113 | + <td>executor (aclOpExecutor**) </td> | ||
| 114 | + <td>Output</td> | ||
| 115 | + <td>Operator executor, containing the operator computation flow.</td> | ||
| 116 | + <td>-</td> | ||
| 117 | + <td>-</td> | ||
| 118 | + <td>-</td> | ||
| 119 | + <td>-</td> | ||
| 120 | + <td>-</td> | ||
| 121 | + </tr> | ||
| 122 | + </tbody> | ||
| 123 | + </table> | ||
| 124 | + | ||
| 125 | +- **Returns** | ||
| 126 | + | ||
| 127 | + `aclnnStatus`: status code. For details, see [aclnn Return Code](../../../docs/en/context/aclnn_return_code.md). | ||
| 128 | + | ||
| 129 | + The first-phase API implements input parameter verification. The following errors may be thrown. | ||
| 130 | + | ||
| 131 | + <table style="undefined;table-layout: fixed;width: 979px"><colgroup> | ||
| 132 | + <col style="width: 272px"> | ||
| 133 | + <col style="width: 103px"> | ||
| 134 | + <col style="width: 604px"> | ||
| 135 | + </colgroup> | ||
| 136 | + <thead> | ||
| 137 | + <tr> | ||
| 138 | + <th>Return Code</th> | ||
| 139 | + <th>Error Code</th> | ||
| 140 | + <th>Description</th> | ||
| 141 | + </tr> | ||
| 142 | + </thead> | ||
| 143 | + <tbody> | ||
| 144 | + <tr> | ||
| 145 | + <td>ACLNN_ERR_PARAM_NULLPTR</td> | ||
| 146 | + <td>161001</td> | ||
| 147 | + <td>gradOutput, self, or gradInput is a null pointer.</td> | ||
| 148 | + </tr> | ||
| 149 | + <tr> | ||
| 150 | + <td rowspan="8">ACLNN_ERR_PARAM_INVALID</td> | ||
| 151 | + <td rowspan="8">161002</td> | ||
| 152 | + <td>The data types or data formats of gradOutput, self, and gradInput do not match.</td> | ||
| 153 | + </tr> | ||
| 154 | + <tr> | ||
| 155 | + <td>The data type of gradInput is not supported.</td> | ||
| 156 | + </tr> | ||
| 157 | + <tr> | ||
| 158 | + <td>The shapes of gradOutput, self, and gradInput do not match.</td> | ||
| 159 | + </tr> | ||
| 160 | + <tr> | ||
| 161 | + <td>self has more than 8 dimensions.</td> | ||
| 162 | + </tr> | ||
| 163 | + </tbody></table> | ||
| 164 | + | ||
| 165 | +## aclnnFastGeluBackward | ||
| 166 | + | ||
| 167 | +- **Parameters** | ||
| 168 | + | ||
| 169 | + <table style="undefined;table-layout: fixed; width: 953px"><colgroup> | ||
| 170 | + <col style="width: 173px"> | ||
| 171 | + <col style="width: 112px"> | ||
| 172 | + <col style="width: 668px"> | ||
| 173 | + </colgroup> | ||
| 174 | + <thead> | ||
| 175 | + <tr> | ||
| 176 | + <th>Name</th> | ||
| 177 | + <th>Input/Output</th> | ||
| 178 | + <th>Description</th> | ||
| 179 | + </tr></thead> | ||
| 180 | + <tbody> | ||
| 181 | + <tr> | ||
| 182 | + <td>workspace</td> | ||
| 183 | + <td>Input</td> | ||
| 184 | + <td>Address of the workspace to be allocated on the device.</td> | ||
| 185 | + </tr> | ||
| 186 | + <tr> | ||
| 187 | + <td>workspaceSize</td> | ||
| 188 | + <td>Input</td> | ||
| 189 | + <td>Size of the workspace to be allocated on the device, which is obtained by calling the first-phase API aclnnFastGeluBackwardGetWorkspaceSize.</td> | ||
| 190 | + </tr> | ||
| 191 | + <tr> | ||
| 192 | + <td>executor</td> | ||
| 193 | + <td>Input</td> | ||
| 194 | + <td>Operator executor, containing the operator computation flow.</td> | ||
| 195 | + </tr> | ||
| 196 | + <tr> | ||
| 197 | + <td>stream</td> | ||
| 198 | + <td>Input</td> | ||
| 199 | + <td>Stream for executing the task.</td> | ||
| 200 | + </tr> | ||
| 201 | + </tbody> | ||
| 202 | + </table> | ||
| 203 | + | ||
| 204 | +- **Returns** | ||
| 205 | + | ||
| 206 | + `aclnnStatus`: status code. For details, see [aclnn Return Code](../../../docs/en/context/aclnn_return_code.md). | ||
| 207 | + | ||
| 208 | +## Constraints | ||
| 209 | + | ||
| 210 | +- Deterministic computation: | ||
| 211 | + - **aclnnFastGeluBackward** defaults to a deterministic implementation. | ||
| 212 | + | ||
| 213 | +## Example | ||
| 214 | + | ||
| 215 | +The following example is for reference only. For details, see [Compile and Run Sample](../../../docs/en/context/compile_and_run_sample.md). | ||
| 216 | + | ||
| 217 | +```Cpp | ||
| 218 | +#include <iostream> | ||
| 219 | +#include <vector> | ||
| 220 | +#include "acl/acl.h" | ||
| 221 | +#include "aclnnop/aclnn_fast_gelu_backward.h" | ||
| 222 | + | ||
| 223 | +#define CHECK_RET(cond, return_expr) \ | ||
| 224 | + do { \ | ||
| 225 | + if (!(cond)) { \ | ||
| 226 | + return_expr; \ | ||
| 227 | + } \ | ||
| 228 | + } while (0) | ||
| 229 | + | ||
| 230 | +#define LOG_PRINT(message, ...) \ | ||
| 231 | + do { \ | ||
| 232 | + printf(message, ##__VA_ARGS__); \ | ||
| 233 | + } while (0) | ||
| 234 | + | ||
| 235 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) { | ||
| 236 | + int64_t shapeSize = 1; | ||
| 237 | + for (auto i : shape) { | ||
| 238 | + shapeSize *= i; | ||
| 239 | + } | ||
| 240 | + return shapeSize; | ||
| 241 | +} | ||
| 242 | + | ||
| 243 | +int Init(int32_t deviceId, aclrtStream* stream) { | ||
| 244 | + // (Boilerplate) Initialize resources. | ||
| 245 | + auto ret = aclInit(nullptr); | ||
| 246 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 247 | + ret = aclrtSetDevice(deviceId); | ||
| 248 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 249 | + ret = aclrtCreateStream(stream); | ||
| 250 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 251 | + return 0; | ||
| 252 | +} | ||
| 253 | + | ||
| 254 | +template <typename T> | ||
| 255 | +int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 256 | + aclDataType dataType, aclTensor** tensor) { | ||
| 257 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 258 | + // Call aclrtMalloc to allocate memory on the device. | ||
| 259 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 260 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 261 | + // Call aclrtMemcpy to copy the data on the host to the memory on the device. | ||
| 262 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 263 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 264 | + | ||
| 265 | + // Compute the strides of the contiguous tensor. | ||
| 266 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 267 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 268 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 269 | + } | ||
| 270 | + | ||
| 271 | + // Call aclCreateTensor to create an aclTensor. | ||
| 272 | + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 273 | + shape.data(), shape.size(), *deviceAddr); | ||
| 274 | + return 0; | ||
| 275 | +} | ||
| 276 | + | ||
| 277 | +int main() { | ||
| 278 | + // 1. (Boilerplate) Initialize the device and stream. For details, see the ACL API manual. | ||
| 279 | + // Set the device ID (deviceId) based on the actual device. | ||
| 280 | + int32_t deviceId = 0; | ||
| 281 | + aclrtStream stream; | ||
| 282 | + auto ret = Init(deviceId, &stream); | ||
| 283 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 284 | + // 2. Construct inputs and outputs based on API definitions. | ||
| 285 | + std::vector<int64_t> gradOutputShape = {3, 3}; | ||
| 286 | + std::vector<int64_t> selfShape = {3, 3}; | ||
| 287 | + std::vector<int64_t> gradInputShape = {3, 3}; | ||
| 288 | + void* gradOutputDeviceAddr = nullptr; | ||
| 289 | + aclTensor* gradOutput = nullptr; | ||
| 290 | + void* selfDeviceAddr = nullptr; | ||
| 291 | + aclTensor* self = nullptr; | ||
| 292 | + void* gradInputDeviceAddr = nullptr; | ||
| 293 | + aclTensor* gradInput = nullptr; | ||
| 294 | + std::vector<float> gradOutputHostData(9, 0); | ||
| 295 | + std::vector<float> selfHostData(9, 0); | ||
| 296 | + std::vector<float> gradInputHostData(9, 0); | ||
| 297 | + // Create gradOutput, self, and gradInput aclTensors. | ||
| 298 | + ret = CreateAclTensor(gradOutputHostData, selfShape, &gradOutputDeviceAddr, aclDataType::ACL_FLOAT, &gradOutput); | ||
| 299 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 300 | + ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self); | ||
| 301 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 302 | + ret = CreateAclTensor(gradInputHostData, gradInputShape, &gradInputDeviceAddr, aclDataType::ACL_FLOAT, &gradInput); | ||
| 303 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 304 | + | ||
| 305 | + // 3. Call the CANN operator library API. Modify the API as required. | ||
| 306 | + uint64_t workspaceSize = 0; | ||
| 307 | + aclOpExecutor* executor; | ||
| 308 | + // Call the first-phase API of aclnnFastGeluBackward. | ||
| 309 | + ret = aclnnFastGeluBackwardGetWorkspaceSize(gradOutput, self, gradInput, &workspaceSize, &executor); | ||
| 310 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnFastGeluBackwardGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 311 | + // Allocate device memory based on workspaceSize computed by the first-phase API. | ||
| 312 | + void* workspaceAddr = nullptr; | ||
| 313 | + if (workspaceSize > 0) { | ||
| 314 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 315 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 316 | + } | ||
| 317 | + // Call the second-phase API of aclnnFastGeluBackward. | ||
| 318 | + ret = aclnnFastGeluBackward(workspaceAddr, workspaceSize, executor, stream); | ||
| 319 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnFastGeluBackward failed. ERROR: %d\n", ret); return ret); | ||
| 320 | + // 4. (Boilerplate) Synchronize the stream and wait for task completion. | ||
| 321 | + ret = aclrtSynchronizeStream(stream); | ||
| 322 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 323 | + // 5. Obtain the output value and copy the result from the device to the host. Modify the code based on the API definition. | ||
| 324 | + auto size = GetShapeSize(gradInputShape); | ||
| 325 | + std::vector<float> resultData(size, 0); | ||
| 326 | + ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), gradInputDeviceAddr, | ||
| 327 | + size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 328 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 329 | + for (int64_t i = 0; i < size; i++) { | ||
| 330 | + LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]); | ||
| 331 | + } | ||
| 332 | + | ||
| 333 | + // 6. Destroy aclTensor. Modify the code based on the API definition. | ||
| 334 | + aclDestroyTensor(gradOutput); | ||
| 335 | + aclDestroyTensor(self); | ||
| 336 | + aclDestroyTensor(gradInput); | ||
| 337 | + | ||
| 338 | + // 7. Release device resources. Modify the code based on the API definition. | ||
| 339 | + aclrtFree(gradOutputDeviceAddr); | ||
| 340 | + aclrtFree(selfDeviceAddr); | ||
| 341 | + aclrtFree(gradInputDeviceAddr); | ||
| 342 | + if (workspaceSize > 0) { | ||
| 343 | + aclrtFree(workspaceAddr); | ||
| 344 | + } | ||
| 345 | + aclrtDestroyStream(stream); | ||
| 346 | + aclrtResetDevice(deviceId); | ||
| 347 | + aclFinalize(); | ||
| 348 | + return 0; | ||
| 349 | +} | ||
| 350 | +``` | ||