Transformer의 데이터 흐름을 따라 가기

이 기사에 대하여



이 기사는 필자가 Harvard NLP의 PyTorch 구현 을 참고로 Transformer를 구현했을 때 얻은 지견을 정리한 기사입니다.

Transformer의 논문 해설 기사가 아니라는 것을 양해 바랍니다.

Transformer 정보



Transformer란, 「Attention is All You Need」라고 하는 논문으로 등장한 Attention 베이스의 모델로, 아래의 그림과 같은 구조를 하고 있습니다.



모델의 구조를 이해하고 싶은 분은 다음 기사를 읽기 쉽고 추천합니다.

논문 해설 Attention Is All You Need (Transformer) (Ryobot씨)
만들어 이해하기 Transformer / Attention (halhorn씨)

데이터 흐름을 추적



스스로 구현해 본 후 모델 전체의 데이터 흐름을 알고 있으면 Transformer의 구조를 더 쉽게 이해할 수 있었을까 생각하고 모델의 각 시점에서 Tensor가 어떤 모양을 취하고 있는지 라는 것을 정리해 보았습니다.

그림 설명



다음과 같은 설정으로 다이어그램을 만들고 있습니다.
  • 「미야자키 후와라입니다」 → 「멋집니다」라고 하는 대화의 학습을 하고 있습니다.
  • Masking의 처리를 이해하기 쉽도록, 의도적으로 Decoder의 입력문의 이상한 곳에 패딩 기호 를 삽입하고 있습니다.
  • Encoder/Decoder 각각에서 에 대한 Masking의 처리를 실시합니다.

  • 또한 그림에서 사용되는 변수에 대한 설명은 표와 같습니다.


    변수 이름
    내용


    batch_size
    학습 시 배치 크기

    src_len/tgt_len
    Encoder/Decoder에 입력하는 문장의 길이

    d_model
    단어 벡터의 차원 수

    h
    Multi-Head Attention의 헤드 수

    vocab_size
    Decoder에서 사용되는 어휘 수


    전체도



    화상중의 「K」와 「V」가 반대로 되어 있습니다. 죄송합니다.



    Attention의 Masking 구현에 대해



    Attention의 마스크 구현에 대해 고민했으므로 Harvard NLP에서 Mask의 구현에 대해 정리해 둡니다.

    Transformer에서는 아래 그림과 같이 3개소의 Multi-Head Attention(안의 Scaled Dot-Product Attention) 중에서 Masking이 등장합니다.
  • Encoder에서의 Self-Attention
  • Decoder에서의 Self-Attention
  • Decoder의 SourceTarget-Attention



  • Harvard NLP 구현은 1과 3에서 사용하는 src_mask와 2에서 사용하는 tgt_mask의 두 가지 마스크를 제공합니다. 이하 각각의 설명입니다.

    src_mask



    src_mask 는 Encoder 에의 입력문의 패딩을 참조하지 않게 하기 위한 마스크로, 다음과 같이 구현되고 있습니다.


    # srcは[batch_size, src_len]
    # パディング箇所が0、それ以外が1のTensorを生成
    self.src_mask = (src != pad).unsqueeze(-2)  # [batch_size, 1, src_len]
    

    src_mask는 [batch_size, 1, src_len]의 형태로 생성됩니다. 이렇게 하면 PyTorch의 브로드캐스트를 이용하여 Self-Attention, SourceTarget-Attention에서 각각 다른 크기의 Tensor에 마스크를 걸 수 있습니다.


    (PyTorch1.1.0 브로드 캐스트 문서)

    tgt_mask



    tgt_mask에는 다음 두 가지 역할이 있습니다.
  • Decoder에 대한 입력 문 패딩을 참조하지 마십시오.
  • Self-Attention에서 미래의 단어를 참조하지 마십시오.

    tgt_mask는 다음과 같이 구현됩니다.


    # tgtは[batch_size, tgt_len]
    # パディング箇所が0、それ以外が1のTensorを生成
    tgt_mask = (tgt != pad).unsqueeze(-2)  # [batch_size, 1, tgt_len]
    # パディング用のマスクと未来の単語用のマスクを重ねる
    tgt_mask = tgt_mask & Variable(
        subsequent_mask(tgt.size(-1)).type_as(tgt_mask.data))  # [batch_size, tgt_len, tgt_len]
    
    # 未来の単語を参照しないようにするマスクを作成する関数
    def subsequent_mask(size):
        attn_shape = (1, size, size)  # [1, tgt_len, tgt_len]
        # 三角行列の生成
        subsequent_mask = np.triu(np.ones(attn_shape), k=1).astype('uint8') # [1, tgt_len, tgt_len]
        # 1と0を反転する処理
        return torch.from_numpy(subsequent_mask) == 0
    

    tgt_mask는 [batch_size, tgt_len, tgt_len]의 형태로 생성됩니다. 작성할 때는 그림과 같이 패딩을 참조하지 않게 하는 마스크와 미래의 단어를 참조하지 않게 하는 마스크의 2개를 작성한 후 그들을 겹치고 있습니다.

    마지막으로



    Transformer 내부의 데이터 구조를 쫓는다는 틈새 내용이지만, 조금이라도 누군가의 도움이되면 다행입니다.
  • 좋은 웹페이지 즐겨찾기