밑바닥부터 시작하는 딥러닝 교재의 코드를 보면(https://github.com/kchcoo/WegraLee-deep-learning-from-scratch /common/layers.py)

SoftmaxWithLoss 레이어의 역전파에서 마지막으로 dx를 반환할 때 batch_size로 나눠주잖아

SoftmaxWithLoss 레이어는 엄밀히 말하면 Softmax 레이어랑 Categorical Cross-Entropy Loss 레이어를 결합한 거고

Categorical Cross-Entropy Loss를


a15714ab041eb360be3335625683746f0053452ed6a6ee89d53463f59e13cd6e85d87400a530eca4e19d286f


이렇게 정의하면 dL/dyhat_i = -1/B * (y_ij / yhat_ij)니까

역전파 때 오차를 batch_size로 나누는 과정은 두 레이어 중에 Cross-Entropy Loss 레이어 과정에서 일어나는 거고, Softmax 레이어랑은 관계 없다고 생각했거든


근데 numpy로 트랜스포머를 구현한 프로젝트(https://github.com/AkiRusProd/numpy-transformer /transformer/activations.py)를 보니까 softmax 함수의 역전파를 이렇게 구현해 놨더라고


class Softmax():

  def __init__(self) -> None:

    self.axis = -1


  def forward(self, x):

    self.x = x

    e_x = np.exp(x - np.max(x, axis = self.axis, keepdims=True))

    self.softmax = e_x / np.sum(e_x, axis = self.axis, keepdims=True)

    return self.softmax


  def backward(self, grad = None):

    batch_size = self.x.shape[0]

    softmax = self.forward(self.x)

    J = softmax[..., np.newaxis] * np.tile(np.identity(softmax.shape[-1], dtype = self.x.dtype), (softmax.shape[0], *tuple(np.ones(softmax.ndim, dtype = np.int8).tolist()))) - (softmax[..., np.newaxis, :].transpose(*tuple(np.arange(0, softmax.ndim - 1, 1, dtype=np.int8).tolist()), -1, -2) @ softmax[..., np.newaxis, :]) #np.matmul(softmax[:, :, None], softmax[:, None, :])

    input_grad = grad[..., np.newaxis, :] @ J

    return input_grad.reshape(self.x.shape) / batch_size


마지막에 batch_size로 나누는데 결국 어느 쪽 레이어에서 batch_size로 나누는 게 맞는 거야? 

아님 애초에 두 레이어 모두 batch_size로 나누든 말든 별로 상관 없는 거야?