pytorch tensor 初始化_浅析对比Tensorflow与PyTorch实现Layer初始化

本帖最后由 levycui 于 2019-7-23 18:53 编辑

问题导读:

1、如何理解Linear层初始化?

2、如何理解实现Conv层?

3、如何理解实现RNN层?4、如何使用Tensorflow初始化?

聊起初始化,大家应该都了解大名鼎鼎的Glorot初始化(也叫Xavier初始化),Kaiming初始化(也叫He初始化)。

0. 起因

之前调了一个模型,原作者是使用Tensorflow实现的,我在复现过程中使用了PyTorch,虽然已经尽可能注意二者的差异,但是效果始终差那么点。后来想到,或许是因为二者层初始化不同所导致的(虽然最终证明不是……),在这个过程中,总结了一点有意义的内容,这里和大家分享。

1. PyTorch初始化方法

首先我们来看一下PyTorch中初始化的方法,此处我们只关心平时最常使用到的3类操作:Linear,Conv,以及RNN。

1.1. Linear层初始化

2019-07-23_183830.jpg (130.46 KB, 下载次数: 5)

2019-7-23 18:40 上传

2019-07-23_184050.jpg (62.45 KB, 下载次数: 8)

2019-7-23 18:40 上传

[mw_shl_code=python,true]import numpy as np

import matplotlib.pyplot as plt

import torch

import torch.nn as nn

# ============================================================

# Check PyTorch Initialization (conv2d / linear / lstm).

# ============================================================

# --------------------

# 1.1. PyTorch Linear

# --------------------

dummy_linear = nn.Linear(100, 250)

layer = dummy_linear

layer_w = layer.weight    # Should be U(-0.1, 0.1)

layer_w = layer_w.detach()

layer_w_np = layer_w.numpy()

layer_w_np = np.reshape(layer_w_np, [-1])

print(layer_w_np.shape)

fig, ax = plt.subplots()

ax.hist(layer_w_np, bins=10)

ax.set_title("PyTorch Linear Initialization")

plt.show()[/mw_shl_code]

2019-07-23_184125.jpg (38.2 KB, 下载次数: 5)

2019-7-23 18:41 上传

1.2 Conv层

2019-07-23_184153.jpg (126.46 KB, 下载次数: 8)

2019-7-23 18:42 上传

2019-07-23_184214.jpg (69.16 KB, 下载次数: 6)

2019-7-23 18:42 上传

其实比较奇怪的是,在这两个例子里,我们的bias也用相同的方法进行了初始化。在我的印象中,bias要不然就是使用全0进行costant初始化,要不然就是直接不加bias,今天得亏是看了文档,才知道在PyTorch里面,bias是默认使用相同的方式进行初始化的。

[mw_shl_code=python,true]import numpy as np

import matplotlib.pyplot as plt

import torch

import torch.nn as nn

# --------------------

# 1.2. PyTorch Conv2d

# --------------------

dummy_conv = nn.Conv2d(25, 64, 2)

layer = dummy_conv

layer_w = layer.weight    # Should be U(-0.1, 0.1)

layer_w = layer_w.detach()

layer_w_np = layer_w.numpy()

layer_w_np = np.reshape(layer_w_np, [-1])

print(layer_w_np.shape)

fig, ax = plt.subplots()

ax.hist(layer_w_np, bins=10)

ax.set_title("PyTorch Conv2d Initialization")

plt.show()[/mw_shl_code]

分布图如下:

2019-07-23_184241.jpg (36.25 KB, 下载次数: 5)

2019-7-23 18:42 上传

1.3. RNN层

终于来到RNN层了,其实我的本意也就是看看两个框架初始化是不是一样,那快开始吧。

2019-07-23_184306.jpg (201.65 KB, 下载次数: 6)

2019-7-23 18:43 上传

2019-07-23_184323.jpg (56.14 KB, 下载次数: 6)

2019-7-23 18:43 上传

2019-07-23_184338.jpg (19.93 KB, 下载次数: 8)

2019-7-23 18:43 上传

[mw_shl_code=python,true]# --------------------

# 1.3. PyTorch GRUCell

# --------------------

dummy_gru_cell = nn.GRUCell(input_size=50, hidden_size=100)

layer = dummy_gru_cell

layer_w = layer.weight_hh    # Should be U(-0.1, 0.1)

layer_w = layer_w.detach()

layer_w_np = layer_w.numpy()

layer_w_np = np.reshape(layer_w_np, [-1])

print(layer_w_np.shape)

fig, ax = plt.subplots()

ax.hist(layer_w_np, bins=10)

ax.set_title("PyTorch GRUCell Initialization")

plt.show()[/mw_shl_code]

2019-07-23_184409.jpg (34.85 KB, 下载次数: 6)

2019-7-23 18:44 上传

小结:

PyTorch有一套自己的初始化方法,这个东西不完全是Glorot初始化,我们就管它叫类Glorot初始化吧,嗯,类Glorot_uniform初始化。

