我对医学一窍不通!
这个项目里所有出血亚型的缩写,硬膜外、脑实质内、脑室内、蛛网膜下腔、硬膜下,我到现在也没真正搞懂它们在解剖学上到底怎么区分,看片子完全看不懂。
负责的只有机器学习那一块,至于这些类别在临床上意味着什么,为什么某一类特别难分,我基本只能转述文献里的说法…………
文中用到的数据是公开数据集,本身已经过脱敏处理,具体的实验数值我也不会放(
适合在做光学/模拟计算硬件,但对上层算法不熟的朋友看qwq如果你在做模型压缩,没接触过光学那一侧,你会发现正负分离其实是一个我们没见过的压缩维度。
主流压缩像剪枝/量化/蒸馏这些都不碰符号结构,正负分离引出的外和分解是P+N个部件组合出 P×N个有效核,器件数线性增长、表达能力平方增长,这条路和现有方法正交是可以叠加的。后面有把训练时约束vs训练后拆分和量化领域的QATvsPTQ做了同构类比,如果你熟悉量化,这个类比能让你理解这套东西在干什么()
refer:
Transferable polychromatic optical encoder for neural
https://www.nature.com/articles/s41467-025-61338-4
Deep learning with coherent nanophotonic circuits, Nature Photonics 11, 441 (2017)
https://arxiv.org/abs/2404.09556
https://github.com/MIC-DKFZ/nnUNet
为什么从正负核分离切入

项目核心就是从这里延伸出来的,给的原始代码用softplus(pos_raw)和-softplus(neg_raw)把卷积核拆成正负两组,一开始我只知道要这么写,不知道为什么必须这么写(
看完了几篇才知道正负核分离的根上,是一个硬件能表示什么和算法需要什么之间的矛盾,这个矛盾不是光学独有的,只要计算硬件的物理载荷量非负、而算法权重需要双极性,就必然出现同一个解法。
ONN目前没解决的四类问题
(1)只能处理简单的灰度数据集。 现有工作 highly restricted on solving a relatively simple gray-scale datasets。对 CIFAR-10 这类彩色多通道数据,要么靠多层堆叠光子电路导致系统体积巨大,要么精度低——作为参照,已发表的 D²NN 在 CIFAR-10 上的盲推理精度只有约六成。
(2)非线性难以光学实现。 最成功的 ANN 架构依赖非线性激活,而 nonlinear activation functions that are challenging to implement optically。现有方案都带来显著的实验复杂度和额外功耗。
(3)静态光学前端无法重训练。 超构表面一旦流片就固定了,不能像数字网络那样重训,基于相变材料或液晶的可重构方案still inferior for practical deployment。
(4)MAC 运算量直接对应功率与延迟。 这是整个方向的驱动力,减少数字端MAC就是减少功耗和延迟。
为什么是 hybrid optical-digital 架构
因为要leverage the strengths of both:用 analog linear optical frontend完成大部分线性运算,把非线性交给 digital backend。
这个分工之所以成立:
- CNN 的卷积层本质是特征提取器,encoding high-dimensional images into low-dimensional features,正好是编码器该干的事。
- every free-space optic inherently performs a two-dimensional convolution operation during the imaging under incoherent light,拍照这个动作本身就是卷积,捕获图像=场景*光学系统的非相干PSF。
因此工程化PSF就能让光学器件替换CNN的初始层,而且只是replacing a conventional lens with PSF-engineered meta-optics,不增加任何额外光学元件。反正我们都要有个镜头才能拍照,把普通镜头换成PSF工程化的超构透镜,系统体积不变。
论文的完整流程:
AlexNet → knowledge distillation → 单卷积层 + 两层 FC
→ metasurface 实现卷积 → 正负核分离
→ transfer learning 到 High-10
正负核分离
算法需要什么
神经网络里的卷积核权重是有正有负的。正权重的意思是这个像素让输出变强,负权重的意思是这个像素让输出变弱。正负号编码的是促进还是抑制这个关键信息,缺了负号网络几乎学不出任何有用的特征。
最典型的例子是边缘检测,中心正、周围负,靠正负相消才能对均匀区域输出零、对边界输出强响应,全正的核只能做模糊。
硬件能表示什么
光学系统里photodetector测量的是intensity,而光强永远非负,因为它本质上是在数光子个数,我们可以有0个光子,可以有很多光子,但不可能有负数个光子,世界上不存在一种光照到某个像素上能让它比纯黑还暗。
于是矛盾出现了,算法要用负权重 硬件造不出负光强。
正负核分离就是化解这个矛盾的办法,思路和记账一样:银行没法记录一笔负存款,每一笔存入都是正数,每一笔支出也都是正数,余额靠收入栏和支出栏两栏之差来表示正负。
正负核分离干的是完全同样的事:把一个有正有负的核W拆成正的部分P和负的部分N,两者都非负,都能用光强表示,光学端各造一个器件分别算出P和N的卷积结果,最后在数字端做一次减法W= P−N,负号就被还原了。
Results 部分:
It is difficult to create positive and negative weights on the camera in terms of light intensity at the same time, so we separate each kernel into its positive and negative parts and design an optic for each, for a total of 32 meta-optics in total corresponding to 16 positive and 16 negative polychromatic kernels.
Methods部分:
we cannot represent both positive and negative weights with optics. Hence, we create 16 positive kernels and 16 negative kernels, then perform digital subtraction on the digital backend.
符号拆分
设标准卷积核W,定义:
- 正核
P = max(W, 0)W 中正元素保留、负元素置零 - 负核
N = max(−W, 0)负元素取绝对值保留、正元素置零
则恒有W = P − N,且 P ≥ 0、N ≥ 0。
光学端两个 metasurface 各自实现 PSF ≈ P 和 PSF ≈ N,分别与输入图像做非负卷积,相机各捕获一幅非负强度图像:
I_P = f ⊛ P , I_N = f ⊛ N
数字端做减法,因卷积对核的线性性:
f ⊛ W = f ⊛ (P − N) = I_P − I_N
结果严格等价于原始卷积
逻辑核/32物理器件
这是我搞混的地方,16个数字核每个拆成正/负两半就是16正16 负,单个metasurface借助色散可以同时承载RGB三个PSF,所以器件数仍是32而不是96,从数字核计数看16核×3色=48 个polychromatic kernels
48是逻辑核数,32是物理器件数,色散复用把3倍的逻辑核压进了同一块物理器件。
16 核→32 器件
这是Choi式正负分离的代价,它解决了造不出负光强的问题,代价是物理器件数量×2。它不是一种压缩方法!
压缩完全由前面的知识蒸馏完成,正负分离在这条流水线上是纯粹的符号修复步骤 还要倒贴一倍器件,这一点是理解我的SignedGrid和它的区别的关键(
dual-rail / differential pair
只要物理载荷量非负 算法权重双极性,就必然出现同样的解法。
忆阻器
忆阻器交叉阵列里 G永远为正,但突触权重需要有正有负。
While the conductance is always positive, synaptic weights can be negative… thus, the weights are commonly depicted by the conductance difference between two devices called a differential pair
即 w ∝ G⁺ − G⁻,和光学的 W = P − N 是同一个东西。
Differential pair/双轨编码
这是用两个非负物理量之差来表示一个有符号量:值 = 正轨−负轨吗,模拟电路里的差分对是两只匹配的晶体管,有意义的信号是两条支路的差。
可以用来模拟神经网络加速器,每个权重=G⁺−G⁻,靠差分放大器做电流相减,还有差分信号传输,像USB/PCIe这些,把信号放在两根线上传V⁺和V⁻,接收端取差,共模噪声被抵消掉。
这是正负分离最直系的对应物了,正负核分离本质就是dual-rail编码用在了卷积核这个层级上,结构相同、代价相同、好处相同。差别只在抽象层级,因为dual-rail是通用电路原理,正负核分离是它在光学卷积核上的具体实例化,不算概念差异。
NMF
给定一个非负数据矩阵V,m×n,所有元素≥0,找两个也全非负的矩阵 W(m×r)和 H(r×n),使 V ≈ W·H,其中r很小,约束是W, H的每个元素都≥0。
这个最经典的例子是人脸,PCA分解人脸会得到特征脸,一张张幽灵般的整脸模板,像素有正有负、互相抵消;而NMF因为只允许相加 不允许相减,学出来的是局部部件,鼻子眉毛嘴角脸=若干部件之和。←这就是parts-based representation,同样的道理用在主题模型、音频分离、推荐系统。算法上就是最小化 ‖V − WH‖² 且约束非负。
它和正负分离的共同基因是非负性是核心约束,而且两者都是神经元发放率非负,突触强度不变号。但目标恰好相反,NMF的非负性是为了禁止减法,形式是两个非负矩阵相乘(V ≈ W·H);正负分离却是要在非负硬件上恢复减法,形式是两个非负矩阵相减。一个拥抱非负、拒绝相减,一个用相减来模拟符号。
归一化破坏重构
论文正文没写的东西。
kernelmino/psf-meta-design-v2,去掉绘图部分的全部核心逻辑:
kernel_index = 9
kernel = kernels[kernel_index, :] # (3,7,7) —— 从 16×3×7×7 里取第 9 个核
kernel_neg = kernel * 0 # 全零容器
kernel_pos = kernel * 0
for n in range(0, len(kernel)): # n = 0,1,2 → R,G,B
for i in range(0, len(kernel[0, :])): # 7 行
for j in range(0, len(kernel[0, 0, :])): # 7 列
if kernel[n, i, j] < 0:
kernel_neg[n, i, j] = np.abs(kernel[n, i, j]) # 负值 → 绝对值 → 负核
else:
kernel_pos[n, i, j] = kernel[n, i, j] # 正值 → 原样 → 正核
# Normalize(逐颜色通道)
max_neg = np.amax(kernel_neg[n, :])
max_pos = np.amax(kernel_pos[n, :])
max = np.max([max_neg, max_pos])
kernel_neg[n] = kernel_neg[n] / max
kernel_pos[n] = kernel_pos[n] / max
kernels = np.load('.../kernel_c_16_k_7_new.npy') # 核是外部训练好、直接读盘的
desired_psf_R = tf.convert_to_tensor(kernel_neg_expanded_R, ...) # 拆出的一半成为 metasurface 优化目标
核是训练好之后才拆的,Choi式分离是post-hoc的符号拆分,不是训练时的参数化。
为什么会这样/calibration layer为什么是必需的
归一化是逐颜色通道除以 max(max_pos, max_neg),R/G/B 三个scale各不相同,所以光学端拿到的P、N只保留了形状,幅度信息被丢掉了,必须由数字后端把三个scale分别乘回来,否则RGB三通道的相对权重就错了。
这就解释了论文里calibration layer为什么是必需的而非可选的,它承担了补回逐通道幅度的职责。物理上也讲得通,metasurface只能控制PSF的形状,绝对光效率受制造精度和材料透射率影响,本来就不可控,所以幅度只能在数字端恢复。
calibration layer被描述为”处理归一化、缩放、平移、旋转、噪声等光学/数字差异”,从代码看,归一化是最本质最不可回避的一项,它是算法流程本身引入的。
SignedGrid是不是同一个矛盾的另一种解法
两种正负分离是不同的东西,虽然同样叫正负分离,但是Choi 2025和我的SignedGrid在做两件不同的事:
Choi 2025是符号拆分
- P = max(W, 0) # W 训练好之后才拆
- N = max(-W, 0)
- W = P - N # 逐元素相减
时机是训练后,W从磁盘读入,P和N支撑集不相交,某位置P>0则必有N=0,P、N不独立,是同一个 W 的互补掩码,16 核到32器件是翻倍的。
SignedGrid=符号约束的外和分解
- pos = conv(x, softplus(pos_raw)) # [B, P, …] P 个正核,全支撑
- neg = conv(x, -softplus(neg_raw)) # [B, N, …] N 个负核,全支撑
- grid = pos.unsqueeze(1) + neg.unsqueeze(2) # [B, N, P, …] 外和
- out = grid.reshape(B, N*P, …) # P×N 个输出通道
时机在训练时从第一步梯度就在约束子空间内,P、N各自满支撑,pos_raw和neg_raw是两组独立的可学习参数,并且C_out个通道只需P+N个物理核。
拿项目里256通道那一层算,标准卷积需要256个自由核,Choi式拆分把这256个核各劈成正负两半,变成512个器件,SignedGrid 用 (16,16) 分解,16 个正核加 16 个负核共 32 个物理核,外和生成完整的256个输出通道。
SignedGrid比Choi式分离用在同一层少16倍器件,项目七个stage的实际分解也是同样的规律,32通道用 (4,8) 共12核,64通道用 (8,8) 共16核,128通道用 (8,16) 共24核,256通道用 (16,16) 32核,320通道用 (16,20) 共36核,相对标准卷积分别省下2.7到8.9倍。
原因在于两者做的是完全不同的运算。
Choi是把一个核劈成两半,信息量没变 容器翻倍,SignedGrid是让两组核做笛卡尔积式的配对,器件数线性增长,有效核数平方增长,简单拆分拿不到这样的结果。
所以在Choi的流水线上,压缩完全由前面的知识蒸馏完成,正负分离在那条链路上是纯粹的符号修复步骤,还要倒贴一倍器件,在SignedGrid里符号问题和压缩问题是被同一个机制同时解决的。
这个优势不是白拿的,Choi的拆分理论上无损,我的外和有明确代价,P×N个有效核并不独立,它们全部落在一个 (P+N) 维参数的仿射子空间里,共享同一个p或同一n的有效核之间只差一个常数核、高度相关。
实验数据
这一节原始数据有参数量、MACs、五个类别各自的Dice、逐病例配对检验的p值、权重检查脚本的原始输出,但是这些数字不会写进来(
一是这些结果还没稳,只跑了单折,消融实验一个都没做,单折的数字随时可能因为换个 fold/换个数据集就变一个样,现在贴出来过两周自己回头看都可能是错的。
二是数字应该出现在该出现的地方,精确的实验结果属于完整的实验报告。
这种分解到底损失了多少
数据是一个公开的3D脑出血CT多类别分割数据集,五类出血亚型,双通道输入。
骨架用nnUNet v2+ResEnc-L+DA5 trainer,也就是该数据集竞赛冠军方案的配置,改动只有一处,重写build_network_architecture,把encoder里的目标Conv3d递归替换成SignedGridConvNd,配置是softplus约束开启、全encoder替换。
损失函数、优化器、学习率调度、patch size、深监督、数据增强全部保持默认。
成本是整网参数量降到基线的三分之一以内,卷积MACs降到约三分之一,这里有个容易误读的地方,单层的压缩比在3到9倍之间,取决于该层宽度,但整网只有三倍多一点,因为 decoder、分割头、InstanceNorm的参数完全没被替换,它们在总量里占了不小的比例,报告整网压缩比时不能拿单层的数字去外推。
精度是前景平均Dice的差距在千分之几的量级,方向上基线略高,光看均值差不够,所以对验证集做了逐病例配对t检验和Wilcoxon检验,五个类别的p值全部远高于0.05,病例级前景 Dice的总体p值也远高于0.05。
有一个细节比任何单个p值都更能说明问题,换一种平均口径,差距的方向会翻转,nnUNet 官方的foreground_mean是先按类别平均、再对类别取平均,这个口径下基线略占优。但如果改成先在每个病例内部把多类Dice平均,再对病例取平均,SignedGrid反而领先,幅度还稍大一些。
所以所谓的差距是均值计算方式带来的噪音,并不存在于逐病例配对的数据里光看输出指标还不够,还得确认SignedGrid内部真的在按设计工作。
所以我又直接从checkpoint把权重读出来逐层统计,没有任何一层塌缩,逐层检查softplus的输出,全零的层数是零,这排除了如果softplus把权重压到接近零,网络实际上是靠一个更小的子网络在跑,那压缩到三分之一还不掉点就完全是假象了。
softplus输出的均值几乎正好落在ln2上,意味着raw权重的分布中心在零附近,正是初始化之后正常收敛该有的形态,没有系统性漂移。
顺带一个待考察的点:如果raw权重的标准差偏小,softplus输出会紧密聚集在ln2附近,有效核就成了零附近的小扰动,实际幅度靠后面的InstanceNorm重新拉起来。
同一次检查让codex还揪出一个工程bug,state_dict里注册的SignedGrid层数是forward实际调用层数的好几倍,因为nnUNet的ConvDropoutNormReLU把同一个卷积同时挂在self.conv和 self.all_modules[0] 两个属性上,我的递归替换把它们当成了不同模块、各替换了一次forward只走all_modules那条路径,所以另一份是被优化器更新过、但从未参与任何计算的死权重。
还没有解决的概念问题
SignedGrid的有效核落在 (P+N) 维仿射子空间里,但实验上没看到精度损失,是任务太简单or这个子空间本身就足够?
真部署到光学硬件 逐层归一化是肯定的。InstanceNorm的affine能不能完整吸收这个scale?