"""【未验证 · 多尺度树档】图像分类 + B 多尺度树分区函数化。
一句话结论:
分区除「按什么信号切」外,还有一维「多尺度树」——先粗分区成大区,再每个大区
内细分小区,叶子区数可调(叶子越多、压缩越弱、保真越高)。本例在小 MLP
(下采样 MNIST)上演示 regionify_hierarchical():打印树结构、扫一遍「树深 →
保真」,并用最细档还原测准确率。
对应分型表的多尺度树方向(方向 B,接口已实现,待真实大模型验证)。
"""
from _common import (accuracy, device, downsample_images, load_mnist,
show_artifacts, train_model)
import numpy as np
import torch
import torch.nn as nn
import nrfunc
class SmallMLP(nn.Module):
def __init__(self, d_in=49, h=16, d_out=10):
super().__init__()
self.fc1 = nn.Linear(d_in, h)
self.fc2 = nn.Linear(h, d_out)
def forward(self, x):
x = torch.relu(self.fc1(x))
return self.fc2(x)
def main():
dev = device()
print(f'设备:{dev}')
train_x, train_y, test_x, test_y = load_mnist()
train_x = downsample_images(train_x, size=7)
test_x = downsample_images(test_x, size=7)
train_x, train_y = train_x[:30000], train_y[:30000]
print('训练小 MLP(49→16→10):')
model = train_model(SmallMLP(), train_x, train_y, epochs=15, seed=0, dev=dev)
acc_before = accuracy(model, test_x, test_y, dev)
print(f'函数化前 · 测试准确率 = {acc_before * 100:.2f}%')
W = model.fc1.weight.detach().cpu().numpy().astype(np.float64)
hier = nrfunc.regionify_hierarchical(W, signal='G', K_top=4, K_sub=2,
order=1, r=4, seed=0)
print(f'\n多尺度树(K_top=4 × K_sub=2):叶子区 K={hier["K"]},'
f'解释方差 = {hier["explained"]:.4f}')
for k in range(hier['K']):
units = (hier['assign'] == k).nonzero()[0]
print(f' 叶子区 {k}:单元 {units.tolist()}')
print('\n树深可调(叶子越多 → 压缩越弱 → 保真越高):')
for kt, ks in [(2, 2), (4, 2), (4, 4)]:
r = nrfunc.regionify_hierarchical(W, signal='G', K_top=kt, K_sub=ks,
order=1, r=4, seed=0)
print(f' K_top={kt} × K_sub={ks} → 叶子 K={r["K"]:2d},解释方差 = {r["explained"]:.4f}')
fine = nrfunc.regionify_hierarchical(W, signal='G', K_top=4, K_sub=4,
order=1, r=4, seed=0)
print('\n生成物(最细档 K_top=4 × K_sub=4,量化打包 + 分片存储):')
show_artifacts(fine, bits=8, n_shards=4)
recon = nrfunc.reconstruct(fine)
with torch.no_grad():
model.fc1.weight.copy_(torch.as_tensor(recon, dtype=torch.float32))
acc_after = accuracy(model, test_x, test_y, dev)
print(f'\n最细档(叶子 K={fine["K"]})部署后 · 测试准确率 = '
f'{acc_after * 100:.2f}%(掉 {acc_before * 100 - acc_after * 100:.2f}pt)')
print('\n[诚实声明] 多尺度树「接口可跑 + 生成物可还原」,树的价值在「层次结构」'
'(子函数可复用、可分片存储/并行 IO),在大 n 层上才明显;本例 n=16 仅演示机制。')
if __name__ == '__main__':
main()