Input Embedding과 Positional Encoding

Transformer 입력을 정리하다가, 수식으로는 분명 행렬곱인데 PyTorch는 행렬곱을 안 한다는 부분에서 한 번 멈췄었다. 그런데도 학습이 된다는 게 처음엔 어 이게 왜 되지 싶었다. 그 부분과 positional encoding의 scaling factor를 같이 정리해봤다.

Input Embedding — 수식은 행렬곱, 구현은 indexing#

토큰 하나의 임베딩 값은 수식으로 보면 one-hot 벡터와 임베딩 행렬의 곱이다.

one-hot 벡터에 행렬을 곱한다는 건 결국 에서 그 토큰에 해당하는 한 행을 골라오는 것과 같다. 그래서 PyTorch는 실제로 행렬곱을 하지 않는다. 더 효율적인 연산을 위해 행렬곱 대신 indexing으로 필요한 행을 바로 가져온다. nn.Embedding이 하는 lookup이 이거다.

여기서 내가 멈췄던 지점이 있다. 행렬곱을 안 하고 indexing만 하면 gradient가 안 흐르는 거 아닌가 싶었던 것이다. 그런데 수학적으로는 indexing이 one-hot 행렬곱과 같은 연산이기 때문에, 기울기는 그 행을 통해 , 즉 nn.Embedding까지 그대로 전달된다. 효율적인 연산으로 바꿔도 학습에는 아무 문제가 없는 것이다. lookup이 어떻게 (vocab, model_dim) 행렬에서 행을 뽑아오는지는 nn.Embedding에 이해하기에 따로 정리해 두었다.

Positional Encoding과 scaling factor#

Transformer 입력은 토큰 임베딩에 위치 정보를 더해서 만든다.

임베딩에 을 곱해주는 게 scaling factor다. 이걸 곱하는 이유는, 임베딩 값이 positional encoding 값에 압도당하는 상황을 막기 위함이다. 위치 정보가 더해질 때 토큰의 의미가 묻혀버리지 않도록 임베딩 쪽을 키워주는 것이다.

Positional Encoding vs Positional Embedding#

퀴즈를 풀다가 이 둘을 헷갈렸어서 다시 짚어둔다. 차이는 학습 여부에 있다.

  • Positional Encoding: 학습되지 않는 고정된 값이다. 위치마다 정해진 함수로 값을 만든다.
  • Positional Embedding: 학습되는 파라미터다. 위치 표현을 데이터로부터 학습한다.

즉 임베딩에 위치 인코딩을 더한 것이 positional embedding인 게 아니라, 위치 표현을 고정된 함수로 줄지 학습으로 얻을지의 차이다. 최신 트렌드는 학습하는 positional embedding 방식, 혹은 RoPE를 사용하는 쪽이다.

이렇게 만든 입력이 인코더로 들어가 self-attention을 거치게 된다.

댓글