首页
/ graphify 增量更新与重聚类实战:--update / --cluster-only 机制与源码原理解析

graphify 增量更新与重聚类实战:--update / --cluster-only 机制与源码原理解析

2026-09-07 23:01:09作者:侯霆垣

本文是 graphify 知识图谱项目面向 AI 编码助手(Droid 等平台)的 Skill 参考文档的技术解读。该文档(源码位于 graphify/skills/droid/references/update.md,其由工具生成的验证副本位于 tools/skillgen/expected/graphify__skills__droid__references__update.md)专门描述两个高频维护命令 --update(增量重抽取)与 --cluster-only(仅重聚类)的完整执行协议。读完本文,你将掌握 graphify 在"新增/修改/删除文件之后如何低成本地保持知识图谱新鲜"的全部关键步骤、中间产物契约、脚本级可复制命令,以及隐藏在命令背后的 Manifest 双哈希、replace-on-re-extract 合并等底层设计原理。

这份参考在什么时机被加载

文档开宗明义:本参考只在用户传入了 --update--cluster-only 时才被读取,首次全量构建从不加载它。 这是 graphify Skill 体系里"按需加载、绝不预先膨胀上下文"的典型设计——主技能文档(例如 graphify/skill-droid.md)描述了从零构建的完整 Steps 1–9 流水线,而本参考是它的两个"后续维护分支"的专用操作手册:

  • --update:针对上次运行之后新增/修改/删除文件的增量场景,只重新抽取变更文件,节省 token 与时间;
  • --cluster-only:跳过抽取,直接对已有图重新做社区聚类并刷新全部产物。

两份文件同属一套 per-platform 参考集(在 graphify/skills/droid/references/ 目录下与 transcribe.mdquery.mdexports.md 等并列),因此文中出现的 Steps 编号(如 Step 3A/3B/3C、Steps 4–8)均指向主技能文档的流水线阶段。

--update:增量重抽取的执行协议

--update 的核心思想是"只对发生变化的文件重做工作"。整个流程由四类状态文件串联:.graphify_incremental.json(探测结果)、.graphify_detect.json(下游步骤共享的语料状态)、.graphify_extract.json(抽取/合并结果)、.graphify_manifest.json(历史基线)。

第一步:用 detect_incremental 探测变更

在确认用户传了 --update 后,先执行下面的探测脚本,它会调用 graphify/detect.py 中的 detect_incremental() 并写出 .graphify_incremental.json

$(cat graphify-out/.graphify_python) -c "
import sys, json
from graphify.detect import detect_incremental, save_manifest
from pathlib import Path

result = detect_incremental(Path('INPUT_PATH'))
new_total = result.get('new_total', 0)
print(json.dumps(result, indent=2, ensure_ascii=False))
Path('graphify-out/.graphify_incremental.json').write_text(json.dumps(result, ensure_ascii=False), encoding=\"utf-8\")
deleted = list(result.get('deleted_files', []))
if new_total == 0 and not deleted:
    print('No files changed since last run. Nothing to update.')
    raise SystemExit(0)
if deleted:
    print(f'{len(deleted)} deleted file(s) to prune.')
if new_total > 0:
    print(f'{new_total} new/changed file(s) to re-extract.')
"

该脚本末尾已经实现了空变更短路:当 new_total == 0 且没有删除文件时,打印提示并以退出码 0 提前结束,避免下游空转。

detect_incremental() 的返回结构(源码位于 graphify/detect.py)值得逐字段理解,后续每一步都要消费它:

字段 含义 驱动哪些后续步骤
files 当前全量语料,按文件类型分组(code/document/paper/image/video…) 写入 .graphify_detect.jsonall_files,供需要全语料上下文的步骤使用
new_files 本次"变更子集",同样按类型分组 驱动 Step 3A(AST)+ Step 3B0(语义缓存命中检查)只处理变更文件
new_total 变更文件总数 短路判断与提示
deleted_files 从磁盘上消失的 manifest 行 后续作为 prune_sources 的唯一来源
excluded_files 仍存活但被排除规则移出扫描的文件 与删除严格区分,绝不当作删除去 prune
incremental 恒为 True,标记这是一次增量运行 状态语义标记

需要澄清其变更判定机制:detect_incremental() 并不是每次都全量计算内容。快路径:mtime 未变且对应 hash 匹配 → 直接判为"未变更"(除一次 stat 外零磁盘 IO);慢路径:mtime 变化后再用 MD5 与对应 hash 字段比对,才决定是否真正重抽。同时它内部对 manifest 中消失的行做了"删除 vs 被排除"的二分(按磁盘上文件是否还存在),这是避免把 .gitignore/.graphifyignore/--exclude 改动误判为删除的关键。更细节地,文档中提到 kind="semantic"graphify extract 默认)对比 semantic_hash,而 --update(AST-only)需要 kind="ast" 对比 ast_hash,以保证"AST 更新过的文件在语义抽取时会被重新排队"。

