tony9402
[Huggingface] transformers에 contribute 하기 본문
최근 huggingface/transformers 에서 모델을 어떻게 구현하였는지 궁금하여 BART 모델 소스코드를 구경하던 도중 이해가 안 되는 주석을 보게 되었다.
`BartEncoderLayer` 모듈을 구경하던 중 `hidden_states`의 shape이 (seq_len, batch, embed_dim)으로 되어 있었다. 저 부분만 아무리 봐도 (batch, seq_len, embed_dim)이 맞는 거 같아 직접 shape들을 계산해 보기로 했다. (사실 직접 계산하는 것보다 shape를 print하는 것이 더 빠르게 확인할 수 있다.)
주석이 맞는지 확인하기 위해 직접 계산하는 과정을 간단히 정리해 보면 아래와 같다. (실제론 더 자세히 계산했다.)
`input_ids`의 shape는 (batch_size, max_length)로 이를 (B, L)로 표현하였다. self.encoder는 BartEncoder이므로 BartEncoder의 forward 부분을 확인하러 가면 된다.
`self.embed_tokens`는 `nn.Embedding`으로 `inputs_embeds`의 shape는 (B, L, H)가 된다. (아래 Reference 참고)
캡처한 사진에 나오지 않았지만 812라인에서 `input`의 shape는 `input_ids`와 같다고 생각하면 된다. 즉, (B, L)이다.
815라인의 `hidden_states`는 `inputs_embeds`와 `embed_pos`을 더하는 연산을 한 결과인데 shape가 일치하지 않는 것을 볼 수 있다. 여기서는 broadcasting으로 연산 결과가 (B, L, H)가 된다. Broadcasting에 대한 자세한 설명은 여기를 확인해 보자.
`attention_mask`는 주석에 달린 것처럼 (B, 1, L, L)이 된다. 이때, tgt_seq_len와 src_seq_len 둘 다 L로 보자.
그다음은 `hidden_states`의 shape는 특별히 변경되는 지점은 없고 `encoder_layer`에 parameter로 들어가는 것을 볼 수 있다. `hidden_states`의 shape는 (B, L, H)이다.
parameter로 주어지는 `hidden_states`의 shape는 (B, L, H)로 계산되었지만, 주석에는 (L, B, H)로 설명이 되어있다. 직접 계산한 결과가 맞는다면 주석은 틀린 것이고 이를 수정하여 huggingface/transformers에 contribution을 할 수 있다는 생각이 들었다.
혹시 계산 실수로 틀린 것이 아닌지 이를 huggingface에 있는 예제 코드와 파이썬 패키지 내에서 직접 hidden_states의 shape를 찍어보아 주석이 틀린 것을 확인하였다.
다른 모델들 구현도 구경하는데 틀린 주석이 보여 이를 직접 테스트해 보고 수정하였다. 많은 모델에서 같은 오류가 많이 보이길래 transformers 내부의 구조를 분석하였더니 새로운 모델을 올릴 때 template을 활용하여 추가하는 것으로 파악되었다.
그래서 이미 올라온 모델에서 틀린 주석을 수정하고 template에 있는 주석도 수정하였다. template에 있는 주석은 오히려 의도한 사항일 수 있으므로 PR을 올릴 때 template 코드 안에 있는 주석을 수정해도 괜찮은지 확인해달라는 글을 남겼는데 수정하는 방향으로 진행하셨다. (사실, (L, B, H)인 경우가 거의 없거나 아예 없는 것 같아 수정하는 게 더 좋아 보이긴 했다.)
단순 주석 수정으로도 Contribution을 할 수 있다는 얘기를 들었지만 막상 해보려고 몇년전부터 이것저것 레포를 봤었는데 실패하였다. 근데 이번에 약 106K개 스타를 받은 transformers에 기여를 할 수 있었다는 게 신기한 경험이다. (역시 자기가 하고 있는 부분에서 쉽게 찾는거 같기도 ?!)
(생각보다 틀린 주석이 많이 보였으므로 큰 레포에 contribution을 해보고 싶은 분들은 도전해 보면 좋을 것 같다 !)