huggingface, BertModelの forwardに入るargumentsをよくわかっていなかったので調べてみた

# huggingface, BertModelの forwardに入るargumentsをよくわかっていなかったので調べてみた
```python
class BertModel(BertPreTrainedModel):

    def forward(
            self,
            input_ids=None,
            attention_mask=None,
            token_type_ids=None,
            position_ids=None,
            head_mask=None,
            inputs_embeds=None,
            encoder_hidden_states=None,
            encoder_attention_mask=None,
            past_key_values=None,
            use_cache=None,
            output_attentions=None,
            output_hidden_states=None,
            return_dict=None,
        ):
```
input_idsは単語のtokenだとして、残り奴らがよくわからなかったので調べながらメモする。
# attention_maskとは
batch処理する際には必ず必要となるものでこのattention_maskが1となるindexのtokenにモデルは注目する。
sequence_a, sequence_bの単語数がそれぞれ異なる時、例えば、

```python
sequence_a = "This is a short sequence."
# tokeninzed
[[101, 1188, 1110, 170, 1603, 4954, 119, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
sequence_b = "This is a rather long sequence. It is at least longer than the sequence A."
# tokeninzed
[101, 1188, 1110, 170, 1897, 1263, 4954, 119, 1135, 1110, 1120, 1655, 2039, 1190, 1103, 4954, 138, 119, 102]]
```
この時、単語数と一致しないのは、前後にtokenがつくからである。
sequence_a
`'[CLS] HuggingFace is based in NYC [SEP]'`

tenosrにa, bを入れるためには、aはpaddingを入れる必要があるし、bはある長さ以上はtruncationしないといけなくなる。この0をpaddingに入れた部分にはbinary tensorとしてpaddingを入れた番号に対して処理しないようにindicaterを入れる、これがattention_maskである。


# token_type_idsとは何か
#### BertModelに入力する `input_ids`　が１つ以上のsequenceの入力となる場合に区別するためのidである。


例えば、質問回答のようなタスクには二つの異なる文章のsequencesを一つの `input_ids`として入力する必要がある、
`sequence_a = "HuggingFace is based in NYC"`
`sequence_b = "Where is HuggingFace based?"`
のようなもの

この二つを区別するものとして `token_type_ids`　は存在して、sequence_aは0、 sequence_bは1として格納された `torch.Tensor`である

```python
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained("bert-base-cased")
sequence_a = "HuggingFace is based in NYC"
sequence_b = "Where is HuggingFace based?"

encoded_dict = tokenizer(sequence_a, sequence_b)


>>> encoded_dict['token_type_ids']
>>> [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]
```
のような結果になる。

この時、tokenizerは[CLS]、[SEP]に当たるtokenを２つのsequenceの間に挿入する。
```python
>>>> decoded = tokenizer.decode(encoded_dict["input_ids"])
[CLS] HuggingFace is based in NYC [SEP] Where is HuggingFace based? [SEP]
```

# position_idsとは
Optionalである。
RNNなどの場合にはRecurrentに処理することでtokenの時系列を考慮していたが、各tokenの位置を意識していない。tokenのリストの中で各tokenの位置を特定するために、position ID（position_ids）がモデルによって使用される。
下のように`self.position_embedding_type == "absolute"`ではnn.Embeddingが用いられている。
`config.max_position_embeddings` => tokenizerでのmax_lenのことそれぞれ独立の`config.hidden_size`のEmbedded vectorとなる

コードからposition_idsに関連した処理の部分
```transformers/models/bert/modeling_bert.py
class BertEmbeddings(nn.Module):
    """Construct the embeddings from word, position and token_type embeddings."""
...
    def __init__(self, config):
        self.position_embeddings = nn.Embedding(config.max_position_embeddings, config.hidden_size)
...
    def forward(..., position_ids, ...):
       if self.position_embedding_type == "absolute":
            position_embeddings = self.position_embeddings(position_ids)
            embeddings += position_embeddings
```

# head_mask
(torch.FloatTensor of shape (num_heads,) or (num_layers, num_heads), optional) 
self-attention modulesで選択されたheadsをnullにできる。1でnot mask, 0でmask
ざっくり調べてもあまり使われてなさそう。

# inputs_embeds とは
`input_ids`か `inputs_embeds`のどちらかをmodelに入れる必要があり、`inputs_embeds`を入れる時には`input_ids`がモデルの内部の embedding lookup matrix ではなく自分で定義したassociated vectorに変換したものを用いたい時である。
より具体的には `BertEmbeddings`内のforward処理のコア部分を抜き出すと
`nn.Embedding`を用いるか、そのほかの処理を用いるかということになる。
```python
## __init__()内部
self.word_embeddings = nn.Embedding(config.vocab_size, config.hidden_size, padding_idx=config.pad_token_id)
self.token_type_embeddings = nn.Embedding(config.type_vocab_size, config.hidden_size)
## forward()内部
token_type_embeddings = self.token_type_embeddings(token_type_ids)
if inputs_embeds is None:
    inputs_embeds = self.word_embeddings(input_ids)
embeddings = inputs_embeds + token_type_embeddings
if self.position_embedding_type == "absolute":
    position_embeddings = self.position_embeddings(position_ids)
    embeddings += position_embeddings
embeddings = self.LayerNorm(embeddings)
embeddings = self.dropout(embeddings)
return embeddings
```


### 参考
[huggingface Glossary](https://huggingface.co/transformers/v3.2.0/glossary.html)
transformerのversion `'4.17.0.dev0'`

以降のargumentsはoptionalなので調べるのはまた今度にする。
もし解説記事があれば教えていただけるとありがたいです。