ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

aclnnBidirectionLSTM:双向LSTM算子从原理到调用的完整指南

aclnnBidirectionLSTM:双向LSTM算子从原理到调用的完整指南 aclnnBidirectionLSTM双向LSTM算子从原理到调用的完整指南【免费下载链接】ops-nn本项目是CANN提供的神经网络类计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-nnaclnnBidirectionLSTM是 CANN 算子库中面向 Ascend NPU 的循环神经网络算子位于 ops-nn 的 rnn 分类下。它接收输入序列与初始隐藏/cell 状态完成双向长短时记忆LSTM的前向推演返回各时刻隐藏状态与序列末端的 cell 状态常用于文本等序列数据的建模与推理。计算原理双向LSTM算子调用的门控机制LSTM 属于循环神经网络家族中的一种变体通过门来调控信息在时间步之间的流动。该算子负责把整段序列按时间步逐步展开每个时间步都用四组门控参数对上一时刻状态和当前输入做加权组合再叠加偏置后过激活函数从而更新隐藏状态与 cell 状态开启双向bidirection时会同时做正向与逆向两条推演把两路输出在特征维上拼接。单个时间步 $t$ 的递推关系如下$$ f_t \mathrm{sigm}(W_f [h_{t-1}, x_t] b_f) \ i_t \mathrm{sigm}(W_i [h_{t-1}, x_t] b_i) \ o_t \mathrm{sigm}(W_o [h_{t-1}, x_t] b_o) \ \tilde{c}t \tanh(W_c [h_{t-1}, x_t] b_c) \ c_t f_t \odot c{t-1} i_t \odot \tilde{c}t \ c{o}^{t} \tanh(c_t) \ h_t o_t \odot c_{o}^{t} $$各符号含义逐条说明$x_t \in R^{d}$对应公式里 $x_t$ 项LSTM 单元的输入向量即当前时间步喂进来的特征。$f_t \in (0, 1)^{h}$对应公式里 $f_t$ 项遗忘门激活向量决定保留多少上一时刻 cell 状态。$i_t \in (0, 1)^{h}$对应公式里 $i_t$ 项输入门更新门激活向量决定写入多少新信息。$o_t \in (0, 1)^{h}$对应公式里 $o_t$ 项输出门激活向量控制 cell 状态向隐藏状态的放行比例。$h_i \in (-1, 1)^{h}$隐藏状态向量也就是该时刻 LSTM 单元对外输出的向量。$\tilde{c}_t \in (-1, 1)^{h}$cell 输入激活向量经 tanh 约束后的候选新状态。$c_t \in R^{h}$cell 状态向量沿时间步累积的长期记忆。$W \in R^{h\times d}$$(U \in R^{h\times h}) \cap (b \in R^{h})$训练阶段需要学习的权重矩阵与偏置向量参数。硬件适配一览该算子目前仅覆盖 Atlas 推理系列产品其余主流训练/推理系列均不在支持范围内。支持状态以 ✅ 表示可用、以 × 表示不可用下表将可用项前置便于快速核对。产品系列支持状态补充说明Atlas 推理系列产品✅当前唯一可用产品线Ascend 950PR / Ascend 950DT×不支持Atlas A3 训练/推理系列产品×不支持Atlas A2 训练/推理系列产品×不支持Atlas 200I / 500 A2 推理产品×不支持Atlas 训练系列产品×不支持调用时序与接口定义aclnn 两段式接口aclnnBidirectionLSTM遵循 CANN 算子的 aclnn 两段式接口规范先由aclnnBidirectionLSTMGetWorkspaceSize完成入参校验并算出所需 CANN 算子 workspace 的大小、返回执行器再由aclnnBidirectionLSTM携带 workspace 与执行器真正下发计算。两段之间不允许插入其他算子调用。文字时序可概括为应用侧 CANN 算子 |--- aclnnBidirectionLSTMGetWorkspaceSize(入参) --| 校验 shape / 类型 / 属性 |-- workspaceSize executor ----------------------| | 按 workspaceSize 在 device 侧申请内存 | |--- aclnnBidirectionLSTM(workspace, executor, stream) --| 执行双向 LSTM 前向 |-- aclnnStatus ------------------------------------|aclnnBidirectionLSTMGetWorkspaceSize函数原型aclnnStatus aclnnBidirectionLSTMGetWorkspaceSize( const aclTensor *x, const aclTensor *initH, const aclTensor *initC, const aclTensor *wIh, const aclTensor *wHh, const aclTensor *bIhOptional, const aclTensor *bHhOptional, const aclTensor *wIhReverseOptional, const aclTensor *wHhReverseOptional, const aclTensor *bIhReverseOptional, const aclTensor *bHhReverseOptional, int64_t numLayers, bool isbias, bool batchFirst, bool bidirection, const aclTensor *yOut, const aclTensor *outputHOut, const aclTensor *outputCOut, uint64_t *workspaceSize, aclOpExecutor **executor)参数一览参数名方向类型Shape / 取值说明x输入aclTensor*(time_step, batch_size, input_size)3 维对应公式中 $x$ 的输入向量支持空 TensorFLOAT16ND支持非连续initH输入aclTensor*(num_layers, batch_size, hidden_size)双向时 (2*num_layers, ...)3 维初始化 hidden 状态即公式中 $h$支持空 TensorFLOAT16ND支持非连续initC输入aclTensor*(num_layers, batch_size, hidden_size)双向时 (2*num_layers, ...)3 维初始化 cell 状态即公式中 $c$支持空 TensorFLOAT16ND支持非连续wIh输入aclTensor*(4*hidden_size, input_size)2 维input-hidden 权重即公式中 $W$支持空 TensorFLOAT16ND支持非连续wHh输入aclTensor*(4*hidden_size, hidden_size)2 维hidden-hidden 权重即公式中 $W$支持空 TensorFLOAT16ND支持非连续bIhOptional输入aclTensor*(4*hidden_size)1 维input-hidden 偏置即公式中 $b$支持空 TensorFLOAT16ND支持非连续bHhOptional输入aclTensor*(4*hidden_size)1 维hidden-hidden 偏置即公式中 $b$支持空 TensorFLOAT16ND支持非连续wIhReverseOptional输入aclTensor*(4*hidden_size, input_size)2 维逆向 input-hidden 权重支持空 TensorFLOAT16ND支持非连续wHhReverseOptional输入aclTensor*(4*hidden_size, input_size)2 维逆向 hidden-hidden 权重支持空 TensorFLOAT16ND支持非连续bIhReverseOptional输入aclTensor*(4*hidden_size)1 维逆向 input-hidden 偏置支持空 TensorFLOAT16ND支持非连续bHhReverseOptional输入aclTensor*(4*hidden_size)1 维逆向 hidden-hidden 偏置支持空 TensorFLOAT16ND支持非连续numLayers输入int64_t当前仅支持 1LSTM 层数isbias输入booltrue / false是否带 biasbatchFirst输入bool当前仅支持 falsebatch 是否位于首维bidirection输入booltrue / false是否双向yOut输出aclTensor*(time_step, batch_size, hidden_size)双向时 (time_step, batch_size, 2*hidden_size)3 维LSTM 单元输出向量FLOAT16ND支持非连续outputHOut输出aclTensor*(num_layers, batch_size, hidden_size)双向时 (2*num_layers, ...)3 维最终 hidden 状态即公式中 $h$FLOAT16ND支持非连续outputCOut输出aclTensor*(num_layers, batch_size, hidden_size)双向时 (2*num_layers, ...)3 维最终 cell 状态即公式中 $c$FLOAT16ND支持非连续workspaceSize输出uint64_t*-返回需在 device 侧申请的 workspace 大小executor输出aclOpExecutor**-返回 op 执行器封装算子计算流程返回值为aclnnStatus状态码。第一段接口会完成入参校验触发报错的典型场景见下文错误码速查。aclnnBidirectionLSTM函数原型aclnnStatus aclnnBidirectionLSTM( void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream)参数一览参数名方向类型说明workspace输入void*在 device 侧申请的 workspace 内存地址workspaceSize输入uint64_t在 device 侧申请的 workspace 大小由第一段接口返回executor输入aclOpExecutor*op 执行器封装算子计算流程stream输入aclrtStream指定执行任务的 Stream返回值为aclnnStatus状态码成功时对应 ACL_SUCCESS。错误码速查第一段接口aclnnBidirectionLSTMGetWorkspaceSize在入参校验阶段可能返回下列状态码均对应aclnnStatus。常量名数字码触发条件ACLNN_ERR_PARAM_NULLPTR161001传入的必选输入、必选输出或必选属性为空指针ACLNN_ERR_PARAM_INVALID161002传入的 aclTensor 数据类型不在支持范围本算子仅 FLOAT16ACLNN_ERR_INNER_TILING_ERROR561002传入的 aclTensor shape 与上文参数说明不符约束与限制⚠️numLayers当前只支持 1层数无法通过该参数叠加。⚠️batchFirst当前只支持 false即时间步必须位于首维若传入 true 会触发 tiling 阶段错误。全部张量数据类型仅支持 FLOAT16数据格式为 ND。双向模式下initH / initC / outputHOut / outputCOut 的首维为2 * num_layersyOut 的特征维为2 * hidden_size正向模式下均为num_layers与hidden_size。确定性aclnnBidirectionLSTM默认即为确定性实现无需额外开关。各输入张量与 yOut / outputHOut / outputCOut 均允许非连续布局也允许以空 Tensor 传入。完整调用示例CANN 算子 workspace 的申请与执行下面示例演示了从初始化 device、构造输入输出张量到调用两段式接口、同步与释放资源的完整链路。代码仅为调用流程参考编译与链接细节请以官方文档为准。#include iostream #include vector #include acl/acl.h #include aclnnop/aclnn_bidirection_lstm.h #define CHECK_RET(cond, return_expr) \ do { \ if (!(cond)) { \ return_expr; \ } \ } while (0) #define LOG_PRINT(message, ...) \ do { \ printf(message, ##__VA_ARGS__); \ } while (0) int64_t GetShapeSize(const std::vectorint64_t shape) { int64_t shapeSize 1; for (auto i : shape) { shapeSize * i; } return shapeSize; } template typename T int CreateAclTensor(const std::vectorT hostData, const std::vectorint64_t shape, void** deviceAddr, aclDataType dataType, aclTensor** tensor) { auto size GetShapeSize(shape) * sizeof(T); auto ret aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtMalloc failed. ERROR: %d\n, ret); return ret); ret aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtMemcpy failed. ERROR: %d\n, ret); return ret); std::vectorint64_t strides(shape.size(), 1); for (int64_t i shape.size() - 2; i 0; i--) { strides[i] shape[i 1] * strides[i 1]; } *tensor aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr); return 0; } int Init(int32_t deviceId, aclrtStream* stream) { auto ret aclInit(nullptr); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclInit failed. ERROR: %d\n, ret); return ret); ret aclrtSetDevice(deviceId); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtSetDevice failed. ERROR: %d\n, ret); return ret); ret aclrtCreateStream(stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtCreateStream failed. ERROR: %d\n, ret); return ret); return 0; } int main() { int32_t deviceId 0; aclrtStream stream; auto ret Init(deviceId, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(Init acl failed. ERROR: %d\n, ret); return ret); int time_step 2, batch_size 32, input_size 32, hidden_size 32; int64_t numLayers 1; bool isbias true, batchFirst false, bidirection true; std::vectorint64_t selfShape {time_step, batch_size, input_size}; std::vectorint64_t weightHIShape {4 * hidden_size, input_size}; std::vectorint64_t weightHHShape {4 * hidden_size, hidden_size}; std::vectorint64_t initHShape {2, batch_size, hidden_size}; std::vectorint64_t initCShape {2, batch_size, hidden_size}; std::vectorint64_t biasHIShape {4 * hidden_size}; std::vectorint64_t biasHHShape {4 * hidden_size}; std::vectorint64_t outShape {time_step, batch_size, 2 * hidden_size}; std::vectorint64_t outHShape {2, batch_size, hidden_size}; std::vectorint64_t outCShape {2, batch_size, hidden_size}; void* selfDeviceAddr nullptr; void* weightHIDeviceAddr nullptr; void* weightHHDeviceAddr nullptr; void* weightHIReverseDeviceAddr nullptr; void* weightHHReverseDeviceAddr nullptr; void* initHDeviceAddr nullptr; void* initCDeviceAddr nullptr; void* biasHIDeviceAddr nullptr; void* biasHHDeviceAddr nullptr; void* biasHIReverseDeviceAddr nullptr; void* biasHHReverseDeviceAddr nullptr; void* outDeviceAddr nullptr; void* outHDeviceAddr nullptr; void* outCDeviceAddr nullptr; aclTensor* self nullptr; aclTensor* weightHI nullptr; aclTensor* weightHH nullptr; aclTensor* weightHIReverse nullptr; aclTensor* weightHHReverse nullptr; aclTensor* biasHI nullptr; aclTensor* biasHH nullptr; aclTensor* biasHIReverse nullptr; aclTensor* biasHHReverse nullptr; aclTensor* initH nullptr; aclTensor* initC nullptr; aclTensor* out nullptr; aclTensor* outH nullptr; aclTensor* outC nullptr; std::vectoruint16_t selfHostData(GetShapeSize(selfShape)); std::vectoruint16_t weightHIHostData(GetShapeSize(weightHIShape)); std::vectoruint16_t weightHHHostData(GetShapeSize(weightHHShape)); std::vectoruint16_t biasHIHostData(GetShapeSize(biasHIShape)); std::vectoruint16_t biasHHHostData(GetShapeSize(biasHHShape)); std::vectoruint16_t initHHostData(GetShapeSize(initHShape)); std::vectoruint16_t initCHostData(GetShapeSize(initCShape)); std::vectoruint16_t outHostData(GetShapeSize(outShape)); std::vectoruint16_t outHHostData(GetShapeSize(outHShape)); std::vectoruint16_t outCHostData(GetShapeSize(outCShape)); ret CreateAclTensor(selfHostData, selfShape, selfDeviceAddr, aclDataType::ACL_FLOAT16, self); CHECK_RET(ret ACL_SUCCESS, return ret); ret CreateAclTensor(weightHIHostData, weightHIShape, weightHIDeviceAddr, aclDataType::ACL_FLOAT16, weightHI); CHECK_RET(ret ACL_SUCCESS, return ret); ret CreateAclTensor(weightHHHostData, weightHHShape, weightHHDeviceAddr, aclDataType::ACL_FLOAT16, weightHH); CHECK_RET(ret ACL_SUCCESS, return ret); ret CreateAclTensor(initHHostData, initHShape, initHDeviceAddr, aclDataType::ACL_FLOAT16, initH); CHECK_RET(ret ACL_SUCCESS, return ret); ret CreateAclTensor(initCHostData, initCShape, initCDeviceAddr, aclDataType::ACL_FLOAT16, initC); CHECK_RET(ret ACL_SUCCESS, return ret); ret CreateAclTensor(biasHIHostData, biasHIShape, biasHIDeviceAddr, aclDataType::ACL_FLOAT16, biasHI); CHECK_RET(ret ACL_SUCCESS, return ret); ret CreateAclTensor(biasHHHostData, biasHHShape, biasHHDeviceAddr, aclDataType::ACL_FLOAT16, biasHH); CHECK_RET(ret ACL_SUCCESS, return ret); ret CreateAclTensor(weightHIHostData, weightHIShape, weightHIReverseDeviceAddr, aclDataType::ACL_FLOAT16, weightHIReverse); CHECK_RET(ret ACL_SUCCESS, return ret); ret CreateAclTensor(weightHHHostData, weightHHShape, weightHHReverseDeviceAddr, aclDataType::ACL_FLOAT16, weightHHReverse); CHECK_RET(ret ACL_SUCCESS, return ret); ret CreateAclTensor(biasHIHostData, biasHIShape, biasHIReverseDeviceAddr, aclDataType::ACL_FLOAT16, biasHIReverse); CHECK_RET(ret ACL_SUCCESS, return ret); ret CreateAclTensor(biasHHHostData, biasHHShape, biasHHReverseDeviceAddr, aclDataType::ACL_FLOAT16, biasHHReverse); CHECK_RET(ret ACL_SUCCESS, return ret); ret CreateAclTensor(outHostData, outShape, outDeviceAddr, aclDataType::ACL_FLOAT16, out); CHECK_RET(ret ACL_SUCCESS, return ret); ret CreateAclTensor(outHHostData, outHShape, outHDeviceAddr, aclDataType::ACL_FLOAT16, outH); CHECK_RET(ret ACL_SUCCESS, return ret); ret CreateAclTensor(outCHostData, outCShape, outCDeviceAddr, aclDataType::ACL_FLOAT16, outC); CHECK_RET(ret ACL_SUCCESS, return ret); uint64_t workspaceSize 0; aclOpExecutor* executor nullptr; ret aclnnBidirectionLSTMGetWorkspaceSize(self, initH, initC, weightHI, weightHH, biasHI, biasHH, weightHIReverse, weightHHReverse, biasHIReverse, biasHHReverse, numLayers, isbias, batchFirst, bidirection, out, outH, outC, workspaceSize, executor); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnBidirectionLSTMGetWorkspaceSize failed. ERROR: %d\n, ret); return ret); void* workspaceAddr nullptr; if (workspaceSize 0) { ret aclrtMalloc(workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(allocate workspace failed. ERROR: %d\n, ret); return ret); } ret aclnnBidirectionLSTM(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnBidirectionLSTM failed. ERROR: %d\n, ret); return ret); ret aclrtSynchronizeStream(stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtSynchronizeStream failed. ERROR: %d\n, ret); return ret); aclDestroyTensor(self); aclDestroyTensor(weightHI); aclDestroyTensor(weightHH); aclDestroyTensor(initH); aclDestroyTensor(initC); aclDestroyTensor(biasHI); aclDestroyTensor(biasHH); aclDestroyTensor(weightHIReverse); aclDestroyTensor(weightHHReverse); aclDestroyTensor(biasHIReverse); aclDestroyTensor(biasHHReverse); aclDestroyTensor(out); aclDestroyTensor(outH); aclDestroyTensor(outC); aclrtFree(selfDeviceAddr); aclrtFree(weightHIDeviceAddr); aclrtFree(weightHHDeviceAddr); aclrtFree(initHDeviceAddr); aclrtFree(initCDeviceAddr); aclrtFree(biasHIDeviceAddr); aclrtFree(biasHHDeviceAddr); aclrtFree(weightHIReverseDeviceAddr); aclrtFree(weightHHReverseDeviceAddr); aclrtFree(biasHIReverseDeviceAddr); aclrtFree(biasHHReverseDeviceAddr); aclrtFree(outDeviceAddr); aclrtFree(outHDeviceAddr); aclrtFree(outCDeviceAddr); if (workspaceSize 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }延伸阅读算子文档aclnnBidirectionLSTM.md与本文信息保持一致适合交叉核对参数约束。反向/双向前向 kernel 实现op_kernel 目录其中 lstm_bidir_fp16.h 给出了 FP16 双向前向的底层组织。tiling 与 op 注册入口bidirection_lstm.h可帮助理解 shape 校验与 workspace 估算的来源。可编译的运行样例test_aclnn_bidirection_lstm.cpp。【免费下载链接】ops-nn本项目是CANN提供的神经网络类计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-nn创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表