井贤栋|可视化损失函数空间三维图( 二 )



   x = x.flatten(1)
   x = F.relu(self.fc1(x))
   x = self.drop2(x)
   x = self.fc2(x)

   return F.log_softmax(x 1)
具有两个卷积层的简单 NN 足以对 MNIST 数据集进行分类和进行演示
这里的\uD835\uDEC9 肯定是高维的(上面代码片段中的简单网络有 1199882 维!) 。但是现实将我们限制在只有三维中——至少就可视化而言 。所以 , 我们需要减少这个维度 。一种简单的方法是从欧几里得空间移动到较低维度(一维或二维)的超空间 。简单来说 , 在欧几里得空间中具有 d 维的 \uD835\uDEC9 可以被认为是超空间的一维表示 。\uD835\uDCDB(\uD835\uDEC9; \uD835\uDC66 \uD835\uDC61) 的图是一个二维图 。同样 , 如果我们假设 \uD835\uDEC9 在超空间中是二维的 , 我们就有了一个理想的三维图 。
使用低阶维度可视化一维
【井贤栋|可视化损失函数空间三维图】将损失绘制为一维图 [1
很简单:它首先测量从一组参数 \uD835\uDEC9 到另一组参数 \uD835\uDEC9* 的损失 , 其中 \uD835\uDEC9 可能是一个随机初始化的集合 , 指向(已经找到的)局部(甚至全局)最优 , \uD835\uDEC9* 。
from torch.nn.utils import (
 parameters_to_vector as Params2Vec
 vector_to_parameters as Vec2Params
)

learnt_model = 'models/learnt.pt'

learnt_net = Net()
learnt_net.load_state_dict(torch.load(learnt_model))
theta_ast = Params2Vec(learnt_net.parameters())

infer_net = Net()
theta = Params2Vec(infer_net.parameters())

loss_fn = torch.nn.NLLLoss()
加载一个经过训练的模型(4.58MB)(准确率超过98%) 。 插值从随机初始化开始
所有可能的参数集可以简单使用从 0 到 1进行表示 , 两者的权重相加等于 1 , 并且由非欧几里得变换给出 , \uD835\uDF0F:
def tau(alpha theta theta_ast):
 return alpha * theta_ast + (1 - alpha) * theta
使用x 轴是一个范围从 0 到 1标量 \uD835\uDEFC , y 轴上的损失为 \uD835\uDCDB(\uD835\uDEC9(\uD835\uDEFC)) , 这样我们就得到了一个一维损失图 。
losses = [


for alpha in torch.arange(-20 20 1):
 for _ (data label) in enumerate(dataloader):
   with torch.no_grad():
     Vec2Params(tau(alpha theta theta_ast)  infer_net.parameters())
     infer_net.eval()
     prediction = infer_net(data)
     loss = loss_fn(prediction label).item()
     losses.append(loss)
计算从随机集到全局优化的所有参数的损失
二维
在二维空间 [1 2
中绘图在原理上同样简单 。给定任何随机或优化的参数集 \uD835\uDEC9* , 我们在两个方向\uD835\uDEFF 和 \uD835\uDF02上前进 。在两个方向上 , 我们分别采取小步骤 , \uD835\uDEFC 和 \uD835\uDEFD 。因此 , 结果图是 \uD835\uDEFC 和 \uD835\uDEFD 的函数 。
由于\uD835\uDEFF和\uD835\uDF02是方向向量 , 它们代表了\uD835\uDEC9*每个维度的方向 。即 , \uD835\uDEFF 和 \uD835\uDF02 具有与 \uD835\uDEC9* 相同的维度 , 它们都可以从随机高斯样本中采样 。
非欧几里得变换由 \uD835\uDF0F 给出:
def tau_2d(alpha beta theta_ast):
 a = alpha * theta_ast[:NoneNone

 b = beta * alpha * theta_ast[:NoneNone

 return a + b
然后可以从 \uD835\uDEFC \uD835\uDF16 [0 1
和 \uD835\uDEFD \uD835\uDF16 [0 1
或任何范围绘制等高线图 。在下面的代码段中 , 两者都在 [-20 20
范围内 。
x = torch.linspace(-20 20 20)
y = torch.linspace(-20 20 20)
alpha beta = torch.meshgrid(x y)
space = tau_2d(alpha beta theta_ast)

losses = torch.empty_like(space[0 : :
)

for a _ in enumerate(x):
 print(f'a = {a')
 for b _ in enumerate(y):
   Vec2Params(space[: a b
infer_net.parameters())
   for _ (data label) in enumerate(dataloader):
     with torch.no_grad():
       infer_net.eval()
       losses[a
[b
= loss_fn(infer_net(data) label).item()
该图为我们提供了两条信息:我们可以在两个方向上移动的速率 , 以及用于获得更大图像的范围 。上面生成等高线图的片段(来自同一个 \uD835\uDEC9*)用于生成下面的等高线图 , 唯一的区别是\uD835\uDEFC 和 \uD835\uDEFD 的范围是 [-25000 25000

一些技巧这种可视化在比较优化方法和网络架构时非常有用 。 然而这并不总是有效的 , 因为有一些层不会对模型的有效结果产生任何影响 。 例如 , ReLU可能不会改变网络的行为(因为都是正数)或者像BN这样的层在网络对这些层的不变性中也同样起作用 。 这使得我们无法进行有意义的比较 。