第一次给 CANN 社区做贡献?从 community 仓库入手 前言开源社区是个奇妙的地方。你用着别人免费分享的代码享受着别人免费提供的文档突然有一天你想我是不是也能为这个社区做点贡献但紧接着你就被一堆问题拦住了怎么提 Issue怎么提 PR代码规范是什么社区治理模式是怎样的第一次贡献会不会被人嘲笑昇腾 CANN 社区的 community 仓库就是为你准备的新手村指南。它详细记录了 CANN 社区的治理模式、贡献流程、代码规范、踩坑经验等让你可以顺畅地完成第一次贡献。1. CANN 社区治理模式谁在管理这个社区要贡献开源社区首先要了解这个社区的治理模式。CANN 社区采用的是贡献者驱动核心团队审核的治理模式。具体来说CANN 社区的决策权分为以下几个层级1.1 贡献者Contributor只要你给 CANN 社区的任何仓库提过 PRPull Request并且被合并你就成为了贡献者。贡献者的权利包括可以在任意仓库提 Issue 和 PR可以参与技术讨论在 Issue 和 PR 的评论区可以获得贡献者证书电子版可在简历中展示贡献者的义务包括遵守社区行为准则Code of Conduct提 PR 之前先提 Issue 讨论避免做无用功及时回复维护者的 Review 意见1.2 核心贡献者Core Contributor如果你持续给 CANN 社区做贡献如过去 6 个月内合并了至少 5 个 PR并且你的贡献被核心团队认可你可以申请成为核心贡献者。核心贡献者的权利包括以上所有贡献者的权利可以 Review 其他人的 PR但还不能合并 PR可以参与社区的技术决策投票如 API 设计、Roadmap 规划等核心贡献者的义务包括以上所有贡献者的义务及时 Review 其他人的 PR通常在 3 个工作日内完成参与技术决策投票如果不投票视为弃权1.3 维护者Maintainer如果你在某个仓库的持续贡献被核心团队认可并且你愿意承担维护责任你可以被提名成为维护者。维护者的权利包括以上所有核心贡献者的权利可以合并 PR拥有 Write 权限可以管理 Issue关闭、打标签、指派负责人等可以参与社区的治理决策投票如 Release 计划、重大技术方向等维护者的义务包括以上所有核心贡献者的义务及时响应 Issue 和 PR通常在 2 个工作日内保证代码质量不合并低质量的 PR参与社区的治理决策投票1.4 核心团队Core Team核心团队是 CANN 社区的最终决策机构由华为昇腾部门的资深工程师组成。核心团队的权利包括以上所有维护者的权利可以管理仓库创建、归档、修改权限等可以修改社区治理规则可以任命/罢免维护者核心团队的义务包括以上所有维护者的义务保证社区的健康发展技术方向、生态建设等及时响应重大技术问题如安全漏洞、许可证问题等2. 如何提 Issue让你的声音被听到在 CANN 社区Issue 是技术讨论的起点。无论你是想报告 Bug、请求新功能、提问使用方法还是想讨论技术方向都应该先提 Issue。2.1 Issue 的类型CANN 社区的 Issue 分为以下几种类型Bug ReportBug 报告你发现了一个可复现的 Bug想让维护者修复它Feature Request功能请求你想要一个新功能但不知道维护者愿不愿意实现Question使用提问你不知道怎么用某个功能想请教学社区Documentation Improvement文档改进你发现文档有错误/不完善想帮它改进Technical Discussion技术讨论你想讨论某个技术方向看看社区的意见2.2 如何提一个高质量的 Issue提 Issue 很容易但提一个高质量的 Issue 不容易。以下是提 Issue 的最佳实践1. 先搜索再提问在提 Issue 之前先用搜索功能看看有没有人提过类似的问题。如果有直接在那个 Issue 下面评论不要重复提。2. 选对仓库CANN 社区有很多仓库如 ops-math、ops-nn、ATB 等每个仓库负责不同的功能模块。提 Issue 之前先确认你的问题属于哪个仓库。如果不确定可以提在community仓库维护者会帮你转移。3. 用清晰的标题标题要简洁明了让人一眼就能看出你的问题是什么。例如❌ 不好一个 Bug✅ 好[Bug] ops-math: matmul_fp16 在 M1024, N1024, K512 时结果错误4. 提供完整的复现步骤如果是 Bug Report一定要提供完整的复现步骤包括环境信息CANN 版本、NPU 型号、操作系统等最小可复现代码Minimal Reproducible Example期望行为 vs 实际行为错误日志如果有以下是一个高质量的 Bug Report 模板## Bug 描述 ops-math 的 matmul_fp16 算子在计算形状为 (1024, 512) x (512, 1024) 的矩阵乘法时结果跟 NumPy 的参考实现不一致最大相对误差达到 5%。 ## 环境信息 - CANN 版本6.0.RC1 - NPU 型号昇腾 910 - 操作系统Ubuntu 20.04 - Python 版本3.8 ## 复现步骤 运行以下代码 python import numpy as np import asnumpy as anp np.random.seed(42) A_np np.random.randn(1024, 512).astype(np.float16) B_np np.random.randn(512, 1024).astype(np.float16) A_npu anp.array(A_np).to_npu() B_npu anp.array(B_np).to_npu() C_np np.matmul(A_np, B_np) C_npu anp.matmul(A_npu, B_npu).to_cpu() rel_error np.abs(C_np - C_npu) / (np.abs(C_np) 1e-8) print(f最大相对误差: {rel_error.max():.6f})期望行为最大相对误差应该 1e-3。实际行为最大相对误差 0.055%。错误日志如果有报错贴在这里**这段代码背后的 WHY** 提供最小可复现代码的目的是**让维护者能够用最少的精力复现你的问题**。如果维护者无法复现你的问题他们就无法修复它。所以你提供的信息越详细你的 Issue 被修复的概率就越高。 ### 2.3 Issue 的生命周期 一个 Issue 从创建到关闭通常会经历以下几个状态 1. **Open打开**你刚创建了 Issue等待维护者响应 2. **Triaged已分类**维护者已经看到了 Issue给它打上了标签如 bug、feature request、question 等 3. **In Progress进行中**维护者正在处理这个 Issue或者有人认领了这个 Issue 4. **Resolved已解决**维护者已经修复了这个 Bug或者实现了这个新功能并且合并了对应的 PR 5. **Closed已关闭**Issue 已经解决维护者关闭了它 ## 3. 如何提 PR让你的代码进入官方仓库 PRPull Request是向 CANN 社区贡献代码的方式。无论你是修复 Bug、实现新功能、改进文档都需要提 PR。 ### 3.1 PR 的生命周期 一个 PR 从创建到合并通常会经历以下几个状态 1. **Draft草稿**你还在写代码不想让别人 Review。这时候可以提 Draft PR 2. **Open打开**你写完了代码想让别人 Review。这时候可以点击 Ready for Review 3. **In Review审查中**维护者正在 Review 你的代码可能会提出修改意见 4. **Changes Requested需要修改**维护者提出了修改意见你需要按照意见修改代码 5. **Approved已批准**维护者认为你的代码质量合格批准了你的 PR 6. **Merged已合并**维护者把你的代码合并到了主分支你的贡献正式生效了 ### 3.2 如何提一个高质量的 PR 提 PR 很容易但提一个高质量的 PR 不容易。以下是提 PR 的最佳实践 **1. 先提 Issue 讨论再提 PR** 除非是微小的改动如修复文档 Typo否则一定要先提 Issue 讨论。这样可以确保 1. 你要做的事跟社区的技术方向一致避免做无用功 2. 维护者认可你的方案避免写了几千行代码后被要求重写 **2. 一个 PR 只做一件事** 不要在一个 PR 里同时修复 Bug、实现新功能、重构代码。这样会让 Review 变得困难也会增加合并冲突的概率。 **3. 写好 Commit Message** Commit Message 要清晰明了让人一眼就能看出你做了什么改动。推荐的格式是():其中type改动类型如fix修复 Bug、feat新功能、docs文档改动、refactor重构等scope改动范围如ops-math、ATB、docs等subject简短描述不超过 50 个字符body详细描述可以有多行说明为什么要做这个改动、怎么做的、有什么影响等footer关联 Issue如Closes #123、以下是一个高质量的 Commit Message 示例fix(ops-math): 修复 matmul_fp16 在 K%64!0 时的精度问题 问题原因 matmul_fp16 算子在 K 维度不是 64 的倍数时会触发 Fallback 到 CPU 计算的逻辑导致性能下降 10 倍以上。 解决方案 修改 Tiling 策略让 K 维度的分块大小可以不是 64 的倍数。 具体改动 1. 修改 tiling_strategy.cpp 中的 ComputeTileSizeK() 函数 2. 添加单元测试 test_matmul_fp16_tiling.py覆盖 K%64!0 的场景 性能影响 在 K1024 的场景下延迟从 18 ms 降低到 12 ms提升 33%。 Closes #4564. 添加单元测试没有单元测试的 PR 通常不会被合并。你需要为你新增/修改的代码添加单元测试确保功能正确性跟参考实现对比边界条件正确性如输入形状为 0、输入数据类型不支持等性能没有回退跟之前的版本对比以下是一个高质量的单元测试示例importnumpyasnpimportasnumpyasanpimportpytestdeftest_matmul_fp16_correctness():测试 matmul_fp16 的计算正确性np.random.seed(42)A_npnp.random.randn(1024,512).astype(np.float16)B_npnp.random.randn(512,1024).astype(np.float16)A_npuanp.array(A_np).to_npu()B_npuanp.array(B_np).to_npu()C_npnp.matmul(A_np,B_np)C_npuanp.matmul(A_npu,B_npu).to_cpu()rel_errornp.abs(C_np-C_npu)/(np.abs(C_np)1e-8)assertrel_error.max()1e-3,f最大相对误差超标:{rel_error.max():.6f}deftest_matmul_fp16_tiling_k_not_multiple_of_64():测试 K 维度不是 64 的倍数时matmul_fp16 仍然正确np.random.seed(42)A_npnp.random.randn(1024,520).astype(np.float16)# K520不是 64 的倍数B_npnp.random.randn(520,1024).astype(np.float16)A_npuanp.array(A_np).to_npu()B_npuanp.array(B_np).to_npu()C_npnp.matmul(A_np,B_np)C_npuanp.matmul(A_npu,B_npu).to_cpu()rel_errornp.abs(C_np-C_npu)/(np.abs(C_np)1e-8)assertrel_error.max()1e-3,f最大相对误差超标:{rel_error.max():.6f})deftest_matmul_fp16_performance():测试 matmul_fp16 的性能没有回退np.random.seed(42)A_npnp.random.randn(1024,1024).astype(np.float16)B_npnp.random.randn(1024,1024).astype(np.float16)A_npuanp.array(A_np).to_npu()B_npuanp.array(B_np).to_npu()# 预热_anp.matmul(A_npu,B_npu)anp.cuda.synchronize()# 计时starttime.time()_anp.matmul(A_npu,B_npu)anp.cuda.synchronize()endtime.time()latencyend-startassertlatency0.015,f延迟回退:{latency:.3f}s (阈值: 0.015 s)这段代码背后的 WHY写单元测试的目的是确保你新增/修改的代码不会引入 Bug也不会导致性能回退。CANN 社区非常看重代码质量没有单元测试的 PR 通常不会被合并。3.3 Code Review 的常见意见当你提了 PR 之后维护者会对你的代码进行 Review。以下是 Code Review 中常见的意见1. 代码风格不符合规范CANN 社区有详细的代码规范在community仓库的CODE_STYLE.md文件中。如果你的代码风格不符合规范维护者会要求你修改。常见的代码风格问题包括缩进不正确应该用 4 个空格而不是 Tab变量命名不规范应该用snake_case而不是camelCase注释不足每个函数都应该有 Docstring行长度超限每行不应该超过 80 个字符2. 缺少单元测试如前所述没有单元测试的 PR 通常不会被合并。3. 性能有回退如果你的 PR 导致了性能回退如某个算子的延迟增加了 10%维护者会要求你解释原因或者要求你优化性能。4. 兼容性问题如果你的 PR 破坏了向后兼容性如修改了某个 API 的函数签名维护者会要求你提供迁移指南或者要求你用 Deprecation 的方式渐进式修改。4. 代码规范让你的代码融入社区CANN 社区有详细的代码规范涵盖代码风格、命名约定、注释规范、测试规范等。4.1 C 代码规范CANN 社区的 C 代码规范基于 Google C Style Guide但有一些自定义的规则。以下是几个关键点1. 缩进和空格// ❌ 不好用了 Tab 缩进voidfoo(){intx1;// Tab}// ✅ 好用了 2 个空格缩进voidfoo(){intx1;// 2 个空格}2. 变量命名// ❌ 不好用了 camelCaseintmyVariable1;// ✅ 好用了 snake_caseintmy_variable1;3. 函数命名// ❌ 不好首字母小写voidmyFunction(){// ...}// ✅ 好首字母大写voidMyFunction(){// ...}4. 注释规范// ❌ 不好注释太少intAdd(inta,intb){returnab;}// ✅ 好有完整的 Docstring// 计算两个整数的和。//// 参数// a: 第一个加数// b: 第二个加数//// 返回// a 和 b 的和//// 示例// Add(1, 2) 返回 3intAdd(inta,intb){returnab;}4.2 Python 代码规范CANN 社区的 Python 代码规范基于 PEP 8但有一些自定义的规则。以下是几个关键点1. 缩进和空格# ❌ 不好用了 Tab 缩进deffoo():intx1# Tab# ✅ 好用了 4 个空格缩进deffoo():x1# 4 个空格2. 变量命名# ❌ 不好用了 camelCasemyVariable1# ✅ 好用了 snake_casemy_variable13. 函数命名# ❌ 不好用了 camelCasedefmyFunction():pass# ✅ 好用了 snake_casedefmy_function():pass4. 注释规范# ❌ 不好注释太少defadd(a,b):returnab# ✅ 好有完整的 Docstringdefadd(a,b):计算两个数的和。 参数 a: 第一个加数 b: 第二个加数 返回 a 和 b 的和 示例 add(1, 2) 3 returnab5. 典型贡献流程从 Idea 到 Merged PR讲了这么多规则和流程你可能会问到底怎么完成第一次贡献这里给出一个完整的、端到端的贡献流程。5.1 阶段 1找到可以贡献的方向如果你不知道从哪里开始贡献以下几个方向适合新手修复文档 Typo这是最简单的贡献适合第一次贡献的人修复简单的 Bug在 Issue 列表中找标签为good first issue的 Bug改进文档很多仓库的文档都不完善你可以帮它改进添加单元测试很多算子都缺少单元测试你可以帮它补充5.2 阶段 2提 Issue 讨论找到可以贡献的方向后先提 Issue 讨论。这可以避免做无用功。Issue 的内容应该包括你想做什么贡献为什么要做这个贡献解决了什么问题打算怎么做技术方案5.3 阶段 3Fork 仓库并克隆到本地Issue 讨论通过后可以开始写代码了。第一步是 Fork 仓库点击 GitHub/Gitee 页面右上角的 “Fork” 按钮然后克隆到本地# 克隆你 Fork 的仓库gitclone https://atomgit.com/your-username/repo-name.gitcdrepo-name# 添加上游仓库gitremoteaddupstream https://atomgit.com/cann/repo-name.git5.4 阶段 4创建分支并写代码不要直接在main分支上写代码。创建一个新分支# 创建并切换到新分支gitcheckout-bfix-matmul-fp16-accuracy# 写代码...写代码的过程中记得经常提交# 查看修改gitstatusgitdiff# 暂存修改gitaddmodified-files# 提交gitcommit-mfix(ops-math): 修复 matmul_fp16 在 K%64!0 时的精度问题5.5 阶段 5推送分支并提 PR写完了代码推送到你的 Fork 仓库然后提 PR# 推送分支到你的 Fork 仓库gitpush origin fix-matmul-fp16-accuracy推送完成后打开 GitHub/Gitee 页面你会看到一个 “Compare Pull Request” 的按钮。点击它填写 PR 描述然后提交。PR 描述应该包括这个 PR 做了什么简短描述为什么做这个 PR解决了什么问题怎么做的技术方案关联 Issue如Closes #1235.6 阶段 6参与 Code Review 并修改代码提了 PR 之后维护者会对你的代码进行 Review。如果维护者提出了修改意见按照意见修改代码# 修改代码...# 提交修改gitaddmodified-filesgitcommit-maddress review comments# 推送修改gitpush origin fix-matmul-fp16-accuracy5.7 阶段 7PR 被合并成为贡献者当维护者批准了你的 PR 并合并了它恭喜你你正式成为了 CANN 社区的贡献者你可以把你的贡献者证书在community仓库的contributors/目录下加到你的简历里去。6. 踩坑经验全记录最后分享一些在 CANN 社区贡献时常见的坑以及对应的解决方案。6.1 坑 1PR 的 CI/CD 失败现象提了 PR 之后CI/CD持续集成/持续部署失败了导致无法合并 PR。原因CI/CD 会自动运行单元测试、代码风格检查、性能基准测试等。如果任何一个测试失败了CI/CD 就会失败。解决方案在本地运行单元测试确保它们都通过cdrepo-namepython-mpytest tests/在本地运行代码风格检查确保没有风格问题cdrepo-namepython-mflake8.# Python 代码python-mcpplint.# C 代码如果本地测试都通过了但 CI/CD 还是失败可能是 CI/CD 环境的问题。这时候可以联系维护者帮忙排查。6.2 坑 2PR 跟 main 分支有合并冲突现象提了 PR 之后发现跟main分支有合并冲突导致无法合并 PR。原因在你写代码的过程中main分支可能有其他人提交了新的代码跟你的修改冲突了。解决方案拉取上游仓库的最新代码gitfetch upstream合并上游仓库的main分支到你的分支gitmerge upstream/main如果有合并冲突手动解决冲突编辑冲突文件然后git add和git commit推送解决冲突后的代码到你的 Fork 仓库gitpush origin fix-matmul-fp16-accuracycommunity 仓库地址https://atomgit.com/cann/community欢迎访问获取最新代码和文档。如果你在使用过程中遇到问题欢迎在仓库提 Issue社区会及时响应。