AIモデルの注意機構を紐解く:『走れメロス』を題材にしたLLM解析
※ この記事は前の記事の続きになります。 AIモデルの裏側を探る:アテンションメカニズムの可視化とは?を参照してください。 先の記事で、LLMのアテンション機構の可視化を実施しました。そこからの続きで別の文について、可視化を試みてみます。モデルをGPT-2系の日本語モデルに変えて、『走れメロス』の冒頭の文に挑戦してみました。使用したのは以下の文になります。「メロスは激怒した。必ず、かの邪智暴虐の王を除かなければならぬと決意した。メロスには政治がわからぬ。メロスは、村の牧人である。笛を吹き、羊と遊んで暮して来た。けれども邪悪に対しては、人一倍に敏感であった。」 基本的なコードは先のコードですが、幾つか変わっています。実験はGoogle Colab上で行っています。 import torch from transformers import GPT2Model, T5Tokenizer, GPT2LMHeadModel import matplotlib.pyplot as plt import seaborn as sns import japanize_matplotlib tokenizer = T5Tokenizer.from_pretrained("rinna/japanese-gpt2-medium") model = GPT2LMHeadModel.from_pretrained("rinna/japanese-gpt2-medium", attn_implementation="eager") text = "メロスは激怒した。必ず、かの邪智暴虐の王を除かなければならぬと決意した。メロスには政治がわからぬ。メロスは、村の牧人である。笛を吹き、羊と遊んで暮して来た。けれども邪悪に対しては、人一倍に敏感であった。" tokens = tokenizer(text, return_tensors="pt") # トークンIDを対応する単語へ変換 tokens_list = tokenizer.convert_ids_to_tokens(tokens["input_ids"][0].tolist()) # 最後の層、最初のAttentionヘッドを取得 layer_idx = -1 head_idx = 0 attention_matrix = attentions[layer_idx][0, head_idx].cpu().numpy() # 左上1/4部分を切り取る quarter_size = attention_matrix.shape[0] // 2 # 行列サイズの1/2を計算 subset_matrix = attention_matrix[:quarter_size, :quarter_size] # 左上1/4部分を抽出 # 対応するトークンのリストも切り取る subset_tokens = tokens_list[:quarter_size] # ヒートマップを描画 plt.figure(figsize=(8, 8)) sns.heatmap(subset_matrix, cmap="viridis", xticklabels=subset_tokens, yticklabels=subset_tokens) plt.xlabel("Attention対象") plt.ylabel("Attention元") plt.title("左斜め上1/4のAttentionマップ拡大表示") plt.xticks(rotation=90, fontsize=8) plt.yticks(fontsize=8) plt.show() 可視化した結果が以下になります。アテンションマップの隅1/4を拡大しています。 ここから言えることは、恐らく、メロスの単語が辞書にないためだと思いますが、メロスの挙動は不安定です。その結果、周囲の文脈から何を意味しているか推測している可能性があります。また、主語「メロス」と「邪」のようなワードに注意が向いているようです。「邪智暴虐」という表現が特徴的ですから、AIがそのフレーズを重要だととらえている可能性があります。また、文のイメージがネガティブというのも影響している可能性があります。また、除にも注意が向いているので、「除かなければならぬ」などの文脈に注意が流れている可能性があります。
AIモデルの裏側を探る:アテンションメカニズムの可視化とは?
最近、あちこちに出てきた、Anthtropicの"On the Biology of a Large Language Model"が気になった。紹介としては、MIT Technology Reviewの"大規模言語モデルは内部で 何をやっているのか? 覗いて分かった奇妙な回路(有料記事)“がある。しかし、有料記事であり私も、中身を見ていない。そのため、この記事のベースであろう、原著論文を辿った。 その結果、以下のことが示唆されるようだ。とりあえず、原著論文をNotebookLM Plusに持ち込んで、最近の成果について尋ねてみた。 多段階推論: Claude 3.5 Haikuが、例えば「ダラスを含む州の州都は?」という質問に対して、「テキサス」という中間的な概念を内部で特定し、「オースティン」という最終的な答えを導き出すといった**「二段階」の推論**を実際に行っていることが示されました。アトリビューショングラフによって、この内部ステップを視覚的に捉え、操作することも可能です。 詩の作成における計画: モデルが詩の行を書く前に、潜在的な韻を踏む単語を事前に特定し、計画していることが発見されました。これらの事前に選択された韻の候補が、その後の行全体の構成に影響を与えている様子が観察されています。 多言語回路: Claude 3.5 Haikuは、言語固有の回路と、言語に依存しない抽象的な回路の両方を使用していることがわかりました。より小型で能力の低いモデルと比較して、言語に依存しない回路がより顕著であることが示されています。これは、モデルが概念をより普遍的なレベルで理解し、処理する能力が高まっていることを示唆しています。 足し算の一般化: 同じ足し算の回路が、非常に異なる文脈間で一般化されている事例が確認されました。これは、モデルが抽象的な計算能力を獲得していることを示唆しています。 医療診断: モデルが報告された症状に基づいて候補となる診断を内部で特定し、それらを用いて追加の症状に関するフォローアップの質問を生成する様子が示されました。これも、モデルが明示的にステップを書き出すことなく「頭の中で」推論を行っている例です。 エンティティ認識とハルシネーション: モデルが既知のエンティティと未知のエンティティを区別する回路を持つことが明らかになりました。この回路の「誤作動」がハルシネーションの原因となる可能性があることが示唆されています。既知のエンティティに関する質問に対しては、モデルは既知の答えを抑制する回路を活性化させることがわかっています。 有害な要求の拒否: モデルが、事前学習中に学習した特定の有害な要求を表す特徴から集約された、汎用的な「有害な要求」の特徴をファインチューニング中に構築する証拠が見つかりました。 ジェイルブレイクの分析: 特定のジェイルブレイク攻撃が、モデルを「気付かないうちに」危険な指示を与え始めさせ、その後、構文的および文法的な規則に従う圧力によって継続させるメカニズムが調査されました。 連鎖的思考の忠実性: モデルが連鎖的思考(CoT)で示す推論が、実際の内部メカニズムと一致する場合、そうでない場合、そして人間が与えた手がかりから逆向きに推論している場合を区別することが可能になりました。 隠れた目標を持つモデルの分析: 訓練プロセスの「バグ」を悪用するという秘密の目標を持つようにファインチューニングされたモデルの変種に対して、その目標の追求に関与するメカニズムが特定されました。興味深いことに、これらのメカニズムはモデルの「アシスタント」ペルソナの内部表現に埋め込まれていました。 ここで、アトリビューショングラフに関心ができた、では、例えばGPT-2でアトリビューショングラフが作れないかと言うのが今回のテーマとなる。 さすがに、GPT-4oのようなモデルは中身が公開されていないし、公開されているとしても、DeepSeek-R1などはモデル規模が大きすぎ、そもそも、処理が重すぎる。 それで、古典的なモデルであるGPT-2に目を付けた。 そのため、以下のようなコードを実行した。 import torch from transformers import GPT2Model, GPT2Tokenizer import matplotlib.pyplot as plt import seaborn as sns tokenizer = GPT2Tokenizer.from_pretrained("gpt2") model = GPT2Model.from_pretrained("gpt2", attn_implementation="eager") text = "The quick brown fox jumps over the lazy dog." tokens = tokenizer(text, return_tensors="pt") with torch.no_grad(): outputs = model(**tokens, output_attentions=True) attentions = outputs.attentions # これはリスト形式で各層のAttentionを含む # 例えば、最後の層のAttentionを可視化 layer_idx = -1 head_idx = 0 # 最初のAttentionヘッドを選択 attention_matrix = attentions[layer_idx][0, head_idx].cpu().numpy() plt.figure(figsize=(8, 8)) sns.heatmap(attention_matrix, cmap="viridis", xticklabels=tokens["input_ids"][0], yticklabels=tokens["input_ids"][0]) plt.xlabel("Attention対象") plt.ylabel("Attention元") plt.title("GPT-2のAttentionマップ") plt.show() このコードによって、以下のように最後の層のAttentionが可視化される。 ...
Hugo PaperModにBlueskyへの共有を追加する
このBlogでは、現在、Hugo PaperModをテーマとして使用しています。現在、Hugo PaperModは結構いろいろなSNSに共有する機能がありますが、 残念ながらBlueskyへの共有はついていません。しかし、対応自体は可能です。 まず、共有はthemes/hugo-PaperMod/layouts/partials/share_icons.htmlに実体があります。 この中を見ていきます。 以下のようなものが見えてきます。 {{- if (or (cond ($custom) (in $ShareButtons "x") (true)) (cond ($custom) (in $ShareButtons "twitter") (true))) }} <li> <a target="_blank" rel="noopener noreferrer" aria-label="share {{ $title | plainify }} on x" href="https://x.com/intent/tweet/?text={{ $title }}&url={{ $pageurl }}&hashtags={{- $.Scratch.Get "tags" -}}"> <svg version="1.1" viewBox="0 0 512 512" xml:space="preserve" height="30px" width="30px" fill="currentColor"> <path d="M512 62.554 L 512 449.446 C 512 483.97 483.97 512 449.446 512 L 62.554 512 C 28.03 512 0 483.97 0 449.446 L 0 62.554 C 0 28.03 28.029 0 62.554 0 L 449.446 0 C 483.971 0 512 28.03 512 62.554 Z M 269.951 190.75 L 182.567 75.216 L 56 75.216 L 207.216 272.95 L 63.9 436.783 L 125.266 436.783 L 235.9 310.383 L 332.567 436.783 L 456 436.783 L 298.367 228.367 L 432.367 75.216 L 371.033 75.216 Z M 127.633 110 L 164.101 110 L 383.481 400.065 L 349.5 400.065 Z" /> </svg> </a> </li> {{- end }} これは、Twitter(X)への共有機能ですが、この前でも後ろでもに以下のようなものを挿入します。ただし、themes以下を直に変更すると面倒なので、ベストプラクティス通り、layouts/partialsに複製して変更します。 ...
HugoによるBLOGサイトの作成
もともとは、他のBLOGの記事をベースに書いていた記事があったのですが、 参考サイトがなくなってしまったため、すべてを書く必要が生じました。 そのため、前提条件を含めて記載します。なお、本記事はWindows環境下を前提にしています。 ※ なお、この記事はまだ作成を進めているので、予告なく変更されます。 レポジトリ構成 この記事では次のレポジトリ構成を想定しています。 BLOG用メインレポジトリ 記事公開用レポジトリ 記事公開用レポジトリはサブモジュールとして、BLOG用メインレポジトリに組み込みます。したがって、全体のディレクトリ構成は以下のようになります。 / - root | - archetypes | - content | - post | - layouts | - public | - static | - theme 記事公開用レポジトリはpublicに組み込みます。 テーマ管理用レポジトリはthemeの配下に組み込みます。 使用したツール 名称 Visual Studio Code cmd scoop 必要なツールの取得 scoopのインストール スタートからPowerShellを起動する PowerShellの設定変更 Set-ExecutionPolicy RemoteSigned -scope CurrentUser PowerShellからのScoopのインストール iex (new-object net.webclient).downloadstring('https://get.scoop.sh') gitのインストール scoop install git hugoのインストール scoop install hugo-extended テーマの準備 テーマは https://themes.gohugo.io/ から探されるといいと思います。 テーマに対する小幅な変更はlayouts以下に同構造でファイルを複製して修正することになります。これにより、themes以下を直接修正しなくても良くなります。 本アーティクルでは、hugo-PaperModの使用を前提として進めます。 BLOG用メインレポジトリの準備 を以下のコマンドで準備します。 hugo new site <my_site> BLOG用のディレクトリが出来たら git init後、github等適当なところにpushします。 テーマは適当にsubmodule addします。submodule addするポイントはthemes以下となります。 ...
EvidenceによるBI入門 #003.1
Evidenceを理解する上でのポイントとして、静的サイトジェネレータを箸休めとして説明します。 まず、静的サイトと動的サイトの区別からです。静的サイトとは、コンテンツがファイルとして固定され、サーバはリクエストに基づきただ配信するだけのものです。初期のホームページと言われたもののスタイルです。 次に動的サイト、これはリクエストに応じて何らかのコードがサーバ上で実行され、動的にレスポンスが生成され、それがクライアントに返されるものです。WordpressなどのBLOGサービスなどはこの形態です。 静的サイトとは Wordpressなどではコンテンツはデータベースに格納されたものがベースで、同じようにテーマなどの情報がデータベースに格納され、それがユーザのリクエストによって組み立てられて返答されるという構造です。 静的サイトと動的サイトの差異 これだけで「静的サイトジェネレーター」のすべてがわかりますを参考にすれば以下のように纏められます。 動的サイト 静的サイト 表示されるページ ユーザーに応じて表示するページを変更できる 全員に同じページを表示する スピード 遅い 速い ページが生成される時 アクセスされた時 ビルド時 Wordpressなどが動的サイトとして構成されたのは、データベースにコンテンツ、テーマを格納しそれをリクエスト時に構築するという構造が都合が良かったためです。 静的サイトが再度注目された理由 しかし、今、再度、静的サイトジェネレータが注目された理由があります。まず、宿命的に表示されるコンテンツをユーザに合わせてというのは苦手ですが、通常のBlogサービスであれば、読者は通常ログインなどの手続きをしないため、ユーザに合わせては要件から除外できます。そうすると、動的サイトのメリットはかなり減ります。恐らく、GUIでのWebベースでのコンテンツメインテナンスなどのこの表に書かれていないモノになるでしょう。 そして、「全員に同じページを表示する」であれば、コンテンツへのテーマなどの適用はアクセス時にこだわる必要性はないになります。よって、バッチ的にサイトをコンテンツから生成する静的サイトジェネレータとなるわけです。 静的サイトジェネレータを支える要素 静的サイトジェネレータが注目された理由はそれだけではありません。一つはクライアント端末の性能向上です。例えば、昔の携帯電話のパフォーマンスと今のスマートフォンのパフォーマンスを比べてください。昔の携帯電話、フィーチャーフォン向けに開発された、CHTMLなどはかなりの仕様を削減していました、当然、クライアント側でのコード実行などは考えてすらいませんでした。しかし、今のスマートフォンはクライアント側でのモバイルコードの実行には十分であり、ECMA Script、WebAssemblyなどの支援もあります。故にコードの実行をWebサーバからクライアントに移すことも可能になりました。 故に、無理に、サーバ側で全てのコンテンツをレンダリングする必要はなくなりました、また、動的コンテンツを残すとしても、インラインフレームなどで組み込みむ手段もあります。従って、メインのコンテンツを動的に生成することは必ずしも必要なくなくなりました。 静的サイトジェネレータの限界 とはいえ、最初に上げた、「全員に同じページを表示する」という特性は無くなることはありません。 従って、静的サイトジェネレータを基盤とするBIツールであるEvidenceでは例えば、ユーザを認識してコンテンツを変えるなどは苦手です。例えば、厳密に、Need-to-Knowを実現するのは困難です。サイト自体に認証などは出来るにしても、コンテンツをユーザに合わせてレンダリングするのは困難です。 この辺のポイントを理解するのが、Evidenceを有効活用する道になります。