nrfunc:基于神经网络权重重构的模型压缩与部署优化项目

AI模型优化,神经区函数化库

分支1Tags4
文件最后提交记录最后更新时间
18 天前
5 天前
5 天前
4 天前
4 天前
18 天前
18 天前
18 天前
5 天前
4 天前

nrfunc —— 神经区函数算法(函数化 + 生成物)

一、原理

已训练好的成熟模型里,一层权重有 n 个输出单元(神经元/卷积核/注意力头), 传统上每个单元独立存 D 个权重(共 n×D)。但很多单元其实是「同类函数」—— 功能相近、参数冗余。

本库把这些单元聚成 K 个「区」(K ≪ n),**同区共用一个「区域函数」**表达:

  • 0 阶:每区一个质心(均值向量),参数从 n×D 降到 K×D
  • 1 阶:每区 = 均值 + 前 r 个主成分(截断 SVD,即低秩),另存每单元 n×r 投影系数

再给每个单元存一个「归属索引」(log₂K 位,记它属于哪一区)。于是整体的存储, 从「n 份独立权重」变成「K 份共享函数 + n 份归属索引」—— 这就是算力复用(K≪n)的来源,体积缩小只是同一重表达的附带结果

把「一层」推广到「一个模型」,本库的建模方式是逐单元累加

f(x) = Σ f(单元ᵢ)    # 总函数化 = 每层/每单元各自函数化之和
  • x 是待压缩的模型(或某一层权重);f(单元ᵢ) 是该模型的第 i 个可函数化单元 (全连接层、卷积核、注意力投影,甚至位置编码的位置向量)各自独立走一次 「区域函数 + 归属索引」的压缩。
  • 各单元互不共享基、独立决策(auto_alloc 逐层搜 (order,K,r,跳过)),最终累加 成整网的生成物——这就是「参差式」逐层函数化;大层激进压、小层/冗余不足层自动跳过,永久不反涨。
  • 原始形状只决定「怎么规整成 (n,D)」:1D(bias/norm)跳过;2D 直接用;4D 卷积 按单元维展平、位置编码按空间维重排成 (空间数, 通道) 再做——规整后统一走同一套压缩。
训练 ── 模型 ── 成熟模型 ──[ 函数化 + 生成物 ]──> 部署
                              ↑
                        本库只负责这一段
  • 上游(不是本库的活):训练、模型定义、蒸馏、微调、量化感知训练(QAT)。
  • 本库只做两件事:① 函数化(把权重重新表达为区域函数 + 归属索引); ② 生成物(区域函数参数 + 索引 + 投影系数 + 量化打包 + 分片存储 + 价值对比)。
  • 下游(也不是本库的活):把生成物接入推理/部署。生成物可经 reconstruct() 还原成近似权重、当模型权重用,但真正跑起来是下游的活。

二、收益评估

函数化的收益,落在性能(CPU/GPU)· 内存 · 体积几个维度,优先级为性能/内存 > 体积 (一个词:用少量精度,换算力与内存;体积缩小只是压缩过程的附加收益,不单独作为目标):

维度 收益 一句话结论
CPU 有条件地省 大模型(K≪n)+ Rust/GPU 才兑现,numpy 小模型可能更慢
GPU 显存 随函数部署省 与「内存·函数部署」同口径
内存 有条件地省 只在 K×(1+r) < n 时净省,且看部署方式
体积 附加收益(8bit 量化,参数量 n×D → K×D 缩小是个事实,但不是函数化的目标

本机真实实测(代表性数据;内存在前,体积仅为附加收益)

例子 内存·函数部署省 体积省(附加) 精度掉点
MNIST MLP fc1 128×784 83.8% 95.9% 2.98pt
真实大 CNN 最大卷积层 features.17 71.4% 92.9% 2.75pt
玩具 ViT wq 64×64 62.4% 90.5% 0.71pt

数据口径:固定种子可复现;掉点均为「函数化后 vs 原始模型」的精度差,红线 <3pt (库自带 auto_alloc 自适应分配器守住)。完整四维一表见下文「价值证明」。

核空间曲面编码器(kernel_surf,新增第三种函数):3×3 卷积核的 9 点 「图形区」用全层共享固定基 P6=[1,x,y,xy,x²,y²] 拟合(基免存),每核只存 6 个私有系数并可 int8/int6 量化,前向走基卷积共享两段乘(省 32% MAC)。 与质心/低秩是同类型不同的函数,经适配层(core/adapters.py)接入 auto_allocenable_kernel_surf=True 默认开)同场竞优。net50 实测: layer4.2(512×4609)P6-int6 省 87.5% 体积、EV 0.9850;layer4.1/4.0 P8-int8 省 77.8%;浅层自动 skip。详见 docs/kernel_surf_design.md

三、使用注意事项

  1. 体积 ≠ 内存:体积用 8bit 量化能省 90%+,但运行时内存是 float32 常驻,省得少; 且内存省不省取决于部署方式——reconstruct() 还原回稠密时内存一点不省, 只有走 functional_forward()(不还原、只常驻紧凑参数)才省。
  2. 性能(CPU 提速)是函数化首要目标、但它不在此 numpy 参考层兑现:numpy 参考实现的 1 阶前向受 Python 循环 + gather 限制,小模型可能慢于 BLAS 稠密前向;真正的提速 在「K≪n 的大模型 + 编译语言(Rust)/GPU」才兑现(见 nrfunc-rs)。
  3. 按层判断,别一刀切:小层/首层函数化可能「内存反涨」甚至「掉点崩盘」。 用 auto_alloc(W, eval_fn=...) 逐层自适应(自动跳过不划算的层)最稳。
  4. 处理对象是一层权重、不是整个模型:本库处理「一层权重矩阵」这个实例无关单元; GPT 级大模型方向只做接口预留 + 理论预演,不负责验证(需 ≥80GB 级多卡)。

