专栏首页大数据文摘听,是梯度的声音!用听觉监控神经网络训练,边听音乐边炼丹

听,是梯度的声音!用听觉监控神经网络训练,边听音乐边炼丹

大数据文摘出品

作者:钱天培、魏子敏

训练神经网络是个极为枯燥的工作。与其盯着Learning Curves发呆,或许可以调动一下其他感官,一起做点更有意思的事情。

比如说,眼睛看久了,可以让耳朵也活动活动。

一位酷爱弹吉他的数据科学家就希望,在调参时把其他器官也调动起来共同监督神经网络的训练。

他用一段程序将神经网络训练时的梯度转化成音频,这样,你就可以通过听不同的声音模式知晓训练情况。

先来一段我们制作的小样——梯度的声音!

听出来了嘛?这可是Adam optimizer的弹拨下,梯度发出的声音。

umm没错,确实很难听... 不过先别急着下结论,因为... 更难听的还在后头呢……

把梯度训练变成声音,边听音乐边炼丹

通常,我们需要通过测量许多不同的指标来完成训练,例如准确度、损失、梯度等。多数调参工程师会选择将这些指标整合,并在TensorBoard上绘制可视化图。

而这位名叫Christian S. Perone的数据科学家就厌倦了一直盯着各种参数的传统训练方式,经常玩音乐的他开发了一个小系统,把梯度训练变成声音,并且发布了全部120行代码。

Christian S. Perone也是位吉他手

他用一段程序将神经网络训练时的梯度转化成音频,通过听不同的声音模式就知道训练情况。

这是个讨巧的训练监督方式,毕竟,听觉是目前在神经网络训练中很少被用到的感官。而事实上,人类的听觉感官也非常敏锐,可以非常好地区分非常小的特征,例如节奏和音调,即便是很微小或者短暂的变动,人们也很容易有直观的感受。

先一起来看几个非常简单的训练例子。

以下的几段声音显示了我们使用每层的梯度范数进行的合成声音,以及使用不同设置(如不同学习率、优化器、动量)对MNIST进行卷积神经网络训练的训练步骤等。

因为微信编辑限制,每篇文章只能插入一段音频,我们将后三段声音转化成了视频,请大家点击收听。

使用LR 0.01训练声音与SGD

此段表示,在第一个epoch的前200个step中使用batch size为10的训练结果。我们选取了0.01的learning rate。音高越高,层的范数(norm)就越高,不同批次之前我们插入了短暂的静音。注意渐变在时间内增加。

使用LR 0.1训练声音与SGD

与上述相同,但我们把learning rate调高到了0.1。

使用LR 1.0训练声音与SGD

与上述相同,但是学习率更高,梯度爆炸并最后发散了,注意高音。嗯,听到最后觉得这个网络大概是死了吧,

使用LR 1.0和BS 256训练声音与SGD

相同的设置,但学习率高达1.0,批量大小为256.注意渐变如何爆炸,然后有NaNs导致最终声音。

这货真的有用吗?

花了这么大力气,我就想知道,靠耳朵调参真的靠谱吗?

没错,如你所料,可能没什么卵用。虽然在上面的例子中,我们可以很明显得听出不同参数的差别,但这些例子都是比较极端的情况。

所以,为什么还要制作这些音频呢?

大概是因为,调参真的是太无聊了吧。

开源代码,自己动手试试吧!

最后,还是放上Christian发布的完整开源代码,你需要安装PyAudio和PyTorch来运行代码。感兴趣的读者,不妨自己试试看。

import pyaudio
import numpy as np
import wave

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms

class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 20, 5, 1)
self.conv2 = nn.Conv2d(20, 50, 5, 1)
self.fc1 = nn.Linear(4*4*50, 500)
self.fc2 = nn.Linear(500, 10)

self.ordered_layers = [self.conv1,
self.conv2,
self.fc1,
self.fc2]

def forward(self, x):
x = F.relu(self.conv1(x))
x = F.max_pool2d(x, 2, 2)
x = F.relu(self.conv2(x))
x = F.max_pool2d(x, 2, 2)
x = x.view(-1, 4*4*50)
x = F.relu(self.fc1(x))
x = self.fc2(x)
return F.log_softmax(x, dim=1)

def open_stream(fs):
p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paFloat32,
channels=1,
rate=fs,
output=True)
return p, stream

def generate_tone(fs, freq, duration):
npsin = np.sin(2 * np.pi * np.arange(fs*duration) * freq / fs)
samples = npsin.astype(np.float32)
return 0.1 * samples

