AI模型优化,神经区函数化库
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 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_alloc(enable_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。
三、使用注意事项
- 体积 ≠ 内存:体积用 8bit 量化能省 90%+,但运行时内存是 float32 常驻,省得少;
且内存省不省取决于部署方式——
reconstruct()还原回稠密时内存一点不省, 只有走functional_forward()(不还原、只常驻紧凑参数)才省。 - 性能(CPU 提速)是函数化首要目标、但它不在此 numpy 参考层兑现:numpy 参考实现的 1 阶前向受 Python 循环 + gather 限制,小模型可能慢于 BLAS 稠密前向;真正的提速 在「K≪n 的大模型 + 编译语言(Rust)/GPU」才兑现(见 nrfunc-rs)。
- 按层判断,别一刀切:小层/首层函数化可能「内存反涨」甚至「掉点崩盘」。
用
auto_alloc(W, eval_fn=...)逐层自适应(自动跳过不划算的层)最稳。 - 处理对象是一层权重、不是整个模型:本库处理「一层权重矩阵」这个实例无关单元; 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 # 用户安装(发布后从包仓库安装)
依赖:numpy、torch。
开发者(本地源码开发)可编辑安装:
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_after、n_candidates/n_tried、r_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 字节小端头(
NRFNmagic + 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。
全局注意事项
assign数组是 int32,to_bytes/from_bytes里也按 int32 处理,别和权重 float 混。- 1 阶净省的近似充要条件是
K×(1+r)<n,不满足就别函数化(auto_alloc 会先验剪枝)。 - 掉点红线 <3pt(库各示例的统一口径),衡量口径是「函数化后 vs 原始模型」的精度差;单层的
single_drop可为负(重建恰好更优),叠加掉点因误差累积而略大于单层之和。 - 体积≠内存:体积是量化位宽口径(能省 90%+),内存是 float32 常驻(省得少);且内存省不省看部署方式(
reconstruct不省,functional_forward才省)。 - 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.py 用 show_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.py 用 multilayer_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.log(scale_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/掉点), 但「省多少」以实测为准。
- 体积 / 内存:确定能省,但幅度有限(实测约 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 也具有的特征,已修正。 - CPU:首次有「真提速」的土壤
小模型测不出提速,是因为 K 不够小、BLAS 稠密占优;GPT 层
K≪n,函数前向 共享计算 + 查表广播的收益才会浮现——但前提是 Rust/CUDA kernel 兑现, numpy 参考实现仍会受 gather/循环拖累。 - 掉点:分型手段能兜住,但「不验证」是硬边界
实测里
F功能分区(大 CNN 掉 2.75pt)、S结构分区(玩具 ViT 掉 0.71pt) 都在 <3pt 内,且auto_alloc的eval_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