详见下文「责任边界」。

许可与算法来源

  • 代码许可:MIT(见 LICENSE)。
  • 算法均为公开学术概念的自研实现:区域函数化(质心/低秩 SVD 展开)、 PQ/RQ 量化(Jégou et al., 2011 概念)、kmeans++ 初始化(Arthur & Vassilvitskii, 2007 概念)、确定性 PRNG mulberry32(Tommy Ettinger, 公开领域算法,见 _rand.py 注释)。库内不含第三方代码。

安装

pip install nrfunc          # 用户安装(发布后从包仓库安装)

依赖:numpytorch

开发者(本地源码开发)可编辑安装:

pip install -e ".[dev]"      # 含 pytest / pytest-cov / mypy

可选依赖(按需安装,不装也不影响函数化 + 生成物主链路):

pip install -e ".[memory]"   # psutil:rss_mb() 实测进程内存(不装时返回 None)

psutil 是「软依赖」:只在 rss_mb() 测真实内存时需要;未安装时 rss_mb() 返回 None(而非 0,避免误导),库其余功能完全不受影响。

快速开始

import numpy as np
import nrfunc

# 1) 你已训练好的成熟模型:抽出一层权重(任意框架,这里给 numpy)
W = np.random.default_rng(0).standard_normal((256, 128)).astype(np.float32)

# 2) 函数化:256 个输出单元 → 16 个区域函数(1 阶低秩,每区 8 个主成分)
res = nrfunc.regionify(W, signal='G', K=16, order=1, r=8)
print(f"区域数 K={res['K']},解释方差={res['explained']:.3f}")

# 3) 生成物 · 价值对比(CPU/GPU 性能优先;内存次之;体积仅为附加收益。
#    CPU/GPU 需传实测参数,完整四维一表落地见 examples 里的 show_value())
tbl = nrfunc.compare_value(W, res, bits_before=32, bits_after=8)
print(tbl['_table'])

# 4) 生成物 · 量化打包(把区域函数参数量化成可部署字节)
packed, scale, n_out, n_in = nrfunc.quantize_weights(res['means'], bits=8)

# 5) 生成物 · 分散存储到 4 个节点,并行读取
store = nrfunc.build_store(res, n_shards=4)
params = store.region_read_many([0, 1, 2, 3])

# 6) 生成物 → 重建权重:还原成近似权重,可当模型权重用(下游再接入推理)
recon = nrfunc.reconstruct(res)   # (256, 128)
print(f"重建权重 shape={recon.shape},保真度={res['explained']:.3f}")

API 参考(参数 / 用法 / 注意事项)

下面是全部公开函数的签名与参数说明,按模块分组。注意:本库处理对象是「一层 权重矩阵」(n, D)(n=神经元/卷积核/头数,D=每单元参数量),不是整个模型。

1. 函数化(core)

regionify(rows, signal='G', K=None, order=0, r=None, iters=60, seed=0, activations=None, groups=None, assign=None, n_init=1) —— 分区函数化统一入口,返回 dict。

参数 说明
rows (n, D) 权重行向量(numpy 或可转 numpy 的数组)
signal 'G' 几何(k-means)/ 'F' 功能(余弦聚类,需 activations)/ 'S' 结构(按边界切,需 groups
K 分区数。省略时默认 sqrt(n)signal='S'groups 决定、可省略
order 0=质心 / 1=低秩(默认 0)
r order=1 时每区主成分数,省略默认 sqrt(D)
iters 聚类迭代次数(G/F 用)
seed 随机种子(库内 mulberry32,固定 seed 跨平台可复现)
activations signal='F' 所需的 (n, T) 激活响应矩阵
groups signal='S' 所需的 (n,) 结构归属(层号/头号/通道号)
assign 可选,已算好的 (n,) 归属,传入时跳过聚类直接构造(auto_alloc 复用)
n_init 多起点重跑次数(G/F),>1 时尝试多个确定性种子取保真最高;默认 1

返回 dict 关键字段:signal/order/K/assign(n,)/n/D/explained,以及按阶数的参数——0 阶 centroids(K,D);1 阶 means(K,D) + components(K,r,D) + coeffs(n,r)。

regionify_hierarchical(rows, signal='G', K_top=None, K_sub=None, order=0, r=None, iters=60, seed=0, activations=None) —— 多尺度树分区(先粗分大区、再区内细分),叶子区总数 ≤ K_top×K_sub。仅支持 'G'/'F''S' 结构边界本就不需层次聚类)。返回与 regionify 同构、可直接 reconstruct()

reconstruct(result) —— 把区域函数还原成近似权重 (n, D)。0 阶=归属质心;1 阶=区均值+投影修正。

functional_forward(result, x) —— 函数形式前向,不还原稠密权重y = x @ W^T 的等价计算。x 形状 (..., D),返回 (..., n)。这是「为提速」的路径(共享函数只算一次),数值与先 reconstruct() 再前向一致(浮点误差内)。

regionify_transformer_block(block, signal='S', order=1, r=None) —— GPT 级接口预留,不做验证(需 ≥80GB 多卡)。普通 Transformer 请用 regionify(signal='S', groups=...)