然后上面几个代码也再简单不过,我只是卡了一下,总是让它的weight分布是一个从-0.1到0.1的一个均匀分布。

2019-07-23_184437.jpg (48.45 KB, 下载次数: 5)

2019-7-23 18:44 上传

2. Tensorflow初始化

撒花,终于到2了!尽管今年已经是2019年,但tensorflow的文档还是一言难尽,读者经常需要dive into source code才能知道你到底想要干嘛。与之相对应,PyTorch的文档就友好很多。怎么说呢,我感觉读者,一方面,其实不想知道太底层的东西,另一方面,拜托您别封装的那么死,我们不是要的不是fit一下就完的东西。

尽管tf1.x已经日趋式微,不过这边我们还是用的是tf1.x版本进行实验。

2.0. tf.get_variable

上面PyTorch是没有这一节的,不过考虑到Tensorflow里面所有的layer的变量声明,实际上都使用的是tf.get_variable这个API,我们有必要做一个简单的查看。

换句话讲,你个tf.get_variable搞明白了,后续那些层,甚至不用再看。

看一下源码,反正文档是指不上了,在variable_scope.py里面,给了下面一句话:

If initializer is `None` (the default), the default initializer passed in the variable scope will be used. If that one is `None` too, a `glorot_uniform_initializer` will be used. The initializer can also be a Tensor, in which case the variable is initialized to this value and shape.

2019-07-23_184518.jpg (39.76 KB, 下载次数: 6)

2019-7-23 18:45 上传

例1. tf.get_variable,二维情况。

[mw_shl_code=python,true]import os

import numpy as np

import matplotlib.pyplot as plt

import tensorflow as tf

# ============================================================

# Check Tensorflow Initialization (conv2d / linear / lstm).

# ============================================================

print(tf.__version__)

os.environ['CUDA_VISIBLE_DEVICES'] = '7'

# --------------------

# 2.0. PyTorch GRUCell

# --------------------

w_2d = tf.get_variable('w_2d', shape=[240, 360])

init = tf.global_variables_initializer()

# --------------------

# Executation

# --------------------

config = tf.ConfigProto()

config.gpu_options.allow_growth = True

with tf.Session(config=config) as sess:

sess.run(init)

w_2d_eval = sess.run(w_2d)

print(w_2d_eval.shape)

layer_w_np = np.reshape(w_2d_eval, [-1])

print(layer_w_np.shape)

fig, ax = plt.subplots()

ax.hist(layer_w_np, bins=30)

ax.set_title("Tensorflow get_variable 2D initialization")

plt.show()[/mw_shl_code]

2019-07-23_184548.jpg (51.27 KB, 下载次数: 5)

2019-7-23 18:45 上传

例2. tf.get_variable,三维情况,新增的维度在前。

2019-07-23_184616.jpg (83.96 KB, 下载次数: 6)

2019-7-23 18:46 上传

[mw_shl_code=python,true]import os

import numpy as np

import matplotlib.pyplot as plt

import tensorflow as tf

# ============================================================

# Check Tensorflow Initialization (conv2d / linear / lstm).

# ============================================================

print(tf.__version__)

os.environ['CUDA_VISIBLE_DEVICES'] = '7'

# --------------------

# 2.0. PyTorch GRUCell

# --------------------

w_2d = tf.get_variable('w_2d', shape=[100, 240, 360])

init = tf.global_variables_initializer()

# --------------------

# Executation

# --------------------

config = tf.ConfigProto()

config.gpu_options.allow_growth = True

with tf.Session(config=config) as sess:

sess.run(init)

w_2d_eval = sess.run(w_2d)

print(w_2d_eval.shape)

layer_w_np = np.reshape(w_2d_eval, [-1])

print(layer_w_np.shape)

fig, ax = plt.subplots()

ax.hist(layer_w_np, bins=30)

ax.set_title("Tensorflow get_variable 3D initialization")

plt.show()[/mw_shl_code]

2019-07-23_184639.jpg (33.02 KB, 下载次数: 8)

2019-7-23 18:46 上传

2019-07-23_184656.jpg (45.2 KB, 下载次数: 6)

2019-7-23 18:47 上传

2019-07-23_184712.jpg (32.06 KB, 下载次数: 7)

2019-7-23 18:47 上传

完全吻合!

2019-07-23_184742.jpg (65.6 KB, 下载次数: 6)

2019-7-23 18:47 上传

好了,我觉得现在可以总结一下了:

2019-07-23_184807.jpg (97.77 KB, 下载次数: 7)

2019-7-23 18:48 上传

其实还想写一下,不过已经发现没必要了,因为在Tensorflow里面,所有变量的申请都使用tf.get_variable这个API,换言之,Tensorflow不会像PyTorch一样根据不同的层,采取不同的初始化策略。所以你只要知道变量的shape,那么按照上面的法则,你就知道它遵循一个什么分布了。

作者:李斌

来源:https://zhuanlan.zhihu.com/p/72853886

最新经典文章,欢迎关注公众号

你可能感兴趣的:(pytorch,tensor,初始化)