news 2026/9/20 13:57:50

CANN ops-nn 中 aclnnSwish 算子接口详解:两段式调用、参数约束与源码级实现原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CANN ops-nn 中 aclnnSwish 算子接口详解:两段式调用、参数约束与源码级实现原理
  • 人工智能
  • 算子库
  • 深度学习
  • CANN
  • Ascend

【免费下载链接】ops-nn

本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。

项目地址:https://gitcode.com/cann/ops-nn
点击查看免费下载

本文以 CANN 神经网络算子库(ops-nn)中 Swish 激活算子的官方接口文档 aclnnSwish.md 为主线,系统讲解 aclnnSwish 两段式接口的完整用法、参数语义、返回码约束,并结合仓库内 aclnn_swish.cpp、swish_def.cpp、swish_tiling.cpp 与 swish.h 等源码,深入剖析算子从 Host 侧校验、构图到 Device 侧 Kernel 执行的完整链路。读完本文,你将掌握 aclnnSwish 的调用姿势、参数约束、常见报错排查方法,以及 Swish 算子在 NPU 上的实现细节。

功能说明与数学定义

aclnnSwish 用于对输入 Tensor 逐元素进行 Swish 激活函数运算并输出结果 Tensor。Swish(又称 SiLU)是一种平滑、非单调的激活函数,被广泛用于深度神经网络中,以替代 ReLU 等传统激活函数,有助于缓解梯度消失问题。

其计算公式为:

$$ s(x) = x \cdot \sigma(\beta x) $$

其中 $\sigma(x)$ 为 sigmoid 函数:

$$ \sigma(x) = \frac{1}{1 + e^{-x}} $$

式中的 $\beta$ 是用于控制 Swish 函数形状与斜率(曲线陡峭程度)的可调标量参数。当 $\beta=1$ 时,Swish 退化为标准形式 $x \cdot \sigma(x)$,即与 SiLU 等价的常见形态;当 $\beta$ 取不同值时,函数曲线会相应拉伸或压缩。

从仓库的算子定义来看,swish_def.cpp 中Swish的 OpDef 将scale(即公式中的 $\beta$)声明为OPTIONAL类型的 Float 属性,默认值为1.0,与文档"betaOptional 为空指针时以 1.0 计算"的约定一一对应。

产品支持情况

根据接口文档,aclnnSwish 的支持情况如下:

产品是否支持
Atlas A2 训练系列产品 / Atlas A2 推理系列产品

算子定义源码 swish_def.cpp 中通过this->AICore().AddConfig("ascend910b", aicoreConfig)为该算子注册了 ascend910b 的 AI Core 配置,与文档所列 Atlas A2 系列产品(Ascend 910B 平台)保持一致。此外,swish_tiling.cpp 在 tiling 阶段会对 SocVersion 做校验:仅ASCEND910BASCEND310B两个版本支持 BF16 输入,其他平台传入 BF16 数据会直接返回失败,这也是接口文档中"Atlas 推理系列产品、Atlas 训练系列产品:数据类型支持 FLOAT16、FLOAT"这一限制的底层来源。

两段式接口与函数原型

aclnnSwish 遵循 CANN 算子库的两段式接口设计规范:必须先调用第一段接口aclnnSwishGetWorkspaceSize获取计算所需 workspace 大小以及包含了算子计算流程的执行器(executor),再调用第二段接口aclnnSwish执行计算。

第一段接口原型:

aclnnStatus aclnnSwishGetWorkspaceSize( const aclTensor* self, const aclScalar* betaOptional, aclTensor* out, uint64_t* workspaceSize, aclOpExecutor** executor)

第二段接口原型:

aclnnStatus aclnnSwish( void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, aclrtStream stream)

两个接口的声明位于 aclnn_swish.h,均以extern "C"导出,头文件通过#include "aclnnop/aclnn_swish.h"引入。接口实现位于 aclnn_swish.cpp。

aclnnSwishGetWorkspaceSize 参数详解

参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续 Tensor
self(aclTensor*)输入表示用于计算激活函数的张量,公式中的 x支持空 Tensor;self 的 shape 和数据类型与 out 一致BFLOAT16、FLOAT16、FLOATND0-8
betaOptional(aclScalar*)输入表示可调节参数,用于控制 Swish 函数形状和斜率的标量,公式中的 β数据类型需为可转换为 FLOAT 的数据类型(参见互转换关系);当 betaOptional 为空指针时,接口以 1.0 进行计算----
out(aclTensor*)输出表示 Swish 函数的输出,公式中的 s(x)支持空 Tensor;out 的 shape 和数据类型与 self 一致BFLOAT16、FLOAT16、FLOATND0-8
workspaceSize(uint64_t*)输出返回需要在 Device 侧申请的 workspace 大小-----
executor(aclOpExecutor**)输出返回 op 执行器,包含了算子计算流程-----

