Open DIYer22 opened 6 years ago
实验一种共生模型,大致思想如下:
共生模型分为宿主模型:host 寄生模型:parasitic, 而 parasitic 能补足 host 的不足之处。
大致结构如下图: 每个节点代表一张 feature map,每层代表一个 Block
首先,选一个 base model 作为 host,host 先单独训练。
host 训练完成后,固定住 host 的参数,开始构建 parasitic,parasitic 的 block 数目和 host 相同
对于每一层 block,parasitic 的 Input 要 concat 上一层的 host 和 parasitic 的 Output .
因此,parasitic block 的 Input Channel 为 host 的 1.5 倍数 Output Channel 为 host 的 0.5 倍数,
以此,构建出寄生于 host 的 parasitic 主干网络
接下来移植 TreeSegNet 中的构建树状网络的方法,根据 host 在 validation set 上的性能,构建一颗树状网络:Tree net
将 Tree net, 接在 parasitic 主干网络后面, 使得整个 parasitic 能够学到 host 的不足之处
接下来训练 parasitic 网络,此时 host 的参数是固定的。为避免多余的计算,传给 parasitic 的 feature 要 detach
通过看 pytorch-summary 的源码,学会了通过 model.apply(regist_hook) 注册 hook 函数来探索网络内部结构,这个操作非常 Hack,但坑也特别多,下文会说。
model.apply(regist_hook)
使用 model.apply(regist_hook) 实现了自动检测 host 的网络结构及每个 block 的内部信息,并自动构建出对应的 parasitic 主干网络
接下来就是训练过程,一开始 我的方案是在 parasitic 内的 self.host=host 使 host 成为 parasitic 的子网络。
self.host=host
在 parasitic.foward(x) 内部, 先用 self.host.eval() 阻止计算 host 的 grad,再通过 self.host.apply(regist_hook) 注册提取 feature 的钩子函数, 在 self.host(x) 后, 便能通过钩子函数 提取出 host 的 feature。
parasitic.foward(x)
self.host.eval()
self.host.apply(regist_hook)
self.host(x)
这样下来发觉计算很慢,一个 epoch 比以前多花几倍的时间。经排查,在host.eval()模式下,host 网络参数的 grad 本应该为 None ,而运行后该参数的 grad 为 0矩阵。这说明 self.host.eval() 失效,整个 host 计算了 grad,哪怕 detach 了,也只是把 detach 部分的导数设置为 0,继续向后计算 grad。这个问题和之前提出来的 不在计算图中仍会计算 grad 的 issue 很相似
host.eval()
None
为避免 host.grad 的无效计算,不能把 host 作为 parasitic 的子网络。于是,我直接把 host 放到 parasitic 外部 作为全局变量,在 parasitic.foward(x) 内部再调用 host(x) 提取 feature。 这种方案在单卡上表现完美。但在多卡情况下,系统复杂性上升了一个数量集,各种错误。
(下都以双卡为例) 在多卡中,module 要被封装成为 torch.nn.DataParallel 通过查看文档和源码,DataParallel 的原理是:
因此,parasitic.foward(x) 内部的 x 是被 DataParallel 分离出来的 半个 batch_size 的 x_i 了, 而且 x_i 已经是分配到了特定卡上的变量, 只有也在特定卡上的 module 才能处理
我还试过把 feature 打包为 list,作为 host 的输出,再传入 parasitic,但实验发现 DataParallel 只允许 return tensor,遂作罢。
经过不断的实验,最后多卡提取 feature 的方案是:在运行 parasitic.foward(x) 前,先运行 host(x) 并通过钩子函数将 host 的 feature 存储到全局变量 shareDic。钩子函数会根据 feature 所在的 device.id 把 feature 分开存储。在 parasitic.foward(x) 时,会根据 x 所在的 device.id 提取 shareDic 中对应 device 上的 feature ,然后前向计算 parasitic 的输出。
host(x)
实验表面 上述方法可在 多卡中正常运行,不会计算 host 的 grad,单个 epoch 的时间也下降到了正常水平。
在上述实验中:
接下来还要把 TreeSegNet 中的 tree net 接上, 再跑实验
mapmp
mapmt
setup.py
pip install boxx
$DISPLAY
logc
>>> from boxx import logc >>> a, b = 1, 2 >>> logc("c = a + b") Code: c = a + b └──—— 3 = 1 + 2
需要约个事件当面讨论
Review
一. 在 Furniture 数据集上实验一种共生模型
1. 实验简介
实验一种共生模型,大致思想如下:
共生模型分为宿主模型:host 寄生模型:parasitic, 而 parasitic 能补足 host 的不足之处。
大致结构如下图:
每个节点代表一张 feature map,每层代表一个 Block
首先,选一个 base model 作为 host,host 先单独训练。
host 训练完成后,固定住 host 的参数,开始构建 parasitic,parasitic 的 block 数目和 host 相同
对于每一层 block,parasitic 的 Input 要 concat 上一层的 host 和 parasitic 的 Output .
因此,parasitic block 的 Input Channel 为 host 的 1.5 倍数 Output Channel 为 host 的 0.5 倍数,
以此,构建出寄生于 host 的 parasitic 主干网络
接下来移植 TreeSegNet 中的构建树状网络的方法,根据 host 在 validation set 上的性能,构建一颗树状网络:Tree net
将 Tree net, 接在 parasitic 主干网络后面, 使得整个 parasitic 能够学到 host 的不足之处
接下来训练 parasitic 网络,此时 host 的参数是固定的。为避免多余的计算,传给 parasitic 的 feature 要 detach
2. 实现过程 (踩坑记)
通过看 pytorch-summary 的源码,学会了通过
model.apply(regist_hook)
注册 hook 函数来探索网络内部结构,这个操作非常 Hack,但坑也特别多,下文会说。使用
model.apply(regist_hook)
实现了自动检测 host 的网络结构及每个 block 的内部信息,并自动构建出对应的 parasitic 主干网络接下来就是训练过程,一开始 我的方案是在 parasitic 内的
self.host=host
使 host 成为 parasitic 的子网络。在
parasitic.foward(x)
内部, 先用self.host.eval()
阻止计算 host 的 grad,再通过self.host.apply(regist_hook)
注册提取 feature 的钩子函数, 在self.host(x)
后, 便能通过钩子函数 提取出 host 的 feature。这样下来发觉计算很慢,一个 epoch 比以前多花几倍的时间。经排查,在
host.eval()
模式下,host 网络参数的 grad 本应该为None
,而运行后该参数的 grad 为 0矩阵。这说明self.host.eval()
失效,整个 host 计算了 grad,哪怕 detach 了,也只是把 detach 部分的导数设置为 0,继续向后计算 grad。这个问题和之前提出来的 不在计算图中仍会计算 grad 的 issue 很相似为避免 host.grad 的无效计算,不能把 host 作为 parasitic 的子网络。于是,我直接把 host 放到 parasitic 外部 作为全局变量,在
parasitic.foward(x)
内部再调用 host(x) 提取 feature。这种方案在单卡上表现完美。但在多卡情况下,系统复杂性上升了一个数量集,各种错误。
(下都以双卡为例)
在多卡中,module 要被封装成为 torch.nn.DataParallel
通过查看文档和源码,DataParallel 的原理是:
因此,
parasitic.foward(x)
内部的 x 是被 DataParallel 分离出来的 半个 batch_size 的 x_i 了, 而且 x_i 已经是分配到了特定卡上的变量, 只有也在特定卡上的 module 才能处理我还试过把 feature 打包为 list,作为 host 的输出,再传入 parasitic,但实验发现 DataParallel 只允许 return tensor,遂作罢。
经过不断的实验,最后多卡提取 feature 的方案是:在运行
parasitic.foward(x)
前,先运行host(x)
并通过钩子函数将 host 的 feature 存储到全局变量 shareDic。钩子函数会根据 feature 所在的 device.id 把 feature 分开存储。在parasitic.foward(x)
时,会根据 x 所在的 device.id 提取 shareDic 中对应 device 上的 feature ,然后前向计算 parasitic 的输出。实验表面 上述方法可在 多卡中正常运行,不会计算 host 的 grad,单个 epoch 的时间也下降到了正常水平。
在上述实验中:
接下来还要把 TreeSegNet 中的 tree net 接上, 再跑实验
二. 完善工具库 Box-X
mapmp
、mapmt
setup.py
打包到了PyPI, 可通过pip install boxx
安装$DISPLAY
为空的情况logc
(log code)三. 看了两集台大李宏毅的 Machine Learning and having it deep and structured
Next