自动求梯度 讨论区


#42

如果头梯度只是求导前面提出来的一个系数,那么就是等于head_gradient * x.grad. 那么也就是个语法糖吧,为什么要把头梯度作为很大条的东西放在参数里面呢?


#43

例子可以看这儿:

同样的代码, 我在 Ubuntu16.04 python3.6 mxnet 1.1.0 cuda8.0 cudnn6.0 就报错


#44

如果是一个值[3], 这就是一个标量,如果是[3, 5], 这就是向量吧。不是w是一个二维数组,而是输入X是一个二维数组。不过不知道为什么我运行nd.sum(z).backward()会报错。你有正确运行吗?


#45
with ag.record():
    y = x * 2
    z = y * x
    nd.sum(z).backward() 

nd.sum(z).backward()必须在with的范围里,否则会报错[14:45:56] C:\projects\mxnet-distro-win\mxnet-build\src\imperative\imperative.cc:375: Check failed: !AGInfo::IsNone(*i) Cannot differentiate node because it is not in a computational graph. You need to set is_recording to true or use autograd.record() to save computational graphs for backward. If you want to differentiate the same graph twice, you need to pass retain_graph=True to backward

但是z.backward()就可以不在with的范围里,不清楚什么原理

 with ag.record():
    y = x * 2
    z = y * x

z.backward()

#46

1.x.attach_grad() 是在内存中划分一块地来放梯度,如果是同一个变量,且shape不变,只需申请一次即可
2.
x = nd.random_normal(shape=(3))
print(x)
with autograd.record():
for i in range(0, 10, 1):
x = x*2
x.attach_grad()
y = x * 2
z = y * x
z.backward(retain_graph= True)
print(x.grad)
可以利用同一个graph运算梯度
但是仍有很多疑问,为什么需要每次运行attach_grad(),print(id(x.attach_grad())发现地址没有改变,不解


#47

学习这一章节,无意中发现求梯度的时候好像有数值进位的问题,具体例子:

from mxnet import autograd, nd
x = nd.array([1, 2, 3, 4, 5, 6])
a = nd.array([0.99999999])
x.attach_grad()
with autograd.record():
y = a * x
y.backward()
print y
print x.grad

输出:
[1. 2. 3. 4. 5. 6.]
<NDArray 6 @cpu(0)>

[1. 1. 1. 1. 1. 1.]
<NDArray 6 @cpu(0)>

不知道是不是环境问题,macOS,Python 2.7.13 |Anaconda custom (x86_64)| GCC 4.2.1 Compatible Clang 4.0.1 (tags/RELEASE_401/final)] on darwin,mxnet:1.1.0


#48

在autograd.record()下面 out = net(data)输出后,又对out进行了一个矩阵变换的操作:
def PS(X, r):
Xc = nd.split(X, num_outputs=3, axis=1)
X = nd.concatenate([phase_shift(x, r) for x in Xc], axis=1)
return X

def phase_shift(I, r):
bsize, a, b, c = list(I.shape)
X = nd.reshape(I, [bsize, b, c,r, r]) # bsize, b, c, r, r
X = nd.split(X, num_outputs=b, axis=2) # b, [bsize, c, r, r]
X = nd.concatenate([nd.squeeze(x) for x in X], 3) # bsize, c, br, r
X = nd.split(X, num_outputs=c, axis=2) # c, [bsize, b
r, r]
X = nd.concatenate([nd.squeeze(x) for x in X], 3) # bsize, br, cr
return nd.reshape(X, (bsize, 1, br, cr))

然后就报错:
mxnet.base.MXNetError: [18:54:56] src/imperative/imperative.cc:250: Check failed: AGInfo::IsNone((outputs[i])) Inplace operations (+=, -=, x[:]=, etc) are not supported when recording with autograd.
其实这个函数并不涉及导数的变化,但在
X = nd.concatenate([nd.squeeze(x) for x in X], 3) # bsize, c, b
r, r这步就会出问题。这种情况要怎么解决呢?


#49

请教一个问题,autograd()是否能对max这类的操作进行恰当的求导呢?比如我需要实现一个ensembing max-pooling操作,返回最大值和次大值的加权平均:

def ensembling_max_pooling(x):
    p = 0.6
    second_max = nd.sort(x, axis=1)[:, -2]
    maximum = nd.max(x, axis=1)
    return p * maximum + (1 - p) * second_max