补充说明:

  • 维度上限 0-8:文档规定 self 与 out 的维度范围是 0-8。从源码看,aclnn_swish.cpp 中CheckDim通过OP_CHECK_MAX_DIM(self, MAX_SUPPORT_DIMS_NUMS, ...)对输入输出做最大维度校验,超出MAX_SUPPORT_DIMS_NUMS会返回ACLNN_ERR_PARAM_INVALID。单元测试 test_aclnn_swish.cpp 用 9 维 shape 验证了这一行为。值得注意的是,第二段接口执行时对超过最大支持维度的长 Tensor 会通过reshapeLongTensor借助l0op::Reshape处理,因此接口能力是"参数校验限制 8 维以内,但底层可兼容长 shape 场景"。
  • betaOptional 的可转换性:源码中 CheckDtypeValidBetaToFloat 调用CanCast(betaOptional->GetDataType(), DataType::DT_FLOAT)校验 beta 数据类型能否无损转换为 FLOAT,若不能则记录OP_LOGE并返回ACLNN_ERR_PARAM_INVALID。从单元测试可见,bool、double、uint8_t、int8_t、FLOAT16 等类型的 beta 均被用于测试,说明凡能转换为 FLOAT 的标量类型均可用。
  • 支持空 Tensor:当 self 或 out 为空 Tensor 时,aclnn_swish.cpp 会直接置workspaceSize = 0并返回ACLNN_SUCCESS,无需真正分配 workspace。对应测试用例为 test_swish_empty_input。
  • 支持非连续 Tensor:第一段接口内部会先通过l0op::Contiguous将非连续输入规整为连续内存再参与构图,所以调用方无需手动搬运数据,传入非连续 Tensor 即可正确计算(测试用例 test_swish_uncontiguous 覆盖了带 strides 的非连续输入)。

返回值与异常校验

aclnnStatus返回状态码,具体参见 aclnn 返回码。第一段接口会完成入参校验,出现以下场景时报错:

返回码错误码描述
ACLNN_ERR_PARAM_NULLPTR161001传入的 self 或 out 是空指针
ACLNN_ERR_PARAM_INVALID161002self、betaOptional 或 out 的数据类型不在支持的范围内
ACLNN_ERR_PARAM_INVALID161002self 和 out 的数据类型不一致
ACLNN_ERR_PARAM_INVALID161002self 和 out 的 shape 不一致

上述校验在源码中的落点非常清晰:CheckParams 依次执行:

  1. CheckNotNull2Tensor(self, out)—— 任一为空指针则返回ACLNN_ERR_PARAM_NULLPTR(对应 161001),测试用例见 test_swish_nullptr_input 与 test_swish_nullptr_out;
  2. GetDtypeSupportListV1(ASCEND910B_DTYPE_SUPPORT_LIST, ASCEND910_DTYPE_SUPPORT_LIST)按平台获取支持的数据类型列表,其中 910 平台支持DT_FLOATDT_FLOAT16,910B 平台额外支持DT_BF16(见 aclnn_swish.cpp),随后CheckDtypeValidActivation校验 self/out 类型;
  3. CheckDtypeValidBetaToFloat校验 beta 可转换为 FLOAT;
  4. CheckDim校验维度不超过上限;
  5. CheckSameShapeNotlimit1In1Out校验 self 与 out 的 shape 完全一致。

单元测试 test_swish_inconsistent_shape 与 test_swish_inconsistent_dtype 分别用 shape 不一致(如 {2,16,32,16} 对 {2,16,32,18})与 dtype 不一致(FLOAT 对 FLOAT16)验证了ACLNN_ERR_PARAM_INVALID的返回。

aclnnSwish 参数详解

参数名输入/输出描述
workspace输入在 Device 侧申请的 workspace 内存地址
workspaceSize输入在 Device 侧申请的 workspace 大小,由第一段接口 aclnnSwishGetWorkspaceSize 获取
executor输入op 执行器,包含了算子计算流程
stream输入指定执行任务的 Stream

