신경망으로 마스킹을 해도 그라디언트를 신경 쓰지 않아도됩니다.

의문



신경망에서 가변 길이 행렬을 다룰 때 그림과 같이 데이터를 마스킹 할 수 있습니다.



$W$나 $x$의 기울기가 가면이 없는 대로 행동할 것을 기대한다.
이 때, 각 $x_{i, j}$에 대한 $W$의 기울기는 마스크가 있는 장소에서는 0, 없는 장소에서는 적당한 숫자가 될 것이므로, 평균을 취하면 $W$의 기울기가 마스크분 "엷게 되어"버리는 것은 궁금해했다.

결론



영향을 받지 않는다. 왜냐하면, 그라디언트의 계산은 평균이 아니라 가산이니까.

확인



확인을 위해 했던 것이 아니라, 하고 있는 도중에 깨달았다.
아래는 chainer를 사용한 확인.
import chainer
import chainer.functions as F
import numpy as np

>> x_orig = np.random.random((3, 2)).astype(np.float32)
>> W = chainer.Variable(np.random.random((2, 1)).astype(np.float32))
>> x = chainer.Variable(x_orig)
>> print x
variable([[ 0.45719743  0.99944282]
          [ 0.6675607   0.33180818]
          [ 0.37650901  0.48325235]])

>> y = F.matmul(x, W)
>> print y
variable([[ 0.26743633]
          [ 0.2829439 ]
          [ 0.18782631]])

>> loss = F.squared_error(y, np.zeros(y.shape, dtype=np.float32))
>> mask = np.array([[True], [True], [False]])
>> loss_masked = F.where(mask, loss, np.zeros(loss.shape, dtype=loss.dtype))
>> print loss_masked
variable([[ 0.07152219]
          [ 0.08005726]
          [ 0.        ]])

>> loss_tot = F.sum(loss_masked)
>> loss_tot.grad = np.array(1.0, dtype=np.float32)
>> loss_tot.backward(retain_grad=True)
>> print loss.grad
[[ 1.]
 [ 1.]
 [ 0.]]

>> print W.grad
[[ 0.62230688]
 [ 0.72234082]]

다음으로, 마스킹을 하는 대신에, 정말로 그 행을 없애 버린다.
>> W.cleargrad()
>> x = chainer.Variable(x_orig[:2, :])
>> print x
variable([[ 0.45719743  0.99944282]
          [ 0.6675607   0.33180818]])

>> y = F.matmul(x, W)
>> loss = F.squared_error(y, np.zeros(y.shape, dtype=np.float32))
>> print loss
variable([[ 0.07152219]
          [ 0.08005726]])

>> loss_tot = F.sum(loss)
>> loss_tot.grad = np.array(1.0, dtype=np.float32)
>> loss_tot.backward(retain_grad=True)
>> print loss.grad
[[ 1.]
 [ 1.]]

>> print W.grad
[[ 0.62230688]
 [ 0.72234082]]

이와 같이, 기울기는 변하지 않는다.

고찰



생각해보니 너무 당연했다. 신경망 주위에서 평균을 사용하는 처리는 거의 없다.
일단 batch normalization이라든지 사용할 때는 조금 조심하는 것이 좋을지도 모른다.

좋은 웹페이지 즐겨찾기