2. 自适应分配器(auto_alloc)

auto_alloc(rows, signal='G', activations=None, groups=None, budget=None, distortion=None, eval_fn=None, K_grid=None, r_grid=None, r_max=None, auto_probe=True, probe_energy=0.95, probe_cap=256, iters=60, seed=0, float_bits=32) —— 给一层自动挑最优 (order,K,r),或判「跳过」。

参数 说明
rows / signal / activations / groups regionify
budget 可选,函数化后字节上限;原权重已 ≤ budget 则直接跳过
distortion 可选,失真度 = 允许的 EV 掉点上限(0~1)。给定时追加硬约束 explained ≥ 1 - distortion;默认 None(走省/保真加权,不设保真硬下限)
eval_fn 可选,真实精度回调 eval_fn(result)->bool,True=接受;这是「掉点<阈值」的可靠实现
K_grid / r_grid 可选候选网格;默认 K 含 K=1(全局低秩)+ 2 的幂 + sqrt(n),r 由谱探测自适应生成
r_max 可选,1 阶主成分数上限(对 r 候选截断)
auto_probe 是否启用谱探测(默认 True);关闭则 r 回退固定网格
probe_energy / probe_cap 谱探测的累积能量阈值(默认 0.95)/ 规模上限(默认 256)
iters / seed / float_bits 聚类迭代 / 随机种子 / 内存口径位宽(默认 32)

返回 dict 关键字段:decision'order1'/'order0'/'skip')、result(跳过为 None)、order/K/r(跳过为 None)、saving(节省率,正=省;跳过=0)、explained(重构保真度,跳过为 None)、skipped_reason(仅 skip 时非空)、bytes_before/bytes_aftern_candidates/n_triedr_est(谱探测估计的有效维度)。

注意eval_fn 的返回语义是「接受 = True」。你在 auto_alloc 之外自行实现掉点护栏时的写法见 examples/python/_common.py::make_drop_guard

3. 生成物 · 量化 / 分片 / 二进制(io)

quantize_weights(w, bits=4) —— per-row 对称量化,返回 (packed_bytes, scale, n_out, n_in)bits 仅 4/8。接受 numpy 或 torch 张量。

dequantize_weights(packed, scale, n_out, n_in, bits=4) —— 反量化回 float32。

packed_bytes(num_params, bits=4) —— 按位宽估算字节数(不含 scale 元数据)。

build_store(result, n_shards=1) —— 构建分片存储,返回 ShardedRegionStore

ShardedRegionStore.region_read(region_id) / region_read_many(ids) —— 读区域函数参数;region_read_many 跨分片多线程并行。placement() 看分布、load_balance() 看负载。

to_bytes(result, bits=8) / from_bytes(data) —— 把整个生成物打成一段紧凑二进制字节块(降 IO 频率与体积),或反向解码。bits=8/4/32:8=INT8、4=INT4(真打包、体积再减半)、32=float32 无损。

字节格式:23 字节小端头(NRFN magic + version/order/bits/K/n/D/r)+ 区域函数参数 + assign 索引。 from_bytes 只还原结构元数据+参数+assign,不还原 signal/explained 等标量(需自行保留)。 跨语言消费示例见 examples/code/(Go/Java/Rust/C++ 读同一段二进制)。

4. 价值证明 / 基准(utils)

size_bytes_raw(n, D, bits=32) —— 函数化前字节数。

size_bytes_regionalized(result, bits=8, index_bits_override=None) —— 函数化后字节数(含 1 阶投影系数与归属索引)。index_bits_override 可选,覆盖归属索引位宽(默认按 ceil(log2(K)) 自动算)。

compare_value(rows, result, bits_before=32, bits_after=8, cpu_before_ns=None, cpu_after_ns=None, gpu_before_mb=None, gpu_after_mb=None, mem_scale=1.0) —— 生成四维对比表(体积/内存/CPU/GPU),返回 dict(含 _table 格式化字符串)。

cpu_time(fn, *args, iters=20, warmup=3) —— 同机同批 CPU 前向耗时(ns/次)。

gpu_memory_bytes(fn, *args, device='cuda') —— 实测显存(字节),无 CUDA 返回 None。

bench_single(fn, x, ...) / bench_batch(fn, batch, ...) —— torch 单样本延迟 / 批量吞吐(取最快轮)。

rss_mb() —— 进程常驻内存(MB),需 psutil(软依赖);未装返回 None。

全局注意事项

  1. assign 数组是 int32to_bytes/from_bytes 里也按 int32 处理,别和权重 float 混。
  2. 1 阶净省的近似充要条件是 K×(1+r)<n,不满足就别函数化(auto_alloc 会先验剪枝)。
  3. 掉点红线 <3pt(库各示例的统一口径),衡量口径是「函数化后 vs 原始模型」的精度差;单层的 single_drop 可为负(重建恰好更优),叠加掉点因误差累积而略大于单层之和。
  4. 体积≠内存:体积是量化位宽口径(能省 90%+),内存是 float32 常驻(省得少);且内存省不省看部署方式(reconstruct 不省,functional_forward 才省)。
  5. CPU 提速有条件:只在「K≪n 大层 + Rust/GPU」兑现,numpy 小模型可能更慢。

分区信号分型

一刀切 k-means 只对「小 MLP」成立。大模型权重空间分层、置换不变,必须按底层模型分型:

模型底层 分区信号 含义 入口
小 MLP G 几何 权重几何 ≈ 功能,按欧氏距离 k-means regionify(signal='G')
CNN F 功能 功能同构的核权重几何可远,按激活响应余弦聚类 regionify(signal='F', activations=...)
Transformer S 结构 头/层是并行功能模块,按结构边界切分不混聚 regionify(signal='S', groups=...)
GPT 级 低秩为主 成熟 LLM 的 FFN/MoE 权重无几何聚类结构、只有低秩结构,K=1 全局低秩 + 前向余弦掉点口径;S/F 聚类对小模型/Transformer 可用、对成熟 LLM 权重多余(实测 DeepSeek-OCR-2 MoE 用 G/geodesic + K=1/2) regionify_transformer_block()(仅预演,不验证)

除「分区信号」这一维,分区尺度还有一维「多尺度树」(先粗分区成大区,再每区内细分小区):

  • regionify_hierarchical(rows, signal='G', K_top=8, K_sub=4, order=1, r=8):两层树,叶子区 ≤ K_top × K_sub,树深(叶子数)可调——叶子越多、压缩越弱、保真越高。
  • 四个方向(A 功能聚类 / B 多尺度树 / C 阶数升级 / D 逐层区域化)的可运行实例见 examples/python/four_directions_demo.py,共用同一数据集,保证可用性。

自适应分配器 auto_alloc(不用手动挑 K/r)

手动选 K / r / 阶数容易踩坑:小层或首层函数化可能「内存反涨」甚至「掉点崩盘」。 auto_alloc() 逐层自动搜 (order, K, r, 跳过),两阶段「auto」:

  • 评估演算 → 深造推算:入口谱探测估计该层「有效维度」(compute_uv=False 只算奇异值 + 超大规模均匀抽样,克制资源),据此自适应生成 r 候选(而非固定 [1,2,4,8]);K 含 K=1 全局低秩模式(成熟精炼权重无聚类结构时的最优解)
  • 硬约束「净省」:内存绝不反涨(K×(1+r)<n 先验剪枝,省去必然反涨的候选)
  • 掉点约束两层:先逐 (signal, order, K) 取保真最优,再做 (净省, 保真) 帕累托前沿、 选「膝盖点」(不再用「省×保真」几何平均,避免 K=1 靠净省上限高系统性偏向 K=1) → distortion(可选硬约束)→ eval_fn(真实精度回调,最可靠)
  • 主动跳过:该层函数化不划算时直接跳过,而不是硬凑一个劣化结果
alloc = nrfunc.auto_alloc(W, eval_fn=lambda res: 你的真实精度掉点 < 阈值)
# alloc['decision'] 为 'order1' / 'order0'({order,K,r})或 'skip'(skipped_reason 说明为什么)

实测把 5 个真实模型里「反涨」的层全部转成净省、掉点全压 <3pt(见 examples/python/auto_alloc_demo.py)。

价值证明:函数化前 vs 后四维对比

四个维度——体积 / 内存 / CPU / GPU——库都有对应能力,不是只有体积:

维度 函数化前 函数化后 来源
CPU 稠密前向 x@Wᵀ 函数前向 functional_forward cpu_time() 实测(单样本+批量)
GPU 原始权重(显存 + 前向) 紧凑参数(显存 + 函数前向) 实测(需 CUDA,显存+单样本+批量)
内存 n×D×32bit 常驻 见「部署方式」 size_bytes_regionalized()
体积 n×D×bits K×D×bits + n×log₂K(含 1 阶投影系数) 参数量 × 位宽(附加收益,非目标)

压缩率来自:不再存 n×D 个独立权重,只存 K 个共享函数 + n 个归属索引。

四维已实测落地examples/python/mnist_mlp_classification.pyshow_value() 在同一张表里 打印全部四维(fc1 层 128×784,auto_alloc 自动选 K=1/r=17 的实测):

维度 函数化前 函数化后 节省率
GPU 单样本延迟 稠密前向 函数前向 见「函数形式前向」
GPU 批量吞吐 稠密前向 函数前向 见「函数形式前向」
内存·函数部署(float32) 401,408 B 65,152 B 83.8%
GPU 显存(float32 常驻) 0.4 MB 0.1 MB 83.5%
内存·还原部署(float32) 401,408 B 401,408 B 0%(还原回稠密,内存不省)
体积(8bit 存储) 401,408 B 16,288 B 95.9%(附加收益,非目标)

诚实口径(关键,别只看一张表):

  • 体积 ≠ 内存:体积用 8bit 量化能省 95.9%,但运行时内存是 float32 常驻,只省 83.8%; 而且内存省不省取决于部署方式——reconstruct() 还原回稠密 float32 时内存一点不省, 只有走 functional_forward() 函数部署(不还原、只常驻紧凑参数)才省内存。
  • CPU/GPU 提速是函数化首要目标,但它不在 numpy 参考层兑现:numpy 参考实现里 functional_forward 的 1 阶小模型受 Python 循环 + gather 限制,可能慢于 BLAS 稠密前向; 提速只在「K≪n 的大模型 + 编译语言(Rust)/ GPU」里兑现(见下「函数形式前向」的 0 阶 29.79× / 1 阶 1.88×)。
  • GPU 显存这里只给 float32 常驻口径(与「内存·函数部署」同数);GPU 上的 函数前向提速需 CUDA/Rust kernel,numpy 参考实现不含。show_value() 会给 GPU 侧 补上单样本延迟 + 批量吞吐(torch 真实 CUDA 前向,与 CPU 侧对称对齐),让 CPU / GPU 两端的「显存 / 耗时」都能并排对比;但 GPU 函数前向的提速潜力仍需 Rust/CUDA kernel 才兑现,此处的 torch 实测是「同一 CUDA 环境」下的可比口径。
  • 内存/显存是「存储占用」口径,不等于运行时峰值分配;CPU/GPU 只保证同机同批可比。

