[LLMのFinetuningのための基礎] transformersのAutoClassesの基本を理解する 1

# はじめに
今回は **[LLMのFinetuningのための基礎] transformersのAutoClassesの基本を理解する 1** と題しまして、transformersのAutoTokenizer・AutoConfigに関して学習したことをまとめました。

もともとはAutoTokenizerだけにしようかと思っていましたが、AutoConfigは切って離せずの関係性だったのでまとめて記事にしました。

今回メインで使用する教材は[TransformersのAutoClassesのAPI reference](https://huggingface.co/docs/transformers/v4.51.3/ja/model_doc/auto)です。

個人的アウトプットのイメージですが、せっかく前回、前々回とアウトプットとしてqiita記事にしていたのでシリーズ化にでもしようかなと思っています。（どこまで読者の方の参考になるかは分かりませんが、、、）

以下、現段階でのアウトプットの記事のイメージ図です。

```mermaid
flowchart LR
subgraph AutoClass
C[AutoTokenizer・AutoConfigの基本を理解する] --> D[AutoModelの基本を理解する]
end
A[LLM事前知識] --> B[datasetsの基本の理解] --> C
```

AutoClassの基本的内容を抑えた記事を書いたあとにどのようなことを書くのかはまだ検討中です。。。
（無理のない範囲で学習目的で書いていこうかなと思っています。）

LLM事前知識・datasetsの基本の理解については下記記事に記載されています。よろしければ是非一読お願いいたします。

https://qiita.com/Sora_Yamamoto/items/fd133dcabc25e697e538

https://qiita.com/Sora_Yamamoto/items/c850f03cd56b097be4d6


# おことわり
本記事はあくまでもLLM初学者である私の学習のアウトプットなので不正確・不十分な説明の可能性もあるため参考にされる場合は十分にご注意ください。


# 目次

<dl>
  <dt>1. AutoClassesとは</dt>  
  <dt>2. AutoConfigとは</dt>  
  <dt>3. AutoTokenizerとは</dt>
  <dt>4. おわりに</dt>
</dl>


# AutoClassesとは
[AutoClasses](https://huggingface.co/docs/transformers/ja/model_doc/auto)とはTransformers APIが提供している主要なクラスの一つです。

HuggingFace上に公開されているほとんどの事前学習済みモデルを、MODEL IDを指定するだけでそのモデルの情報を自動的にロードし、すぐに使える状態にすることができます。

AutoClassesは大きく3つのコンポーネントに分けられます。

<dl>
  <dt>1. AutoConfig</dt>
  <dt>2. AutoTokenizer</dt>  
  <dt>3. AutoModel</dt>
</dl>

それぞれが何をロードするものなのかを簡単に説明すると、

- AutoConfig --> モデルのアーキテクチャ（構造）を定義するための設定情報
- AutoTokenizer --> トークナイザーの構造
- AutoModel --> モデルの構造

上記は非常に簡易的説明ですが、次以降でより詳しく見ていきます。

:::note warn
**注意1**
本記事で触れるのはAutoConfigとAutoTokenizerのみです。
AutoModelについては次回触れます。
:::

:::note warn
**注意2**
上記では簡単に、「MODEL IDを指定するだけで」 と述べていますがその他にも、モデルの情報へのローカルパスなどでもロードすることができます。
:::


:::note info
**ロード対象**
ロードする対象はHuggingFace hubのモデルカードで確認できます。
例えば *google-bert/bert-base-uncased* の場合は[こちら](https://huggingface.co/google-bert/bert-base-uncased/tree/main)で確認できます。
:::


# AutoConfigとは
AutoConfigとは、**MODEL ID もしくは ローカルパスの情報から、関連するモデルの `config.json` ファイルを特定・ロードし、その内容に基づいて適切な `PretrainedConfig` のサブクラスのインスタンス（設定オブジェクト）を生成・返却するクラス**です。

つまり、`AutoConfig` が提供するのは、`PretrainedConfig`クラスを継承した具体的な設定クラス（例: `BertConfig`, `GPT2Config`）の**インスタンス**です。

### [PretrainedConfig](https://huggingface.co/docs/transformers/ja/main_classes/configuration#transformers.PretrainedConfig)とは何か。
これは、**事前学習済みモデルのアーキテクチャやハイパーパラメータといった構成情報を扱うための抽象化クラス**です。設定情報をファイル (`config.json`) からロードしたり、ファイルへ保存したり、Pythonの辞書形式に変換したりするための共通メソッドを実装しています。

これを継承した各Configクラスは各モデルごとの固有の属性を付与することが可能になっています。
基本的に全てのConfigで共通の属性としては**hidden_​​size**、**num_attention_heads**、**num_hidden_​​layers**の3つであり、テキストモデルの場合は**vocab_size**が加わります。

:::note info
**各モデルごとの固有の属性とは？**

[AutoClasses](https://huggingface.co/docs/transformers/v4.51.3/ja/model_doc/auto)のreferenceには、次の様に記載があります。
>各タスクごと、そして各バックエンド（PyTorch、TensorFlow、またはFlax）ごとにAutoModelのクラスが存在します。

この説明通り、Transformersで扱うことのできるモデルにはそれぞれに異なる背景が存在し、それらを各モデルごとの固有の属性とここでは読んでいます。

この様な実装がされていることは[PretrainedConfig](https://huggingface.co/docs/transformers/ja/main_classes/configuration#transformers.PretrainedConfig)の Parameters の部分に **PyTorch specific parameters** や **TensorFlow specific parameters** といった記載があることからも確認ができます。
:::


### 実際に見てみる
説明文を見ただけではなかなか理解しにくいです。
実際にロードして中身を確かめてみます。

今回扱う環境はGoogle Colabで、モデルには`google-bert/bert-base-uncased`を使用します。

```python
from transformers import AutoConfig

model_name = "google-bert/bert-base-uncased"

config = AutoConfig.from_pretrained(model_name)
```

実行するとプログレスバーが表示され、`config.json`がロードされていることが分かります。
![スクリーンショット 2025-05-10 192742.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3491855/407d1fbd-b985-405f-93c1-92d2caf334d0.png)

中身を確認してみます。

```python
print(config)
# 出力結果:
#
# BertConfig {
#   "architectures": [
#     "BertForMaskedLM"
#   ],
#   "attention_probs_dropout_prob": 0.1,
#   "classifier_dropout": null,
#   "gradient_checkpointing": false,
#   "hidden_act": "gelu",
#   "hidden_dropout_prob": 0.1,
#   "hidden_size": 768,
#   "initializer_range": 0.02,
#   "intermediate_size": 3072,
#   "layer_norm_eps": 1e-12,
#   "max_position_embeddings": 512,
#   "model_type": "bert",
#   "num_attention_heads": 12,
#   "num_hidden_layers": 12,
#   "pad_token_id": 0,
#   "position_embedding_type": "absolute",
#   "transformers_version": "4.51.3",
#   "type_vocab_size": 2,
#   "use_cache": true,
#   "vocab_size": 30522
# }
```

この出力結果をみると、BertConfigというクラスであり、その中には`num_attention_heads`や`vocab_size`と言ったようなモデルの構成情報が含まれていることが分かります。

また、上記の結果からは分かりませんが`dir(config)`などを実行すると、`push_to_hub()`などの関数も実装されていることが分かり、PretrainedConfigを継承していると理解できます。

:::note info
**ロードしたファイルの行方**

ロードしたファイルたちは通常「~/.cache」の中にキャッシュされています。（環境や設定によって異なる）

Google Colabの場合、下記の画像の位置に存在しています。
![スクリーンショット 2025-05-10 195047.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3491855/522dba28-0719-47e1-9263-cb766f73362c.png)

`/root/.cache/huggingface/hub/models--google-bert--bert-base-uncased/`にキャッシュ化された情報が入っています。
:::

# AutoTokenizerとは
AutoTokenizerはテキストの前処理（トークン化やトークンID化など）を行う為のルールや語彙、それを行うトークナイザーをロードします。

AutoTokenizerについて理解するために次の段階を踏んで確認を行います。

<dl>
  <dt>1. 何がロードされるのか</dt>
  <dt>2. どう使うのか</dt>  
  <dt>3. 何が出力されるのか</dt>
</dl>


## 何がロードされるのか
実際にコードを実行してロードされるものを確認してみます。

```python
from transformers import AutoTokenizer

model_name = "google-bert/bert-base-uncased"

tokenizer = AutoTokenizer.from_pretrained(model_name)
```

結果：

![スクリーンショット 2025-05-10 202916.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3491855/d45ff657-692f-4897-8b06-c5dcc783a130.png)

セルの出力から今回の場合は、`tokenizer_config.json`、`vocab.txt`、`tokenizer.json`の3つがロードされていることが分かります。

それぞれの中身を軽く確認してみます。コメントアウト部分が標準出力の結果です。

```python
import json


with open("/root/.cache/huggingface/hub/models--google-bert--bert-base-uncased/snapshots/86b5e0934494bd15c9632b12f734a8a67f723594/vocab.txt", "r") as f:
    vocab_txt = f.read()

with open("/root/.cache/huggingface/hub/models--google-bert--bert-base-uncased/snapshots/86b5e0934494bd15c9632b12f734a8a67f723594/tokenizer.json", "r") as f:
    tokenizer_json = json.load(f)

with open("/root/.cache/huggingface/hub/models--google-bert--bert-base-uncased/snapshots/86b5e0934494bd15c9632b12f734a8a67f723594/tokenizer_config.json", "r") as f:
    tokenizer_config_json = json.load(f)

print(vocab_txt[:100])
# [PAD]
# [unused0]
# [unused1]
# [unused2]
# [unused3]
# [unused4]
# [unused5]
# [unused6]
# [unused7]
# [unused8]
# [unu


print(tokenizer_json.keys())
# dict_keys(['version', 'truncation', 'padding', 'added_tokens', 'normalizer', 'pre_tokenizer', 'post_processor', 'decoder', 'model'])


print(tokenizer_config_json.keys())
# dict_keys(['do_lower_case', 'model_max_length'])
```

これらは前処理用のトークナイザーに関連する重要な情報を含んだファイルです。

#### vocab.txt
vocab.txtは`WordPiece`に合わせた語彙情報テキストファイルであり、この部分はTransformers で使用される3つの主要なトークナイザー`Byte-Pair Encoding (BPE)`、`WordPiece`、`SentencePiece`で若干変わってきます。

例えば、[GPT2](https://huggingface.co/openai-community/gpt2/tree/main)では`BPE`が使用されており、この場合はvocab.txtではなく`vocab.josn`と`merges.txt`が使用されています。


#### tokenizer.json
tokenizer.jsonはトークナイザーパイプラインの一連の処理に関する情報を含んだファイルです。
中身をもう少し詳しく見てみます。

```python
from pprint import pprint

pprint(tokenizer_json["version"])
# 1.0

pprint(tokenizer_json["truncation"])
# null

pprint(tokenizer_json["padding"])
# null

pprint(tokenizer_json["added_tokens"])
# [{'id': 0,
#   'special': True,
#   'content': '[PAD]',
#   'single_word': False,
#   'lstrip': False,
#   'rstrip': False,
#   'normalized': False},
#  {'id': 100,
#   'special': True,
#   'content': '[UNK]',
#   'single_word': False,
#   'lstrip': False,
#   'rstrip': False,
#   'normalized': False},
#  {'id': 101,
#   'special': True,
#   'content': '[CLS]',
#   'single_word': False,
#   'lstrip': False,
#   'rstrip': False,
#   'normalized': False},
#  {'id': 102,
#   'special': True,
#   'content': '[SEP]',
#   'single_word': False,
#   'lstrip': False,
#   'rstrip': False,
#   'normalized': False},
#  {'id': 103,
#   'special': True,
#   'content': '[MASK]',
#   'single_word': False,
#   'lstrip': False,
#   'rstrip': False,
#   'normalized': False}]

pprint(tokenizer_json["normalizer"])
# {'type': 'BertNormalizer',
#  'clean_text': True,
#  'handle_chinese_chars': True,
#  'strip_accents': None,
#  'lowercase': True}

pprint(tokenizer_json["pre_tokenizer"])
# {'type': 'BertPreTokenizer'}

pprint(tokenizer_json["post_processor"])
# {'pair': [{'SpecialToken': {'id': '[CLS]', 'type_id': 0}},
#           {'Sequence': {'id': 'A', 'type_id': 0}},
#           {'SpecialToken': {'id': '[SEP]', 'type_id': 0}},
#           {'Sequence': {'id': 'B', 'type_id': 1}},
#           {'SpecialToken': {'id': '[SEP]', 'type_id': 1}}],
#  'single': [{'SpecialToken': {'id': '[CLS]', 'type_id': 0}},
#             {'Sequence': {'id': 'A', 'type_id': 0}},
#             {'SpecialToken': {'id': '[SEP]', 'type_id': 0}}],
#  'special_tokens': {'[CLS]': {'id': '[CLS]', 'ids': [101], 'tokens': ['[CLS]']},
#                     '[SEP]': {'id': '[SEP]',
#                               'ids': [102],
#                               'tokens': ['[SEP]']}},
#  'type': 'TemplateProcessing'}

pprint(tokenizer_json["decoder"])
# {'type': 'WordPiece', 'prefix': '##', 'cleanup': True}

pprint(tokenizer_json["model"].keys()) # vocabの量が多すぎるので keys()
# dict_keys(['unk_token', 'continuing_subword_prefix', 'max_input_chars_per_word', 'vocab'])
```

ご覧の通り、正規化やpre-tokenization等の情報が含まれていることが分かります。


#### tokenizer_config.json
tokenizer.jsonの補足にちｋ情報を含んだ情報です。
こちらも軽く中身を確認してみます。

```python
print(tokenizer_config_json['do_lower_case'])
# True

print(tokenizer_config_json['model_max_length'])
# 512
```

小文字に直すかどうかや最大長に関する情報が含まれていることが分かります。

私の理解ではこれらは後述するtokenizerを使うする際のデフォルトのふるまいを指定しているものだと考えられます。

:::note info
**トークナイズの一連処理**
Transformersの裏側で行われているトークナイズの一連の処理パイプラインについてより深く理解したい方は以下のページをご覧ください。
[Hugging Face: Understanding tokenizers](https://medium.com/@awaldeep/hugging-face-understanding-tokenizers-1b7e4afdb154)
[トークナイザーの概要](https://huggingface.co/docs/transformers/tokenizer_summary)
:::

::: note info
**ロードされる各ファイルの詳細**
ここではロードされたファイルたちをかなり簡潔に説明させていただきましたが、より詳しく調べてまとめてくださった方がQiitaにいらっしゃったのでこちらもご確認することをお勧めさせていただきます。

[Hugging Face モデルフォルダにある設定ファイルたち完全理解](https://qiita.com/hiyoko1729/items/955c99d59a360ff7ba83)

:::


## どう使うのか
`from_pretrained()`でインスタンス化したインスタンスに直接引数を与えて使用します。

内部的には`__call__`で定義されています。

[PreTrainedTokenizer.\__call__](https://huggingface.co/docs/transformers/ja/main_classes/tokenizer#transformers.PreTrainedTokenizer.__call__)をご覧ください。

```python
from transformers import AutoTokenizer

model_name = "google-bert/bert-base-uncased"

tokenizer = AutoTokenizer.from_pretrained(model_name)

outputs = tokenizer("ここにいれる")
```

`__call__`にはいくつか引数が用意されていますが、ここでは代表的なものをまとめます。

#### 入力テキスト
入力テキストの引数としてよく見るのは`text`と`text_pair`です。
`text`はトークナイズしたいテキスト本体。`text_pair`の場合はQandAタスクなどのsequenceペアが必要な際に使用します。

```python
outputs = tokenizer(text="質問", text_pair="これを基に回答してもらう")
```

#### 処理制御
トークナイズ処理における制御を行う引数として4つおさえておきます。

1. add_special_tokens
    この引数は`bool値`を取ります。デフォルトは`True`です。
    モデルが必要とする特殊トークン（BERTの場合は`[CLS]`や`[SEP]`）を自動的に付与します。

1. padding
    この引数は`Union[bool, str, PaddingStrategy]`を取りますが、筆者は`bool`か`str`しか意識したことがありません。デフォルトは`False`です。
    `True`もしくは`"longest"`の場合は、バッチ内で最も長いsequenceに合わせてPaddingします。
    `"max_length"`の場合は後述の`max_lenght`に合わせてPaddingします。

    基本的にモデルに渡すsequence長は揃える必要性があるため、`True`もしくは`"max_length"`を指定します。

1. truncation
    この引数は`Union[bool, str, PaddingStrategy]`を取りますが、筆者は`bool`しか意識したことがありません。デフォルトは`False`です。
    基本的にはモデルが扱えるsequence長には限界があるため`True`にしておくべき値です。

1. max_length
    この引数は`int`を取ります。
    PaddingやTruncationの基準となる最大長です。
    デフォルトは`None`です。

#### 出力形式の制御
`__call__`の出力形式を制御するために、`retunr_tensors`があります。
引数としては`Union[str, TensorType, NoneType]`ですが、基本的には文字列で打ち込むことが多い印象です。

戻り値のテンソル型を指定するため**非常に重要な引数です。**

後の作業でエラーを起こさないためにも明示的に指定すべき引数かと思います。

引数として、`"pt"`ならばPyTorchのテンソル、`"tf"`ならばTensorFlowのテンソル、`"np"`ならばNumPyの配列を返してきます。


#### その他の引数
その他に各モデルが必要とする情報に関数引数もあります。
以下一例です。

1. return_attention_mask
    引数としては`bool値`を取ります。
    `True`の場合は戻り値にAttention Maskも含まれます。

1. return_token_type_ids
    引数としては`bool値`を取ります。
    `True`の場合は戻り値にToken Type IDも含まれます。


```python
input_text = "Hello, How are you ?"

outputs = tokenizer(
    input_text,
    padding=True,
    truncation=True,
    max_length=512,
    return_tensors="pt"
)
```

## 何が出力されるのか
先ほどの[API reference](https://huggingface.co/docs/transformers/ja/main_classes/tokenizer#transformers.PreTrainedTokenizer.__call__)を見ると分かるのですが、戻り値としては[BatchEncoding](https://huggingface.co/docs/transformers/ja/main_classes/tokenizer#transformers.PreTrainedTokenizer.__call__.returns)を返します。

更に言うと、`input_ids`や`token_type_ids`をフィールドに持つBatchEncodingです。

どんなフィールドをどんな時に持つのかは[BatchEncodingのreference](https://huggingface.co/docs/transformers/ja/main_classes/tokenizer#transformers.PreTrainedTokenizer.__call__.returns)に記載があります。一読ください。

実際に確認してみます。
```python
input_text = "Hello, How are you ?"

outputs = tokenizer(
    input_text,
    padding=True,
    truncation=True,
    max_length=512,
    return_tensors="pt"
)

print(outputs)
# {'input_ids': tensor([[ 101, 7592, 1010, 2129, 2024, 2017, 1029,  102]]), 'token_type_ids': tensor([[0, 0, 0, 0, 0, 0, 0, 0]]), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1]])}
```

outputsは`input_ids`、`token_type_ids`、`attention_mask`のフィールドを持つことが確認できました。


# おわりに
今回はAutoClassesの内、`AutoConfig`と`AutoTokenizer`について学習しました。

これらはモデルを構築、使用するうえで重要な情報を提供するクラスです。
是非一度、API referenceなどを一読の上ご理解いただけますと幸いです。

次回は`AutoModelの基本`について学習しようかと思います。