第二步:回填 .graphify_detect.json

探测完成后,必须把增量状态"翻译"成全量流水线各步骤无条件读取的 .graphify_detect.json,使 Step 3A–6 在增量运行时看到正确的状态:

$(cat graphify-out/.graphify_python) -c "
import json
from pathlib import Path
r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
Path('graphify-out/.graphify_detect.json').write_text(json.dumps({
    'files': r.get('new_files', {}),
    'all_files': r.get('files', {}),
    'total_files': r.get('new_total', 0),
    'total_words': r.get('total_words', 0),
    'skipped_sensitive': r.get('skipped_sensitive', []),
    'needs_graph': True,
}, ensure_ascii=False), encoding=\"utf-8\")
"

这里体现了一个核心语义约定:files 携带的是变更子集(让 Step 3A 的 AST 与 Step 3B0 的缓存检查只碰变更文件);all_files 携带完整语料(供任何需要全语料上下文的步骤使用)。 二者分工不同,缺一不可。

第三步:判断"纯代码变更"以选择流水线分支

在新文件存在的前提下,先判断这次变更是否全部是代码文件。文档提供了扩展名白名单集合,几乎覆盖 graphify AST 支持的主流语言后缀(.py/.ts/.js/.go/.rs/.java/.cpp/.c/.rb/.swift/.kt/.cs/.scala/.php/.cc/.cxx/.hpp/.h/.kts/.lua/.toc,以及 Fortran 全家族 .f/.F/.f90/.F90/.f95/.F95/.f03/.F03/.f08/.F08):

$(cat graphify-out/.graphify_python) -c "
import json
from pathlib import Path

result = json.loads(open('graphify-out/.graphify_incremental.json', encoding='utf-8').read()) if Path('graphify-out/.graphify_incremental.json').exists() else {}
code_exts = {'.py','.ts','.js','.go','.rs','.java','.cpp','.c','.rb','.swift','.kt','.cs','.scala','.php','.cc','.cxx','.hpp','.h','.kts','.lua','.toc','.f','.F','.f90','.F90','.f95','.F95','.f03','.F03','.f08','.F08'}
new_files = result.get('new_files', {})
all_changed = [f for files in new_files.values() for f in files]
code_only = all(Path(f).suffix.lower() in code_exts for f in all_changed)
print('code_only:', code_only)
"

依据 code_only 布尔值,流程分化出两条路径:

路径 A —— code_only 为 True(纯代码变更):完全不需要 LLM。 打印提示 [graphify update] Code-only changes detected - skipping semantic extraction (no LLM needed),只对变更文件执行 Step 3A(确定性 AST 抽取),整体跳过 Step 3B(不派发任何语义子代理),随后直接进入下面的 merge 合并,再照常执行 Steps 4–8。这正是增量更新省 token 的主要来源——改几行代码无需为它们再跑一次大模型语义抽取。

路径 B —— code_only 为 False(变更里混入了文档/论文/图片/视频)。 需要走完整的 Steps 3A–3C 语义流水线,并且有一个前置陷阱必须处理:如果变更里有视频(new_files['video'] 非空),必须先按 graphify/skills/droid/references/transcribe.md(即 Step 2.5)对它们做语音转写,然后重写 .graphify_detect.json,把转写出的文本路径并入 files['document']、删掉 files['video']。文档特别指出:否则原始的 .mp4/.mp3 路径会被当作不可读媒体直接喂给语义子代理(#1392)。

路径 C —— 没有新文件,只有删除。 此时需要先创建一个空抽取文件,让 merge 步骤有能力"剪除"被删文件的遗留节点:

if [ ! -f graphify-out/.graphify_extract.json ]; then
    echo '[graphify update] Only deletions -- creating empty extraction for merge.'
    $(cat graphify-out/.graphify_python) -c "
import json
from pathlib import Path
Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8')
"
fi

第四步:build_merge 合并新旧图谱

无论走哪条路径,最终都要通过 build_merge()(源码位于 graphify/build.py)把"本次新抽取"与磁盘上的 graph.json 合并。文档给出了完整脚本,注释里浓缩了大量血泪教训:

$(cat graphify-out/.graphify_python) -c "
import json
from pathlib import Path
from graphify.build import build_merge
from graphify.detect import save_manifest

# Load new extraction and incremental state
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
deleted = list(incremental.get('deleted_files', []))
# prune_sources is ONLY for genuinely DELETED files. Changed/re-extracted files are
# handled by build_merge's replace-on-re-extract (#1344): every source_file in
# new_chunks is dropped from the base before merge, so old/stale nodes don't survive.
# Do NOT add `changed` here: with root= passed, prune_set relativizes to the same base
# as the freshly merged nodes and would DELETE the re-extracted content (#1178 is moot
# now that replace — not the dedup pass — reconciles changed files).
prune = list(deleted) or None

# Use build_merge() — reads graph.json directly without NetworkX round-trip
# so edge direction (calls, implements, imports) is always preserved (#801).
# Pass root= so prune_sources (absolute paths from detect_incremental) are
# relativized to match the graph's relative source_file values; without it
# nothing is pruned and stale nodes accumulate on every update (#1361).
# directed=IS_DIRECTED: replace IS_DIRECTED with True if --directed was given, else
# False. Without it a --directed --update silently rebuilds undirected and collapses
# reciprocal A<->B edges (#1392).
G = build_merge(
    [new_extraction],
    graph_path='graphify-out/graph.json',
    prune_sources=prune,
    root='INPUT_PATH',
    directed=IS_DIRECTED,
)
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')

# Write merged result back to .graphify_extract.json so Step 4 sees the full graph
merged_out = {
    'nodes': [{'id': n, **d} for n, d in G.nodes(data=True)],
    'edges': [
        # Explicit source/target last so they win over any stale attrs in d.
        {**{k: val for k, val in d.items() if k not in ('_src', '_tgt', 'source', 'target')},
         'source': d.get('_src', u), 'target': d.get('_tgt', v)}
        for u, v, d in G.edges(data=True)
    ],
    # G.graph[\"hyperedges\"] holds hyperedges from both existing graph.json
    # and new_extraction (build_merge combines them). Falling back to
    # new_extraction only would silently drop prior-run hyperedges (#801).
    'hyperedges': list(G.graph.get('hyperedges', [])),
    'input_tokens': new_extraction.get('input_tokens', 0),
    'output_tokens': new_extraction.get('output_tokens', 0),
}
Path('graphify-out/.graphify_extract.json').write_text(json.dumps(merged_out, ensure_ascii=False), encoding=\"utf-8\")
print(f'[graphify update] Merged extraction written ({len(merged_out[\"nodes\"])} nodes, {len(merged_out[\"edges\"])} edges)')

# Save manifest so next --update diffs against today's state, not the
# prior run's baseline (prevents ghost-node reports on subsequent updates).
# root= matches the build_merge call above so the manifest keys stay relative to
# the scan root — portable across clones/machines, so --update keeps matching
# cached files instead of missing every one after a move (#1417).
#
# Only stamp semantic files (docs/papers/images) that ACTUALLY produced output
# THIS run (new_extraction is this run's fresh extraction, read above before the
# merge overwrote the file): a changed doc whose chunk failed must stay unstamped
# so the next --update re-queues it, otherwise it is marked done and its content
# is lost forever (#2015). Mirrors the library extract path
# (cli._stamped_manifest_files + clear_semantic + scan_corpus).
from graphify.cli import _stamped_manifest_files
_manifest_files = _stamped_manifest_files(incremental['files'], new_extraction, Path('INPUT_PATH'))
# Changed semantic files dispatched this run but NOT stamped had their chunk fail
# or be omitted; clear any stale semantic_hash so they are re-queued (#1948).
_sem_types = ('document', 'paper', 'image')
_dispatched = {f for t, fl in incremental.get('new_files', {}).items() if t in _sem_types for f in fl}
_stamped = {f for fl in _manifest_files.values() for f in fl}
_cleared = _dispatched - _stamped
# scan_corpus = the RAW full corpus so in-root files newly excluded since last run
# are dropped rather than masquerading as deletions; untouched rows preserved (#1908).
_scan = {f for fl in incremental['files'].values() for f in fl}
save_manifest(_manifest_files, root='INPUT_PATH', scan_corpus=_scan, clear_semantic=_cleared or None)
print('[graphify update] Manifest saved.')
"

围绕这段脚本,有三组设计要点必须理解到位,否则极容易在生产中埋坑:

1. prune_sources 只装"真删除"文件。 被修改/被重抽的文件由 build_mergereplace-on-re-extract 语义处理——凡出现在 new_chunks 里的 source_file,合并前会先从既有基础图中按层剔掉其旧节点/旧边,再并入新内容,因此陈旧节点不会残存(#1344)。代码注释明确警告:绝不把 changed 加进 prune_set——一旦传了 root=,prune 集会被相对化到与刚合并节点相同的基础路径上,等于把刚重抽出来的内容亲手删掉。

2. root=directed= 两个参数缺一不可。 root= 使 detect_incremental 返回的绝对路径 prune 源被相对化为与图中 source_file 一致的形式,否则"什么都剪不掉",每次更新都会堆积幽灵节点(#1361)。directed= 必须按用户当初构建时是否传了 --directed 显式传入 True/False:若漏传,一次 --directed --update 会静默把有向图重建为无向图,把互为引用的 A↔B 双向边折叠掉(#1392)。对照源码可见,build_mergedirected=None 缺省行为是继承磁盘上既有图的 directed 标志(graphify/build.py),所以脚本中的显式传参属于"不依赖图文件自描述、把决定权握在调用方"的稳妥写法。

3. Manifest 写入是三重语义的叠加。 脚本先从 cli._stamped_manifest_files() 构造"只含本run真正产出过的语义文件"的清单,然后 save_manifest(源码见 graphify/detect.py)一次性落实三个守卫:

  • root= 相对化(#1417):manifest 键以相对扫描根的形式落盘,可跨机器/克隆位置移植,--update 在仓库挪动后仍能命中缓存而非全量失效;
  • 只 stamp 真正产出的语义文件(#2015):某份变更文档若本 run 的分块抽取失败,就必须保持未 stamp 状态,让下一次 --update 重新排队——否则会被当作"已完成"而永久丢失内容;
  • clear_semantic(#1948):本 run 派发过但未 stamp 的语义文件,其旧的 semantic_hash 必须被清空(集合差 _dispatched - _stamped),避免掩蔽抽取遗漏;同时 scan_corpus 必须传原始完整语料incremental['files']),让自上次以来新被排除在根内文件被正确丢弃而不是伪装成删除,且未触碰行原样保留(#1908)。

配合说明 _stamped_manifest_files()(源码位于 graphify/cli.py)的判定细节:节点与超边(hyperedges)都算有效语义产出可触发 stamp(#1920),而"仅产出边的结果"因无法在图里形成实体表示,必须保持未 stamp 以便下次重排(#2927);出现在 partial_source_files 中的文件即便有产出也只是截断片段,同样不 stamp(#933 同机制)。

合并完成后打印节点/边总数,随后 照常运行 Steps 4–8(社区聚类、标注、报告生成等),把合并后的完整图交给后续分析阶段。

第五步:展示图差异(graph diff)

在 Step 4 完成之后,更新文档要求向用户展示这次增量前后的图谱差异。实现依赖 graphify/analyze.pygraph_diff():它对比新旧两个 NetworkX 图的节点集合、边集合(有向图按 (u, v, relation) 成键、无向图按排序后的端点成键),返回 new_nodesremoved_nodesnew_edgesremoved_edges 与一段人类可读的 summary(如 "3 new nodes, 5 new edges, 1 node removed")。执行脚本如下:

$(cat graphify-out/.graphify_python) -c "
import json
from graphify.analyze import graph_diff
from graphify.build import build_from_json
from networkx.readwrite import json_graph
import networkx as nx
from pathlib import Path

# Load old graph (before update) from backup written before merge
old_data = json.loads(Path('graphify-out/.graphify_old.json').read_text(encoding=\"utf-8\")) if Path('graphify-out/.graphify_old.json').exists() else None
new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
G_new = build_from_json(new_extract, directed=IS_DIRECTED)

if old_data:
    G_old = json_graph.node_link_graph(old_data, edges='links')
    diff = graph_diff(G_old, G_new)
    print(diff['summary'])
    if diff['new_nodes']:
        print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5]))
    if diff['new_edges']:
        print('New edges:', len(diff['new_edges']))
"

脚本依赖一个"合并前备份"约定,文档要求严格执行:merge 之前先 cp graphify-out/graph.json graphify-out/.graphify_old.json,展示完 diff 后再 rm -f graphify-out/.graphify_old.json 清理,避免备份残留在输出目录里污染下一次运行。

--cluster-only:仅对既有图重聚类

当用户没有改动任何语料、只想重新做社区发现时(例如调整了聚类分辨率、换了标签后端、或发现上一轮社区划分不理想),使用 --cluster-only。其语义被文档概括为三个字:自包含(self-contained)——跳过 Steps 1–3 的所有抽取工作,只对现存 graph.json 重新聚类并刷新全套产物:

graphify cluster-only .

该命令执行后会自动完成:重新社区聚类 → 重新命名社区 → 依据既有图重新生成 GRAPH_REPORT.mdgraph.jsongraph.html

--update 相关的三点必须严格遵守:

  1. 不要重跑 Steps 5–9。这些步骤会读取中间文件(.graphify_extract.json.graphify_detect.json.graphify_analysis.json),而一次完整构建的 Step 9 清理阶段早已把它们删掉,重跑只会触发 FileNotFoundError(#1392)。
  2. 命令完成后,照常把刷新后的 GRAPH_REPORT.md 摘要呈现给用户。
  3. 它从零开始读取 graph.json 自身携带的 directed 标志(参见 graphify/cli.pybuild_from_json(_raw, directed=_directed)),再进入 cluster() 流程。

从源码(graphify/cli.py)可以看到,graphify cluster-only 比表面看起来更"重"也更"稳":它加载既有图后依次执行 cluster()(默认分辨率 --resolution=1.0)、通过 remap_communities_to_previous() 把新社区 ID 映射回旧社区(按节点重叠度匹配,保证已保存的社区标签不错位,#1027)、计算社区内聚度、检测 god nodes 与跨社区意外连接,再统一落盘。可用参数一并列出:

参数 作用
graphify cluster-only <path> 指定项目路径(缺省为当前目录)
--graph <path> 指向其他位置/项目租户的 graph.json
--resolution <float> Leiden 聚类分辨率,默认 1.0
--exclude-hubs <percentile> 聚类前剔除高度数 hub 节点
--no-label 只生成 "Community N" 占位名,不调用 LLM
--backend <name> / --model <name> 重命名社区的 LLM 后端与模型
--no-viz 跳过可视化产物
--missing-only / --min-community-size 标签补齐策略与最小社区规模

从源码看增量设计的三个底层机制

1. Manifest 双哈希:ast_hashsemantic_hash 各司其职

detect_incremental 的变更判定之所以又快又准,靠的是 graphify/detect.py 中每行 manifest 记录的 {mtime, ast_hash, semantic_hash, seen}。两个 hash 字段对应两条不同频度的抽取链:--update(AST-only)消费 ast_hashgraphify extract(语义抽取)消费 semantic_hashsave_manifest 通过 kind="ast"/"semantic"/"both" 决定 stamp 哪个。此外 save_manifest 还处理了若干防御性边界——mtime 相同文件系统时钟粒度内的"等长改写"会触发一次 MD5 兜底验证(_mtime_may_hide_a_rewrite)、legacy 纯数值 mtime 与 {mtime, hash} 旧格式的向后兼容、以及写盘前用原子写避免崩溃留下半截 manifest。

2. build_merge 的分层替换语义(AST 层与语义层共存)

build_merge 中每个文件在图上存在两类生产者:确定性 AST 抽取层与语义/LLM 抽取层,两层节点集共存在同一张图里(COEXIST,#2333/#2336)。因此它的替换是按层(tier)作用域的——重抽语义层绝不能误删该文件的 AST 层贡献。源码用 _is_ast_tier(n) 判定节点归属层后分别构造 new_ast_sourcesnew_sem_sources,只在对应的源集合内做"先剔旧再并入"(graphify/build.py)。这也回答了文档里"为什么改文件靠 replace 而非 dedup 调和(#1178 已过时)"的历史疑问:build() 时代的同名合并只折叠完全重复的边,节点一旦从新版本消失就会永远残留,build_merge 的 replace 语义从根上解决了累积污染。

3. Hyperedge 在增量链路中的"携带"契约

脚本把超边单独处理并非多此一举。合并结果写回 .graphify_extract.json 时,hyperedges 必须取自 G.graph['hyperedges']——因为 build_merge 已经把既有 graph.jsonnew_extraction 的超边合并进了图的 graph 属性;若回退到只读 new_extraction 的超边,会静默丢掉历史 run 的全部超边(#801)。这与 _stamped_manifest_files 把 hyperedge 计为有效语义产出(#1920)互为表里:超边是 graphify 里"3 个以上节点共享一个概念"的一等实体,增量更新的每一条链路都必须对它负责。

实战易错清单与建议

综合文档中的 issue 注释(#801/#1027/#1178/#1344/#1361/#1392/#1417/#1908/#1948/#2015/#2333 等)与源码实现,把最常见的坑归纳如下,供实现或审查增量流程时逐条对照:

  1. changed 文件混入 prune_sources:在 root= 相对化后会误删刚重抽出的内容;删除集合必须只来自 deleted_files
  2. 漏传 root=:绝对路径的 prune 源永远匹配不上图中的相对 source_file,结果是每次更新都在累积陈旧节点(#1361)。
  3. 漏传 directed=--directed --update 会静默退化为无向重建并折叠双向边(#1392)。
  4. 视频文件未经转写直接进入语义流水线:原始 .mp4/.mp3 路径会被当作不可读媒体派发给子代理;必须先走 graphify/skills/droid/references/transcribe.md 的 Step 2.5 并把转录文本并入 files['document']
  5. --cluster-only 之后重跑 Steps 5–9:中间文件已被 Step 9 清理,必然抛 FileNotFoundError
  6. 变更文档抽取失败却仍被 stamp:会永久丢失其内容;必须保持未 stamp 让下次 --update 重新排队,或借 clear_semantic 主动清空(#1948/#2015)。
  7. save_manifest 传过滤后的子集而非原始语料作 scan_corpus:会误删仅因过滤被省略的行;应传原始 detect 输出,让"新增排除的文件"与"真删除"保持可区分(#1908)。
  8. diff 展示前忘记备份旧图、展示后忘记清理.graphify_old.json 备份与删除必须成对出现。

小结

--update--cluster-only 构成了 graphify 全量流水线之外最常用的两条维护路径:前者用"Manifest 双哈希差分 → 纯代码短路 → replace-on-re-extract 合并 → 精确 manifest 回写"把每次变更的增量成本压到只重抽真正变化的内容;后者则在零抽取的前提下让社区划分可以反复重算。理解这两条路径,本质上是理解 graphify 状态机的中枢——.graphify_* 中间文件、Manifest 行、graph.json 三者的读写契约。若希望进一步深入相邻主题,可继续阅读同目录下的 add-watch.md(监听模式)、query.md(查询协议)与 exports.md(导出能力)。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.74 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.81 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
595
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
920
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.63 K
1.02 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
518
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
389