函数形式前向:不还原权重,直接按生成物算

reconstruct() 是「还原成稠密权重再算」,推理速度与原始权重一致、精度有损。另一条为提速设计的路径是 functional_forward()——不还原、直接用生成物算,共享的区域函数只算一次再按归属广播,省掉 K≪n 时的重复乘:

  • 0 阶y = (x @ centroids^T)[:, assign] —— 只算 K 次内积,再查表广播回 n 个单元
  • 1 阶y = (x @ means^T)[:, assign] + Σ_j coeffs[i,j]·(components[assign[i],j] @ x)

数值上等价于先 reconstruct() 再前向(浮点误差内一致)。本机实测提速(n=1024, D=512, K=16, r=8):

阶数 单样本延迟 批量吞吐(B=1024) 体积
0 阶 29.79× 1.85× 省 99.6%
1 阶 1.88× 0.24× 省 96.1%

诚实声明:numpy 参考实现下,0 阶提速干净兑现1 阶批量未兑现理论 6.4×(低秩修正的 gather / 小 K 矩阵乘在 numpy 里开销大)。1 阶的完整提速需在编译语言(Rust)/ GPU 里兑现——那里 gather 廉价、无 Python 开销,这正是下游部署(演算服务)该做的事。

这条「Rust/GPU 才兑现」的判断已有端到端参照examples/project 的 13.77M 检测大模型上,函数化 fc2(2048×4097 宽层、K=32 r=8)用 Rust 二进制整网前向,CPU 快 1.93~2.65x、GPU 快 1.31~1.38x,数值自检 9.2e-14 一致(详见 examples/project/README.md 的 comparison.log)。

权重分散存储拓扑

区域函数权重不必集中单节点,可分散多节点分片 + IO 并行读取:

  • 动机①:大规模权重单节点放不下,分片是唯一出路(呼应张量/模型并行)。
  • 动机②:高并发批量读取会打爆单节点权重读取吞吐,分片后 IO 并行、吞吐随分片数扩展。
  • ShardedRegionStore 把 K 个区域函数按 region_id 散列到 n 个分片,region_read_many() 多线程并行拉取。
  • n_shards=1 退化为「集中单节点」。

嵌入式设备可行性(大模型上边缘)

本库能把「大模型上嵌入式」的体积/内存这堵墙撬动,但它只做「压缩 + 生成物」, 不含推理运行时——产物要能在嵌入式跑,必须有一个 C/Rust 推理 kernel 去消费它。

关键:本库能撬动哪几堵墙

