9 ポイント 投稿者 GN⁺ 2024-10-24 | 1件のコメント | WhatsAppで共有
  • 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件のコメント

 
GN⁺ 2024-10-24
Hacker Newsのコメント
  • トークナイザーはLLMの「セクシー」な部分とは見なされていないが、そこに機会を見る人もいる。xValのような論文は、トークナイゼーションの特化戦略を提示している。スペリングや文字単位の作業は、トークナイゼーションの革新によって恩恵を受けられるもう1つの課題である

    • LLMは単語内の文字数を数えたり、文字の省略を行ったりするのが苦手である。たとえばGPT-4oは、文字の出現回数を数えるために小さなPythonプログラムを書いて実行する。トークナイゼーションは、プロンプト内の文字に関する知識を事実上消し去り、こうした作業の性能に直接的な悪影響を与える
  • 意味のある作業を行うには、データを理解する必要がある。多くの人が自動化されたデータ処理ツールを使う主な理由は、データを自分で見たくないからである。コンピュータがデータを見て、追加情報の収集を要求できるようになってほしい

  • ブログ記事の誤字に関する部分を特にありがたく思った。プロジェクトでRAGに似たアプリケーションを支援しており、ユーザークエリの小さな誤字や書式の違いが埋め込み距離の計算に与える影響を懸念している

    • 訓練データに意図的な誤字/置換/大文字化を加えて、wrkworkがおそらく同義語であることを学習させるべきか考えている
  • Elasticsearchを使って、1〜2文の入力と段落以上の文書との類似性を高度なテキストクエリで処理するアプリに携わったことがある。トークナイゼーション戦略が特定のクエリにどれほど影響しうるかは興味深かった

    • たとえばW-4W4のような場合、標準的なトークナイゼーションでは-や英字/数字の境界で分割されることがある。この入力はインデックス内で完全に識別不能になる
  • 記事では各問題に対する解決策の議論が不足しているように感じた。スペルチェックをトークナイズ前に実行したり、誤綴りの単語と修正候補の単語を並べてトークナイズしたりする方法が提案できる

    • ブランド名の問題については解決方法がわからない。この問題は、より一般的でない言語や、複合語を多く使う言語ではさらに深刻かもしれない
  • 多くの開発者は従来の(決定論的な)空間での開発に慣れているが、統計的空間で問題を考えるように発想を変えられていない。LLMアプリは最終的に統計的空間である

    • 開発者として、この問題をユーザーに説明するのに苦労している
  • RAGを実装する人の多くは、トークナイゼーションについてではなく埋め込みについて考えている

    • データコーパスをチャンクに分割し、各チャンクの埋め込みを計算する。クエリを生成し、各クエリの埋め込みを計算する。クエリとの距離でコーパスのチャンクを順位付けする。返り値を構成する
    • この記事は、システム性能に大きな影響を与えうる、隠れた比較的地味な作業の重要性を強調している
  • ブログ記事内の一部の数値を再現できない。たとえばSentenceTransformerを使ったコードで2つの文のコサイン類似度を計算した結果が、予想と異なる

  • 複数のRAG実装で、対象文書自体が入力クエリに対する良い検索キーになると仮定している問題を見てきた。最近のプロジェクトでは、検索キーを返り値(チャンク化された文書)から分離し、LMを使って適切なキーを生成して埋め込むことで、検索関連性が大きく向上した

  • 多くの大規模LLMの語彙はかなり大きいとはいえ、英語だけでも100万語以上ある。30k〜300kトークンは小さく見える