模型参数的访问、初始化和共享 讨论区


#85

如果第一层 和 第三层 共享参数w,对w求导,类似于求全导数。
https://baike.baidu.com/item/全导数/7146883?fr=aladdin

假设不共享的时候,第一层参数w1的导数为w1_grad,第二层参数w2的导数为w2_grad。
参数共享之后,w1和w2变为同一个自变量,这个自变量的导数为“w1_grad + w2_grad”。
编程验证方法:
建立两个网络,net1 和 net2.
net1 和 net2 的结构相同,参数初始值相同,loss相同,输入的x相同。
唯一不同的是:
(1)net1 每一层参数都是独立的。
第一层参数为w1,第三层参数为w3。w1 和 w3 数值相等,但是分别占用不同的存储空间。
(2)net2的 第一层 和 第三层 共享参数。
第一层参数 和 第三层参数 都是为w。并且设置 w = w1 = w3。
对两个网络定义相同的loss,然后采用相同的输入x,进行 前向传播 和 后向传播。
然后查看各个参数的grad。
预期结果:w.grad == w1.grad +w2.grad。

下面这段程序打印的结果验证了上述猜测是正确的。

from mxnet import autograd, nd
from mxnet.gluon import loss as gloss

# 生成测试数据
X = nd.random.uniform(shape=(2, 20))
y = nd.random.uniform(shape=(2, 10))

# 创建共享参数的网络
# 第二隐藏层(shared变量)和第三隐藏层共享模型参数
net_shared = nn.Sequential()
shared = nn.Dense(8, activation='relu')
net_shared.add(nn.Dense(8, activation='relu'),
               shared,
               nn.Dense(8, activation='relu', params=shared.params),
               nn.Dense(10))

# 创建普与参数共享网络结构相同的普通网络
net_woShared = nn.Sequential()
net_woShared.add(nn.Dense(8, activation='relu'),
                 nn.Dense(8, activation='relu'),
                 nn.Dense(8, activation='relu'),
                 nn.Dense(10))

# 初始化网络,并进行前向传播
net_shared.initialize()
y_shared_hat = net_shared(X)

net_woShared.initialize()
y_woShared_hat = net_woShared(X)

# 两个网络参数不同,所以前向传播的结果不相同。
print('y_woShared_hat == y_shared_hat')
print(y_woShared_hat == y_shared_hat)


# 修改普通网络的参数,使其与 共享参数网络 中的参数相同。
net_woShared[0].weight.set_data(net_shared[0].weight.data())
net_woShared[0].bias.set_data(net_shared[0].bias.data())
net_woShared[1].weight.set_data(net_shared[1].weight.data())
net_woShared[1].bias.set_data(net_shared[1].bias.data())
net_woShared[2].weight.set_data(net_shared[2].weight.data())
net_woShared[2].bias.set_data(net_shared[2].bias.data())
net_woShared[3].weight.set_data(net_shared[3].weight.data())
net_woShared[3].bias.set_data(net_shared[3].bias.data())

# 修改参数之后,再一次前向传播
y_woShared_hat = net_woShared(X)

# 两个网络的参数相同,所以前向传播的结果相同。
y_woShared_hat == y_shared_hat
print('y_woShared_hat == y_shared_hat')
print(y_woShared_hat == y_shared_hat)


# 定义损失函数
loss = gloss.L2Loss()

# 先进行前向传播,然后后向传播计算梯度
with autograd.record():
    l = loss(net_woShared(X), y)
l.backward()

# 先进行前向传播,然后后向传播计算梯度
with autograd.record():
    l = loss(net_shared(X), y)
l.backward()

# 参数共享网络第二隐藏层的梯度 等于 非参数共享网络中 第二隐藏层和第三隐藏层的梯度 相加
net_shared[1].weight.grad() == net_woShared[1].weight.grad()  + net_woShared[2].weight.grad() 
print('net_shared[1].weight.grad() == net_woShared[1].weight.grad()  + net_woShared[2].weight.grad() ')
print(net_shared[1].weight.grad() == net_woShared[1].weight.grad()  + net_woShared[2].weight.grad() )