瓶颈 本库能否解决
① 存储体积(FLASH 放不下) ✅ 能(量化 + 函数化直接压字节)
② 运行内存(RAM 装不下) ✅ 部分能(函数部署不还原,条件 K×(1+r)<n
③ 算力(推理太慢) ⚠️ 间接(需 Rust/C 实现 + 大层才兑现)
④ 推理框架(嵌入式无 PyTorch) ❌ 不能(库只产生成物,不产可执行引擎)

估算:给定内存预算,函数化 + 量化能装下多大模型

仅算「权重存储」字节(不含激活缓冲),量化 f32→i8=4×、f32→i4=8×,函数化再压 约 7~17 倍(取决于 K/n,此处统一取保守中值 12×;可复现脚本 examples/python/embedded_feasibility.py):

模型(参数量) f32 体积 f32函数化 i8函数化 i4函数化
小 MLP(0.5M) 1.9 MB 0.16MB 0.04MB 0.02MB
中 CNN(5M) 19.1 MB 1.59MB 0.40MB 0.20MB
较大 CNN(25M) 95.4 MB 7.95MB 1.99MB 0.99MB
大 ViT(100M) 381.5 MB 31.79MB 7.95MB 3.97MB

三档内存预算下的「装得下」判定(取最省 i4 口径):

模型(参数量) 512MB 64MB 8MB
小 MLP(0.5M)
中 CNN(5M)
较大 CNN(25M)
大 ViT(100M) ✓(i4 3.97MB)

三档设备分水岭:

  • MCU 级(STM32/ESP32,KB~MB RAM):基本不可行——即便 i4 压进体积, MCU 也没有算力跑它,本库只能当「存储端压缩」。
  • 边缘 SoC(RK3588/树莓派,GB 级):最佳落点——中模型轻松装下、且「又省又稳」。
  • 中间档(64MB / 8MB 级):25M 参数 i8 即过 64MB,100M 需 i4 才稳妥。

诚实边界:① 上表只算权重、不含激活缓冲(嵌入式运行时激活常比权重更吃内存); ② 掉点口径:跨规模 MLP 扫描的实测(scale_scan.py)+ 真实 ResNet50 的函数化验证;真实大 CNN/ResNet50 层函数化掉点可压到 ±0.5pt(见 aitest 结论),但小层(h=64)叠加掉点仍会到 4.16pt—— 「装得下」与「不掉点」都取决于层冗余度; ③ 「装得下」≠「跑得动」,推理框架与算力是另一堵更硬的墙。

责任边界

  • 几何分区 G + 0/1 阶函数:已实证可用
  • 功能分区 F已实现 + 已实证——真实大 CNN(VGG 风格 6 卷积层,585,066 参数)全 6 卷积层函数化后测试准确率 99.59% → 96.84%(掉 2.75pt,固定种子可复现值)、最大卷积层体积省 92.9%(见 examples/python/cnn_classification.py)。
  • 结构分区 S、多尺度树 regionify_hierarchical已实现,均有实例 + 防回归测试(生成物可 reconstruct() 还原),但尚未在真实 Transformer/ViT 上验证精度,属「待验证」而非「已验证」。
  • 函数形式前向 functional_forward已实现 + 防回归测试(函数前向 == 还原前向,浮点误差内一致)。0 阶单样本提速 29.9× 已实证;1 阶批量提速需 Rust/GPU 兑现(numpy 参考实现受 gather 限制)。
  • 自适应分配器 auto_alloc已实现 + 已实证(合成数据验证机制,真实精度须 eval_fn 兑底)——逐层搜 (order,K,r,跳过) + 硬约束净省 + 谱探测自适应 r 候选 + 省/保真加权目标,把反涨层转净省。
  • GPT 级:regionify_transformer_block() 只做接口预留、不做验证(需 ≥80GB 级多卡 + ≥256GB 内存)。谁有条件谁验证。

图像分类示例(examples/,真实 MNIST)

分型表的每一档,都配一个**真实图像分类(MNIST)**示例。每个示例都是「训练 → 模型 → 函数化 → 生成物 → 部署使用」这条完整链路的实例——MNIST 图像分类只是「训练/模型」上游环节的载体,让函数化有真实权重可切、部署有真实准确率可测。运行(需 torch):

python examples/python/mlp_classification.py          # [已验证] 小 MLP
python examples/python/mnist_mlp_classification.py    # [已验证] MNIST MLP
python examples/python/cnn_feature_clustering.py      # [未验证] 小 CNN + F 功能(接口演示)
python examples/python/cnn_classification.py          # [已验证] 真实大 CNN(VGG 风格 6 卷积层)
python examples/python/transformer_structure_partition.py  # [未验证] Transformer + S 结构
python examples/python/hierarchical_multiscale.py     # [未验证] 多尺度树
python examples/python/gpt_preview.py                 # [未验证] GPT 级预演(纯理论)
python examples/python/auto_alloc_demo.py             # 自适应分配器(把反涨层转净省)
python examples/python/multilayer_autoalloc.py        # 参差式逐层函数化(多层 fc 各层独立决策 + 叠加测掉点)

另有两个纯推算 script(不训练、无 MNIST,快速可跑):

python examples/python/embedded_feasibility.py  # [估算] 嵌入式:内存预算能装下多大模型(量化的体积推演)
python examples/python/gpt_extrapolation.py     # [推断] GPT 级收益外推(三条规律 + 跨规模扫描 + K=1 低秩证据)
示例 分型档 分区信号 数据集 状态
mlp_classification.py 小 MLP G 几何 MNIST(下采样 7×7) ✅ 已验证
mnist_mlp_classification.py MNIST MLP G 几何 MNIST(28×28) ✅ 已验证
cnn_feature_clustering.py CNN F 功能 MNIST ⚠️ 未验证(小 CNN 接口演示)
cnn_classification.py 真实大 CNN F 功能 MNIST(28×28) ✅ 已验证
transformer_structure_partition.py Transformer S 结构 MNIST(玩具 ViT) ⚠️ 未验证
hierarchical_multiscale.py 多尺度树 G MNIST(下采样) ⚠️ 未验证
gpt_preview.py GPT 级 S+F+低秩 纯理论 ⚠️ 预演不验证
multilayer_autoalloc.py MNIST MLP(多层 fc) G 几何(参差式逐层) MNIST(28×28) ✅ 已验证

「已验证」= 本项目已实证精度/压缩达标;「未验证」= 接口可跑、生成物可还原、 但尚未在真实规模的 Transformer/GPT 上验证精度。数据集统一用 MNIST:图像分类是 MLP/CNN/玩具 ViT 的天然试金石,能给出真实的「函数化前后准确率」对比; CNN 档用真实大 CNN(VGG 风格 6 卷积层,测试 99.59% → 96.84%,掉 2.75pt, 固定种子可复现值) 证明 F 功能分区在真实规模上成立;Transformer 档用玩具 ViT(真实 MNIST 训练, 测试 94.99% → 94.28%,掉 0.71pt)证明 S 结构分区按头切正确、生成物可还原, 真实 ViT/LLM 精度未验证;GPT 档为纯理论预演。 multilayer_autoalloc.py(参差式逐层)用 784→512→256→10 的三层 fc,各层独立 auto_alloc(不划算的 fc3 自动 skip),整体省 81.6%、叠加掉点 2.17pt——比单层 函数化更能体现「逐层各取所需」与「误差累积」两条诚实口径。

完整链路五阶段(每个示例都走这条)

阶段 谁负责 在示例里的对应
① 训练 上游(非库) _common.train_model() 在 MNIST 上训练小网络
② 模型 上游(非库) 训练好的 model,抽出要函数化的一层权重 W
③ 函数化 nrfunc.regionify(W, signal=..., K=..., order=...)
④ 生成物 show_value()/compare_value() 价值四维(体积/内存/CPU/GPU)+ quantize_weights() 量化打包 + build_store() 分片存储
⑤ 部署使用 下游(非库) reconstruct() 还原权重 → 塞回模型 → 测准确率

库只负责 ③ 函数化 + ④ 生成物 两段;①② 训练/模型、⑤ 部署 是上下游, 示例为了给出真实权重和真实准确率,把它们也一并跑通,构成「训练 → 模型 → 函数化 → 生成物 → 部署使用」的完整闭环。

目录结构

nrfunc/
├── src/nrfunc/
│   ├── core/
│   │   ├── region.py          # 区划分(功能区 / 旁区)
│   │   ├── functionalize.py   # 函数化核心(k-means / 低秩 / F/S 分型)
│   │   └── auto_alloc.py      # 自适应分配器(逐层搜 (order,K,r,跳过))
│   ├── io/
│   │   ├── serialize.py       # 生成物 · 量化打包
│   │   └── sharding.py        # 生成物 · 分散存储
│   ├── utils/
│   │   ├── benchmark.py       # 性能基准
│   │   └── value.py           # 价值证明四维对比
│   └── _rand.py               # 确定性随机(复现)
├── tests/
└── examples/
    ├── python/
    │   ├── _common.py                      # 共享:路径引导 + MNIST 加载 + 训练/评估助手
    │   ├── _run_all.py                     # 一键跑全部示例(UTF-8 日志落盘)
    │   ├── functionalize_demo.py           # 端到端:函数化 → 生成物 → 重建权重(合成数据)
    │   ├── four_directions_demo.py         # 四方向(A/B/C/D)各一实例,共用合成数据集
    │   ├── functional_forward_demo.py      # 函数形式前向:正确性 + 稠密 vs 函数提速
    │   ├── auto_alloc_demo.py              # 自适应分配器:把反涨层转净省
    │   ├── multilayer_autoalloc.py         # 参差式逐层函数化(多层 fc 各层独立决策 + 叠加测掉点)
    │   │
    │   │  # ── 估算 / 推断(纯推算,无训练,快)──
    │   ├── embedded_feasibility.py         # [估算] 嵌入式设备可行性:内存预算能装下多大模型
    │   ├── gpt_extrapolation.py            # [推断] GPT 级收益外推:三条规律 + 跨规模扫描 + K=1 低秩证据
    │   │
    │   │  # ── 图像分类示例(真实 MNIST,含训练上游 + 函数化 + 精度对比)──
    │   ├── mlp_classification.py           # [已验证] 小 MLP(下采样 MNIST)+ G 几何
    │   ├── mnist_mlp_classification.py     # [已验证] MNIST MLP(784→128→64→10)+ G 几何
    │   ├── cnn_feature_clustering.py       # [未验证] 小 CNN + F 功能(按激活响应聚)
    │   ├── cnn_classification.py           # [已验证] 真实大 CNN(VGG 风格 6 卷积层)+ F 功能
    │   ├── transformer_structure_partition.py  # [未验证] 玩具 ViT(真实 MNIST)+ S 结构(按头切)
    │   ├── hierarchical_multiscale.py      # [未验证] 小 MLP + B 多尺度树(先粗后细)
    │   └── gpt_preview.py                  # [未验证] GPT 级 S+F+低秩 组合预演(纯理论)
    ├── rust/                               # Rust 版前向实测(CPU 零依赖 + GPU cudarc/cuBLAS,见该目录报告)
    └── project/                            # 多对象检测大模型端到端(传统 vs 函数化两种部署对比)

测试

pytest tests -q

推断:GPT 这类超大模型的收益

本节是基于实测规律的外推,不是验证结论。库内对 GPT 级只做接口预留 (regionify_transformer_block())+ 理论预演(examples/python/gpt_preview.py), 真实收益需 ≥80GB 级多卡验证,本机做不到。请把它当「方向性判断」。

从小模型到大模型,三条实测规律

收益优先级是分场景的(不是全局一刀切):

  • 小模型 / CNN:GPU/CPU 性能(端到端前向提速)为第一优先级,内存次之,体积是附加。
  • GPT 级超大模型:内存(显存/常驻内存)是第一优先级(第一矛盾是「显存/内存装不下」), 但前提门槛是 GPU/CPU 至少要略有提升(至少不能倒退),否则宁可不压。
  • 体积缩小在任何场景都仅是附加收益,不单独作为目标。
规律 实测证据(固定种子)
CPU 提速只在「大模型 + Rust/GPU」兑现 numpy 小模型反慢,大层(K≪n)才转正
内存/显存靠「K≪n」才兑现(GPT 级第一优先级) 充要条件 K×(1+r)<n,小层会反涨、大层净省
体积省钱随冗余度上升(附加收益,非目标) 小 MLP 省 82% → 大 CNN 92.9%(最大层) → 玩具 ViT 90.5%,越大越省

跨规模实测:层越宽,函数化越「又省又稳」

同 MNIST、同 seed、3 隐层 MLP(784→h→h→h→10),只改隐层宽度 h、逐层参差式函数化 (scale_scan.pymultilayer_autoalloc.py 的逐层机制跑 6 个宽度档的对照扫描, 新版 auto_alloc:K=1 全局低秩 + 谱探测 + 3pt 掉点红线):

隐层宽 h 参数量 叠加掉点 整体节省率
64 5.9 万 4.16pt 71.7%
128 13.5 万 1.82pt 79.6%
256 33.5 万 1.01pt 82.8%
512 93.2 万 0.19pt 82.7%
1024 291.3 万 0.08pt 85.3%
2048 1002.1 万 -0.06pt 84.4%

数据来源与时效性:上表数字来自 examples/python/reports/scale_scan.logscale_scan.py 实跑产出)。以 log 最新实测为准——若脚本/算法更新后重跑 scale_scan.py 得到新数字,本表与 log 不符时,以 log 为准修改本表, 绝不反向拿本表旧数字去改脚本或当结论