如果这个操作是发生在网络的forward()阶段,请问在反向传播的时候梯度能否正确地传递回相对应的最大值和次大值的位置呢?


#50

这个是在cmd命令行窗口一条一条换行打的吗,还有别的好方法吗,我换行打可能有点小问题


#51

x = Variable(torch.ones(2, 2), requires_grad=True)
y=3x+2
y.backward(gradient=2
torch.ones(1,2))
print(x.grad.data)

这个是pytorch代码,维度数就不一样,但是没有报错。


#52

a = nd.arange(9).reshape((3,3))
print(a)
a.attach_grad()
with autograd.record():
y = 2*nd.dot(a.T,a)
print(y)

b=y.backward()

a.grad`

以上是代码,按照上面教程所说,y不是标量时要对y进行求和,然后求导,我的输出结果显示是对X求和,显示的,这个是怎么回事?

[[0. 1. 2.]
[3. 4. 5.]
[6. 7. 8.]]
<NDArray 3x3 @cpu(0)>

[[ 90. 108. 126.]
[108. 132. 156.]
[126. 156. 186.]]
<NDArray 3x3 @cpu(0)>
Out[53]:

[[12. 12. 12.]
[48. 48. 48.]
[84. 84. 84.]]
<NDArray 3x3 @cpu(0)>

`


#53

每次运行attach_grad()的原因是你的id(x)变了吧


#54

我猜应该是可以的


#55

看明白了,谢谢。但是 你们在哪看到的这样知识点,在这一课时,我为什么没看到?


#56

对autograd有两个疑问.
1.使用autograd要怎么才能对一个矩阵的某一行求导?
2.尝试了一下
15%20PM
In[15] 返回的是NoneType, In[16]是可以求出结果,但是对整个矩阵求导,是否在性能上有损失?


#57

这个好像是矩阵求导,研究中,也没弄明白。因为如果是矩阵对矩阵求导,应该结果是9x9矩阵


#58

很容易理解的文档! 感谢您的分享{抱拳}


#59

手动计算梯度,直接使用课程的例子,
假设x是

[[0.] [1.] [2.] [3.]] 

那么对应的y是28,那么这个点的梯度或者导数是怎么计算的?

x的4个元素,让某一个元素加1,保持其他元素不变,计算出对应的y的变化。

比如x的第一列加1,x变成

[[1.] [1.] [2.] [3.]]

此时的y变成了30,变化是2=30-28,那么2/1=2。

类似的,x的第二列加1,x变成

[[0.] [2.] [2.] [3.]]

此时的y变成34,变化是6=34-28,那么6/1=6。

对x的第3列和第4列进行类似的运算,最终得到在这个点的矩阵梯度是

[[ 2.] [ 6.] [ 10.] [ 14.]]

这个结果跟教材不同,过程是类似的。
这样计算出来,可以看出矩阵梯度就是在多维空间中,函数y对于自变量x的变化率。


#60

大家好,我想问一下,并行加速w,x用gluon怎么写呢?

这里有张图比较形象.
实现的主要目的是把x和w求导过程分离,在计算x导数的时候不用记录w的导数(我应该没理解错吧),这样可以节省大量显存,尤其是在w也就是output层非常巨大的时候.

有小伙伴有思路吗?
我卡在了不知道如何在求x梯度的时候不记录w的.而且实现的也不太好,会计算两遍loss.
我大致的实现是这样的

        with autograd.record():
            feats = [fea_net(X.astype(dtype, copy=False)) for X in trans]
            outputs = [cls_net(fea) for fea in feats]  # 这个地方还是会记录cls_net的梯度
            fea_losses = [Loss(yhat, y.astype(dtype, copy=False)) for yhat, y in zip(outputs, labels)]
        for loss in fea_losses:
            loss.backward()
        trainer_fea.step(batch_size)

        with autograd.record():
            outputs = [cls_net(fea.detach()) for fea in feats]
            cls_losses = [Loss(yhat, y.astype(dtype, copy=False)) for yhat, y in zip(outputs, labels)]
        for loss in cls_losses:
            loss.backward()
        trainer_cls.step(batch_size)

求大佬指点下. @astonzhang @szha


#61

cls_net.weight.grad_req = 'null'