返回值同样为aclnnStatus,状态码含义参见 aclnn 返回码。第二段接口的实现非常轻量:aclnn_swish.cpp 中aclnnSwish仅做L2_DFX_PHASE_2打点,然后调用CommonOpExecutorRun将第一阶段构造好的执行器提交到指定 stream 上运行,所有构图与 workspace 计算工作均在第一段接口内完成。

约束说明

  • 确定性计算:aclnnSwish 默认采用确定性实现,即相同的输入与配置在多次运行中产生完全一致的结果。确定性计算的通用机制可参考 确定性计算。

调用示例

以下示例代码来自 aclnnSwish.md,仓库中的可运行版本见 test_aclnn_swish.cpp,两者逻辑一致。具体编译和执行过程请参考编译与运行样例。

#include <iostream> #include <vector> #include "acl/acl.h" #include "aclnnop/aclnn_swish.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::vector<int64_t>& shape) { int64_t shape_size = 1; for (auto i : shape) { shape_size *= i; } return shape_size; } 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; } template <typename T> int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, aclDataType dataType, aclTensor** tensor) { auto size = GetShapeSize(shape) * sizeof(T); // 调用aclrtMalloc申请device侧内存 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); // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 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); // 计算连续tensor的strides std::vector<int64_t> strides(shape.size(), 1); for (int64_t i = shape.size() - 2; i >= 0; i--) { strides[i] = shape[i + 1] * strides[i + 1]; } // 调用aclCreateTensor接口创建aclTensor *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr); return 0; } int main() { // 1. (固定写法)device/stream初始化, 参考acl API手册 // 根据自己的实际device填写deviceId int32_t deviceId = 0; aclrtStream stream; auto ret = Init(deviceId, &stream); CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); // 2. 构造输入与输出,需要根据API的接口自定义构造 std::vector<int64_t> selfShape = {4, 2}; std::vector<int64_t> outShape = {4, 2}; void* selfDeviceAddr = nullptr; void* outDeviceAddr = nullptr; aclTensor* self = nullptr; aclScalar* betaOptional = nullptr; aclTensor* out = nullptr; std::vector<float> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7}; std::vector<float> outHostData = {0, 0, 0, 0, 0, 0, 0, 0}; float betaValue = 1.1f; // 创建self aclTensor ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self); CHECK_RET(ret == ACL_SUCCESS, return ret); // 创建betaOptional aclScalar betaOptional = aclCreateScalar(&betaValue, aclDataType::ACL_FLOAT); CHECK_RET(betaOptional != nullptr, return ret); // 创建out aclTensor ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out); CHECK_RET(ret == ACL_SUCCESS, return ret); // 3. 调用CANN算子库API,需要修改为具体的API uint64_t workspaceSize = 0; aclOpExecutor* executor; // 调用aclnnSwish第一段接口 ret = aclnnSwishGetWorkspaceSize(self, betaOptional, out, &workspaceSize, &executor); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSwishGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); // 根据第一段接口计算出的workspaceSize申请device内存 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;); } // 调用aclnnSwish第二段接口 ret = aclnnSwish(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSwish failed. ERROR: %d\n", ret); return ret); // 4. (固定写法)同步等待任务执行结束 ret = aclrtSynchronizeStream(stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 auto size = GetShapeSize(outShape); std::vector<float> resultData(size, 0); ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, size * sizeof(float), ACL_MEMCPY_DEVICE_TO_HOST); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); for (int64_t i = 0; i < size; i++) { LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]); } // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改 aclDestroyTensor(self); aclDestroyScalar(betaOptional); aclDestroyTensor(out); // 7. 释放device资源,需要根据具体API的接口定义修改 aclrtFree(selfDeviceAddr); aclrtFree(outDeviceAddr); if (workspaceSize > 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }

示例的执行流程可分为七个步骤:初始化 device/stream → 构造 self、betaOptional、out 三个对象 → 依次调用两段式接口(含 workspace 申请)→ 同步等待 → 结果回拷并打印 → 释放 Tensor/Scalar → 释放 Device 资源。其中 workspace 的申请遵循"仅当workspaceSize > 0时才aclrtMalloc"的惯例,避免无谓的内存分配。

源码级实现原理

Host 侧构图流程(aclnn_swish.cpp)