注:上表是「等宽三隐层 784→h→h→h→10」的缩放扫描,逐层 auto_alloc 用 3pt 掉点红线 约束单层(叠加掉点因误差累积可略超单层红线,如 h=64 的 4.16pt);窄层 h=64 掉点超 3pt 属于「窄层扫描观察值、非达标记录」。正式示例 multilayer_autoalloc.py 用的是「递减 784→512→256→10」(省 81.6%、掉 2.17pt), 两者结构不同,数字不可直接互换。

两条清晰趋势(新版 nrfunc 下的诚实值):

  • 掉点在跨过某临界宽度后「断崖式收敛」(h=128 起掉点就压进 2pt 内,h=256 起 <1.1pt、 到 h=2048 甚至 -0.06pt 精度反升),比旧版(到 h=1024 才稳在 <1.5pt)收敛得更早、更狠;
  • 节省率整体随宽度上升、但不再严格单调(71.7%→85.3% 区间内小幅波动), 因为新版 auto_alloc 会为 3pt 保真红线主动牺牲一点压缩,换取掉点大幅下降—— 「省得多」与「掉得少」在宽层同时成立的判断依然成立。

这正是「fc 层极宽时,参差式函数化优势被放大」的直接证据——GPT 的 FFN 层 正是典型的极宽 fc 层,按此趋势收益只会更显著。

