来源:Reddit 等 编辑:金磊、鹏飞
【新智元导读】训练神经网络可以用听的!Reddit 网友做了一个非常有趣的实验:将每个神经网络层梯度范式转换成了一个音调,这样人类就可以凭借听觉,来很好的分辨出非常小的干扰,比如节奏和音调。
训练神经网络还可以用“听”的!
网友做了一个非常有趣的实验:将每个神经网络层梯度范式转换成了一个音调,这样人类就可以凭借听觉,来很好的分辨出非常小的干扰,比如节奏和音调。
以往,我们在训练神经网络的时候,通常会测量许多不同的指标,例如精度、损失以及梯度等等。这些工作大部分是在 TensorBoard 上聚合上述度量指标并且绘制可视化。
但除了视觉之外,有 Reddit 网友提出:用听觉也可以监控神经网络的训练!
博客地址:
http://blog.christianperone.com/2019/08/listening-to-the-neural-network-gradient-norms-during-training/
声音是目前神经网络训练中研究较少的一个方向。人类的听觉可以很好的分辨出非常小的干扰(即使这些干扰时间很短或很细微),比如节奏和音高。
在这个实验中,研究者做了一个非常简单的例子,显示了使用每层的梯度范数进行的合成声音,以及使用不同设置(如不同学习率、优化器,动量等)对 MNIST 进行卷积神经网络训练的步骤等。
看到这个结果,Reddit 网友嗨了,纷纷开发脑洞。
MLApprentice:
这真太了不起了。我一直在寻找直观体验渐变的方法,我觉得只看直方图时很难注意到训练模式。你有没有想过用图层深度来控制音高并使用音量来表示规范呢?这样我们光靠听音高就能知道是第几层了。
klaysDoodle:
10 层网络以后,我聋了
MLApprentice:
楼上你太搞笑了。你可以将深度标准化,使其保持在人类听觉范围内就可以。
gohu_cd:
很有意思!我想知道这是否有助于调试神经网络训练。因为其中存在不同的加权损失,甚至是对抗的(例如 GAN)。因为视觉和听觉都是感官,查看图表或听觉声音应该具有相同数量的信息。可以用对应于加权梯度的所有声音创建一个“交响乐”,也许这对于确定每个损失的正确权重是有用的。
在下文给出的实验中,你需要安装 PyAudio 和 PyTorch 来运行代码。
如下训练神经网络的声音可跳转至下方链接听:
http://blog.christianperone.com/2019/08/listening-to-the-neural-network-gradient-norms-during-training/
用 LR 0.01 和 SGD 训练声音
下面这个音频片段表示在第一个 epoch 的前 200 步中使用 4 个层的梯度,并使用 10 个 batche 大小的训练会话。音高越高,一个神经网络层的标准值就越高,不同的 batche 之间会有短暂的静音。
用 LR 0.1 的 SGD 训练声音
同上,但是学习率更高了。
用 LR 1.0 的 SGD 训练声音
同上,但是随着学习率的提高,神经网络产生发散(diverge)。
用 LR 1.0、BS 256 的 SGD 训练声音
设置是相同的,但是学习率高达 1.0,batche 大小为 256。
用 LR 0.01 的 Adam 训练声音
与 SGD 的设置相同,但使用的是 Adam。
二、源代码展示
以下是实验的全部源代码,有兴趣的读者可以上手试一下。
1 import pyaudio 2 import numpy as np 3 import wave 4 5 import torch 6 import torch.nn as nn 7 import torch.nn.functional as F 8 import torch.optim as optim 9 from torchvision import datasets, transforms 10 11 12 class Net (nn.Module): 13 def __init__(self): 14 super (Net, self).__init__() 15 self.conv1 = nn.Conv2d (1, 20, 5, 1) 16 self.conv2 = nn.Conv2d (20, 50, 5, 1) 17 self.fc1 = nn.Linear (4*4*50, 500) 18 self.fc2 = nn.Linear (500, 10) 19 20 self.ordered_layers = [self.conv1, 21 self.conv2, 22 self.fc1, 23 self.fc2] 24 25 def forward (self, x): 26 x = F.relu (self.conv1(x)) 27 x = F.max_pool2d (x, 2, 2) 28 x = F.relu (self.conv2(x)) 29 x = F.max_pool2d (x, 2, 2) 30 x = x.view (-1, 4*4*50) 31 x = F.relu (self.fc1(x)) 32 x = self.fc2(x) 33 return F.log_softmax (x, dim=1) 34 35 36 def open_stream (fs): 37 p = pyaudio.PyAudio () 38 stream = p.open (format=pyaudio.paFloat32, 39 channels=1, 40 rate=fs, 41 output=True) 42 return p, stream 43 44 45 def generate_tone (fs, freq, duration): 46 npsin = np.sin (2 * np.pi * np.arange (fs*duration) * freq / fs) 47 samples = npsin.astype (np.float32) 48 return 0.1 * samples 49 50 51 def train (model, device, train_loader, optimizer, epoch): 52 model.train () 53 54 fs = 44100 55 duration = 0.01 56 f = 200.0 57 p, stream = open_stream (fs) 58 59 frames = [] 60 61 for batch_idx, (data, target) in enumerate (train_loader): 62 data, target = data.to (device), target.to (device) 63 optimizer.zero_grad () 64 output = model (data) 65 loss = F.nll_loss (output, target) 66 loss.backward () 67 68 norms = [] 69 for layer in model.ordered_layers: 70 norm_grad = layer.weight.grad.norm () 71 norms.append (norm_grad) 72 73 tone = f + ((norm_grad.numpy ()) * 100.0) 74 tone = tone.astype (np.float32) 75 samples = generate_tone (fs, tone, duration) 76 77 frames.append (samples) 78 79 silence = np.zeros (samples.shape[0] * 2, 80 dtype=np.float32) 81 frames.append (silence) 82 83 optimizer.step () 84 85 # Just 200 steps per epoach 86 if batch_idx == 200: 87 break 88 89 wf = wave.open ("sgd_lr_1_0_bs256.wav", 'wb') 90 wf.setnchannels (1) 91 wf.setsampwidth (p.get_sample_size (pyaudio.paFloat32)) 92 wf.setframerate (fs) 93 wf.writeframes (b''.join (frames)) 94 wf.close () 95 96 stream.stop_stream () 97 stream.close () 98 p.terminate () 99 100 101 def run_main (): 102 device = torch.device ("cpu") 103 104 train_loader = torch.utils.data.DataLoader ( 105 datasets.MNIST ('../data', train=True, download=True, 106 transform=transforms.Compose ([ 107 transforms.ToTensor (), 108 transforms.Normalize ((0.1307,), (0.3081,)) 109 ])), 110 batch_size=256, shuffle=True) 111 112 model = Net () .to (device) 113 optimizer = optim.SGD (model.parameters (), lr=0.01, momentum=0.5) 114 115 for epoch in range (1, 2): 116 train (model, device, train_loader, optimizer, epoch) 117 118 119 if __name__ == "__main__": 120 run_main ()
Reddit 地址:
https://www.reddit.com/r/MachineLearning/comments/clyzgx/p_listening_to_the_neural_network_gradient_norms/
博客:
http://blog.christianperone.com/2019/08/listening-to-the-neural-network-gradient-norms-during-training/