第一段接口aclnnSwishGetWorkspaceSize在完成参数校验后,会构造一条由底层 Level 0 算子组成的计算图(aclnn_swish.cpp):

  1. 空 Tensor 短路处理:self 或 out 为空时直接返回ACLNN_SUCCESS,workspace 置 0;
  2. l0op::Contiguous(self, ...):将非连续输入规整为连续 Tensor;
  3. 读取 beta:scale = betaOptional != nullptr ? betaOptional->ToFloat() : 1.0f,与文档"空指针时按 1.0 计算"的约定一致;
  4. l0op::Swish(reshapeSelf, scale, ...):携带 scale 标量调用底层 Swish 算子;
  5. 长 shape 场景通过reshapeLongTensor(借助l0op::Reshape)恢复原始维度;
  6. l0op::ViewCopy(reshapeSwishOut, out, ...):将计算结果拷贝到用户指定的 out Tensor;
  7. *workspaceSize = uniqueExecutor->GetWorkspaceSize():汇总全图所需 workspace 并返回执行器。

算子原型与 Infershape(swish_def.cpp / swish_infershape.cpp)

  • swish_def.cpp 声明了算子输入x(tensor,支持 DT_FLOAT16/DT_FLOAT/DT_BF16,ND 格式)、输出y(tensor,约束同 x)与可选 Float 属性scale(默认 1.0),并在 AICore 配置中开启动态 Shape、动态 Rank 支持与 PrecisionReduce 标志;
  • swish_infershape.cpp 的InferShapeSwish将输出 shape 直接赋值为输入 shape(*y_shape = *x1_shape),印证了"out 与 self 的 shape 一致"的接口约束。

Tiling 策略(swish_tiling.cpp)

swish_tiling.cpp 负责在编译期决定核数、分块与 workspace:

  • 依据 UB 容量、Block 大小与双缓冲(BUFFER_NUM = 2)计算每个 tile 可承载的数据量,FLOAT 类型每个 UB 单元可容纳 2 个元素,其他类型为 4 个;
  • 根据输入长度决定使用 1 个核还是多核并行,多核时按"大核 + 小核"模式均衡负载(bigCoreDataNum/smallCoreDataNum),并将每个核的工作量进一步切分为多个 tile 与尾部数据;
  • 依据 scale 取值选择不同的 tiling key:scale 为 -1 时走TPL_SCALE_NEG_ONE,为 0 时走TPL_SCALE_ZERO,其余情况走TPL_SCALE_OTHER(swish_tiling.cpp),使 Kernel 侧可以对特殊 scale 做简化计算;
  • workspace 大小来自ascendcPlatform.GetLibApiWorkSpaceSize()

Device 侧 Kernel(swish.cpp / swish.h)

swish.cpp 是 AscendC 核函数入口,通过GET_TILING_DATA_WITH_STRUCT反序列化 tiling 数据,然后驱动 swish.h 中的KernelSwish完成计算。核心计算逻辑在Compute中:

  • FLOAT 路径Muls(乘以 -scale,见 swish.h 中this->scale = -1.0f * scale)→Exp(求 e^(-βx))→Adds(加 1,构成分母 1+e^(-βx))→Div(x 除以分母),即 $x / (1 + e^{-\beta x})$,等价于文档中的 $x \cdot \sigma(\beta x)$;
  • 非 FLOAT 路径(FP16/BF16):先Cast到 FP32 中间缓冲计算(calcBuf1/calcBuf2),计算完成后再Cast回原类型(RoundMode::CAST_ROUND),以提升中间运算精度。

Process采用"循环 tile + 尾部处理"模式:对前tileNum - 1个 tile 执行常规的 CopyIn/Compute/CopyOut 流水(配合双缓冲隐藏访存延迟),最后一个 tile 以tailDataNum处理余量数据。

构建与运行验证

Swish 算子目录的 README.md 提供了完整的编译与运行方式:

编译算子包:

bash build.sh --pkg --soc=ascend910b --experimental --ops=swish

运行 aclnn 调用示例:

bash build.sh --run_example swish eager cust --vendor_name=custom --experimental

其中--experimental表示从实验特性目录构建,--ops=swish只编译 Swish 算子以加速迭代。运行示例对应的样例代码为 test_aclnn_swish.cpp,通过 aclnn 两段式接口完成算子调用与结果校验。

单元测试覆盖

仓库为 aclnnSwish 提供了较完整的 UT 覆盖,位于 tests/ut/op_api/test_aclnn_swish.cpp,可归纳为以下几类:

测试用例验证点
test_swish_dataType_error非法数据类型(INT8/INT32/DOUBLE/BF16 等)返回校验错误
test_swish_format多 format 下的兼容性(ND 之外的 format 不报错,构图层做格式适配)
test_swish_inconsistent_shape / _dtypeself 与 out 的 shape、dtype 不一致时返回ACLNN_ERR_PARAM_INVALID
test_swish_empty_input空 Tensor 正常返回ACLNN_SUCCESS
test_swish_nullptr_input / _out / _beta空指针校验:self/out 为空返回ACLNN_ERR_PARAM_NULLPTR,beta 为空(走默认 scale=1.0)正常执行
test_swish_FP32 / FP16主流精度的数值正确性(相对/绝对误差 1e-4)
test_swish_uncontiguous非连续 Tensor 的正确性
test_swish_shape_larger_8 / *_invalid_dim超过 8 维或 shape 非法时返回ACLNN_ERR_PARAM_INVALID

此外还有 InferShape 与 Tiling 的 Host 侧单测(test_swish_infershape.cpp、test_swish_tiling.cpp),共同保证算子各阶段行为符合接口文档约定。

总结

aclnnSwish 是 CANN ops-nn 中实现 Swish 激活函数的 Level 2 接口算子:数学上以s(x) = x·σ(βx)逐元素计算,接口上遵循"先 GetWorkspaceSize 后执行"的两段式规范,数据上支持 FLOAT16/FLOAT/BFLOAT16 与 ND 格式、0-8 维、空 Tensor 与非连续 Tensor。通过阅读 aclnnSwish.md 并结合 aclnn_swish.cpp 等源码,可以清楚看到参数校验、构图、tiling 与 Kernel 计算各环节如何协同实现接口文档中的每一条约束——这对在 Atlas A2 系列产品上正确、高效地使用 Swish 激活函数,以及排查接口调用问题都具有直接的实践价值。

  • 人工智能
  • 算子库
  • 深度学习
  • CANN
  • Ascend

【免费下载链接】ops-nn

本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。

项目地址:https://gitcode.com/cann/ops-nn
点击查看免费下载

相关推荐

上一篇:DroneBridge for ESP32安全加密机制:AES256-GCM如何保护你的无人机数据
下一篇:embed-js高级技巧:自定义插件开发与性能优化实战

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 13:57:39

数据中台能力平台建设指南:从架构设计到落地避坑

简介&#xff1a;这是一份面向企业数字化转型与数据中台建设议题的完整PPT方案&#xff0c;适合数字化转型负责人、数据架构师、IT规划人员及业务管理人员参考。方案共52页&#xff0c;围绕数据中台的理解、解决方案与实践汇报三大部分展开&#xff0c;清晰梳理了数据资产化、数…

作者头像 李华
网站建设 2026/9/20 13:57:33

OpenClaw 装好 Gateway 在线,模型却调不动?TaoToken 这样改模型通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 13:54:31

GitHub Trending周报:开源项目评估与AI工具链实战

GitHub Trending 这周榜单&#xff0c;我没法用“热闹”两个字简单打发。9月7号到13号这一周&#xff0c;首页趋势面板上有一个特别明显的分层&#xff1a;头部依旧是 Model 层的军备竞赛&#xff0c;但真正踢开榜单下沿、被反复转发到朋友圈的&#xff0c;已经变成了模型评估、…

作者头像 李华
网站建设 2026/9/20 13:52:57

Gauss伪谱法火箭轨迹优化:Matlab实现与调试实战

简介&#xff1a;面向航空航天与计算力学领域的研究者和工程师&#xff0c;这套MATLAB代码基于Gauss伪谱法求解火箭飞行轨迹&#xff0c;将连续最优控制问题离散为有限维非线性规划&#xff0c;适用于上升段轨迹优化、制导算法验证及多阶段飞行方案设计等场景。压缩包内含9个文…

作者头像 李华
网站建设 2026/9/20 13:52:56

ChatTTS-ui 本地语音合成实测:从部署到调通 TTS API 的完整记录

ChatTTS-ui 本地语音合成实测&#xff1a;从部署到调通 TTS API 的完整记录 【免费下载链接】ChatTTS-ui 一个简单的本地网页界面&#xff0c;使用ChatTTS将文字合成为语音&#xff0c;同时支持对外提供API接口。A simple native web interface that uses ChatTTS to synthesiz…

作者头像 李华