def train(model, device, train_loader, optimizer, epoch):
model.train()

fs = 44100
duration = 0.01
f = 200.0
p, stream = open_stream(fs)

frames = []

for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device)
optimizer.zero_grad()
output = model(data)
loss = F.nll_loss(output, target)
loss.backward()


norms = []
for layer in model.ordered_layers:
norm_grad = layer.weight.grad.norm()
norms.append(norm_grad)

tone = f + ((norm_grad.numpy()) * 100.0)
tone = tone.astype(np.float32)
samples = generate_tone(fs, tone, duration)

frames.append(samples)

silence = np.zeros(samples.shape[0] * 2,
dtype=np.float32)
frames.append(silence)

optimizer.step()

# Just 200 steps per epoach
if batch_idx == 200:
break

wf = wave.open("sgd_lr_1_0_bs256.wav", 'wb')
wf.setnchannels(1)
wf.setsampwidth(p.get_sample_size(pyaudio.paFloat32))
wf.setframerate(fs)
wf.writeframes(b''.join(frames))
wf.close()

stream.stop_stream()
stream.close()
p.terminate()

def run_main():
device = torch.device("cpu")

train_loader = torch.utils.data.DataLoader(
datasets.MNIST('../data', train=True, download=True,
transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])),
batch_size=256, shuffle=True)

model = Net().to(device)
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)

for epoch in range(1, 2):
train(model, device, train_loader, optimizer, epoch)

if __name__ == "__main__":
run_main()

相关报道:

http://blog.christianperone.com/2019/08/listening-to-the-neural-network-gradient-norms-during-training/

实习/全职编辑记者招聘ing

加入我们,亲身体验一家专业科技媒体采写的每个细节,在最有前景的行业,和一群遍布全球最优秀的人一起成长。坐标北京·清华东门,在大数据文摘主页对话页回复“招聘”了解详情。简历请直接发送至zz@bigdatadigest.cn

本文分享自微信公众号 - 大数据文摘(BigDataDigest),作者:文摘菌

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-08-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 判菜系、调众囗、打分数,这一回,我们用大数据烧菜?

    年前,文摘菌曾经扒下了全网所有“年夜饭”菜谱,找到了最有年味的一道菜的一文,对于菜谱数据分析产生了浓厚的兴趣,遂自己也写了个爬虫爬取了某美食网站的一些精选菜谱和...

    大数据文摘
  • 百闻不如一码!手把手教你用Python搭一个Transformer

    与基于RNN的方法相比,Transformer 不需要循环,主要是由Attention 机制组成,因而可以充分利用python的高效线性代数函数库,大量节省训练...

    大数据文摘
  • DOTA2获胜的AI比AlphaGo厉害?还是媒体和马斯克在联合炒作?

    大数据文摘
  • 亲耳“听见”神经网络的声音:梯度变化一听即可辨别(附代码)

    网友做了一个非常有趣的实验:将每个神经网络层梯度范式转换成了一个音调,这样人类就可以凭借听觉,来很好的分辨出非常小的干扰,比如节奏和音调。

    代码医生工作室
  • 亲耳“听见”神经网络的声音:梯度变化一听即可辨别(附代码)

    网友做了一个非常有趣的实验:将每个神经网络层梯度范式转换成了一个音调,这样人类就可以凭借听觉,来很好的分辨出非常小的干扰,比如节奏和音调。

    新智元
  • python3小游戏(1):吃苹果小游戏

    (1).可以通过键盘的上下左右四个键来控制主人公小刘的位置(同是移动方向不同,小刘的姿势也不同)

    py3study
  • Linux学习_012_Centos 6.8 安装 Netcat

    2、解压缩文件到指定目录(注意:要先创建 /opt/module/netcat/ 目录)

    黑泽君
  • Gradle 任务访问文件的几种方式

    文件树是按层次结构排序的文件集合。例如,文件树可能表示一个目录树或 ZIP 文件的内容。它通过 FileTree 接口表示。FileTree 接口继承自 Fil...

    Jerry Wang
  • BAT面试题43:log(n)时间复杂度下求n次幂

    https://blog.csdn.net/weixin_42292229/article/details/86742650

    double
  • Python 之异常处理

      在Python中不同的异常可以用不同的类型(Python中统一了类与类型,类型即使类)去标识,不同的类对象标识不同的异常,一个异常标识一种错误。

    py3study

扫码关注云+社区

领取腾讯云代金券