成熟模型的直接证据:K=1 全局低秩(ResNet50)

上述规律在真实成熟 ResNet50上得到进一步验证(101 类花草识别,13.77M 参数):

  • 旧版 auto_alloc(K 网格缺 K=1、r 网格过窄)对 layer2~4 的 13 个卷积层全部判 skip(总省 0%);
  • 新版(谱探测 + K=1 全局低秩 + distortion 约束)14 层全部函数化,总省 11.2%,叠加掉点 -0.44pt(精度不降反升)。

关键启示:成熟精炼的卷积核权重「没有几何聚类结构、只有低秩结构」,K=1 全局低秩 (等价 PCA)才是正解。这直接支撑了「GPT 的 FFN/注意力层用 K=1 全局低秩 + 前向余弦 掉点口径函数化」的可行性——GPT 的 FFN 层同样是「成熟、无聚类、低秩」的宽层。 (DeepSeek-OCR-2 MoE 实测印证:三 proj 用 K=1/2 低秩 + cos≥0.90,而非结构切分/功能聚类。)

按这三条规律外推 GPT 级

以下外推已被真实 DeepSeek-OCR-2(MoE 大模型,3389M 参数)的实测定论修正cos≥0.90 前向余弦口径下,2112 个 MoE expert 三 proj 全函数化(零 skip), 平均只省约 22.8%(gate 25.1% / up 21.8% / down 21.5%),远低于早年外推的「95%+」。 结论:成熟 LLM 的 FFN 权重冗余是「低秩冗余」而非小模型的「聚类冗余」, 在保精度红线下省 20~40%,到不了 95%。保留以下三条规律(体积/CPU/掉点), 但「省多少」以实测为准。

  1. 体积 / 内存:确定能省,但幅度有限(实测约 23%) GPT/MoE 的 FFN 层 K≪n 天然成立、参数冗余充分,函数化不反涨、确定净省; 但「省多少」由「保真红线允许 r 降到多低」决定,不由 K≪n 决定。 DeepSeek-OCR-2 实测:cos≥0.90 下 MoE 平均省 22.8%(单层 14.9%~51.3%), 全模型口径约 10~15%(MoE 占全模型 71.5%)。早年的「95%+」是把小模型的 「聚类冗余」错当成了成熟 LLM 也具有的特征,已修正。
  2. CPU:首次有「真提速」的土壤 小模型测不出提速,是因为 K 不够小、BLAS 稠密占优;GPT 层 K≪n,函数前向 共享计算 + 查表广播的收益才会浮现——但前提是 Rust/CUDA kernel 兑现, numpy 参考实现仍会受 gather/循环拖累。
  3. 掉点:分型手段能兜住,但「不验证」是硬边界 实测里 F 功能分区(大 CNN 掉 2.75pt)、S 结构分区(玩具 ViT 掉 0.71pt) 都在 <3pt 内,且 auto_alloceval_fn 能逐层把掉点压住。DeepSeek-OCR-2 的 MoE 实测用「K=1/2 低秩 + 前向余弦(cos≥0.90)」,而非早年预想的 「S(切分)+ F(功能聚类)+ 低秩」三件套——成熟 LLM 权重无聚类结构,S/F 聚类 路径对大模型 FFN 多余。真实 LLM 的整网级掉点仍无验证。

为什么不直接给结论

  • 本机 12G 显存 + 16G 内存,加载不了 GPT 级权重,无法实测
  • GPT 的权重/激活分布、冗余结构与小模型不同,前面的规律不能保证线性外推
  • 这正对应库的诚实边界:GPT 级「谁有条件谁验证」,本库只提供接口与理论预演。

如果你有条件(≥80GB 级多卡 + 大内存),欢迎用 regionify_transformer_block() 的接口骨架 + 上述分型思路做真实验证,那是本节推断能否成立的最终判据。


算法逻辑由本人提出,算法推演实现由AI推断

License

MIT

项目介绍

AI模型优化,神经区函数化库

定制我的领域