Skorokhodov I, Burtsev M. Loss Landscape Sightseeing with Multi-Point Optimization.[J]. arXiv: Learning, 2019.

@article{skorokhodov2019loss,

title={Loss Landscape Sightseeing with Multi-Point Optimization.},

author={Skorokhodov, Ivan and Burtsev, Mikhail},

journal={arXiv: Learning},

year={2019}}

现在的任务是, 给出了第一幅图, 这是一只鸟,我们希望loss landscape 表现的同这只鸟一样. 换言之, 这幅图的一个像素点代表了一个相同规模的神经网络的在一网络参数下的损失(或者正确率). 黑色的部分表示这部分的网络我们希望他们能正确识别样本, 白色像素点希望他们错误识别样本. 第三幅图就是通过训练后的正确率的一个热点图.

所以这实际上一种正则化的过程.

主要内容

固定神经网络\(\mathcal{F}\)的模式,给定三组参数\(w_O, w_{right}, w_{up}\), 考虑如下线性组合

\[w_{\alpha, \beta} = w_O + \alpha w_{right} + \beta w_{up},
\]

这里我们视\(\alpha, \beta \in \{0, 1, 2, \ldots\}\), \(w_{\alpha, \beta}\)就是图片中第\((\alpha, \beta)\)个元素(看了作者代码,在实际操作中\(\alpha, \beta\)可以再同乘一个系数).

所以, 样本\(x\), 传入网络\(\mathcal{F}_{\alpha, \beta}\),

