- e-commerceデータを扱うAIアプリ開発を支援する過程で、Retrieval-augmented generation(RAG)が一部のクエリではうまく動作する一方、別のクエリではそうならないという問題を発見した
- このような問題を解決する際には、入力データ(インデックス化された元テキスト、検索に使われるユーザークエリ)を確認することが重要
- 特にchunkingとトークナイゼーションの観点で最適化が必要に見えた
[Tokenization]
- トークナイゼーションは、テキストをトークナイザーによってより小さな断片であるトークンに分解する過程
- これらのトークンは、トークナイザー語彙内でトークンを一意に識別する整数値であるトークンIDにマッピングされる
- トークナイザー語彙は、トークナイザーの学習に使われるすべての可能なトークンの集合
- テキストのトークンがLLMのトークナイザー語彙に存在しない場合、問題が発生する可能性がある
- ほとんどのLLMは30k〜300k規模の大きな語彙を持っている
- 広く使われているLLMの多くはsubwordトークナイザーに依存している(BPE、Wordpieceなど)
- トークナイザーの種類
- word: 空白文字や句読点などを基準に分割
- character: 個々の文字(場合によっては句読点まで)に分割
- subword: トークンを、一見意味がないように見える下位語に分割
- ほとんどのLLMはsubwordトークナイザーを使用
- BPE(Byte-Pair Encoder): OpenAIの
tiktokenライブラリ
- Wordpiece: Cohere、MiniLM-L6-v2 など
MiniLM-L6-v2とtiktokenの比較
- MiniLM-L6-v2モデルのトークナイザー語彙サイズは30522で、tiktoken(200019)よりはるかに小さい
- "tokenizer tokenizes text into tokens" という文をトークナイズすると
- MiniLM-L6-v2: [CLS] token ##izer token ##izes text into token ##s [SEP]
- tiktoken: token, izer, token, izes, text, into, tokens
- OpenAIの
tiktokenライブラリはBPEトークナイザーを実装しており、ChatGPTのLLMモデルで使われている
- MiniLM-L6-v2の語彙にはドイツ語の文字や日本語の文字も含まれている
絵文字、タイプミス、ドメイン特化語のトークナイジング
- MiniLM-L6-v2は絵文字を
[UNK]トークンとしてトークナイズする
- tiktokenは一部のUnicode文字トークンで学習されているが、RAGでは依然として問題になりうる
- "Gucci Savoy Leathertrimmed Printed Coatedcanvas Suitcase" のようなドメイン特化の製品名も適切にトークナイズされない
- タイプミスのある文("I hve received wrong pckage")の場合
- MiniLM-L6-v2: i, h, ##ve, received, wrong, pc, ##ka, ##ge
- tiktoken: I, h, ve, received, wrong, p, ck, age
[Embeddings]
- トークナイザー自体はそれほど有用ではない。主に個々のトークンの頻度に基づいて複雑な数値分析を行うために開発された
- テキストの文脈的意味を保持するには、トークン間の関係を捉えられる方法が必要
- 埋め込みはトークンを表すベクトルであり、テキスト内の単語間の意味や関係をうまく捉える
- 埋め込みはTransformer学習の副産物であり、トークナイズされた大量のテキストから実際に学習される
- テキスト生成を依頼する際にLLMへ入力として与えられるのが、まさにこの埋め込み
- LLMはエンコーダーとデコーダーという2つの主要コンポーネントで構成される
- エンコーダーとデコーダーはいずれも埋め込みを入力として受け取る
- エンコーダーの出力もまた埋め込みであり、これはデコーダーのcross-attentionヘッドへ渡され、デコーダー出力のトークン生成(予測)に重要な役割を果たす
- RAGパイプラインでは、テキストはまずトークナイズされ、埋め込み化された後、Transformerに入力される
- トークンIDはトークナイザー語彙のインデックスとして機能し、埋め込み行列から埋め込みを取り出す際にも使われる
- 取り出した埋め込みはテンソルとして組み立てられ、Transformer入力として与えられる
- エンコーダーの流れ: テキストをトークナイズ -> 各トークンの埋め込みを取得 -> 埋め込みテンソルを組み立てる -> Transformer入力に入れる -> エンコード -> エンコーダー出力をデコーダーのcross-attentionに渡す -> デコーダー出力を生成
埋め込みの例
- "You can break it 😞" と "You can not break it 😊" は感情が正反対であるにもかかわらず、MiniLM-L6-v2では埋め込み距離が非常に近い
- OpenAIはトークン語彙が絵文字をうまく扱えるため、より良い性能を示す
- タイプミスの場合でもOpenAIのほうがうまく処理する
- しかしOpenAIでも、文末に空白を追加すると埋め込み間の距離が予想外に広がる
- 日付形式を扱う際にも開発者は苦労する。相対的な時間表現("昨日発送されました")は特に大きな問題になりうる
- 通貨表記(£40、$50、40£、50¢ など)の違いも奇妙な問題を引き起こすことがある
- Gucciのバッグの事例のようにドメイン特化データの場合、通常はファインチューニングで解決するが、常にデータと評価指標を必ず確認すべき
結論
- この記事は、トークナイザーがRAGアプリにどのような影響を与えうるのか、そしてなぜトークナイザーに注意を払うべきなのかをよりよく理解させてくれる
- エージェントアプリケーションでは、garbage-in garbage-out が常に期待どおりの成果を出すとは限らない
- 入力テキストを少し整えるだけでも大きな助けになることがある
- 日付形式を一貫して標準化する
- 可能な限り末尾の空白を削除する(埋め込みへの影響が確認されている)
- 異なる通貨の価格など、ほかの数値データにも同様に適用する
- いつかはトークナイザーのことをまったく考えなくてよくなることを願う。完全に捨てられるようになってほしい
- そうなれば、タイプミス、任意の空白文字、単語perplexityベースの敵対的攻撃などを扱う必要もなくなる。ある種の悲しみが一夜にして消えるかもしれない
- それまでは責任を持ってトークナイズしよう
GN⁺の意見
- この記事は、トークナイザーと埋め込みがRAGベースのAIアプリの性能にどのような影響を与えうるかをよく示している。特に絵文字、タイプミス、ドメイン特化用語などを扱う際の注意点を実例とともに説明しており、開発者にとって大いに参考になりそうだ
- ただし、この記事で紹介されているMiniLM-L6-v2とOpenAIの
tiktokenはいずれも英語に最適化されたモデルであるため、日本語のような他言語を扱う際には追加の考慮事項がありうる。日本語では形態素解析を用いたトークナイジングが多く使われており、それに伴う長所・短所や限界についても見ていく必要がありそうだ
- また、この記事はRAGパイプラインにおけるトークナイザーと埋め込みの役割に焦点を当てているが、実際の本番環境ではデータ前処理、ハイパーパラメータ調整、モデル軽量化など、考慮すべき事項ははるかに多い。したがって、この記事の内容はひとつの出発点としつつ、実際の開発過程ではさまざまな実験と評価を通じて最適な方法を見つけていくことが重要だと思われる
- 一方で、GPT-4のような大規模言語モデルの登場によって、トークナイザーの重要性が低下しているという意見もある。これらのモデルはトークンレベルではなく文または段落レベルで動作するため、個々のトークンの品質が性能に与える影響が相対的に小さくなる可能性があるためだ。ただし、これについてはまだ研究が十分ではなく、断定するのは難しそうだ
- 最後に、この記事で言及されているように、入力データを事前に整形・標準化するだけでもモデル性能を大きく改善できる。実サービスを開発する際には、ユーザー入力の多様性とノイズを考慮し、堅牢なデータ前処理パイプラインを構築することが非常に重要になりそうだ。あわせて、データラベリングやアノテーション作業にも十分なリソースを投入し、高品質な学習データを確保する必要がありそうだ
1件のコメント
Hacker Newsのコメント
トークナイザーはLLMの「セクシー」な部分とは見なされていないが、そこに機会を見る人もいる。xValのような論文は、トークナイゼーションの特化戦略を提示している。スペリングや文字単位の作業は、トークナイゼーションの革新によって恩恵を受けられるもう1つの課題である
意味のある作業を行うには、データを理解する必要がある。多くの人が自動化されたデータ処理ツールを使う主な理由は、データを自分で見たくないからである。コンピュータがデータを見て、追加情報の収集を要求できるようになってほしい
ブログ記事の誤字に関する部分を特にありがたく思った。プロジェクトでRAGに似たアプリケーションを支援しており、ユーザークエリの小さな誤字や書式の違いが埋め込み距離の計算に与える影響を懸念している
wrkとworkがおそらく同義語であることを学習させるべきか考えているElasticsearchを使って、1〜2文の入力と段落以上の文書との類似性を高度なテキストクエリで処理するアプリに携わったことがある。トークナイゼーション戦略が特定のクエリにどれほど影響しうるかは興味深かった
W-4やW4のような場合、標準的なトークナイゼーションでは-や英字/数字の境界で分割されることがある。この入力はインデックス内で完全に識別不能になる記事では各問題に対する解決策の議論が不足しているように感じた。スペルチェックをトークナイズ前に実行したり、誤綴りの単語と修正候補の単語を並べてトークナイズしたりする方法が提案できる
多くの開発者は従来の(決定論的な)空間での開発に慣れているが、統計的空間で問題を考えるように発想を変えられていない。LLMアプリは最終的に統計的空間である
RAGを実装する人の多くは、トークナイゼーションについてではなく埋め込みについて考えている
ブログ記事内の一部の数値を再現できない。たとえばSentenceTransformerを使ったコードで2つの文のコサイン類似度を計算した結果が、予想と異なる
複数のRAG実装で、対象文書自体が入力クエリに対する良い検索キーになると仮定している問題を見てきた。最近のプロジェクトでは、検索キーを返り値(チャンク化された文書)から分離し、LMを使って適切なキーを生成して埋め込むことで、検索関連性が大きく向上した
多くの大規模LLMの語彙はかなり大きいとはいえ、英語だけでも100万語以上ある。30k〜300kトークンは小さく見える