#86

from mxnet import init, nd
from mxnet.gluon import nn
net = nn.Sequential()
net.add(nn.Dense(256, activation=‘relu’))
net.add(nn.Dense(10))
net.initialize() # 使用默认初始化方式。
x = nd.random.uniform(shape=(2, 20))
y = net(x) # 前向计算。

定义好上述网络后, 查看以下两项:
net[0].params, type(net[0].params)

输出为: (dense0_ (
Parameter dense0_weight (shape=(256, 20), dtype=float32)
Parameter dense0_bias (shape=(256,), dtype=float32)
), mxnet.gluon.parameter.ParameterDict)

为什么输出的dense0_weight 的shape是(256,20)?输入的shape是(2,20), 那么与输入连接的那一层不应该是(20,256)吗


#87

所以请问下正确的bias初始化应该怎么写呢


#88

个人理解:可能代码实现的时候 y = Wx.T+b,而不是 y = xW+b,所以 W 是 (num, num_input)
Dense 类的__init__方法中:
self.weight = self.params.get(‘weight’, shape=(units, in_units),
init=weight_initializer, dtype=dtype,
allow_deferred_init=True)
其中 shape 大小是
shape=(units, in_units)


#89

感觉不太对,只看这一句的话:
假设不共享的时候,第一层参数w1的导数为w1_grad,第二层参数w2的导数为w2_grad。
参数共享之后,w1和w2变为同一个自变量,这个自变量的导数为“w1_grad + w2_grad”。

感觉自变量的导数应该为 w1_grad 或者 w2_grad


#90

是不是可以这样解释呢?
不共享的时候,假设第一层参数w1的导数为3,假设第二层参数w2的导数为4。
参数共享之后,w1和w2变为同一个自变量,这个自变量的导数为“3 +4=7”。


#91

参数共享 应该是在 构建网络的时候 定好的,这种 在 网络运算途中 把 w1和w2 变为同一变量 应该需要 人工编写代码介入


#92

老师你好 请问在训练过程中 如果我想得到输出层(比如FC1)到前面某一个卷积层(conv0)的梯度 需要怎么写代码 能不能给一个例子学习下


#93

求助~~~~
初始化权重之后,第一次的结果和第二次的结果不一样,gpu
但用cpu是一样的
求助,感觉自己忽略了啥

from mxnet import gluon, image, init, nd, autograd, gpu, cpu
from mxnet.gluon import data as gdata, loss as gloss, model_zoo, nn
import numpy as np
import  mxnet as mx

ctx = gpu(0)
net = nn.HybridSequential()
net.add(
    nn.Conv2D(in_channels=3, channels=48, kernel_size=3,
              strides=1, padding=1, use_bias=False),
    nn.BatchNorm(momentum=0.1, in_channels=48),
    nn.LeakyReLU(alpha=0.2),
    nn.Conv2DTranspose(in_channels=48, channels=6, kernel_size=3,
                       strides=2, padding=1, output_padding=1, use_bias=False)
)

net.collect_params('.*gamma|.*running_var').initialize(mx.init.Constant(1), ctx=ctx)
net.collect_params('.*beta|.*bias|.*running_mean').initialize(mx.init.Constant(0),ctx=ctx)
net.collect_params('.*weight').initialize(init=mx.init.Constant(1),ctx=ctx)

x=nd.ones((1,3,6,6))



with autograd.record():
    y = net(x.as_in_context(ctx))
    # np.save('dd', y.asnumpy())

    s_pred = np.load('dd.npy')
    t_pred = y.asnumpy()
    sub = s_pred - t_pred
    print (sub.sum())

#94

感觉式子应该是y = XW.T+b把?X输入的时候行数是样本数,输出的y行数应该也是样本数才方便下一层或者打印时保持形状吧?


#95

Parameter dense0_weight (shape=(256, 20)
W的形状不应该是(20, 256)吗?


#96

bias的初始化怎么使用一个numpy矩阵来初始化


#97

感觉很有可能是这样,希望哪位大佬出来解答一下