\[loss =
\left \{
\begin{array}{ll}
\mathcal{L}(\mathcal{F}_{\alpha, \beta}(x), y) &K(\alpha, \beta) = 1 \\
-\mathcal{L}(\mathcal{F}_{\alpha, \beta}(x), y) &K(\alpha, \beta) = -1 \\
\end{array} \right.
\]

其中\(K(\alpha, \beta)=1\)表示需要正确分类, 反之为不正确分类. 在代码中, 发现作者对\(K(\alpha, \beta)=-1\)的损失额外乘上了一个系数.

在作者的代码中, 并非是按序选择\(\mathcal{F}_{\alpha, \beta}\)的, 而是随机选择.

另外, 并非一定要限制在二维, 作者只是为了便于说明.

此外, 可以通过Schmidt正交法使得\(w_{right}, w_{up}\)正交, 这部分就不讲了(蛮简单的).

代码

作者的代码



"""
这部分相当于是作者代码中的layerops.py
个人认为代码的难点就在于此, 故只重写了这部分
的代码. 作者是完全重新定义Module模块, 我是在
Module的模块上进行修改.
""" import torch
import torch.nn as nn
import torch.nn.functional as F class Modulerebuild(nn.Module):
"""
对Module的部分方法进行重定义, 因为
一般的Module只接受Parameter, 这就要求
网络参数都是叶节点, 这与论文的思路不符
"""
def register_parameter(self, name: str, param):
if '_parameters' not in self.__dict__:
raise AttributeError(
"cannot assign parameter before Module.__init__() call") elif not isinstance(name, torch._six.string_classes):
raise TypeError("parameter name should be a string. "
"Got {}".format(torch.typename(name)))
elif '.' in name:
raise KeyError("parameter name can't contain \".\"")
elif name == '':
raise KeyError("parameter name can't be empty string \"\"")
elif hasattr(self, name) and name not in self._parameters:
raise KeyError("attribute '{}' already exists".format(name)) if param is None:
self._parameters[name] = None
elif not param.requires_grad:
raise ValueError("Invalid parameters, "
"the tensor should requires_grad == True")
else: self._parameters[name] = param def __setattr__(self, name, value):
def remove_from(*dicts):
for d in dicts:
if name in d:
del d[name] params = self.__dict__.get('_parameters')
if isinstance(value, torch.Tensor):
if params is None:
raise AttributeError(
"cannot assign parameters before Module.__init__() call")
remove_from(self.__dict__, self._buffers, self._modules)
self.register_parameter(name, value)
elif params is not None and name in params:
self.register_parameter(name, value)
else:
modules = self.__dict__.get('_modules')
if isinstance(value, Modulerebuild):
if modules is None:
raise AttributeError(
"cannot assign module before Module.__init__() call")
remove_from(self.__dict__, self._parameters, self._buffers)
modules[name] = value
elif modules is not None and name in modules:
if value is not None:
raise TypeError("cannot assign '{}' as child module '{}' "
"(torch.nn.Module or None expected)"
.format(torch.typename(value), name))
modules[name] = value
else:
buffers = self.__dict__.get('_buffers')
if buffers is not None and name in buffers:
if value is not None and not isinstance(value, torch.Tensor):
raise TypeError("cannot assign '{}' as buffer '{}' "
"(torch.Tensor or None expected)"
.format(torch.typename(value), name))
buffers[name] = value
else:
object.__setattr__(self, name, value) def parameters_(self):
"""
对parameters方法进行了重定义, 因为如果直接采用parameters() 结果
会返回空的生成器. 不直接在parameters上重定义的原因是, parameters的
参数设置与parameters_不同...
:return:
"""
for p in self._parameters.values():
yield p
for m in self._modules.values():
for p in m.parameters_():
yield p class Squentialrebuild(Modulerebuild): def __init__(self, *rebs):
super(Squentialrebuild, self).__init__()
self.rebs = rebs
for i, m in enumerate(self.rebs):
self.__setattr__(f'module_{i}', m) def forward(self, x):
for m in self.rebs:
x = m(x) return x def parameters_(self):
print(self._modules.values())
return super(Squentialrebuild, self).parameters() class Linearrebuild(Modulerebuild): def __init__(self, weight, bias=None):
super(Linearrebuild, self).__init__()
self.weight = weight
self.bias = bias def __call__(self, x):
return F.linear(x, self.weight, self.bias) class Conv2drebuild(Modulerebuild): def __init__(self, weight, bias=None, **kwargs):
super(Conv2drebuild, self).__init__()
self.weight = weight
self.bias = bias
self.kwargs = kwargs def forward(self, x):
return F.conv2d(x, self.weight, self.bias, **self.kwargs) class BatchNormrebuild(Modulerebuild): def __init__(self, weight, bias, **kwargs):
super(BatchNormrebuild, self).__init__()
self.weight = weight
self.bias = bias
self.kwargs = kwargs def forward(self, x):
dummy_mean = torch.zeros_like(self.bias)
dummy_var = torch.ones_like(self.weight)
return F.batch_norm(x, dummy_mean, dummy_var,
self.weight, self.bias,
training=True, **self.kwargs) class Net(Modulerebuild): def __init__(self, *rebs):
super(Net, self).__init__()
self.dense = Squentialrebuild(
*rebs
) def forward(self, x):
return self.dense(x) if __name__ == "__main__": parameters = []
rebs = []
weight = torch.rand(10, 2, requires_grad=True)
bias = torch.rand(10, requires_grad=True)
parameters += [weight, bias]
rebs.append(Linearrebuild(weight, bias))
weight = torch.rand(10, requires_grad=True)
bias = torch.rand(10, requires_grad=True)
parameters += [weight, bias]
rebs.append(BatchNormrebuild(weight, bias))
rebs.append(nn.ReLU())
weight = torch.rand(1, 10, requires_grad=True)
bias = torch.rand(1, requires_grad=True)
parameters += [weight, bias]
rebs.append(Linearrebuild(weight, bias + 1)) #注意我们这里传进去的bias+1不是叶节点 net = Net(*rebs)
x = torch.tensor([[1., 2.], [3., 4]])
y = torch.tensor([[1.], [2.]]) criterion = nn.MSELoss()
opti = torch.optim.SGD(parameters, lr=0.001) #虽然net.parameters_()可以获得参数, 但是
#里面的参数并非全是叶结点时, optim依旧无法
#进行更新
print(parameters[-1])
pred = net(x)
loss = criterion(pred, y)
opti.zero_grad()
loss.backward()
opti.step()
print(parameters[-1]) #但是可以发现bias的确发生了变化

Loss Landscape Sightseeing with Multi-Point Optimization的更多相关文章

  1. 损失函数(Loss Function) -1

    http://www.ics.uci.edu/~dramanan/teaching/ics273a_winter08/lectures/lecture14.pdf Loss Function 损失函数 ...

  2. (转) An overview of gradient descent optimization algorithms

    An overview of gradient descent optimization algorithms Table of contents: Gradient descent variants ...

  3. An overview of gradient descent optimization algorithms

    原文地址:An overview of gradient descent optimization algorithms An overview of gradient descent optimiz ...

  4. A Deep Neural Network’s Loss Surface Contains Every Low-dimensional Pattern

    目录 概 相关工作 主要内容 引理1 定理1 定理2 A Deep Neural Network's Loss Surface Contains Every Low-dimensional Patte ...

  5. zz先睹为快:神经网络顶会ICLR 2019论文热点分析

    先睹为快:神经网络顶会ICLR 2019论文热点分析 - lqfarmer的文章 - 知乎 https://zhuanlan.zhihu.com/p/53011934 作者:lqfarmer链接:ht ...

  6. How Do Vision Transformers Work?[2202.06709] - 论文研读系列(2) 个人笔记

    [论文简析]How Do Vision Transformers Work?[2202.06709] 论文题目:How Do Vision Transformers Work? 论文地址:http:/ ...

  7. caffe学习5——Model initialization and Model format

    参考文献 1 用Net::Init().做了两件事:一.绑架所有的layers和blobs,调用 layers’SetUp() 函数.验证全部网络的正确性等一系列琐碎的事.二.初始化时给出一些日志信息 ...

  8. Spring 2017 Assignments3

    一.作业要求 原版:http://cs231n.github.io/assignments2017/assignment3/ 翻译:http://www.mooc.ai/course/268/lear ...

  9. PaddlePaddle实现线性回归

    在本次实验中我们将使用PaddlePaddle来搭建一个简单的线性回归模型,并利用这一模型预测你的储蓄(在某地区)可以购买多大面积的房子.并且在学习模型搭建的过程中,了解到机器学习的若干重要概念,掌握 ...

随机推荐

  1. day33 前端之css

    day33 前端之css css简介 CSS(Cascading Style Sheet,层叠样式表)定义如何显示HTML元素. # 语法结构 选择器 { 属性名1,属性值 属性名2,属性值 } # ...

  2. ASP.NET Core中使用固定窗口限流

    算法原理 固定窗口算法又称计数器算法,是一种简单的限流算法.在单位时间内设定一个阈值和一个计数值,每收到一个请求则计数值加一,如果计数值超过阈值则触发限流,如果达不到则请求正常处理,进入下一个单位时间 ...

  3. 练习1--爬取btc论坛的title和相应的url

    爬不到此论坛的html源码,应该涉及到反爬技术,以后再来解决,代码如下 import requests from lxml import etree import json class BtcSpid ...

  4. ORACLE中dual用法详解

    基本上oracle引入dual为的就是符合语法1. 我们先从名称来说,dual不是缩写词,本身就是完整的单词.dual名词意思是对数,做形容词时是指二重的,二元的.2. Oracle中的dual表是一 ...

  5. clickhouse客户端使用

    测试初始化 clickhouse-client -m create database if not exists test; use test; drop table test; create tab ...

  6. OSGI与Spring结合开发web工程

    简介: 作为一个新的事实上的工业标准,OSGi 已经受到了广泛的关注, 其面向服务(接口)的基本思想和动态模块部署的能力, 是企业级应用长期以来一直追求的目标.Spring 是一个著名的 轻量级 J2 ...

  7. 【Linux】【Commands】文件管理工具

    文件管理工具:cp, mv, rm cp命令:copy 源文件:目标文件 单源复制:cp [OPTION]... [-T] SOURCE DEST 多源复制:cp [OPTION]... SOURCE ...

  8. ubuntu 使用mysql

    一: 安装: sudo apt-get install mysql-serversudo apt-get install mysql-clientsudo apt-get install libmys ...

  9. 程序员Meme 第02期

  10. mysqldump备份容灾脚本

    目录 一.备份脚本 环境需求 全量脚本 增量脚本 二.备份策略 三.容灾测试 准备 测试 误删除 一.备份脚本 环境需求 编辑/etc/my.cnf文件添加在[mysqld]版块下添加如下变量,添加后 ...