<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:webfeeds="http://webfeeds.org/rss/1.0">
  <title>DataScience カテゴリ | フューチャー技術ブログ</title>
  <subtitle>DataScience カテゴリの記事一覧</subtitle>
  <icon>https://future-architect.github.io/feed_icon.png</icon>
  <logo>https://future-architect.github.io/apple-touch-icon.png</logo>
  <webfeeds:icon>https://future-architect.github.io/apple-touch-icon.png</webfeeds:icon>
  <webfeeds:accentColor>258fb8</webfeeds:accentColor>
  <link href="https://future-architect.github.io/categories/DataScience/atom.xml" rel="self"/>
  <link href="https://future-architect.github.io/categories/DataScience/"/>
  <updated>2026-07-21T15:00:00.000Z</updated>
  <id>https://future-architect.github.io/categories/DataScience/</id>
  <generator uri="https://hexo.io/">Hexo</generator>
  <entry>
    <title>基礎から深く理解する、実践型NLP講習会の取り組み</title>
    <link href="https://future-architect.github.io/articles/20260722a/"/>
    <id>https://future-architect.github.io/articles/20260722a/</id>
    <published>2026-07-21T15:00:00.000Z</published>
    <updated>2026-07-21T15:00:00.000Z</updated>
    <author><name>岸波洋介</name></author>
    <content type="html"><![CDATA[<h2 id="はじめに">はじめに</h2><p>みなさんこんにちは！AI戦略推進グループ (AIXG) の岸波と申します。入社後はAIXGの自然言語処理 (NLP) チームに所属し、現在は主にNLPに関する研究開発や社会実装に取り組んでいます。</p>
<p>私たちのチームでは、約3カ月間にわたる実践的なNLP講習会を昨年から社内で開催しています。</p>
<p>そして先月、第2期（2年目）が無事に一区切りを迎えました。</p>
<p>このブログでは、私たちが継続して取り組んでいるこの講習会の内容や特徴についてご紹介します。ブログを通して、「フューチャーではこんな取り組みも行っているんだな」「こんな成長環境があるんだな」ということをぜひ知っていただけたら嬉しいです！</p>
<h2 id="講習会実施のきっかけ">講習会実施のきっかけ</h2><p>最近では、AIエージェントや大規模言語モデル (LLM) の話題を聞かない日はないほど、私たちの日常生活や仕事でも幅広く活用されています。</p>
<p>当社のNLPチームでも、AIエージェントやLLMを中心としたNLPの技術を応用するプロジェクトに日々取り組んでいます。チームには、学生時代からNLPを専門に研究してきたメンバーもいれば、別の領域から新たにNLPにチャレンジしているメンバーもおり、バックグラウンドはさまざまです。</p>
<p>NLPチームのメンバーとしてプロジェクトを進めていくにあたり、技術の根本から理解し、これまでの分野の流れや概況をつかんでおくことは非常に重要です。さまざまなタスクやアプローチを基礎から理解しておくことで、実際のプロジェクトで課題が発生した際に「この課題はこのNLPタスクの枠組みに近いかもしれない」「この課題なら、この手法が有効かもしれない」と、自身の引き出しを増やすことができます。</p>
<p>そのような狙いから、基礎から最先端の実装までを一貫して学ぶことができる実践型のNLP講習会を社内で企画・実施しています。</p>
<h2 id="講習会の全体像">講習会の全体像</h2><p>本講習会は、大きく4種類のカリキュラムで構成しており、全体で約3カ月間かけて実施しています。</p>
<ul>
<li>NLPプログラミングの基礎</li>
<li>教科書の輪読</li>
<li>LLMやAIエージェントの実践チュートリアル</li>
<li>自由課題</li>
</ul>
<p>カリキュラムは大学の研究室などで新規配属者向けに行われている勉強会※も参考にしながら、当社の実業務での応用を見据えて作成しました。</p>
<p>これらのカリキュラムは<strong>業務の一環として、しっかりと時間を確保して</strong>取り組んでいます。日頃は自習として実装や教科書理解を進めつつ、週次で講義ミーティングを実施して全員で議論する時間を取っています。</p>
<p>※ 特にTohoku NLP Groupで開催されている自然言語処理基礎勉強会や、プログラミング基礎勉強会を参考にさせていただきました。</p>
<h3 id="NLPプログラミングの基礎">NLPプログラミングの基礎</h3><p>指定の教材を活用しながら実際に手を動かし、NLPに関する実装力を身につけるカリキュラムです。</p>
<p>Pythonでの基本的なテキスト処理から、NLP特有のライブラリの使い方、機械学習の基礎、APIを利用したLLMの扱いなどを学びます。これらは実際のプロジェクトでNLPの技術を利用したアプローチを実装する際にも活かせる実践的なコーディングスキルです。</p>
<h3 id="教科書の輪読">教科書の輪読</h3><p>指定の教科書を受講メンバーで読み進め、NLPに関するタスクの一般的なアプローチや、現在のLLMを支える技術の根幹などの理解を深めます。</p>
<p>あわせて、教科書の題材に関する最新技術や応用例も紹介し、実際のプロジェクトでの応用イメージもつかんでもらいながら進めます。</p>
<h3 id="LLMやAIエージェントの実践チュートリアル">LLMやAIエージェントの実践チュートリアル</h3><p>実際にローカルLLMを特定のタスクのデータでファインチューニングしたり、AIエージェントを構築したりといった応用的なチュートリアルを実施します。</p>
<p>実装コードを追いながら実際に動かすことで、学習や推論過程などをブラックボックスにせず、1つ1つ理解しながら学びます。</p>
<h3 id="自由課題">自由課題</h3><p>最後は集大成として、参加者それぞれが自由なテーマを設定し、アプローチ検討から実装、評価実験、分析を1周することに挑戦します。</p>
<p>ここまで学んだ知識をフル活用して各自がゼロから作り上げるため難易度は高いですが、実際のプロジェクトに近い形で、特定の課題に対する試行錯誤の一連の流れを経験できます。</p>
<p>↓自由課題のテーマ例</p>
<img fetchpriority="high" src="/images/2026/20260722a/image1.png" alt="image1.png" width="1200" height="574">

<img src="/images/2026/20260722a/image2.png" alt="image2.png" width="928" height="198" loading="lazy">

<h2 id="講習会の特徴">講習会の特徴</h2><p>本講習会は、カリキュラムを単なる自習や座学で終わらせず、参加メンバー全員が技術を深く、そして楽しみながら学べるような特徴や雰囲気があります。</p>
<h3 id="手厚いメンター制">手厚いメンター制</h3><p>各カリキュラムには、過去の講習会受講メンバーやその領域に知見を持ったメンバーがメンターとしてサポートする体制をとっています。</p>
<p>メンターは受講メンバーが実装したコードへのコメントや、理解に困ったポイントへの解説などを行います。</p>
<p>さらに、自身の知見や経験に基づいて教材にはない情報を補足することで、より理解が深まり幅広い知識を得ることができます。特に過去に受講したメンバーがメンターを務めるシステムは、<strong>ただ受講して終わるのではなく、次は自身が育てる・サポートする側に回るという良いサイクル</strong>に繋がっています。</p>
<h3 id="実際のプロジェクトとの接続">実際のプロジェクトとの接続</h3><p>週次の講義ミーティングでは、メンターから実際のプロジェクトでの応用例なども紹介してもらっています。</p>
<p>これによって、今学んでいることの意義・価値を感じながら進めることができ、受講メンバーのモチベーション維持に繋がっています。</p>
<h3 id="質問しやすく柔軟に学べる環境">質問しやすく柔軟に学べる環境</h3><p>現在は比較的少人数で進めていることもあり、全体として質問しやすい雰囲気で進んでいます。</p>
<p>また、講義ミーティングは録画してアーカイブ化されているため、<strong>各自のプロジェクトの業務状況に合わせて柔軟にキャッチアップできる</strong>形をとっています。</p>
<h2 id="受講者からの声">受講者からの声</h2><p>講習会を完走したメンバーからは以下のような声をいただいており、過去の受講メンバーもすでにNLPに関するプロジェクトの第一線で活躍しています。</p>
<ul>
<li>「これまでよく理解できていなかった部分が講習を通じてクリアになりました。概要レベルの知識から一歩踏み込み、実際のモデルの学習プロセスや論文内のアーキテクチャの意味が少しずつ紐解けるようになったと感じています。」</li>
<li>「日々の業務にて『なんとなく』の理解で進めていたところが講習会に参加することで明確になり、自分のナレッジとして正しく蓄積できたと感じています。また、自由課題では、普段の業務で触れている技術と向き合いながら進めることで、技術的な価値や困難をより実感でき、日々の業務にも生かすことができるような経験ができました。」</li>
<li>「これまで触れてこなかった分野で仕事をするにあたっての基礎知識吸収の場として参加させていただき、自然言語処理の統計的手法や機械学習など、様々な知識を吸収できました。基礎知識が身に付いたことにより、日々の業務の理解度が向上したとともに、実際のプロジェクトでも複数の手段を検討できており、成果物の品質向上にも寄与していると感じています。」</li>
</ul>
<h2 id="おわりに">おわりに</h2><p>昨年から実施している講習会ですが、多くの方々からのご協力のもと今年も開催できました。</p>
<p>受講メンバーからも好評で、今後もさらにアップデートしながら継続的に実施していきたいと思っています。また、特徴でも触れたように「学んだメンバーが次に教える側に回る」という良いサイクルを次回以降も回し続けることで、個人の成長にとどまらず、チーム全体の技術力向上に繋げていきたいと考えています。</p>
<p>AIXGでは、このように社員の成長をチーム全体で後押しし、最先端の技術を楽しみながらキャッチアップしていける環境も大切にしています。</p>
<p>そして、ともに自然言語処理の実社会応用を推進していく方も募集しています！ ご興味を持っていただいた方、ぜひAIXGで一緒に働きましょう！</p>
<ul>
<li>新卒採用 : https://www.future.co.jp/recruit/recruit/rec-fresh/</li>
<li>キャリア採用 : https://www.future.co.jp/recruit/recruit/rec-career/</li>
</ul>
]]></content>
    <summary type="html">私たちのチームでは、約3カ月間にわたる実践的なNLP講習会を昨年から社内で開催しています。そして先月、第2期（2年目）が無事に一区切りを迎えました。このブログでは、私たちが継続して取り組んでいるこの講習会の内容や特徴についてご紹介します。</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="AIエージェント" scheme="https://future-architect.github.io/tags/AI%E3%82%A8%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%B3%E3%83%88/"/>
    <category term="LLM" scheme="https://future-architect.github.io/tags/LLM/"/>
    <category term="NLP" scheme="https://future-architect.github.io/tags/NLP/"/>
    <category term="機械学習" scheme="https://future-architect.github.io/tags/%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92/"/>
  </entry>
  <entry>
    <title>AWS Certified Generative AI Developer - Professional 合格体験記 - 試験対策をサービスアイデアに昇華させて一発合格</title>
    <link href="https://future-architect.github.io/articles/20260721a/"/>
    <id>https://future-architect.github.io/articles/20260721a/</id>
    <published>2026-07-20T15:00:00.000Z</published>
    <updated>2026-07-20T15:00:00.000Z</updated>
    <author><name>棚井龍之介</name></author>
    <content type="html"><![CDATA[<img fetchpriority="high" src="/images/2026/20260721a/aws-certified-generative-ai-developer-professional.png" alt="aws-certified-generative-ai-developer-professional.png" width="600" height="600">

<h2 id="はじめに">はじめに</h2><p>フューチャーでFutureVuls（脆弱性管理SaaS）の開発に携わる棚井です。2026年7月14日に AWS Certified Generative AI Developer - Professional (AIP-C01) を受験し、794点&#x2F;1000点（合格ライン750点）で一発合格しました。</p>
<p>受けた動機はシンプルで、生成AIの知識武装です。</p>
<p>前回の AWS Certified Advanced Networking - Specialty の合格体験記 の最後に、「設計から障害調査までをAIが担うようになっても、その出力の妥当性を自分で見極められるように、知識をアップデートし続けたい」と書きました。書いておいて何ですが、そのAIを、当時の私はノリと雰囲気で使っていただけです。</p>
<img src="/images/2026/20260721a/俺たちは雰囲気で.png" alt="俺たちは雰囲気で.png" width="640" height="384" loading="lazy">

<p>（上の画像は 雰囲気ジェネレータ で生成しました）</p>
<p>Claude CodeもPerplexityも、仕事でも仕事以外でも毎日のように使っています。ただ正直なところ、その多くは勘で動かしているだけで、内側で何が起きているかは分かっていません。</p>
<p>RAGやファインチューニングにしても、概念としては知っているものの、いざ設計や実装のレベルになると手が止まります。AIにまるごと渡せば、いい感じに処理してくれるので、それ以上を深掘りする機会がありませんでした。それほど、手軽にAIを使えるようになったのだとも言えます。</p>
<p>ちょうどAWSから、生成AIアプリ開発に振り切ったProfessionalの新しい認定が出たので、これを言い訳のきかない締め切りにして学び直すことにしました。</p>
<h2 id="試験の概要">試験の概要</h2><p>AIP-C01 は、AWSの認定のなかで初のProfessionalレベルのAI&#x2F;生成AI専門資格です。これまでAIまわりの認定は、基礎の AI Practitioner (AIF-C01) とAssociateの Machine Learning Engineer (MLA-C01) が中心でした。かつては Machine Learning - Specialty (MLS-C01) という Specialty もありましたが、こちらは廃止済みです。AIP-C01は、これらに続く開発者向けの上位の資格です。</p>
<p>対象がはっきりしているのが特徴です。MLの研究者やデータサイエンティスト向けではなく、基盤モデル（FM）をアプリや業務ワークフローに組み込んで本番投入する開発者に振ってあります。モデルを一から訓練する話やデータエンジニアリングはスコープ外で、RAG、プロンプト管理、エージェント、コスト最適化、セキュリティ、評価といった、作って運用する側のテーマが並びます。FutureVulsのようなSaaSを作っている人間には、業務の延長にある内容でした。</p>
<p>試験概要は次のとおりです（2026年7月時点、公式ページ・試験ガイドより）。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>項目</th>
<th>内容</th>
</tr>
</thead>
<tbody><tr>
<td>試験時間</td>
<td>180分</td>
</tr>
<tr>
<td>設問数</td>
<td>75問（採点対象65問＋評価用の非採点10問）</td>
</tr>
<tr>
<td>出題形式</td>
<td>選択式（4択1正解）・複数選択式（複数正解）</td>
</tr>
<tr>
<td>受験料</td>
<td>300 USD</td>
</tr>
<tr>
<td>合格ライン</td>
<td>750 &#x2F; 1000（スコア範囲 100〜1000）</td>
</tr>
<tr>
<td>受験方法</td>
<td>テストセンター &#x2F; オンライン監督</td>
</tr>
<tr>
<td>推奨経験</td>
<td>本番グレードのアプリ構築2年＋生成AIソリューション実装1年 など</td>
</tr>
</tbody></table></div>
<p>コンテンツ分野と出題比率は以下です。分野1と分野2だけで合わせて57%を占めるので、ここを落とすと苦しくなります。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>コンテンツ分野</th>
<th>出題比率</th>
</tr>
</thead>
<tbody><tr>
<td>1. 基盤モデルの統合、データ管理、コンプライアンス</td>
<td>31%</td>
</tr>
<tr>
<td>2. 実装と統合</td>
<td>26%</td>
</tr>
<tr>
<td>3. AIの安全性、セキュリティ、ガバナンス</td>
<td>20%</td>
</tr>
<tr>
<td>4. GenAIアプリケーションの運用効率と最適化</td>
<td>12%</td>
</tr>
<tr>
<td>5. テスト、検証、トラブルシューティング</td>
<td>11%</td>
</tr>
</tbody></table></div>
<h2 id="学習方法">学習方法</h2><p>新しい試験で日本語の一次情報がまだ少なく、対策の順番から自分で決める必要がありました。効いたのは次の4つです。</p>
<h3 id="1-Perplexityで計画を立て、「モデル評議会」で弱点を特定する">1. Perplexityで計画を立て、「モデル評議会」で弱点を特定する</h3><p>まず Perplexity と壁打ちして学習計画を立てました。Perplexityにしたのは、新しい情報を踏まえて回答してほしいからです。AIP-C01は出たばかりで、学習ブログの蓄積に頼りきれません。試験ガイドや公式ドキュメントを裏取りしながら答えてくれる相手として、分からないところはすべてPerplexityに聞きました。</p>
<p>面白かったのが、Perplexity Maxプランのモデル評議会という機能です。同じ問いを複数のモデルに投げて、それぞれの見解を突き合わせられます。最初にSkill Builderの無料の20問セットを解いたところ、正答率は45%でした。この結果（分野別スコアと解答時間）をそのままモデル評議会にかけて、傾向を分析させました。返ってきた指摘がこれです。</p>
<blockquote>
<p>3モデルが揃って注目しているのが「不正解の方が平均解答時間が短い」点です。これは”迷って外した”というより、”知らないので即決で外した”傾向を示唆し、対策としては演習を闇雲に回すより、まず概念と選定基準（いつどれを選ぶか）をインプットしてから演習に入った方が伸びが速いパターンです。</p>
</blockquote>
<p>知らないから即答で外している、という見立ては、耳が痛いくらい当たっていました。実際、20問のドメイン別正答率は分野4と分野5がともに0%でした。ここでいきなり過去問を回しても意味がないと割り切り、まず概念と選定基準を頭に入れてから演習に入る、という順番に切り替えました。この切り替えで、演習の伸び方が変わりました。</p>
<h3 id="2-書籍でエージェント実装を押さえる">2. 書籍でエージェント実装を押さえる</h3><img src="/images/2026/20260721a/agentcore実践入門.jpg" alt="agentcore実践入門.jpg" width="251" height="320" loading="lazy">

<p>AIエージェント周りの概念のインプットに、書籍『Amazon Bedrock AgentCore実践入門 Strands Agentsで構築するAIエージェント』（AWS深掘りガイド）を読みました。AgentCore（エージェントの実行基盤）とStrands Agents（モデル駆動のエージェントSDK）は、まさに分野2（実装と統合）の中心です。</p>
<p>この領域は新しく、日本語でまとまった情報が少ないので、一冊で通して学べたのは効率がよかったです。ただし後述するとおり、配点最大の分野1（RAG・モデル選定・データ管理）や分野5（評価・トラブルシューティング）はこの本の守備範囲外なので、そこは別教材で補う前提で読むのがよさそうです。</p>
<h3 id="3-AWS-Skill-Builderで演習を回す">3. AWS Skill Builderで演習を回す</h3><img src="/images/2026/20260721a/skill_builder.png" alt="skill_builder.png" width="640" height="243" loading="lazy">

<p>演習は AWS Skill Builder の月額サブスクリプション（29 USD）を契約しました。やった順番はこうです。</p>
<ul>
<li>Official Practice Question Set（無料・20問）… 最初の腕試し</li>
<li>Domain 1〜5 Practice … 分野ごとの演習。弱かった分野4と分野5を優先的に</li>
<li>Official Pretest … 本番形式の公式模試で最終確認</li>
</ul>
<p>分野別に演習できるのが今回はありがたく、モデル評議会に指摘された弱点を狙い撃ちできました。正解を選べたかだけでなく、誤答の選択肢がなぜ誤りかまで説明できるかを毎回確認しました。この試験は選択肢がどれもそれっぽいので、消去法の根拠を言葉にできないと本番で崩れます。</p>
<h3 id="4-Udemyで本番の長文に慣れる">4. Udemyで本番の長文に慣れる</h3><img src="/images/2026/20260721a/udemy.png" alt="udemy.png" width="640" height="296" loading="lazy">

<p>仕上げに Udemyの対策講座 の問題を回しました。Udemyの演習には、過去2回の合格体験記（AWS Certified Security - Specialty・AWS Certified Advanced Networking - Specialty）でもお世話になっていて、今回も頼りにしました。</p>
<p>ひとつ補足すると、このAIP-C01の講座は執筆時点でサブスクリプションの対象外で、追加料金を払って個別に購入する必要がありました。追加の出費にはなりましたが、解説が丁寧で量も多く、日本語で学べるAIP-C01の対策教材がまだ限られるなかでは貴重でした。</p>
<p>Professionalの問題文は状況設定が長く、要件（レイテンシのSLA、予算、データの機密性など）を読み落とすと一発で外します。数をこなして、長文から何を最適化したい問題なのかを早く抜き出せるようにしました。</p>
<h2 id="試験勉強で得た学び">試験勉強で得た学び</h2><p>私はもともとAI領域の知識が足りませんでした。とはいえ体系立てて学び直したわけではなく、問題演習で知らない自然言語処理の用語に出くわすたびに、そこで立ち止まって、理解できるまでAIと壁打ちする、という進め方です。この試験は用語の暗記ではなく判断を問うので、特に効いた知識を、いつどれを選ぶかの選定基準として整理します。</p>
<h3 id="知識をどう入れるか：RAG・ファインチューニング・継続事前学習・プロンプト">知識をどう入れるか：RAG・ファインチューニング・継続事前学習・プロンプト</h3><p>分野1で最頻出、そして基本となるのがこの4つの使い分けです。社内ドキュメントの内容を答えさせたい、と言われて反射でファインチューニングと答えると、たいてい外れます。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>手法</th>
<th>変えられるもの</th>
<th>必要なデータ</th>
<th>使いどころ</th>
</tr>
</thead>
<tbody><tr>
<td>プロンプトエンジニアリング</td>
<td>指示の与え方</td>
<td>不要</td>
<td>まず最初に試す</td>
</tr>
<tr>
<td>RAG</td>
<td>参照する知識</td>
<td>外部ドキュメント</td>
<td>情報が更新される／出典を示したい</td>
</tr>
<tr>
<td>ファインチューニング</td>
<td>振る舞い（口調・出力形式・タスク精度）</td>
<td>ラベル付き（プロンプト-応答ペア）</td>
<td>出力のスタイルや形式を固定したい</td>
</tr>
<tr>
<td>継続事前学習</td>
<td>ドメイン知識そのもの</td>
<td>大量の非ラベルデータ</td>
<td>専門分野全体に適応させたい</td>
</tr>
</tbody></table></div>
<p>軸はこうです。知識の鮮度ならRAG、振る舞いならファインチューニング、ドメイン知識の底上げなら継続事前学習。特に、ラベル付きならファインチューニング、非ラベルの大量データなら継続事前学習、という判別は問題文の一語で正解が変わるので気をつけました。原則は、安いプロンプトやRAGで足りないかを先に確かめてからカスタマイズに進むこと。コスト意識が正解の根拠になる問題が多いです。</p>
<p>同じファインチューニングでも、かけるコストには幅があります。モデルの重みをすべて更新するフルファインチューニングは重い一方で、LoRA（Low-Rank Adaptation）のように、元のモデルは凍結したまま小さなアダプター（低ランク行列）だけを学習する手法もあります。パラメータ効率のよいファインチューニング（PEFT）と呼ばれる考え方で、全体を再学習せずに振る舞いを調整できるぶん、計算コストを大きく抑えられます。</p>
<h3 id="チャンキングと埋め込み、RAGの検索品質">チャンキングと埋め込み、RAGの検索品質</h3><p>RAGの精度は、検索の前工程でほとんど決まります。ドキュメントをどう分割（チャンキング）し、どう埋め込むかです。</p>
<pre class="mermaid" data-mermaid="7fc180626f23ea6570b89ab7b518d90cf386f3b45a00198d5f2cb44470eeef56">flowchart LR
    A[ドキュメント] --> B["チャンキング<br/>固定長 / 階層型 / セマンティック"]
    B --> C["埋め込みモデル<br/>Titan Text Embeddings 等"]
    C --> D[("ベクトルストア<br/>OpenSearch Serverless 等")]
    E[ユーザーの質問] --> F["ハイブリッド検索<br/>セマンティック + キーワード"]
    D --> F
    F --> G["リランカー<br/>上位の適合率を上げる"]
    G --> H[LLMで回答生成]</pre>

<p>Amazon Bedrock の Knowledge Bases では、チャンキングを固定長・階層型・セマンティック・分割なし・Lambdaによるカスタムから選べます。技術マニュアルや法務文書のように入れ子構造のものは、親チャンクで文脈を保ちつつ小さな子チャンクで検索する階層型が効きます。見出しのない長文の記事や調査レポートのように、構造は平坦でも話題が移っていくものは、意味のまとまりで区切るセマンティックが向きます。隣り合う文の埋め込みの類似度が下がったところを境界にするので、話題の途中でチャンクが切れにくくなります。細かすぎると文脈が切れ、粗すぎるとノイズが混ざるので、この加減を文書の性質で判断させるのが出題パターンでした。</p>
<p>地味に効いたのが、取り込み時とクエリ時の埋め込みモデルは同じでなければならない、という制約です。当たり前のようで、選択肢に紛れ込ませてくる引っかけがありました。</p>
<h3 id="ハイブリッド検索とリランカー：再現率と適合率">ハイブリッド検索とリランカー：再現率と適合率</h3><p>セマンティック検索は言い換えに強い一方で、型番や固有名詞、略語のように完全一致してほしい語に弱いです。脆弱性管理でいう <code>CVE-2026-XXXXX</code> のようなIDがまさにそれで、意味が近いだけでは拾えません。そこでキーワード検索を組み合わせるのがハイブリッド検索です。</p>
<p>ここで役割を混同しないことが大事でした。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>目的</th>
<th>手段</th>
<th>効く指標</th>
</tr>
</thead>
<tbody><tr>
<td>取りこぼしを減らす</td>
<td>ハイブリッド検索（セマンティック + キーワード）</td>
<td>再現率（Recall）を上げる</td>
</tr>
<tr>
<td>上位の精度を上げる</td>
<td>リランカー（検索後の再順位付け）</td>
<td>適合率（Precision）を上げる</td>
</tr>
</tbody></table></div>
<p>ハイブリッド化は漏れなく拾うための再現率対策、リランカーは上位を精度よく絞るための適合率対策で、別のレイヤーの話です。リランカーが再現率を上げると誤解していると、選択肢で足をすくわれます。ちなみにハイブリッド検索が使えるかどうかは、選ぶベクトルストアに左右されます。Bedrock Knowledge Basesでは当初OpenSearch Serverlessが中心でしたが、その後Aurora PostgreSQLなど対応先が広がりました。こうした実装の制約もセットで問われました。</p>
<h3 id="推論パラメータ：TemperatureとTop-Pはどちらか一方で調整する">推論パラメータ：TemperatureとTop-Pはどちらか一方で調整する</h3><p>出力を制御するパラメータも、名前を知っているだけでは足りず、効果と使いどころまで問われます。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>パラメータ</th>
<th>効果</th>
<th>使いどころ</th>
</tr>
</thead>
<tbody><tr>
<td>Temperature</td>
<td>出力のランダム性（低いほど決定的）</td>
<td>事実回答・抽出は低め、創作は高め</td>
</tr>
<tr>
<td>Top-P</td>
<td>累積確率がP（0〜1）に達するまでの上位語彙に限定</td>
<td>Temperatureとどちらか一方で調整</td>
</tr>
<tr>
<td>Top-K</td>
<td>上位K個の語彙に限定</td>
<td>モデル依存</td>
</tr>
<tr>
<td>停止シーケンス</td>
<td>指定文字列が出たら生成停止</td>
<td>出力を厳密に区切りたい</td>
</tr>
<tr>
<td>最大トークン長</td>
<td>出力の上限</td>
<td>コスト・レイテンシの制御</td>
</tr>
</tbody></table></div>
<p>引っかかったのは、TemperatureとTop-Pはどちらもランダム性を制御するので、両方を同時に動かさず、どちらか一方で調整する、という点です。多様性を出すために両方を上げる、という選択肢を正解に見せてくる問題がありました。長さペナルティやTop-Kのように、モデルによって使えたり使えなかったりするパラメータもあり、モデルごとに公開されているパラメータが違う前提で読む必要があります。</p>
<h3 id="Bedrock-Agents・AgentCore・Strands-Agents、そしてMCP">Bedrock Agents・AgentCore・Strands Agents、そしてMCP</h3><p>分野2の山場が、エージェントまわりの三者の区別です。ここは書籍が効きました。</p>
<pre class="mermaid" data-mermaid="0b0cc240c8fe2882c3fe7653b38e4998082cf05acdcff0206b9fe09d1c61a18e">flowchart TB
    S["Strands Agents<br/>モデル駆動のエージェントSDK（開発）"]
    subgraph AgentCore["Amazon Bedrock AgentCore（運用基盤）"]
        R["Runtime<br/>microVMで隔離実行"]
        M["Memory（短期/長期記憶）"]
        G["Gateway<br/>API/LambdaをMCPツール化"]
        I["Identity（Cognito/Auth0連携）"]
        O["Observability（トレース）"]
    end
    S -->|デプロイ| R
    S -->|ツール接続| G</pre>

<ul>
<li>Strands Agents … オープンソース（Apache-2.0）のエージェントSDK。LLM自身に推論・計画・ツール選択を任せるモデル駆動で、少ないコードでツールを使うエージェントを組めます。作る側の道具です。</li>
<li>Amazon Bedrock AgentCore … フレームワークに依存しない実行基盤。作ったエージェントを隔離実行（Runtime）し、記憶（Memory）、認証（Identity）、可観測性（Observability）、ツール接続（Gateway）を後から足せます。動かす側の道具です。</li>
<li>Bedrock Agents … Bedrock内で完結する、マネージドな簡易エージェント機能です。</li>
</ul>
<p>紛らわしいのは名前の近さですが、役割のレイヤーが違います。Strandsはエージェントを組み立てるSDK、AgentCoreはそれを本番で動かす実行基盤で、補完関係にあります。ただしAgentCoreはフレームワークに依存せず、Strands以外で作ったエージェントも動かせるので、両者は必ずセットというわけではありません。Bedrock Agentsは、これらを自分で組み合わせる代わりにBedrockにまかせるマネージドな選択肢です。この違いで見分けると、三者を混ぜてくる問題にも対応できます。特に注目したのが、AgentCoreのGatewayが既存のAPIやLambdaをMCP（Model Context Protocol）のツールとして公開できる点です。エージェントが外部の道具を使うための共通規格としてMCPが使われていて、この考え方が後半の話につながります。</p>
<h2 id="試験勉強を通しての所感">試験勉強を通しての所感</h2><h3 id="ユースケースを自分のサービスに引き寄せて考えられる">ユースケースを自分のサービスに引き寄せて考えられる</h3><p>対策のなかでは、さまざまなユースケースの説明が出てきます。それをひたすら追ううちに、自分が担当するサービスのどこに、どう展開できるかが具体的に見えてくるのが面白く、勉強しながらメモを取り続けました。</p>
<p>メモにはこんな走り書きが並びます。</p>
<ul>
<li>このユースケース、うちのあの機能にRAGでそのまま使えそう</li>
<li>呼び出すモデルは固定でなくてよく、軽い処理と重い処理で動的に切り替える（ルーティングする）制御もできる</li>
<li>モデルの評価には、LLM-as-a-judge に加えて、迷うエッジケースは人が判定し、両者を組み合わせるハイブリッドもある</li>
</ul>
<p>どれも、言われてみれば確かにそうだ、とうなずけるものばかりでした。生成AIの実装経験は浅くても、アプリ開発の勘所があれば、こうした学びは設計に生きます。</p>
<h3 id="PII対応で、法律と実装がつながった">PII対応で、法律と実装がつながった</h3><p>試験を通して、PII（個人を特定できる情報）の扱いが何度も出てきました。実は先日、個人情報保護士認定試験にも合格し、その体験記を書きました。そこで学んだ法律や制度を、いざサービスに実装する段になると、Amazon Bedrock GuardrailsのPIIフィルタ、テキストから個人情報を検出するAmazon Comprehend、S3上の機微データを見つけるAmazon Macieといったサービスが要ります。</p>
<p>制度として知っていたことと、それをどう実装するかが、一本の線でつながりました。コンプライアンスを要件から実装まで通して考えられるようになったのは、今回の思わぬ収穫です。</p>
<h2 id="試験結果の振り返り">試験結果の振り返り</h2><p>スコアは794点、合格ラインの750点を44点上回っての合格でした。</p>
<img src="/images/2026/20260721a/results.png" alt="results.png" width="640" height="227" loading="lazy">

<p>分野別の評価はこうです。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>コンテンツ分野</th>
<th>評価</th>
</tr>
</thead>
<tbody><tr>
<td>1. 基盤モデルの統合、データ管理、コンプライアンス</td>
<td>コンピテンシーを満たしている</td>
</tr>
<tr>
<td>2. 実装と統合</td>
<td>コンピテンシーを満たしている</td>
</tr>
<tr>
<td>3. AIの安全性、セキュリティ、ガバナンス</td>
<td>コンピテンシーを満たしている</td>
</tr>
<tr>
<td>4. GenAIアプリケーションの運用効率と最適化</td>
<td>コンピテンシーを満たしている</td>
</tr>
<tr>
<td>5. テスト、検証、トラブルシューティング</td>
<td>改善が必要</td>
</tr>
</tbody></table></div>
<p>正直に書くと、最後まで分野5（テスト、検証、トラブルシューティング）が埋まりきりませんでした。弱点だった分野4・5のうち、分野4は個別Practiceで持ち直しましたが、分野5は薄いまま本番に臨みました。モデル評価やLLM-as-a-judge、RAGの検索と生成を分けて診断する話は書籍でも手薄で、公式ドキュメントを直接あたる必要がありました。配点が11%と小さいことに救われた面はあります。</p>
<p>本番の進め方も少し書いておきます。試験時間の180分は、見直しまで含めて目一杯使いました。時間にゆとりは決してなく、最後まで押し気味でした。もう1つ、数問だけ日本語では文意を取りにくい設問があり、その場で英語に切り替えて読み直しました。技術的な内容は英語の原文のほうが素直に読めることもあるので、少しでも迷ったら切り替えるのは有効な手でした。</p>
<p>44点差での合格です。数字のうえでは少し上回っていますが、手応えとしてはぎりぎりでした。効いたのは、配点の大きい分野1と分野2を固めきれたことです。埋めきれなかった分野5は割り切り、重い分野から順に押さえる。この判断が、合否を分けたのだと思います。</p>
<h2 id="おわりに">おわりに</h2><p>生成AIの知識武装という当初の目的は、ひとまず果たせました。勘や雰囲気で動かしていたものを、内側で何が起きているかを踏まえて扱えるようになったのは、大きな収穫です。</p>
<p>学んでいて感じたのは、SaaSに求められるものが変わりつつあることです。先日、日経クロステックに「フリーは『AIが使いやすい』SaaSを目指す、CAIO直下に新組織」（2026年7月13日、有料会員限定）という記事が出ました。freee共同創業者でCAIOの横路隆氏の言葉として、こう紹介されています。</p>
<blockquote>
<p>SaaSのあり方も、これまでは人が使いやすいプロダクトを目指してきましたが、これからはAIエージェントが使いやすいものにする必要があります。</p>
</blockquote>
<p>SaaSを作る側にいる自分にとって、この指摘は他人事ではありません。プロダクトを使うのが人だけでなくAIエージェントにもなるなら、エージェントが叩ける口、つまりMCPサーバーを備えていることは、もう前提に近いはずです。画面を磨くのと同じ手間を、AIエージェント向けの入り口にもかける必要があります。</p>
<p>折しも、私のいるFutureVulsチームでは、7月17日に FutureVuls MCP Server をリリースしました。「いつものAIエージェントに、“脆弱性管理”を」というものです。試験勉強では、AgentCore GatewayがまさにMCPを軸にしているのを見ました。作る側に回るいま、その中身を理解したうえで判断できるのは大きいです。</p>
<p>今回の試験では、AWSのAIエコシステムの知識と、設計に落とし込める自然言語処理の知識が身につきました。これからは両方をフル活用して、サービス開発につなげていきます。</p>
<p>とはいえ、AWSのサービスは日々増えていきます。そのキャッチアップとして、ランチタイムのウェビナー「もぐもぐ AWS」に毎日参加しています。30分で最新のサービス動向を追えるのがちょうどよく、毎回いい刺激をもらっています。</p>
<p>次に何を受けるかは迷っていますが、AIエージェントの運用が本格化するほど、それを支えるインフラやセキュリティの知識がまた要るはずです。受かったら、また書きます。</p>
<h2 id="参考">参考</h2><ul>
<li>AWS Certified Generative AI Developer - Professional（公式ページ）</li>
<li>AIP-C01 試験ガイド</li>
</ul>
]]></content>
    <summary type="html">2026年7月14日に AWS Certified Generative AI Developer - Professional を受験し、794点/1000点（合格ライン750点）で一発合格しました。受けた動機はシンプルで、生成AIの知識武装です。</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="AWS" scheme="https://future-architect.github.io/tags/AWS/"/>
    <category term="合格記" scheme="https://future-architect.github.io/tags/%E5%90%88%E6%A0%BC%E8%A8%98/"/>
  </entry>
  <entry>
    <title>人工知能学会 (JSAI2026) 参加報告 </title>
    <link href="https://future-architect.github.io/articles/20260709a/"/>
    <id>https://future-architect.github.io/articles/20260709a/</id>
    <published>2026-07-08T15:00:00.000Z</published>
    <updated>2026-07-08T15:00:00.000Z</updated>
    <author><name>松岡祐司</name></author>
    <content type="html"><![CDATA[<h2 id="はじめに">はじめに</h2><p>AI戦略推進グループ（AIXG）の松岡です。</p>
<p>2026年6月8日（月）〜12日（金）、群馬県高崎市のGメッセ群馬にて人工知能学会全国大会（JSAI2026）が開催されました。フューチャーからもメンバが現地参加しましたので、その様子をレポートします。</p>
<p>一昨年のJSAI2024参加レポートに続き、今年もゴールドスポンサーとして現地参加してきました。</p>
<img fetchpriority="high" src="/images/2026/20260709a/Image_20260619_181038_085.jpeg" alt="Image_20260619_181038_085.jpeg" width="900" height="1200">

<h2 id="人工知能学会全国大会とは">人工知能学会全国大会とは</h2><p>人工知能学会全国大会（JSAI）は、日本最大規模のAI関連学会の1つで、研究者・技術者・ビジネスパーソンが一堂に会するイベントです。</p>
<p>今年のJSAI2026は、2026年6月8日（月）〜12日（金）の5日間、Gメッセ群馬（群馬県高崎市）にてハイブリッド形式（現地＋オンライン）で開催されました。学会設立40周年の大会となります。</p>
<p>参加者数は集計の結果<strong>5,278名</strong>（現地4,296名、遠隔982名）、発表件数は<strong>1,397件</strong>で、いずれも過去最多を記録しました。</p>
<p>プログラムは口頭発表・ポスター発表・企画セッション・チュートリアルなど多岐にわたり、40周年という節目にふさわしく、AI研究の歩みを振り返るとともに、社会実装・Physical AI・AI倫理など多様な領域へと広がる現在のAI研究の全体像を俯瞰できる大会でした。</p>
<h2 id="スポンサーブース">スポンサーブース</h2><p>フューチャーは今年もスポンサーブースへ出展しました。ブースではポスターを掲示し、AIXGが手がけるAIの社会実装案件を紹介しました。</p>
<p>研究の最先端を追うだけでなく、実ビジネスの現場にAIをどう組み込んでいくかというフューチャーならではの取り組みを来場者に伝えることができました。</p>
<img src="/images/2026/20260709a/Image_20260619_181033_722.jpeg" alt="Image_20260619_181033_722.jpeg" width="1200" height="900" loading="lazy">

<img src="/images/2026/20260709a/Image_20260619_181038_666.jpeg" alt="Image_20260619_181038_666.jpeg" width="1200" height="900" loading="lazy">

<p>グッズとしてペットボトルホルダーとトートバッグを配布しました。トートバッグは特にデザインのセンスが良いと好評で、多くの方に喜んでいただけました。</p>
<p>ブースには人工知能学会で初めてフューチャーを知った人たちから社名は聞いたことがある、社員に知り合いがいるといった人たち、インターンの選考を受けている学生に内定者と幅広くたくさんの方にお越しいただきました。</p>
<h2 id="セッション聴講">セッション聴講</h2><p>ここからは、特に印象に残ったセッション・発表について各メンバからご紹介します。</p>
<div class="note-container note-info"><span class="note-icon"></span><div>

<p>全論文のJ-Stageへの掲載は2026年7月17日に予定されています。それまでの間は参加登録者のみ閲覧が可能で、「ログイン」から、参加登録サイトに登録されたメールアドレスとパスワードで認証が必要です。</p>
</div></div>

<h3 id="4H1-OS-4a-04-ツンデレな心的状態理解を促すロボットの視線モデルの提案">[4H1-OS-4a-04]ツンデレな心的状態理解を促すロボットの視線モデルの提案</h3><p>日常空間で普及しつつある対話ロボットにおいて、視線の動きは相手の感情や意図を推測する非言語情報として、円滑なコミュニケーション領域で重要視されています。</p>
<p>円滑なサービス提供に向けて対話の流れや意図に合わせて視線制御をすることでスムーズに伝達できることが理想ですが、実際には顔追従や発話権に合わせた注視切替などに偏ってしまい、ロボット自身の「心境変化」といった内的状態を十分に表出するには至っていません。</p>
<p>本研究では、先行研究で提案されている相手の視線を入力としてエネルギーを逐次最小化する視線モデルに対して「ツンデレ（最初は照れ隠しで視線を回避するが、心を開くとアイコンタクトが増える状態遷移）」の概念を導入し、会話に応じて視線の動きを段階的に変化させる視線モデルを提案しました。</p>
<p>提案の視線モデルの有効性を検証するために、常時対話相手を注視する条件と先行研究の視線モデルに基づいて対話相手を注視する条件と比較した結果、提案モデルによって視線変化の理由理解と心境変化の知覚を有意に向上させることが明らかになりました。</p>
<p>対話ロボットが普及する中で、「ツンデレ」というサブカルチャーの概念を状態遷移モデルとして真面目に実装し、視線1つでロボットの「心」を表現するに至った点が面白くこちらの発表を取り上げました。(加藤)</p>
<h3 id="2E5-GS-10o-02-時系列データ解釈のためのマルチモーダルLLM設計と自動車の運転挙動説明への応用">[2E5-GS-10o-02] 時系列データ解釈のためのマルチモーダルLLM設計と自動車の運転挙動説明への応用</h3><p>トヨタ自動車とNABLASによる発表をご紹介します。</p>
<p>車速・加速度・操舵角といった車載の時系列データは、可視化やタスクごとの個別モデル構築に人手を要し、解釈にも専門知識が必要でした。本研究はこの課題に対し、時系列エンコーダと射影（プロジェクション）層を組み合わせ、抽出した時系列特徴を直接LLMへ入力する新アーキテクチャ <strong>Time-Series Language Model（TSLM）</strong> を提案しています。</p>
<p>構成は画像分野のVLM（LLaVA）に着想を得ており、時系列基盤モデル <strong>MOMENT</strong> で走行データから特徴量を抽出し、<strong>2層のMLP（射影層）</strong> でLLMの埋め込み空間へ写像、LLM（<strong>Qwen3-4B-Instruct-2507</strong>）へテキスト指示とともに入力して運転挙動の説明文を生成します。特に、<strong>エンコーダとLLMの重みは凍結し、学習するのは射影層のMLPのみ</strong> という点が特徴で、少ない計算資源で学習でき、モデルの置き換えも容易という利点があります。</p>
<p>データセットは実車走行データ（カムリ・クラウンで一般道・高速道路を走行）から構築し、8系列を0.1秒周期で記録して10秒ごとに区切っています。教師となる説明文はグラフ画像をVLMに読ませて生成させ、約2万件の時系列⇔テキストのペアを自動的に用意したとのことです。</p>
<p>評価では、時系列を折れ線グラフの画像に変換してVLMで処理するベースラインと比較し、LLM as a Judge（1〜10点）で説明文の質を測定。提案手法TSLMは平均 <strong>6.82点</strong> とベースラインの <strong>4.86点</strong> を上回り、時系列を画像化せず直接LLMへ取り込むアプローチの有効性が示されました。</p>
<p>時系列を「画像化してから読ませる」のではなく専用エンコーダで特徴量化して直接渡す発想が新鮮で、学習対象を射影層だけに絞った軽量・転用性の高い設計も実務的でした。センサーやログなど時系列を扱う社会実装案件への応用可能性を感じる発表でした。(岩城)</p>
<h3 id="4G1-OS-23-04-ReMIND：大規模言語モデルのモジュラー統合によるセレンディピティ創発">[4G1-OS-23-04] ReMIND：大規模言語モデルのモジュラー統合によるセレンディピティ創発</h3><p>新しいアイデア創発にLLMを利用することは昨今珍しい話ではありませんが、新規性と、アイデアの論理的整合性を両立させることは簡単ではありません。</p>
<p>本研究ではリアルの人間がレム睡眠の際にアイデアを創発することに着想を得たLLMフレームワーク<strong>ReMIND</strong>の提案をしています。</p>
<p>人間はレム睡眠の間に、記憶や知識をランダムに組み合わせて「ひらめき」を生み出し、起きている間にそれを「整合性のあるアイデア」へと収束させています。</p>
<p>本フレームワークはこの仕組みを着想源としており、wake、dream、judge、re-wake の4ステップで構成されています。</p>
<ul>
<li>wake（覚醒状態）：Temperature を低く設定し、ベースラインとなる堅実で安定した応答を生成します。</li>
<li>dream（睡眠状態）：Temperature を高く設定し、普段は結びつかない概念同士を掛け合わせた、自由で意外性のある応答を生成します。</li>
<li>judge（評価）：生成されたアイデアに対して粗く評価し、有望な候補を抽出します。</li>
<li>re-wake（再覚醒・収束）：抽出した候補を再度 wake（低Temperature）に入力し、最終的なアイデアとして綺麗に再構成した上で出力します。</li>
</ul>
<p>複数のプロンプト条件、モデル、およびパラメータを対象に、LLM as a judgeにより評価しました。その結果、新規性のあるアイデアの出現自体は確率的なものにとどまる側面はあるものの、本フレームワークのように「構造化された探索」と「選択的な統合」を組み合わせることで、限られた試行回数の中でもその出現確率を向上させられることが示されました。</p>
<p>深層学習という手法に起因する、現在のAIにおける『純粋な創造性』の構造的ジレンマに対抗するアプローチとして非常に面白い研究でした。</p>
<p>また、本研究を発表された佐藤純先生は、神経科学をはじめとする生物科学をご専門とされており、その知見を彷彿とさせるフレームワークの着想は、大変興味深いものでした。</p>
<h3 id="3N1-GS-8a-03-実会話の雰囲気を伝えるロボット行動生成">[3N1-GS-8a-03]実会話の雰囲気を伝えるロボット行動生成</h3><p>人間の会話にある「言葉には表れない全体の雰囲気」を、2台のコミュニケーションロボットで再現しようと試みた非常に興味深い発表でした。</p>
<p>本セッションでは、会話の雰囲気は「発話内容」「音声韻律」「ジェスチャ」の統合的な制御によって作られるという仮説に基づいて研究が進められています。</p>
<p>最新のLLMに漫才の会話データを読み込ませて発話の役割ごとの声の制御や、絶妙な「発話間の間」の取り方を推定させているそうです。</p>
<p>さらに、テキストの指示からロボットの関節の動きまで生成して連動させています。一見無機質に思われがちなロボットとのやりとりですが、提案された生成システムを用いて人間の漫才を再現したところ、間の取り方や身振りが統合され、人間同士のやり取りにかなり近い雰囲気が醸し出されていました。</p>
<p>この研究が進めば、将来的にロボットとのやり取りが人間にとってごく自然なものになるのではないかと、大きな期待が膨らむセッションでした。(松岡)</p>
<h2 id="さいごに">さいごに</h2><p>基盤モデル・生成AI研究の盛況は今年も続いていましたが、様々な業界におけるRAGやAIエージェントの活用など「実務への適用」を重視した発表が増え、研究コミュニティ全体が社会実装フェーズへ移行しつつある印象でした。</p>
<p>マルチモーダルAIの広がりや、発表・企業ブースでのロボットに関する出展の増加からはPhysical AIへの関心の高まりも感じられ、AIが現実世界に根ざした技術として進化していることを改めて実感しました。</p>
<p>AIXGではAIの社会実装に一緒に取り組む仲間を募集しています。新卒・キャリアともに採用中ですので、ご興味のある方はぜひご覧ください。</p>
<ul>
<li>新卒採用</li>
<li>キャリア採用</li>
</ul>
]]></content>
    <summary type="html">026年6月8日（月）〜12日（金）、群馬県高崎市のGメッセ群馬にて人工知能学会全国大会（JSAI2026）が開催されました。フューチャーからもメンバが現地参加しましたので、その様子をレポートします。</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="JSAI" scheme="https://future-architect.github.io/tags/JSAI/"/>
    <category term="参加レポート" scheme="https://future-architect.github.io/tags/%E5%8F%82%E5%8A%A0%E3%83%AC%E3%83%9D%E3%83%BC%E3%83%88/"/>
    <category term="学会" scheme="https://future-architect.github.io/tags/%E5%AD%A6%E4%BC%9A/"/>
    <category term="機械学習" scheme="https://future-architect.github.io/tags/%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92/"/>
  </entry>
  <entry>
    <title>主要AIモデルのデータ保持期間とZDRを、一次情報で確認する</title>
    <link href="https://future-architect.github.io/articles/20260703a/"/>
    <id>https://future-architect.github.io/articles/20260703a/</id>
    <published>2026-07-02T15:00:00.000Z</published>
    <updated>2026-07-02T15:00:00.000Z</updated>
    <author><name>棚井龍之介</name></author>
    <content type="html"><![CDATA[<img fetchpriority="high" src="/images/2026/20260703a/Gemini_Generated_Image_k0m0q5k0m0q5k0m0.png" alt="Gemini_Generated_Image_k0m0q5k0m0q5k0m0.png" width="1200" height="670">

<div class="note-container note-warn"><span class="note-icon"></span><div>

<p>本記事は2026年7月2日時点の情報に基づく内容です。一次情報（主に英語）の読み取りやリサーチの過程で、事実誤認や誤りが含まれている可能性があります。数値・仕様・各社ポリシーは、実務判断の前に必ず最新の一次情報でご確認ください。あわせて、業務でAIを利用する際は、必ず自社の社内ポリシーも確認してください。</p>
</div></div>

<p>データエンジニアリング連載 の3本目です。今回の担当は棚井です。</p>
<h2 id="はじめに-Fableが帰ってきた">はじめに: Fableが帰ってきた</h2><p>ついに、Claude Fable 5の利用が再開されました。6月に発表されたばかりのモデルだったのが、6月12日に米国政府の輸出規制がかかって全ユーザー向けにアクセスが止まっていたところからの復帰です（Anthropic: Redeploying Claude Fable 5）。6月30日に規制が解除され、7月2日から再開されたという経緯です。使えなくなっていたモデルが戻ってきて、正直やったぜと思いました。</p>
<p>ただし、トークン消費量の多さとは別に、押さえておきたい注意点があります。Fable 5は、ZDRではなく30日のデータ保持が必須という仕様です。同じClaudeでも、他の多くのモデルはZDR下で会話内容を残さないサービス仕様ですが、Fable 5はこの点が異なります。同じサービス・同じAPIキーでも、どのモデルを呼ぶかでデータ保持のルールが変わることがありますので、それならば主要モデルのデータ保持の扱いを一度横断で整理しておこう、と思ったのが今回のきっかけです。</p>
<p>テーマは、生成AIをデータ基盤やアプリに組み込むときに毎回引っかかる「入力したデータがプロバイダ側にどれだけ残るのか」です。いわゆるデータ保持期間（Data Retention）と、ZDR（Zero Data Retention、ゼロデータ保持）です。2026年7月2日時点の各社公式ドキュメント・利用規約を一次情報として整理しました。</p>
<p>また最近、セキュリティチェック項目に「AIの利用可否」と「データ保持の有無」について問われる機会が増えてきました。ここでつまずきやすいのが「学習に使われない」と「サーバに残らない」を同じものと扱ってしまう点です。この2つを分けずに「APIなら安全」と判断すると、監査で足をすくわれます。</p>
<p>先に、5サービスの要点を表でまとめます。今回は「API&#x2F;エンタープライズ利用」を前提に取り上げます（個人向けアプリは別ポリシーなので、必要な範囲でのみ触れます）。細かい根拠は各節で扱うので、ここでは全体像だけ押さえてください。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>サービス</th>
<th>ZDR・データ保持の特徴</th>
<th>例外・注意点</th>
</tr>
</thead>
<tbody><tr>
<td><strong>OpenAI</strong>（GPT &#x2F; Codex &#x2F; API）</td>
<td>エンドポイント単位で保持挙動が最も細かく公開されている</td>
<td>画像モデルによってZDRの可否が分かれる</td>
</tr>
<tr>
<td><strong>Anthropic</strong>（Claude &#x2F; Claude Code）</td>
<td>通常モデルはZDR下で非保持</td>
<td>Fable 5 &#x2F; Mythos 5は30日保持必須（ZDR不可）</td>
</tr>
<tr>
<td><strong>Google</strong>（Gemini API）</td>
<td>モデルによる仕様差はなし</td>
<td>Grounding（検索拡張）など機能側に例外あり</td>
</tr>
<tr>
<td><strong>Preferred Networks</strong>（PLaMo API）</td>
<td>国内勢で最も明確にZDRを打ち出している</td>
<td>モデルの差ではなく、契約プランによって決まる</td>
</tr>
<tr>
<td><strong>Sakana AI</strong>（Fugu）</td>
<td>外部モデルにルーティングするオーケストレーション型</td>
<td>現時点ではZDRを掲げているサービスではない</td>
</tr>
</tbody></table></div>
<h2 id="便宜的に3つのレイヤに分けて考える">便宜的に3つのレイヤに分けて考える</h2><p>実際のデータ保持のメカニズムは、サービスごとに細かい差分があります。その差分を一度に並べると読みづらいので、ここでは説明のための便宜的なグルーピングとして、次の3つの軸を使います。公式な規格や定義ではなく、あくまでこの記事での整理軸です。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>レイヤ</th>
<th>何を指すか</th>
<th>よくある勘違い</th>
</tr>
</thead>
<tbody><tr>
<td>① 学習利用（Training）</td>
<td>入力・出力を将来のモデルの重み更新（学習・ファインチューニング）に使うか</td>
<td>「学習に使わない」＝「保存もされない」と思い込む</td>
</tr>
<tr>
<td>② ログ保持（Retention &#x2F; Abuse Monitoring）</td>
<td>不正利用監視・デバッグ・法令対応のため、入出力を一定期間サーバに保存するか</td>
<td>学習に使わなくても保存はされていることを見落とす</td>
</tr>
<tr>
<td>③ ゼロデータ保持（ZDR）</td>
<td>そもそも②の保存自体を行わず、処理直後に破棄するか</td>
<td>ZDRにすれば全機能で何も残らないと思い込む</td>
</tr>
</tbody></table></div>
<p>同じ②の中でも、サービスによっては「不正利用監視用の保持」と「デバッグ&#x2F;運用ログ」で期間が違ったり、ZDRを有効にしても特定の機能だけ②が残ったりします。その細かい差分は各節で拾います。まずはこの3つを分けて見る、というところを押さえておいてください。</p>
<p>エンタープライズ向けの主要API（OpenAI &#x2F; Anthropic &#x2F; Google Gemini API）は、①の学習利用がデフォルトでオフです。各社が規約で明記しています（Homula: エンタープライズLLMのデータ主権）。</p>
<p>問題は②です。学習には使わないが、Abuse Monitoring（不正利用監視）のために入出力を最大30日ほど保存する、というのが多くのサービスのデフォルトになっています。「入れたデータが一切残らない環境」ではない、という認識のズレはここから来ます。</p>
<p>③のZDRは、その②の保存をやめる仕組みです。ただし後述のとおり、ZDRを有効にしても保存が残る例外が各社にあります。「魔法の全消し設定」だと思っていると危ないです。</p>
<p>ZDRの定義としては、XIMIX（NTTインテグレーション）の説明が端的でした。ZDRとは「ユーザーが入力したプロンプトやAIが生成した回答データを、サービス提供者側のサーバに一切保存せず、処理直後に破棄すること」であり、「学習に利用しない」より厳格なアプローチだとしています（XIMIX: 生成AI時代のゼロデータリテンション）。ただし、ZDRの具体的な定義はサービスごとに異なります。各サービスの定義は、それぞれが公開している情報で確認してください。</p>
<h2 id="OpenAI（GPT-Codex-API）">OpenAI（GPT &#x2F; Codex &#x2F; API）</h2><img src="/images/2026/20260703a/logo-openai.png" alt="logo-openai.png" width="845" height="320" loading="lazy">

<p>OpenAIはエンドポイント単位の保持挙動を表で公開していて、ここが一番細かく追えます（OpenAI: Data controls in the OpenAI platform）。</p>
<p>API経由のデータは、2023年3月以降、明示的にopt-inしない限りモデル学習に使われません。Abuse Monitoring目的のログは全APIで生成され、最大30日保持されます（法令上より長期の保持を求められる場合を除く）。このログにはprompts &#x2F; responsesや分類器の出力などのメタデータが含まれえます。</p>
<p>ZDRやMAM（Modified Abuse Monitoring）は、Eligible customers（適格な顧客）が事前承認と追加要件への同意を経て使えます。組織またはプロジェクト単位です。ZDR有効時、<code>/v1/responses</code> と <code>/v1/chat/completions</code> の <code>store</code> パラメータは、リクエストで <code>true</code> を指定してもfalse扱いに固定されます。</p>
<h3 id="モデル単位で挙動が変わるところ">モデル単位で挙動が変わるところ</h3><p>テキストモデルは、同じエンドポイントを使う限り保持挙動も同じです。テキスト側に「モデルを変えたらZDR可否が変わる」という差は見当たりません。公式のData controlsページで明示されているモデル単位の差は、画像生成モデルの間にあります。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>モデル</th>
<th>種別</th>
<th>ZDR対象</th>
</tr>
</thead>
<tbody><tr>
<td>gpt-image-1 &#x2F; gpt-image-1.5 &#x2F; gpt-image-1-mini</td>
<td>画像生成</td>
<td>可</td>
</tr>
<tr>
<td>dall-e-3 &#x2F; dall-e-2</td>
<td>画像生成</td>
<td><strong>不可</strong></td>
</tr>
</tbody></table></div>
<p>画像生成でdall-e系を選ぶとZDRから外れます。同じ「OpenAIで画像を作る」でも、gpt-image系に寄せるかどうかで結論が反転します（OpenAI: Data controls in the OpenAI platform）。</p>
<h3 id="エンドポイント単位のZDR対象可否">エンドポイント単位のZDR対象可否</h3><p>モデル以上に効いてくるのがエンドポイントの違いです。主要なものを抜粋します。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>エンドポイント</th>
<th>学習利用</th>
<th>Abuse監視保持</th>
<th>ZDR対象</th>
</tr>
</thead>
<tbody><tr>
<td><code>/v1/chat/completions</code></td>
<td>No</td>
<td>30日</td>
<td>可（制限あり）</td>
</tr>
<tr>
<td><code>/v1/responses</code></td>
<td>No</td>
<td>30日（<code>store=true</code>時）</td>
<td>可（制限あり）</td>
</tr>
<tr>
<td><code>/v1/embeddings</code></td>
<td>No</td>
<td>30日</td>
<td>可</td>
</tr>
<tr>
<td><code>/v1/moderations</code></td>
<td>No</td>
<td>なし</td>
<td>可</td>
</tr>
<tr>
<td><code>/v1/conversations</code></td>
<td>No</td>
<td>削除まで</td>
<td><strong>不可</strong></td>
</tr>
<tr>
<td><code>/v1/assistants</code>, <code>/v1/threads</code>系, <code>/v1/vector_stores</code></td>
<td>No</td>
<td>30日</td>
<td><strong>不可</strong></td>
</tr>
<tr>
<td><code>/v1/files</code>, <code>/v1/batches</code>, <code>/v1/fine_tuning/jobs</code></td>
<td>No</td>
<td>30日</td>
<td><strong>不可</strong></td>
</tr>
<tr>
<td><code>/v1/videos</code></td>
<td>No</td>
<td>30日</td>
<td><strong>不可</strong></td>
</tr>
</tbody></table></div>
<p>出典はOpenAI公式のData controlsページです。</p>
<p>OpenAIのZDRがしっかり効くのは、chat&#x2F;completionsやresponsesで、余計な機能を付けずに推論だけをシンプルに実行する場合です。拡張キャッシュのような便利機能を足すほど、その分ZDRの対象から外れる部分が出てきます。Codexも同様で、内部でどのエンドポイント・機能を叩くかで保持挙動が変わるので、「Codexだから安全」ではなく利用エンドポイント単位で判断してください。</p>
<p>データレジデンシー（保存先リージョン）については、対象エンドポイントで欧州&#x2F;米国を明示選択できるオプションがあります（OpenAI: ビジネスデータのプライバシー）。</p>
<h2 id="Anthropic（Claude-Claude-Code）">Anthropic（Claude &#x2F; Claude Code）</h2><img src="/images/2026/20260703a/logo-claude.png" alt="logo-claude.png" width="1051" height="320" loading="lazy">

<p>Anthropicは個人向けと法人向けでポリシーページが分かれています。そしてここが今回の主題そのもので、同じClaudeでもモデルによってZDR可否が違います。</p>
<h3 id="再開したFable-5とMythos-5の保持要件">再開したFable 5とMythos 5の保持要件</h3><p>Claude Fable 5とClaude Mythos 5は「Covered Models」に指定されていて、30日のデータ保持が必須です。ZDRは選べません（Anthropic: API and data retention）。Claude APIでは、この30日保持を満たさないZDR組織からのリクエストは <code>400 invalid_request_error</code> を返します。この30日要件はどのプラットフォームでも同じで、Bedrock、Google Cloud、Microsoft Foundry経由でも保持データは各クラウドプロバイダの環境内に残ります。<br>冒頭で触れたとおり、Fable 5は再開直後です。戻ってきたばかりのタイミングだからこそ、ここで30日保持の要件を改めて確認しておきましょう。それ以外のClaudeモデルは、ZDR下で会話内容をデフォルト保持しません。同じアカウント・同じAPIキーでも、Fable 5 &#x2F; Mythos 5を呼ぶかどうかでデータ保持のルールが変わってきます。この点を運用ルールに落とし込んでください。</p>
<h3 id="個人向けプラン">個人向けプラン</h3><p>個人向け（Claude Free &#x2F; Pro &#x2F; Max、およびそのアカウントで使うClaude Code）の保持は次のとおりです。会話削除時、履歴からは即時、バックエンドからは30日以内に削除されます。モデル改善を許可した場合、de-identified形式で最長5年、学習パイプラインに保持されえます（設定を有効にした後の新規・再開チャットに適用）。Usage Policy違反時は入出力を最長2年、trust &amp; safetyの分類スコアを最長7年保持します。Incognito chatsはモデル改善に使われません（Anthropic: How long do you store my data?）。</p>
<p>特に注意したいのが、モデル改善を許可した状態の保持期間です。プライバシー設定はいつでも変更できますが、デフォルトの学習利用可否は利用時点の設定を自分で確認してください。業務データを個人向けプランに入れる行為は、会社の管理下にないAI利用、いわゆる「シャドーAI」にあたります。個人向けプランは学習利用や保持期間のデフォルトが法人向けと異なるため、業務データは法人向けプランで扱い、個人向けプランには入れないよう徹底してください。</p>
<h3 id="法人向けプランとZDR契約">法人向けプランとZDR契約</h3><p>法人向け（Anthropic API、Claude Team &#x2F; Enterprise）は学習利用がデフォルトでオフです。ここで注目したいのがClaude Codeで、同じClaude Codeでも、どの経路で動かすかでログの保持が変わります。</p>
<p>APIキー（Anthropic API）で動かすClaude Codeは、APIの保持ルールに従います。会話コンテンツ（プロンプトとClaudeの出力）はデフォルトで保持されず、バックエンドに残る場合も受領・生成から30日以内に自動削除されます（Files APIなどユーザー管理下の長期保持、ZDR等の別途合意、Usage Policy執行、法令対応は例外）（Anthropic: API and data retention、Anthropic: How long do you store my organization’s data?）。</p>
<p>一方、Team &#x2F; Enterpriseで使う場合は、その組織のデータポリシーに従います。会話やプロジェクトを保存して継続できる製品では、保存したデータが製品内に残ります。Enterpriseプランではカスタムデータ保持期間を設定でき、最小は30日です。設定しなければ無期限保持になります。削除は指定日のUTC 0時に実行され、監査ログに記録されます（Anthropic: Configure custom data retention for Enterprise plans）。</p>
<p>ZDR契約の対象は、Messages APIなどの適格なAnthropic API、法人向けの組織APIキーで使う製品（APIキー経由のClaude Codeを含む）、そしてEnterpriseプランのClaude Codeです。Teamプランや個人向けのClaude Codeは対象外になります。ZDR時、Anthropicは法令遵守や不正・危害対策に必要な場合を除き、入出力を保存しません。ただし、入出力そのものではなく、コンテンツが利用規約に反していないかを判定する安全性チェック（User Safety分類器）の結果だけは、規約違反への対応のために残ります。承認制で組織単位、申請はSales Team経由です。HIPAA対応サービス／BAA（Business Associate Agreement）には構成上の制約があり、たとえばWeb検索機能にはBAAが適用されません（Anthropic: ZDR agreement — supported products）。</p>
<h2 id="Google（Gemini-API）">Google（Gemini API）</h2><img src="/images/2026/20260703a/logo-gemini.png" alt="logo-gemini.png" width="1006" height="320" loading="lazy">

<p>GoogleはGemini Developer APIでZDRドキュメントを公開しています。ドキュメントはモデル別のZDR可否を列挙しておらず、保持の可否はモデルではなく使う機能側で差が出る構造です。</p>
<p>有料サービスでは、プロンプト（システム指示・キャッシュ・画像&#x2F;動画&#x2F;ドキュメント等のファイルを含む）や回答は製品改善に使われません。Abuse Monitoring目的では、Prohibited Use Policy違反検出に限りプロンプト・回答を一定期間ログ記録します。ZDR承認が下りると、ログ記録前にユーザーコンテンツと識別可能メタデータ（IPアドレス、GoogleアカウントID等）がクリアされ、サニタイズ済みレコードとしてマークされます。</p>
<p>ZDRを有効にしても残る、または無効化できない機能があります。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>機能</th>
<th>挙動</th>
<th>ZDR達成のための対応</th>
<th>保持期間</th>
</tr>
</thead>
<tbody><tr>
<td>Grounding with Google Search</td>
<td>プロンプト・文脈・出力を保存</td>
<td><strong>無効化不可</strong></td>
<td>30日</td>
</tr>
<tr>
<td>Grounding with Google Maps</td>
<td>プロンプト・文脈・出力を保存</td>
<td><strong>無効化不可</strong></td>
<td>30日</td>
</tr>
<tr>
<td>Interactions API</td>
<td>デフォルトで状態保存</td>
<td><code>store=false</code> を明示指定</td>
<td>デフォルト状態保存</td>
</tr>
<tr>
<td>Live API</td>
<td>状態保存で再接続可能</td>
<td><code>SessionResumptionConfig</code> を構成しない</td>
<td>セッションハンドル生成時24時間</td>
</tr>
<tr>
<td>File API</td>
<td>ファイルをat-rest保存</td>
<td>手動削除が必要</td>
<td>削除／期限まで</td>
</tr>
<tr>
<td>明示的コンテキストキャッシュ</td>
<td><code>cached_content</code>で保存</td>
<td>当機能を使わない</td>
<td>ユーザー定義TTL</td>
</tr>
<tr>
<td>暗黙的インメモリキャッシュ</td>
<td>RAM上のみ</td>
<td>ZDR違反にはならない</td>
<td>24時間TTL</td>
</tr>
</tbody></table></div>
<p>出典はGoogle AI for Developers: Zero data retention in the Gemini Developer APIです。</p>
<p>実務で一番のハマりどころはGroundingです。Google検索・Maps連携を使うと、ZDR契約下でもプロンプト・文脈・出力が30日保存され、これはオプトアウトできません。「精度を上げたいからGrounding ON、でもZDRだから安心」という構成は成立しません。外部知識を足す機能とZDRが両立しないのは、OpenAIのCode Interpreterやキャッシュと同じ構造です。片方が立てば片方が崩れると覚えておくと応用が効きます。</p>
<h2 id="Preferred-Networks（PLaMo-API）">Preferred Networks（PLaMo API）</h2><img src="/images/2026/20260703a/logo-plamo.png" alt="logo-plamo.png" width="1200" height="314" loading="lazy">

<p>国内のAPI勢のなかで、ZDRを正面から掲げているのがPLaMoです。現行モデルはplamo-3.0-prime（262kコンテキストのフラッグシップ）、plamo-3.0-prime-beta（2026年7月31日で提供終了）、plamo-2.2-prime（2026年9月30日で提供終了）です（PLaMo API ドキュメント）。</p>
<p>保持と学習の扱いは、どのプランを選ぶかで変わります。プラン比較表ではStandardプランの「ZDR（入力データの非保持）」欄に「入力データを学習に利用しない」と記載され、Freeプランは同欄が「―」で対象外です。Standardプランの特徴欄には「入力したデータを保存せず、モデル学習にも使わない」とも明記されています（PLaMo API プラン）。利用規約側では、有償サービスのコンテンツを「本サービス、新サービス又はAIモデルの開発若しくは改善の目的で、閲覧又は利用することはありません」と定める一方、Freeプラン及び無償サービスのコンテンツは同目的で「閲覧又は利用する場合があります」としています。あわせて「当社は利用者に対して本コンテンツを保存する義務を負いません」とも定めています（PLaMo API 利用規約）。規約は個人情報保護法（APPI）の遵守を明記し、無償サービスでの個人データ入力を禁止するなど、国内のコンプラ要件を意識して作られているのが分かります。</p>
<h2 id="Sakana-AI（Fugu）">Sakana AI（Fugu）</h2><img src="/images/2026/20260703a/logo-sakana.png" alt="logo-sakana.png" width="1200" height="248" loading="lazy">

<p>SakanaのFuguは、受け取ったリクエストを内部でいくつかの小さな作業に分け、それぞれを外部のフロンティアモデル（OpenAI &#x2F; Anthropic &#x2F; Google等）に振り分けて処理させるサービスです。たとえば、難しい推論が必要な部分と単純な整形で済む部分を、それぞれ得意なモデルへ自動で割り振ります。こうして複数のモデルを束ねて使い分ける仕組みを、オーケストレーション型と呼びます（Sakana Fugu Terms of Service）。入力は外部LLMへ転送され、各プロバイダのポリシーが適用されます。ここが保持を考えるうえで効いてきます。</p>
<p>学習利用については、ContentをTraining Use（再学習・ファインチューニング含む）に利用しうるとしています。コンソールでopt-out可能ですが遡及しません。保持については、入力・出力の保存義務を負わないと定めています。加えて、Contentを基に学習したモデルの重み・外部ベンダーの一時キャッシュ・監査ログについても、削除義務を負わないと明記しています。品質・安全性向上のため人間レビュアーがContentを注釈・処理する場合があり、フィルタで個人・機密情報のレビューを完全には制限できないとも書いています。金融個人データについては別途「金融個人データ保護指針」（2025年6月施行）で安全管理措置を定めますが、保持期間・学習利用・ZDRの具体的記載はありません。</p>
<p>現時点のFuguはZDRを掲げるサービスではありません。オーケストレーション型なので、データ保持は「Sakana自身」と「転送先の外部LLM」の二重で評価する必要があります。機密データを入れる用途では、この二重評価をやりきれるかがそのまま採否の判断になります。</p>
<h2 id="横断比較表（2026年7月時点）">横断比較表（2026年7月時点）</h2><p>「API&#x2F;エンタープライズ利用」を前提とした比較です（個人向けアプリは別ポリシー）。モデル固有の差がある行は「主なモデル差」に書きました。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>サービス</th>
<th>学習利用（デフォルト）</th>
<th>標準保持</th>
<th>ZDR&#x2F;非保持</th>
<th>主なモデル差</th>
<th>主な例外・注意</th>
</tr>
</thead>
<tbody><tr>
<td><strong>OpenAI API</strong></td>
<td>なし</td>
<td>Abuse監視30日</td>
<td>可（承認制、組織&#x2F;プロジェクト単位）</td>
<td>dall-e系は<strong>ZDR不可</strong>、gpt-image系は可</td>
<td>conversations&#x2F;assistants&#x2F;files等は対象外。拡張キャッシュ・Code Interpreter・Backgroundは非対応。CSAM検出は保持</td>
</tr>
<tr>
<td><strong>Anthropic API &#x2F; Enterprise</strong></td>
<td>なし</td>
<td>API（Messages API等）は<strong>非保持がデフォルト</strong>（残っても30日以内に自動削除）。会話保存型のTeam&#x2F;Enterpriseは<strong>無期限</strong>（Enterpriseはカスタム設定可・最小30日）</td>
<td>可（承認制・組織単位、Sales経由）</td>
<td><strong>Fable 5 &#x2F; Mythos 5は30日保持必須・ZDR不可</strong>。他モデルはZDR下で非保持</td>
<td>ZDRはMessages API・API経由&#x2F;EnterpriseのClaude Codeが対象（Team・個人向けは対象外）。User Safety分類は保持。違反時入出力2年&#x2F;スコア7年</td>
</tr>
<tr>
<td><strong>Google Gemini API</strong></td>
<td>なし</td>
<td>Abuse監視ログ（ZDR承認でサニタイズ）</td>
<td>可（プロジェクト単位、承認制）</td>
<td>モデル別のZDR可否はドキュメント上未列挙（機能側で差）</td>
<td><strong>Grounding(Search&#x2F;Maps)は30日保持でオプトアウト不可</strong>。Live API 24h、暗黙キャッシュ24h(RAM)</td>
</tr>
<tr>
<td><strong>PFN PLaMo API</strong></td>
<td>Standard（有償）は<strong>なし</strong>、Free（無償）は<strong>あり</strong></td>
<td>Standardは<strong>非保持</strong></td>
<td>Standardで標準提供</td>
<td>plamo-3.0-prime等でモデル差なし（プランで決まる）</td>
<td><strong>Freeは学習利用されうる・ZDR対象外（2026年7月時点は準備中）</strong>。APPI意識の国内設計</td>
</tr>
<tr>
<td><strong>Sakana AI（Fugu）</strong></td>
<td><strong>あり</strong>（opt-out可・非遡及）</td>
<td>保存義務なし（削除義務も負わないと明記）</td>
<td>明示なし</td>
<td>転送先の外部モデルのポリシーに依存</td>
<td>外部LLMへルーティング、二重評価が必要。人間レビューあり</td>
</tr>
</tbody></table></div>
<p>各セルの出典は本文の該当節を参照してください。</p>
<h2 id="実務でどう判断するか">実務でどう判断するか</h2><p>整理して見えてきた勘所は4点です。</p>
<ol>
<li><p>「学習しない」と「保存しない」は別物です。エンタープライズAPIは学習利用こそデフォルトオフですが、Abuse Monitoring目的の保持（多くは30日）は別に走っています。</p>
</li>
<li><p>ZDRは全消し設定ではありません。OpenAIのキャッシュやCode Interpreter、GoogleのGrounding、AnthropicのUser Safety分類スコアなど、ZDRを有効にしても残るものが各社にあります。機能単位で棚卸ししてください。</p>
</li>
<li><p>同じサービスでも、選んだモデルで結論が変わります。Claude Fable 5 &#x2F; Mythos 5はZDR契約下でも30日保持が必須、OpenAIはdall-e系がZDR不可・gpt-image系が可です。実際に叩くモデルまで落として確認してください。</p>
</li>
<li><p>デフォルトの保持挙動はサービスやプランで真逆になることがあります。同じAnthropicでも素のAPIは非保持、Team &#x2F; Enterpriseはカスタム設定しない限り無期限で、PLaMoも有償Standardは非保持・無償Freeは対象外です。ZDRも各社とも承認制・上位契約前提なので、全業務に引くのは過剰です。データを分類し、極秘データを扱う経路には確実にZDRを当てるのが現実的です。</p>
</li>
</ol>
<p>セキュリティレビューでは、AIサービスについて「①学習利用 ②保持期間 ③ZDR可否と例外 ④利用モデル ⑤リージョン&#x2F;契約要件（承認制か・BAA&#x2F;DPA〈データ処理契約〉有無）」の5点を、最低限のチェック項目として確認すべきだと思われます。モデルが1つ増えても、この5軸に当てはめれば整理できます。今回のFable 5のように同じサービスでもモデルで結論が変わることがあるため、④利用モデルは独立した観点として持っておくとよいでしょう。</p>
<p>各社ポリシーは改定が速い領域です。この記事の数値も、実務判断の前には必ず一次情報で再確認してください。</p>
<hr>
<p><strong>参考（主な一次情報）</strong></p>
<ul>
<li>OpenAI: Data controls in the OpenAI platform &#x2F; Enterprise privacy at OpenAI</li>
<li>Anthropic: API and data retention &#x2F; How long do you store my data? &#x2F; How long do you store my organization’s data? &#x2F; Custom data retention for Enterprise &#x2F; ZDR agreement — supported products</li>
<li>Google: Zero data retention in the Gemini Developer API</li>
<li>Preferred Networks: PLaMo API ドキュメント &#x2F; PLaMo API プラン &#x2F; PLaMo API 利用規約</li>
<li>Sakana AI: Fugu Terms of Service &#x2F; 金融個人データ保護指針</li>
</ul>
]]></content>
    <summary type="html">Fable 5は、ZDRではなく30日のデータ保持が必須という仕様です。同じClaudeでも、他の多くのモデルはZDR下で会話内容を残さないサービス仕様ですが、Fable 5はこの点が異なります。</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="LLM" scheme="https://future-architect.github.io/tags/LLM/"/>
  </entry>
  <entry>
    <title>BigQueryから直接Geminiを叩こう。BigQueryMLによるログ解析ハンズオン</title>
    <link href="https://future-architect.github.io/articles/20260430a/"/>
    <id>https://future-architect.github.io/articles/20260430a/</id>
    <published>2026-04-29T15:00:00.000Z</published>
    <updated>2026-04-29T15:00:00.000Z</updated>
    <author><name>柴田健太</name></author>
    <content type="html"><![CDATA[<p>春の入門祭り2026の6本目です。</p>
<h2 id="はじめに">はじめに</h2><p>こんにちは。フューチャーアーキテクト 製造・エネルギーサービス事業部の柴田です😌 見真の心で本質を探求しています!</p>
<p>BigQuery上のデータに対して、外部APIを呼び出すことなく、クエリ内でGeminiによるテキスト生成やデータ解析する手順をまとめました。サービスに対する対応の手間を減らすために、エラー発生時の推奨アクションを提示しています。</p>
<p>普段のGemini利用と異なる利用料金などについても整理しています。</p>
<h2 id="事前準備">事前準備</h2><p>BigQueryとVertex AIを連携させるための設定とモデルを作成します。</p>
<h3 id="全体の構成図">全体の構成図</h3><p>モデル利用のためには、次の設定が必要です。</p>
<ul>
<li>外部接続</li>
<li>外部接続で呼び出すモデル</li>
</ul>
<p>構成図は以下の通りです。</p>
<pre class="mermaid" data-mermaid="4916b6432fd4e1427f7eb1f797ab2e0ec84e47bbd700e7051914218418da70db">graph LR
    %% ノードの定義とラベル
    Query[SQL クエリ<br/>ML.GENERATE_TEXT]

    subgraph BQ_RemoteModel [BQリモートモデル gemini_model]
        direction TB
        Model_Config[モデル設定]
        Connection[外部接続 vertex_ai_conn<br/>認証の通り道]
    end

    VertexAI[Vertex AI Gemini API]

    %% フローの定義
    Query -->|モデルを指定<br/>Connection情報をロード| BQ_RemoteModel

    %% 認証とAPI呼び出しのフロー (ここがデータの通り道)
    Connection -->|セキュアに通信<br/>API呼び出し| VertexAI

    %% スタイリング（Google Cloudカラーをイメージ）
    classDef bq fill:#e0f7fa,stroke:#01579b,stroke-width:1px,color:#01579b;
    classDef conn fill:#ffccbc,stroke:#bf360c,stroke-width:1px,color:#bf360c,stroke-dasharray: 5 5;

    class Query,BQ_RemoteModel,Model_Config bq;
    class Connection conn;</pre>

<h3 id="外部接続（Connection）の作成">外部接続（Connection）の作成</h3><p>BigQueryコンソールの「データ 追加」 &gt; 「Vertex AI」のデータソースを選択（vertex aiで検索）</p>
<img fetchpriority="high" src="/images/2026/20260430a/データ追加を選択してVertexAIのデータソースを選択.png" alt="データ追加を選択してVertexAIのデータソースを選択" width="1190" height="839">

<p>外部データへのアクセスで、BiqQueryフェデレーションを選択します。</p>
<img src="/images/2026/20260430a/BiqQueryフェデレーションが赤枠で囲まれている.png" alt="BiqQueryフェデレーションが赤枠で囲まれている" width="1200" height="351" loading="lazy">

<p>以下のように、外部データソースとの接続を作成します。</p>
<ul>
<li>接続タイプ：Vertex AI リモートモデル、リモート関数、BigLake, Spanner（Cloud リソース）</li>
<li>接続ID：用途が分かりやすい名前にする（接続名なので*_connという命名を推奨）</li>
<li>ロケーションタイプ：任意のリージョンを選択</li>
<li>分かりやすい名前：日本語OKなので利用方法が明確な名前にします</li>
<li>説明：より詳細な説明</li>
</ul>
<img src="/images/2026/20260430a/外部データソース設定.png" alt="外部データソース設定" width="1038" height="962" loading="lazy">

<p>作成した接続はBigQueryコンソールの「接続」で確認できます。</p>
<img src="/images/2026/20260430a/サイドバーの接続を、接続を確認.png" alt="サイドバーの接続を、接続を確認" width="1200" height="436" loading="lazy">

<h3 id="リモートモデルの定義">リモートモデルの定義</h3><p>BigQueryから外部のGemini APIを呼び出すための、設定情報（メタデータ）を登録します。<br>以下の<code>CREATE OR REPLACE MODEL</code>クエリを実行してモデルを作成します。<br>BigQuery内に、Geminiを呼び出すためのモデルを定義します。これは1度だけ実行すればOKです。</p>
<figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">OR</span> REPLACE MODEL プロジェクト名.データセット名.モデル名</span><br><span class="line">REMOTE <span class="keyword">WITH</span> CONNECTION プロジェクト名.リージョン.先ほど作成した接続ID</span><br><span class="line">OPTIONS (</span><br><span class="line"><span class="comment">-- 利用したいGeminiのエンドポイントを指定（例:gemini-2.5-flash, gemini-2.5-pro）</span></span><br><span class="line">endpoint <span class="operator">=</span> <span class="string">&#x27;使用するモデル&#x27;</span></span><br><span class="line">);</span><br></pre></td></tr></table></figure>

<p>参考：クエリの具体例は以下の通りです。</p>
<figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">OR</span> REPLACE MODEL `project_id.logexplorer.gemini_model`</span><br><span class="line">REMOTE <span class="keyword">WITH</span> CONNECTION `project_id.asia<span class="operator">-</span>northeast1.logexplorer_ai_conn`</span><br><span class="line">OPTIONS (</span><br><span class="line">endpoint <span class="operator">=</span> <span class="string">&#x27;gemini-2.5-flash&#x27;</span></span><br><span class="line">);</span><br></pre></td></tr></table></figure>

<p>クエリを実行すると、指定したデータセットの直下にモデルが作成されます。</p>
<img src="/images/2026/20260430a/モデル.png" alt="モデル" width="1200" height="676" loading="lazy">

<h2 id="モデルの利用">モデルの利用</h2><p>作成したモデルを利用して推論します。ここでは実際のクエリ例を示します。特定の処理で発生したエラーログをBigQueryにリアルタイムで取り込ませている状態で、このようなプロンプトでエラーに対する推奨アクションをAIに教えてもらおうとしています。</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">あなたは優秀なクラウドデータエンジニアです。</span><br><span class="line">以下のエラーメッセージから原因を推測し、解決のための具体的な「推奨対応方法」を150文字以内で提示してください。</span><br><span class="line">【対象ファイル】：対象ファイル名</span><br><span class="line">【エラーメッセージ】：エラーメッセージ</span><br></pre></td></tr></table></figure>

<p>以下の例はstatus_tag が ‘error’ のログを抽出し、Geminiに推奨アクションを推論させるというクエリです。</p>
<figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="comment">-- ====================================================================</span></span><br><span class="line"><span class="comment">-- 目的: status_tag が &#x27;error&#x27; のログを抽出し、Geminiに推奨アクションを推論させる</span></span><br><span class="line"><span class="comment">-- ====================================================================</span></span><br><span class="line"><span class="keyword">SELECT</span></span><br><span class="line">	timestamp_jst,</span><br><span class="line">	service_name,</span><br><span class="line">	target_file,</span><br><span class="line">	status_tag,</span><br><span class="line">	message,</span><br><span class="line"><span class="comment">-- JSONレスポンスからテキスト部分のみを抽出（回答の本文のみを取り出す必須処理）</span></span><br><span class="line"><span class="built_in">JSON_VALUE</span>(ml_generate_text_result, <span class="string">&#x27;$.candidates[0].content.parts[0].text&#x27;</span>) <span class="keyword">AS</span> recommended_action</span><br><span class="line"><span class="keyword">FROM</span> ML.GENERATE_TEXT(</span><br><span class="line"><span class="comment">-- ==================================================================</span></span><br><span class="line"><span class="comment">-- モデルの指定</span></span><br><span class="line"><span class="comment">-- 事前に CREATE MODEL で作成した、Vertex AI（Gemini）を呼び出すためのモデルを指定します。</span></span><br><span class="line"><span class="comment">-- ==================================================================</span></span><br><span class="line">	MODEL project_id.logexplorer.gemini_model,</span><br><span class="line">(</span><br><span class="line"><span class="comment">-- ================================================================</span></span><br><span class="line"><span class="comment">-- 1. AIに渡すためのデータ（プロンプト）を準備するサブクエリ</span></span><br><span class="line"><span class="comment">-- ================================================================</span></span><br><span class="line"><span class="keyword">SELECT</span></span><br><span class="line">	timestamp_jst,</span><br><span class="line">	service_name,</span><br><span class="line">	target_file,</span><br><span class="line">	status_tag,</span><br><span class="line">	message,</span><br><span class="line">	CONCAT(</span><br><span class="line">	<span class="string">&#x27;あなたは優秀なクラウドデータエンジニアです。\n&#x27;</span>,</span><br><span class="line">	<span class="string">&#x27;以下のエラーメッセージから原因を推測し、解決のための具体的な「推奨対応方法」を150文字以内で提示してください。\n\n&#x27;</span>,</span><br><span class="line">	<span class="string">&#x27;【対象ファイル】&#x27;</span>, IFNULL(target_file, <span class="string">&#x27;不明&#x27;</span>), <span class="string">&#x27;\n&#x27;</span>,</span><br><span class="line">	<span class="string">&#x27;【エラーメッセージ】\n&#x27;</span>, IFNULL(message, <span class="string">&#x27;なし&#x27;</span>)</span><br><span class="line">	) <span class="keyword">AS</span> prompt</span><br><span class="line"><span class="keyword">FROM</span></span><br><span class="line">	project_id.logexplorer.logexplorer_errors</span><br><span class="line"><span class="keyword">WHERE</span></span><br><span class="line">	status_tag <span class="operator">=</span> <span class="string">&#x27;error&#x27;</span>          <span class="comment">-- 指定条件：エラーのみを対象</span></span><br><span class="line">	<span class="keyword">AND</span> message <span class="keyword">IS</span> <span class="keyword">NOT NULL</span>       <span class="comment">-- メッセージが空のものは除外（APIの無駄撃ち防止）</span></span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span></span><br><span class="line">	timestamp_jst <span class="keyword">DESC</span></span><br><span class="line">),</span><br><span class="line"><span class="comment">-- ==================================================================</span></span><br><span class="line"><span class="comment">-- 2. モデルの推論パラメータ設定</span></span><br><span class="line"><span class="comment">-- ==================================================================</span></span><br><span class="line">STRUCT(</span><br><span class="line"><span class="number">0.0</span> <span class="keyword">AS</span> temperature,       <span class="comment">-- 0.0にすると回答が固く・決定的になる（エラー分析に適している）</span></span><br><span class="line"><span class="number">300</span> <span class="keyword">AS</span> max_output_tokens  <span class="comment">-- 出力される最大トークン数（コスト上限のストッパー）</span></span><br><span class="line">)</span><br><span class="line">);</span><br></pre></td></tr></table></figure>

<h2 id="利用料金を押さえるためのポイント">利用料金を押さえるためのポイント</h2><p>これまでの手順で各レコードに対してGeminiを実行できますが、好き放題に利用すると料金が膨らんでいきコストを圧迫してしまいます。</p>
<p>なので、ここでは利用料金を抑えるための解決方法の例を紹介しますす。</p>
<h3 id="Geminiの料金体系（Gemini-2-5-2025年4月29日現在）">Geminiの料金体系（Gemini 2.5  2025年4月29日現在）</h3><ul>
<li>トークン数の比例して課金される（日本語の場合は１文字２トークン）</li>
<li>入力・出力の合計トークン数で課金額が決まる</li>
</ul>
<div class="scroll"><table>
<thead>
<tr>
<th>モデル</th>
<th>タイプ</th>
<th>料金（100 万トークンあたり）&lt;&#x3D; 20 万入力トークン</th>
<th>料金（100 万トークンあたり）&gt;20 万入力トークン</th>
</tr>
</thead>
<tbody><tr>
<td>Gemini 2.5 Pro</td>
<td>入力（テキスト、画像、動画、音声）</td>
<td>$1.25</td>
<td>$2.50</td>
</tr>
<tr>
<td></td>
<td>テキスト出力（回答と推論）</td>
<td>$10</td>
<td>$15</td>
</tr>
<tr>
<td>Gemini 2.5 Flash</td>
<td>入力（テキスト、画像、動画）</td>
<td>$0.30</td>
<td>$0.30</td>
</tr>
<tr>
<td></td>
<td>テキスト出力（回答と推論）</td>
<td>$2.50</td>
<td>$2.50</td>
</tr>
</tbody></table></div>
<h3 id="利用料金を抑える方法の例">利用料金を抑える方法の例</h3><ol>
<li>用途におけるモデルの選択<br>上記の表が示すように、FlashとProでは利用料金が3倍以上変わります。普段使いではとりあえず一番性能がいいものを選びがちですが、コストに直結するため複雑な推論を必要としない場合などにはFlashや古いバージョンのモデルを利用します。</li>
<li>同じ質問を何度もしない<br>一度推論した結果（プロンプトと回答のセット）はBigQueryのテーブルに保存し、次回以降は JOIN で過去の回答を使い回す。</li>
<li>バッチ内重複排除<br>2.とやや共通していますが、1回のスケジュール実行内で同じエラーが複数ある場合、GROUP BY や ROW_NUMBER() を使って代表の1件だけをGeminiに投げ、結果を他の行にコピーする。</li>
</ol>
<h2 id="さいごに">さいごに</h2><p>以上、BigQuery内で直接Geminiを実行する方法の紹介でした。</p>
<p>普段Gemiiniに何かを聞くときは料金を気にしないと思いますが、システムに組み込むときにはちゃんと事前にコストを計算しないと、思わぬ請求額へと膨れ上がってしまう可能性があります。特に入力プロンプトは長くなりがちですが、ここは料金にかなり大きく効いてきます。</p>
<p>これからのデータエンジニアリングにとっても、AIを組み込むことが必須になっていますので、その助力になれば幸いです。</p>
<h2 id="参考">参考</h2><ul>
<li>BIqQueryでのAI実行方法<br>https://docs.cloud.google.com/bigquery/docs/generate-text?hl=ja</li>
<li>Vertex AIの料金<br>https://cloud.google.com/vertex-ai/generative-ai/pricing?hl=ja</li>
<li>モデル一覧（実装時に必要なモデルIDを確認できる）<br>https://console.cloud.google.com/vertex-ai/model-garden?hl=ja</li>
</ul>
]]></content>
    <summary type="html">BigQuery上のデータに対して、外部APIを呼び出すことなく、クエリ内でGeminiによるテキスト生成やデータ解析を行う手順をまとめました。</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="BigQuery" scheme="https://future-architect.github.io/tags/BigQuery/"/>
    <category term="Gemini" scheme="https://future-architect.github.io/tags/Gemini/"/>
    <category term="GoogleCloud" scheme="https://future-architect.github.io/tags/GoogleCloud/"/>
    <category term="ハンズオン" scheme="https://future-architect.github.io/tags/%E3%83%8F%E3%83%B3%E3%82%BA%E3%82%AA%E3%83%B3/"/>
  </entry>
  <entry>
    <title>言語処理学会 (NLP2026) 参加報告</title>
    <link href="https://future-architect.github.io/articles/20260420a/"/>
    <id>https://future-architect.github.io/articles/20260420a/</id>
    <published>2026-04-19T15:00:00.000Z</published>
    <updated>2026-04-19T15:00:00.000Z</updated>
    <author><name>田中裕真</name></author>
    <content type="html"><![CDATA[<h2 id="はじめに">はじめに</h2><p>はじめまして！フューチャー株式会社の田中裕真と申します。</p>
<p>私は2025年10月に新卒として入社し、2026年2月にAIXG(AI戦略推進グループ)のNLPチームに配属されました。配属からちょうど2ヶ月が経ち、これまでのゆったりとした生活から一変して、忙しくも目まぐるしく新しい情報が得られ、知的好奇心を満たしながら働く充実した毎日を送っています。</p>
<p>大学院での研究ではAIの性能調査などを通じてAI自体には触れていたものの、自然言語処理（NLP）分野はあまり経験がありませんでした。現在はNLP関連のキャッチアップを進めながら、チャットシステムの構築業務に携わっています。</p>
<p>本記事では、2026年3月9日(月)〜3月13日(金)にかけて栃木県宇都宮市で開催された言語処理学会第32回年次大会 (NLP2026) の参加報告をお届けします。</p>
<p>当社はプラチナスポンサーとして協賛し、総勢8名がオンサイトで参加しました。スポンサーブースでの企業紹介や、メンバーによる研究発表など、非常に活気あふれる5日間となりました。<br><img fetchpriority="high" src="/images/2026/20260420a/image5.jpg" alt="image5.jpg" width="1200" height="800"></p>
<h2 id="言語処理学会とは">言語処理学会とは</h2><p>言語処理学会は、自然言語処理（NLP）分野における国内最大の学会で、毎年3月に開催されています。第32回となる今年の年次大会は、栃木県宇都宮市でのオンサイト開催とオンライン配信のハイブリッド形式で行われました。</p>
<p>今回の大会は、事前＋直前参加登録者が2236人（歴代2位）に上り、当日参加者を合わせると歴代1位の参加者数を記録しました。さらに、発表件数は797件（歴代1位）、スポンサー数は100団体（歴代2位）と過去最大級の規模となりました。生成AIや大規模言語モデル（LLM）の社会実装が急速に進む中、産学問わず非常に多くの研究者が集い、基礎研究から応用事例まで幅広い議論が交わされる熱気のある学会です。NLP初学者の私にとっても、最前線の研究トレンドを直接肌で感じることができる非常に貴重な機会となりました。<br><img src="/images/2026/20260420a/attendances.jpeg" alt="attendances.jpeg" width="1200" height="825" loading="lazy"></p>
<h2 id="スポンサーブースの様子">スポンサーブースの様子</h2><p>企業ブースでは、NLP関連の過去の導入事例や、そのほかのAIXG担当領域について紹介しました。連日多くの方々に足を運んでいただき、NLPの社会実装に関するディスカッションや、学生の皆さんとの交流で大いに盛り上がりました。</p>
<p>今回はノベルティとして眼鏡やディスプレイを拭ける「クロス」と折りたたみ可能な「トートバッグ」を用意しご好評をいただきました。</p>
<figure><img src="/images/2026/20260420a/booth.jpg" alt="booth.jpg" width="1200" height="900" loading="lazy"><figcaption>▲ 企業ブースの様子</figcaption></figure>
<h2 id="祝・若手奨励賞受賞！">祝・若手奨励賞受賞！</h2><p>本大会では、同じAIXGメンバーである藤井の主著論文『TimeMachine-bench: LLMは「あの日」のコードを最新環境に適応できるか？』が、見事<strong>若手奨励賞</strong>に選出されました！<br>当論文の背景や解説については、著者の藤井自身が執筆したブログ記事が公開されておりますので、ぜひ併せてご覧ください。</p>
<ul>
<li>【著者解説】NLP2026 若手奨励賞受賞論文 “TimeMachine-bench” を著者が解説する</li>
</ul>
<h2 id="投稿論文の紹介">投稿論文の紹介</h2><p>当社は、NLP2026において著者・共著者を含めて合計4件の論文を投稿しました。</p>
<p>本章ではこれらの4件の論文について簡単に紹介します。</p>
<ul>
<li><strong>[B8-1]UI-Redline-bench: 赤入れ指示によるWebUIコード修正ベンチマーク</strong><br>この論文では、WebUI開発における、スクリーンショットに直接手書きで修正指示を書き込む「赤入れ」プロセスに着目し、視覚的指示に基づくコード修正タスクのベンチマーク「UI-Redline-bench」を構築しています。人間にとって直感的な形式の指示に対するVLM（視覚言語モデル）の処理能力に焦点を当て、VLMを活用した開発作業の能率向上への寄与を目指すものです。<br>　既存研究が主に言語的指示を扱っているのに対し、本研究は図形や文字を使って描きこまれた視覚的指示を扱う点が特徴です。著者らが視覚的指示を描きこみ作成した、計350件のHTML&#x2F;CSSコード修正データセットにより、GPT-5等の主要なVLMの視覚的指示に基づくコード修正能力を検証しました。<br>検証の結果、GPT-5等は全体として高い修正能力を示した一方で、矢印を使って示された離れた位置に、概形で描かれたUIを実装する事例では、修正に失敗する傾向が見られました。この結果から、今後VLMの空間推論能力の強化が不可欠であると言えます。具体的には、矢印の指し示す位置を正しく認識する、個々の図形を意味のあるまとまりとしてグループ化するなど、空間的に分散した視覚的指示を統合するタスクの必要性が示唆されています。（肥合）</li>
<li><strong>[B8-3]TimeMachine-bench: LLMは「あの日」のコードを最新環境に適応できるか？</strong><br>この論文は本学会において若手奨励賞に選出されました！こちらの技術ブログで詳しく説明されていますので、ぜひご覧ください。</li>
<li><strong>[B9-19]WikiOriginQA: 知識の起源を組み込んだ文化的バイアス分析用QAデータセットの自動構築</strong><br>この論文では、LLMの性能における文化的バイアスを検証するためのQAデータセットと、その自動構築手法を提案しています。LLMの学習データは、英語をはじめとした使用者の多い主要な言語に偏っています。そのため、主要言語圏の知識は良く知っている一方で、マイナーな言語圏の知識は適切に扱えないという文化的バイアスが起こることが知られています。しかし、既存の手法では該当する文化に詳しい協力者を必要とするため、多言語・多文化にわたる調査用データセットの構築は困難でした。そこで本論文では、「ある文化に特有の知識は、その文化と関係の深い言語において最も早くドキュメント化される」という仮説に基づき、文化的知識と言語の結びつきをWikipediaの記事作成日を用いて表現することで、文化的知識を問うQAデータセット「WikiOriginQA」を自動構築しました。<br>WikiOriginQAを用いた実験の結果、先行研究と同様にLLMの性能における英語圏の文化へ偏重傾向が確認され、これにより、多様な文化におけるバイアス検証を人手を介さずに行う上で、本手法が有効であることが示唆されました。（羽根田）</li>
<li><strong>[C9-20]項の復元は必要か？日英機械翻訳における省略された項の扱いの分析</strong><br>この論文では、主語や目的語等の述語の項が省略されやすい日本語のような言語 (pro-drop言語) から英語への機械翻訳において、従来重視されてきた「省略された項の同定および復元」が本当に必要かという問題に対し、その必要性を実証的に検証しています。<br>具体的には、LLM (GPT-4o) を用いた日英翻訳を対象に、省略項の同定 (ゼロ照応解析) の成否と翻訳品質の関係、および翻訳時に項がどの程度復元されるかを分析しています。また、省略項が復元されなかった場合の構文選択なども含め、多角的な事例分析が行われています。<br>その結果、GPT-4oは省略項の同定が困難な事例や項を復元せずに訳した場合においても文意が伝達できる翻訳が行えていました。ただし、項の同定が困難な事例では復元を避ける傾向が見られるなど項の同定可否に伴って翻訳の性質には差が見られました。しかし、省略項を復元しない場合、GPT-4oは述語の名詞化や受動態などを用いることで構文的に自然な翻訳が行えていました。これらの結果から、項の同定・復元は必須ではなく、日英翻訳において最先端のLLMには項の省略はもはや主要な障壁ではないことが示唆されました。 (野末)</li>
</ul>
<h3 id="社員が選ぶNLP2026の注目論文の紹介">社員が選ぶNLP2026の注目論文の紹介</h3><p>ここからは、NLP2026に参加したメンバーが各自の視点で「これは面白い！」「業務に活かせそう！」と感じたイチオシの論文やセッションを3件ピックアップして紹介します。</p>
<ul>
<li><strong>[P8-20] 多言語文埋め込みの意味と言語の分離のための損失関数の分析</strong><br>日本語や英語など、言語が違っても似た意味の文同士が近くなるようにベクトル化する「多言語文埋め込み」は、情報検索や機械翻訳の品質推定など幅広い領域で使われています。<br> この技術では「言語によらず」意味の近さが反映されることが理想ですが、実際には言語情報に引っ張られてクラスタが分離してしまい、言語横断的なタスクでの性能低下を招くことが知られています。そのため先行研究では、文埋め込みを「意味表現」と「言語表現」に分離し、意味表現のみを用いる手法が提案されてきました。<br>この分離のための学習手法（損失関数の設計）には、各要素内で完結する「要素内制約」と、両者に跨る「要素間制約」が存在しますが、これらが分離にどう寄与するかは十分に分かっていませんでした。本研究でこれらを比較した結果、従来のエンコーダ由来モデル（LaBSEなど）では両者の併用が有効な一方、近年のデコーダ由来モデル（Gemini Embeddingなど）では「要素間制約」のみを用いる方が高い性能を示すことが明らかになりました。<br>　LLMベースのモデルが普及する中で、従来のモデルとは適した学習アプローチが異なることを実証した事実は興味深いと考え、こちらの発表を取り上げました。（森下）</li>
<li><strong>[Q3-10] マルチモーダルかつ長い文脈の処理が求められる語用論的推論ベンチマーク</strong><br>大規模言語モデル（LLM）や大規模視覚言語モデル（VLLM）において、言語の辞書的な意味ではなく文脈依存の意味を理解するための「語用論的推論能力」の向上は社会実装を目指すうえで重要な課題です。この研究では、特にマルチモーダルかつ長期文脈の処理が必要な設定における語用論的推論のベンチマークを提案しています。<br>特徴として、漫画データを題材として採用し、著者が人手で問題・選択肢を作成することで計101問の多肢選択式QAデータセットを構築しています。実際にVLLMと人間による評価実験を行った結果、最新のVLLMであっても正解率は人間を大きく下回り、語用論的推論能力には課題が残っていることが示されました。<br>マルチモーダル・長期文脈の処理が必要な設定として漫画を活用している点や、評価実験を通して昨今著しい性能向上が見られるVLLMの弱点を浮き彫りにした点が非常に興味深く、挙げさせていただきました。(岸波)</li>
<li><strong>[B6-7] クロスコーダーを用いた脳と言語モデルにおける内部表現の特徴量比較</strong><br>本研究は、ポッドキャスト聴取時の脳活動（fMRIデータ）と言語モデル（LM）の内部表現を「クロスコーダー」という手法で比較し、両者の情報処理における類似点や相違点を検証した論文です。従来の研究では、LMの表現から脳応答を予測するエンコーディングモデルが主流でしたが、これはLMから脳への一方向的な写像に留まり、予測の根拠となる要因を人間が理解できる形で抽出できない（解釈性が低い）という課題がありました。<br>本手法では、脳応答とLM表現の両方を同一のスパース（疎）な潜在空間に写像し、そこからそれぞれの表現を再構成するプロセスを学習します。この仕組みにより、抽出された特徴量が脳とLMのどちらに強く寄与しているかを定量的に評価することが可能になりました。実験の結果、「場所」に関する描写は脳とLMで共通して表現されている一方、「負の情動」は脳側に、フィラー（言いよどみ）などの「口語表現」はLM側に特有の反応として抽出されました。<br>fMRIの解像度の限界や、因果関係の特定といった課題はあるものの 、AIの内部表現と人間の理解を直接比較し、その差を数値で示せる点は非常に画期的です。知性の在り方を定量的に議論できる可能性に興味を惹かれ、本論文を取り上げました。（田中）</li>
</ul>
<h3 id="会場の様子・オフタイムのエピソード">会場の様子・オフタイムのエピソード</h3><p>オンサイト参加ならではの、現地の雰囲気やエピソードも少しご紹介します。</p>
<p>最も印象的だったのは、学会オープニングでの出来事です。全プログラム終了後に「重要な注意事項」と銘打たれたスライドで<strong>宇都宮餃子の正しい食べ方</strong>のレクチャーがありました。開催地である宇都宮ならではの粋な計らいに、会場全体が温かい笑いと拍手に包まれました。</p>
<figure><img src="/images/2026/20260420a/gyoza_lecture.jpeg" alt="gyoza_lecture.jpeg" width="1200" height="900" loading="lazy"><figcaption>▲ オープニングでの「重要なお知らせ（餃子の食べ方）」</figcaption></figure>
<p>また、天候に関しては驚きの連続でした。開催2日目には、3月であるにもかかわらずなんと<strong>大雪</strong>に見舞われました。会場周辺の道も真っ白に雪が積もり、ある意味で非常に記憶に残る学会となりました。</p>
<figure><img src="/images/2026/20260420a/snow_scene.jpg" alt="snow_scene.jpg" width="1200" height="855" loading="lazy"><figcaption>▲ 3月とは思えない大雪に見舞われた2日目</figcaption></figure>
<p>一方で、天気の良いお昼時には会場の外にキッチンカーが出店しており、日差しを浴びながら外でランチを楽しむこともできました。</p>
<h2 id="おわりに">おわりに</h2><p>NLP初学者としての参加でしたが、日々の業務に直結する知見や、LLMの最新動向など、膨大なインプットを得ることができました。何より、最前線で活躍する研究者やエンジニアの熱量に直接触れることができ、「自分もさらに技術を磨いていこう」と強くモチベーションを刺激されました。</p>
<p>現在、AIXGのNLPチームでは、以下のような環境・制度を整え、NLPの基礎・応用技術開発を積極的に推進しています。</p>
<ul>
<li><strong>大学との共同研究</strong></li>
<li><strong>社会人博士制度</strong></li>
<li><strong>新規参画者への教育プログラム</strong></li>
<li><strong>GPUクラスタ</strong></li>
</ul>
<p>こうした環境のもと、ともに働くメンバーを積極的に募集しています！</p>
<p><strong>学生の皆様へ</strong><br>夏季インターンやアルバイトについては、4月20日 (月) に下記のウェブサイトから募集を開始いたします。<br>また、博士課程向けのResearch Internは通年募集中です。</p>
<p>https://www.future.co.jp/recruit/summer_intern/2026/</p>
<p>昨年のインターンシップ参加者へのインタビューもぜひご確認ください。</p>
<p>https://future-architect.github.io/articles/20260323a/</p>
<p><strong>新卒・キャリア採用について</strong><br>NLP分野における社会実装のニーズは拡大し続けており、自然言語処理の力で顧客のビジネス課題を解決していく仲間を求めています。少しでも興味を持っていただけた方は、ぜひ以下の採用リンクからご応募をお待ちしております！</p>
<ul>
<li>新卒採用 : https://www.future.co.jp/recruit/recruit/rec-fresh/</li>
<li>キャリア採用 : https://www.future.co.jp/recruit/recruit/rec-career/</li>
</ul>
]]></content>
    <summary type="html">2026年3月9日(月)〜3月13日(金)にかけて栃木県宇都宮市で開催された 言語処理学会第32回年次大会 NLP2026 の参加報告をお届けします。</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="NLP" scheme="https://future-architect.github.io/tags/NLP/"/>
    <category term="参加レポート" scheme="https://future-architect.github.io/tags/%E5%8F%82%E5%8A%A0%E3%83%AC%E3%83%9D%E3%83%BC%E3%83%88/"/>
    <category term="学会" scheme="https://future-architect.github.io/tags/%E5%AD%A6%E4%BC%9A/"/>
  </entry>
  <entry>
    <title>【著者解説】NLP2026 若手奨励賞受賞論文 &quot;TimeMachine-bench&quot; を著者が解説する</title>
    <link href="https://future-architect.github.io/articles/20260316a/"/>
    <id>https://future-architect.github.io/articles/20260316a/</id>
    <published>2026-03-15T15:00:00.000Z</published>
    <updated>2026-03-15T15:00:00.000Z</updated>
    <author><name>藤井諒</name></author>
    <content type="html"><![CDATA[<h2 id="はじめに">はじめに</h2><p>こんにちは。Strategic AI Group (SAIG) の藤井です。</p>
<p>この度、3&#x2F;9 (月) 〜 3&#x2F;13 (金) に栃木県は宇都宮市で開催された言語処理学会第32回年次大会 (NLP2026) において、光栄なことに主著論文 TimeMachine-bench: LLMは「あの日」のコードを最新環境に適応できるか？ が若手奨励賞に選出されました。<br>論文の審査を担当いただきました関係者の皆様にこの場をお借りして感謝いたします。</p>
<p>本記事では、当該論文、およびその拡張版であるEACL2026 (Main Conference) 採択論文 TimeMachine-bench: A Benchmark for Evaluating Model Capabilities in Repository-Level Migration Tasks (3&#x2F;24 〜, モロッコ・ラバトにて開催) を著者として解説します。</p>
<img fetchpriority="high" src="/images/2026/20260316a/overview.png" alt="overview.png" width="1200" height="742">

<h3 id="背景">背景</h3><p>研究や業務でプログラムを書く人であれば、誰しもがこんな経験をしたことがあるのではないでしょうか？</p>
<p><strong>あれ、昨日までは動いていたのに… 何もしてないのに壊れたー！</strong></p>
<p>我々 (あるいはAI) が日頃書くプログラムは、その多くが外部のライブラリに依存しています。例えば、 <code>transformers</code> や <code>pytorch</code>、<code>openai</code> といったライブラリにお世話になっている人も多いのではないでしょうか？</p>
<p>しかし、ソフトウェアというものは常に進化しています。</p>
<p>これには、より便利な機能を追加するといったポジティブな側面はもちろん、セキュリティ脆弱性や、サポート切れ (EOL) への対応といったものも含まれます。そして、そのような進化は時として「破壊的変更」(breaking changes) をもたらします。</p>
<p>すなわち、なんらかの関数が削除されたり、取りうる引数が変わるなど、引き続き使い続けるためには、<strong>それらを利用する側のコードにも修正が必要になる</strong>ような変更が度々発生します。そうした変更は「利用者の望む望まざるに関わらず」依存ライブラリのどこかで突然発生しうることから、冒頭に述べたような (我々は)「何もしてないのに壊れたー！」が生み出される原因となるわけです。</p>
<p>このような「不可抗力」的な性質も相まって、ユーザコードを新たな環境に適応させるタスクである「ソフトウェアマイグレーション」はエンジニアの悩みの種となっています🌱。</p>
<p>さて、世はLLM時代。</p>
<p>もはや人間が一からコードを書くことは少なくなった今、LLMは「マイグレーション」もそつなくやってのけるのでしょうか？<br>本研究はそんな疑問から出発しました。</p>
<h3 id="先行研究のギャップ">先行研究のギャップ</h3><h4 id="static-vs-dynamic">static vs. dynamic</h4><p>数年前には短い関数の補完すらままならなかったCode LLMsも、今や日頃の開発パートナーとして欠かせない存在となっています。</p>
<p>このような急速なモデルや手法の進化を支えているのが、モデルの性能を評価するベンチマークの存在です。初めはHumanEvalやMBPPといった関数レベルのコード補完タスクが中心でしたが、それらが徐々に解けるようになり、現在ではエンジニアの日常業務を模したより実世界的なタスクにフォーカスが移行しています。例えば、現在Code LLMs評価のデファクトであるSWE-benchは、GitHubのissueを読み、issueに記載された問題を解決するためのパッチを作成するという非常に実用的な課題を対象としています。</p>
<p>しかしながら、そうした先行研究はソフトウェアのある重要な側面を軽視してきました。それが冒頭に述べた「進化」です。</p>
<p>言葉の使われ方が時を経て変化するように、ある機能を実現するために正しいプログラムもバージョンの変遷とともに変化します。近年では、このように「進化」する環境におけるコード生成・マイグレーション能力にも注目が集まってきています。</p>
<p>一方で、それらの先行研究はしばしばスケーラブルではなく、タスクの内容も「新旧の対応を知っているかを問う一問一答」のような形式となっており、現実的なマイグレーションタスクのベンチマークとしては不足感が否めない状況にありました。</p>
<h4 id="手法の限界">手法の限界</h4><p>では、なぜそのような課題が生じるのか。</p>
<p>これは、主に先行研究がどのようにタスクを作成していたか、という手法の限界による部分が大きいと考えます。例えば、ある先行研究 では、バージョンごとのソースコードを収集し、その差分から破壊的変更が発生したバージョン (例えばpandasのv2.0で <code>df.append()</code> が削除された) を特定することで、<code>Q. pandas v2.0 では？ df = [WRITE_HERE]</code> といった問題を作るといった方法を取っています。また、他の研究 では、ライブラリのドキュメンテーションをデータソースとして取り扱っています。</p>
<p>しかしながら、このような手法こそが先に述べた2つの欠点をもたらす元凶となっています。</p>
<p>例えばソースコードの差分を比較する場合、その解析コストは「ライブラリ数×バージョン数」の速さで増大します。世の中に (Pythonに限定しても) 数十万と存在するライブラリに対して、そのような解析をすることは現実的ではなく、事実、先行研究でも対象は主要な300ライブラリに限定されています。</p>
<p>また、ドキュメンテーションを用いる方法では、そもそも世の中の多くのライブラリは十分なドキュメントが整備されていないという点にも留意が必要です。</p>
<p>さらに、個々の破壊的変更の情報から、多段階のエラー解決や複数ファイルの修正を含むリポジトリレベルの課題をボトムアップに作成することは困難であることから、タスクは必然的に局所的、シングルステップのいわば「一問一答」と呼べるものに限定されていました。</p>
<h3 id="TimeMachine-benchの提案">TimeMachine-benchの提案</h3><h4 id="コアアイデア">コアアイデア</h4><p>さて先行研究では、マイグレーションを「あるバージョンで動いていたものが、別のあるバージョンでは動かなくなった」ものを探すというように「バージョン」のカットで捉えていました。</p>
<p>しかし、これは少し視点を変えれば、それまで正しく動いていたものが「ある日を境に」動かなくなるという「時系列」の問題に読み替えることができます。つまり、過去のある日の (を再現した) 環境では正しく動作するが、今はもう動かない、といったものを、日付の指定のみで抽出できる、ということです。そうすれば、「どのライブラリの、どのバージョンが犯人か」を知らずとも、ライブラリごとの解析をすることなく、マイグレーションタスクを構築できるのではないか？というのが本研究のコアアイデアです。</p>
<p>では、どのように過去の環境を再現するのか？</p>
<p>ここに本ベンチマークが “TimeMachine-bench” たる所以があります。</p>
<p>まず、Pythonのパッケージマネージャである <code>pip</code> がどのように依存関係を解決するかを簡単に説明すると、<code>pip</code> は <code>pip install ...</code> でインストールのリクエストを受けると、Pythonの公式パッケージリポジトリである PyPI (The Python Package Index) にパッケージのメタデータをリクエストします。このメタデータには、当該ライブラリのバージョン情報と各バージョンが要求する依存ライブラリのバージョン情報などが含まれており、 <code>pip</code> は受け取ったメタデータを元に、バージョン指定子の条件 (<code>==</code>や<code>&gt;=</code>など) や他ライブラリとの整合性を判断して最終的にインストールするバージョンを確定します。</p>
<p>ここで、もしPyPIが例えば <strong>2025年7月までのリリース情報しか持っていない</strong> としたらどうなるでしょうか？この場合、<code>pip</code> は2025年7月までにリリースされていたライブラリのバージョンと、それらが依存するライブラリの、同じく2025年7月までのバージョン情報をもとに、最終的にインストールするバージョンを決定します。</p>
<p>つまり、所定のカットオフ日以降の情報をフィルタしたパッケージリポジトリを経由すれば、 <code>pip</code> の依存関係アルゴリズムや環境構築手順に一切のテコ入れをせずとも、<strong>あたかもその時点にいるかのように (タイムトラベルしたかのように)</strong> 過去の環境を再現できるわけです。</p>
<p>本研究ではこのアイデアの具現化に際して、pypi-timemachine という素晴らしいOSSを活用させていただきました。具体的には、環境構築の際 <code>PIP_INDEX_URL</code> (パッケージメタデータの問い合わせ先) を公式のPyPIサーバではなく、dockerで構築したローカル環境のタイムマシンサーバに向けることで、PyPIへのリクエストをプロキシし、過去の指定日における環境の (ほぼ*) 厳密な再現を実現しました。</p>
<img src="/images/2026/20260316a/methodology.png" alt="methodology.png" width="1200" height="330" loading="lazy">

<div class="note-container note-warn"><span class="note-icon"></span><div>

<p>「ほぼ」厳密の理由として、レアケースではありますが、PyPIから過去のバージョン情報が削除されるなどが考えられます。<br>例えば、2025年7月にv1.1がリリースされた場合、同時期に <code>pip install</code> したケースではバージョンを指定しない限り、(当時の) 最新版であるv1.1がインストールされますが、その後何らかの理由によりv1.1がPyPIから削除されると、カットオフを2025年7月としてもv1.0がインストールされるといったことが発生します。</p>
</div></div>

<h4 id="データセットの構築">データセットの構築</h4><p>先述のアイデアのもと、本研究では The Stack v2 から、ユニットテストが実装されているPythonリポジトリを選定のうえ「2つの異なる断面 (日付) でテストを実行し、テスト結果が Pass → Failとなるものを抽出する」 <strong>全自動のパイプライン</strong> を構築しました。<br>全自動であるというのは、すなわちデータセットの「継続的な更新が可能である」ということです。</p>
<p>評価データが学習データに混入することで評価の妥当性が失われる「データ汚染」が深刻な課題となる昨今、このような “ライブ” なパイプラインには大きな意味があります。</p>
<p>さらに、本研究では人手の検証により「所与の環境下で解けることを保証した」100件のサブセット (Verified) を構築しました。<br>「所与の環境下で解ける」ものに限定した背景として、もしLLM (エージェント) に環境へのテコ入れを許容すると、任意のマイグレーションタスクはダウングレードにより (テストを通すだけであれば) 解決できる、ということが挙げられます。<br>しかしながら、そのようなショートカットが、マイグレーション本来の目的に即していないことは火を見るより明らかです。<br>一方で、自動パイプラインにより抽出されたリポジトリの中には、ダウングレード以外での解決が本質的に困難なものも一定数含まれます。</p>
<p>例えば、当該リポジトリが依存するサードパーティライブラリの実装において、バグの修正、あるいは何らかの仕様変更により計算誤差が生じるようなケースです。今回は、モデルに安易なショートカットの選択肢を与えず、コードの修正によってマイグレーションに対応する能力を評価するため、Verifiedサブセットで評価することとしました。</p>
<p>なお、Verifiedサブセットの構築にあたっては、問題の解決に必要な最小限の修正 (Gold Edit)、および人が解決までに要した時間に応じた問題の難易度 (Easy: 〜15分, Medium: 〜1時間, Hard: 〜2時間) のアノテーションを行いました。</p>
<p>以下は実際の問題の例となります。</p>
<img src="/images/2026/20260316a/task_example.png" alt="task_example.png" width="1200" height="399" loading="lazy">

<p>この問題では <code>pandas</code> のアップデートに関連して複数のランタイムエラーが発生しますが、1つのエラーを解決することで初めてその背後に隠蔽されていた別の不具合が顕在化するという多段の構造になっており、マイグレーションを対象とした既存のベンチマークとの違いが見て取れます。<br>また、データセット中に含まれるエラー関連ライブラリは <code>numpy</code> や <code>flask</code> といったメジャーなものはもちろん、 <code>pysnmp</code> のように特定のドメインでのみ用いられるものなど多岐に渡っており、日付ベースの環境構築 (タイムマシン) の優れたスケーラビリティが確認できます。</p>
<img src="/images/2026/20260316a/library_count.png" alt="library_count.png" width="1200" height="763" loading="lazy">

<h3 id="現在の到達点">現在の到達点</h3><p>本研究では、最終的にタスクを解決できたか (<code>pass@1</code>) に加えて、人手のアノテーション (Gold Edit) と比較して無駄のない修正ができたか (<code>prec@1</code>) 、という2つの観点からモデルの性能を評価しました。<br>マイグレーションの本質は新環境への適応であり、コード品質の改善を目的とする「リファクタリング」とは本質的に役割が異なります。</p>
<p>両者を同時に行うことは変更の意図を不明瞭にし、レビューコストの増大や予期せぬバグの混入のリスクを増大させることから、「環境に適応するための最小限の変更」を特定する能力についても評価することとしました。</p>
<p>実験では、4つのプロプライエタリモデル、および7つのオープンモデルを評価しました。ファイルの探索や多段の問題解決を要する「リポジトリレベル」のマイグレーションタスクについては標準的なアプローチが確立されていないことから、今回はSWE-benchに対する解法の1つであるSWE-Agentを参考に、10種のツールからなるReActエージェントをベースラインとしました。</p>
<p>モデルは最初の入力として、環境における各ライブラリのバージョンと初期のエラーログを受け取り、10種のツールを駆使しながらエラーの解決を目指します。最大で100回のLLM呼び出し (≒100回のツール利用)、10回のテスト実行の制限を設定し、この制限内でどれだけタスクを解決できたかを評価しました。</p>
<p>以下がTimeMachine-bench-Verifiedにおける11モデルの評価結果です。<br>※ Easy, Medium, Hardは各難易度の正解数、および正解率 (括弧内)</p>
<div class="scroll"><table>
<thead>
<tr>
<th>モデル</th>
<th>pass@1 (%)</th>
<th>prec@1 (%)</th>
<th>Easy</th>
<th>Medium</th>
<th>Hard</th>
</tr>
</thead>
<tbody><tr>
<td>Claude Sonnet 4</td>
<td>99.0</td>
<td>78.0</td>
<td>64 (100.0)</td>
<td>30 (100.0)</td>
<td>5 (83.3)</td>
</tr>
<tr>
<td>Claude 3.5 Sonnet v2</td>
<td>91.0</td>
<td>66.8</td>
<td>61 (95.3)</td>
<td>25 (83.3)</td>
<td>5 (83.3)</td>
</tr>
<tr>
<td>GPT-5</td>
<td>91.0</td>
<td>54.2</td>
<td>62 (96.9)</td>
<td>27 (90.0)</td>
<td>2 (33.3)</td>
</tr>
<tr>
<td>GPT-4o</td>
<td>76.0</td>
<td>61.4</td>
<td>57 (89.1)</td>
<td>19 (63.3)</td>
<td>0 (0.0)</td>
</tr>
<tr>
<td>Qwen3-Coder-480B</td>
<td>90.0</td>
<td>70.1</td>
<td>62 (96.9)</td>
<td>26 (86.7)</td>
<td>2 (33.3)</td>
</tr>
<tr>
<td>Qwen3-235B</td>
<td>87.0</td>
<td>69.1</td>
<td>62 (96.9)</td>
<td>24 (80.0)</td>
<td>1 (16.7)</td>
</tr>
<tr>
<td>Qwen3-32B</td>
<td>53.0</td>
<td>44.1</td>
<td>40 (62.5)</td>
<td>13 (43.3)</td>
<td>0 (0.0)</td>
</tr>
<tr>
<td>Llama-4-Maverick</td>
<td>76.0</td>
<td>63.2</td>
<td>56 (87.5)</td>
<td>20 (66.7)</td>
<td>0 (0.0)</td>
</tr>
<tr>
<td>Llama-3.3</td>
<td>52.0</td>
<td>44.0</td>
<td>40 (62.5)</td>
<td>12 (40.0)</td>
<td>0 (0.0)</td>
</tr>
<tr>
<td>DeepSeek-V3.1</td>
<td>75.0</td>
<td>61.4</td>
<td>52 (81.3)</td>
<td>21 (70.0)</td>
<td>2 (33.3)</td>
</tr>
<tr>
<td>gpt-oss-120b (low)</td>
<td>55.0</td>
<td>33.8</td>
<td>36 (56.3)</td>
<td>19 (63.3)</td>
<td>0 (0.0)</td>
</tr>
</tbody></table></div>
<p>この表を見てまず目につくのは、Claude Sonnet 4の99.0%という高いタスク解決率でしょう。また、オープンモデルの躍進も注目に値します。特に、Qwen3-Coder-480Bは前世代のフラグシップモデルであるClaude 3.5 Sonnet v2やGPT-4oに匹敵、もしくはそれらを上回るスコアを記録しました。</p>
<p>従来ベンチマーク化されてこなかった「リポジトリレベル」のマイグレーションという (モデルにとって) 未知のタスクにおいて、これだけのスコアを達成したということは、モデルが単に既存のベンチマークを暗記しているのではなく、実用的なエンジニアリングタスクに対して一定の汎化性能を有することを示す結果であると考えられます。</p>
<p>しかし、手放しでは喜べない懸念点もいくつか残されています。</p>
<p>まず、無駄のない修正という観点では、最もスコアの高いClaude Sonnet 4でさえ、20%以上 (<code>prec@1</code> &#x3D; 78.0%) の、課題解決に寄与しない修正を行なっているという点が挙げられます。これは一部のモデルではより顕著であり、例えばGPT-5は91.0%と高いタスク解決率を達成する一方で、その修正の約45%は過剰な修正であったことが確認できます。</p>
<p>また、タスクの難易度に着目すると、唯一の例外であるgpt-oss-120bを除いては、難易度の上昇に伴いタスク解決率が低下する一貫した傾向が見られました。特にHardの問題ではClaude系列を除くモデルの解決率が50%未満に留まるなど、人間にとって難しい問題は多くのLLMにとっても依然難しいということが示されました。</p>
<h3 id="マイグレーションは解決済みなのか？">マイグレーションは解決済みなのか？</h3><p>先に述べたような課題こそあれ、99%という高いスコアを見れば当然このような疑問が浮かぶでしょう。</p>
<p>しかしながら、我々は、この課題はまだ「解決済みとはほど遠い」と考えています。</p>
<p>その理由として、まずひとつにVerifiedサブセットの構築方法に起因する選択バイアスが挙げられます。人手での検証は安易なショートカットの除外というポジティブな側面 (信頼性) と引き換えに、人間が (妥当な時間で) 解ける程度の難易度に限定してしまうという欠点も持ち合わせています。すなわち、実世界の問題はHardや、2時間よりもずっと長くかかるが不可能ではないようなUltra-Hardの問題をより多く含むということです。</p>
<p>また、今回はダウングレードを禁じ手としましたが、真に有用なエージェントは、然るべき状況では (ダウングレードが唯一の正解であるような状況では)、選択的にダウングレードするといった判断も行いながら問題を解決することが期待されます。<br>そのため、この結果はマイグレーションタスクが99%解決されたことを保証するものではなく、「人間が短時間で対処可能な」課題に対する一定の自動化の可能性を示すものと解釈するのが妥当だと考えています。</p>
<div class="note-container note-info"><span class="note-icon"></span><div>

<p>これは余談となりますが、本データセットの人手検証は約1ヶ月間、私が普段より少し早起きをしてコツコツ行いました。検証は合計で70時間以上かかっており、その大半を短時間で解いてしまうLLMのコストパフォーマンスの良さも実感したところです…</p>
</div></div>

<p>また、個々の事例を分析すると99%という数字の裏に隠れたトリックも見えてきます。</p>
<p>以下の問題では <code>pysnmp.hlapi</code> パッケージに定義されていた定数が、他の場所に移動したことに伴って発生するimportエラーを解決することが期待されます。ここで、Claude Sonnet 4はいくつか候補として考えられるパスを試したのち、それらがいずれも不正解であることがわかると、最終的には図のようにtry-exceptブロックのネストとダミー変数の定義によりエラーをバイパスするという手段を選択しました。</p>
<p>この例は、モデルとデータ、双方に残る信頼性の課題を浮き彫りにするものです。</p>
<p>まず、モデルの側面として、このように「意味的な正しさよりもテストの通過を優先する」選択をすることはpass rateへの過度な最適化の弊害と考えられます。無理にハックしてでも進むのではなく、自身の限界を正しく認識し「ここでは立ち止まる (あるいは人間に助けを求める) べきだ」という判断を下すことのできる高度なメタ認知能力の獲得は、今後のLLM開発における大きな課題であると考えられます。データの側面としては、このようなハックを見抜けないテストケースの危うさが挙げられます。</p>
<p>今回のケースではインポートされた定数がどのように使われるか、といった挙動をチェックするテストケースが定義されておらず、それゆえ、このような回答が「見かけ上は」正しいと判断されてしまいました。</p>
<p>これは、本研究で構築したデータセットが、GitHubリポジトリに紐づく既存のテストケースに依存していること、および (人間が書いた) それらのテストケースが往々にして不足していることに起因します。ユニットテスト自動生成 (UTG) のような技術を統合することで、より頑健、かつチャレンジングなベンチマークの構築を目指すことは、今後の有力な方向性のひとつだと考えています。</p>
<img src="/images/2026/20260316a/case_study.png" alt="case_study.png" width="1200" height="1354" loading="lazy">

<h3 id="後日談">後日談</h3><p>今回の話は、SWE-benchの下に名前を載せるという意気込みで取り組みました。</p>
<p>その意味では、手法のピースがはまり、初めてモデルに解かせた際「あまりにも解けてしまった」ことには、モデルの進化に対する驚きとともに、なんとも言えない悔しさが入り交じる複雑な心境を抱かずにはいられませんでした。</p>
<p>先に述べたようなテストの穴を塞ぐ、大規模な人手検証を通して難易度の高い (人間にとって時間のかかる) 問題のみを集める、といった方法でこのタスク成功率は70%, いや50%にもできたかもしれません。</p>
<p>しかし、たとえこのデータセットの寿命は出た瞬間に尽きていたとしても、この方法論を早く世に出すことにこそ意味があると考え、このように公開するに至りました。</p>
<p>果たして近い世の中、コンテナ開発のように、コードも「壊れたら使い捨て」「メンテナンスよりもスクラッチで作り直し」という時代になるのかもしれません。</p>
<p>しかし、実際のプロジェクトでは (望ましくないことではありますが) 検討段階で漏れていた仕様がコードのみに反映されているといった不一致や、そもそも「コードこそが仕様書」であることも少なくありません。<br>仕様とコードの自由な往来が達成されるまでの間においては、人間はこの厄介な業務と付き合っていくことになるでしょう。</p>
<p>本研究が、マイグレーション、バージョンや時系列を扱うCode LLMs研究の道標となり、より実用的で信頼できるLLMの実現に向けた議論を加速させる一助となれば、著者としてこれほど嬉しいことはありません。</p>
<h2 id="おわりに">おわりに</h2><p>今回は、NLP2026にて若手奨励賞を受賞した自著論文 “TimeMachine-bench” について、裏話も含めてじっくりと解説させていただきました。</p>
<p>改めまして、論文の審査を担当いただきました皆様に、この場をお借りして感謝申し上げます。</p>
<p>この記事を読んで興味を持っていただけましたら、ぜひオリジナルの方もご一読いただけますと幸甚です。引き続き、本分野における研究の発展とその社会還元に貢献していきたいと思います。</p>
<p>ここまでお読みいただきありがとうございました！</p>
<p>フューチャーではともに働くメンバーを募集しています。</p>
<p>ご興味を持っていただいた方は、ぜひ キャリア採用サイト からのご応募をお待ちしております。</p>
]]></content>
    <summary type="html">この度、3/9 が若手奨励賞に選出されました。論文の審査を担当いただきました関係者の皆様にこの場をお借りして感謝いたします。</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="NLP" scheme="https://future-architect.github.io/tags/NLP/"/>
    <category term="論文紹介" scheme="https://future-architect.github.io/tags/%E8%AB%96%E6%96%87%E7%B4%B9%E4%BB%8B/"/>
  </entry>
  <entry>
    <title>データ分析を『ただの数字』で終わらせない。現場で痛感した、精度を支える4つの必須ステップ</title>
    <link href="https://future-architect.github.io/articles/20260206a/"/>
    <id>https://future-architect.github.io/articles/20260206a/</id>
    <published>2026-02-05T15:00:00.000Z</published>
    <updated>2026-02-05T15:00:00.000Z</updated>
    <author><name>高橋佑弥</name></author>
    <content type="html"><![CDATA[<img fetchpriority="high" src="/images/2026/20260206a/carlos-muza-hpjSkU2UYSU-unsplash.jpg" alt="" width="1200" height="855">

<h2 id="はじめに">はじめに</h2><p>はじめまして。2023年4月に新卒入社し、流通サービス事業部に所属している高橋です。</p>
<p>これまで主にシステム構築フェーズを経験してきましたが、直近ではデータ分析プロジェクトに分析メンバーとして携わりました。</p>
<p>本記事では、データ分析のプロジェクトを進める中で「実務上どのようなポイントで悩みやすいのか」「分析をスムーズに進めるために何に気を配るべきか」といった視点で、自分なりの学びをまとめました。</p>
<h2 id="本プロジェクトにおけるデータ分析の位置付け">本プロジェクトにおけるデータ分析の位置付け</h2><p>データ分析において最も重要なことは、単に「分析すること」ではなく、「解決すべき課題に対して、どの領域で、どのような分析をするか」という事前の設計にあります。</p>
<p>今回の取り組みは、ある領域で実績のあるシステムを異なるビジネスドメインへ適応させ、オペレーションの効率化を目指すものでした。この最適化を実現するためには、前述した「設計」の精度が成否を分ける鍵となります。</p>
<p>そのため、本プロジェクトは大きく分けて次の2つの要素で構成されていました。</p>
<ol>
<li>既存ロジックの新領域における適応可能性の検証</li>
<li>検証の効果を正しく評価するための「分析対象」の選定</li>
</ol>
<p>特に「2」については、単に手元のデータを処理するのではなく、「ビジネスインパクトがどこにあるのか」「どのデータを抽出して評価すべきか」をゼロから検討する必要があり、<strong>データ分析を通じた意思決定</strong>が強く求められるパートでした。</p>
<h3 id="なぜ「分析対象の選定」が重要だったのか">なぜ「分析対象の選定」が重要だったのか</h3><p>結論から述べると、拠点によって状況が正反対であり、全てのデータをひとまとめに集計すると本来解決すべき 「歪み」が平均化されて見えなくなってしまうからです。</p>
<p>本プロジェクトの背景には、複数の拠点を展開するビジネスモデル特有の「<strong>需要と供給のミスマッチ</strong>」という課題がありました。</p>
<ul>
<li>高需要拠点：商品の売れ行きは好調な一方、在庫不足による機会損失が発生している</li>
<li>低需要拠点：商品があまり売れず、余剰在庫がコストを圧迫している</li>
</ul>
<p>仮に、これら「不足」と「余剰」のデータを一括りで分析してしまうと、数値上は過不足が相殺され、あたかも「ちょうど良い状態」であるかのような結果が出てしまいます。</p>
<p>こうした不均衡を解消し、実効性の高い改善を実現するためには、全方位を漠然と分析するのではなく、「<strong>どこを分析対象として定義し、どのデータで課題を可視化すべきか</strong>」という設計が、プロジェクトの成否を分けるポイントとなりました。</p>
<h2 id="「検証対象」定義の難しさと学び">「検証対象」定義の難しさと学び</h2><p>本プロジェクトにおいて、対象となる店舗や商品群の大枠は早い段階で決まっていました。</p>
<p>しかし、実務レベルで「検証の切り口をどう定義するか」という点には、想像以上に丁寧な検討が必要でした。単に「どこを分析するか」だけでなく、どのデータを用い、どの条件で切り出すのが検証として最も意味があるのか。この「切り出し方」の定義をいかに精密に行うかが、今回の大きな学びとなりました。</p>
<p>試行錯誤の中で見えてきた、検証対象の定義や分析において欠かせない視点を、4つのポイントで詳しくお伝えします。</p>
<h3 id="1-データ構造の早期合意">1. データ構造の早期合意</h3><p>初期の検証段階ではスピードが重視されますが、使用するデータの定義や粒度の合意を後回しにすることはリスクが伴います。</p>
<p>「このデータを使う前提で進めて良いか」という認識合わせが不十分だと、後続の工程で大きな修正コストが発生してしまいます。</p>
<p>本格的なデータ分析に着手する段階で、<strong>どのデータをどの粒度で使うかをクイックに合意しておくこと</strong>の大切さを痛感しました。</p>
<h3 id="2-データ分析におけるターゲットの定義と対象範囲の設定">2. データ分析におけるターゲットの定義と対象範囲の設定</h3><p>限られた期間で成果を検証するためには、膨大なデータの中から「どこを対象とするか」を戦略的に決める必要があります。</p>
<p>今回は、漠然と課題を探すのではなく、規模感や変動率などのデータに基づき、ビジネスへの影響が最も大きい領域を分析によって特定しました。</p>
<p>実効性を証明するため、以下の2軸で対象を絞り込んでいます。</p>
<ul>
<li>高インパクト領域の特定<ul>
<li>全体の成果への貢献度が高く、改善が直接的な利益向上につながりやすい領域を抽出</li>
</ul>
</li>
<li>検証の妥当性の確保<ul>
<li>十分なデータ量が確保でき、分析結果の有効性を正しく評価できるセグメントを定義</li>
</ul>
</li>
</ul>
<p>このように、分析を通じて「どの範囲で検証するのが最も効果的か」という合意形成の根拠を作ることが、プロジェクト初期における極めて重要なステップであると学びました。</p>
<h3 id="3-分析意図の明確化">3. 分析意図の明確化</h3><p>分析を進める際、複数の条件を組み合わせてデータを段階的に絞り込んでいく作業が発生しました。</p>
<p>ここで重要だったのは、単なる計算作業として進めるのではなく、「なぜこの条件で絞り込むのか」という分析意図を正しく理解することでした。</p>
<p>実務において特に意識すべきだと感じたのは、以下の2点です。</p>
<ul>
<li>データの「業務的な意味」を定義する<ul>
<li>「この条件で抽出されたデータは、実務上のどのような状況を表現しているのか」という背景を常に意識する</li>
</ul>
</li>
<li>判断軸を明確化する<ul>
<li>単に数字を示すのではなく、「どの数値を用いて意思決定を行うか」を、関係者と合意しながら進める</li>
</ul>
</li>
</ul>
<p>「何のために算出しているのか」という意図が抜けると、アウトプットは「ただの結果報告」に終わってしまいます。</p>
<p>分析工程の全ステップにおいて、<strong>ビジネス的な意味付けを徹底すること</strong>が、精度の高い検証には不可欠だと実感しました。</p>
<h3 id="4-分析結果は「計算結果」ではなく「意図」を出力">4. 分析結果は「計算結果」ではなく「意図」を出力</h3><p>分析結果として出力する成果物は、単なる数値の羅列では不十分です。</p>
<p>「何のための数値か」「どの条件で絞られたものか」がひと目で伝わらなければ、意思決定の判断材料にはなりません。</p>
<p>例えば、特定の対象を抽出する場合、以下のように<strong>「数値が絞り込まれていくプロセス」</strong>をセットで提示することが重要です。</p>
<h4 id="具体例：新商品プロモーションの対象選定">具体例：新商品プロモーションの対象選定</h4><p>単に「対象は150件です」と報告するのではなく、絞り込みのステップに「意図」を添えて出力します。</p>
<div class="scroll"><table>
<thead>
<tr>
<th align="left">項目（具体的な集計内容）</th>
<th align="center">数値（件数）</th>
<th align="left">定義・分析の意図（抽象的な背景）</th>
</tr>
</thead>
<tbody><tr>
<td align="left">取扱全商品</td>
<td align="center">1,000</td>
<td align="left"><strong>【全体像の把握】</strong><br> 分析対象の最大範囲を定義し、規模感を合意する。</td>
</tr>
<tr>
<td align="left">供給安定商品<br>（機会損失未発生）</td>
<td align="center">800</td>
<td align="left"><strong>【ノイズの除去】</strong><br> 欠品や入荷不安定なデータを除外し、施策効果を正しく測定できる母集団を作る。</td>
</tr>
<tr>
<td align="left">新規取り扱い商品</td>
<td align="center">150</td>
<td align="left"><strong>【戦略的抽出】</strong><br> 分析の主目的である「新規品」へフォーカスし、意思決定の直接の対象を特定する。</td>
</tr>
</tbody></table></div>
<p>このように、数値の関係性が <strong>① ＞ ② ＞ ③</strong> となるプロセスを明示することで、読み手は「なぜこの150件なのか」という根拠を即座に理解できます。</p>
<h4 id="「プロセス」が信頼を生む">「プロセス」が信頼を生む</h4><p>単に「結果は150件です」とだけ伝えるのと、「1,000件の全体像からノイズを除き、戦略対象である150件に絞り込みました」と伝えるのとでは、情報の信頼性が全く異なります。</p>
<p>「分析資料は単なる計算結果の提示ではなく、意図を表現するための成果物である」という意識を持つことは、読み手の疑問を先回りして解消し、スムーズな意思決定を促す鍵になると実感しました。</p>
<h2 id="さいごに">さいごに</h2><p>今回のプロジェクトでは…</p>
<ul>
<li>検証対象をどう定義するか</li>
<li>どのデータを活用し、何を判断の軸にするか</li>
</ul>
<p>…といった、<strong>分析以前の設計部分</strong>に多くの学びがありました。</p>
<p>データ分析というと手法やロジックに注目が集まりがちですが、実務ではむしろ…</p>
<ul>
<li>データ構造の合意</li>
<li>インプットデータの整理</li>
<li>分析意図の共有</li>
</ul>
<p>…といった「土台」となる部分が、プロジェクトの成否を左右することを強く感じました。</p>
<p>本記事が、データ分析に携わる方の参考になれば幸いです。</p>
<h2 id="参考">参考</h2><p>詳細なデータ分析手法や実装面については、下記に記載されておりますので、あわせてご覧ください。</p>
<ul>
<li>データ分析でプロジェクトをリードした話</li>
<li>システム開発からデータ分析へ。やってみて気づいた技術選定と実装のポイント</li>
</ul>
]]></content>
    <summary type="html">データ分析のプロジェクトを進める中で 「実務上、どのようなポイントで悩みやすいのか」「分析をスムーズに進めるために、何に気を配るべきか」といった視点で、自分なりの学びをまとめました。</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="Excel" scheme="https://future-architect.github.io/tags/Excel/"/>
    <category term="データ分析" scheme="https://future-architect.github.io/tags/%E3%83%87%E3%83%BC%E3%82%BF%E5%88%86%E6%9E%90/"/>
    <category term="初心者向け" scheme="https://future-architect.github.io/tags/%E5%88%9D%E5%BF%83%E8%80%85%E5%90%91%E3%81%91/"/>
  </entry>
  <entry>
    <title>システム開発からデータ分析へ。やってみて気づいた技術選定と実装のポイント</title>
    <link href="https://future-architect.github.io/articles/20251211a/"/>
    <id>https://future-architect.github.io/articles/20251211a/</id>
    <published>2025-12-10T15:00:00.000Z</published>
    <updated>2025-12-10T15:00:00.000Z</updated>
    <author><name>篠原智</name></author>
    <content type="html"><![CDATA[<h2 id="はじめに">はじめに</h2><p>はじめまして。2023年10月にキャリア入社した篠原です。</p>
<p>これまではシステム開発がメインでしたが、最近データ分析の業務に関わらせていただく機会がありました。そこで求められる成果物、注力すべきポイント、そして技術選定の観点など、従来のシステム開発とは異なる部分が多く、様々な気づきがありました。</p>
<p>自身の振り返りも兼ねて、その知見を共有したいと思います。</p>
<p>なお、データ分析の目的と流れについてはこちらの過去記事も併せてご覧ください。</p>
<h3 id="データ分析で求められるものと意識すること">データ分析で求められるものと意識すること</h3><p>会社や組織が意思決定を行う上で様々な手法がありますが、データを用いた定量的分析は重要な判断材料となります。</p>
<ul>
<li>「どこに施策を打つのが効果的だろうか」</li>
<li>「施策を打った結果、どのような効果があったのか。その結果を元に今後の動きを考えたい」</li>
</ul>
<p>こうした問いがある際、「正確さ」はもちろんですが、次のアクションへ繋げるために「スピード」も重要になる場面が多いです。これらの問いに正確かつスピーディーに答え、提案するには、分析そのものに全力を注ぐべきであり、ツール選定や環境構築、分析の実装における「不安定な要素」は極力取り除くべきです。</p>
<p>実際にデータ分析を通して、これらの不安要素を取り除くために気をつけるべき点をお話しします。</p>
<p><strong>検証環境</strong>:</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">OS: Ubuntu 22.04.5 LTS (WSL使用)</span><br><span class="line">CPU: i7-1255U</span><br><span class="line">RAM: 16GB</span><br><span class="line">Python: 3.10</span><br><span class="line">pandas: 2.0.2</span><br><span class="line">PostgreSQL: 17.4</span><br></pre></td></tr></table></figure>

<h3 id="分析で使用するツール（言語）の特徴を理解して使い分ける">分析で使用するツール（言語）の特徴を理解して使い分ける</h3><p>データ分析に使用される技術としては Python (pandas)、R、RDB (PostgreSQL、SQL) などが挙げられます。</p>
<p>これらは「分析ができる」という点は共通していますが、得意分野が異なるため、状況に応じて使い分けることが重要だと感じました。代表として Python と RDBの特徴を比較します。</p>
<div class="scroll"><table>
<thead>
<tr>
<th align="left">観点</th>
<th align="left">Python</th>
<th align="left">RDB</th>
</tr>
</thead>
<tbody><tr>
<td align="left">構築の手軽さ</td>
<td align="left">非常に手軽。Python導入済みなら <code>pip install</code> のみ。</td>
<td align="left">RDB自体のインストールとデータ投入（DDL&#x2F;DML）に手間がかかる。</td>
</tr>
<tr>
<td align="left">分析の手軽さ</td>
<td align="left">Notebookを使用することで、読み取ったデータを逐次実行しながら試行錯誤が可能。</td>
<td align="left">基本的に1つのSQLで処理を書き切る必要があるため、試行錯誤のサイクルは少し重い。</td>
</tr>
<tr>
<td align="left">大規模データの分析　※</td>
<td align="left">メモリに全データを載せるため、大規模データではメモリ不足に陥りやすい。</td>
<td align="left">ディスクベースで処理し、必要分をメモリに載せるため、メモリ不足に陥りにくい。</td>
</tr>
<tr>
<td align="left">計算速度</td>
<td align="left">高速（ただし書き方に依存）。</td>
<td align="left">Indexを活用できれば非常に高速。</td>
</tr>
<tr>
<td align="left">使用難度</td>
<td align="left">低。CSV等をDataFrame化し、都度加工が可能。</td>
<td align="left">中。複雑な集計を1SQLで完結させる必要があり、クエリが複雑になりがち。</td>
</tr>
<tr>
<td align="left">データ型の管理</td>
<td align="left">推定で判断されるため、意図しない型変換による結合エラー等が起きうる。</td>
<td align="left">テーブル定義で型が厳密に管理されているため、堅牢。</td>
</tr>
<tr>
<td align="left">他ツールへの連携</td>
<td align="left">DataFrameをそのまま機械学習や可視化ライブラリへ連携可能。</td>
<td align="left">別途考慮が必要。</td>
</tr>
</tbody></table></div>
<p>※なお、PythonでTB級などのさらに大規模なデータを扱う場合は、DaskやPySparkといった分散処理ライブラリの利用が選択肢に入ります。今回はローカル環境（メモリ16GB程度）で完結する規模の分析を前提としていることと、DaskやPySparkにもある一定のキャッチアップが必要ということも考慮し、既にメンバーの経験があるpandasを使用しています。</p>
<p>以上の特徴を踏まえて、pandas と RDB は下記のように使い分けると分析がスムーズでした。</p>
<ul>
<li><strong>RDB を使用すべき場面</strong><ul>
<li>分析対象や期間が定まっておらず、大容量データに対して探索的に分析する場面</li>
<li>詳細な分析の前に、大規模なマスタやトランザクションデータを結合し、中間データを準備する場面</li>
</ul>
</li>
<li><strong>pandas を使用すべき場面</strong><ul>
<li>データの準備が整ってからの、詳細な加工や分析が必要な場面。</li>
<li>データ規模が小さく、複雑な結合が不要な場面。</li>
<li>可視化や機械学習へのパイプラインとして使用する場面。</li>
</ul>
</li>
</ul>
<p>データ型については、pandasでCSVを読み取る場合も、dtypeで型を指定できますが、多くのカラムに対しての指定する場合、小規模の分析の場合でもコード数が増えやすいです。</p>
<figure class="highlight py"><table><tr><td class="code"><pre><span class="line">m_product_df = pd.read_csv(</span><br><span class="line">    <span class="string">&quot;data/m_products.csv&quot;</span>,</span><br><span class="line">    dtype= &#123;<span class="string">&quot;product_id&quot;</span> : <span class="built_in">str</span>&#125;</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">t_sales_df = pd.read_csv(</span><br><span class="line">    <span class="string">&quot;data/t_sales.csv&quot;</span>,</span><br><span class="line">    dtype=&#123;</span><br><span class="line">        <span class="string">&quot;product_id&quot;</span>: <span class="built_in">str</span>,</span><br><span class="line">        <span class="string">&quot;quantity&quot;</span> : <span class="built_in">int</span>,</span><br><span class="line">    &#125;,</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">merge_df = pd.merge(</span><br><span class="line">    t_sales_df,</span><br><span class="line">    m_product_df,</span><br><span class="line">    how=<span class="string">&quot;left&quot;</span>,</span><br><span class="line">    on=<span class="string">&quot;product_id&quot;</span>,</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">merge_df</span><br></pre></td></tr></table></figure>

<p>そのため、型定義が重要かつ、複雑な局面はなるべくRDBで実装をする方が、考慮すべき点も少ないと感じました。</p>
<p>当初は「早く結果を出したいので、慣れている pandas を使おう」という判断で進めていましたが、大規模データの分析では考慮すべき点が増え、かえって時間がかかってしまうことがありました。</p>
<p>また、小規模な分析であれば Excel の方が直観的に操作でき、可視化まで完結する場合もあります。分析を始める前に、チーム内で適切な技術やツールを検討することをお勧めします。</p>
<h3 id="これまでの分析の流れを図示しておく">これまでの分析の流れを図示しておく</h3><p>分析業務では詳細な設計書を作成する時間は確保しにくいですが、データの流れを図示してチーム内で共有することをお勧めします。</p>
<p>データ分析では、分析した結果を基に話し合いそれを受けてさらに詳細な分析や、別角度からの分析を重ね最終的な結論を出すというパターンが多いと思います。</p>
<p>ER図としては複雑ではなくとも、仕様変更や追加の要望が来る頻度は高く、それが重なってくると今までの経緯が抜け落ちやすくなり、「この値は何のために出すんだっけ？」と目的がわからなくなってしまうこともあります。</p>
<p>それを防ぐためにも簡易的な図示でも良いので、これまでの分析の経緯と決定事項、PGのデータの流れを記載しておくことは非常に有効と考えます。図の体裁の善し悪しは重要でなく、メンバー全員が1つの図を指しながら、今までの決定事項と立ち位置を理解して次のアクションを考えることが重要です。</p>
<h3 id="処理速度に固執しすぎず、一般的に速くなる技法を持っておく">処理速度に固執しすぎず、一般的に速くなる技法を持っておく</h3><p>分析コードやクエリの実装において、パフォーマンスは重要です。システム開発同様、処理が遅すぎると業務に影響が出ます。</p>
<p>しかし、データ分析のコードは「毎日頻繁に実行される」とは限らず、「1回きりの実行」になることも多々あります。</p>
<p>パフォーマンスチューニングは突き詰めるとキリがありません。全ての処理を限界まで高速化しようとすると膨大な工数がかかってしまいます。そのため、「これをやっておけば間違いなく速くなる」という定石テクニックの適用にとどめ、特に1回きりの分析であればそれ以上の深追いはしないという割り切りが重要です。</p>
<p>その技法を一通り実装し、それでも許容できないほど遅ければ初めて追加のチューニングを検討する。このスタンスが、工数とパフォーマンスのバランスとして最適解だと感じました。</p>
<p>内容はpandasに寄っていますが、その技法を一部ご紹介させていただきます。</p>
<h4 id="1-取得するカラムは必要なもののみに絞る">1. 取得するカラムは必要なもののみに絞る</h4><p>取得するカラムを絞ることの必要性は、SQLだけではなく、pandas でも同様です。</p>
<p>pandas は読み取ったデータをメモリ上に展開し、処理の過程で新たな変数を生成します。そのためメモリが枯渇しやすい傾向にあります。速度面だけでなく、メモリ使用量の観点からもカラムの絞り込みは意識すべきです。</p>
<p>例えば、5000万レコード・20カラムのデータを全件読み込むと、以下のようにメモリ不足でプログラムは落ちることがあります。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> psutil</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"><span class="keyword">import</span> pandas <span class="keyword">as</span> pd</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">measure_time</span>(<span class="params">func</span>):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;関数実行完了までに要した時間を出力&quot;&quot;&quot;</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">wrapper</span>(<span class="params">*args, **kwargs</span>):</span><br><span class="line">        start = time.time()</span><br><span class="line">        result = func(*args, **kwargs)</span><br><span class="line">        elapsed = time.time() - start</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;  Result Time: <span class="subst">&#123;elapsed:<span class="number">.4</span>f&#125;</span> sec&quot;</span>)</span><br><span class="line">        <span class="keyword">return</span> result</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> wrapper</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">print_memory_status</span>(<span class="params">label=<span class="string">&quot;&quot;</span></span>):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;メモリ状況を出力&quot;&quot;&quot;</span></span><br><span class="line">    mem = psutil.virtual_memory()</span><br><span class="line"></span><br><span class="line">    <span class="comment"># byteをGBに変換</span></span><br><span class="line">    total_gb = mem.total / (<span class="number">1024</span>**<span class="number">3</span>)</span><br><span class="line">    available_gb = mem.available / (<span class="number">1024</span>**<span class="number">3</span>)</span><br><span class="line">    used_gb = total_gb - available_gb</span><br><span class="line">    percent = mem.percent</span><br><span class="line"></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;[<span class="subst">&#123;label&#125;</span>] RAM Status:&quot;</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;  Total:     <span class="subst">&#123;total_gb:<span class="number">.2</span>f&#125;</span> GB&quot;</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;  Used:      <span class="subst">&#123;used_gb:<span class="number">.2</span>f&#125;</span> GB (<span class="subst">&#123;percent&#125;</span>%)&quot;</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;  Available: <span class="subst">&#123;available_gb:<span class="number">.2</span>f&#125;</span> GB&quot;</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">@measure_time</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">read_big_data</span>():</span><br><span class="line">    <span class="string">&quot;&quot;&quot;巨大データの読み取り&quot;&quot;&quot;</span></span><br><span class="line">    print_memory_status(label=<span class="string">&quot;BEFORE LOAD&quot;</span>)</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="comment"># 全カラム読み込み</span></span><br><span class="line">        df = pd.read_csv(<span class="string">&quot;data/t_sales.csv&quot;</span>)</span><br><span class="line">        print_memory_status(label=<span class="string">&quot;AFTER LOAD&quot;</span>)</span><br><span class="line">    <span class="keyword">except</span> MemoryError:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;メモリ枯渇&quot;</span>)</span><br><span class="line">        print_memory_status(label=<span class="string">&quot;ON CRASH&quot;</span>)</span><br><span class="line">    <span class="keyword">except</span> Exception <span class="keyword">as</span> e:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;Crashed: <span class="subst">&#123;e&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 実行</span></span><br><span class="line">read_big_data()</span><br><span class="line"><span class="comment"># -&gt; メモリ枯渇でクラッシュ</span></span><br></pre></td></tr></table></figure>

<p><code>usecols</code> を使用して必要なカラムのみ読み込むことで、メモリを節約できます。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 時間やメモリ計測の関数やラッパーは省略</span></span><br><span class="line"><span class="meta">@measure_time</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">read_big_data</span>():</span><br><span class="line">    print_memory_status(label=<span class="string">&quot;BEFORE LOAD&quot;</span>)</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        df = pd.read_csv(</span><br><span class="line">            <span class="string">&quot;data/t_sales.csv&quot;</span>,</span><br><span class="line">            usecols=[<span class="string">&quot;user_id&quot;</span>, <span class="string">&quot;product_id&quot;</span>, <span class="string">&quot;quantity&quot;</span>, <span class="string">&quot;sale_date&quot;</span>],</span><br><span class="line">        )</span><br><span class="line">        print_memory_status(label=<span class="string">&quot;AFTER LOAD&quot;</span>)</span><br><span class="line">    <span class="keyword">except</span> Exception <span class="keyword">as</span> e:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;Crashed: <span class="subst">&#123;e&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">read_big_data()</span><br></pre></td></tr></table></figure>

<p><strong>出力結果（例）</strong>:</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">[BEFORE LOAD] RAM Status:</span><br><span class="line">  Total:     11.68 GB</span><br><span class="line">  Used:       7.68 GB (65.8%)</span><br><span class="line">  Available:  4.00 GB</span><br><span class="line">[AFTER LOAD] RAM Status:</span><br><span class="line">  Total:     11.68 GB</span><br><span class="line">  Used:       9.52 GB (81.5%)</span><br><span class="line">  Available:  2.16 GB</span><br><span class="line">  Result Time: 31.3573 sec</span><br></pre></td></tr></table></figure>

<h4 id="2-ループ処理は避け、集約関数を活用する">2. ループ処理は避け、集約関数を活用する</h4><p>pandas において、<code>for</code> ループによる行ごとの処理は非常に低速です。</p>
<p>以下は、10万レコードのデータに対して <code>product_id</code> ごとの集計する比較です。</p>
<p>【for文を用いて行う場合】 実行時間: <strong>約91.37秒</strong></p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment"># merge_df: 結合済みの元データ</span></span><br><span class="line"></span><br><span class="line">result_df = merge_df[</span><br><span class="line">    [</span><br><span class="line">        <span class="string">&quot;product_id&quot;</span>,</span><br><span class="line">        <span class="string">&quot;product_name&quot;</span>,</span><br><span class="line">        <span class="string">&quot;category&quot;</span>,</span><br><span class="line">    ]</span><br><span class="line">].drop_duplicates()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">start = time.time()</span><br><span class="line"><span class="keyword">for</span> index, row <span class="keyword">in</span> result_df.iterrows():</span><br><span class="line">    <span class="comment"># 現在実施中のproduct_idのレコードを出力する</span></span><br><span class="line">    product_id = row[<span class="string">&quot;product_id&quot;</span>]</span><br><span class="line">    target_df = merge_df[merge_df[<span class="string">&quot;product_id&quot;</span>] == product_id]</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 売上合計を算出</span></span><br><span class="line">    result_df.loc[</span><br><span class="line">        result_df[<span class="string">&quot;product_id&quot;</span>] == product_id,</span><br><span class="line">        <span class="string">&quot;total_quantity&quot;</span>,</span><br><span class="line">    ] = target_df[<span class="string">&quot;quantity&quot;</span>].<span class="built_in">sum</span>()</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 売上回数を算出</span></span><br><span class="line">    result_df.loc[</span><br><span class="line">        result_df[<span class="string">&quot;product_id&quot;</span>] == product_id,</span><br><span class="line">        <span class="string">&quot;sale_count&quot;</span>,</span><br><span class="line">    ] = <span class="built_in">len</span>(target_df)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># ギフト注文の回数を算出</span></span><br><span class="line">    gift_count = <span class="built_in">len</span>(target_df[target_df[<span class="string">&quot;is_gift&quot;</span>] == <span class="string">&quot;t&quot;</span>])</span><br><span class="line">    result_df.loc[</span><br><span class="line">        result_df[<span class="string">&quot;product_id&quot;</span>] == product_id,</span><br><span class="line">        <span class="string">&quot;gift_count&quot;</span>,</span><br><span class="line">    ] = gift_count</span><br><span class="line"></span><br><span class="line">elapsed = time.time() - start</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;  Result Time: <span class="subst">&#123;elapsed:<span class="number">.4</span>f&#125;</span> sec&quot;</span>)</span><br><span class="line"></span><br><span class="line">result_df</span><br></pre></td></tr></table></figure>

<p>【集約関数 (<code>groupby</code>) と <code>merge</code> を用いて行う場合】 実行時間: <strong>約0.06秒</strong></p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line">result_df = merge_df[</span><br><span class="line">    [</span><br><span class="line">        <span class="string">&quot;product_id&quot;</span>,</span><br><span class="line">        <span class="string">&quot;product_name&quot;</span>,</span><br><span class="line">        <span class="string">&quot;category&quot;</span>,</span><br><span class="line">    ]</span><br><span class="line">].drop_duplicates()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">start = time.time()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 売上合計を算出</span></span><br><span class="line">quantity_df = merge_df.groupby([<span class="string">&quot;product_id&quot;</span>])[<span class="string">&quot;quantity&quot;</span>].<span class="built_in">sum</span>().reset_index()</span><br><span class="line">result_df = pd.merge(</span><br><span class="line">    result_df,</span><br><span class="line">    quantity_df,</span><br><span class="line">    on=<span class="string">&quot;product_id&quot;</span>,</span><br><span class="line">    how=<span class="string">&quot;left&quot;</span>,</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 売上回数を算出</span></span><br><span class="line">count_df = merge_df.groupby([<span class="string">&quot;product_id&quot;</span>]).size().reset_index(name=<span class="string">&quot;sale_count&quot;</span>)</span><br><span class="line"></span><br><span class="line">result_df = pd.merge(</span><br><span class="line">    result_df,</span><br><span class="line">    count_df,</span><br><span class="line">    on=<span class="string">&quot;product_id&quot;</span>,</span><br><span class="line">    how=<span class="string">&quot;left&quot;</span>,</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># ギフト注文の回数を算出</span></span><br><span class="line">gift_count_df = (</span><br><span class="line">    merge_df[merge_df[<span class="string">&quot;is_gift&quot;</span>] == <span class="string">&quot;t&quot;</span>][[<span class="string">&quot;product_id&quot;</span>]]</span><br><span class="line">    .groupby([<span class="string">&quot;product_id&quot;</span>])</span><br><span class="line">    .size()</span><br><span class="line">    .reset_index(name=<span class="string">&quot;gift_count&quot;</span>)</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">result_df = pd.merge(</span><br><span class="line">    result_df,</span><br><span class="line">    gift_count_df,</span><br><span class="line">    on=<span class="string">&quot;product_id&quot;</span>,</span><br><span class="line">    how=<span class="string">&quot;left&quot;</span>,</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">elapsed = time.time() - start</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;  Result Time: <span class="subst">&#123;elapsed:<span class="number">.4</span>f&#125;</span> sec&quot;</span>)</span><br><span class="line"></span><br><span class="line">result_df</span><br></pre></td></tr></table></figure>

<p>pandas は Python の構文（for文やif文）を使っても実装できますが、集約関数を用いた計算は圧倒的に高速です。</p>
<p>チームメンバーが pandas に不慣れで <code>groupby</code> を自由に扱えなくても、多少の時間を割いてでも扱えるようになることはデータ分析では重要となります。</p>
<h3 id="出力すべき粒度を意識する">出力すべき粒度を意識する</h3><p>分析の実装に没頭すると、目の前のデータ処理にリソースが割かれ、本来の目的と逸れて分析してしまうこともあり得ると思います。</p>
<p>これを防ぐために、常に「出力すべき粒度（分母）」の認識合わせを行うことをお勧めします。</p>
<p>具体例として、「クーポンを発行すべき商品」を選定するケースを考えます。</p>
<ul>
<li>売れている商品は、さらにクーポンを発行して販促する。</li>
<li>全く売れていない商品も、試験的にクーポンを発行して効果を見る。</li>
</ul>
<p>この方針に対し、単に売上データだけを集計してしまうと、落とし穴があります。</p>
<figure class="highlight py"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 売上データ(sale_df)のみをベースに集計</span></span><br><span class="line"><span class="comment"># クーポンで売れた個数を算出</span></span><br><span class="line">sale_df.loc[</span><br><span class="line">    sale_df[<span class="string">&quot;coupon_code&quot;</span>].notna(),</span><br><span class="line">    <span class="string">&quot;coupon_sale_qty&quot;</span>,</span><br><span class="line">] = sale_df[<span class="string">&quot;quantity&quot;</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment"># 集約</span></span><br><span class="line">sale_df_g = (</span><br><span class="line">    sale_df.groupby([<span class="string">&quot;product_id&quot;</span>])</span><br><span class="line">    .agg(</span><br><span class="line">        total_qty=(<span class="string">&quot;quantity&quot;</span>, <span class="string">&quot;sum&quot;</span>),</span><br><span class="line">        mean_price=(<span class="string">&quot;unit_price&quot;</span>, <span class="string">&quot;mean&quot;</span>),</span><br><span class="line">        total_coupon_sale_qty=(<span class="string">&quot;coupon_sale_qty&quot;</span>, <span class="string">&quot;sum&quot;</span>),</span><br><span class="line">    )</span><br><span class="line">    .reset_index()</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 四捨五入</span></span><br><span class="line">sale_df_g[<span class="string">&quot;mean_price&quot;</span>] = sale_df_g[<span class="string">&quot;mean_price&quot;</span>].<span class="built_in">round</span>().astype(<span class="built_in">int</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># どの程度がクーポンで売れたかの割合を算出</span></span><br><span class="line">sale_df_g[<span class="string">&quot;coupon_sale_ratio&quot;</span>] = (</span><br><span class="line">    <span class="number">100</span> * (sale_df_g[<span class="string">&quot;total_coupon_sale_qty&quot;</span>] / sale_df_g[<span class="string">&quot;total_qty&quot;</span>])</span><br><span class="line">).<span class="built_in">round</span>()</span><br><span class="line"><span class="comment"># 結果の出力</span></span><br><span class="line">sale_df_g.sort_values(</span><br><span class="line">    by=[</span><br><span class="line">        <span class="string">&quot;coupon_sale_ratio&quot;</span>,</span><br><span class="line">        <span class="string">&quot;total_qty&quot;</span>,</span><br><span class="line">    ],</span><br><span class="line">    ascending=[</span><br><span class="line">        <span class="literal">True</span>,</span><br><span class="line">        <span class="literal">True</span>,</span><br><span class="line">    ],</span><br><span class="line">).head(<span class="number">10</span>)</span><br></pre></td></tr></table></figure>

<p><strong>出力結果</strong>:</p>
<div class="scroll"><table>
<thead>
<tr>
<th align="right">product_id</th>
<th align="right">total_qty</th>
<th align="right">mean_price</th>
<th align="right">total_coupon_sale_qty</th>
<th align="right">coupon_sale_ratio</th>
</tr>
</thead>
<tbody><tr>
<td align="right">33</td>
<td align="right">1</td>
<td align="right">6879</td>
<td align="right">0</td>
<td align="right">0</td>
</tr>
<tr>
<td align="right">197</td>
<td align="right">1</td>
<td align="right">32302</td>
<td align="right">0</td>
<td align="right">0</td>
</tr>
<tr>
<td align="right">322</td>
<td align="right">1</td>
<td align="right">14283</td>
<td align="right">0</td>
<td align="right">0</td>
</tr>
<tr>
<td align="right">977</td>
<td align="right">1</td>
<td align="right">14648</td>
<td align="right">0</td>
<td align="right">0</td>
</tr>
<tr>
<td align="right">994</td>
<td align="right">1</td>
<td align="right">43825</td>
<td align="right">0</td>
<td align="right">0</td>
</tr>
<tr>
<td align="right">1711</td>
<td align="right">1</td>
<td align="right">46073</td>
<td align="right">0</td>
<td align="right">0</td>
</tr>
<tr>
<td align="right">1825</td>
<td align="right">1</td>
<td align="right">49039</td>
<td align="right">0</td>
<td align="right">0</td>
</tr>
<tr>
<td align="right">2138</td>
<td align="right">1</td>
<td align="right">18128</td>
<td align="right">0</td>
<td align="right">0</td>
</tr>
<tr>
<td align="right">2484</td>
<td align="right">1</td>
<td align="right">4507</td>
<td align="right">0</td>
<td align="right">0</td>
</tr>
<tr>
<td align="right">2890</td>
<td align="right">1</td>
<td align="right">4466</td>
<td align="right">0</td>
<td align="right">0</td>
</tr>
</tbody></table></div>
<p>この結果には、「一度も売れていない商品」が含まれていません。売上テーブルには実績があるデータしか存在しないためです。</p>
<p>これでは、「全く売れていない商品にクーポンを発行してみる」という施策の対象が抜け落ちてしまいます。</p>
<p>正しくは、「全商品マスタ」を主軸（左側）に置き、そこに売上データを結合（Left Join）する必要があります。<br><img fetchpriority="high" src="/images/2025/20251211a/image.png" alt="image.png" width="584" height="304"></p>
<figure class="highlight py"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 検証対象とすべき粒度の全データの枠（商品マスタ）を作成</span></span><br><span class="line">result_df = m_product_df[[<span class="string">&quot;product_id&quot;</span>, <span class="string">&quot;regular_price&quot;</span>]].drop_duplicates()</span><br><span class="line"></span><br><span class="line"><span class="comment"># （中略：売上データの集計処理）</span></span><br><span class="line"></span><br><span class="line"><span class="comment">## 結合（商品マスタを左側にLeft Join）</span></span><br><span class="line">result_df = pd.merge(</span><br><span class="line">    result_df,</span><br><span class="line">    sale_df_g,</span><br><span class="line">    how=<span class="string">&quot;left&quot;</span>,</span><br><span class="line">    on=<span class="string">&quot;product_id&quot;</span>,</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 売上がない商品は、0埋めなどで処理</span></span><br><span class="line">result_df = result_df.fillna(<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># （後略）</span></span><br></pre></td></tr></table></figure>

<p><strong>出力結果（マスタ主軸）</strong>:</p>
<div class="scroll"><table>
<thead>
<tr>
<th align="right">product_id</th>
<th align="right">regular_price</th>
<th align="right">total_qty</th>
<th align="right">mean_price</th>
<th align="right">total_coupon_sale_qty</th>
<th align="right">coupon_sale_ratio</th>
</tr>
</thead>
<tbody><tr>
<td align="right">50</td>
<td align="right">77052</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
</tr>
<tr>
<td align="right">151</td>
<td align="right">80856</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
</tr>
<tr>
<td align="right">319</td>
<td align="right">91912</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
</tr>
<tr>
<td align="right">325</td>
<td align="right">86916</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
</tr>
<tr>
<td align="right">425</td>
<td align="right">23177</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
</tr>
<tr>
<td align="right">435</td>
<td align="right">93272</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
</tr>
<tr>
<td align="right">461</td>
<td align="right">26445</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
</tr>
<tr>
<td align="right">466</td>
<td align="right">52490</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
</tr>
<tr>
<td align="right">713</td>
<td align="right">24460</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
</tr>
<tr>
<td align="right">825</td>
<td align="right">22449</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
</tr>
</tbody></table></div>
<p>このようにマスタを主軸にすることで、売上実績がない商品もリストアップされました。これにより、「売れていない商品群」を正しく把握し、施策検討のテーブルに乗せることができます。</p>
<p>この意識を持って実装すると、コードの構成は自然と<strong>出力すべき粒度のベースリストを作成し、そこに各指標を順次結合していく</strong>という形になると思います。</p>
<img src="/images/2025/20251211a/image_2.png" alt="image.png" width="1200" height="272" loading="lazy">

<p>このスタイルの利点は、第三者が見ても「最終的に何の粒度で集計したいのか」が一目瞭然であることです。また、分析項目の追加要望があった際も、複雑な加工を経た変数の状態を追いかける必要は無く、常にこの「ベースリスト」に対して新たな計算結果を結合するだけで済むため、変更に強く拡張性の高いコードになります。</p>
<p><strong>話を聞くと単純なことかもしれませんが、いざ分析に入ると陥りやすい内容となりますので、ぜひ意識をしてみてください。</strong></p>
<h2 id="まとめ">まとめ</h2><p>データ分析での業務を振り返り気づいた、品質高くスピーディーに結果を出すために技術的に留意すべきことをまとめました。</p>
<p>システム開発とは異なり、事前に入念なインフラやPGの設計がされているわけではなく、その状況下で大量データを分析し、より一層スピーディーに結果を出すことは難しいと感じるかもしれません。</p>
<p>そういった場合でも、焦ってすぐに分析に取り掛かるのではなく一度立ち止まり、現在は何を知りたい場面か・何を出力すべきか・そのために何を使用すべきかを、考えてから動くことが結果を出す近道だと感じました。</p>
<h2 id="参考">参考</h2><ul>
<li>Dask Docs</li>
<li>pandas Docs</li>
<li>PySpark Docs</li>
</ul>
]]></content>
    <summary type="html">これまではシステム開発がメインでしたが、最近データ分析の業務に関わらせていただく機会がありました。そこで求められる成果物、注力すべきポイント、そして技術選定の観点など、従来のシステム開発とは異なる部分が多く、様々な気づきがありました。自身の振り返りも兼ねて、その知見を共有したいと思います。</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="PostgreSQL" scheme="https://future-architect.github.io/tags/PostgreSQL/"/>
    <category term="pandas" scheme="https://future-architect.github.io/tags/pandas/"/>
    <category term="データ分析" scheme="https://future-architect.github.io/tags/%E3%83%87%E3%83%BC%E3%82%BF%E5%88%86%E6%9E%90/"/>
    <category term="技術選定" scheme="https://future-architect.github.io/tags/%E6%8A%80%E8%A1%93%E9%81%B8%E5%AE%9A/"/>
  </entry>
  <entry>
    <title>第20回言語処理若手シンポジウム (YANS2025) 参加報告</title>
    <link href="https://future-architect.github.io/articles/20251028a/"/>
    <id>https://future-architect.github.io/articles/20251028a/</id>
    <published>2025-10-27T15:00:00.000Z</published>
    <updated>2025-10-27T15:00:00.000Z</updated>
    <author><name>肥合智史</name></author>
    <content type="html"><![CDATA[<h2 id="はじめに">はじめに</h2><p>はじめまして。フューチャー株式会社の肥合と申します。私は2025年1月に入社し、現在はStrategic AI Group (SAIG) に所属し、主に自然言語処理 (NLP) に関する業務に携わっております。</p>
<p>2025年9月17日（水）から9月19日（金）にかけて開催されたYANS2025に参加しましたので、その様子をご報告します。当社はプラチナスポンサーとして参加しており、スポンサーブースでの会社紹介やポスター・チュートリアルの聴講などを行いました。</p>
<h2 id="言語処理若手シンポジウム-YANS-とは">言語処理若手シンポジウム (YANS) とは</h2><p>YANSは、NLPおよびその関連分野の研究発表が行われるシンポジウムです。若手の相互交流や研究推進をはかり、培われた研究開発の成果が実社会に応用されることを奨励し、学問および産業の進歩発展に貢献する目的で、年に1回開催されています。例年、ハッカソンやチュートリアル、ポスター発表等様々なプログラムが開催されています。</p>
<p>今年で20回目の開催となる本シンポジウムは静岡県のアクトシティ浜松にて開催されました。「研究と実装をつなぐ自然言語処理」をキーワードとして、自然言語処理分野の研究から実社会への実装をつなぐことをテーマに実施されました。参加・発表ともに過去最多の570名の参加と257件の発表となったとのことで、会場は大盛況でした。</p>
<img fetchpriority="high" src="/images/2025/20251028a/1000001125_clipped.jpg" alt="1000001125_clipped.jpg" width="1200" height="1682">

<h2 id="スポンサー参加">スポンサー参加</h2><p>フューチャーはプラチナスポンサーとして参加し、主にスポンサーブースでの会社紹介をしました。ブースに来られた方々に、当社のNLPやAI関連の取り組みについてご紹介させていただきました。</p>
<p>ノベルティとしてパンフレットと当社のロゴ入りの扇子を配布させていただいたのですが、ご好評いただき、扇子が早々に品切れとなりました。当社の取り組みについて多くの方に知っていただく機会になったと思います。改めてブースに足を運んでくださった皆様に感謝申し上げます。</p>
<img src="/images/2025/20251028a/IMG_7410_clipped.jpg" alt="IMG_7410_clipped.jpg" width="1200" height="1477" loading="lazy">

<h2 id="スポンサー賞">スポンサー賞</h2><p>当社のスポンサー賞には <strong>[S4-P18] CEFRに基づく文難易度を連続的に制御可能なテキスト平易化</strong> の発表を選定させていただきました。この研究は、テキストの難易度を連続値で制御できる平易化モデルを提案するものです。従来手法は目標の難易度を段階的（離散的）にしか指定できませんでした。本手法では難易度をベクトルの長さで表現し、連続値で制御します。</p>
<p>選定理由は以下の通りです。</p>
<blockquote>
<p>まず「LLMの出力品質をコントロールしたい」というモチベーションが非常に明確で分かりやすい点を高く評価しました。さらに、先行研究が離散的な制御に留まっていた中で、それを連続値で扱えるようにした技術的な新規性も素晴らしく、「子供新聞の見出し作成」といった具体的な応用例にも大いに期待が持てます。発表当日は丁寧な導入から分かりやすく解説いただき、その真摯な発表姿勢も受賞を決定づける大きな要因となりました。</p>
</blockquote>
<p>副賞として、開催地にちなみ、浜松うなぎと浜松餃子を贈呈させていただきました。</p>
<h2 id="発表紹介">発表紹介</h2><p>スポンサー賞の他に、当社から参加したメンバーが特に面白いと感じた発表をいくつか紹介します。</p>
<h3 id="S4-P10-大規模言語モデルにおける文化理解のニューロンレベル分析">[S4-P10] 大規模言語モデルにおける文化理解のニューロンレベル分析</h3><p>この研究では、大規模モデルの文化理解のメカニズムについて分析しています。文化理解に寄与するニューロンを特定し、メカニズムを分析しています。</p>
<p>文化全体の理解に寄与するニューロン（文化全体ニューロン）、特定の文化理解に寄与する（個別文化ニューロン）を特定し、分析しています。実験の結果、文化全体ニューロンについては、マスクすると文化ベンチマークの精度が低下することが示されています。また、個別文化ニューロンについては、マスクするとその文化の問題に対する精度が低下するだけではなく、地理的・歴史的に近い文化の問題の精度低下も大きいことが示されています。（例：メキシコ文化のニューロンをマスクすると、歴史的に関係のあるスペインの問題も精度が大きく低下）</p>
<p>個別文化ニューロンに関する実験が特に興味深く、様々な観点からも検証しており、今後の展開に期待ができる研究だと思いました。</p>
<h4 id="S4-P27-物語性が大規模言語モデルの記憶再生に与える影響の検証">[S4-P27] 物語性が大規模言語モデルの記憶再生に与える影響の検証</h4><p>この研究では、人間の記憶研究においてストーリー性のある文章は干渉に強く、要素の羅列は干渉に脆弱という背景から、文章の物語性に着目し、LLMにおいても物語性の違いによって記憶保持能力に差が生まれるのかを検証しています。</p>
<p>実験では小説風の高物語性の文、箇条書き形式の低物語性の文のいずれかを提示したうえで、その文について場所や時間などに関する質問の回答を生成するQAタスクを用意し、意味のない文を与えるなどの干渉条件の元でQA性能がどう変化するかを調査しています。</p>
<p>実験の結果、高物語性の文を提示すると人間同様に干渉に対して頑健であり、一方で低物語性の文では干渉に弱いことが示されています。物語性というユニークな着眼点で実際に人間と同様の傾向が見えるという興味深い結果が得られており、また実験設定やデータセットの拡張によってさらなる知見獲得の可能性を秘めていることから、今後の展開に期待できる発表だと感じました。</p>
<h4 id="S4-P33-視覚言語モデルを活用したWebフロントエンドコード生成におけるデザイン忠実度の改善">[S4-P33] 視覚言語モデルを活用したWebフロントエンドコード生成におけるデザイン忠実度の改善</h4><p>この研究では、入力画像のデザインを忠実に反映したWebサイトを生成するためのVLM学習手法を検討しています。<br>従来より、Webサイト画像と当該サイトを生成するコードのペアを用いた教師あり学習は提案されてきましたが、本研究では生成コードのレンダリング結果を視覚的に正解と比較することで、デザイン忠実度の改善を図っています。</p>
<p>具体的にはGRPO (Group Relative Policy Optimization) を用いて、配色や要素の位置が正解と似ている生成結果を選好するように最適化することで、モデルの生成するコードがどのように変化するかを検証しています。</p>
<p>昨今、Code LLMsのケイパビリティは急速に拡大していますが、デザインに関する部分は未だ、比較的苦手としている印象があります。<br>これに対する1つの理由としては、正しさの評価が困難である、という点が挙げられます。実際に、本研究では、テキスト要素に着目した結果、それ以外の箇所における忠実性の低下が見られたことも触れられています。忠実性をどのようにモデリングするか、今後の展開に期待できる研究だと感じました。</p>
<h4 id="S1-P13-多目的問題でのGRPOにおける報酬ハッキングの緩和について">[S1-P13] 多目的問題でのGRPOにおける報酬ハッキングの緩和について</h4><p>この研究は、GRPOで複数報酬を最適化する場合の課題である報酬ハッキングの緩和に取り組んだものです。GRPOは、文章生成モデルの学習において、複数の候補を生成し、報酬関数で点数づけして、相対的な良し悪しで学習をすすめる強化学習の一種です。GRPOの課題として、複数の報酬関数を適用する際に、一部の報酬だけに過剰に最適化し、 他の報酬を犠牲にしてしまう報酬ハッキングがあります。この研究では、各報酬関数の正規化によって、バランスの良い学習に寄与するMO-GRPOを提案しています。</p>
<p>機械翻訳タスクでの評価実験において、読みやすさの評価指標 (jReadability) と翻訳の評価指標 (BLEURT) を報酬関数とした訓練をした結果、GRPOではjReadabilityが向上、BLEURTが低下した一方、提案手法では両方の指標でバランスの取れたスコアを達成し、評価用の別指標 (GPT-Eval) でも高精度となりました。<br>複数の観点で同時に良くしたいという状況は普遍的なもので、そこに取り組んだシンプルかつ実用的な研究だと考え、この研究を挙げさせていただきました。</p>
<h2 id="おわりに">おわりに</h2><p>YANS2025は、過去最多の参加者・発表件数の、非常に密度の高いシンポジウムでした。ポスターセッションをはじめ、会場の各所で活発な議論が交わされており、大変良い刺激を受けることができました。ポスター発表で議論させていただいた皆様はもちろんのこと、スポンサーブースや懇親会などの企画で交流させていただいた皆様、そしてこの盛況な場を準備・運営してくださった運営・委員の皆様にも心より感謝申し上げます。今後もぜひ、このような活気ある場に参加し続けていきたいと考えています。</p>
<p>現在SAIGではともに働くメンバーを募集しています。特にNLP分野における社会実装のニーズは根強く、多くの仲間を必要としているところです。キャリア採用ページではシニアNLPエンジニアをはじめ、NLPリサーチエンジニア及びNLPエンジニアも同じく絶賛募集中です。条件等応相談ですので、我こそはという方は是非先のリンクよりご応募をお待ちしております。</p>
<p>ほかにも幅広く新卒採用およびキャリア採用を募集中です。興味のある方は是非一緒に働きましょう。よろしくお願いします！</p>
]]></content>
    <summary type="html">2025年9月17日（水）から9月19日（金）にかけて開催されたYANS2025に参加しましたので、その様子をご報告します。</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="NLP" scheme="https://future-architect.github.io/tags/NLP/"/>
    <category term="YANS" scheme="https://future-architect.github.io/tags/YANS/"/>
    <category term="参加レポート" scheme="https://future-architect.github.io/tags/%E5%8F%82%E5%8A%A0%E3%83%AC%E3%83%9D%E3%83%BC%E3%83%88/"/>
    <category term="論文紹介" scheme="https://future-architect.github.io/tags/%E8%AB%96%E6%96%87%E7%B4%B9%E4%BB%8B/"/>
  </entry>
  <entry>
    <title>【論文紹介】AIは「正しさ」だけで評価できるか？ 社会階層とAI利用の関係について</title>
    <link href="https://future-architect.github.io/articles/20250909a/"/>
    <id>https://future-architect.github.io/articles/20250909a/</id>
    <published>2025-09-08T15:00:00.000Z</published>
    <updated>2025-09-08T15:00:00.000Z</updated>
    <author><name>小橋昌明</name></author>
    <content type="html"><![CDATA[<p>夏の自由研究連載2025のラスト、10日目での記事です。</p>
<h2 id="はじめに">はじめに</h2><p>SAIGの小橋です。最近、間違って冷凍庫のドアを開けたまま外出してしまい、中身が全部解凍されてしまったので凹んでいます。</p>
<p>さて、今回は、AIと社会格差について、論文を読んで記事を書きたいと思います。</p>
<p>GPT-5がリリースされた際、#keep4o という運動が起きました。旧モデルのGPT-4oは暖かさや共感力があったが、新しいGPT-5は冷淡で機械的だと、一部ユーザーから批判の声が上がりました。</p>
<p>それに関連してこの論文を思い出しました。ただ、腰を据えて読んだことが無かったので、これを機に読むことにしました。</p>
<ul>
<li>The AI Gap: How Socioeconomic Status Affects Language Technology Interactions</li>
</ul>
<h2 id="概要と注意点">概要と注意点</h2><p>この論文では、1000人にアンケートを実施して収集したデータを分析し、個人のSES（社会経済的状況）とAIの使い方には関連性があることを示しています。</p>
<p>今回のSESは、IT企業でよく登場するSES契約（System Engineering Service）の話ではなく、「社会経済的地位」の意味です。分かりやすくいうと、「SESが高い」とは、高学歴・高収入で良い暮らしをしている人を指します。</p>
<p>注意点として、私が気になった箇所を特に注目して掘り下げて考察しています。全体の概要を知りたい人は、先に他の記事を読んだ方がいいかもしれません。例えばこちらの記事などがあります。</p>
<ul>
<li>AI格差は今、どうなっているのか？　収入や地位、教育などの違いで生成AIの活用方法、プロンプトがどう違うのか　1000人を対象に「AIギャップ」を調査（生成AIクローズアップ） | テクノエッジ TechnoEdge</li>
</ul>
<h2 id="AIを活用した論文の読み方">AIを活用した論文の読み方</h2><p>私は研究開発職ではないので、論文を日常的に読んでいるわけではなく、いきなり論文を頭から読んでいくのはちょっと大変です。そこでAIの力を借りて、alphaXivというツールを使うことにしました。</p>
<p>会員登録が必要ですが、無料で論文をブログ記事として読むことができます。しかも、英語だけではなく、日本語に変換した記事も読むことができます。（原文の日本語訳はありません）</p>
<p>またこのサイト上ではLLMのチャットボットのシステムがあり、論文の内容について質問すると原文を適宜参照して答えてくれます。いわば、論文を取り込んだnotebookLMのようなものです。便利な世の中ですね。</p>
<p>なお、以下の文章中では、alphaXivのチャットボットの回答が一部含まれています。</p>
<h2 id="調査におけるデータ収集方法">調査におけるデータ収集方法</h2><p>まず私が気になったのは、著者らがどうやってデータを収集したかという点です。</p>
<p>著者らは、Prolificというクラウドソーシングサイトを使って回答を収集しました。</p>
<p>サイトを見ると、（特定の成果物を作成してもらうタイプのクラウドソーシングではなくて）データ収集に特化したサイトのようです。つまり仕事を発注する側は何らかのアンケート（データ収集用フォーム）を準備して回答者を募集します。受注者はそのアンケートに回答して報酬を得るという形だと思います。</p>
<p>研究者たちは、Prolificを通じてデータを収集したことにより、偏りや歪みが生じた可能性があると考えています。この点については、論文の「制限事項」の章に説明があります。</p>
<ul>
<li><strong>対象者が広い集団を代表していると言えるか:</strong> この研究は、Prolificプラットフォームの米国および英国のクラウドワーカーに限られているため、広い人口を代表していない可能性があります。社会経済的地位に関して、Prolificの利用者は中流階級から下流階級に偏っていると研究者たちは予測しています。</li>
<li><strong>言語技術への親和性:</strong> クラウドワーカーは一般の人口と比較して、技術、特に言語技術に詳しい可能性が高く、そのため言語技術をより頻繁に利用している傾向があるかもしれません。</li>
</ul>
<h2 id="SESとは何か、どのように測定したか">SESとは何か、どのように測定したか</h2><p>次に私が気になったのは「回答者のSESをどのように測定したか」という点です。結論から言うと、Macarthurスケールというものを使用していて、「自分の社会経済的地位を1〜10の中で評価してください」という質問をしています。</p>
<p>SESはSocioeconomic Statusの略で、日本語では「社会経済的地位」と訳されます。論文では、SESを個人またはグループの社会経済的な位置を指すと定義しています。具体的には、個人の経済的、社会的、文化的な資本の関数であり、収入、教育、職業、富といった要素がSESに影響を与えると説明されています。</p>
<p>SESの測定方法としては、Macarthurスケールを使用しています。下図の通り、参加者にはしごの絵を見せて、「自身は、社会経済的はしごの1から10までの間でどの位置に該当するか?」という質問をしています。<br>その後、1〜3と答えた人を低SES、4〜7を中SES、8〜10を高SESと分類しています。</p>
<img fetchpriority="high" src="/images/2025/20250909a/SESの測定方法.png" alt="SESの測定方法.png" width="630" height="502">

<p>この方法は結構意外でした。学歴や年収などの客観的な指標を聞くのかと想像していましたが、「主観的な質問1問だけで良い」と考えて、SESを測定するというのはいい加減な手法ではないかと思いました。ただ、調べてみるとMacarthurスケールはよく使われる手法らしいです。</p>
<p>著者らもこの手法の限界については気づいていて、以下の通り述べています。「我々はSESを測定する上でマッカーサスケールを使用しました。主観的な尺度は曖昧さや偏りが生じやすい傾向があります。しかしながら、自分自身のSESに対する認識が行動や態度に重要な役割を果たすことも認識しているため、このため本調査ではこの尺度を用いることにしました」</p>
<p>なお学歴や趣味などもアンケートで収集していますが、SESを分類する際には使用していません。完全に蛇足ですが、趣味の選択肢に “Visit to stately homes” という項目があるのが不思議でした。イギリスなどにある昔からの貴族の屋敷を訪問することを指しているようですが、もっと一般的な「travel」のような項目が無いのに、こんな特定の項目があるのはなぜ……?</p>
<h2 id="SESとプロンプトの長さの関係">SESとプロンプトの長さの関係</h2><p>それでは分析の方に移りましょう。論文中の分析は大きく分けて「言語関連の技術の使用状況について」「プロンプトの言語学敵分析（長さや語彙など）」「プロンプトのクラスタリングによる内容分析」「ユーザーがAIをどう認識しているか」の4つです。</p>
<p>ここでは特に興味深い2つの側面に焦点を当てて考察してみたいと思います。まず最初に、プロンプトの長さとSESの関係について見ていきましょう。次に、AIとの日常会話とSESの関係についても触れます。</p>
<p>社会階層が高い人々ほどプロンプトが短く簡潔になるらしいです。プロンプトの平均単語数は以下の通りです。</p>
<ul>
<li><strong>低SES層:</strong> 27.0語</li>
<li><strong>中SES層:</strong> 22.3語</li>
<li><strong>高SES層:</strong> 18.4語</li>
</ul>
<p>この違いは、統計的に有意であると書かれています。この違いは、高SES層の個人がより広い語彙を持ち、少ない単語で自分自身を表現できることに起因するのではないかと研究者たちは推測しています。</p>
<h3 id="調査方法への疑問">調査方法への疑問</h3><p>一見納得できる結果のようですが、立ち止まって考えてみると、この具体的な数値（20〜30単語）が私個人の実感と全く合致しないのでどうも腑に落ちません。</p>
<p>著者らはこの論文のcontributionとして</p>
<blockquote>
<p>The first dataset of real prompts annotated with fine-grained sociodemographic information, including SES</p>
</blockquote>
<p>と述べていますが、この内容がどこまで「リアル」なのかは注意すべきでしょう。正確な（実際に入力したものと全く同じ）プロンプトではないと推測されます。</p>
<p>第一に、自分が望む回答を得るために質問をどんどん具体的にしていったら語数は増えていき、上記に全く収まらないのではないでしょうか。例えば論文中には「Create a cover letter for a new role as a communication manager」という例が載っています。これをそのまま入力してもChatGPTなどは回答を出力しますが、その内容が自分の職歴に合致しているとは限りません。したがって回答の精度を上げるためには自分の職業内容や応募先の職務内容を入力するのが望ましく、そうするとプロンプトの語数は30単語どころではなくなります。</p>
<p>第二に、ある種の質問は対象となる文章が必要なので、明らかにプロンプトが長くなります。具体的には翻訳、要約、文章校正などです。「以下の文章を翻訳してください。（翻訳対象の文章）」というプロンプトの場合、ゆうに数百語、数千語になる可能性があります。要約や文章校正についても同じです。先の例であれば「カバーレターを書いてみたがこれでよいかレビューしてください」のようなプロンプトならば語数は多くなります。</p>
<p>このアンケートでは、回答者にプロンプトを入力してもらう際に「できれば、会話から直接コピーペーストしてください（Perferably, copy and paste the questions directly from the conversation.）」と依頼しています。したがって回答者はその場でプロンプトを書くこともできるし、コピーペーストもできます。しかし、上記の点を考えると、本当のプロンプトを入力したにしては平均単語数が少なすぎます。回答者は正確なプロンプトをコピー＆ペーストする代わりに、回答者が改めて一から新しくプロンプトを書いた可能性があるのではないでしょうか。</p>
<p>また、前処理についての記載を調べました。例えば極端に長いプロンプトを除外するなどの処理をしれから平均長を計算したのかとも予想しましたが、前処理について何ら記載はありませんでした。論文の記載を見る限り、特に前処理をせずにアンケートの回答結果をそのまま用いたようです。</p>
<h2 id="SESと日常会話の関係">SESと日常会話の関係</h2><p>低SES層のユーザーは、生成AIを人間のように扱い、一般的な会話をしているという結果も見られました。その内容を詳しく見ていきましょう。</p>
<img src="/images/2025/20250909a/各タスクに.png" alt="各タスクに.png" width="985" height="446" loading="lazy">

<p>まず、アンケートでは、どのような用途でチャットボットを使用したかを質問しています。低SES層の方が利用割合が高かった主な項目は以下の2つです。</p>
<ul>
<li>Generic conversation（一般的な会話）</li>
<li>QA on general knowledge（一般的な知識についての質問と回答）</li>
</ul>
<p>この結果の解釈は慎重に行う必要があります。まずアンケートの結果はプロンプトに基づいたものではなく自己申告であるため、回答バイアスの影響が考えられます。例えば、高SES層の方々は実際には「一般的な会話」をしていても、見栄を張って「一般的な会話はしていない」と回答をした可能性も否定できません。<br>また、「一般的な会話」が具体的にどのようなものを指すのか知りたかったですが、論文中に具体的なプロンプト例が示されていません。なお、今回のプロンプトの分類はアンケートに基づいた結果であり、実際のプロンプトの内容分析はクラスタリングを使用しており、両者が別々に実施されていることにも留意する必要があります。</p>
<p>次に、「ユーザーがAIをどう認識しているか」についてです。Anthropomorphism（擬人化）という単語は論文中に登場し、4種類の条件を満たす割合を求めています。4種類のうち「Phatic expression（挨拶的表現）」については「thank, thanks, please, hi, hello」を含むプロンプトの割合を計算しています。これが低SES層のほうが使用率が高かった（統計的に有意ではない）ようです。</p>
<p>ただ、前述の通り、分析対象は正確なプロンプトではないと考えられます。そのため、この分析の妥当性には疑問が残ります。<br>仮に実際のプロンプトからコピーペーストせずに自分で改めてプロンプトを書く場合、「thank you」や「hello」などの挨拶的表現は真っ先に省略される可能性が高いでしょう。「挨拶的単語の使用割合」について有意義な議論をするためには、ユーザーが実際に入力したプロンプトを一字一句正確に収集する必要があります。この点で調査方法に課題があるため、この分析結果の解釈には慎重になるべきだと考えます。</p>
<p>2つの点について分析結果を見てきましたが、この分析では生成AIとの会話内容の一側面しか分からないでしょう。例えば極端な例として、ChatGPT（4o）と結婚した人のニュースがありました。本論文は、AIに人格を与えたり、回答のスタイルを大きく調整するような話には全く言及していないことには注意が必要です。</p>
<h2 id="AIの性能評価は一面的な尺度だけを見ている">AIの性能評価は一面的な尺度だけを見ている?</h2><p>ここまで論文の分析内容を見てきましたが、調査方法や結果の解釈には慎重に検討すべき点がいくつかあることがわかりました。最後に、論文の議論の部分で特に興味深い指摘があったので、それを紹介して締めくくりたいと思います。</p>
<p>高SES層のユーザーが行うような、言い換え、要約、数学的問題解決といったタスクは「ground-truth（正解）のある評価」には適している。一方で、低SES層のユーザーがより頻繁に行うようなタスクは、人間の好みによる評価に大きく依存しているため、既存のベンチマークでの評価が不十分です。将来の研究では、全てのSES層を代表するような現実的なシナリオに対してモデルの性能をベンチマークすることに焦点を当てるべきだと、著者らは述べています。</p>
<p>確かに、例えば私が「技術ブログを書いているけど、なかなか書き終わらないしもう疲れてきた」と弱音を吐いた場合に、AIが「もう少しだけ頑張ってみましょう」と励ますのが正解なのでしょうか。それとも、「そうですね、疲れているならば今日はもう寝て、続きは明日にしましょう」と休憩を促すのが正解なのか、これは難しい問題です。時と場合によって正解は変わりえるからです。（AIの回答が当初の予想と違うものだったけど結果的にOK、という場合さえあります）</p>
<p>この指摘は、AIの性能評価のあり方について考えさせられます。現在のAIの性能は、「数学オリンピックの問題を何%解けたか」といった、いわゆる「ground-truth（正解）のある評価」で語られがちです。しかし、AIの良し悪しを判断する材料は、それだけで十分なのでしょうか。</p>
<p>大学院や専門家レベルの難問を解く能力よりも、人間と楽しく会話できる能力の方が重要だという側面もあるはずです。正解のあるタスクの評価だけでは、こうした側面を見逃してしまうかもしれません。その結果として、例えば「GPT-4oがおべっかばかりで気持ち悪い」と批判されたり、「GPT-5のモデルが冷淡すぎるから以前のバージョンに戻してほしい」と言われたりするような問題に繋がっていくのかもしれない、と感じました。</p>
<h2 id="おわりに">おわりに</h2><p>この記事では、論文をきっかけに、社会経済的地位（SES）とAIの使われ方の関係、そして現在のAI性能評価のあり方について考えてきました。特にAIの性能評価というテーマは、今後どのように発展していくのか興味深いところです。単純な正解・不正解だけでなく、ground-truth（正解）のない問題に対してどのような評価指標を設計していくのか。これは、これからのAI開発における大きな課題と言えるでしょう。</p>
<p>記事の冒頭で触れた「#keep4o」の運動を思い返すと、今回の論文が示唆するテーマとの繋がりが見えてきます。GPT-4oに「暖かさや共感力」を見出したのは誰だったのか。人が生成AIに何を求め、そのニーズが個人の属性によってどう変わるのか。今回読んできた論文は、これらの問いの一部に答えているに過ぎません。今後、この分野のさらなる研究が登場することを待ちたいと思います。</p>
<p>（論文を読んでいて気づいたのですが、このアンケート結果はhuggingfaceに公開されているようです。せっかくの自由研究ならそのデータを使って何か分析すれば良かった……）</p>
]]></content>
    <summary type="html">AIと社会格差について、論文を読んで記事を書きたいと思います。GPT-5がリリースされた際、#keep4o という運動が起きました]。旧モデルのGPT-4oは暖かさや共感力があったが、新しいGPT-5は冷淡で機械的だと、一部ユーザーから批判の声が上がりました。</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="ChatGPT" scheme="https://future-architect.github.io/tags/ChatGPT/"/>
    <category term="LLM" scheme="https://future-architect.github.io/tags/LLM/"/>
    <category term="生成AI" scheme="https://future-architect.github.io/tags/%E7%94%9F%E6%88%90AI/"/>
    <category term="論文紹介" scheme="https://future-architect.github.io/tags/%E8%AB%96%E6%96%87%E7%B4%B9%E4%BB%8B/"/>
  </entry>
  <entry>
    <title>日本語×ソフトウェア開発に強いLLMの開発に取り組んだ挑戦者の備忘録 (後編)</title>
    <link href="https://future-architect.github.io/articles/20250716a/"/>
    <id>https://future-architect.github.io/articles/20250716a/</id>
    <published>2025-07-15T15:00:00.000Z</published>
    <updated>2025-07-15T15:00:00.000Z</updated>
    <author><name>藤井諒</name></author>
    <content type="html"><![CDATA[<p>AI Tips連載の5本目の記事となります。</p>
<h2 id="はじめに">はじめに</h2><p>こんにちは。Strategic AI Group (SAIG) の藤井です。</p>
<p>GENIAC第2期事業にて採択された「日本語とソフトウェア開発に特化した基盤モデルの構築」プロジェクトに関する取り組み紹介、全2編の後編です。</p>
<p>前編では、開発したモデルの概要や開発の流れ、プロジェクト進行における反省点をご紹介しました。後編では、モデルの技術的特徴に関するより込み入った内容や、取り組みの中では明らかに出来なかった今後の検討課題・オープンクエスチョンを共有します。</p>
<p>改めて、本プロジェクトで開発したモデル Llama-3.1-Future-Code-Ja-8B はHugging Faceにて公開しております。</p>
<p>商用利用も可能な許容的ライセンスで公開しておりますので、ぜひ幅広く試して (遊んで) いただけると嬉しいです。</p>
<h2 id="モデル学習における気づき・学び">モデル学習における気づき・学び</h2><p>今回のモデル開発では、① 継続事前学習、② 教師ありファインチューニング、③ 選好最適化 の3つのフェーズで学習しました。</p>
<p>ここでは、モデル学習における気づきや学びを、フェーズの順に紹介していきます。</p>
<h3 id="継続事前学習">継続事前学習</h3><h4 id="Fill-in-the-Middle-FIM-は学習時間のオーバーヘッド、性能低下ともに最小限">Fill-in-the-Middle (FIM) は学習時間のオーバーヘッド、性能低下ともに最小限</h4><p>今回のモデル学習では Fill-in-the-Middle (FIM) と呼ばれる学習手法を導入しました。</p>
<p>ここで、LLMの (継続) 事前学習では、所定のコンテキスト長まで複数のドキュメントをつなぎ合わせ、詰め込んだものを1つのシーケンスとして学習することが一般的です(この操作は <code>packing</code> と呼ばれます)。</p>
<p>この時、1つの詰め込みシーケンスから <em>prefix</em>, <em>middle</em>, <em>suffix</em> の分割を作成する方法を “Context-level FIM”、元のドキュメント境界を尊重し、ドキュメント内で各分割を作成する方法を “Document-level FIM” と呼びます。</p>
<p>“Document-level FIM” は、各ドキュメントを事前に分割 → 順序を入れ替えておく処理で完結するため、実装が容易であり、学習時のオーバーヘッドも発生しませんが、packingの際に各分割が異なるシーケンスに分散してしまう可能性があることから、精度面では “Context-level FIM” に軍配が上がることが論文中で述べられています。そのため、今回はMegatron LM上に “Context-level FIM” の実装を追加して学習を進めることとしました。</p>
<p>Megatron LMを用いる場合、前処理の段階でコーパスはtokenize (トークン化) されます。packingの処理は、前処理済の <strong>トークンID</strong> を所定のコンテキスト長まで取得する形で実現されるため、テキストを任意の箇所で3分割するためには、<strong>一度detokenizeして文字列に戻した上で改めてtokenizeする</strong> という処理が必要になります。このように、学習時に追加の処理が加わることとなるため、学習速度の低下が懸念されたのですが、今回の開発環境 (p5.48xlarge × 4ノード) では速度面の影響はほとんど見られませんでした。</p>
<p>また、論文でも <code>FIM-for-free</code> と呼ばれているように、FIMの導入前後で一般的なLeft-to-Right生成タスクの到達点が顕著に下がるような現象は確認されませんでした。しかしながら、リソース制約により厳密な比較実験ができておらず、確かなことはまだ分からないというのも事実です。</p>
<p>↓ FIM導入前後のスコアの比較 (NIILC)</p>
<p>桃色がFIM導入後、その他の線は導入前のもの (※ ただし、桃色線とそれ以外では学習データの総量、組成も異なる）。<br>FIM導入後 (桃色線) の到達点は、学習データの組成が類似するFIM導入前のモデル (青・橙線) と同等以上をキープしている。</p>
<img fetchpriority="high" src="/images/2025/20250716a/niilc_v6.jpg" alt="niilc_v6.jpg" width="1200" height="819">

<h4 id="事前学習時に学んだ-“嫌な形質”-は増強するのは簡単だが、取り除くのは困難">事前学習時に学んだ “嫌な形質” は増強するのは簡単だが、取り除くのは困難</h4><p>継続事前学習では、学習データに適用するフィルタを段階的に実装して、出力の定量・定性的な変化を確認していきました。</p>
<p>その過程で、特に初期のモデルに特徴的な傾向として <code># TODO: implement this function</code> 等、ユーザに追記を促すような出力が顕著に増加する、(それに起因してか) 出力の平均長が学習前より短くなる現象が確認されました。Web上には教育目的で書かれたソースコードも多く存在しており、上記以外にも <code>Write your solution</code>, <code>Implement me</code> 等の派生が多数見られます。しかし、ソフトウェア開発 (コーディング) を支援するLLMにおいて、このような出力が望ましいケースというのはそう多くありません。</p>
<p>そのため、今回は学習データから数百万件のソースコードをサンプリングし、考えられる表現パターンを <code>grep</code> で洗い出した上で、いずれかの表現とマッチする場合には「ドキュメントごと」学習対象外とする対応を取ることとしました。しかしながら、そのような厳格な対応を取ってなお、<code># TODO: implement this function</code> 問題は完全には解決しませんでした。</p>
<p>学習データで数百万件に1度と出現しない程度の頻度でありながら、そのような表現が生成されてしまう理由として、今回は「継続」事前学習であったことが考えられます。今回、学習に用いたトークン数 (約290B) は決して小さくありませんが、それでもLlama-3.1の事前学習におけるトークン数 (15T) と比較すると極めて小規模です。</p>
<p>手元の学習データにない入力<mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="1.294ex" height="1.025ex" role="img" focusable="false" viewBox="0 -442 572 453"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z"></path></g></g></g></svg></mjx-container>に対して <code># TODO...</code> を出力するよう、モデルが既に学んでしまっていたとすれば、仮に手元の学習データで出現数を0に抑えられたとて生成を抑制できません。<strong>Next Token Predictionでモデルが学習するのは、手元のデータセットに対する Do’s</strong> であり、Don’ts の抑制はここでは困難である (選好最適化で対応するか、スクラッチからの学習時に徹底的に綺麗にするべき) というのは学びでした。</p>
<h3 id="教師ありファインチューニング">教師ありファインチューニング</h3><h4 id="LLMによる疑似データ生成はモデルが既に知っているタスクにbiasedな可能性が高い">LLMによる疑似データ生成はモデルが既に知っているタスクにbiasedな可能性が高い</h4><p>今回の取り組みでは、 Magpie の手法を適用することで、ソフトウェア開発に特化したinstructionを「より優れたモデルから引き出して」学習しました。</p>
<p>この時、instructionを生成するための (システム) プロンプトは論文のAppendixに記載のものをベースとしたのですが、オリジナルのプロンプトを愚直に用いた場合では生成されるinstructionの多く (7割以上) がPythonに関するものとなってしまいました。</p>
<p>そのため、今回は <code>The user will ask you a wide range of coding questions about the {language} programming language.</code> のように、ユーザがアシスタントに求める役割として、関連するプログラミング言語を明示することでタスクに多様性を持たせることとしました。</p>
<p>このような「偏り」が存在する理由としては、Code LLMに関する既存の評価ベンチマークが極めてPythonに寄っているということが挙げられます。この状況は望ましくありませんが、そうなってしまっている以上、既存のモデルの多くがPythonに力を入れているのは当然であり、それらから抽出されるinstructionもまたPythonに偏ってしまいます。</p>
<p>さらに、この「偏り」はプログラミング言語の分布に限った話ではなく、生成されるタスクの種類についても同様に考えられます。今回の取り組みの過程で調査していて驚いたことですが、to code (生成する対象がコード) では様々なベンチマークが提案されている一方、コードを説明する・レビューをするなどの to 自然言語 のタスクには、ほとんどといって良いほどベンチマークが存在しません。</p>
<p>また、to code のタスクにおいても、純粋なコード生成 (補完) のベンチマークは多数存在する一方で、言語間翻訳などは盛んには取り組まれていない印象です。これには、評価方法が確立されていない、データの作成が困難であるなど様々な要因が考えられ、一朝一夕解決するようなものではないのですが「富める者は富み」の状況になってしまっていることは間違いないでしょう。</p>
<p>実際に、前編に記載のように、今回学習したモデルはベースライン (Llama 3.1-8B) と比較して高いコード補完性能を実現していますが、その一方でバグフィックス (HumanEvalFix) や仕様変更対応 (CanItEdit) に関するベンチマークではLlamaと同等の性能に留まってしまいました。</p>
<p>LLMの生成する疑似データには偏りが存在することを認識したうえで、より明示的なタスク誘導を入れる、他のスキーム (Evol-Instruct など) と組み合わせる、Human-in-the-Loopを検討するなど柔軟な対応が求められそうです。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>モデル</th>
<th>HumanEvalFixTests (Python)</th>
<th>CanItEdit (Descriptive)</th>
<th>CanItEdit (Lazy)</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Llama-3.1-Future-Code-Ja-8B</strong></td>
<td><strong>0.4698</strong></td>
<td><strong>0.4462</strong></td>
<td><strong>0.3857</strong></td>
</tr>
<tr>
<td>Llama-3.1-8B-Instruct</td>
<td>0.4707</td>
<td>0.4648</td>
<td>0.3738</td>
</tr>
<tr>
<td>Llama-3.1-Swallow-8B-Instruct-v0.3</td>
<td>0.3250</td>
<td>0.3329</td>
<td>0.2329</td>
</tr>
<tr>
<td>Qwen2.5-7B-Instruct</td>
<td>0.5415</td>
<td>0.4914</td>
<td>0.4138</td>
</tr>
<tr>
<td>Qwen2.5-Coder-7B-Instruct</td>
<td>0.5857</td>
<td>0.5395</td>
<td>0.4533</td>
</tr>
<tr>
<td>Qwen3-8B</td>
<td>0.5622</td>
<td>0.5833</td>
<td>0.4319</td>
</tr>
<tr>
<td>gemma-2-9b-it</td>
<td>0.4509</td>
<td>0.4643</td>
<td>0.3833</td>
</tr>
</tbody></table></div>
<h3 id="選好最適化">選好最適化</h3><h4 id="モデルベースのフィードバックでは報酬スコアのノイズに関する一定の考慮が必要">モデルベースのフィードバックでは報酬スコアのノイズに関する一定の考慮が必要</h4><p>今回、各instructionに対し4件のresponseを生成し、それぞれを報酬モデル (Llama-3.1-Nemotron-70B-Reward-HF) で評価することで、DPO用の学習データを作成しました。この時、正例 <em>chosen</em> については「最もスコアの高いものを選択する」で基本的に問題ないと思われますが、負例 <em>rejected</em> の選び方についてはいくつかのバリエーションが考えられます。</p>
<p>検証では、① 最もスコアが近いもの (＝2位) ② 最もスコアが遠いもの (≒4位) ③ <em>chosen</em> 以外からランダム選択 の3つのパターンで学習し、各モデルのベンチマーク性能 (コード補完性能) を確認しました。その結果、② スコアが遠いもの と ③ ランダム選択 の優劣はまちまちであるものの、① スコアが近いもの では他の設定を明確に下回るケースが多く見られました。</p>
<p>モデルベースの報酬は採点基準に沿った加点法ではないため、あるresponseがより高いスコアを獲得したとからいって、必ずしもそのresponseがユースケースに沿って「より優れている」ことを意味しません。コード生成を例にあげると、responseが満たすべき観点の1つには「機能的に正しく動作すること」があげられますが、モデルベースの報酬は「コードとは一切関係しない何らかの観点で優れている」ことを機能的正確性よりも重く評価する可能性があります。特にスコアの近い出力どうしのペアでは、このような非本質的観点による良さの逆転 (ノイズ) により良い学習シグナルが得られなかったことが考えられます。</p>
<p>↓ DPO時のペア選択法によるスコアの違い (予備実験)<br>青線 (②) と 赤線 (③) の優劣はタスク依存だが、緑線 (①) は明確にスコアが低い傾向。</p>
<img src="/images/2025/20250716a/pair_selection_strategy.png" alt="pair_selection_strategy.png" width="979" height="382" loading="lazy">

<div class="note-container note-info"><span class="note-icon"></span><div>

<p>各responseは、報酬モデルで評価される前にルールベースのフィルタで事前に選別されます。そのため、生成時点では各instructionに必ず4件の候補が存在しますが、ペアデータ作成時には最もスコアの遠いもの = 4位であるとは限りません。<br>なお、選別の結果responseが1件しか残らなかった場合、該当のデータはSFTで用いることとしました。</p>
</div></div>

<h2 id="モデル評価における気づき・学び">モデル評価における気づき・学び</h2><p>続いて、モデル評価における気づきや学びを紹介していきます。</p>
<p>また、ここでは「今後の」モデル開発における有力な方向性にも触れたいと思います。</p>
<h3 id="コード補完タスクの評価は「怪しい」">コード補完タスクの評価は「怪しい」</h3><p>不穏な見出しですが、HumanEval, MultiPL-Eなどのコード補完タスクについては「同一の環境で比較実行した結果」以外の結果は比較不能だと思った方が良い、という話になります。</p>
<p>これには、temperature (サンプリング温度) などハイパーパラメータの問題もありますが、より大きな問題としてsanitizeの問題が挙げられます。コード補完の評価では、補完対象の関数 (やメソッド) のみを評価するため、モデル出力の不要な部分を後処理で削除する手順があり、この処理はsanitizeと呼ばれます。例えば Code Generation LM Evaluation Harness のHumanEvalでは、<code>\nclass</code>, <code>\ndef</code> 等いくつかのストップワードを定義し、これらが出現したら補完対象の関数は閉じているだろう (切り詰めてもよいだろう) という判断をしています。</p>
<p>一方で、プログラミング言語によってはこのような単純な文字列マッチでは対応が難しいこともあります。</p>
<p>これに対して EvalPlus では、より正確な評価に向けて、AST (抽象構文木) を用いた高度なsanitize処理を実装するなどの対応を取っています。</p>
<p>しかしながら、問題は <strong>sanitize処理が統一されていない</strong> という点です。たとえ同じ評価ベンチマークを用いていても、異なる処理を実装したライブラリで評価した結果を直接的に比較することは適切ではありません。さらにいえば、同一のライブラリであっても開発の過程で処理が変化している場合があり、より厳密にはcommit hashのレベルまで統一されて初めて比較可能となります。</p>
<p>実際に、主要なオープンソースモデルについて手元の環境で評価した際、公称値とは10ポイント以上異なるようなケースも確認されました。</p>
<h3 id="日本語-×-○○-に強いモデル構築は、特化モデルへの日本語学習が確かな方向性？">日本語 × ○○ に強いモデル構築は、特化モデルへの日本語学習が確かな方向性？</h3><p>ソフトウェア開発タスク (特にコーディング) 特化のQwen2.5-Coder (以後Qwen) と、汎用モデルであるLlama 3.1 (以後Llama) を比較すると、しばしば、”英語タスク指示におけるLlamaのスコア” &lt; “日本語タスク指示におけるQwenのスコア” であることが分かりました。</p>
<p>これはつまり、汎用モデルを起点に 日本語 × ○○ に強い、今回で言えば 日本語 × ソフトウェア開発 に強いモデルを目指そうとすると、もともと英語で出来ていたレベル以上の性能を日本語で達成しなければならない、というハードモードになってしまいます。</p>
<p>殊にCode LLMに関しては、Claude, GPT, Qwenをはじめとして世界中のモデルプロバイダがしのぎを削ってその性能を競い合っています。このような背景において、世界一のソフトウェア開発データを作ることは困難ですが、日本のLLM開発者・研究者にとって、世界一の日本語データを作ることはこの苦難と比べれば幾分容易いと言えます。</p>
<p>また、今回Python以外にも多くのプログラミング言語で評価したことで、&lt;10B (7～9B) の比較的小規模なモデルでは継続学習時に見ていない言語を忘れがちであるのに対し、70B等の大規模モデルでは学習していないことがビハインドになりにくいということも見えてきました。</p>
<p>これらの観測を踏まえると、コーディングや数学など、ドメインに特化した大規模モデルを起点に高品質な日本語を学習し、それらの蒸留を通して小規模モデルを作成することが有望な方向性であるように感じます。</p>
<h2 id="今後の検討課題">今後の検討課題</h2><p>ここでは、今回の取り組みの中では明らかに出来なかった今後の検討課題、今後明らかにしていくべきオープンクエスチョンに触れたいと思います。</p>
<h3 id="継続-事前学習においてlinterやformatterを活用すべきか">(継続) 事前学習においてlinterやformatterを活用すべきか</h3><p>PythonのPEP 8のように、プログラミング言語にはしばしば「こう書くべき」を定義したコーディング規約が存在します。linterやformatterは、ルール・スタイルに従わない不適切なコードの検知や修正をするツールであり、LLMの学習データに適用すれば自然と (一般的な) ベストプラクティスに沿った良いコードを出力することが期待されます。</p>
<p>しかしながら、実際の利用シチュエーションを想定すると「綺麗なコードしか見たことがない」というのは問題です。例えば、構文エラーについて一切知らないモデルは、構文エラーを含む入力に対して「バグを修正してください」というリクエストには応えられないでしょう。</p>
<p>「知らない」は回避しつつ、望まない出力は「出さない」を実現するために、静的解析ツールを含めた諸々のフィルタリングルールを如何に組み込むべきか、という点はさらなる検討が必要と考えます。</p>
<h3 id="LLMで作成したデータを-継続-事前学習-から取り込むべきか">LLMで作成したデータを (継続) 事前学習 から取り込むべきか</h3><p>今回、継続事前学習のフェーズでは、GitHubやCommonCrawlに由来するウェブ上の生データのクリーニングに注力し、instruction tuningで用いるようなタスク指示と応答のデータや、LLMで作成したデータ (疑似データ) は用いませんでした。</p>
<p>しかし、このような「LLM時代のデータ」を事前学習時に混ぜておくことが、”ベースモデル” のタスク遂行性能の向上につながることも明らかになっています。ここで疑問に上がるのは、この「タスク遂行性能の向上」が、SFT以降で獲得される能力の先取りに過ぎないのか、SFT (DPO) 後の最終到達点を上げるポテンシャルを有するものなのか、ということです。</p>
<p>今回の取り組みから得られたベースモデルのコード補完性能は、純粋なウェブ上のデータのクリーニングで到達できる性能としてはアッパーバウンドに近いと考えています。主要なオープンソースモデルを評価した結果、同規模のモデルで比較すると、Llama, gemma系のベースモデルのスコアは今回の学習モデルと同等 ～ やや学習モデルの方が優れている程度である一方、Qwen系のベースモデルはベースモデルのスコアが非常に高いことが分かりました。このことから、おそらくLlama, gemma系とQwen系はベースモデルに対するスタンスが異っており、Qwenはより早期から積極的に疑似データを採用していると推察されます。</p>
<p>instructモデルの性能で比較した時、コード補完タスクにおいては多くのケースでQwen系が優れています。</p>
<p>しかしながら、Llama, gemma系はベース → instructの伸び率がQwen系と比較して顕著に高く、ベースモデルでの両者の差ほど最終性能には差がないというのも事実です。また、最終性能の差は (SFT以降の) 事後学習データの差にも起因します。</p>
<p>仮に同じ事後学習データを用いたとして、事前学習時から疑似データを見た方が良いのか？は未だ明らかになっておらず、今後の調査に値すると考えます。</p>
<h2 id="おわりに">おわりに</h2><p>さて、ここまで2回に分けて「日本語とソフトウェア開発に特化した基盤モデル」Llama-3.1-Future-Code-Ja-8B の開発に関する取り組みをご紹介してきました。</p>
<p>本記事の内容が、LLMを作る・使う多くの方々に少しでも響いてくれたなら嬉しいです。</p>
<p>フューチャーではともに働くメンバーを募集しています。<br>自然言語処理 (NLP) 分野では基礎研究から最先端技術の社会実装まで、幅広いキャリアパスの選択肢をご用意しています。<br>ご興味を持っていただいた方は、ぜひ キャリア採用サイト からのご応募をお待ちしております。<br>また、本取り組みに関して詳細を聞きたい、フューチャーのNLP, AIの取り組みについて気軽に聞きたいという方は、以下もご活用ください。</p>
<ul>
<li>本取り組みについての問い合わせ : pj-geniac at future.co.jp</li>
<li>SAIG NLPチームへの問い合わせ : gr-saig-llm at future.co.jp</li>
</ul>
<p>ご覧いただきありがとうございました！</p>
]]></content>
    <summary type="html">GENIAC第2期事業にて採択された「日本語とソフトウェア開発に特化した基盤モデルの構築」プロジェクトに関する取り組み紹介、全2編の後編となります。モデルの技術的特徴に関するより込み入った内容や、取り組みの中では明らかに出来なかった今後の検討課題・オープンクエスチョンを共有します。</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="LLM" scheme="https://future-architect.github.io/tags/LLM/"/>
    <category term="Llama" scheme="https://future-architect.github.io/tags/Llama/"/>
    <category term="ソフトウェア" scheme="https://future-architect.github.io/tags/%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2/"/>
  </entry>
  <entry>
    <title>日本語×ソフトウェア開発に強いLLMの開発に取り組んだ挑戦者の備忘録 (前編)</title>
    <link href="https://future-architect.github.io/articles/20250715a/"/>
    <id>https://future-architect.github.io/articles/20250715a/</id>
    <published>2025-07-14T15:00:00.000Z</published>
    <updated>2025-07-14T15:00:00.000Z</updated>
    <author><name>藤井諒</name></author>
    <content type="html"><![CDATA[<p>AI Tips連載の4本目の記事となります。</p>
<h2 id="はじめに">はじめに</h2><p>こんにちは。Strategic AI Group (SAIG) の藤井です。</p>
<p>GENIAC第2期事業にて採択された「日本語とソフトウェア開発に特化した基盤モデルの構築」プロジェクトについて、開発の過程で得られた知見や学び、今後の課題を共有します。</p>
<p>みなさまご存じの通り、生成AI技術を取り巻く状況は日進月歩であり、殊にコーディングをはじめとしたソフトウェア開発ドメインでは、(人間を含む) 環境のフィードバックを受けながら自律的に問題を解決するエージェントなど日夜新たなツールが登場しています。その意味で「ソフトウェア開発×基盤モデル」は血の海であり、どのような方針・立ち位置を取るかという部分に非常に頭を悩ませました。</p>
<p>本稿は前後編の2本立てで、前編は開発したモデルの概要や開発の流れ、プロジェクト進行における反省点について、後編ではモデルの技術的特徴に関するより込み入った内容や、今後明らかにすべきオープンクエスチョンなど次のチャレンジャーに向けたメッセージを著したいと思います。</p>
<p>本プロジェクトで開発したモデル Llama-3.1-Future-Code-Ja-8B はHugging Faceにて公開しています。</p>
<p>開発のベースとした Llama-3.1 モデルに起因するもの以外では、利用に際する条件など設けておりませんので、ぜひ幅広く試していただけると開発者冥利に尽きます。</p>
<h2 id="GENIACプロジェクトについて">GENIACプロジェクトについて</h2><p>GENIAC (Generative AI Accelerator Challenge) は、経済産業省、および国立研究開発法人新エネルギー・産業技術総合開発機構 (NEDO) が実施する日本国内の生成AI開発力強化プロジェクトです。</p>
<p>これまでに2024年2月に開始した第1期、同年10月に開始した第2期の2サイクルが完了し、フューチャーは第2期公募において「日本語とソフトウェア開発に特化した基盤モデルの構築」のテーマで採択されました。</p>
<h2 id="開発の背景">開発の背景</h2><p>これまで、日本語に強みを持つとされたモデルでは、コーディングやそれを包含するソフトウェア開発のタスクにあまりスポットが当てられてきませんでした。</p>
<p>しかしながら、日本語で記載した仕様に沿って関数を設計するなど、国内では日本語をコンピュータと人間の橋渡しに使いたいというニーズは根強いと考えられます。また、コーディングに特化した大規模言語モデル (Code LLM) の文脈では、従来コードの途中までが与えられた状態での後方補完 (code completion) タスクが活発に取り組まれてきましたが、ソフトウェア開発においてはコードを理解して自然言語を生成するようなタスク、例えばコードレビューなども対象となり得ます。</p>
<p>そのようなタスクにおいて、自然な日本語を扱えることはメリットであり「日本語」と「ソフトウェア開発」の双方において強味を持つモデルの構想に至りました。</p>
<h2 id="開発の流れ">開発の流れ</h2><p>前述のとおり、本プロジェクトは2024年10月に開始し、翌年4月までの6か月間をメインに実施しました。</p>
<p>大規模言語モデル (LLM) の学習は主に、① 事前学習 ② 教師ありファインチューニング ③ 選好最適化 の3つの段階に分かれます。</p>
<p>なお、今回はスクラッチ (ランダムな初期値) からの学習ではなく、Meta社の Llama-3.1 8B モデルの重みをベースに学習したため、ステップ①は「継続」事前学習 (continual pretraining) となります。</p>
<p>今回のモデル開発では、結果的に2&#x2F;3以上の期間を継続事前学習、その後各1ヶ月程度で後続のフェーズを検討するというスケジュールとなりました。</p>
<h2 id="プロジェクト体制">プロジェクト体制</h2><p>GENIACでは週次・月次での事務局への進捗報告をはじめ、対社内外のやり取りが多く発生します。今回のプロジェクトでは社内事務局を設置することで、開発者がモデル開発に専念できる体制を整えていただけたのが良かったと感じます。しかしながら、開発側も決して潤沢なリソースがある状況ではありませんでした。特に、継続事前学習パートでは手を動かせる定常メンバが一人という状況にあり、打てる試行錯誤の数としても限られてしまったと感じます。</p>
<p>GENIACコミュニティでは採択事業者向けのイベントがしばしば企画されるのですが、第2期ではMeta社やAnthropic社など生成AI領域をリードする企業を訪問する米国視察イベントもありました。参加された方から伺ったところでは、そのような企業は数百人～数千人という規模でモデルを開発しているようです。各組織の限られたメンバーに知見が閉じているような状況ではいけない、というのも、今回開発したモデルの許容的ライセンスでの公開、および本記事の執筆に至った経緯です。</p>
<h2 id="各フェーズの概要">各フェーズの概要</h2><p>各フェーズの取り組みをダイジェストにてご紹介します。</p>
<p>より詳しい内容については、ぜひ後編をご覧ください。</p>
<h3 id="フェーズ1-継続事前学習">フェーズ1 : 継続事前学習</h3><p>ウェブ上のソースコード、日英テキストのデータクリーニングに注力し、ソースコード約205Bトークン、日英テキスト約86Bトークンの混合データで継続事前学習しました。</p>
<p>LLMの学習でしばしば見られるloss spikeは発生せず、以下のように安定した学習曲線で推移しました。</p>
<img fetchpriority="high" src="/images/2025/20250715a/wandb_log.jpg" alt="wandb_log.jpg" width="1200" height="612">

<p>データクリーニングでは非常に多くの困難がありましたが、GitHub由来のソースコードのみでも、堅実なフィルタリングルールの設計でベースモデルから一定のコード補完精度向上が見られるというのは学びでした。</p>
<p>フィルタの実装には、<code>tree-sitter-language-pack</code>, <code>lizard</code> といったOSSの静的解析ツールも積極的に採用したのですが、前者が内部で依存するparser (構文解析器) が数百万件に一件レベルで踏むバグで退勤前に仕込んだ処理が翌朝コケているのには参りました。</p>
<p>また、今回のモデル学習では、通常のNext Token Predictionに加えて、Fill-in-the-Middle (FIM) と呼ばれる学習手法を採用しました。</p>
<p>FIMとは「途中補完」を意味しますが、これはIDE上でカーソルの前後「双方」の文脈を考慮してカーソルの後ろ側を補完するかのように、前後の文脈から中間部分を予測するタスクとなります。</p>
<div class="note-container note-info"><span class="note-icon"></span><div>

<p>言語モデルのデファクトである Transformer のアーキテクチャには大きく、Encoder-Decoder型、Encoder型、Decoder型の3つのパターンが存在します。GPTやLlamaなどのモデルはDecoder型のアーキテクチャを取っており、これはそれ以前の文脈から次に続くトークン (≒ 言語モデルにとっての単語のようなもの) を予測するもの (Causal LM) です。<br>後方の文脈を考慮する方法として、補完箇所に <code>[FILL_ME]</code> 等を配置し、プロンプトで例示して穴埋めタスクとして解くというアプローチも考えられますが、今回「途中補完」は明確なユースケースのひとつとして想定されるため、明示的にサポートすることとしました。</p>
</div></div>

<h3 id="フェーズ2-教師ありファインチューニング-SFT">フェーズ2 : 教師ありファインチューニング (SFT)</h3><p>今回のモデル開発では、基本的な指示追従・汎用的なタスク遂行能力の獲得にはモデルマージを活用し、ソフトウェア開発関連タスクに特化したinstruction-tuningデータセットのみを用いて学習しました。</p>
<p>モデルマージ手法にも多種多様なものが提案されていますが、今回は Task Arithmetic と呼ばれるシンプルな手法を採用しました。この手法では、あるモデルと、そのモデルを何らかのタスクでファインチューニングしたモデルの2つのモデルに対して、ファインチューニング前後のパラメータの差分 (タスクベクトル) を「そのタスクを解く能力」と考えます。</p>
<p>そして、任意のモデルにこの「タスクベクトル」を足し合わせることで、後天的に (再学習することなく) 当該タスクを解く能力を身につけることを期待します。<br>今回は、継続事前学習後のモデルに「Llama 3.1 8B と Llama 3.1 8B Instruct の差分」を足し合わせることで、一定の指示追従能力が獲得されることを確認しました。</p>
<div class="note-container note-warn"><span class="note-icon"></span><div>

<p>厳密にはマージ元 &#x2F; 先のモデルは同一のアーキテクチャである必要があり、「任意」のモデル間でTask Arithmeticを適用できません。<br>また、一般には同一のベースモデル (今回の例では Llama 3.1 8B) からファインチューニングされたモデル間で上手く働くと考えられています。</p>
</div></div>

<p>instruction-tuningデータの作成には Magpie と呼ばれる手法を用いています。</p>
<p>Magpieについて簡単に説明すると、本来LLMの推論では “システムプロンプト” と “ユーザプロンプト” に続いて【アシスタントここから生成】 (※イメージ) のようなトリガーが与えられ、システムはAIアシスタントとしての応答を生成します。これを “システムプロンプト” に続けて【ユーザここから生成】と渡すことでユーザが聞きそうな指示文をモデル自身から引き出してしまおう、という考え方になります。</p>
<p>テクニカルな話をすれば、通常、SFTでは最後のアシスタント応答部分以外にはlossを流さないため、モデルはユーザ指示部分のNext Token Predictionを学習しておらず、Magpieが成立する理由は謎なのですが、シードデータを要することなく「無」から大量に、かつ定性的にも妥当な学習データを生成できる手法として今回の採用に至りました。</p>
<p>Magpieのデータ作成は比較的スケールし、Llama 3.3 70B Instruct で1万件のinstructionを作成後、各4件のresponseを生成するケースでは10 (H100) GPU時間以内で実現できます。 (執筆時点でAWS東京リージョンにおける p5.48xlarge &#x3D; H100×8 のオンデマンド単価は$68.80ですので、100ドル未満で1万件のデータを生成できるということになります)最終的に、今回の取り組みでは約1,200万件のinstruction-tuningデータを用いて学習しました。</p>
<p>なお、マージ直後のモデルについて、対話形式の入力では問題なくターンを終えることができましたが、FIM形式の入力では途中補完として妥当な出力を始めた後、必要な内容の出力が終わっても生成を止められないという現象が見られました。今回のモデル開発では、SFTの学習データにFIM形式のデータを少量混ぜることで対話能力とFIMを両立させることができました。</p>
<div class="note-container note-info"><span class="note-icon"></span><div>

<p>この現象に関する説明として、Llama 3.1では、事前学習時は <code>&lt;|end_of_text|&gt;</code>、SFT時は <code>&lt;|eot_id|&gt;</code> と異なるトークンを「区切り」に用いることから、FIMにおいて <code>&lt;|end_of_text|&gt;</code> で終わることをモデルが忘れてしまったものと考えています。</p>
</div></div>

<h3 id="フェーズ3-選好最適化">フェーズ3 : 選好最適化</h3><p>前述のMagpieで作成したinstruction-tuningデータセットの一部を用いて DPO (直接選好最適化) を行いました。</p>
<p>DPOではある入力 <em>prompt</em> に対して、良い出力 <em>chosen</em> と悪い出力 <em>rejected</em> のペアを用いて、<em>chosen</em> を出力しやすく、 <em>rejected</em> を出力しにくくするように重みを更新します。今回は作成したinstruction1件に対して4件のresponseを生成しましたが、各responseに Llama-3.1-Nemotron-70B-Reward-HF で報酬 (良さのスコア) を付与し、最もスコアの高いものを <em>chosen</em>、最もスコアの低いものを <em>rejected</em> として学習しました。</p>
<p>当初、DPOにはSFT用のデータと重複しないよう100万件のinstructionを取り分けて進めていましたが、コード補完ベンチマークのスコアをモニタリングした結果、学習初期にピークを迎えた後にスコアが低下する傾向が認められたため、最終的には10万件にサンプリングして学習することとしました。</p>
<div class="note-container note-info"><span class="note-icon"></span><div>

<p>全量で1000万件超のinstruction × 4件のresponseについて、そのすべてを大規模な報酬モデルで評価することは時間的制約から困難であったため、DPO用のサブセットに対してのみ70Bの報酬モデルで評価しました。<br>SFT用のサブセットでは軽量な ArmoRM-Llama3-8B-v0.1 (8B) で評価し、最もスコアの高かった1つを正解として学習しています。</p>
</div></div>

<h2 id="モデルの評価">モデルの評価</h2><p>ここでは、開発したモデルについて、いくつか特徴的な評価結果に触れ、そこから考えられる強み・可能性について考察したいと思います。</p>
<p>評価結果の完全な表は Hugging Faceのモデルページ をご参照ください。</p>
<p>以下は、日本語タスク指示文を含むコード補完ベンチマークの評価スコアです。</p>
<p>表中のスコアは <em>pass@1</em> という評価指標によるもので、「1度の生成で単体テストを通過する “機能的に正しい” コードを生成できる割合の期待値」です。この表の結果から、主要なプログラミング言語において、開発したモデルのコード補完性能は学習元の Llama-3.1-8B-Instruct を大きく上回り、同規模のオープンソースモデルの中では高い水準にあることが分かります。</p>
<p>しかしながら、ドメイン特化モデルである Qwen2.5-Coder との比較では劣後しており、コーディングタスクにおいて、当該モデルが非常に強力であることを改めて実感しました。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>モデル</th>
<th>Python</th>
<th>C++</th>
<th>C#</th>
<th>Java</th>
<th>JavaScript</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Llama-3.1-Future-Code-Ja-8B</strong></td>
<td><strong>0.6335</strong></td>
<td><strong>0.5267</strong></td>
<td><strong>0.3633</strong></td>
<td><strong>0.4696</strong></td>
<td><strong>0.5528</strong></td>
</tr>
<tr>
<td>Llama-3.1-8B-Instruct</td>
<td>0.5061</td>
<td>0.4391</td>
<td>0.2835</td>
<td>0.3753</td>
<td>0.4640</td>
</tr>
<tr>
<td>Llama-3.1-Swallow-8B-Instruct-v0.3</td>
<td>0.4213</td>
<td>0.3329</td>
<td>0.2456</td>
<td>0.3468</td>
<td>0.3112</td>
</tr>
<tr>
<td>Qwen2.5-7B-Instruct</td>
<td>0.6018</td>
<td>0.5106</td>
<td>0.3601</td>
<td>0.5044</td>
<td>0.5416</td>
</tr>
<tr>
<td>Qwen2.5-Coder-7B-Instruct</td>
<td>0.6695</td>
<td>0.6379</td>
<td>0.4601</td>
<td>0.5468</td>
<td>0.6696</td>
</tr>
<tr>
<td>Qwen3-8B</td>
<td>0.6256</td>
<td>0.5683</td>
<td>0.3709</td>
<td>0.4778</td>
<td>0.5814</td>
</tr>
<tr>
<td>gemma-2-9b-it</td>
<td>0.5549</td>
<td>0.4590</td>
<td>0.3608</td>
<td>0.4601</td>
<td>0.2863</td>
</tr>
</tbody></table></div>
<div class="note-container note-info"><span class="note-icon"></span><div>

<p>ベンチマークの一部 (JMultiPL-E) はフューチャーと東北大学の共同研究で作成されたものです。</p>
</div></div>

<p>代わって、以下は日本語を生成するタスクの評価スコアとなります。</p>
<p>ここで「日本語を生成する」とは、”A”, “B”, … , “ポジティブ”, “ネガティブ” のようなラベルではなくフリーフォームでの生成が求められるものと考えます。</p>
<p>表中には質問応答 (NIILC)、要約 (XL-Sum)、翻訳 (WMT)と性質の異なる3つのタスクのスコアを記載しました。</p>
<p>各タスクの評価指標については割愛しますが、いずれも「高いほど良い」指標であり、これらのタスクについてもまた、開発したモデルは学習元のモデルと比較して高い性能を達成していることがわかります。また、ここで特筆すべき点としてQwen系のモデルのパフォーマンスが相対的に低く留まっているという点が挙げられます。</p>
<p>これらの結果を総括すると、今回開発したモデルは <strong>高度なコード理解と日本語の生成の双方が求められるようなタスク</strong> 、すなわちコードレビューや仕様書の逆生成において光る可能性があるのではないかと考えています。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>モデル</th>
<th>NIILC</th>
<th>XL-SUM</th>
<th>WMT20 en-ja</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Llama-3.1-Future-Code-Ja-8B</strong></td>
<td><strong>0.5118</strong></td>
<td><strong>0.1779</strong></td>
<td><strong>0.2624</strong></td>
</tr>
<tr>
<td>Llama-3.1-8B-Instruct</td>
<td>0.4050</td>
<td>0.1486</td>
<td>0.2195</td>
</tr>
<tr>
<td>Llama-3.1-Swallow-8B-Instruct-v0.3</td>
<td>0.5805</td>
<td>0.1920</td>
<td>0.2818</td>
</tr>
<tr>
<td>Qwen2.5-7B-Instruct</td>
<td>0.3998</td>
<td>0.1690</td>
<td>0.2091</td>
</tr>
<tr>
<td>Qwen2.5-Coder-7B-Instruct</td>
<td>0.3045</td>
<td>0.1533</td>
<td>0.1816</td>
</tr>
<tr>
<td>Qwen3-8B</td>
<td>0.4197</td>
<td>0.1882</td>
<td>0.2450</td>
</tr>
<tr>
<td>gemma-2-9b-it</td>
<td>0.5306</td>
<td>0.0873</td>
<td>0.2305</td>
</tr>
</tbody></table></div>
<h2 id="プロジェクト進行における反省点">プロジェクト進行における反省点</h2><h3 id="試行錯誤の回数を増やすために">試行錯誤の回数を増やすために</h3><p>今回、モデルの学習には Megatron-LM を用いましたが、評価のためにはチェックポイントをHuggingface Transformersで扱える形式に変換 → 評価スクリプトを実行という手順を踏む必要がありました。</p>
<p>Megatronのチェックポイントはインスタンスに備え付けのNVMeストレージに一時保存後、自動的にs3にアップロードされるよう設定を組んでいたのですが、変換・評価については自動化の構成検討まで手が回らず期間を通して手動実行することとなってしまいました。毎回の作業はさほど大きくはないのですが、何度も発生することによるチリツモの影響、評価スコアが早く見えることによる判断早期化への期待から、腰を据えて学習に取り掛かる前に自動評価を整備すべきだったと感じます。</p>
<p>より小規模なモデルを用いる、学習途中で打ち切って判断するというのも魅力的なオプションに見えますが、個人的にはあまりおすすめしません。</p>
<p>というのも、学習初期は低空飛行であっても、最後まで伸びてこないかといえば必ずしもそうとは限りませんでした。小規模モデルや学習初期の観測だけでも、あるデータやハイパーパラメータが明確に「良い」ということは言えるかもしれません。しかしながら、それらが「良くない」、芽が出ない設定であるということは本番と同等の設定で、できるだけ最後まで学習して判断すべきだと感じました。そのためにも、繰り返し発生する定型作業の省力化は特に意識しておきたいポイントです。</p>
<p>↓ ベースモデル学習時の評価曲線<br>学習序盤ではベースライン (黄破線) を下回っている。</p>
<img src="/images/2025/20250715a/v8_plot.png" alt="v8_plot.png" width="1200" height="527" loading="lazy">

<h3 id="モデルに「色」を持たせるために">モデルに「色」を持たせるために</h3><p>今回の開発において頭を悩ませた点のひとつが <strong>「基盤モデルに何を求めるか」</strong> です。</p>
<p>ここまで読んでいただいた方は薄々お気づきかと思われますが、今回のモデルが「これまでのモデルに出来なかった新たな領域 (タスク) 」に強みを持つかといえばそれはNoです。</p>
<p>先述の通り、ソフトウェア開発においてコーディングタスクは氷山の一角に過ぎず、Code LLMの切り込む余地はまだまだ残されているはずです。しかしながら、レビュータスクひとつを例にとっても、基盤モデルが持っていて嬉しい特徴とは何か、というのは突然ひらめくものではありませんでした。もちろん、社内で日々行われるレビューの情報をin-outに学習すれば、社内で使う分にはそれらしいレビューを生成できるかもしれません。</p>
<p>一方で、レビューの方法、仕様書の書き方などは、全世界的に標準が定まっているものではなく、それらに対するある1つの「方言」である社内 (組織内) 標準はファインチューニングで学ぶべき特徴に思われます。そのため、今回は「日本語」や「ソフトウェア開発」の領域でこれまでデファクトとして評価されてきたベンチマークを評価指標に定めて開発を推し進めていくこととなりました。</p>
<p>しかし、このようなタスクを想定した時、基盤モデルにできることはないのか、といえばこれもNoであると考えます。目下モデル開発の終了を受けて、今回のモデルを含めた複数のLLMを社内のコードレビュー補助に使えないかという実応用の検討が進んでいます。その過程で実際にどのような使い方が想定されるのかを見れば、例えば「指摘に該当する行番号を指摘内容と合わせて出力したいのだな」といったニーズをくみ取ることができ、パッチファイルのようなデータを重く学習するなど一定の工夫は取れたと思われます。石橋を叩いて渡る慎重さも必要ですが、殊にLLM時代においては、 <strong>積極的なアルファ・ベータテストとFBを回していくべきだった</strong> と考えます。</p>
<h2 id="おわりに">おわりに</h2><p>今回は「日本語とソフトウェア開発に特化した基盤モデル」Llama-3.1-Future-Code-Ja-8B の開発について、その概観をお伝えしました。</p>
<p>個人としても、組織としても初めての基盤モデル開発プロジェクトであり、振り返ってみると反省すべき点も多かったと感じます。<br>しかし、こうして書き起こしてみると、どうすればより価値のあるものを作れるか、半年間1つのモデルと向き合うことで得られた学びも多々あったと実感しました。</p>
<p>フューチャーではともに働くメンバーを募集しています。</p>
<p>自然言語処理 (NLP) 分野では基礎研究から最先端技術の社会実装まで、幅広いキャリアパスの選択肢をご用意しています。<br>ご興味を持っていただいた方は、ぜひ キャリア採用サイト からのご応募をお待ちしております。</p>
<p>後編では、より詳細な技術的特徴・工夫や、今回の取り組みでは明らかに出来なかった今後の検討課題などをご紹介できればと思いますので、もしよろしければそちらもぜひご覧ください。<br>ありがとうございました！</p>
]]></content>
    <summary type="html">GENIAC第2期事業にて採択された「日本語とソフトウェア開発に特化した基盤モデルの構築」プロジェクトについて、開発の過程で得られた知見や学び、今後の課題を共有したいと思います。</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="LLM" scheme="https://future-architect.github.io/tags/LLM/"/>
    <category term="Llama" scheme="https://future-architect.github.io/tags/Llama/"/>
    <category term="ソフトウェア" scheme="https://future-architect.github.io/tags/%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2/"/>
  </entry>
  <entry>
    <title>Kubernates✖️MLflow✖️GCPで簡単にAIモデル公開</title>
    <link href="https://future-architect.github.io/articles/20250701a/"/>
    <id>https://future-architect.github.io/articles/20250701a/</id>
    <published>2025-06-30T15:00:00.000Z</published>
    <updated>2025-06-30T15:00:00.000Z</updated>
    <author><name>大前七奈</name></author>
    <content type="html"><![CDATA[<img fetchpriority="high" src="/images/2025/20250701a/image.png" alt="image.png" width="1200" height="449">

<p>こんにちは！Energy Transformation Groupの大前七奈です。</p>
<p>機械学習モデルを本番環境で運用する際、スケーラビリティや管理のしやすさは重要です。MLflowのFastAPIによるデプロイは手軽ですが、大規模運用には不向きな場合があります。</p>
<p>本記事では、MLflowで管理されたモデルを、Kubernetes上で動作する高機能なMLモデルサービング基盤KServeにデプロイする方法を解説します。ローカル環境でKubernetesを簡単に扱えるminikubeを用いた構築手順から、Google Kubernetes Engine (GKE) へのデプロイ、さらにはCI&#x2F;CDへの応用まで、実践的なMLOpsの構築方法を詳しく紹介します。</p>
<h2 id="バージョン">バージョン</h2><p>本記事で利用を想定しているツールのバージョンは以下の通りです。</p>
<ul>
<li>minikube: v1.36.0</li>
<li>mlflow: v3.1.1</li>
<li>kserve: v0.13.0</li>
</ul>
<h2 id="なぜFastAPIでなく、Kubernates">なぜFastAPIでなく、Kubernates?</h2><p>MLflowの公式サイトでも以下のように書かれています。</p>
<blockquote>
<p>MLflow provides an easy-to-use interface for deploying models within a FastAPI-based inference server. You can deploy the same inference server to a Kubernetes cluster by containerizing it using the mlflow models build-docker command. However, this approach may not be scalable and could be unsuitable for production use cases. FastAPI is not designed for high performance and scale (why?), and also manually managing multiple instances of inference servers is backbreaking.</p>
</blockquote>
<p>端的にいうと、<strong>MLflowのFastAPIによるモデルデプロイは手軽ですが、本番環境には不向きです。FastAPIは大規模な利用を想定しておらず、スケーラビリティやサーバー管理に課題があるためです。</strong></p>
<h2 id="minikubeとKubernatesの関係">minikubeとKubernatesの関係</h2><p>Kubernates (k8s) は、コンテナ化されたアプリケーションのデプロイ、スケーリング、管理を自動化するためのオープンソースプラットフォームです。本番環境で広く使われていますが、学習や開発のために手元で動かすには、セットアップが複雑です。</p>
<p>そこで登場するのが minikube です。minikubeは、自分のPC（Windows, macOS, Linux）上に、仮想的に単一ノードのKubernatesクラスタを簡単に構築できるツールです。Kubernatesの機能を学習したり、アプリケーションをデプロイしてテストしたりするのに最適です。つまり、<strong>「minikubeは、Kubernatesを手軽に試すためのローカル環境構築ツール」</strong>だと理解すると分かりやすいでしょう。</p>
<h2 id="スケーラブルにモデル公開できるのがKserve">スケーラブルにモデル公開できるのがKserve</h2><p>KServeはKubernetes上で動作する、本番環境向けの高度なMLモデルサービング基盤です。サーバーレスでの自動スケールやカナリアリリースといった機能を提供し、単純なデプロイ方法では難しい拡張性や安定性を実現します。</p>
<p>前項で話したMLflowの標準デプロイ機能は本番の大規模な負荷には向いていませんので、そこで、MLflowでバージョン管理されたモデルを、本番のサービング基盤としてKServeにデプロイするという連携が極めて有効です。これにより、開発・管理はMLflow、本番運用はKServeと、両者の強みを活かした堅牢なMLOpsを構築できます。</p>
<p>以下は本番環境のGKEにデプロイしたあとの利用されるイメージです。</p>
<img src="/images/2025/20250701a/image_2.png" alt="image.png" width="720" height="431" loading="lazy">

<h2 id="構築手順-MacOS版">構築手順(MacOS版)</h2><h3 id="1-PCにツールをインストール">1. PCにツールをインストール</h3><figure class="highlight sh"><figcaption><span>install.sh</span></figcaption><table><tr><td class="code"><pre><span class="line">brew install minikube  <span class="comment"># クラスタ構築用</span></span><br><span class="line">brew install kubectl  <span class="comment"># Kubernates操作用</span></span><br></pre></td></tr></table></figure>

<h3 id="2-pipでmlflowをインストール">2. pipでmlflowをインストール</h3><figure class="highlight sh"><figcaption><span>install.sh</span></figcaption><table><tr><td class="code"><pre><span class="line">pip install mlflow</span><br></pre></td></tr></table></figure>

<h3 id="3-ベストモデルの訓練後、MLserverでローカルテスト">3. ベストモデルの訓練後、MLserverでローカルテスト</h3><p>GCPで訓練する場合、直接にステップ５へ飛ばしていただいてOKです。</p>
<figure class="highlight sh"><figcaption><span>serve.sh</span></figcaption><table><tr><td class="code"><pre><span class="line"><span class="comment"># ローカルのPort1234で推論サーバーを立ち上げる</span></span><br><span class="line">mlflow models serve -m models:/&#123;my_model_id&#125; -p 1234 --enable-mlserver</span><br><span class="line"></span><br><span class="line"><span class="comment"># テスト</span></span><br><span class="line">curl -X POST -H <span class="string">&quot;Content-Type:application/json&quot;</span> --data <span class="string">&#x27;&#123;&quot;inputs&quot;: [[14.23, 1.71, 2.43, 15.6, 127.0, 2.8, 3.06, 0.28, 2.29, 5.64, 1.04, 3.92, 1065.0]]&#125;&#x27;</span> http://127.0.0.1:1234/invocations</span><br><span class="line"></span><br><span class="line">&#123;<span class="string">&quot;predictions&quot;</span>: [-0.03416275504140387]&#125;</span><br></pre></td></tr></table></figure>

<h3 id="3-ローカルクラスタにkserveをインストール">3. ローカルクラスタにkserveをインストール</h3><figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">minikube start</span><br><span class="line">kubectl apply -f https://github.com/kserve/kserve/releases/download/v0.13.0/kserve.yaml</span><br></pre></td></tr></table></figure>

<div class="note-container note-warn"><span class="note-icon"></span><div>

<p><strong>注意</strong></p>
<p>公式サイトではkindを利用してインストールすることをすすめしていますが、今回minikube上で動かすには、minikubeの作法に合わせた手順（例えば、minikubeのDockerデーモンを利用してイメージをビルドする、またはyamlで構築するなど）に読み替える必要がありました。</p>
</div></div>

<h3 id="4-ローカルDockerとminikubeでテストデプロイ">4. ローカルDockerとminikubeでテストデプロイ</h3><p>KServeにモデルをデプロイするための定義ファイル（マニフェスト）を用意します。以下がDockerを利用したときの書き方となります。</p>
<figure class="highlight yaml"><figcaption><span>inferenceservice.yaml（ローカルDocker用）</span></figcaption><table><tr><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">&quot;serving.kserve.io/v1beta1&quot;</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">&quot;InferenceService&quot;</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">&quot;my-model&quot;</span></span><br><span class="line">  <span class="attr">namespace:</span> <span class="string">&quot;mlflow-kserve-test&quot;</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">predictor:</span></span><br><span class="line">    <span class="attr">containers:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">&quot;my-model&quot;</span></span><br><span class="line">        <span class="attr">image:</span> <span class="string">&quot;&#123;docker_user_name&#125;/my-model&quot;</span></span><br><span class="line">        <span class="attr">ports:</span></span><br><span class="line">          <span class="bullet">-</span> <span class="attr">containerPort:</span> <span class="number">8080</span></span><br><span class="line">            <span class="attr">protocol:</span> <span class="string">TCP</span></span><br><span class="line">        <span class="attr">env:</span></span><br><span class="line">          <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">PROTOCOL</span></span><br><span class="line">            <span class="attr">value:</span> <span class="string">&quot;v2&quot;</span></span><br></pre></td></tr></table></figure>

<p>以下のコマンドでデプロイできます。</p>
<figure class="highlight console"><figcaption><span>deploy_docker.sh</span></figcaption><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">イメージをビルド、Dockerにプッシュする</span></span><br><span class="line">mlflow models build-docker -m models:/&#123;my_model_id&#125; -n my-model --enable-mlserver</span><br><span class="line">docker push my-model</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">kubectlの接続先を確認</span></span><br><span class="line">kubectl config current-context</span><br><span class="line"><span class="meta prompt_">&gt; </span><span class="language-bash">minikube</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">ローカルminikubeで定義ファイルを適用する</span></span><br><span class="line">kubectl create namespace mlflow-kserve-test</span><br><span class="line">kubectl apply -f inferenceservice.yaml -n mlflow-kserve-test</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">エンドポイントのURLを確認</span></span><br><span class="line">kubectl get inferenceservice mlflow-model -n mlflow-kserve-test</span><br></pre></td></tr></table></figure>

<h3 id="5-GCSにアップロード、Google-Kubernate-Engine-GKE-へデプロイ">5. GCSにアップロード、Google Kubernate Engine(GKE)へデプロイ</h3><p>CLI経由してGKEにも直接にデプロイできます。Kserve定義ファイルの書き方は少々先のものと異なります。</p>
<figure class="highlight yaml"><figcaption><span>inferenceservice.yaml（GCP用）</span></figcaption><table><tr><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">&quot;serving.kserve.io/v1beta1&quot;</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">&quot;InferenceService&quot;</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">&quot;my-model&quot;</span></span><br><span class="line">  <span class="attr">namespace:</span> <span class="string">&quot;mlflow-kserve-test&quot;</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">predictor:</span></span><br><span class="line">    <span class="attr">model:</span></span><br><span class="line">      <span class="attr">modelFormat:</span></span><br><span class="line">        <span class="attr">name:</span> <span class="string">mlflow</span></span><br><span class="line">      <span class="attr">protocolVersion:</span> <span class="string">v2</span></span><br><span class="line">      <span class="attr">storageUri:</span> <span class="string">&quot;gs://&#123;gcp_project_id&#125;-models/artifacts&quot;</span></span><br></pre></td></tr></table></figure>

<p>定義ファイルを用意できましたら、必要なモデルArtifactをGcloud Storageにアップロードし、デプロイします。GKEがGCSからモデルをダウンロードして推論サーバーを構築してくれます。</p>
<figure class="highlight console"><figcaption><span>deploy_gke.sh</span></figcaption><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">MLflowで生成されたモデルartifactsをGCSにアップロード</span></span><br><span class="line">gsutil cp -r models/&#123;model_id&#125; gs://&#123;gcp_project_id&#125;_mlflow_models/</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">GKEクラスタを作成</span></span><br><span class="line">gcloud container clusters create my-model</span><br><span class="line"><span class="meta prompt_">&gt; </span><span class="language-bash">Creating cluster my-model <span class="keyword">in</span> asia-northeast1-a... Cluster is being configured...⠏</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">Kserveをインストールする</span></span><br><span class="line">kubectl apply -f https://github.com/kserve/kserve/releases/download/v0.13.0/kserve.yaml</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">kubectlの接続先を確認</span></span><br><span class="line">kubectl config current-context</span><br><span class="line"><span class="meta prompt_">&gt; </span><span class="language-bash">gke_research-426801_asia-northeast1-a_my-model</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">GKEで定義ファイルを適用する</span></span><br><span class="line">kubectl create namespace mlflow-kserve-test</span><br><span class="line">kubectl apply -f inferenceservice.yaml -n mlflow-kserve-test</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">エンドポイントのURLを確認</span></span><br><span class="line">kubectl get inferenceservice mlflow-model -n mlflow-kserve-test</span><br></pre></td></tr></table></figure>

<div class="note-container note-info"><span class="note-icon"></span><div>

<p>もし、gke-gcloud-auth-pluginがないと怒られたら、<code>gcloud components install gke-gcloud-auth-plugin</code>でインストールしましょう。それでも怒られたら、gcloud sdkのパスが通っていない可能性あるので、<code>export PATH=&quot;/path/to/google-cloud-sdk/bin:$PATH&quot;</code>でパスを通してあげましょう。</p>
</div></div>

<p>以上がデプロイの流れとなりました！</p>
<p>さらなる発展として、<code>deploy_gke.sh</code>のbashスクリプトを、GitHub actionsに組み込めば、リポジトリに新しいモデルがプッシュされたら、自動でGCSにアップロードされ、KServeにデプロイされます。これは、MLOpsにおけるCI&#x2F;CD（継続的インテグレーション&#x2F;継続的デリバリー）の基本的な流れです。</p>
<h2 id="あとがき">あとがき</h2><p>前職(メーカのデータサイエンティスト)の経験上、モデルのバージョン管理やデプロイ管理が非常に煩雑な印象でしたが、記事を通じてMLflowのモデル管理ダッシュボードの便利さ・kubernateへのデプロイドの手軽さなどMLOps周りのエコシステムをしっかり体感できて感動しました。</p>
<p>また、現在主にデータ基盤構築プロジェクトのアーキテクトとしてつとめていますが、データを使ってモデルを構築したあとのMlOpsを触る機会がなく、今回記事を書かせてもらうのを機に、触りたかったGKEを触れてとても大満足でした。今回の記事は、書き手にとってブログ記事を書く価値と意義を改めて体感できた一本です。</p>
<h2 id="番外編">番外編</h2><h3 id="番外編１：minikubeとkind：なにか違うの？">番外編１：minikubeとkind：なにか違うの？</h3><p>kind (Kubernetes IN Docker) もminikubeと同様にローカルでKubernatesクラスタを構築するツールですが、いくつかの違いがあります。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>特徴</th>
<th>minikube</th>
<th>kind</th>
</tr>
</thead>
<tbody><tr>
<td>主な用途</td>
<td>開発、学習、Kubernatesの機能を試す</td>
<td>CI&#x2F;CDパイプラインでのテスト、マルチノードクラスタのシミュレーション</td>
</tr>
<tr>
<td>仕組み</td>
<td>仮想マシン（Hyper-V, VirtualBoxなど）またはDockerコンテナ上にクラスタを構築</td>
<td>各ノードをDockerコンテナとして実行</td>
</tr>
<tr>
<td>手軽さ</td>
<td>ダッシュボードやIngressなどのアドオンが豊富で、コマンド一つで有効化できるため、初心者にも扱いやすい</td>
<td>よりKubernatesのコアな機能に近く、設定の自由度が高い。CI環境での利用実績が豊富</td>
</tr>
</tbody></table></div>
<h3 id="番外編２：kubeflowとMLflow：なにか違うの？">番外編２：kubeflowとMLflow：なにか違うの？</h3><p>どちらもMLOps（機械学習基盤）のための強力なツールですが、スコープと目的が異なります。</p>
<div class="scroll"><table>
<thead>
<tr>
<th></th>
<th>MLflow</th>
<th>kubeflow</th>
</tr>
</thead>
<tbody><tr>
<td>用途</td>
<td>「機械学習のライフサイクル管理」に特化したツール</td>
<td>「Kubernates上でMLワークフローを構築・実行するための総合プラットフォーム」</td>
</tr>
<tr>
<td>機能</td>
<td>「実験の追跡（Tracking）」「モデルのパッケージング（Projects）」「モデルの管理・共有（Models）」「モデルのデプロイ」</td>
<td>データの準備、モデルのトレーニング、パイプラインの構築、モデルのサービングまで</td>
</tr>
<tr>
<td>特徴</td>
<td>特定のプラットフォームに依存せず、軽量で導入しやすいのが特徴です。個人や小規模チームでの実験管理から始めるのに最適</td>
<td>MLflowをコンポーネントとして内包することも可能です。大規模でスケーラブルな本番環境をKubernatesで構築する場合に適する</td>
</tr>
</tbody></table></div>
<p>一言でいうと、MLflowが「実験とモデル」の管理ツールであるのに対し、Kubeflowは「ML全体のワークフロー」をKubernates上で動かすための基盤です。 今回の構成では、Kubernates上でモデルをサービングする部分にKServeを使い、モデル管理の部分でMLflowの思想を取り入れています。</p>
<h2 id="参考">参考</h2><ul>
<li>Develop ML model with MLflow and deploy to Kubernetes | MLflow</li>
<li>Kubeflow: How to Install and Launch Kubeflow on your Local Machine | Towards Data Science</li>
<li>TensorFlow Extended、Vertex AI Pipelines、Cloud Build を使用した MLOps のアーキテクチャ</li>
<li>Kserve | GKE AI Labs</li>
</ul>
]]></content>
    <summary type="html">機械学習モデルを本番環境で運用する際、スケーラビリティや管理のしやすさは重要です。MLflowのFastAPIによるデプロイは手軽ですが、大規模運用には不向きな場合があります。本記事では、MLflowで管理されたモデルを、Kubernetes上で動作する高機能なMLモデルサービング基盤KServeにデプロイする方法を解説します。</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="CNCF" scheme="https://future-architect.github.io/tags/CNCF/"/>
    <category term="GoogleCloud" scheme="https://future-architect.github.io/tags/GoogleCloud/"/>
    <category term="MLOps" scheme="https://future-architect.github.io/tags/MLOps/"/>
    <category term="MLflow" scheme="https://future-architect.github.io/tags/MLflow/"/>
    <category term="Minikube" scheme="https://future-architect.github.io/tags/Minikube/"/>
  </entry>
  <entry>
    <title>初めてのQuickSight</title>
    <link href="https://future-architect.github.io/articles/20250513a/"/>
    <id>https://future-architect.github.io/articles/20250513a/</id>
    <published>2025-05-12T15:00:00.000Z</published>
    <updated>2025-05-12T15:00:00.000Z</updated>
    <author><name>板垣翼</name></author>
    <content type="html"><![CDATA[<img fetchpriority="high" src="/images/2025/20250513a/thumnail.png" alt="thumnail.png" width="1200" height="500">

<h2 id="はじめに">はじめに</h2><p>初めまして、製造エネルギー事業部の板垣です。先日アコギを購入し学生時代ぶりにギター再燃中です。</p>
<p>春の入門祭り2025の15本目の記事ですが、技術ブログの投稿自体が初めてなためやや緊張しています。温かく見守っていただけますと幸いです。</p>
<p>Amazon QuickSightの入門記事です。最近、業務で触れる機会があったので、これから入門される方々の取っ掛かりとなるような内容になるようまとめます。</p>
<h2 id="QuickSightとは">QuickSightとは</h2><p>QuickSightは、AWSが提供しているBI（Business Intelligence）サービスです。</p>
<p>BIで表示するデータの接続先には、AWS内の各種サービス（S3やRDSなど）に加え、企業のデータベースや外部サービス（Google BigQuery、Snowflakeなど）幅広く選択できます<sup id="fnref:1">1</sup>。目的に応じて、AWS内外のデータを収集／整形し、様々な情報を可視化できます。</p>
<p>QuickSightには様々なユーザを追加できます。AWSのルートユーザやIAMユーザだけでなく（企業の開発者やベンダーなど想定）や、例えばメール招待によって外部ユーザ（企業の経営者や顧客などを想定）を追加ことができます。各ユーザには個別のロールを付与できます。利用費はロール毎に異なり、2025年5月時点のロール別の料金は以下のようになっていました<sup id="fnref:2">2</sup>。</p>
<div class="scroll"><table>
<thead>
<tr>
<th align="left">ロール</th>
<th align="left">1ユーザあたりの料金［USD&#x2F;月］</th>
</tr>
</thead>
<tbody><tr>
<td align="left">作成者（Author）</td>
<td align="left">24</td>
</tr>
<tr>
<td align="left">作成者プロ（Author Pro）</td>
<td align="left">50</td>
</tr>
<tr>
<td align="left">閲覧者（Reader）</td>
<td align="left">3</td>
</tr>
<tr>
<td align="left">閲覧者プロ（Reader Pro）</td>
<td align="left">20</td>
</tr>
</tbody></table></div>
<p>また、Enterprise版ではグループや名前空間といった権限管理周りの仕組みが用意されているため、多様なユースケースに対応できます。</p>
<h2 id="さっそく触ってみる">さっそく触ってみる</h2><p>データを「収集／整形／可視化」する部分のみに注目すると、QuickSightは以下のような要素で構成されています。</p>
<p>各要素の正確な説明はドキュメントに記載されていますが、ここではざっくりなイメージで説明しています。</p>
<p>また、図中の「テンプレート」については後ほど説明します。</p>
<ol>
<li><strong>データソース</strong>：QuickSightと外部データとの窓口。外部データにアクセスするための設定などを定義して利用します</li>
<li><strong>データセット</strong>：可視化の目的に応じて加工されたデータ集合。データ集合どうしを組み合わせて利用が可能です</li>
<li><strong>分析</strong>：データセットを元に様々なビジュアル（グラフや指標など）を作成しまとめたものです</li>
<li><strong>ダッシュボード</strong>：名前の通りですが、分析で可視化した内容を参照だけできるようにしたものです</li>
<li><strong>SPICE</strong>：可視化を効率的に実現するためのQuickSight専用の機構。データセットで定義されたデータを保持したり（外部データへの直接問い合わせなどが無くなる）、分析やダッシュボードの内部で走る計算を効率的に実現しているようです。SPICEは「Super-fast, Parallel, In-memory Calculation Engine」の略です</li>
</ol>
<img src="/images/2025/20250513a/QuickSightの構成イメージ.png" alt="QuickSightの構成イメージ" width="1162" height="894" loading="lazy">

<p>ここではQuickSightの画面上での利用イメージを説明するため「データソース／データセットの準備からダッシュボードの公開まで」の一連の流れを順に説明します。</p>
<p>なお、作業するには作成者または管理者相当のロール権限が必要になりますのでご注意ください。ちなみに今回は、管理者ロールで実施しています。</p>
<h3 id="0-アカウントの作成とユーザの登録">0. アカウントの作成とユーザの登録</h3><p>ダッシュボード作成の前に、QuickSightアカウントとユーザの登録が必要です（既に完了していればこちらの手順はスキップ可能です）。</p>
<p>AWSアカウントがない場合はAWSアカウントを作成した上で、以下のようにAWSのコンソール画面から検索することでQuickSightのアカウント作成画面へ遷移できます。</p>
<img src="/images/2025/20250513a/検索結果.png" alt="検索結果" width="981" height="379" loading="lazy">

<p>アカウント作成画面に進むと以下のような画面になる想定です（2025年5月時点）。</p>
<img src="/images/2025/20250513a/アカウント作成1.png" alt="アカウント作成1" width="1200" height="606" loading="lazy">

<p>そのまま「QuickSightにサインアップ」へ進むと、アカウント作成に必要な情報を求めらるので入力して進めましょう。</p>
<p>Lambdaのような他のAWSリソースと異なり、QuickSightアカウントはAWSアカウントに1つしか作ることができません。アカウントを複数の方が利用する場合などは、アカウント名などの設定内容については予め相談しておくと良いと思います（もちろん後から変更可能な設定もあります）。</p>
<img src="/images/2025/20250513a/アカウント作成2.png" alt="アカウント作成2" width="1200" height="574" loading="lazy">

<p>入力を終え、無事作成が完了するとQuickSightの画面に遷移できます。</p>
<img src="/images/2025/20250513a/アカウント作成3.png" alt="アカウント作成3" width="1200" height="548" loading="lazy">

<p>アカウント作成後は、同じAWSアカウント内のルートユーザやIAMユーザであればそのままコンソール画面からログインできます（初回ログイン時だけ確認のためのダイアログ画面は表示されます）。</p>
<p>また前述の通り外部のユーザも管理者からの招待を受けることでログイン可能です。いずれも初回のログイン以降、ユーザロールに応じて前述したような料金が発生しますのでユーザの管理は気を付ける必要があります。</p>
<h3 id="1-データソース／データセットを準備する">1. データソース／データセットを準備する</h3><p>自身のユーザでQuickSightにログインした後、以下の画面に遷移するので画面左側のデータセット項目を選択した後、右上にある「新しいデータセット」を押します。</p>
<img src="/images/2025/20250513a/サインイン後の画面.png" alt="サインイン後の画面" width="1200" height="739" loading="lazy">

<p>データソース（新規または既存）を選択する画面に遷移するので、目的のデータソースを選択し、必要があれば設定（データベースなら接続先の設定など）を行います。</p>
<p>ここでは単純な「ファイルのアップロード」による方法で新規データセットを作成します。取り込むデータは、2014年4月から2025年3月までの東京の日別の平均気温で、気象庁のページからダウンロードし、整形したものです。</p>
<p>データソースの各種設定が最後まで進むと以下のようなダイアログが出るため「データの編集&#x2F;プレビュー」に進みます。</p>
<img src="/images/2025/20250513a/データソースの選択.png" alt="データソースの選択" width="1200" height="976" loading="lazy">

<p>進むと以下のような画面に遷移します。ここで、この後の作業のために画像の「計算フィールドを追加」からデータの取込元に存在しない項目（日付）を用意します。</p>
<p>計算フィールドは、既存のデータ項目と演算子、専用の関数などを利用することでデータセットに新しいデータ項目を追加できる仕組みです。</p>
<img src="/images/2025/20250513a/データセットの準備1.png" alt="データセットの準備1" width="1200" height="788" loading="lazy">

<p>計算フィールドの編集画面で、項目名と以下の計算式を入力し画像右上の「保存」で追加します。</p>
<p>計算式の詳しい説明はQuickSightのユーザガイドなどが参考になりますが、表計算アプリ（ExcelやGoogleスプレッドシートなど）を利用されたことのある方であれば、セルに入力する計算式のようなイメージに近いかと思います。</p>
<figure class="highlight txt"><table><tr><td class="code"><pre><span class="line">parseDate(concat(toString(&#123;年&#125;), &quot;/&quot;, toString(&#123;月&#125;), &quot;/&quot;, toString(&#123;日&#125;)), &quot;yyyy/MM/dd&quot;)</span><br></pre></td></tr></table></figure>

<img src="/images/2025/20250513a/データセットの準備2.png" alt="データセットの準備2" width="1200" height="894" loading="lazy">

<p>完了すると以下の画面に戻るので画像右上の「保存して公開」を押します。</p>
<img src="/images/2025/20250513a/データセットの準備3.png" alt="データセットの準備3" width="1200" height="838" loading="lazy">

<p>最初のデータセット一覧画面に戻り、新しくデータセットが作成されていればデータセットの準備は完了です。</p>
<img src="/images/2025/20250513a/データセットの準備4.png" alt="データセットの準備4" width="1200" height="736" loading="lazy">

<h3 id="2-分析を作成する">2. 分析を作成する</h3><p>用意したデータセットを元に分析を作成します。</p>
<p>先ほどのデータセット一覧画面に新しく作成されたデータセットの右端から「分析の作成」に進みます。</p>
<img src="/images/2025/20250513a/分析の作成1.png" alt="分析の作成1" width="1200" height="757" loading="lazy">

<p>分析は以下のような画面で作成することになります。画像左側に見えているのが先ほど準備したデータセットです（見てわかる通り計算フィールドはここからでも追加可能です）。今回は特に実施していませんが、複数のデータセットを分析に追加も可能です。</p>
<img src="/images/2025/20250513a/分析の作成2.png" alt="分析の作成2" width="1200" height="723" loading="lazy">

<p>試しに、先ほど準備した計算フィールド（日付）と平均気温を使ってグラフを作成してみます。</p>
<p>ビジュアル（折れ線グラフや円グラフなど、表示したいグラフの種類）を選択し、データセットから表示する項目を選択することで簡単にグラフを描画できます。</p>
<img src="/images/2025/20250513a/分析の作成3.png" alt="分析の作成3" width="1200" height="716" loading="lazy">

<p>適宜見た目を整え、準備したデータセットを元に、目的に応じた内容を分析に用意していきます。</p>
<p>今回は最終的に以下のようになりました。気温の表示期間をユーザが自由に調整できるよう「コントロール（画像上側に見える入力パラメータのような欄）」という機能を利用していますが、他にも様々な機能があるので実際に触ってみると面白いかと思います。</p>
<img src="/images/2025/20250513a/分析の作成4.png" alt="分析の作成4" width="1200" height="982" loading="lazy">

<h3 id="3-ダッシュボードを公開する">3. ダッシュボードを公開する</h3><p>ダッシュボードの公開は簡単です。先ほど作成した分析の画面から右上にある「公開」ボタンからダッシュボードを公開できます。</p>
<img src="/images/2025/20250513a/ダッシュボードの公開1.png" alt="ダッシュボードの公開1" width="1200" height="771" loading="lazy">

<p>以下の一覧画面でも作成されたことが確認できます。</p>
<img src="/images/2025/20250513a/ダッシュボードの公開2.png" alt="ダッシュボードの公開2" width="1200" height="606" loading="lazy">

<p>分析なども同じですが、作成したダッシュボードは、QuickSightの他ユーザやグループなどへ共有できます。</p>
<h2 id="もう少し踏み込んでみる">もう少し踏み込んでみる</h2><p>他のAWSサービスと同様にQuickSightではいくつかのAPIが提供されており、付随してCLI（Command Line Interface）や各種SDKも整備されています。</p>
<p>これらを利用することで他サービスとの連携や、QuickSightの各種リソースのコード管理などができます。既にTerraformやCloudFormationなどに代表されるIaC（Infrastructure as Code）ツールも充実してきているようです<sup id="fnref:3">3</sup>。</p>
<p>APIを利用することで、より高度なユースケースを実現できるようになります。ここでは、APIのみで利用可能なQuickSightの仕組み（テンプレート）を題材に、CLIの利用例をご紹介します。使用したAWS CLIのバージョンは以下の通りです。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">aws --version</span></span><br><span class="line">aws-cli/2.17.33 Python/3.11.9 Linux/5.15.153.1-microsoft-standard-WSL2 exe/x86_64.ubuntu.22</span><br></pre></td></tr></table></figure>

<h3 id="例：テンプレートで同じ見た目のダッシュボードを作成する">例：テンプレートで同じ見た目のダッシュボードを作成する</h3><p>QuickSightにはテンプレートという仕組みがあり、これを利用することで既存の分析やダッシュボードの雛形を同一のQuickSightアカウント内や別のQuickSightアカウントに共有できます（公式ではカプセル化／抽象化するなどと表現されていました）。</p>
<p>共有されたテンプレートとそのスキーマを満たすデータセットを元に、既存のものと同じ（表示しているデータの中身だけ異なる）分析やダッシュボードを作成できます。例えば、開発環境に用意した分析やダッシュボードを本番環境に同じ見た目のものを作成したい、といった場面で利用できると思います。</p>
<p>AWS CLIを利用して先ほどを作成した東京の平均気温をテンプレートとして、別地点（北海道宗谷岬）で同じ見た目のダッシュボードを作成してみます<sup id="fnref:4">4</sup>。</p>
<p>テンプレートを作成するために、先ほど作成したデータセットと分析のARNをCLIを使って取得しておきます。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">データセットのARNを取得する例</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">aws quicksight list-data-sets \</span></span><br><span class="line"><span class="language-bash">  --aws-account-id <span class="variable">$&#123;AWS_ACCOUNT_ID&#125;</span> \</span></span><br><span class="line"><span class="language-bash">  --query <span class="string">&#x27;DataSetSummaries[?Name==`tokyo_kion_2014-2024`].Arn&#x27;</span> \</span></span><br><span class="line"><span class="language-bash">  --output text \</span></span><br><span class="line"><span class="language-bash">  --profile <span class="variable">$&#123;AWS_PROFILE&#125;</span></span></span><br><span class="line"></span><br><span class="line">arn:aws:quicksight:ap-northeast-1:$&#123;AWS_ACCOUNT_ID&#125;:dataset/$&#123;DATA_SET_ID&#125;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">分析のARNを取得する例</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">aws quicksight list-analyses \</span></span><br><span class="line"><span class="language-bash">  --aws-account-id <span class="variable">$&#123;AWS_ACCOUNT_ID&#125;</span> \</span></span><br><span class="line"><span class="language-bash">  --query <span class="string">&#x27;AnalysisSummaryList[?Name==`tokyo_kion_2014-2024 analysis`].Arn&#x27;</span> \</span></span><br><span class="line"><span class="language-bash">  --output text \</span></span><br><span class="line"><span class="language-bash">  --profile <span class="variable">$&#123;AWS_PROFILE&#125;</span></span></span><br><span class="line"></span><br><span class="line">arn:aws:quicksight:ap-northeast-1:$&#123;AWS_ACCOUNT_ID&#125;:analysis/$&#123;ANALYSIS_ID&#125;</span><br></pre></td></tr></table></figure>

<p>取得したARNを元に以下の形式のファイルを用意します。</p>
<figure class="highlight json"><figcaption><span>template_source_entity.json</span></figcaption><table><tr><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;SourceAnalysis&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;Arn&quot;</span><span class="punctuation">:</span> <span class="string">&quot;&#123;先ほど取得した分析のARN&#125;&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;DataSetReferences&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">      <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;DataSetPlaceholder&quot;</span><span class="punctuation">:</span> <span class="string">&quot;kion-data-set&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;DataSetArn&quot;</span><span class="punctuation">:</span> <span class="string">&quot;&#123;先ほど取得したデータセットのARN&#125;&quot;</span></span><br><span class="line">      <span class="punctuation">&#125;</span></span><br><span class="line">    <span class="punctuation">]</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure>

<p>作成したファイルを元にテンプレートを作成できます。</p>
<p>以下のコマンドでは指定していませんが、<code>--permission</code>オプションを利用することで、指定先（本番環境など）へテンプレートの参照権限を付与できます。</p>
<p>作成されたテンプレートは、<code>describe-template</code>のAPIなどから確認できます。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">aws quicksight create-template \</span></span><br><span class="line"><span class="language-bash">  --aws-account-id <span class="variable">$&#123;AWS_ACCOUNT_ID&#125;</span> \</span></span><br><span class="line"><span class="language-bash">  --template-id kion-template \</span></span><br><span class="line"><span class="language-bash">  --name <span class="string">&#x27;Kion Template&#x27;</span> \</span></span><br><span class="line"><span class="language-bash">  --source-entity file://<span class="variable">$&#123;PWD&#125;</span>/template_source_entity.json \</span></span><br><span class="line"><span class="language-bash">  --profile <span class="variable">$&#123;AWS_PROFILE&#125;</span></span></span><br></pre></td></tr></table></figure>

<p>続いて、テンプレートを元に別地点（北海道宗谷岬）のデータを同じように表示するダッシュボードを作成します。</p>
<p>作成のため以下の形式のファイルを用意します。説明は省略していますが、あらかじめ別地点のデータセットを用意しておく必要があります。</p>
<figure class="highlight json"><figcaption><span>dashboard_source_entity.json</span></figcaption><table><tr><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;SourceTemplate&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;DataSetReferences&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">      <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;DataSetPlaceholder&quot;</span><span class="punctuation">:</span> <span class="string">&quot;kion-data-set&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;DataSetArn&quot;</span><span class="punctuation">:</span> <span class="string">&quot;&#123;別地点（北海道宗谷岬）の平均気温のデータセットのARN&#125;&quot;</span></span><br><span class="line">      <span class="punctuation">&#125;</span></span><br><span class="line">    <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;Arn&quot;</span><span class="punctuation">:</span> <span class="string">&quot;&#123;先ほど作成したテンプレートのARN&#125;&quot;</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure>

<p>また、作成されたダッシュボードをQuickSightの画面上で閲覧するために既存のダッシュボード（東京の平均気温）から同じ権限情報を取得しておきます。</p>
<p>以下で指定している<code>ダッシュボードのID</code>は、<code>describe-dashboard</code>のAPIなどから確認できます。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">aws quicksight describe-dashboard-permissions \</span></span><br><span class="line"><span class="language-bash">  --aws-account-id <span class="variable">$&#123;AWS_ACCOUNT_ID&#125;</span> \</span></span><br><span class="line"><span class="language-bash">  --dashboard-id <span class="variable">$&#123;ダッシュボードのID&#125;</span> \</span></span><br><span class="line"><span class="language-bash">  --query <span class="string">&#x27;Permissions&#x27;</span> \</span></span><br><span class="line"><span class="language-bash">  --profile <span class="variable">$&#123;AWS_PROFILE&#125;</span> &gt; permissions.json</span></span><br></pre></td></tr></table></figure>

<p>作成したテンプレートと用意した情報を元に、別地点のダッシュボードは以下のように作成します。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">aws quicksight create-dashboard \</span></span><br><span class="line"><span class="language-bash">  --aws-account-id <span class="variable">$&#123;AWS_ACCOUNT_ID&#125;</span> \</span></span><br><span class="line"><span class="language-bash">  --dashboard-id soyamisaki-kion-dashboard \</span></span><br><span class="line"><span class="language-bash">  --name <span class="string">&#x27;宗谷岬の平均気温&#x27;</span> \</span></span><br><span class="line"><span class="language-bash">  --permissions file://<span class="variable">$&#123;PWD&#125;</span>/permissions.json \</span></span><br><span class="line"><span class="language-bash">  --source-entity file://<span class="variable">$&#123;PWD&#125;</span>/dashboard_source_entity.json \</span></span><br><span class="line"><span class="language-bash">  --profile <span class="variable">$&#123;AWS_PROFILE&#125;</span></span></span><br></pre></td></tr></table></figure>

<p>QuickSightの画面を見ると作成したダッシュボードが追加されていることがわかります（グラフのタイトルに「東京」となっていますが元のダッシュボードをそのままテンプレートに利用したためです。わかりづらいですが表示しているデータは別地点の情報になっています）。</p>
<img src="/images/2025/20250513a/別地点のダッシュボードを作成1.png" alt="別地点のダッシュボードを作成1" width="1200" height="634" loading="lazy">

<p>作成されたダッシュボードは一番初めに作った見た目と同じであることがわかります。</p>
<img src="/images/2025/20250513a/別地点のダッシュボードを作成2.png" alt="別地点のダッシュボードを作成2" width="1200" height="838" loading="lazy">

<h2 id="まとめ">まとめ</h2><p>QuickSightを入門しようと検討されている方向けの内容をまとめました。後半はやや難しくなりましたが、これからQuickSightを使いこなす上でも必要な内容かと思っています。</p>
<p>ここまで読んでくださりありがとうございました。</p>
<p>初めての寄稿でうまく書けたか不安ではありますが良い経験となりました。これからも機会があれば挑戦していきたいなと思っています。</p>
<h2 id="参考">参考</h2><ul>
<li>ワークショップ :: Amazon QuickSight ハンズオン</li>
<li>QuickSightで作成した分析を、テンプレート機能を使って別アカウントへ配布してみる</li>
</ul>
<div id="footnotes"><hr><div id="footnotelist"><ol style="list-style:none; padding-left: 0;"><li id="fn:1"><span style="vertical-align: top; padding-right: 10px;">1.</span><span style="vertical-align: top;">QuickSightでサポートされているデータ接続先（データソース）はこちらから確認できます。</span> ↩</li><li id="fn:2"><span style="vertical-align: top; padding-right: 10px;">2.</span><span style="vertical-align: top;">詳しい料金体系はこちらから確認できます。</span> ↩</li><li id="fn:3"><span style="vertical-align: top; padding-right: 10px;">3.</span><span style="vertical-align: top;">TerraformやCloudFormationで扱える内容はこちらやこちらなどで確認できます。特にTerraformでは、寄稿した2025年5月時点でほとんどのリソースに対応していそうです。</span> ↩</li><li id="fn:4"><span style="vertical-align: top; padding-right: 10px;">4.</span><span style="vertical-align: top;">QuickSightのCLIのドキュメントはこちらから確認できます。</span> ↩</li></ol></div></div>]]></content>
    <summary type="html">Amazon QuickSightの入門記事です。最近、業務で触れる機会があったので、これから入門される方々の取っ掛かりとなるような内容になるようまとめます。</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="AWS" scheme="https://future-architect.github.io/tags/AWS/"/>
    <category term="BI" scheme="https://future-architect.github.io/tags/BI/"/>
    <category term="入門" scheme="https://future-architect.github.io/tags/%E5%85%A5%E9%96%80/"/>
    <category term="可視化" scheme="https://future-architect.github.io/tags/%E5%8F%AF%E8%A6%96%E5%8C%96/"/>
  </entry>
  <entry>
    <title>【MLOps】 Azure Data FactoryとAzure Purviewを使ってAI Searchに登録してみた</title>
    <link href="https://future-architect.github.io/articles/20250512b/"/>
    <id>https://future-architect.github.io/articles/20250512b/</id>
    <published>2025-05-11T15:00:01.000Z</published>
    <updated>2025-05-11T15:00:01.000Z</updated>
    <author><name>菅野滉大</name></author>
    <content type="html"><![CDATA[<div class="note-container note-warn"><span class="note-icon"></span><div>

<p>※担当チーム都合で、記事の公開が執筆次期から期間を空けてしまいました。<br>当時から変更がある可能性がある旨はご承知おきください。</p>
</div></div>

<h2 id="はじめに">はじめに</h2><p>こんにちは、SAIG&#x2F;MLOpsチームでインターンをしていた菅野です。</p>
<p>データ処理やデータ管理を効率化できるAzure Data FactoryとAzure Purviewを検証しました。</p>
<h2 id="背景">背景</h2><h3 id="MLOpsとは">MLOpsとは</h3><p>近年、チャットボットによる問い合わせ対応や、ECサイトのレコメンデーションなど機械学習を用いたサービスが増えるとともに、これらのシステムを効率的に運用することが重要になってきました。</p>
<p>そこで重要になってくるのがMLOps（Machine Learning Operations）です。MLOpsは、機械学習（ML）プロジェクトのライフサイクルを管理・効率化するために、DevOpsの原則を適用する概念です。機械学習のプロジェクトにおいて、モデルの作成・学習は全体の一部であり、他の作業が大きな割合を占めています。下記の画像はビジネスにおける機械学習に関して書かれた有名な論文から引用したものです。モデル作成はシステムの一部であり、モデル作成以外が大きな割合を占めていることが分かります。MLOpsは、そのような周辺の作業を含めた、機械学習プロジェクト全体の作業を効率化し、コスト削減をするためのものです。</p>
<img fetchpriority="high" src="/images/2025/20250512b/ml_abstract.png" alt="" width="1074" height="297">

<p>▲ 「Hidden Technical Debt in Machine Learning Systems」(D.scully らNIPS 2015)より引用</p>
<p>本記事ではMLOpsを推進するためのツールとして、<strong>Azure Data Factory</strong>と<strong>Azure Purview</strong>について検証します。</p>
<h3 id="RAG-Retrieval-Augmented-Generation">RAG(Retrieval Augmented Generation)</h3><p>様々なタスクをこなせる便利な生成AIですが、こなすことができないタスクもあります。それは学習データに含まれていない情報に基づく回答を生成することです。</p>
<p>生成AIは公開されているテキストデータを基に訓練されており、そこに含まれていない情報に関しては知識を持っていません。例えば、自社の社内規定や議事録について質問しても正しく回答ができません。</p>
<p>この課題を解決するためによく用いられる手法が <strong>RAG</strong>(<strong>Retrieval Augmented Generation</strong>) です。RAGを用いることで、生成AIが社内情報などに基づいた回答できるようになります。</p>
<p>RAGには、検索フェーズと生成フェーズの2段階が存在します。</p>
<ul>
<li>検索フェーズ: 生成AIにない知識を補うために、自社に蓄積された社内情報や外部の最新情報を取得します。<ol>
<li>ユーザーが質問を入力</li>
<li>入力された質問に関する情報を検索</li>
<li>検索結果データを取得</li>
</ol>
</li>
<li>生成フェーズ: 検索フェーズで取得した文章と、ユーザーの質問文の2つを生成AIに入力することで回答を生成します<ol start="4">
<li>ユーザーの質問と3で取得した検索結果データを生成AIに入力</li>
<li>入力されたデータをもとに、生成AIが回答を作成</li>
<li>作成された回答をユーザーに出力</li>
</ol>
</li>
</ul>
<img src="/images/2025/20250512b/rag.png" alt="" width="567" height="332" loading="lazy">

<p>▲ RAGとは？仕組みと導入メリット、使用の注意点をわかりやすく解説</p>
<p>このようなRAGシステムを導入するにあたって、課題となるのは<strong>検索フェーズ</strong>の精度です。入力された質問に関連する情報を検索する際の精度が、RAGシステムの品質に直結します。そこで本記事では、優秀な検索エンジンと噂の、Azureサービスで提供されている<strong>Azure AI Search</strong>を用いてRAGシステムを運用することを想定します。</p>
<p>また、Azure AI Searchで効率的な検索するためには事前にチャンキングや、エンベディングなどの前処理を行いインデックスに登録しておく必要があります。</p>
<p>インデックスの詳細は以下のサイトを参照してください。</p>
<ul>
<li>検索インデックスの概要 - Azure AI Search | Microsoft Learn</li>
<li>基本概念から理解するAzure AI Search - Azure OpenAI Serviceとの連携まで - 電通総研 テックブログ</li>
</ul>
<h3 id="Azure-AI-Searchを用いたRAGにおける課題">Azure AI Searchを用いたRAGにおける課題</h3><p>優秀な検索エンジンであるAzure AI Searchですが、RAGを実現する際に2つ課題があります。</p>
<ol>
<li><p><strong>Azure AI Searchが非Azureサービスとの連携に弱い</strong><br>Azure AI Searchは、インデクサーというコンポーネントを用いて、データの読み込みからインデックスに登録するまでを自動化できます。これにより手作業でAzure AI Searchにデータを登録する必要がなくなり運用コストを抑えることができます。</p>
<img src="/images/2025/20250512b/azure_ai_search_problem.avif" alt="" width="653" height="393" loading="lazy">
</li>
<li><p><strong>どのような前処理を経て、Azure AI Searchに登録されたのかわからない</strong><br>  Azure AI Searchのインデックスに登録するためには、チャンキングや、テキストをベクトルに変換するエンベディングなどの前処理が必要になります。しかし現状のシステムだと、どのような前処理を経てAzure AI Searchに保存されたのかがわからなく、正確性が担保できません。</p>
</li>
</ol>
<h2 id="目的">目的</h2><p>上記の課題を解決することが本検証の目的となります。本記事では、Azure Data FactoryとAzure Purviewを用いて、課題解決を目指します。</p>
<ol>
<li><strong>Azure Data Factory</strong>を用いて、複数データソースからAzure AI Searchに登録<br>多様なデータベースと連携ができるAzure Data Factoryを用いて、Azure AI Searchが連携できないデータベースと連携し、前処理を行ったうえで、Azure AI Searchに保存します。またAzure Data Factoryの自動トリガー機能やアラート機能を活用してコスト削減する。</li>
<li><strong>Azure Purview</strong>を用いて、リネージ管理<br>どのデータを基に、どのような前処理を経て、どのファイルに保存したのかを記録し管理することを<strong>リネージ管理</strong>といいます。このリネージ管理をAzure Purviewの機能を用いて実現します。</li>
</ol>
<h2 id="ツールの紹介">ツールの紹介</h2><p>今回検証するAzure Data FactoryとAzure Purviewについて紹介します。</p>
<h3 id="Azure-Data-Factoryとは">Azure Data Factoryとは</h3><p>Azure Data Factoryは、Microsoftが提供するクラウド型のデータ統合サービスで、オンプレミスにあるデータやクラウド上にあるデータを効率的に移動・変換・統合が可能です。Azure Data Factoryを利用することで、異なるデータソースからのデータを収集・統合・変換して、機械学習モデルの訓練や評価に必要な形式に整えることができます。</p>
<p>▼参考：Azure Data Factory とは何ですか。</p>
<img src="/images/2025/20250512b/image_2.png" alt="" width="1200" height="753" loading="lazy">

<div class="note-container note-info"><span class="note-icon"></span><div>

<p><strong>Azure Logic Appsとの違い</strong></p>
<p>データの統合や自動化を目的としたツールとして、Azure Data Factoryに類似したツールであるLogic Appsがあります。ユースケースに合わせて使い分ける必要があります（参考）</p>
<p>大規模なデータ処理を行う際はAzure Data Factory、軽量な処理などにはLogic Appsを用いるイメージです。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>特徴</th>
<th>Logic Apps</th>
<th>Azure Data Factory</th>
</tr>
</thead>
<tbody><tr>
<td>目的とユースケース</td>
<td>イベント駆動型アプリ・ビジネスプロセスの自動化</td>
<td>大規模データ処理・高度なETL&#x2F;ELT処理</td>
</tr>
<tr>
<td>データ処理のスケーラビリティ</td>
<td>軽量なデータ処理・リアルタイムイベントの処理</td>
<td>高スループットのデータ処理・バッチ処理</td>
</tr>
<tr>
<td>コネクタとサービスの統合</td>
<td>SaaSアプリ・APIとの広範な統合</td>
<td>データの移動と変換を中心に多くのデータソースに対応</td>
</tr>
<tr>
<td>ワークフローの自動化</td>
<td>ビジネスプロセスの多段階自動化</td>
<td>データパイプラインの設計・自動実行</td>
</tr>
</tbody></table></div>
</div></div>

<h3 id="Azure-Purviewとは">Azure Purviewとは</h3><p>Azure Purviewは、オンプレおよびクラウドに散在しているデータを管理し、統制する「データガバナンス」ソリューションです。主に、データの保護、データソースを跨いだデータ検索、データがどのように処理されたのかを管理するデータリネージの機能などがあります。本検証では特にデータリネージ機能について検証します。</p>
<ul>
<li>Microsoft Purview の詳細 | Microsoft Learn</li>
</ul>
<h3 id="Azure-Data-FactoryとAzure-Purviewでできること">Azure Data FactoryとAzure Purviewでできること</h3><p>Azure Data Factoryを用いることで、様々なデータソースからデータを取得して処理を行うことができます。</p>
<p>またAzure Data FactoryとAzure Purviewを組み合わせることで、データ処理とデータ管理にかかる人的コストを削減ができます。</p>
<h4 id="1-コスト削減">1. コスト削減</h4><p>Azure Data Factoryでは、<strong>インフラの管理やメンテナンスが不要</strong>です。また、<strong>データ処理を自動化</strong>することで、エンジニアが定期的にプログラムを実行する手間を省くことができます。さらにAzure Purviewを用いることで、どのデータからどのようなプロセスを経て作成されたかなどの<strong>リネージ管理</strong>をおこなうことができます。データの正確性を担保することでデータの再利用がしやすくなり、再びデータ処理などをする手間がなくなります。</p>
<h4 id="2-データの一元化">2. データの一元化</h4><p>Azure Data Factoryは多様なデータソース（オンプレミスやクラウド、構造化データや非構造化データ）をサポートしており(参考：対応しているデータソース)、簡単にデータを取り込み、統合ができます。一度登録したデータソースであれば、すぐに呼び出して使うことができます。また、Azure Purviewを用いることでデータソースを跨いだデータの検索、参照できます。</p>
<h4 id="3-可視化">3. 可視化</h4><p>Azure Data FactoryとAzure Purviewにはビジュアルインターフェースがあり、データ処理のフローやデータ依存関係を視覚的に管理できます。これにより、処理の流れやデータの関係性を素早く理解ができます。</p>
<h2 id="検証">検証</h2><p>本記事で検証したAzureのUIは2024年9月時点でのものです。</p>
<h3 id="Azure-Data-FactoryとAzure-Purviewの利用手順">Azure Data FactoryとAzure Purviewの利用手順</h3><h4 id="初期設定">初期設定</h4><p>Azure Data FactoryとAzure Purviewで作業を始めるための設定の流れです。</p>
<ol>
<li><p><strong>Azureポータルでリソースを作成</strong><br>以下のリソースを作成します。</p>
<ul>
<li>Azure Data Factory</li>
<li>Azure Purview</li>
<li>キーコンテナ</li>
<li>ストレージアカウント</li>
</ul>
</li>
<li><p><strong>Azure Purviewでコレクションを作成</strong><br>Azure Purviewでは、コレクションごとに管理します。コレクションには複数のデータソースを登録でき、またアクセス制御などもコレクションごとに行えます。</p>
<img src="/images/2025/20250512b/image_3.png" alt="" width="1200" height="573" loading="lazy">
</li>
<li><p><strong>Azure Data FactoryとAzure Purviewの接続</strong><br>Azure Purviewの「管理」画面から「系列接続」を選び、Azure Data Factoryの項目で設定します。</p>
<img src="/images/2025/20250512b/image_4.png" alt="" width="1068" height="388" loading="lazy">
</li>
<li><p><strong>ストレージアカウントとAzure Purviewの接続</strong><br>キーコンテナを使用して接続します</p>
<ol>
<li>キーコンテナのアクセス権限を編集します<ul>
<li>アクセス制御画面で自分のAzureアカウントにキーコンテナ管理権限を付与</li>
<li>アクセスポリシー画面でAzure Purviewリソースに「シークレットのアクセス許可」の「取得」権限を付与</li>
</ul>
</li>
<li>ストレージアカウントでアクセスキーを発行し、キーコンテナに登録します</li>
<li>Azure Purviewでソースメニューの適切なコレクションから「登録」アイコンを選択し、新しいAzure Blobデータソースを登録します</li>
</ol>
<img src="/images/2025/20250512b/image_5.png" alt="" width="1200" height="633" loading="lazy"></li>
</ol>
<h4 id="Azure-Data-Factoryによるデータソースの登録">Azure Data Factoryによるデータソースの登録</h4><p>以下の手順で登録します。</p>
<img src="/images/2025/20250512b/image_6.png" alt="" width="1200" height="851" loading="lazy">

<h4 id="Azure-Data-Factoryによるパイプライン作成">Azure Data Factoryによるパイプライン作成</h4><p>Azure Data Factoryは、<strong>データセット</strong>、<strong>パイプライン</strong>、<strong>データフロー</strong>という3つの要素から構成されます。</p>
<ul>
<li>データセット：各種データサービスとの連携を設定します</li>
<li>パイプライン：データ処理全体の流れを記載します</li>
<li>データフロー：実際にデータ処理を行います。パイプラインから呼び出します</li>
</ul>
<p>パイプラインとデータフローには以下のアクティビティがあります。アクティビティとは、プログラミングにおける関数のようなもので、アクティビティ内に行いたい処理を記載し、それらを呼び出すことでデータ処理を行います。一度作成したアクティビティは再利用可能で、他のパイプラインやデータフローに使用できます。アクティビティに用意されていない複雑なデータ処理を行いたい場合は、Azure関数やDataBricksを呼び出すことで、コードベースによるデータ処理も行うことができます。</p>
<img src="/images/2025/20250512b/image_7.png" alt="" width="1105" height="889" loading="lazy">

<img src="/images/2025/20250512b/image_8.png" alt="" width="995" height="632" loading="lazy">

<p>Azure Data Factoryに慣れるため、以下のようなパイプラインを作成しました。</p>
<ol>
<li>特定のディレクトリからファイル名の一覧を取得します</li>
<li>取得したファイル名を変数に設定してデータフローに渡します</li>
<li>データフローを呼び出します</li>
<li>データを読み込みます</li>
<li>不要なカラムを削除します</li>
<li>「male」や「female」などの文字カテゴラルデータを数字に変換します</li>
<li>変換後のデータを保存します</li>
</ol>
<img src="/images/2025/20250512b/image_9.png" alt="" width="884" height="505" loading="lazy">

<p>パイプラインで設定した変数やデータは、データフロー内で使えません。使いたい場合は、データフローのパラメーターに渡す必要があります。具体例を説明します。</p>
<p>まず、データフロー側でパラメーターを設定します。</p>
<img src="/images/2025/20250512b/image_10.png" alt="" width="764" height="197" loading="lazy">

<p>次に、パイプライン側からデータフローのパラメーターに変数を設定します。</p>
<img src="/images/2025/20250512b/image_11.png" alt="" width="882" height="408" loading="lazy">

<h3 id="Azure-Data-FactoryとAzure-Purviewの動作確認">Azure Data FactoryとAzure Purviewの動作確認</h3><p>作成したパイプラインを用いて、Azure Data FactoryとAzure Purviewの機能を確認します。</p>
<h4 id="作成したパイプラインの処理結果">作成したパイプラインの処理結果</h4><p>作成したパイプラインをKaggleのtitanicデータに対して、実行してみると正しくデータ処理を行えていることが確認できました。</p>
<img src="/images/2025/20250512b/image_12.png" alt="" width="1200" height="1017" loading="lazy">

<h4 id="パイプラインの自動トリガー">パイプラインの自動トリガー</h4><p>Azure Data Factoryで作成したパイプラインは、様々な方法で実行させることができます。</p>
<ul>
<li>API&#x2F;SDKを使用した実行<br>.NET SDK、Azure PowerShell、REST API、Python SDKを使用してパイプラインを実行できます。(参考)</li>
<li>スケジュール<br>日時に関する条件をトリガーにパイプラインを実行できます。</li>
<li>ストレージイベント<br>ファイルの追加&#x2F;削除などのストレージに関する条件をトリガーにパイプラインを実行できます。</li>
<li>カスタムイベント<br>自分で作成したトリガー条件によってパイプラインを実行できます。</li>
</ul>
<p>今回はストレージイベントを使用して、指定したディレクトリにファイルが追加されたらパイプラインを実行するようにしました。3ステップで簡単に設定できます。</p>
<img src="/images/2025/20250512b/image_13.png" alt="" width="1200" height="564" loading="lazy">

<p>ディレクトリにファイルを追加すると、設定したしたトリガーによってパイプラインが実行されていることがわかります。</p>
<img src="/images/2025/20250512b/image_14.png" alt="" width="1199" height="289" loading="lazy">

<h4 id="リネージ管理">リネージ管理</h4><p>接続しておいたAzure Purviewから、リネージを確認してみます。</p>
<p>test-inputが、Data flow 1で処理されて、test-outputに保存されていることが確認できます。</p>
<p>Data flow 1の処理内容が知りたいときは、「Azure Data Factoryで開く」をクリックすることで確認しに行けます。</p>
<img src="/images/2025/20250512b/image_15.png" alt="" width="1200" height="424" loading="lazy">

<h3 id="Azure-AI-Searchのインデックスに登録">Azure AI Searchのインデックスに登録</h3><p>使い方が分かったところで、Azure Data Factoryを用いて、Azure AI Searchのインデックスにフューチャー技術ブログのテキストを登録してみようと思います。</p>
<h4 id="初期設定-1">初期設定</h4><p>Azure AI Searchのインデックス登録のために、以下のリソースを作成します。</p>
<ul>
<li>Azure Open AI<br>作成したリソース内でテキストエンベディングのを行うモデルをデプロイします。今回はtext-embedding-ada-002モデルを使用します。</li>
<li>Azure AI Search</li>
</ul>
<h4 id="手法">手法</h4><p>今回は以下の流れでテキストデータをAzure AI Searchインデックスに登録します。</p>
<ol>
<li>フューチャー技術ブログからテキストデータを取得&#x2F;保存</li>
<li>テキストファイルからテキストデータを取得</li>
<li>Azure OpenAIでベクトル化</li>
<li>文章、タイトル、ベクトル等をAzure AI Searchインデックスに登録する</li>
</ol>
<p>また 2~3 の処理をAzure Data Factory内で行うことで、Azure AI Searchに保存する処理までを自動化します。</p>
<p>Azure Purviewによって各データ処理を監視することで、リネージを管理します。</p>
<img src="/images/2025/20250512b/image_16.png" alt="" width="1200" height="521" loading="lazy">

<p>AI Searchインデックスに登録するパイプラインは以下のようになります。</p>
<img src="/images/2025/20250512b/image_17.png" alt="" width="1061" height="359" loading="lazy">

<h5 id="1-フューチャー技術ブログからテキストデータを取得-保存">1. フューチャー技術ブログからテキストデータを取得&#x2F;保存</h5><p>Databricksを用いて、フューチャー技術ブログの情報を取得し、Azure Blobストレージに保存します。</p>
<p>Azure Data FactoryのWebアクティビティを用いて、フューチャー技術ブログの情報を取得もできますが、Databricksを用いました。</p>
<h5 id="2-テキストファイルからテキストデータを取得">2. テキストファイルからテキストデータを取得</h5><p>まず、「Get Metadata」アクティビティを用いて、ディレクトリ内のファイル名を配列として取得します。データセットを指定することで、そのデータセットに関する情報を取得できます。今回は以下の3つを取得します。</p>
<ul>
<li>アイテム名(ディレクトリ名)</li>
<li>子項目(ディレクトリ内の各ファイル情報)</li>
</ul>
<img src="/images/2025/20250512b/image_18.png" alt="" width="1200" height="365" loading="lazy">

<p>次に「ForEach」アクティビティを作成し、取得したファイル名それぞれに対して処理できるようにします。</p>
<p>「ForEach」アクティビティ→設定→項目に以下のように記載することで「ForEach」アクティビティ内で取得した配列を扱えるようになります。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">@<span class="title function_">activity</span>(<span class="string">&#x27;「Get Metadata」アクティビティ名&#x27;</span>).<span class="property">output</span>.<span class="property">childItems</span></span><br></pre></td></tr></table></figure>

<img src="/images/2025/20250512b/image_19.png" alt="" width="805" height="484" loading="lazy">

<p>最後に、「ForEach」アクティビティ内に「参照」アクティビティを作成して、テキストデータを取得します。</p>
<p>ソースデータセットと値を下記のように設定します。</p>
<p>取得したテキストデータは@{activity(‘Lookup1’).output}という変数に格納されます。</p>
<img src="/images/2025/20250512b/image_20.png" alt="" width="1200" height="492" loading="lazy">

<h5 id="3-Azure-OpenAIでベクトル化">3. Azure OpenAIでベクトル化</h5><p>読み取った文章をAPI経由でAzure OpenAIに渡してベクトル化します。</p>
<ol>
<li><p><strong>「Web」アクティビティを作成:</strong></p>
<ul>
<li>UIから指定すると動作が不安定な場合があるので、JSONを直接編集することをお勧めします</li>
</ul>
</li>
<li><p><strong>テキストのエンベディングモデルを作成:</strong></p>
<ul>
<li>Azure OpenAIのリソースからエンベディングモデルをデプロイします</li>
<li>今回は <code>text-embedding-ada-002</code> を使用します</li>
</ul>
</li>
<li><p><strong>URLの指定規則:</strong></p>
<ul>
<li>以下の形式に従います</li>
</ul>
 <figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">https://&lt;OpenAIのリソース名&gt;.openai.azure.com/openai/deployments/&lt;デプロイしたモデル名&gt;/embeddings?api-version=&lt;APIのバージョン&gt;</span><br></pre></td></tr></table></figure>
</li>
<li><p><strong>inputにエンベディングしたい文章を指定:</strong></p>
<ul>
<li>作成した「Web」アクティビティのjsonのtypePropertiesの箇所を以下のように編集します</li>
<li>取得したテキストデータはbody→inputに設定されています</li>
</ul>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line"><span class="attr">&quot;typeProperties&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;method&quot;</span><span class="punctuation">:</span> <span class="string">&quot;POST&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;headers&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;api-key&quot;</span><span class="punctuation">:</span> <span class="string">&quot;YOUR API KEY&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Content-Type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;application/json&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;url&quot;</span><span class="punctuation">:</span> <span class="string">&quot;https://OpenAIのリソース名.openai.azure.com/openai/deployments/OpenAIの中でデプロイしたモデル名/embeddings?api-version=APIのバージョン&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;body&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;input&quot;</span><span class="punctuation">:</span> <span class="string">&quot;@&#123;activity(&#x27;&lt;アクティビティ名&gt;&#x27;).output.firstRow.Prop_0&#125;&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;model&quot;</span><span class="punctuation">:</span> <span class="string">&quot;text-embedding-ada-002&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure></li>
</ol>
<h5 id="4-文章、タイトル、ベクトル等をAzure-AI-Searchインデックスに登録">4. 文章、タイトル、ベクトル等をAzure AI Searchインデックスに登録</h5><p>Azure OpenAIから作成したベクトルや、本文をAPIを経由してAzure AI Searchに保存します。</p>
<ol>
<li><p><strong>「Web」アクティビティを選択</strong></p>
<ul>
<li>api-key、URL、本文を指定します</li>
</ul>
</li>
<li><p><strong>URLの指定規則</strong></p>
<ul>
<li>以下の形式に従います</li>
</ul>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">https://Azure AI Searchのリソース名-free.search.windows.net/indexes/Azure AI Search内のインデックス名/docs/index?api-version=your api version</span><br></pre></td></tr></table></figure>
</li>
<li><p><strong>本文に登録したいデータを設定</strong><br>Azure AI Searchのインデックスに登録したい情報を設定します。<br>今回は、ファイル名、id、文章、ベクトル化した文章を設定しました。idには記号を設定できないため、ファイル名から記号を取り除いたものを設定しています。任意に設定してください。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="string">&quot;@search.action&quot;</span>: <span class="string">&quot;upload&quot;</span>,</span><br><span class="line"><span class="string">&quot;file_name&quot;</span>: <span class="string">&quot;@&#123;item().name&#125;&quot;</span>,</span><br><span class="line"><span class="string">&quot;id&quot;</span>: <span class="string">&quot;@&#123;concat(base64(replace(replace(replace(replace(item().name, &#x27;/&#x27;, &#x27;_&#x27;), &#x27;-&#x27;, &#x27;_&#x27;), &#x27;.&#x27;, &#x27;_&#x27;), &#x27; &#x27;, &#x27;_&#x27;)), &#x27;_&#x27;, formatDateTime(utcNow(), &#x27;yyyyMMddTHHmmssZ&#x27;))&#125;&quot;</span>,</span><br><span class="line"><span class="string">&quot;content&quot;</span>: <span class="string">&quot;@&#123;activity(&#x27;&lt;アクティビティ名&gt;&#x27;).output.firstRow.Prop_0&#125;&quot;</span>,</span><br><span class="line"><span class="string">&quot;content_vec&quot;</span>: <span class="string">&quot;@&#123;activity(&#x27;&lt;アクティビティ名&gt;&#x27;).output.data[0].embedding&#125;&quot;</span></span><br></pre></td></tr></table></figure></li>
</ol>
<h4 id="動作確認">動作確認</h4><p>Azure AI Searchのインデックスを見てみます。ファイル名や文章、ベクトルが正しく保存されていることがわかります。このインデックスを用いてRAGを実現できます。</p>
<img src="/images/2025/20250512b/image_21.png" alt="" width="821" height="461" loading="lazy">

<h4 id="Azure-Purviewによるリネージ管理">Azure Purviewによるリネージ管理</h4><p>Azure Purviewを用いたリネージ管理は今回実現できませんでした。考えられる原因は以下です。</p>
<ul>
<li>Azure PurviewがAzure AI Searchに対応していない</li>
<li>APIで行った処理はAzure Purviewで追跡できない</li>
</ul>
<p>解決策として、前処理を行った後のベクトル等のデータを一度どこかのストレージに保存することなどが考えられます。</p>
<h2 id="まとめ">まとめ</h2><p>今回の検証では以下を行いました。</p>
<ul>
<li>Azure Data FactoryとAzure Purviewの利用手順の確認</li>
<li>Azure Data Factoryを用いたデータ処理の自動化</li>
<li>Azure Purviewを用いたリネージ管理</li>
<li>テキストファイルからAzure AI Searchのインデックスに自動登録</li>
</ul>
<p>また検証を通してそれぞれのツールに対して感じたことは以下です。</p>
<p><strong>Azure Data Factory</strong></p>
<ul>
<li>メリット<ul>
<li>幅広いデータソースとの連携</li>
<li>作成したアクティビティの再利用</li>
<li>自動トリガーやアラート機能などの周辺機能</li>
</ul>
</li>
<li>デメリット<ul>
<li>アクティビティとして用意されていない処理を行いたい時に不便</li>
</ul>
</li>
</ul>
<p><strong>Azure Purview</strong></p>
<ul>
<li>メリット<ul>
<li>リネージ管理が便利</li>
<li>データソースを跨いだ検索やタグ付けが優秀(未検証)</li>
</ul>
</li>
<li>デメリット<ul>
<li>軽く導入するには費用が高い点</li>
<li>Azure Data Factory側で、適切な設定をしないとリネージ管理されない点</li>
</ul>
</li>
</ul>
<h2 id="展望">展望</h2><p>インターン期間の関係で検証しきれなかった点があるので記載いたします。</p>
<ul>
<li>Azure Data Factory内のwebアクティビティを用いて、Webサイトからテキストを抽出できるか</li>
<li>Azure Data Factoryから、リンクサービスとしてAzure AI Searchに登録ができるか</li>
<li>Azure Purviewを用いて、AI Searchインデックスのリネージ管理を実現できるか</li>
</ul>
<p>またAzure Data FactoryとAzure Purview以外の検証事項について以下があります。</p>
<ul>
<li>Azure AI Searchのセマンティックランカー&#x2F;ハイブリッド検索</li>
<li>適切なチャンク分けを行い、Azure AI Searchに登録</li>
<li>Azure AI Searchの検索精度</li>
</ul>
<h2 id="感想">感想</h2><p>Engineer Campに参加させていただき、これまで触れてこなかったAzureサービスに初めて触れることができ、とても新鮮な体験となりました。普段プログラムを作成して行っている処理を、驚くほど簡単に実現できることに衝撃をうけ、クラウドサービスがこれほど流行している理由が理解できました。</p>
<p>また、1ヶ月のインターンを通じて、開発から発表まで一通りの業務を行う中で、相談の重要性やプレゼンテーションの構成方法、スモールスタートを意識した課題解決のアプローチなど、多くの貴重な学びを得ることができました。資料作成スキルなど、自身の課題も浮き彫りになり、成長すべき点を具体的に認識できたことも大きな収穫でした。</p>
<p>非常に有意義な時間を過ごさせていただき、ありがとうございました。</p>
]]></content>
    <summary type="html">MLOpsを推進するためのツールとして、Azure Data FactoryとAzure Purviewについて検証していきます。</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="Azure" scheme="https://future-architect.github.io/tags/Azure/"/>
    <category term="MLOps" scheme="https://future-architect.github.io/tags/MLOps/"/>
    <category term="RAG" scheme="https://future-architect.github.io/tags/RAG/"/>
    <category term="インターン" scheme="https://future-architect.github.io/tags/%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%B3/"/>
    <category term="インターン2024" scheme="https://future-architect.github.io/tags/%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%B32024/"/>
  </entry>
  <entry>
    <title>データ分析でプロジェクトをリードした話</title>
    <link href="https://future-architect.github.io/articles/20250508a/"/>
    <id>https://future-architect.github.io/articles/20250508a/</id>
    <published>2025-05-07T15:00:00.000Z</published>
    <updated>2025-05-07T15:00:00.000Z</updated>
    <author><name>岡田陸</name></author>
    <content type="html"><![CDATA[<h2 id="はじめに">はじめに</h2><p>はじめまして、製造エネルギー事業部に所属している岡田と申します。現在、〆切に追われて出張先へ向かう飛行機の中で焦って本稿を書いています&gt;_&lt;</p>
<p>私は2020年4月に新卒で入社し、一貫してシステムの構築～保守というシステム構築における王道パターンのキャリアを歩んできました。</p>
<p>しかし、昨年1年間は「データを駆使して仕事を進める」という少しいままでと色の違う経験をしました。この記事では、その中で得た知見や工夫した点を、「春の入門祭り2025」にあわせて共有します。</p>
<h2 id="データ分析の目的">データ分析の目的</h2><p>当たり前ですが、データ分析の目的は「分析すること」ではなく「達成したい目的(課題)に対してデータの観点からアシストをすること」と捉えていますす。</p>
<p>クライアントが「〇〇したいが、何故かできない」のような状況の際に、データという観点からどのようなアシストができるのかを見つけるツールのようなイメージです。そのため、分析自体になにか価値があるというわけではなく、分析によって実現したいことへ近づけた際に初めて分析の価値が生まれます。</p>
<p>たとえば、スーパーを運営しているクライアントから「利益率を上げたいが、これ以上上がる見込みがない。投資する余力はあるが、どこに投資していいのかがわからない。」という相談を受けたとします。</p>
<p>そのとき、（スーパーのデータに全てアクセスできると仮定したとき）読者のあなたはどのような分析が出来るでしょうか？</p>
<ul>
<li>各レジの単位時間あたりの売上を見て、偏りがあれば偏らせないような施策を打つ</li>
<li>廃棄している商品の割合を商品別に出し、廃棄が多い商品は早めに割引する施策を打つ</li>
<li>レジ員ごとの単位時間あたりの処理数を出し、効率が悪いレジ員はクビを(ry</li>
</ul>
<p>…などなど、データという観点から業務のボトルネックとなっている箇所を特定し、そこに対してなんらかのアプローチを打つことで利益率を上げることが出来るでしょう。</p>
<h2 id="データ分析による施策の効果見積もり">データ分析による施策の効果見積もり</h2><p>また、データ分析はボトルネックの特定だけではなく、複数の施策案があったとき、どの施策がどの程度の効果があるかを見積もることもできます。</p>
<p>すごく簡単な例で例えると、「100人の従業員を今より2時間早く帰社させたときに、人件費はどれだけ削減出来るか？」という問いがあった際は、100人それぞれの時給単価×2時間を合計するような20行ほどのSQLを書けば分すぐに見積もることができます。</p>
<p>このように、現在の実績データをもとに、将来どの程度の効果がかるのかを見積もり数値化出来ることもデータ分析の面白いところかもしれません。</p>
<h2 id="机上の空論と現場とのすり合わせ">机上の空論と現場とのすり合わせ</h2><p>ここまでの話は、データ上のみの話で、いわば机上の空論です。</p>
<p>では、机上の空論による改善案を実際に現場に実行させようとするとどうなるでしょうか？現場からは非難の嵐になるでしょう。現場の実情は、データから見えることとは大きく違う可能性があります。</p>
<p>そのため、データによって出た案をまずは現場の方々に見せ、認識があっているかを事前にすり合わせます。現場の方々との感覚をすり合わせながら軌道修正した案を実行することで、現場の方々も納得しながら高い効果を発揮できるようになります。</p>
<h2 id="んで、実際に分析ってどうやるの？">んで、実際に分析ってどうやるの？</h2><p>ここまでは、データ分析における前提や、進め方について記載しました。</p>
<ul>
<li>データ分析というものになんとなく興味があるが、実際なにをどうするのかイメージがついていない</li>
<li>とりあえずデータは手元にあり、なんか面白い分析をやってみたい</li>
</ul>
<p>…のような方に、超簡単にできるデータ分析のワザを記載します。</p>
<p>これを読んだら今日からあなたもデータ分析マスターです。</p>
<h3 id="1-調査するデータの構造を理解する">1.調査するデータの構造を理解する</h3><p>まずは、入口にして一番大事なところです。</p>
<p>最初にデータを扱う際は、まずデータの構造について自身が腹落ちするまで理解する必要があります。</p>
<p>最初に1から100まで完璧に理解をする必要はありませんが、最低でも主要テーブルと、主要テーブルの中のプライマリーキー、フォーリンキー（外部キー）、主要な属性項目については頭に叩き込んでおきましょう。また、カラム（横軸）だけではなく、レコード（縦軸）の発行の粒度についても理解が出来るとなお可です。</p>
<p>これらが十分に理解できたとき、データ分析を始める下地は十分整っていることでしょう。</p>
<h3 id="2-実際にSQLで、調査したいデータを出力する">2.実際にSQLで、調査したいデータを出力する</h3><p>前工程である程度テーブル構造について理解ができたら、まずは試しにデータを出してみましょう。</p>
<p>最初は簡単に、1つのトランをそのままselectしてくるのでも構いません（ただし、全selectはデータ量によっては障害を起こす可能性もあるのでlimit句や日付指定等で、過剰なデータを要求しないよう気をつけてください。）</p>
<p>ただし、Excelは100万行程度までしか受け付けられないため、大きなデータのときはあらかじめ観点を絞って集約関数やウィンドウ関数等を用いてデータ量を圧縮してから出力しましょう。</p>
<h3 id="3-Excelに貼り付けて、自由に分析する">3.Excelに貼り付けて、自由に分析する</h3><p>次は、A5ERやDBeaverなどのクライアントツールで出力された結果をコピーし、Excelにそのまま貼り付けます。<br>（今回は、適当に用意した表を用いて説明をします）。</p>
<p>貼り付けた直後にCTRL+Tを押すとテーブルとなり、リボンのテーブルデザインから「ピボットテーブルで集計」を押してみましょう。</p>
<img fetchpriority="high" src="/images/2025/20250508a/image.png" alt="image.png" width="594" height="278">

<p><font color="gray">表をテーブルに変換</font></p>
<img src="/images/2025/20250508a/image_2.png" alt="image.png" width="806" height="519" loading="lazy">

<p><font color="gray">「ピボットテーブルで集計」を押し、ピボットテーブル化。</p>
<p>作成先をテーブルを新規シートではなく、表のすぐ右隣にしておくと便利。</font></p>
<p>そうすると準備完了です。ピボットテーブルで横軸・縦軸をそれぞれ設定し、「値」のところは適当な項目を設定し右クリックで「個数」「合計」など、好きなものを選択してもらえれば、自由に分析結果を出すことができます。</p>
<img src="/images/2025/20250508a/image_3.png" alt="image.png" width="945" height="579" loading="lazy">

<p><font color="gray">「種類」を列に、「年齢」を行にドラッグし、値を種類の個数とすると、犬と猫の年齢別の数が出てきます。</font></p>
<p>この例だとサンプルが少なすぎて傾向等は見えませんが、データ量が大きくなると相関やボリュームゾーンが見えてくるようになります。</p>
<p>最後に、グラフを出してみましょう。（性別のカラムを追加しました）</p>
<p>今回は、犬と猫それぞれで性別にどのような偏りがあるかを見てみましょう。</p>
<img src="/images/2025/20250508a/image_4.png" alt="image.png" width="1200" height="775" loading="lazy">

<p><font color="gray">行を種類、列を性別とし、リボンの「ピボットグラフ」から「100％積み上げ縦棒」を選択すると、犬と猫それぞれの性別の割合を示すグラフが出てきます。</font></p>
<p>こうグラフ化することで、「犬はメスの割合が多いのか～」ということがわかると思います。<br>（※データは適当に作成したため、現実世界におけるオスメスの割合とは一致しません）</p>
<p>さて、ここまでの分析操作ができれば、今日からあなたもクライアントや上司から一目置かれるデータ分析マスターです。</p>
<h2 id="おわりに">おわりに</h2><p>今回は、入門者向けにデータ分析に関する簡単なやり方を記載してみました。</p>
<p>私も最初は「自分にデータ分析なんて出来るんだろうか」とモヤモヤしていましたが、やってみると楽しく、統計の勉強を進めるキッカケにもなったので、興味のある方は是非挑戦してみてください。</p>
<p>手元にデータがあれば、ぜひ簡単なところからデータ分析を始めてみませんか？</p>
]]></content>
    <summary type="html">昨年1年間は「データを駆使して仕事を進める」という少しいままでと色の違う経験をしました。この記事では、その中で得た知見や工夫した点を共有します。</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="Excel" scheme="https://future-architect.github.io/tags/Excel/"/>
    <category term="データ分析" scheme="https://future-architect.github.io/tags/%E3%83%87%E3%83%BC%E3%82%BF%E5%88%86%E6%9E%90/"/>
    <category term="可視化" scheme="https://future-architect.github.io/tags/%E5%8F%AF%E8%A6%96%E5%8C%96/"/>
  </entry>
  <entry>
    <title>Engineer Camp 2024 参加記：自然言語処理の研究開発で大崎から長崎へ</title>
    <link href="https://future-architect.github.io/articles/20250424a/"/>
    <id>https://future-architect.github.io/articles/20250424a/</id>
    <published>2025-04-23T15:00:00.000Z</published>
    <updated>2025-04-23T15:00:00.000Z</updated>
    <author><name>羽根田賢和</name></author>
    <content type="html"><![CDATA[<h2 id="はじめに">はじめに</h2><p>こんにちは。フューチャーのサマーインターン2024 Engineer Campに参加した、羽根田です。</p>
<p>インターンに参加した経緯・実際に取り組んだ内容・学会参加の後日談を、インターン体験記としてまとめます。</p>
<h3 id="概要">概要</h3><p>ここからは、私のインターン参加記を時系列順にまとめていきます。</p>
<p>私は就活の一環として本インターンに応募し、自身の研究における専門性を活かすために「自然言語処理に関する研究開発」というテーマで参加しました。業務としてはサーベイから実験といった基礎研究に取り組み、最終的にインターンの成果を国内学会で発表できました。</p>
<p>詳細はそれぞれの章にまとめていきますので、気になるところだけでも読んでいただければと思います。</p>
<img fetchpriority="high" src="/images/2025/20250424a/IMG_7896.jpg" alt="IMG_7896.jpg" width="1200" height="900">

<h3 id="応募から参加まで">応募から参加まで</h3><p>大学院修士1年の夏、私はこのインターンに参加しました。</p>
<p>大学院生としての研究生活には少しづつ慣れてきたものの、多くのM1の方と同じように、私もまた迫りくる「就活」の二文字に背中を焼かれているような状況でした。しかし、2年後の春にはどこかの企業で働いているということの想像があまりにもつかず、とにかくこのあたりのイメージを固めたいという気持ちからインターンを探し始めました。</p>
<p>こういった経緯もあり私はEngineer Campだけでなく、様々なインターンに乱れ撃つように応募をしていました。</p>
<p>私の中でのインターン先の条件としては次の2つがありました。</p>
<ul>
<li>自分の自然言語処理分野へのスキルや興味を活かせること</li>
<li>2週間以上の、ある程度長期間取り組めるものであること</li>
</ul>
<p>1つ目は私が自然言語処理の研究室に所属しており、せっかくならそこで培ったスキルがどの程度活かせるのか試してみたいという気持ちから。2つ目に関しては、比較的長期間腰を据えて参加できるものの方が自分の今後の成長につながるのではないか、という考えからです。</p>
<p>とはいえこの2つを満たせるインターンはそう多くありません。</p>
<p>さて次はどの企業のインターンに応募しようかと考えていたころ、ふと、春先に参加した言語処理学会にて「フューチャー」という企業がポスター発表をしていたことを思い出しました。この発表が面白かったこともあり、「ITコンサルも言語処理をやっているんだなあ」という意外さとともに私のなかで印象に残っていました。</p>
<p>早速調べてみるとフューチャーのサマーインターン募集ページを発見。</p>
<p>20種類近い、かなり幅広い分野のテーマで実施しており、その中には私の希望する自然言語処理分野のテーマもありました。</p>
<blockquote>
<p>大規模言語モデル（LLM）を含む自然言語処理 （NLP） 技術を活用した様々な問題の解決に、メンターとなる社員と共に挑戦していただきます。国際会議を含めた論文出版、特許取得を狙う基礎研究寄りのタスクから、実社会のデータを活用したモデル構築、実際に多くの方に使われるシステム開発まで幅広いプロセスに携わっていただきます。実際に取り組むタスクについてはご本人の希望・適性に応じて相談の上で決定します。</p>
</blockquote>
<p>という若干ふわっとした概要に一抹の不安を抱きながらも、とりあえず応募してみることにしました。</p>
<h3 id="インターン本番">インターン本番</h3><p>無事に選考を通過し、晴れてインターンに参加できることとなりました。</p>
<p>1ヵ月の長期インターンということもあり、不安な気持ちもありましたが、当初の希望通り「自然言語処理に関する研究開発」での参加ということで、かなり前向きな気持ちで臨むことができていました。</p>
<p>ここからは実際の業務内容をメインに、1ヵ月間の具体的な過ごし方をまとめていきたいと思います。</p>
<h4 id="初日">初日</h4><p>Engineer Campは基本的にはリモートで行われたのですが、顔合わせや手続きのために初日と最終日は大崎のオフィスに出社しました。緊張で目を回しそうな私を、いかにも”TOKYO”といった雰囲気の洒落たエントランスがお出迎え。ここから4週間のインターン生活がスタートしました。</p>
<p>初日はまず全体説明からはじまりました。業務で用いるパソコンのセットアップや業務内容・契約の確認などを済ませているうちにあっという間にお昼休憩の時間となりました。ランチタイムでは自分以外のインターン生や社員の方とも交流しました。</p>
<p>午後はセキュリティ講習から業務再開となり、その後受け入れ先の自然言語処理チームのメンターの方との顔合わせがありました。メンターの方々は温厚な雰囲気で話しやすく、ほっとしたことをよく覚えています。その後、オフィス内の見学やパソコンのセットアップの続きをしているうちにあっという間に終業となりました。</p>
<p>余談ですがオフィス内にはカフェスペースやボルダリングスペース（なぜ？）などがあり、かなり面白かったです。</p>
<h4 id="第1週">第1週</h4><p>1週目は基本的に、今後の活動の方針決めや環境構築などをして過ごしました。</p>
<p>私の参加したテーマは「自然言語処理に関する研究開発」であり、かなり研究寄りの業務でした。そのためまずはメンターの方々から提示された研究アイデアをもとに、この1か月間取り組むテーマを決定しました。</p>
<p>テーマに関しては、基本的には提示されたものの中から選ぶ形でしたが、あくまでインターン生の興味関心が重視されていました。メンターの方と一緒にアイデアを形にしていく感覚が強く、インターンとしては特徴的な進め方だったと思います。</p>
<p>話し合いの結果、私は「LLMを用いた文字数カウント・文字数制御」というテーマに取り組むこととなりました。</p>
<h4 id="第2週">第2週</h4><p>2週目はまず、既存研究のサーベイをすることから始まりました。</p>
<p>私のチームはインターン生1人に対しメインメンターが1人付くという形で業務を進めることになっており、学生とメンターが3組、計6名で構成されていました。基本的にはメインメンターの方と密にやり取りをしつつ、時々チーム全体での報告会をしながら、各々の研究を進めていきます。</p>
<p>そのため毎朝メインメンターの方とミーティングをする機会がありました。朝のミーティングでは、前日の進捗報告→次にやることを決定するというサポートを丁寧にしていただけるため、手が止まってしまうことや何をすればいいかわからなくなってしまうということはほとんどありませんでした。</p>
<p>万が一そうなってしまった場合でも、Slackを通じてメンターの方とはいつでもコミュニケーションが取れるため、すぐに救助を要請できました。</p>
<p>また、毎日の朝会では、業務の話以外に雑談をすることもありました。雑談は普段のコミュニケーションがより円滑になるだけでなく、社員の方の生の声が聞けるため、就職先選びという文脈においても貴重な話を聞くチャンスでした。</p>
<p>サーベイ結果のまとめ方のフィードバックや、研究のアイデア出しなどをもらいながら、2週目の段階で簡単な予備実験まで進めることができました。</p>
<p>この時期には私もかなりインターン生活に慣れており、大きなトラブルなどもなく、業務を進めることができていました。始業10分前まで布団に入っているほど<strong>慣れて</strong>しまっていたときもあるほどでした。</p>
<h4 id="第3週">第3週</h4><p>3週目ではいよいよ本格的に実験を進めることになりました。</p>
<p>基本的にはPythonでコードを書き、結果をメンターの方に共有しつつ、次の実験に向けて調整していくという流れで業務が進行していきました。2週目のサーベイからこの週の実験に至るまでは特に「研究」という色が濃かったと思います。個人的には一番熱中して作業に取り組むことができた期間でした。</p>
<p>一方で、ただ実験をしていればよい、というわけではありませんでした。最終週にインターン参加者とメンターの参加する成果発表会が控えていたためです。そのため、インターンの研究として明確にゴールを見据えて作業することが求められていました。</p>
<p>当然、1ヵ月という限られた期間での研究業務であるため、ある程度結果を出しつつ、最終の着地点を調整することは容易でありませんでした。しかしメンターの方と密にやり取りをしながら計画的に作業を進めることができたため、全体を通じて見通し良く作業ができたように思います。</p>
<p>最終週の発表会に向けてスライド作成を始めながら、この週の業務を終えました。</p>
<h4 id="第4週">第4週</h4><p>最終週は発表会への準備とインターンの締め作業とで慌ただしく過ぎていきました。</p>
<p>発表会用のスライドに関しても、メンターの方のフィードバックをもらいながら作業に取り組みました。フューチャーは会社の文化としてプレゼン能力を重視していることもあり、スライド作成についても多くの学びを得ることができました。</p>
<p>発表会当日は他のインターン参加者の発表も聞くことができました。改めてバラエティ豊かなテーマ展開だなと感じつつ、他のインターン生の発表ぶりはかなり良い刺激になりました。</p>
<p>最終日は大崎のオフィスに出社し、振り返りや後片付けなどを行い、私の<strong>インターンとしての</strong>研究業務は終了となりました。</p>
<h4 id="その他">その他</h4><p>毎週、通常の業務の他にいくつかイベントもありました。</p>
<p>1つ目は、人事の方との週次面談です。</p>
<p>インターン業務に関する相談をはじめ、就活全般のアドバイスをもらうことができます。やはりプロとは恐ろしいもので、私が進路についてフワフワとしか考えていなかったことは瞬時に見抜かれました。即席の自己分析会が開催され、そこで進路について一緒に考えてもらいました。</p>
<p>2つ目は社員の方による講義です。</p>
<p>スライドの作り方やプレゼンの仕方、プロジェクトの進め方といった講義が開かれました。社員の方ならではの貴重なお話が聞ける機会だったと思います。長期インターンであることに加えリモートでの作業であったため、どうしても<strong>慣れすぎてしまう</strong>タイミングはありました。ですが、こういったイベントがスパイスのように時折挟まれるため、全体としては業務がダレにくくなっていたように感じました。</p>
<h3 id="1日のスケジュール">1日のスケジュール</h3><ul>
<li>10:00～11:00　メインメンターとの朝会<br>　進捗を報告し、ネクストアクションを決定します。</li>
<li>11:00～12:00　午前中の作業<br>　私の場合は、朝会の振り返りをしながら午後に取り組む作業をより明確に分割して整理したりしていました。</li>
<li>12:00～13:00　お昼休憩<br>　お昼ご飯です。仮眠を取ったりした日もありました。また、休憩タイミングは任意に選べるので、休憩前の業務時間を長めに取る日もありました。</li>
<li>13:00～18:30　午後の作業<br>　実験を回したりサーベイをしたりなど、午後は腰を据えて時間のかかる作業に取り組んでいました。</li>
<li>18:30～19:00　整理など<br>　翌日の朝会に向けて資料や結果をまとめたり、日報を書いたりして過ごしました。勤務時間の申請をして退勤となります。</li>
</ul>
<h3 id="後日談：アルバイトとしての研究継続～学会まで">後日談：アルバイトとしての研究継続～学会まで</h3><p>さて、ここからはインターンの後のお話をさせていただこうと思います。</p>
<p>インターン終了後、私はアルバイトとして契約し、インターン時のテーマに関して引き続き研究業務に取り組むこととなりました。インターン後にアルバイトとして雇用されることは珍しいケースではなく、私以外にも何人かの方が継続してフューチャーで仕事をしているようです。</p>
<p>アルバイトとしての業務ではインターンの際に取り組んだテーマをさらに深堀りつつ、3月に行われる言語処理学会年次大会での発表を目標に、論文の執筆に取り組みました。インターン期間中にしっかりと方向性を定めた実験ができていたこともあり、比較的スムーズに論文を完成させることができました。</p>
<img src="/images/2025/20250424a/image.png" alt="image.png" width="562" height="352" loading="lazy">

<p>学会では長崎でポスター発表し、インターンから始まった研究をきちんと締めることができたと感じています。</p>
<p>自分がフューチャーの存在を知ることになった学会発表を、今度は自分がフューチャーの一員として行うことができたというのも感慨深いものがありました。</p>
<h3 id="インターンを通して">インターンを通して</h3><p>就職のイメージ固め、という理由から始まった私のインターン生活ですが、こうして振り返ってみると、とても多くのものを得られたように感じます。</p>
<p>まず普段の研究とは少し違ったコミュニケーションのスキルを学ぶことができました。メンターの方との認識の齟齬が生じないような伝え方の工夫や、非同期テキストコミュニケーションを効率的に活用することなど、適切な情報伝達の重要性を感じました。</p>
<p>また、個人的には「制限時間」の存在が作業の進め方に見通しを持たせてくれたとも感じています。</p>
<p>今回のインターンは1ヵ月という制限時間の中で結果をまとめる必要がありました。もちろん毎日の業務も規定された勤務時間内に行う必要があります。この制限時間によって、1ヵ月なら最終的なゴールはここにして…なら今週中にここまで進めたいから…それなら今日はここまで…と逆算して計画を立てるクセをつけられたと感じています。</p>
<p>他にもサーベイ→実験→まとめのサイクルといった研究的なスキルや、インターン生の友人やメンターの方といった人とのつながりなど、多くのものを得ることができました。</p>
<p>改めて全体を通して大きく成長できた期間だったと思います。</p>
<h2 id="さいごに">さいごに</h2><p>今回は私が参加したフューチャーのEngineer Campについて、実際の業務内容や参加者としての感想などをまとめてみました。</p>
<p>改めて、今回受け入れていただいたメンターの皆さん、大変お世話になりました。</p>
<p>最後にこの記事がインターン先を考えている方にとって少しでも参考になるところがあれば嬉しく思います。</p>
<p>ここまで読んでいただき、ありがとうございました。</p>
]]></content>
    <summary type="html">フューチャーのサマーインターン2024 Engineer Campに参加した経緯から実際にインターンで取り組んだ内容、学会参加の後日談までを、私のインターン体験記としてまとめていこうと思います。</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="NLP" scheme="https://future-architect.github.io/tags/NLP/"/>
    <category term="インターン" scheme="https://future-architect.github.io/tags/%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%B3/"/>
    <category term="インターン2024" scheme="https://future-architect.github.io/tags/%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%B32024/"/>
  </entry>
  <entry>
    <title>言語処理学会 （NLP2025）参加報告</title>
    <link href="https://future-architect.github.io/articles/20250421b/"/>
    <id>https://future-architect.github.io/articles/20250421b/</id>
    <published>2025-04-20T15:00:01.000Z</published>
    <updated>2025-04-20T15:00:01.000Z</updated>
    <author><name>松岡翔平</name></author>
    <content type="html"><![CDATA[<p>春の入門祭り2025 6日目です。</p>
<h2 id="はじめに">はじめに</h2><p>はじめまして。フューチャー株式会社の松岡と申します。私は2024年7月に当社に入社し、現在はStrategic AI Group（SAIG）の一員として大規模言語モデル（LLM）の社会実装に取り組んでいます。私自身、LLMは大学院時代の専門領域ではありませんでしたが、LLMに興味を持ち、SAIGに所属しています。現在はNLP畑出身の専門家の方々と日々の業務と技術の研鑽に取り組んでいます。</p>
<p>そんな私が、2025年3月10日（月）〜3月14日（金）において長崎出島メッセにて開催されました言語処理学会第31回年次大会（NLP2025）に初参加してきました。</p>
<p>当社はプラチナスポンサーとして参加しており、私含めてSAIG7名がオンサイトで参加し、スポンサーブースで会社を紹介し、ポスターを発表しました。</p>
<p>私は社会人1年目の新参者であるにもかかわらず、SAIG内部で参加者を募集している際に「私も参加したい」と声を上げたところ、参加できることとなりました！！快く送ってくださったSAIGの方々には感謝してもしきれません。</p>
<img fetchpriority="high" src="/images/2025/20250421b/IMG_7884.jpg" alt="" width="1200" height="900">

<h2 id="言語処理学会とは">言語処理学会とは</h2><p>言語処理学会はNLP分野における国内最大の学会で、毎年3月に開催されています。年次大会は今年で31回目となります。口頭発表は5会場に加えポスター発表2会場の合計7会場に分かれ実施され、最終日にはワークショップと盛りだくさんの内容です。</p>
<p>参加者数は当日登録含まない一日目時点で2248名、発表件数777件、スポンサー数103団体と、過去最大の参加者数、発表件数、スポンサー数であり、参加していて非常に活気がある学会でした。</p>
<p>実際に参加をしてみて、独特だなと思ったのはslackの運用です。NLP2025ではslackのワークスペースを独自に開設しており、聞きたい発表のチャンネルに入ることで、そちらから質問できました。発表内容に関する議論も積極的に行われており、その議論から知見も多く得られたと同時に言語処理学会の熱気を感じ取ることができました。</p>
<h2 id="スポンサーブース">スポンサーブース</h2><p>企業ブースを出展しAI案件実績を紹介し、人材を募集しました。当社をご存じなかった方々にもアピールでき、研究についてや案件内容に用いた技術についてのディスカッションなど、大変盛り上がりました。</p>
<p>主に学生の方へ向けては、会社紹介のパンフレットと共にノベルティとしてトートバッグを配布しながら、会社についての紹介をしました。たくさんの方々に来ていただき、大盛況でした。</p>
<img src="/images/2025/20250421b/IMG_6636_2.jpg" alt="" width="2238" height="1073" loading="lazy">

<h2 id="投稿論文の紹介">投稿論文の紹介</h2><p>当社は、NLP2025において著者・共著者を含めて合計5件の論文を投稿しました。</p>
<p>本章ではこれらの5件の論文について簡単に紹介します。</p>
<h3 id="P2-13-「数」に着目したLLMの多言語能力の検証">[P2-13]「数」に着目したLLMの多言語能力の検証</h3><p>この論文では、大規模言語モデル（LLM）の多言語能力を、LLMに単語や文の文字数を数えさせるカウントタスクと、指定した文字数で文を生成させる生成長制御タスクの2つの「数」に着目したタスクによって検証しました。</p>
<p>文字列カウントタスクでは、単語のカウントは高い精度を示しましたが、文のカウントでは精度の低下が確認されました。</p>
<p>生成長制御タスクでは、ヨーロッパ言語はヨーロッパ言語の指示で生成させる方が、アジア言語はアジア言語の指示で生成させる方が精度が高い傾向が見られました。また、中国語と日本語を生成させた場合、生成結果の平均長が指定した50文字よりも短くなる傾向がありました。さらに、日本語で指示を与えた場合、英語、スペイン語、ポルトガル語の生成結果が著しく長くなる現象が確認されました。</p>
<h3 id="P2-24-Wikipediaリダイレクト情報を活用したエンティティベース質問応答データセットの構築">[P2-24] Wikipediaリダイレクト情報を活用したエンティティベース質問応答データセットの構築</h3><p>この論文では、大規模言語モデル（LLM）がエンティティをどのように記憶しているかを調査するために、Wikipediaのリダイレクト情報を活用した新しい質問応答データセットRedirectQAを提案しています。</p>
<p>RedirectQAでは複数の表層を考慮に入れることが可能であることが特徴で、LLMがエンティティ自体を記憶しているのか、それとも特定の表層を記憶しているのかをより詳細な分析が可能です。</p>
<p>また、Pythiaの12Bモデルを用いて、作成したデータセットを用いて、LLMの記憶がエンティティではなく表層に紐づいているかを評価しました。</p>
<p>その結果、LLMは代表的な表層を記憶している場合でも、必ずしもすべてのリダイレクト表層を記憶しているわけではないことが示されました。また、表記揺れのような表層の差異が小さい場合には、記憶が紐づきやすい傾向があることも示唆されました。</p>
<h3 id="Q6-9-日本語によるコード生成能力の正確な評価に向けて">[Q6-9] 日本語によるコード生成能力の正確な評価に向けて</h3><p>この論文では、日本語によるコード生成能力の正確な評価を目的として、複数のプログラミング言語に対応したコード生成ベンチマークであるMultiPL-Eを日本語化することで、JavaおよびC++の評価データセットJMultiPL-Eを構築しました。そして、Llama-3.1-8B-Instruct（Llama）とLlama 3.1-8Bに対して日本語で継続事前学習したLlama-3.1-Swallow-8B-Instruct-v0.1（Swallow）という2つのLLMモデルを用いて、日本語でのPython、Java、C++のコード生成能力と継続事前学習がコード生成能力に与える影響を調査しました。</p>
<p>日本語で継続事前学習したSwallowでは、日本語と英語の指示文によるスコア差の縮小が確認されました。また、SwallowはJavaおよびC++において、Llamaよりも高い日本語でのコード生成能力を示しました。</p>
<h3 id="Q8-18-新聞ドメインにおける大規模言語モデルの継続事前学習と下流タスクデータ量の関係">[Q8-18]新聞ドメインにおける大規模言語モデルの継続事前学習と下流タスクデータ量の関係</h3><p>この論文では、大規模言語モデルを特定のドメインに適応させるための継続事前学習の有無と教師ありファインチューニング（SFT）に用いるデータ量が性能に与える影響について、新聞ドメインの見出し生成タスクを対象に分析しています。</p>
<p>分析では新聞記事として信濃毎日新聞株式会社が自社で執筆した紙面記事の本文、見出しを用いて、Llama-3.1-Swallow8B-v0.1、新聞記事本文で継続事前学習したモデル、日本語Wikipediaで継続事前学習したモデルの3つのモデルに対して見出し生成タスクへのSFTを行い、性能を評価しました。</p>
<p>評価の結果、SFTの学習データ量によらず基本的に新聞記事本文で継続事前学習したモデルの性能が高いことを確認しました。特に、SFTの学習データが50件など極端に少ない場合に継続事前学習の効果が大きい可能性が示唆されました。</p>
<h3 id="D9-4-MQM-Chat-対話翻訳のための多次元品質指標">[D9-4] MQM-Chat:対話翻訳のための多次元品質指標</h3><p>この論文では、従来の翻訳評価指標では捉えきれない、曖昧さ、流行語、対話の不整合性などの問題に対処するための、対話翻訳における特有の課題を評価するための新しい指標「MQM-Chat」が提案されています。</p>
<p>MQM-Chatは、誤訳、省略・追加、用語・固有名詞の誤り、不自然なスタイル、曖昧さ、流行語、対話の不整合性という7つのエラータイプで構成されており、特に最後の3つのエラータイプ（曖昧さ、流行語、対話の不整合性）が、対話翻訳に特化した新しい分類です。</p>
<p>提案されたMQM-Chatを用いて、5つの機械翻訳モデルによる中英・日英の対話翻訳を評価した結果、MQM-Chatは既存のMQMよりも詳細なエラー分類を提供し、標準MQMでは捉えきれなかった対話特有の問題を明確に識別できることが示されました。</p>
<h2 id="社員が選ぶNLP2025イチオシ論文の紹介">社員が選ぶNLP2025イチオシ論文の紹介</h2><p>本章では、NLP2025で発表された論文の中で、NLP2025に参加した7名の社員が選んだイチオシの論文を簡単に紹介します。</p>
<h3 id="Q2-4-llm-jp-judge-日本語LLM-as-a-Judge評価ツール">[Q2-4]llm-jp-judge:日本語LLM-as-a-Judge評価ツール</h3><p>この論文では、LLMの応答を自動評価するLLM-as-a-Judgeという手法を、日本語LLMに対して統一的に扱うためのツール「Llm-jp-judge」の提案と、評価ツールを用いた評価とメタ評価との比較を実施しています。</p>
<p>興味深かったのは、人によって評価する場合と、評価ツールを用いるLLM（gpt-4o）による評価の比較において、LLMの方が評価を高くつける傾向にあることが示されているということです。にもかかわらず、相関値を比較してみると正確性を除き、すべての評価指標で高い相関を得られていることが結果で示されていました。</p>
<p>LLMの自動評価ツールが注目されている中、人間よりも高い評価をつけるとはいえ、高い相関性を持つことが判明したことは今後の自動評価ツールの開発において非常に良い知見であると考え、こちらの発表を取り上げました。（松岡）</p>
<h3 id="Q2-13-架空語に対するLLMの知ったかぶりの自動評価">[Q2-13]架空語に対するLLMの知ったかぶりの自動評価</h3><p>この研究では尤もらしい架空語を生成しLLMにその意味を答えさせることで、LLMが引き起こす幻覚を分析しています。</p>
<p>架空語の生成では実際に存在しそうな尤もらしい架空語を生成する手法を提案しており、LLMの幻覚を誘発しやすい設定での実験を可能にしています。実験では尤もらしい架空語ほどLLMによる捏造が発生しやすいことを示しており、さらに追加実験ではRAGに近い設定で架空語に対する挙動を分析しており、たとえ架空語の意味をLLMに与えたとしても既存の知識に依存して幻覚が発生してしまう、という興味深い結果が得られています。</p>
<p>RAGなどの文脈において専門用語などのLLMにとって未知の単語を扱うケースは頻繁に発生し、その影響を分析することは非常に重要なタスクだと考えられるため、こちらの発表を取り上げさせていただきました。（神戸）</p>
<h3 id="P7-1-対照学習を用いたhallucination検出手法">[P7-1]対照学習を用いたhallucination検出手法</h3><p>LLMの出力に対するhallucination検出タスクにおいて、対照学習を用いて検出モデルを学習することで検出精度を向上させた研究です。</p>
<p>hallucinationを含む文章には入力文章と矛盾する情報などが含まれることから、入力文章とは乖離する埋め込み表現を持っていると仮定し、入力文章と正例（hallucinationのない文章）との埋め込みを近づけ、負例（hallucinationを含む文章）との埋め込みを遠ざけるようなtriplet lossと、通常の分類問題のlossを組み合わせることで検出器を学習しています。<br>既存のデータセットを用いた評価の結果、特にQAタスク・要約タスクにおけるhallucination検出精度が大きく向上したようです。</p>
<p>LLMのhallucinationは未だ課題であるなかで、埋め込み表現に着目したアプローチで大幅な精度向上を実現していることや、特に応用範囲の広いQA・要約タスクで効果が高いことから実用的にも重要な知見であると考え挙げさせていただきました。（岸波）</p>
<h3 id="Q3-25-VLMによるソフトウェア図表の理解に関する予備調査">[Q3-25]VLMによるソフトウェア図表の理解に関する予備調査</h3><p>この研究では、ソフトウェア開発におけるVLMの活用を目指し、ソフトウェア図表理解能力を評価するベンチマーク「JSWEMU」を開発しました。</p>
<p>このベンチマークは、図表の画像と設問で構成されており、描画スタイル、図表の種類ごとにVLMの図表理解能力を評価できます。<br>実験では、描画スタイルの正答率への影響は限定的で、図表の種類やモデルにより理解能力に差が生じるという興味深い結果が得られています。</p>
<p>VLMの得意&#x2F;不得意な領域が見えてくれば、実際の開発での活用に一歩近づくのではないかと思います。ソフトウェア開発での実応用に向けて意義のある研究だと思い、この研究を挙げさせていただきました。（加藤）</p>
<h3 id="D1-5-テキストの埋め込み表現に基づくデータ増強を用いたX（旧Twitter）における日本語の皮肉検出">[D1-5]テキストの埋め込み表現に基づくデータ増強を用いたX（旧Twitter）における日本語の皮肉検出</h3><p>皮肉検出のための新しいデータ増強手法の研究です。</p>
<p>皮肉は感情分析誤りの原因となるため、検出が必要ですが、分類器の学習に十分な規模の日本語皮肉データの収集は困難です。そこで、少数のサンプルを基に、類似データを作るデータ増強が有効です。</p>
<p>従来の増強手法は、文章の意味を表す埋め込みにノイズを加えるといった方法で微妙に異なるサンプルを作りますが、皮肉文においては「君はおめでたい人だ」を「君は喜ばしい人だ」のように変えると皮肉らしさがなくなるように、繊細なニュアンスを損なう可能性があります。そこで提案手法では、皮肉らしさに影響を与えない部分を特定し、その埋め込みにノイズを加えることで、ニュアンスを保ったままデータを増強する手法を提案しました。増強後データを利用して学習したモデルは、従来手法より高精度となりました。</p>
<p>この研究は、レビュー分析やコミュニケーション円滑化など実社会での応用に加え、皮肉という言語現象の理解にも貢献する、意義深いものだと考え、挙げさせていただきました。（肥合）</p>
<h3 id="ワークショップ1-podnikaniゴရှウ≫的聲音毎回強いメッセージを提供するかどうか模案まれたပေမယယယ့်-ตอน-ไป-のこと歓通だった。">[ワークショップ1] podnikáníゴရှウ≫的聲音毎回強いメッセージを提供するかどうか模案まれたပေမယယယ့် ตอน ไป のこと歓通だった。</h3><p>言語モデルを破壊しそうなタイトルですが…最終日のワークショップで非常に盛り上がった発表です。</p>
<p>こちらの研究では、翻訳のタスクのおいて“どう見てもおかしいのに評価値だけがなぜか高い”評価指標ハック文を作成するため、ベクトル検索の文脈等で問題となるhubnessに着目しています。</p>
<p>この発表では、ある評価指標においてあらゆる入力文でスコアが高くなるような翻訳文のベクトル表現（hubベクトル）を学習 → 文埋め込みから文に復元するような「文エンコーダの逆関数」を学習し、エンコードした際にhubベクトルに近くなるような自然（？）言語文を復元するという手順を踏んでいます。</p>
<p>得られた文を初期解として1単語ずつ評価値をより高くできるように置換すると、タイトルのようにまったく意味をなさないにも関わらず、翻訳コンペティションの上位サブミッションにも匹敵するスコアが出てしまうのは驚きです。</p>
<p>ワークショップ内の別の発表で、LLMベースの翻訳評価は“この翻訳はプロの翻訳家が作成したものです”と入れるだけで過大評価するといった報告もされていましたが、このようなモデルベース評価の脆さは昨今注目されるllm-as-a-judgeに対しても警鐘を鳴らす実りある内容だと感じました。（藤井）</p>
<h3 id="P1-19-ニューラルかな漢字変換システム-Zenzai">[P1-19] ニューラルかな漢字変換システム Zenzai</h3><p>高性能かつ高速なニューラルかな漢字変換システムを考案した研究です。</p>
<p>通常かな漢字変換システムは統計的機械学習に基づいています。時折ニューラルネットワークを用いたモデルが提案され精度面で統計モデルを上回ることがあるものの、実行時の速度的な観点から中々実用に至りませんでした。<br>この問題に対して、本研究ではニューラル言語モデルの推論時に、投機的デコーディングを併用することで推論を高速化し、実用に耐えうるレベルの速度と精度を両立しました。</p>
<p>投機的デコーディングは本来数十B〜数百Bクラスの大規模言語モデルの推論を高速化する手法として提案されましたが、それを遥かに小さいかな漢字変換モデルに対して適用したという点が興味深く、これによりニューラルかな漢字変換モデルが実用レベルとなった点は大きな貢献だと考えています。（森下）</p>
<h2 id="さいごに">さいごに</h2><p>NLPの学会初参加だったのですが、非常に多くの知見を得ることができました、特に研究の熱気に当てられ自分もさらに技術の探求を頑張らねばとやる気を新たにしています。</p>
<p>NLP2025は大学院時代の研究分野から垣根を大きく超えた先の分野ではありましたが、数多くの研究を見ることができ、とても良い刺激になりました。</p>
<p>現在SAIGではともに働くメンバーを募集しています。特にNLP分野における社会実装のニーズは根強く、多くの仲間を必要としているところです。キャリア採用ページではNLPシニアエンジニアをはじめ、NLPリサーチエンジニア及びNLPエンジニアも同じく絶賛募集中です。条件等応相談ですので、我こそはという読者の方は是非先のリンクよりご応募をお待ちしております。</p>
<p>ほかにも幅広く新卒採用およびキャリア採用を募集中です。興味のある方は是非一緒に働きましょう。よろしくお願いします！</p>
]]></content>
    <summary type="html">2025年3月10日（月）〜3月14日（金）において長崎出島メッセにて開催されました言語処理学会第31回年次大会（NLP2025）に初参加してきました。当社はプラチナスポンサーとして参加しており、私含めてSAIG7名がオンサイトで参加し、スポンサーブースで会社を紹介し、ポスターを発表しました。</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="NLP" scheme="https://future-architect.github.io/tags/NLP/"/>
    <category term="NLP2025" scheme="https://future-architect.github.io/tags/NLP2025/"/>
    <category term="参加レポート" scheme="https://future-architect.github.io/tags/%E5%8F%82%E5%8A%A0%E3%83%AC%E3%83%9D%E3%83%BC%E3%83%88/"/>
    <category term="学会" scheme="https://future-architect.github.io/tags/%E5%AD%A6%E4%BC%9A/"/>
  </entry>
  <entry>
    <title>Gemini、社内利用スタート！</title>
    <link href="https://future-architect.github.io/articles/20250311a/"/>
    <id>https://future-architect.github.io/articles/20250311a/</id>
    <published>2025-03-10T15:00:00.000Z</published>
    <updated>2025-03-10T15:00:00.000Z</updated>
    <author><name>棚井龍之介</name></author>
    <content type="html"><![CDATA[<img fetchpriority="high" src="/images/2025/20250311a/Gemini_Brand_Color.png" alt="" width="1200" height="450">

<br>

<p>米国時間の2025年1月15日に「Google AI の優れた機能を Google Workspace の Business プランと Enterprise プランに組み込むことを決定しました」でもアナウンスされた <strong>Gemini</strong> が、ついに当社内でも利用が始まりました。Chatbot Arena で常連の Gemini モデルが業務で使えるようになり、とても熱い展開なのでブログ化しました。</p>
<h2 id="はじめに">はじめに</h2><p>こんにちは。tanai（棚井龍之介） です。</p>
<p>先日、ある企業さんのオフィスへ訪問した際に、「ウチでは、〇〇（←誰もが知っている生成AIサービス）は、全員にアカウントが支給されているよ」という話を伺い、とても羨ましいなと思っていました。私の場合、<strong>業務外で</strong>  ChatGPT Plus、Felo Pro、Gemini Advanced、Mapify Pro を中心に課金して、他サービスもお試し利用しながら生成 AI ライフを送っています。</p>
<p>これらのツールが業務内で使えたら、どれほど効率化できるのだろうかと考えていたところ、ついに社内で <strong>Geminiの利用がスタート</strong> しました。Gemini Advanced と同様なので、「1.5 Pro with Deep Research」「2.0 Pro Experimental」「2.0 Flash Thinking Experimental」などの AI モデルが業務で使えるようになりました。各モデルの使い方はインターネット上でいくらでも見つかりますので、その利用例に追加する形で、私の利用例を説明します。</p>
<h2 id="上手な-AI-の使い方を、AI-に質問する">上手な AI の使い方を、AI に質問する</h2><p>「<strong>上手な AI の使い方を、AI に質問する</strong>」というのが、AI を手軽に活用する方法だと思います。</p>
<p>例えば、「1.5 Pro with Deep Research」は、プロンプトで与えた特定のトピックに対して、インターネット上の情報を収集してレポートを生成してくれる機能です。「プロンプトを与える」ということは、Few-shotプロンプティング や Chain-of-Thoughtプロンプティング などの「<strong>プロンプトエンジニアリング</strong>」のノウハウがあると、より良いアウトプットが得られます。しかしながら、これらのテクニックを習得せずとも <strong>「2.0 Flash Thinking Experimental」に「1.5 Pro with Deep Research へ投げるプロンプトを生成してもらう」</strong> ことも可能です。</p>
<h3 id="実践例-トレンド分析">実践例: トレンド分析</h3><p>「マイクロサービスのトレンド」を調査して欲しい場合、以下のフローとなります。</p>
<br>

<ul>
<li>「2.0 Flash Thinking Experimental」に投げたプロンプト</li>
</ul>
<blockquote>
<p>マイクロサービスのトレンドについて「1.5 Pro with Deep Research」に調査してもらうプロンプトを作成してください。</p>
</blockquote>
<p>↓</p>
<ul>
<li>回答</li>
</ul>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">はい、承知いたしました。「1.5 Pro with Deep Research」にマイクロサービスのトレンド調査を依頼するためのプロンプトを作成します。以下プロンプト案です。</span><br><span class="line"></span><br><span class="line">---</span><br><span class="line"></span><br><span class="line">**プロンプト:**</span><br><span class="line"></span><br><span class="line">**宛先:** 1.5 Pro</span><br><span class="line"></span><br><span class="line">**依頼事項:** マイクロサービスに関する最新トレンドの深掘り調査</span><br><span class="line"></span><br><span class="line">**調査目的:**</span><br><span class="line"></span><br><span class="line">マイクロサービス技術は、現代のソフトウェア開発において重要なアーキテクチャパターンとして広く採用されています。本調査の目的は、マイクロサービスに関する最新のトレンドを詳細に把握し、今後の技術選定や戦略策定に役立てるための知見を得ることです。特に、技術的な進化、アーキテクチャの変遷、運用方法の進化、ビジネスへの影響など、多角的な視点からトレンドを深く理解することを目指します。</span><br><span class="line"></span><br><span class="line">**調査範囲と内容:**</span><br><span class="line"></span><br><span class="line">以下のテーマに焦点を当て、マイクロサービスのトレンドを深掘り調査してください。各テーマにおいて、現状、背景、具体的な事例、将来展望を含めて分析し、詳細なレポートとしてまとめてください。</span><br><span class="line"></span><br><span class="line">1.  **技術トレンド:**</span><br><span class="line">    *   **コンテナ技術とオーケストレーション:** Kubernetes、Docker Swarm、Nomadなどの最新動向、進化、ベストプラクティス</span><br><span class="line">    *   **サーバーレスマイクロサービス:**  AWS Lambda、Azure Functions、Google Cloud Functionsなどの利用状況、ユースケース、アーキテクチャパターン</span><br><span class="line">    *   **サービスメッシュ:** Istio、Linkerd、Consul Connectなどの導入状況、メリット・デメリット、運用課題と解決策</span><br><span class="line">    *   **APIゲートウェイ:**  最新のAPIゲートウェイ技術、進化、セキュリティ、パフォーマンス最適化</span><br><span class="line">    *   **イベントドリブンアーキテクチャ (EDA):**  Kafka、RabbitMQなどのメッセージング技術を活用したマイクロサービス間連携のトレンド、設計パターン</span><br><span class="line">    *   **GraphQL:**  マイクロサービスにおけるGraphQLの採用状況、REST APIとの比較、ユースケース</span><br><span class="line">    *   **バックエンド・フォー・フロントエンド (BFF):**  BFFパターンの最新動向、具体的な実装例、メリット・デメリット</span><br><span class="line">    *   **マイクロサービスフレームワーク・言語:**  Spring Boot、Micronaut、Quarkus、Go、Rustなど、最新のフレームワークや言語の利用トレンド、選定基準</span><br><span class="line"></span><br><span class="line">2.  **アーキテクチャトレンド:**</span><br><span class="line">    *   **モノリシックからマイクロサービスへの移行:**  移行戦略、成功事例、アンチパターン、段階的移行のアプローチ</span><br><span class="line">    *   **マイクロサービスアーキテクチャの進化:**  分散トレーシング、サービスディスカバリ、サーキットブレーカーなどの実装パターンの成熟度、新たなアーキテクチャパターンの出現</span><br><span class="line">    *   **マルチクラウド・ハイブリッドクラウド環境でのマイクロサービス:**  異なるクラウド環境でのマイクロサービス展開の課題とソリューション、ベストプラクティス</span><br><span class="line">    *   **エッジコンピューティングとマイクロサービス:**  エッジ環境におけるマイクロサービス活用、ユースケース、アーキテクチャ設計</span><br><span class="line"></span><br><span class="line">3.  **運用トレンド:**</span><br><span class="line">    *   **DevOpsとマイクロサービス:**  CI/CDパイプラインの進化、自動化、インフラストラクチャ・アズ・コード (IaC) の活用</span><br><span class="line">    *   **マイクロサービスモニタリング:**  分散トレーシング、ログ集約、メトリクス収集・分析の最新ツールと手法、可観測性 (Observability) の重要性</span><br><span class="line">    *   **セキュリティ:**  マイクロサービスにおけるセキュリティ対策の進化、APIセキュリティ、認証・認可、コンテナセキュリティ</span><br><span class="line">    *   **Fault Toleranceとレジリエンス:**  サーキットブレーカー、リトライ、バルクヘッドなどの実装パターン、障害回復性の向上</span><br><span class="line"></span><br><span class="line">4.  **ビジネス・組織トレンド:**</span><br><span class="line">    *   **マイクロサービス導入の目的と効果:**  ビジネス上のメリット、導入事例、ROI (投資対効果) の評価</span><br><span class="line">    *   **組織構造とマイクロサービス:**  マイクロサービス導入に伴う組織文化、チーム編成、DevOps組織への変革</span><br><span class="line">    *   **マイクロサービス成熟度モデル:**  導入フェーズ、成熟度段階、成熟度向上のためのステップ</span><br><span class="line">    *   **マイクロサービス関連のコミュニティとエコシステム:**  主要なコミュニティ、イベント、オープンソースプロジェクト、ベンダーの動向</span><br><span class="line"></span><br><span class="line">**調査方法:**</span><br><span class="line"></span><br><span class="line">*   技術系ニュースサイト、技術ブログ、業界レポート、カンファレンス資料、学術論文、ベンダー資料など、信頼性の高い情報源を幅広く参照してください。</span><br><span class="line">*   GitHub、Stack Overflowなどの開発者向けプラットフォームでの議論やトレンドも分析に含めてください。</span><br><span class="line">*   必要に応じて、専門家へのインタビューやアンケート調査も検討してください。</span><br><span class="line">*   定量的なデータ（統計情報、導入率、成長率など）と定性的なデータ（専門家の意見、事例分析など）をバランス良く収集し、分析してください。</span><br><span class="line"></span><br><span class="line">**成果物:**</span><br><span class="line"></span><br><span class="line">以下の内容を含む詳細な調査レポートを提出してください。</span><br><span class="line"></span><br><span class="line">*   **エグゼクティブサマリー:**  調査全体の概要と主要なトレンドを簡潔にまとめたもの</span><br><span class="line">*   **詳細レポート:**  上記の調査範囲と内容に基づいて、各テーマの詳細な分析、現状、背景、具体的な事例、将来展望を記述したもの</span><br><span class="line">*   **主要トレンド一覧:**  調査結果から明らかになった主要なトレンドをリスト形式でまとめたもの</span><br><span class="line">*   **提言・示唆:**  調査結果を踏まえ、今後のマイクロサービス技術の活用や戦略策定に関する提言や示唆</span><br><span class="line"></span><br><span class="line">**その他:**</span><br><span class="line"></span><br><span class="line">*   調査の過程で疑問点や不明点があれば、遠慮なく質問してください。</span><br><span class="line">*   必要に応じて、調査の進捗状況を報告してください。</span><br><span class="line">*   レポートは、技術者だけでなく、ビジネスサイドの担当者にも理解しやすいように、専門用語を適切に解説し、図表やグラフを効果的に活用してください。</span><br><span class="line"></span><br><span class="line">**期待する成果:**</span><br><span class="line"></span><br><span class="line">この調査を通じて、マイクロサービス技術の最新トレンドを深く理解し、技術戦略、アーキテクチャ設計、運用方法、組織変革など、多岐にわたる領域での意思決定に役立つ知見が得られることを期待しています。</span><br><span class="line"></span><br><span class="line">---</span><br><span class="line"></span><br><span class="line">**プロンプトのポイント:**</span><br><span class="line"></span><br><span class="line">*   **明確な指示:** 宛先、依頼事項、調査目的、調査範囲と内容、調査方法、成果物、納期などを具体的に記述し、1.5 Proが何をすべきかを明確に指示しています。</span><br><span class="line">*   **詳細な調査範囲:**  技術トレンド、アーキテクチャトレンド、運用トレンド、ビジネス・組織トレンドの4つのカテゴリに分け、さらに具体的な調査項目をリストアップすることで、調査の焦点を絞り込んでいます。</span><br><span class="line">*   **深掘り調査の要求:**  各トレンドについて、現状だけでなく、背景、具体的な事例、将来展望を含めた分析を要求することで、「Deep Research」にふさわしい深さのある調査を促しています。</span><br><span class="line">*   **具体的な成果物:**  エグゼクティブサマリー、詳細レポート、主要トレンド一覧、提言・示唆など、具体的な成果物の形式と内容を指定することで、期待するアウトプットを明確にしています。</span><br><span class="line">*   **ビジネス視点の包含:**  ビジネス・組織トレンドの調査項目を含めることで、技術トレンドだけでなく、ビジネスへの影響や組織変革といった視点もカバーしています。</span><br><span class="line">*   **表現:**  丁寧な言葉遣いを心がけ、依頼する姿勢を示しています。</span><br><span class="line"></span><br><span class="line">このプロンプトを「1.5 Pro」に渡すことで、期待されるレベルの高いマイクロサービストレンド調査が実施されることを期待しています。</span><br></pre></td></tr></table></figure>

<p>↓</p>
<ul>
<li>「1.5 Pro with Deep Research」に「依頼事項 ~ 期待する成果」までを投下する</li>
</ul>
<img src="/images/2025/20250311a/スクリーンショット_2025-03-09_18.02.49.png" alt="スクリーンショット_2025-03-09_18.02.49.png" width="1200" height="847" loading="lazy">

<br>

<p>実際にどのような調査レポートが出力されるかは、読者みなさんの Gemini 環境で試してみてください！</p>
<br>

<p>以下2パターンの</p>
<ul>
<li>自力でプロンプトを作成して、1.5 Pro with Deep Research に投げた場合のアウトプット</li>
<li>「プロンプトの作成自体を 2.0 Flash Thinking Experimental に依頼して」その結果を 1.5 Pro with Deep Research に投げた場合のアウトプット</li>
</ul>
<p>を比較すると、後者の手法により「<strong>高度なプロンプトエンジニアリングの知識がなくても</strong>」低コストでレベルの高いプロンプトが作成できます。「プロンプト自体をAIに作らせる」ことも Tips の1つとして試してみてください。</p>
<h2 id="おわりに">おわりに</h2><p>Gemini が社内利用可能となったので、勢いでブログを執筆しました。</p>
<p>生成 AI サービスは、各ツールやモデルごとに「得意領域」がありますので、それらの「強みを組み合わせる」ことで、より効率的にアウトプットが得られると感じています。また、本ブログの「上手な AI の使い方を、AI に質問する」のように、<strong>知っていれば誰でも試せる</strong> ことが多くあると思いますので、「Gemini の Note 公式アカウント」などの活用事例が参考になります。</p>
<p>今後は、Geminiを活用して、ストーリーラインの草案作成、メール返信文の作成、アウトプットの校正など、さまざまな業務を効率化していきたいと考えています。また、冒頭で「ウチでは、〇〇（←誰もが知っている生成AIサービス）は、全員にアカウントが支給されているよ」と記載したように、業務内で「どの言語モデルが利用できるのか？」が、今後は重要なポイントになると思いました。</p>
]]></content>
    <summary type="html">米国時間の2025年1月15日に「Google AI の優れた機能を Google Workspace の Business プランと Enterprise プランに組み込むことを決定しましたで常連の Gemini モデルが業務で使えるようになり、とても熱い展開なのでブログ化しました。</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="Gemini" scheme="https://future-architect.github.io/tags/Gemini/"/>
    <category term="GoogleWorkspace" scheme="https://future-architect.github.io/tags/GoogleWorkspace/"/>
  </entry>
  <entry>
    <title>Transformerの文章生成の仕組みを理解する</title>
    <link href="https://future-architect.github.io/articles/20250226a/"/>
    <id>https://future-architect.github.io/articles/20250226a/</id>
    <published>2025-02-25T15:00:00.000Z</published>
    <updated>2025-02-25T15:00:00.000Z</updated>
    <author><name>森友雅</name></author>
    <content type="html"><![CDATA[<h2 id="本記事の前提">本記事の前提</h2><h3 id="読んでほしい人">読んでほしい人</h3><ul>
<li>Transformerを知っていて、その理解を深めたい人</li>
<li>大規模言語モデル (LLM: Large Language Model) がどのようにして推論しているのかを知りたい人</li>
</ul>
<h3 id="触れている内容">触れている内容</h3><ul>
<li>ユーザが質問をして、Transformerが回答を生成するまでの一連(end-to-end)の処理</li>
<li>Transformerの仕組みについて広く浅く</li>
</ul>
<h3 id="触れていない内容">触れていない内容</h3><ul>
<li>学習時に行われる処理（MaskやDropoutなど）</li>
<li>Pythonなどのプログラミング言語を用いたTransformerの実装方法</li>
</ul>
<h2 id="最初に「構成図」で理解する">最初に「構成図」で理解する</h2><p>まずは元論文「Attention Is All You Need」から引用したTransformerの構成図を図1に示します。</p>
<figure><img fetchpriority="high" src="/images/2025/20250226a/new_ModalNet-21.jpg" alt="" width="750" height="1105"><figcaption>図 1．元論文から引用したTransformerの構成図</figcaption></figure>
<p>とても簡潔ですが、図からは理解できない内容が多々あるかと思います。そのため、少しだけ具体化した構成図を図2に示します。できるだけ見やすく作りたかったのですが、どうしても複雑になる箇所があるため、拡大して見ていただければと思います。図2の補足ですが、EmbeddingやLinear、Layer Normalization、Softmaxは行方向（＝各Tokenのベクトル方向）に対して行われる処理であることに注意してください。</p>
<figure><img src="/images/2025/20250226a/Screenshot_2025-02-26_101047.png" alt="" width="1105" height="459" loading="lazy"><figcaption>図 2．私が作った、元論文の構成図を具体化させたTransformerの構成図</figcaption></figure>
<h2 id="次に「処理フロー」で理解する">次に「処理フロー」で理解する</h2><p>前章で示した構成図だけでは説明が不十分であるため、次は処理フローの側面から理解を深めていただこうと思います。図2と照らし合わせながら読み進めていただくと理解しやすい気がします。</p>
<p>※以下の処理フローの「3-1-2～4」や「6-3-2～4」で出てくるQ,K,VはそれぞれQuery,Key,Valueのことです。図3に図2の構成図内のどれがQ,K,Vなのかを示します。</p>
<figure><img src="/images/2025/20250226a/76fa3ac9-6b02-48c1-a1a2-8dd97951d03e.png" alt="" width="558" height="592" loading="lazy"><figcaption>図 3．図2のQ,K,Vの対応</figcaption></figure>
<figure class="highlight txt"><table><tr><td class="code"><pre><span class="line">1.質問を入力</span><br><span class="line"></span><br><span class="line">2.エンコードのための前処理</span><br><span class="line">　├ 1.Tokenizerで質問をTokenに変換(Tokenization)</span><br><span class="line">　├ 2.変換したTokenの潜在表現を抽出(Input Embedding)</span><br><span class="line">　└ 3.時系列情報を付与(Positional Encoding)</span><br><span class="line"></span><br><span class="line">3.質問をエンコード</span><br><span class="line">　├ 1.「2の結果」を用い、質問に含まれる単語間の関連度を算出(Multi-Head Attention)</span><br><span class="line">　| 　├ 1.ヘッド数分、各Tokenのベクトル方向に次元を分割</span><br><span class="line">　| 　├ 2.Q,K,Vの3つに複製し、それぞれ線形変換(Linear)</span><br><span class="line">　| 　├ 3.「Q」と「転置したK」で行列積をとり(MatMul)、確率に変換(Softmax)</span><br><span class="line">　| 　├ 4.「3-1-3の結果」と「V」で行列積をとり(MatMul)、Tokenに重みづけをする</span><br><span class="line">　|　 └ 5.分割した行列を結合し、線形変換(Linear)</span><br><span class="line">　├ 2.「2の結果」と「3-1の結果」の和を取り（Residual Connection）、各Tokenのベクトル方向に正規化(Layer Normalization)</span><br><span class="line">　├ 3.各Tokenに対し、ベクトル間の潜在表現を抽出する(Feed Forward)</span><br><span class="line">　| 　├ 1.線形変換で次元を拡張(Linear)</span><br><span class="line">　| 　├ 2.非線形変換(ReLU)</span><br><span class="line">　| 　└ 3.線形変換で次元を元に戻す(Linear)</span><br><span class="line">　├ 4.「3-2の結果」と「3-3の結果」の和を取り（Residual Connection）、各Tokenのベクトル方向に正規化(Layer Normalization)</span><br><span class="line">　└ 5.「3-1」~「3-4」の処理をN回分ループ</span><br><span class="line"></span><br><span class="line">4.生成中の文章を入力（最初は生成の開始を表す文字(BOS: Beginning of Sequence)を入力）</span><br><span class="line"></span><br><span class="line">5.デコードのための前処理（「2-1」~「2-3」と同じ）</span><br><span class="line"></span><br><span class="line">6.回答をデコード（生成）</span><br><span class="line">　├ 1.「5の結果」を用い、生成中の回答に含まれる単語間の関連度を算出(Multi-Head Attention)（「3-1-1」~「3-1-5」と同じ）</span><br><span class="line">　├ 2.「5の結果」と「6-1の結果」の和を取り（Residual Connection）、各Tokenのベクトル方向に正規化(Layer Normalization)</span><br><span class="line">　├ 3.「6-2の結果」と「3の結果」を用い、質問と生成中の回答の対応関係を算出(Multi-Head Attention)</span><br><span class="line">　| 　├ 1.「3」の出力と「6-2」の出力に対し、ヘッド数分、各Tokenのベクトル方向に次元を分割</span><br><span class="line">　| 　├ 2.「6-2の出力」をQとし、「3の出力」をK,Vとしてそれぞれ線形変換(Linear)</span><br><span class="line">　| 　├ 3.「Q」と「転置したK」で行列積をとり(MatMul)、確率に変換(Softmax)</span><br><span class="line">　| 　├ 4.「6-3-3の結果」と「V」で行列積をとり(MatMul)、Tokenに重みづけをする</span><br><span class="line">　| 　└ 5.分割した行列を結合し、線形変換(Linear)</span><br><span class="line">　├ 4.「6-2の結果」と「6-3の結果」の和を取り（Residual Connection）、各Tokenのベクトル方向に正規化(Layer Normalization)</span><br><span class="line">　├ 5.各Tokenに対し、ベクトル間の潜在表現を抽出する(Feed Forward)（「3-3」と同じ）</span><br><span class="line">　├ 6.「6-4の結果」と「6-5の結果」の和を取り（Residual Connection）、各Tokenのベクトル方向に正規化(Layer Normalization)</span><br><span class="line">　├ 7.「6-1」~「6-6」の処理をN回分ループ</span><br><span class="line">　├ 8.各Tokenのベクトル方向の次元を表現可能な単語数に増加させ(Linear)、確率に変換(Softmax)</span><br><span class="line">　└ 9.生成中の最交尾のTokenに対し、最も確率の高いTokenを次に生成する単語とする</span><br><span class="line"></span><br><span class="line">7.生成の終了を表す文字（EOS: End of Sequence）が生成されるか、生成Token数が上限になるまで「4」~「6」を繰り返す。</span><br></pre></td></tr></table></figure>

<h2 id="最後に「各処理の深掘り」で理解する">最後に「各処理の深掘り」で理解する</h2><p>これまで「構成図」と「処理フロー」で見てきましたが各段階の処理を深ぼる説明がありませんでした。そのため、最後にTransformerで利用されている処理を軽く解説します。本章で触れるのは以下の処理です。</p>
<ul>
<li>トークナイザ(Tokenizer)</li>
<li>潜在表現(Latent Representation)<ul>
<li>埋め込み(Embedding)</li>
<li>線形/全結合(Linear/Fully Connected)</li>
</ul>
</li>
<li>位置符号化(Positional Encoding)</li>
<li>注意機構(Attention)<ul>
<li>マルチヘッド注意機構(Multi-Head Attention)</li>
<li>スケール化内積注意機構(Scaled Dot-Product Attention)<ul>
<li>自己注意(Self-Attention)</li>
<li>相互注意(Cross-Attention)</li>
</ul>
</li>
</ul>
</li>
<li>正規化(Normalization)<ul>
<li>レイヤー正規化(LN:Layer Normalization)</li>
</ul>
</li>
<li>活性化関数(Activation Function)<ul>
<li>ReLU:Rectified Linear Unit</li>
</ul>
</li>
<li>出力関数(Output Function)<ul>
<li>Softmax</li>
</ul>
</li>
</ul>
<h3 id="トークナイザ-Tokenizer">トークナイザ(Tokenizer)</h3><p>Transformerは入力された文章（自然言語）のまま扱うことができません。</p>
<p>代わりに「Token」というものを扱います。Tokenとは文章を「Subword」に分割したものを指します。例えば<code>日本の首都は？</code>が入力された場合、<code>[日本, の, 首都, は, ？]</code>のように単語単位(Subword)に分割し、<code>[1234, 654, 58295, 219, 179]</code>のように 各自然言語に対応する ID に変換します。</p>
<p>この処理を行うものが「Tokenizer」であり、「Word Piece」や「BPE: Byte Pair Encoding」が有名です。「Learn about language model tokenization」ではGPT4やGPT4oのTokenizerのデモができます。</p>
<p>このサイトのTokenizerはBPEベースの「Tiktoken」というモデルを利用しています。</p>
<h3 id="埋め込み-Embedding">埋め込み(Embedding)</h3><p>Tokenizerで得たTokenの潜在表現を抽出します。例えば<code>[1234, 654, 58295, 219, 179]</code>のようなTokenを<code>[[1.0, 0.2, ..., 0.3], [0.4, 0.2, ..., 1.0], [0.2, 0.2, ..., 0.1], [0.5, 0.3, ..., 0.7], [0.9, 0.2, ..., 0.1]]</code>のように、各Tokenの値をD次元に拡張します。そうすることで、類似した意味を持つTokenを同じ方向や、同じ大きさのベクトルとして表現できます。</p>
<p>Embeddingは事前に学習された重みを利用することもあります。</p>
<h3 id="線形-全結合-Linear-Fully-Connected">線形/全結合(Linear/Fully Connected)</h3><p>学習可能なパラメータを利用して入力した潜在表現を変換します。学習可能なパラメータの数は調整でき、この調整次第で変換後の次元数を増減させることができます。</p>
<h3 id="位置符号化-Positional-Encoding">位置符号化(Positional Encoding)</h3><p>Embeddingで得られた潜在表現には 時系列情報がありません。これは<code>[日本, の, 首都, は, ？]</code>と<code>[の, 首都, ？, 日本, は]</code>が同じ文章と言っているようなものです。そのため、時系列の意味合いを持つ値を各潜在表現に加算することで時系列情報を付与します。</p>
<p>Embeddingで得られた潜在表現に悪影響を及ぼさない大きさで、相対的な変化を持たせやすい値を加算する必要があります。元論文では以下の式で算出される値を加算しています。sinとcosの1波長は2πであるため、「pos = 2π*10000」が一意の位置情報を付与できるToken数の上限であることがわかります。</p>
<p><mjx-container class="MathJax" jax="SVG" display="true"><svg style="vertical-align: -2.827ex;" xmlns="http://www.w3.org/2000/svg" width="57.386ex" height="6.785ex" role="img" focusable="false" viewBox="0 -1749.5 25364.8 2999"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D443" d="M287 628Q287 635 230 637Q206 637 199 638T192 648Q192 649 194 659Q200 679 203 681T397 683Q587 682 600 680Q664 669 707 631T751 530Q751 453 685 389Q616 321 507 303Q500 302 402 301H307L277 182Q247 66 247 59Q247 55 248 54T255 50T272 48T305 46H336Q342 37 342 35Q342 19 335 5Q330 0 319 0Q316 0 282 1T182 2Q120 2 87 2T51 1Q33 1 33 11Q33 13 36 25Q40 41 44 43T67 46Q94 46 127 49Q141 52 146 61Q149 65 218 339T287 628ZM645 554Q645 567 643 575T634 597T609 619T560 635Q553 636 480 637Q463 637 445 637T416 636T404 636Q391 635 386 627Q384 621 367 550T332 412T314 344Q314 342 395 342H407H430Q542 342 590 392Q617 419 631 471T645 554Z"></path></g><g data-mml-node="mi" transform="translate(751,0)"><path data-c="1D45C" d="M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z"></path></g><g data-mml-node="mi" transform="translate(1236,0)"><path data-c="1D460" d="M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z"></path></g><g data-mml-node="mi" transform="translate(1705,0)"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z"></path></g><g data-mml-node="mi" transform="translate(2050,0)"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z"></path></g><g data-mml-node="mi" transform="translate(2411,0)"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z"></path></g><g data-mml-node="mi" transform="translate(2756,0)"><path data-c="1D45C" d="M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z"></path></g><g data-mml-node="mi" transform="translate(3241,0)"><path data-c="1D45B" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z"></path></g><g data-mml-node="mi" transform="translate(3841,0)"><path data-c="1D44E" d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z"></path></g><g data-mml-node="mi" transform="translate(4370,0)"><path data-c="1D459" d="M117 59Q117 26 142 26Q179 26 205 131Q211 151 215 152Q217 153 225 153H229Q238 153 241 153T246 151T248 144Q247 138 245 128T234 90T214 43T183 6T137 -11Q101 -11 70 11T38 85Q38 97 39 102L104 360Q167 615 167 623Q167 626 166 628T162 632T157 634T149 635T141 636T132 637T122 637Q112 637 109 637T101 638T95 641T94 647Q94 649 96 661Q101 680 107 682T179 688Q194 689 213 690T243 693T254 694Q266 694 266 686Q266 675 193 386T118 83Q118 81 118 75T117 65V59Z"></path></g><g data-mml-node="mi" transform="translate(4668,0)"><path data-c="1D438" d="M492 213Q472 213 472 226Q472 230 477 250T482 285Q482 316 461 323T364 330H312Q311 328 277 192T243 52Q243 48 254 48T334 46Q428 46 458 48T518 61Q567 77 599 117T670 248Q680 270 683 272Q690 274 698 274Q718 274 718 261Q613 7 608 2Q605 0 322 0H133Q31 0 31 11Q31 13 34 25Q38 41 42 43T65 46Q92 46 125 49Q139 52 144 61Q146 66 215 342T285 622Q285 629 281 629Q273 632 228 634H197Q191 640 191 642T193 659Q197 676 203 680H757Q764 676 764 669Q764 664 751 557T737 447Q735 440 717 440H705Q698 445 698 453L701 476Q704 500 704 528Q704 558 697 578T678 609T643 625T596 632T532 634H485Q397 633 392 631Q388 629 386 622Q385 619 355 499T324 377Q347 376 372 376H398Q464 376 489 391T534 472Q538 488 540 490T557 493Q562 493 565 493T570 492T572 491T574 487T577 483L544 351Q511 218 508 216Q505 213 492 213Z"></path></g><g data-mml-node="mi" transform="translate(5432,0)"><path data-c="1D45B" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z"></path></g><g data-mml-node="mi" transform="translate(6032,0)"><path data-c="1D450" d="M34 159Q34 268 120 355T306 442Q362 442 394 418T427 355Q427 326 408 306T360 285Q341 285 330 295T319 325T330 359T352 380T366 386H367Q367 388 361 392T340 400T306 404Q276 404 249 390Q228 381 206 359Q162 315 142 235T121 119Q121 73 147 50Q169 26 205 26H209Q321 26 394 111Q403 121 406 121Q410 121 419 112T429 98T420 83T391 55T346 25T282 0T202 -11Q127 -11 81 37T34 159Z"></path></g><g data-mml-node="mi" transform="translate(6465,0)"><path data-c="1D45C" d="M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z"></path></g><g data-mml-node="mi" transform="translate(6950,0)"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z"></path></g><g data-mml-node="mi" transform="translate(7470,0)"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z"></path></g><g data-mml-node="mi" transform="translate(7815,0)"><path data-c="1D45B" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z"></path></g><g data-mml-node="mi" transform="translate(8415,0)"><path data-c="1D454" d="M311 43Q296 30 267 15T206 0Q143 0 105 45T66 160Q66 265 143 353T314 442Q361 442 401 394L404 398Q406 401 409 404T418 412T431 419T447 422Q461 422 470 413T480 394Q480 379 423 152T363 -80Q345 -134 286 -169T151 -205Q10 -205 10 -137Q10 -111 28 -91T74 -71Q89 -71 102 -80T116 -111Q116 -121 114 -130T107 -144T99 -154T92 -162L90 -164H91Q101 -167 151 -167Q189 -167 211 -155Q234 -144 254 -122T282 -75Q288 -56 298 -13Q311 35 311 43ZM384 328L380 339Q377 350 375 354T369 368T359 382T346 393T328 402T306 405Q262 405 221 352Q191 313 171 233T151 117Q151 38 213 38Q269 38 323 108L331 118L384 328Z"></path></g><g data-mml-node="mo" transform="translate(9169.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path></g><g data-mml-node="mrow" transform="translate(10225.6,0)"><g data-mml-node="mo" transform="translate(0 -0.5)"><path data-c="7B" d="M661 -1243L655 -1249H622L604 -1240Q503 -1190 434 -1107T348 -909Q346 -897 346 -499L345 -98L343 -82Q335 3 287 87T157 223Q146 232 145 236Q144 240 144 250Q144 265 145 268T157 278Q242 333 288 417T343 583L345 600L346 1001Q346 1398 348 1410Q379 1622 600 1739L622 1750H655L661 1744V1727V1721Q661 1712 661 1710T657 1705T648 1700T630 1690T602 1668Q589 1659 574 1643T531 1593T484 1508T459 1398Q458 1389 458 1001Q458 614 457 605Q441 435 301 316Q254 277 202 251L250 222Q260 216 301 185Q443 66 457 -104Q458 -113 458 -501Q458 -888 459 -897Q463 -944 478 -988T509 -1060T548 -1114T580 -1149T602 -1167Q620 -1183 634 -1192T653 -1202T659 -1207T661 -1220V-1226V-1243Z"></path></g><g data-mml-node="mtable" transform="translate(806,0)"><g data-mml-node="mtr" transform="translate(0,700)"><g data-mml-node="mtd"><g data-mml-node="mi"><path data-c="1D460" d="M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z"></path></g><g data-mml-node="mi" transform="translate(469,0)"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z"></path></g><g data-mml-node="mi" transform="translate(814,0)"><path data-c="1D45B" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z"></path></g><g data-mml-node="mo" transform="translate(1414,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z"></path></g><g data-mml-node="mi" transform="translate(1803,0)"><path data-c="1D45D" d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z"></path></g><g data-mml-node="mi" transform="translate(2306,0)"><path data-c="1D45C" d="M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z"></path></g><g data-mml-node="mi" transform="translate(2791,0)"><path data-c="1D460" d="M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z"></path></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(3260,0)"><g data-mml-node="mo"><path data-c="2F" d="M423 750Q432 750 438 744T444 730Q444 725 271 248T92 -240Q85 -250 75 -250Q68 -250 62 -245T56 -231Q56 -221 230 257T407 740Q411 750 423 750Z"></path></g></g><g data-mml-node="msup" transform="translate(3760,0)"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)"></path><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(1000,0)"></path><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(1500,0)"></path><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(2000,0)"></path></g><g data-mml-node="TeXAtom" transform="translate(2533,393.1) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mi"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z"></path></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(345,0)"><g data-mml-node="mo"><path data-c="2F" d="M423 750Q432 750 438 744T444 730Q444 725 271 248T92 -240Q85 -250 75 -250Q68 -250 62 -245T56 -231Q56 -221 230 257T407 740Q411 750 423 750Z"></path></g></g><g data-mml-node="mi" transform="translate(845,0)"><path data-c="1D437" d="M287 628Q287 635 230 637Q207 637 200 638T193 647Q193 655 197 667T204 682Q206 683 403 683Q570 682 590 682T630 676Q702 659 752 597T803 431Q803 275 696 151T444 3L430 1L236 0H125H72Q48 0 41 2T33 11Q33 13 36 25Q40 41 44 43T67 46Q94 46 127 49Q141 52 146 61Q149 65 218 339T287 628ZM703 469Q703 507 692 537T666 584T629 613T590 629T555 636Q553 636 541 636T512 636T479 637H436Q392 637 386 627Q384 623 313 339T242 52Q242 48 253 48T330 47Q335 47 349 47T373 46Q499 46 581 128Q617 164 640 212T683 339T703 469Z"></path></g></g></g><g data-mml-node="mo" transform="translate(7526,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z"></path></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(7915,0)"><g data-mml-node="mo"><text data-variant="normal" transform="scale(1,-1)" font-size="884px" font-family="serif">　</text></g></g><g data-mml-node="mo" transform="translate(8915,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z"></path></g><g data-mml-node="mi" transform="translate(9304,0)"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z"></path></g><g data-mml-node="mo" transform="translate(9926.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path></g><g data-mml-node="mn" transform="translate(10982.5,0)"><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z"></path></g><g data-mml-node="mo" transform="translate(11482.5,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z"></path></g><g data-mml-node="mi" transform="translate(11927.2,0)"><path data-c="1D452" d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z"></path></g><g data-mml-node="mi" transform="translate(12393.2,0)"><path data-c="1D463" d="M173 380Q173 405 154 405Q130 405 104 376T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Q21 294 29 316T53 368T97 419T160 441Q202 441 225 417T249 361Q249 344 246 335Q246 329 231 291T200 202T182 113Q182 86 187 69Q200 26 250 26Q287 26 319 60T369 139T398 222T409 277Q409 300 401 317T383 343T365 361T357 383Q357 405 376 424T417 443Q436 443 451 425T467 367Q467 340 455 284T418 159T347 40T241 -11Q177 -11 139 22Q102 54 102 117Q102 148 110 181T151 298Q173 362 173 380Z"></path></g><g data-mml-node="mi" transform="translate(12878.2,0)"><path data-c="1D452" d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z"></path></g><g data-mml-node="mi" transform="translate(13344.2,0)"><path data-c="1D45B" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z"></path></g><g data-mml-node="mo" transform="translate(13944.2,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z"></path></g></g></g><g data-mml-node="mtr" transform="translate(0,-873.4)"><g data-mml-node="mtd"><g data-mml-node="mi"><path data-c="1D450" d="M34 159Q34 268 120 355T306 442Q362 442 394 418T427 355Q427 326 408 306T360 285Q341 285 330 295T319 325T330 359T352 380T366 386H367Q367 388 361 392T340 400T306 404Q276 404 249 390Q228 381 206 359Q162 315 142 235T121 119Q121 73 147 50Q169 26 205 26H209Q321 26 394 111Q403 121 406 121Q410 121 419 112T429 98T420 83T391 55T346 25T282 0T202 -11Q127 -11 81 37T34 159Z"></path></g><g data-mml-node="mi" transform="translate(433,0)"><path data-c="1D45C" d="M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z"></path></g><g data-mml-node="mi" transform="translate(918,0)"><path data-c="1D460" d="M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z"></path></g><g data-mml-node="mo" transform="translate(1387,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z"></path></g><g data-mml-node="mi" transform="translate(1776,0)"><path data-c="1D45D" d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z"></path></g><g data-mml-node="mi" transform="translate(2279,0)"><path data-c="1D45C" d="M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z"></path></g><g data-mml-node="mi" transform="translate(2764,0)"><path data-c="1D460" d="M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z"></path></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(3233,0)"><g data-mml-node="mo"><path data-c="2F" d="M423 750Q432 750 438 744T444 730Q444 725 271 248T92 -240Q85 -250 75 -250Q68 -250 62 -245T56 -231Q56 -221 230 257T407 740Q411 750 423 750Z"></path></g></g><g data-mml-node="msup" transform="translate(3733,0)"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)"></path><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(1000,0)"></path><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(1500,0)"></path><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(2000,0)"></path></g><g data-mml-node="TeXAtom" transform="translate(2533,393.1) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mi"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z"></path></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(345,0)"><g data-mml-node="mo"><path data-c="2F" d="M423 750Q432 750 438 744T444 730Q444 725 271 248T92 -240Q85 -250 75 -250Q68 -250 62 -245T56 -231Q56 -221 230 257T407 740Q411 750 423 750Z"></path></g></g><g data-mml-node="mi" transform="translate(845,0)"><path data-c="1D437" d="M287 628Q287 635 230 637Q207 637 200 638T193 647Q193 655 197 667T204 682Q206 683 403 683Q570 682 590 682T630 676Q702 659 752 597T803 431Q803 275 696 151T444 3L430 1L236 0H125H72Q48 0 41 2T33 11Q33 13 36 25Q40 41 44 43T67 46Q94 46 127 49Q141 52 146 61Q149 65 218 339T287 628ZM703 469Q703 507 692 537T666 584T629 613T590 629T555 636Q553 636 541 636T512 636T479 637H436Q392 637 386 627Q384 623 313 339T242 52Q242 48 253 48T330 47Q335 47 349 47T373 46Q499 46 581 128Q617 164 640 212T683 339T703 469Z"></path></g></g></g><g data-mml-node="mo" transform="translate(7499,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z"></path></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(7888,0)"><g data-mml-node="mo"><text data-variant="normal" transform="scale(1,-1)" font-size="884px" font-family="serif">　</text></g></g><g data-mml-node="mo" transform="translate(8888,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z"></path></g><g data-mml-node="mi" transform="translate(9277,0)"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z"></path></g><g data-mml-node="mo" transform="translate(9899.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path></g><g data-mml-node="mi" transform="translate(10955.5,0)"><path data-c="1D45C" d="M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z"></path></g><g data-mml-node="mi" transform="translate(11440.5,0)"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z"></path></g><g data-mml-node="mi" transform="translate(11960.5,0)"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z"></path></g><g data-mml-node="mo" transform="translate(12480.5,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z"></path></g></g></g></g><g data-mml-node="mo" transform="translate(15139.2,0) translate(0 250)"></g></g></g></g></svg></mjx-container></p>
<h3 id="マルチヘッド注意機構-Multi-Head-Attention">マルチヘッド注意機構(Multi-Head Attention)</h3><p>次で説明する「Scaled Dot-Product Attention」をN個に分割して処理するための機構です。</p>
<p>Embeddingで各TokenをD次元に拡張しますが、分割がない場合、1点の尺度でToken間の関連度を求めることになります。Multi-Head Attentionを導入し、D次元をN個に分割して並列で処理させることで、N点の尺度でToken間の関連度を求めることができるようになります。</p>
<p>これがMulti-Head Attentionの強みです。各ヘッドの次元数は「D/ヘッド数」です。</p>
<figure><img src="/images/2025/20250226a/multi-head-attention_l1A3G7a.png" alt="" width="576" height="746" loading="lazy"><figcaption>図 4．元論文から引用したMulti-Head Attentionの構成図</figcaption></figure>
<h3 id="スケール化内積注意機構-Scaled-Dot-Product-Attention">スケール化内積注意機構(Scaled Dot-Product Attention)</h3><p>トークン間の類似度を内積で求めます。はじめに、QとKで行列積をとり、Dの平方根で除算します。Dの平方根を除算している理由はQとKの行列積の値を標準化するためです。</p>
<p>行列積の値はDの値が大きくなるほど最大値が大きくなります。それだと学習が進まなくなるため、Dの平方根を除算して学習の安定化をしています。次に、除算した行列とVで行列積をとり、後で説明するSoftmax関数に通すことでトークン間の類似度が確率分布で求まります。</p>
<figure><img src="/images/2025/20250226a/35184258-10f5-4cd0-8de3-bd9bc8f88dc3.png" alt="" width="684" height="732" loading="lazy"><figcaption>図 5．元論文から引用したScaled-Dot Product Attentionの構成図</figcaption></figure>
<p><mjx-container class="MathJax" jax="SVG" display="true"><svg style="vertical-align: -2.305ex;" xmlns="http://www.w3.org/2000/svg" width="50.046ex" height="5.741ex" role="img" focusable="false" viewBox="0 -1518.9 22120.4 2537.7"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mtable"><g data-mml-node="mtr" transform="translate(0,1.1)"><g data-mml-node="mtd"><g data-mml-node="mi"><path data-c="1D446" d="M308 24Q367 24 416 76T466 197Q466 260 414 284Q308 311 278 321T236 341Q176 383 176 462Q176 523 208 573T273 648Q302 673 343 688T407 704H418H425Q521 704 564 640Q565 640 577 653T603 682T623 704Q624 704 627 704T632 705Q645 705 645 698T617 577T585 459T569 456Q549 456 549 465Q549 471 550 475Q550 478 551 494T553 520Q553 554 544 579T526 616T501 641Q465 662 419 662Q362 662 313 616T263 510Q263 480 278 458T319 427Q323 425 389 408T456 390Q490 379 522 342T554 242Q554 216 546 186Q541 164 528 137T492 78T426 18T332 -20Q320 -22 298 -22Q199 -22 144 33L134 44L106 13Q83 -14 78 -18T65 -22Q52 -22 52 -14Q52 -11 110 221Q112 227 130 227H143Q149 221 149 216Q149 214 148 207T144 186T142 153Q144 114 160 87T203 47T255 29T308 24Z"></path></g><g data-mml-node="mi" transform="translate(645,0)"><path data-c="1D450" d="M34 159Q34 268 120 355T306 442Q362 442 394 418T427 355Q427 326 408 306T360 285Q341 285 330 295T319 325T330 359T352 380T366 386H367Q367 388 361 392T340 400T306 404Q276 404 249 390Q228 381 206 359Q162 315 142 235T121 119Q121 73 147 50Q169 26 205 26H209Q321 26 394 111Q403 121 406 121Q410 121 419 112T429 98T420 83T391 55T346 25T282 0T202 -11Q127 -11 81 37T34 159Z"></path></g><g data-mml-node="mi" transform="translate(1078,0)"><path data-c="1D44E" d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z"></path></g><g data-mml-node="mi" transform="translate(1607,0)"><path data-c="1D459" d="M117 59Q117 26 142 26Q179 26 205 131Q211 151 215 152Q217 153 225 153H229Q238 153 241 153T246 151T248 144Q247 138 245 128T234 90T214 43T183 6T137 -11Q101 -11 70 11T38 85Q38 97 39 102L104 360Q167 615 167 623Q167 626 166 628T162 632T157 634T149 635T141 636T132 637T122 637Q112 637 109 637T101 638T95 641T94 647Q94 649 96 661Q101 680 107 682T179 688Q194 689 213 690T243 693T254 694Q266 694 266 686Q266 675 193 386T118 83Q118 81 118 75T117 65V59Z"></path></g><g data-mml-node="mi" transform="translate(1905,0)"><path data-c="1D452" d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z"></path></g><g data-mml-node="mi" transform="translate(2371,0)"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z"></path></g><g data-mml-node="mi" transform="translate(2891,0)"><path data-c="1D437" d="M287 628Q287 635 230 637Q207 637 200 638T193 647Q193 655 197 667T204 682Q206 683 403 683Q570 682 590 682T630 676Q702 659 752 597T803 431Q803 275 696 151T444 3L430 1L236 0H125H72Q48 0 41 2T33 11Q33 13 36 25Q40 41 44 43T67 46Q94 46 127 49Q141 52 146 61Q149 65 218 339T287 628ZM703 469Q703 507 692 537T666 584T629 613T590 629T555 636Q553 636 541 636T512 636T479 637H436Q392 637 386 627Q384 623 313 339T242 52Q242 48 253 48T330 47Q335 47 349 47T373 46Q499 46 581 128Q617 164 640 212T683 339T703 469Z"></path></g><g data-mml-node="mi" transform="translate(3719,0)"><path data-c="1D45C" d="M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z"></path></g><g data-mml-node="mi" transform="translate(4204,0)"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z"></path></g><g data-mml-node="mi" transform="translate(4565,0)"><path data-c="1D443" d="M287 628Q287 635 230 637Q206 637 199 638T192 648Q192 649 194 659Q200 679 203 681T397 683Q587 682 600 680Q664 669 707 631T751 530Q751 453 685 389Q616 321 507 303Q500 302 402 301H307L277 182Q247 66 247 59Q247 55 248 54T255 50T272 48T305 46H336Q342 37 342 35Q342 19 335 5Q330 0 319 0Q316 0 282 1T182 2Q120 2 87 2T51 1Q33 1 33 11Q33 13 36 25Q40 41 44 43T67 46Q94 46 127 49Q141 52 146 61Q149 65 218 339T287 628ZM645 554Q645 567 643 575T634 597T609 619T560 635Q553 636 480 637Q463 637 445 637T416 636T404 636Q391 635 386 627Q384 621 367 550T332 412T314 344Q314 342 395 342H407H430Q542 342 590 392Q617 419 631 471T645 554Z"></path></g><g data-mml-node="mi" transform="translate(5316,0)"><path data-c="1D45F" d="M21 287Q22 290 23 295T28 317T38 348T53 381T73 411T99 433T132 442Q161 442 183 430T214 408T225 388Q227 382 228 382T236 389Q284 441 347 441H350Q398 441 422 400Q430 381 430 363Q430 333 417 315T391 292T366 288Q346 288 334 299T322 328Q322 376 378 392Q356 405 342 405Q286 405 239 331Q229 315 224 298T190 165Q156 25 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 114 189T154 366Q154 405 128 405Q107 405 92 377T68 316T57 280Q55 278 41 278H27Q21 284 21 287Z"></path></g><g data-mml-node="mi" transform="translate(5767,0)"><path data-c="1D45C" d="M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z"></path></g><g data-mml-node="mi" transform="translate(6252,0)"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z"></path></g><g data-mml-node="mi" transform="translate(6772,0)"><path data-c="1D462" d="M21 287Q21 295 30 318T55 370T99 420T158 442Q204 442 227 417T250 358Q250 340 216 246T182 105Q182 62 196 45T238 27T291 44T328 78L339 95Q341 99 377 247Q407 367 413 387T427 416Q444 431 463 431Q480 431 488 421T496 402L420 84Q419 79 419 68Q419 43 426 35T447 26Q469 29 482 57T512 145Q514 153 532 153Q551 153 551 144Q550 139 549 130T540 98T523 55T498 17T462 -8Q454 -10 438 -10Q372 -10 347 46Q345 45 336 36T318 21T296 6T267 -6T233 -11Q189 -11 155 7Q103 38 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z"></path></g><g data-mml-node="mi" transform="translate(7344,0)"><path data-c="1D450" d="M34 159Q34 268 120 355T306 442Q362 442 394 418T427 355Q427 326 408 306T360 285Q341 285 330 295T319 325T330 359T352 380T366 386H367Q367 388 361 392T340 400T306 404Q276 404 249 390Q228 381 206 359Q162 315 142 235T121 119Q121 73 147 50Q169 26 205 26H209Q321 26 394 111Q403 121 406 121Q410 121 419 112T429 98T420 83T391 55T346 25T282 0T202 -11Q127 -11 81 37T34 159Z"></path></g><g data-mml-node="mi" transform="translate(7777,0)"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z"></path></g><g data-mml-node="mi" transform="translate(8138,0)"><path data-c="1D434" d="M208 74Q208 50 254 46Q272 46 272 35Q272 34 270 22Q267 8 264 4T251 0Q249 0 239 0T205 1T141 2Q70 2 50 0H42Q35 7 35 11Q37 38 48 46H62Q132 49 164 96Q170 102 345 401T523 704Q530 716 547 716H555H572Q578 707 578 706L606 383Q634 60 636 57Q641 46 701 46Q726 46 726 36Q726 34 723 22Q720 7 718 4T704 0Q701 0 690 0T651 1T578 2Q484 2 455 0H443Q437 6 437 9T439 27Q443 40 445 43L449 46H469Q523 49 533 63L521 213H283L249 155Q208 86 208 74ZM516 260Q516 271 504 416T490 562L463 519Q447 492 400 412L310 260L413 259Q516 259 516 260Z"></path></g><g data-mml-node="mi" transform="translate(8888,0)"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z"></path></g><g data-mml-node="mi" transform="translate(9249,0)"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z"></path></g><g data-mml-node="mi" transform="translate(9610,0)"><path data-c="1D452" d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z"></path></g><g data-mml-node="mi" transform="translate(10076,0)"><path data-c="1D45B" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z"></path></g><g data-mml-node="mi" transform="translate(10676,0)"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z"></path></g><g data-mml-node="mi" transform="translate(11037,0)"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z"></path></g><g data-mml-node="mi" transform="translate(11382,0)"><path data-c="1D45C" d="M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z"></path></g><g data-mml-node="mi" transform="translate(11867,0)"><path data-c="1D45B" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z"></path></g><g data-mml-node="mo" transform="translate(12744.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path></g><g data-mml-node="mi" transform="translate(13800.6,0)"><path data-c="1D446" d="M308 24Q367 24 416 76T466 197Q466 260 414 284Q308 311 278 321T236 341Q176 383 176 462Q176 523 208 573T273 648Q302 673 343 688T407 704H418H425Q521 704 564 640Q565 640 577 653T603 682T623 704Q624 704 627 704T632 705Q645 705 645 698T617 577T585 459T569 456Q549 456 549 465Q549 471 550 475Q550 478 551 494T553 520Q553 554 544 579T526 616T501 641Q465 662 419 662Q362 662 313 616T263 510Q263 480 278 458T319 427Q323 425 389 408T456 390Q490 379 522 342T554 242Q554 216 546 186Q541 164 528 137T492 78T426 18T332 -20Q320 -22 298 -22Q199 -22 144 33L134 44L106 13Q83 -14 78 -18T65 -22Q52 -22 52 -14Q52 -11 110 221Q112 227 130 227H143Q149 221 149 216Q149 214 148 207T144 186T142 153Q144 114 160 87T203 47T255 29T308 24Z"></path></g><g data-mml-node="mi" transform="translate(14445.6,0)"><path data-c="1D45C" d="M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z"></path></g><g data-mml-node="mi" transform="translate(14930.6,0)"><path data-c="1D453" d="M118 -162Q120 -162 124 -164T135 -167T147 -168Q160 -168 171 -155T187 -126Q197 -99 221 27T267 267T289 382V385H242Q195 385 192 387Q188 390 188 397L195 425Q197 430 203 430T250 431Q298 431 298 432Q298 434 307 482T319 540Q356 705 465 705Q502 703 526 683T550 630Q550 594 529 578T487 561Q443 561 443 603Q443 622 454 636T478 657L487 662Q471 668 457 668Q445 668 434 658T419 630Q412 601 403 552T387 469T380 433Q380 431 435 431Q480 431 487 430T498 424Q499 420 496 407T491 391Q489 386 482 386T428 385H372L349 263Q301 15 282 -47Q255 -132 212 -173Q175 -205 139 -205Q107 -205 81 -186T55 -132Q55 -95 76 -78T118 -61Q162 -61 162 -103Q162 -122 151 -136T127 -157L118 -162Z"></path></g><g data-mml-node="mi" transform="translate(15480.6,0)"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z"></path></g><g data-mml-node="mi" transform="translate(15841.6,0)"><path data-c="1D45A" d="M21 287Q22 293 24 303T36 341T56 388T88 425T132 442T175 435T205 417T221 395T229 376L231 369Q231 367 232 367L243 378Q303 442 384 442Q401 442 415 440T441 433T460 423T475 411T485 398T493 385T497 373T500 364T502 357L510 367Q573 442 659 442Q713 442 746 415T780 336Q780 285 742 178T704 50Q705 36 709 31T724 26Q752 26 776 56T815 138Q818 149 821 151T837 153Q857 153 857 145Q857 144 853 130Q845 101 831 73T785 17T716 -10Q669 -10 648 17T627 73Q627 92 663 193T700 345Q700 404 656 404H651Q565 404 506 303L499 291L466 157Q433 26 428 16Q415 -11 385 -11Q372 -11 364 -4T353 8T350 18Q350 29 384 161L420 307Q423 322 423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 181Q151 335 151 342Q154 357 154 369Q154 405 129 405Q107 405 92 377T69 316T57 280Q55 278 41 278H27Q21 284 21 287Z"></path></g><g data-mml-node="mi" transform="translate(16719.6,0)"><path data-c="1D44E" d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z"></path></g><g data-mml-node="mi" transform="translate(17248.6,0)"><path data-c="1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z"></path></g><g data-mml-node="mo" transform="translate(17820.6,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z"></path></g><g data-mml-node="mfrac" transform="translate(18209.6,0)"><g data-mml-node="mrow" transform="translate(220,676)"><g data-mml-node="mi"><path data-c="1D444" d="M399 -80Q399 -47 400 -30T402 -11V-7L387 -11Q341 -22 303 -22Q208 -22 138 35T51 201Q50 209 50 244Q50 346 98 438T227 601Q351 704 476 704Q514 704 524 703Q621 689 680 617T740 435Q740 255 592 107Q529 47 461 16L444 8V3Q444 2 449 -24T470 -66T516 -82Q551 -82 583 -60T625 -3Q631 11 638 11Q647 11 649 2Q649 -6 639 -34T611 -100T557 -165T481 -194Q399 -194 399 -87V-80ZM636 468Q636 523 621 564T580 625T530 655T477 665Q429 665 379 640Q277 591 215 464T153 216Q153 110 207 59Q231 38 236 38V46Q236 86 269 120T347 155Q372 155 390 144T417 114T429 82T435 55L448 64Q512 108 557 185T619 334T636 468ZM314 18Q362 18 404 39L403 49Q399 104 366 115Q354 117 347 117Q344 117 341 117T337 118Q317 118 296 98T274 52Q274 18 314 18Z"></path></g><g data-mml-node="msup" transform="translate(791,0)"><g data-mml-node="mi"><path data-c="1D43E" d="M285 628Q285 635 228 637Q205 637 198 638T191 647Q191 649 193 661Q199 681 203 682Q205 683 214 683H219Q260 681 355 681Q389 681 418 681T463 682T483 682Q500 682 500 674Q500 669 497 660Q496 658 496 654T495 648T493 644T490 641T486 639T479 638T470 637T456 637Q416 636 405 634T387 623L306 305Q307 305 490 449T678 597Q692 611 692 620Q692 635 667 637Q651 637 651 648Q651 650 654 662T659 677Q662 682 676 682Q680 682 711 681T791 680Q814 680 839 681T869 682Q889 682 889 672Q889 650 881 642Q878 637 862 637Q787 632 726 586Q710 576 656 534T556 455L509 418L518 396Q527 374 546 329T581 244Q656 67 661 61Q663 59 666 57Q680 47 717 46H738Q744 38 744 37T741 19Q737 6 731 0H720Q680 3 625 3Q503 3 488 0H478Q472 6 472 9T474 27Q478 40 480 43T491 46H494Q544 46 544 71Q544 75 517 141T485 216L427 354L359 301L291 248L268 155Q245 63 245 58Q245 51 253 49T303 46H334Q340 37 340 35Q340 19 333 5Q328 0 317 0Q314 0 280 1T180 2Q118 2 85 2T49 1Q31 1 31 11Q31 13 34 25Q38 41 42 43T65 46Q92 46 125 49Q139 52 144 61Q147 65 216 339T285 628Z"></path></g><g data-mml-node="mi" transform="translate(974,363) scale(0.707)"><path data-c="1D447" d="M40 437Q21 437 21 445Q21 450 37 501T71 602L88 651Q93 669 101 677H569H659Q691 677 697 676T704 667Q704 661 687 553T668 444Q668 437 649 437Q640 437 637 437T631 442L629 445Q629 451 635 490T641 551Q641 586 628 604T573 629Q568 630 515 631Q469 631 457 630T439 622Q438 621 368 343T298 60Q298 48 386 46Q418 46 427 45T436 36Q436 31 433 22Q429 4 424 1L422 0Q419 0 415 0Q410 0 363 1T228 2Q99 2 64 0H49Q43 6 43 9T45 27Q49 40 55 46H83H94Q174 46 189 55Q190 56 191 56Q196 59 201 76T241 233Q258 301 269 344Q339 619 339 625Q339 630 310 630H279Q212 630 191 624Q146 614 121 583T67 467Q60 445 57 441T43 437H40Z"></path></g></g></g><g data-mml-node="msqrt" transform="translate(535.9,-929)"><g transform="translate(853,0)"><g data-mml-node="mi"><path data-c="1D437" d="M287 628Q287 635 230 637Q207 637 200 638T193 647Q193 655 197 667T204 682Q206 683 403 683Q570 682 590 682T630 676Q702 659 752 597T803 431Q803 275 696 151T444 3L430 1L236 0H125H72Q48 0 41 2T33 11Q33 13 36 25Q40 41 44 43T67 46Q94 46 127 49Q141 52 146 61Q149 65 218 339T287 628ZM703 469Q703 507 692 537T666 584T629 613T590 629T555 636Q553 636 541 636T512 636T479 637H436Q392 637 386 627Q384 623 313 339T242 52Q242 48 253 48T330 47Q335 47 349 47T373 46Q499 46 581 128Q617 164 640 212T683 339T703 469Z"></path></g></g><g data-mml-node="mo" transform="translate(0,109)"><path data-c="221A" d="M95 178Q89 178 81 186T72 200T103 230T169 280T207 309Q209 311 212 311H213Q219 311 227 294T281 177Q300 134 312 108L397 -77Q398 -77 501 136T707 565T814 786Q820 800 834 800Q841 800 846 794T853 782V776L620 293L385 -193Q381 -200 366 -200Q357 -200 354 -197Q352 -195 256 15L160 225L144 214Q129 202 113 190T95 178Z"></path></g><rect width="828" height="60" x="853" y="849"></rect></g><rect width="2512.8" height="60" x="120" y="220"></rect></g><g data-mml-node="mo" transform="translate(20962.4,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z"></path></g><g data-mml-node="mi" transform="translate(21351.4,0)"><path data-c="1D449" d="M52 648Q52 670 65 683H76Q118 680 181 680Q299 680 320 683H330Q336 677 336 674T334 656Q329 641 325 637H304Q282 635 274 635Q245 630 242 620Q242 618 271 369T301 118L374 235Q447 352 520 471T595 594Q599 601 599 609Q599 633 555 637Q537 637 537 648Q537 649 539 661Q542 675 545 679T558 683Q560 683 570 683T604 682T668 681Q737 681 755 683H762Q769 676 769 672Q769 655 760 640Q757 637 743 637Q730 636 719 635T698 630T682 623T670 615T660 608T652 599T645 592L452 282Q272 -9 266 -16Q263 -18 259 -21L241 -22H234Q216 -22 216 -15Q213 -9 177 305Q139 623 138 626Q133 637 76 637H59Q52 642 52 648Z"></path></g></g></g></g></g></g></svg></mjx-container></p>
<p>Transformerでは「自己注意(Self-Attention)」と「相互注意(Cross-Attention)」が登場します。Self-AttentionとはEncoderとDecoderで登場し、「Q」と「K」と「V」に同じ行列を与える方法です。Cross-AttentionとはDecoderでのみ登場する「Q」と「KとV」で異なる行列を与える方法です。</p>
<h3 id="レイヤー正規化-LN-Layer-Normalization">レイヤー正規化(LN:Layer Normalization)</h3><p>各Tokenのベクトル方向に正規化行う手法です。正規化手法には他にもBatch NormalizationやInstance Normalizationなどありますが、入力長が可変のTransformerではInstance Normalizationが有効です。</p>
<h3 id="ReLU-Rectified-Linear-Unit">ReLU:Rectified Linear Unit</h3><p>非線形変換する関数です。0以下の入力を0にするだけのシンプルな関数です。ReLUの傾きは0か1なので、層を増やしても勾配を消失させにくい特性があります。（最近は活性化関数として使われることが少なくなりましたが、Sigmoid関数は傾きの範囲が0~0.25で、層が増えると勾配が0になってしまう「勾配消失問題」が発生します。）</p>
<h3 id="Softmax">Softmax</h3><p>行列の和が1.0(100%)になるように確率分布に変換します。Transformerではvocab size分の単語が生成対象として存在しています。eで計算している理由は、出力がマイナスにならないことや微分してもeのままであること、値の強調（＝非線形な変化）が可能なことがあります。</p>
<p><mjx-container class="MathJax" jax="SVG" display="true"><svg style="vertical-align: -3.071ex;" xmlns="http://www.w3.org/2000/svg" width="28.257ex" height="6.129ex" role="img" focusable="false" viewBox="0 -1351.5 12489.7 2708.9"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mtext"><path data-c="53" d="M55 507Q55 590 112 647T243 704H257Q342 704 405 641L426 672Q431 679 436 687T446 700L449 704Q450 704 453 704T459 705H463Q466 705 472 699V462L466 456H448Q437 456 435 459T430 479Q413 605 329 646Q292 662 254 662Q201 662 168 626T135 542Q135 508 152 480T200 435Q210 431 286 412T370 389Q427 367 463 314T500 191Q500 110 448 45T301 -21Q245 -21 201 -4T140 27L122 41Q118 36 107 21T87 -7T78 -21Q76 -22 68 -22H64Q61 -22 55 -16V101Q55 220 56 222Q58 227 76 227H89Q95 221 95 214Q95 182 105 151T139 90T205 42T305 24Q352 24 386 62T420 155Q420 198 398 233T340 281Q284 295 266 300Q261 301 239 306T206 314T174 325T141 343T112 367T85 402Q55 451 55 507Z"></path><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(556,0)"></path><path data-c="66" d="M273 0Q255 3 146 3Q43 3 34 0H26V46H42Q70 46 91 49Q99 52 103 60Q104 62 104 224V385H33V431H104V497L105 564L107 574Q126 639 171 668T266 704Q267 704 275 704T289 705Q330 702 351 679T372 627Q372 604 358 590T321 576T284 590T270 627Q270 647 288 667H284Q280 668 273 668Q245 668 223 647T189 592Q183 572 182 497V431H293V385H185V225Q185 63 186 61T189 57T194 54T199 51T206 49T213 48T222 47T231 47T241 46T251 46H282V0H273Z" transform="translate(1056,0)"></path><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(1362,0)"></path><path data-c="6D" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q351 442 364 440T387 434T406 426T421 417T432 406T441 395T448 384T452 374T455 366L457 361L460 365Q463 369 466 373T475 384T488 397T503 410T523 422T546 432T572 439T603 442Q729 442 740 329Q741 322 741 190V104Q741 66 743 59T754 49Q775 46 803 46H819V0H811L788 1Q764 2 737 2T699 3Q596 3 587 0H579V46H595Q656 46 656 62Q657 64 657 200Q656 335 655 343Q649 371 635 385T611 402T585 404Q540 404 506 370Q479 343 472 315T464 232V168V108Q464 78 465 68T468 55T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(1751,0)"></path><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(2584,0)"></path><path data-c="78" d="M201 0Q189 3 102 3Q26 3 17 0H11V46H25Q48 47 67 52T96 61T121 78T139 96T160 122T180 150L226 210L168 288Q159 301 149 315T133 336T122 351T113 363T107 370T100 376T94 379T88 381T80 383Q74 383 44 385H16V431H23Q59 429 126 429Q219 429 229 431H237V385Q201 381 201 369Q201 367 211 353T239 315T268 274L272 270L297 304Q329 345 329 358Q329 364 327 369T322 376T317 380T310 384L307 385H302V431H309Q324 428 408 428Q487 428 493 431H499V385H492Q443 385 411 368Q394 360 377 341T312 257L296 236L358 151Q424 61 429 57T446 50Q464 46 499 46H516V0H510H502Q494 1 482 1T457 2T432 2T414 3Q403 3 377 3T327 1L304 0H295V46H298Q309 46 320 51T331 63Q331 65 291 120L250 175Q249 174 219 133T185 88Q181 83 181 74Q181 63 188 55T206 46Q208 46 208 23V0H201Z" transform="translate(3084,0)"></path></g><g data-mml-node="mo" transform="translate(3612,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z"></path></g><g data-mml-node="msub" transform="translate(4001,0)"><g data-mml-node="mi"><path data-c="1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z"></path></g><g data-mml-node="mi" transform="translate(605,-150) scale(0.707)"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z"></path></g></g><g data-mml-node="mo" transform="translate(4900,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z"></path></g><g data-mml-node="mo" transform="translate(5566.7,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path></g><g data-mml-node="mfrac" transform="translate(6622.5,0)"><g data-mml-node="msup" transform="translate(2341.3,676)"><g data-mml-node="mi"><path data-c="1D452" d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z"></path></g><g data-mml-node="TeXAtom" transform="translate(499,363) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z"></path></g><g data-mml-node="mi" transform="translate(605,-150) scale(0.707)"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z"></path></g></g></g></g><g data-mml-node="mrow" transform="translate(220,-927.8)"><g data-mml-node="munderover"><g data-mml-node="mo"><path data-c="2211" d="M61 748Q64 750 489 750H913L954 640Q965 609 976 579T993 533T999 516H979L959 517Q936 579 886 621T777 682Q724 700 655 705T436 710H319Q183 710 183 709Q186 706 348 484T511 259Q517 250 513 244L490 216Q466 188 420 134T330 27L149 -187Q149 -188 362 -188Q388 -188 436 -188T506 -189Q679 -189 778 -162T936 -43Q946 -27 959 6H999L913 -249L489 -250Q65 -250 62 -248Q56 -246 56 -239Q56 -234 118 -161Q186 -81 245 -11L428 206Q428 207 242 462L57 717L56 728Q56 744 61 748Z"></path></g><g data-mml-node="TeXAtom" transform="translate(1089,477.1) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mi"><path data-c="1D463" d="M173 380Q173 405 154 405Q130 405 104 376T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Q21 294 29 316T53 368T97 419T160 441Q202 441 225 417T249 361Q249 344 246 335Q246 329 231 291T200 202T182 113Q182 86 187 69Q200 26 250 26Q287 26 319 60T369 139T398 222T409 277Q409 300 401 317T383 343T365 361T357 383Q357 405 376 424T417 443Q436 443 451 425T467 367Q467 340 455 284T418 159T347 40T241 -11Q177 -11 139 22Q102 54 102 117Q102 148 110 181T151 298Q173 362 173 380Z"></path></g><g data-mml-node="mi" transform="translate(485,0)"><path data-c="1D45C" d="M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z"></path></g><g data-mml-node="mi" transform="translate(970,0)"><path data-c="1D450" d="M34 159Q34 268 120 355T306 442Q362 442 394 418T427 355Q427 326 408 306T360 285Q341 285 330 295T319 325T330 359T352 380T366 386H367Q367 388 361 392T340 400T306 404Q276 404 249 390Q228 381 206 359Q162 315 142 235T121 119Q121 73 147 50Q169 26 205 26H209Q321 26 394 111Q403 121 406 121Q410 121 419 112T429 98T420 83T391 55T346 25T282 0T202 -11Q127 -11 81 37T34 159Z"></path></g><g data-mml-node="mi" transform="translate(1403,0)"><path data-c="1D44E" d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z"></path></g><g data-mml-node="mi" transform="translate(1932,0)"><path data-c="1D44F" d="M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z"></path></g><g data-mml-node="mi" transform="translate(2361,0)"><path data-c="1D460" d="M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z"></path></g><g data-mml-node="mi" transform="translate(2830,0)"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z"></path></g><g data-mml-node="mi" transform="translate(3175,0)"><path data-c="1D467" d="M347 338Q337 338 294 349T231 360Q211 360 197 356T174 346T162 335T155 324L153 320Q150 317 138 317Q117 317 117 325Q117 330 120 339Q133 378 163 406T229 440Q241 442 246 442Q271 442 291 425T329 392T367 375Q389 375 411 408T434 441Q435 442 449 442H462Q468 436 468 434Q468 430 463 420T449 399T432 377T418 358L411 349Q368 298 275 214T160 106L148 94L163 93Q185 93 227 82T290 71Q328 71 360 90T402 140Q406 149 409 151T424 153Q443 153 443 143Q443 138 442 134Q425 72 376 31T278 -11Q252 -11 232 6T193 40T155 57Q111 57 76 -3Q70 -11 59 -11H54H41Q35 -5 35 -2Q35 13 93 84Q132 129 225 214T340 322Q352 338 347 338Z"></path></g><g data-mml-node="mi" transform="translate(3640,0)"><path data-c="1D452" d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z"></path></g></g><g data-mml-node="TeXAtom" transform="translate(1089,-285.4) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mi"><path data-c="1D457" d="M297 596Q297 627 318 644T361 661Q378 661 389 651T403 623Q403 595 384 576T340 557Q322 557 310 567T297 596ZM288 376Q288 405 262 405Q240 405 220 393T185 362T161 325T144 293L137 279Q135 278 121 278H107Q101 284 101 286T105 299Q126 348 164 391T252 441Q253 441 260 441T272 442Q296 441 316 432Q341 418 354 401T367 348V332L318 133Q267 -67 264 -75Q246 -125 194 -164T75 -204Q25 -204 7 -183T-12 -137Q-12 -110 7 -91T53 -71Q70 -71 82 -81T95 -112Q95 -148 63 -167Q69 -168 77 -168Q111 -168 139 -140T182 -74L193 -32Q204 11 219 72T251 197T278 308T289 365Q289 372 288 376Z"></path></g><g data-mml-node="mo" transform="translate(412,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path></g><g data-mml-node="mn" transform="translate(1190,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path></g></g></g><g data-mml-node="msup" transform="translate(4209,0)"><g data-mml-node="mi"><path data-c="1D452" d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z"></path></g><g data-mml-node="TeXAtom" transform="translate(499,318.6) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z"></path></g><g data-mml-node="mi" transform="translate(605,-150) scale(0.707)"><path data-c="1D457" d="M297 596Q297 627 318 644T361 661Q378 661 389 651T403 623Q403 595 384 576T340 557Q322 557 310 567T297 596ZM288 376Q288 405 262 405Q240 405 220 393T185 362T161 325T144 293L137 279Q135 278 121 278H107Q101 284 101 286T105 299Q126 348 164 391T252 441Q253 441 260 441T272 442Q296 441 316 432Q341 418 354 401T367 348V332L318 133Q267 -67 264 -75Q246 -125 194 -164T75 -204Q25 -204 7 -183T-12 -137Q-12 -110 7 -91T53 -71Q70 -71 82 -81T95 -112Q95 -148 63 -167Q69 -168 77 -168Q111 -168 139 -140T182 -74L193 -32Q204 11 219 72T251 197T278 308T289 365Q289 372 288 376Z"></path></g></g></g></g></g><rect width="5627.2" height="60" x="120" y="220"></rect></g></g></g></svg></mjx-container></p>
<h2 id="おわりに">おわりに</h2><p>Transformerの仕組みを「構成図」「処理フロー」「各処理の深掘り」で解説してきました。今回は推論の処理の理解を深めることができましたが、学習時の理解はまだできておりません。今後は学習時の理解も深め、続編を出したいなと思っています。少しでも皆様のTransformerの理解を深めることへの手助けになれば幸いです。</p>
]]></content>
    <summary type="html">Transformerを知っていて、その理解を深めたい人、大規模言語モデル がどのようにして推論しているのかを知りたい人向けに...</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="LLM" scheme="https://future-architect.github.io/tags/LLM/"/>
    <category term="Transformer" scheme="https://future-architect.github.io/tags/Transformer/"/>
    <category term="論文紹介" scheme="https://future-architect.github.io/tags/%E8%AB%96%E6%96%87%E7%B4%B9%E4%BB%8B/"/>
  </entry>
  <entry>
    <title>第19回言語処理若手シンポジウム(YANS2024) 参加報告</title>
    <link href="https://future-architect.github.io/articles/20241015a/"/>
    <id>https://future-architect.github.io/articles/20241015a/</id>
    <published>2024-10-14T15:00:00.000Z</published>
    <updated>2024-10-14T15:00:00.000Z</updated>
    <author><name>神戸隆志</name></author>
    <content type="html"><![CDATA[<h2 id="はじめに">はじめに</h2><p>はじめまして。Strategic AI Group (SAIG) の神戸です。</p>
<p>2024.09.04(水)から09.06(金)にかけて開催されたYANS2024に参加したのでその様子をご報告します。</p>
<p>当社はプラチナスポンサーとしてSAIGから7名のメンバーが学会に参加し、スポンサーブースでの会社紹介やポスター・チュートリアルの聴講に加え、今年度はフューチャーから1件のポスター発表も行いました。</p>
<h2 id="言語処理若手シンポジウム（YANS）とは">言語処理若手シンポジウム（YANS）とは</h2><p>YANSは自然言語処理、およびその関連分野の研究発表が行われるシンポジウムです。2024年で19回目の開催となる本シンポジウムは大阪の梅田スカイビルにて開催されました。</p>
<p>本シンポジウムではポスター発表だけでなく、分野交流ハッカソンや招待講師によるチュートリアル、参加者がスポンサーブースを回るスポンサーツアーなど様々なプログラムが開催されました。</p>
<p>「ことばがつむぐ、新たなつながり ～分野の境界を超えて～」という本シンポジウムのスローガンにもある通り、自然言語処理だけでなく関連する周辺分野のポスター発表やチュートリアルも行われていました。</p>
<p>公式の発表によれば今年度の参加人数は411人と、前年度の300人を大きく上回る参加者数となっています。発表件数も前年度に比べ56件多い196件と過去最多の発表件数となっており、現地でもその盛況ぶりを感じることができました。</p>
<img fetchpriority="high" src="/images/2024/20241015a/IMG_6625.jpg" alt="" width="1200" height="1171">

<h2 id="スポンサーブース">スポンサーブース</h2><p>スポンサーブースでは自然言語処理に関する取り組みだけでなくAIに関する取り組み全般を紹介しました。自然言語処理に関する取り組みはもちろん、それ以外のAIに関する取り組みについても興味を持って聞いて下さる参加者の方が多く、当社の取り組みについて多くの方に知っていただく機会になったと思います。</p>
<p>ブースに来ていただいた参加者の方にはノベルティとしてパンフレットとトートバッグを配布させていただきました。ノベルティは多めに用意していたのですが、ブースに足を運んで下さった参加者の方が想定よりも多く、シンポジウム2日目の午前中には配り終えてしまいました。改めてブースに足を運んでくださった皆様に感謝申し上げます。</p>
<img src="/images/2024/20241015a/IMG_6593_2.jpg" alt="" width="1200" height="900" loading="lazy">

<h2 id="スポンサー賞">スポンサー賞</h2><p>当社のスポンサー賞には <strong>[S4-P25] 日本語の単語を対象とした複数時期の意味変化パターン分析</strong> の発表を選定させていただきました。選定理由は以下の通りです。</p>
<p><code>本研究は日本語の単語の意味や使われ方が年代とともにどのように変化したのかを分析する手法を提案しています。 意味変化の仕方をクラスタリングすることで、コロナ禍で使われ方が変わった単語のグループが表出するなど興味深い結果が得られており、今後の発展に期待が持てます。 また、聴講者からの質問に対する補足資料の提示をタブレットを用いて行うなど、発表に対する十分な準備ができている点も高く評価しました。</code></p>
<p>副賞として「九州産黒毛和牛A5ランク ITADAKIセット」を送付させていただきました。</p>
<img src="/images/2024/20241015a/image.png" alt="" width="559" height="565" loading="lazy">

<h2 id="当社の発表">当社の発表</h2><p>今年のYANSでは、フューチャーからも1件発表しました。</p>
<p>現在当社で自然言語処理の研究開発に関するアルバイトをお願いしているNAIST 西田さんとの共同研究成果です。</p>
<p>フューチャーでは基礎から応用まで幅広く研究開発を進めており、今後も様々な学会でその成果を公表していきます。</p>
<h3 id="S4-P34-大規模言語モデルの知識は何に由来して記憶されるか？">[S4-P34] 大規模言語モデルの知識は何に由来して記憶されるか？</h3><p><strong>西田 悠人 (NAIST&#x2F;フューチャー), 岸波 洋介 (フューチャー), 藤井 諒 (フューチャー), 森下 睦 (フューチャー)</strong></p>
<p>大規模言語モデル (LLM) は「『ハムレット』の著者は誰ですか？」のような事実に関する知識が必要な質問に答えられることがあります。これまで、LLMがどのような事実知識を記憶しているかについて研究が行われており、「訓練データ中の頻度が低い知識ほど記憶しにくい」「有名ではない知識ほど記憶しにくい」ということが知られていました。では、頻度と有名度のどちらがLLMの記憶により寄与しているのでしょうか？本研究では、記憶の強さと知識の頻度や有名度との相関を比較することで、LLMの記憶の主要因を調査しました。実験の結果、我々の直観に反して、知識のカテゴリごとにみると頻度よりも有名度と記憶の相関のほうが優勢であることが明らかになりました。このことは、ある知識が有名かどうかをLLMが暗黙的に理解している可能性を示唆しました。</p>
<img src="/images/2024/20241015a/image_2.png" alt="" width="672" height="954" loading="lazy">

<h3 id="第一著者コメント">第一著者コメント</h3><p>今回のYANSでは、始まりたての萌芽的な研究を発表させていただきました。発表を聞きに来てくださった参加者の皆様から、さまざまな質問やコメントをいただき、今後の研究の方向性についてより明確になりました。改めて、発表に足を運んでくださった皆様に感謝申し上げます。</p>
<h2 id="発表紹介">発表紹介</h2><p>スポンサー賞の他に、当社から参加したメンバーが特に面白いと感じた発表をいくつか紹介します。</p>
<p><strong>[S1-P38] 指示数増加による大規模言語モデルの指示追従性能への悪影響</strong><br>この研究では、大規模言語モデルが追従できるプロンプト内の指示数について調査しています。</p>
<p>個々の指示は単純な場合でも、数が増えるごとに追従できなくなるという問題が大規模言語モデルには見られます。この問題に対し、指示に追従できているか各指示ごとにフィードバックを行い回答を修正する手法が提案されています。提案手法によって指示追従性が改善するという結果を示しており、プロンプト中の指示の位置によって追従性が変わるのか、指示数がさらに増えた場合でも追従性が落ちないようにするために改善することは可能かなど、今後の発展が期待される研究だと感じました。（加藤）</p>
<p><strong>[S3-P08] Attentionに基づく大規模言語モデルのHallucination検出手法の検討</strong><br>こちらの研究では、先行研究においてハルシネーション (幻覚) 発生時特有のAttentionパターンが存在する可能性が示唆されていることから、LLMのAttention情報を特徴量としてハルシネーション検出器を学習する手法を提案しています。</p>
<p>本手法によって構築される検出器は、検出予測時のAttention情報を確認することで検出対象文におけるハルシネーション発生個所が特定できるというメリットがあります。生成AIの活用が広がるなかでハルシネーションの検出は非常に重要な技術であり、検出箇所まで特定できる本手法は応用可能性が高いと考えられます。</p>
<p>現状の検出精度には改善の余地があるものの、特徴量の改善や外部知識の利用など今後の方向性も十分に検討されており、これからの発展が期待される研究だと感じました。(岸波)</p>
<p><strong>[S1-P17] ゲームの台詞を題材としたキャラクターらしさを構成する要素の検討</strong><br>この研究では、既存キャラクターを模した対話システムにおけるそのキャラクターらしさを構成する要素を評価しています。</p>
<p>ユーザから得られた自由記述評価を元に、対応する「らしさ」を構成する要素へとラベル付け・スコアリングを行い、その結果からキャラクター再現において優先すべき特性を考察しています。先行研究や文献からキャラクターらしさの構成要素候補が大量に挙げられていますが、そのすべてが「らしさ」を等しく述べているわけではない、性格を反映した発話であってもケースバイケースで「らしさ」への影響の大小があるという考察は、ノベルゲーム、ソーシャルゲームの一プレイヤーとして納得感がありました。</p>
<p>サイバーエージェントさんでは「[S2-P27] 『IDOLY PRIDE』におけるライブスコアを用いたアイドル埋め込み評価手法の検討」も発表されており、こちらはゲームのバランス調整のたたきにLLMを活用されている旨の発表がありました（こちらも面白かったです）。自然言語処理の知見がゲームの現場でこう使われているのかと興味深く感じました。(佐藤)</p>
<p><strong>[S4-P21] LLMはなぜ算数が苦手なのか？ Transformerの外挿能力に関する分析</strong><br>この研究では、言語モデルが与えられた例からタスクの入出力の関係性を捉え、追加の学習なしでタスクに適応する能力である In Context Learning (ICL) を、コントロールされた四則演算の設定で検証しています。</p>
<p>人間であれば5桁の数字どうしの計算ができれば、6桁どうしの計算にも簡単に汎化できますが、GPT-2のような言語モデルは学習時に見ていない未知の桁数どうしの足し算をほとんど解けないということを明らかにしています。</p>
<p>また、数字の1つ1つが独立したトークンになっていると正解率が上がるというようにトークナイズの仕方によってタスク遂行能力に大きな差が生まれる、未知の桁数の問題では例の中の同じ桁数の問題にアテンションが張られている &#x3D; なんらか違うことまでは理解できていそう、などとても興味深く示唆に富んだ良い研究だと感じました。</p>
<p>ポスターで述べられていた四則演算以外の問題への展開はもちろん、より表現力の高い大きなモデルではどうなのか？突然 “腑落ち” して四則演算のルールを学ぶことがあるのか？など、様々な方向性から今後の展開に期待できます。(藤井)</p>
<p><strong>[S4-P14] SubRegWeigh: サブワード正則化による高速アノテーション補正</strong><br>こちらの研究ではデータセット中のアノテーションミスを特定しその悪影響を軽減する “アノテーション補正”に関する新しい手法を提案しています。</p>
<p>従来の手法ではアノテーションミスを検出するために複数のモデルを使用して検出しなければならなかったため多くの時間を必要としていたところ、こちらの研究では複数のモデルを使用する代わりに複数のサブワード系列、つまり複数のテキストの区切り方のパターンで1つのモデルに学習をさせることでアノテーションミスの検出を高速に行えるようになっています。複数のモデルによる推論を、単一モデルによる複数のサブワード系列に対する推論に置き換えるアイデアが非常に面白いと感じました。実験では従来手法に比べ高速なアノテーション補正ができるようになったことだけでなく後段タスクの精度改善も確認されており、今後のさらなる展望が期待される発表だと感じました。(神戸)</p>
<h2 id="「目指せ国際会議！」セッション">「目指せ国際会議！」セッション</h2><p>国際会議経験者を招き、国際会議に関するライトニングトーク (LT) およびパネルディスカッションを行うセッションが行われました。</p>
<p>今回ご招待を頂き当社から森下が「国際会議でやるべきこと3選」というタイトルでLTを行いました。</p>
<p>1回目の国際会議では（あまり）会議のレベルを気にせず、まずはどこでも良いので投稿し発表する経験を積むことの大切さをお伝えさせていただきました。</p>
<p>全発表者の資料は以下に掲載されています。</p>
<p>https://yans.anlp.jp/entry/yans2024report#%E7%9B%AE%E6%8C%87%E3%81%9B%E5%9B%BD%E9%9A%9B%E4%BC%9A%E8%AD%B0</p>
<h2 id="おわりに">おわりに</h2><p>私自身が約1年半ぶりの自然言語処理系の学会への参加だったため、LLMが台頭し始めて以降の自然言語処理の動向はほとんど把握できておりませんでした。今回のシンポジウムでLLMに関する研究の雰囲気を掴むことができましたし、LLM以外の研究も依然活発に行われていることを知ることができ、良い刺激を得られました。</p>
<p>Futureでは一緒に働くメンバーを募集しています。特に最近ではNLPに関する採用にも力を入れており、NLPエンジニア、NLPリサーチエンジニア、シニアNLPエンジニアの募集も行っております。条件等は応相談ですので、興味を持っていただけた方は是非採用ページの内容をご確認ください。</p>
<p>他にも新卒採用やキャリア採用を幅広く行っておりますので、多くの方からのご応募をお待ちしております。</p>
<p>みなさまと一緒に働ける日を心待ちにしております！</p>
]]></content>
    <summary type="html">2024.09.04にかけて開催されたYANS2024に参加して参りましたのでその様子をご報告します。</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="NLP" scheme="https://future-architect.github.io/tags/NLP/"/>
    <category term="YANS" scheme="https://future-architect.github.io/tags/YANS/"/>
    <category term="参加レポート" scheme="https://future-architect.github.io/tags/%E5%8F%82%E5%8A%A0%E3%83%AC%E3%83%9D%E3%83%BC%E3%83%88/"/>
  </entry>
  <entry>
    <title>JDLA E資格（エンジニア資格）合格体験記</title>
    <link href="https://future-architect.github.io/articles/20240926a/"/>
    <id>https://future-architect.github.io/articles/20240926a/</id>
    <published>2024-09-25T15:00:00.000Z</published>
    <updated>2024-09-25T15:00:00.000Z</updated>
    <author><name>引網康暁</name></author>
    <content type="html"><![CDATA[<h2 id="はじめに">はじめに</h2><p>フューチャーアーキテクト物流サービス事業部の引網康暁です。現在、お客様の物流DXのご支援や、物流関連法改正に伴うCLO（Chief Logistics Officer：物流統括管理者)ご支援のコンサルティングを行っています。</p>
<p>物流DXの実践のためには、サプライチェーン上のデータの「可視化」やAIも活用した「最適化」が不可欠と考えており、コンサルタントとして自らの知識を高めておく必要があります。その一環として、2024年8月に行われたE資格2024#2を受験して合格しましたので、その体験記を綴ってみたいと思います！</p>
<img fetchpriority="high" src="/images/2024/20240926a/DSC_0166.JPG" alt="" width="1200" height="731">

<h2 id="E資格とは">E資格とは</h2><p>E資格とは、日本ディープラーニング協会（JDLA）が認定するAI人材に関する資格のうち、エンジニアを対象とした資格で、ディープラーニングの理論を理解し、適切な手法を選択して実装する能力や知識を認定する資格となっています。</p>
<p>試験範囲（シラバス）は、機械学習のベースとなる数学から、機械学習・深層学習のモデルや手法、モデルを実装するための環境構築に至るまで、とても幅広い内容が問われます。さらに、理論のみならず、PyTorchまたはTensorFlowを利用した実装も含まれますので、Pythonの基礎的なコーディングスキルも求められます。</p>
<ol>
<li><strong>数学的基礎</strong>（確率・統計、情報理論）</li>
<li><strong>機械学習</strong>（機械学習の基礎）</li>
<li><strong>深層学習の基礎</strong>（順伝播型ネットワーク、深層モデルのための最適化、深層モデルのための正則化、畳み込みニューラルネットワーク、リカレントニューラルネットワーク、Transformer、汎化性能向上のためのテクニック）</li>
<li><strong>深層学習の応用</strong>（画像認識、物体検出、セマンティックセグメンテーション、自然言語処理、生成モデル、深層強化学習、様々な学習方法、深層学習の説明性）</li>
<li><strong>開発・運用環境</strong>（エッジコンピューティング、分散処理、アクセラレータ、環境構築）</li>
</ol>
<h2 id="E資格受験の「資格」を取得する必要があります">E資格受験の「資格」を取得する必要があります</h2><p>E資格受験のハードルが高い理由の1つでもあるのですが、E資格を受験するにあたっては、事前にJDLAの認定プログラムを過去2年以内に履修し、修了試験に合格しておく必要があります。つまり、E資格受験のための「資格」を事前に取得しなければなりません。私はコストパフォーマンスの良さげな認定プログラムを選択し（G検定合格者割引が受けられました）、2024年3月から受講を開始しました（すなわち、受験勉強期間は6か月でした）。</p>
<p>プログラムによって内容は異なるようですが、私が選択した認定プログラムは、オンラインでの動画講義（約25時間）を受講した上で、テスト（約400問）のクリアとコーディング課題（4問）の提出が修了の要件でした。</p>
<p>まず、オンラインでの動画講義ですが、いわゆる予備校みたいな感じの「ココが試験に出ますよ！」とか「ココは暗記しましょう！」のようなノリを勝手に期待していたのですが、全く違いました（自分の勘違い）。。。講義は試験範囲の基礎的な知識を一通り、均して説明するという内容でしたので、私の場合、単に講義を受講するだけでは、E資格本番の合格は難しかったと思います。なお、テストとコーディング課題は、ネットを漁ったり、ChatGPTも駆使したりして、なんとか6月に認定プログラムを修了できました。正直なところ、この認定プログラムの修了だけでも「やりきった感」が出てしまったほどです。</p>
<h2 id="受験勉強本番">受験勉強本番</h2><p>さて、認定プログラムを修了し、E資格の受験資格を得て、ようやくスタート地点に立てました。ここからが受験勉強の本番となります。私は、以下の4つをバイブルとして勉強を進めました。</p>
<ul>
<li>ゼロから作るDeep Learning<br>「赤本」と呼ばれる、受験生必須の参考書です。この本は、フレームワークを一切使わずにディープラーニング（特に画像認識）をゼロから実装する！という、言わずと知れた名著です。私の場合、この本を精読しながら、そして、ただ単に読み込むだけでなく、コーディング（写経）して実際に手を動かしながら、2回転しました。</li>
<li>ゼロから作るDeep Learning2（自然言語処理編）<br>こちらも同じく「赤本」と呼ばれる参考書で、word2vec、RNN、LTSMから、ChatGPTを生み出したTransformerの基盤技術であるAttentionまでが本当に分かりやすく解説されています。私はこの本の精読を2回転しました（写経はしていない）</li>
<li>ディープラーニングE資格エンジニア問題集<br>こちらは「黒本」と呼ばれる問題集で、私が勉強していた時期では唯一の問題集でした（E資格は過去問が公表されていません）。この「黒本」も受験生必須アイテムの1つで、「やらない」という選択肢はありません。私の場合、それこそ<strong>過学習</strong>を覚悟に7回転しました。実装問題はコードを写経したり、計算問題は式を自分で展開したりすることで、ようやく血肉になりました。何より手を動かすことが重要でした。</li>
</ul>
<img src="/images/2024/20240926a/DSC_0178.JPG" alt="DSC_0178.JPG" width="1200" height="675" loading="lazy">

<ul>
<li>JDLA公式例題<br>上記の「黒本」は発刊された時期がちょっと古いところが難点で、最新の試験範囲（シラバス）に対応できていない箇所があります（シラバスはしばしば更改されます）。そこで、認定プログラムを修了したタイミングで修了者に共有されたJDLA公式例題を何度か解き、問題演習の足りない箇所を補いました。</li>
</ul>
<h2 id="受験日当日から合格発表まで">受験日当日から合格発表まで</h2><p>受験にあたって、<strong>試験問題に関する守秘義務について誓約をしました</strong>ので、今回のブログでも、当日の試験問題については一切触れることができないこと、ご了承ください。試験はCBT（Computer Based Test）方式で、120分間で多肢選択式の約100問を解きます。見直し時間を考えると、1問をだいたい1分間で解いていかないといけないので、かなり時間にシビアな試験です。また、テストセンターの入場にあたっては、参考書や問題集は一切持ち込めませんし、ズボンのポケットの中身やメガネの裏までチェックされたセキュリティ面もとても印象的でした。</p>
<p>当日の自分の感触としては、「できた！」という問題が5割くらい、「ちんぷんかんぷん」という問題が2割くらい、「多分こっちだと思うけど。。」という問題が3割くらいで、あまり手応えが無かったというのが実感です。その分、3週間後に無事に合格のメールを受け取ったときは本当にうれしかったです！ 結果的に、各分野ともに7～8割くらいが正答だったようで一安心しましたが、問題数の多くを占める深層学習の出来が合否を決める試験であるように思いました。</p>
<h2 id="おわりに">おわりに</h2><p>私の場合、E資格受験を考え始めて、実際に「黒本」を目にした時の感想は「とっても難しい。。（絶句）」というものでした。それでも、認定プログラムを修了し、問題集や参考書を手を動かしながら解き進めることで、なんとか合格できました。この合格体験記がE資格取得に関心のある方に参考になれば幸いです。</p>
<p>お読みいただいてありがとうございました。</p>
]]></content>
    <summary type="html">物流DXの実践のためには、サプライチェーン上のデータの「可視化」やAIも活用した「最適化」が不可欠と考えており、コンサルタントとして自らの知識を高めておく必要があります。その一環として、2024年8月に行われたE資格2024#2を受験して合格しましたので、その体験記を綴ってみたいと思います！</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="E資格" scheme="https://future-architect.github.io/tags/E%E8%B3%87%E6%A0%BC/"/>
    <category term="合格記" scheme="https://future-architect.github.io/tags/%E5%90%88%E6%A0%BC%E8%A8%98/"/>
  </entry>
  <entry>
    <title>画像の認識・理解シンポジウム（MIRU2024）参加報告</title>
    <link href="https://future-architect.github.io/articles/20240902a/"/>
    <id>https://future-architect.github.io/articles/20240902a/</id>
    <published>2024-09-01T15:00:00.000Z</published>
    <updated>2024-09-01T15:00:00.000Z</updated>
    <author><name>佐良和孝</name></author>
    <content type="html"><![CDATA[<h2 id="はじめに">はじめに</h2><p>みなさんはじめまして。フューチャー株式会社の佐良と申します。</p>
<p>普段はStrategic AI Group (SAIG)の一員として、主にAI-OCRサービス事業を中心に携わっています。</p>
<p>この度は、2024年8月6日(火)〜8月9日(金)において熊本城ホールにて開催されました第27回 画像の認識・理解シンポジウム(MIRU2024)に参加してきたので、その様子を報告します。</p>
<p>当社はシルバースポンサーとして、SAIGから7名が参加しました。<br>学会期間中は発表の聴講に加えて、スポンサーブースを出展し、学会に参加している学生や他企業の方々と交流しました。</p>
<img fetchpriority="high" src="/images/2024/20240902a/1000029797.jpg" alt="" width="1200" height="1600">

<h2 id="画像の認識・理解シンポジウムとは">画像の認識・理解シンポジウムとは</h2><p>画像の認識・理解シンポジウム（MIRU）は、画像の認識と理解技術に関する国内最大規模の会議です。今回の開催で27回目となり、ポスター発表件数も629件と過去最多となっていました。</p>
<p>個人的な感想としては、口頭発表が1つの会場のみで実施されていたため、興味のある発表の時間が被って聞き逃すといったことがなく非常に助かりました。</p>
<h2 id="スポンサーブース">スポンサーブース</h2><p>スポンサーブースでは、画像処理に関わる案件にとどまらず、SAIGで取り組んできた様々なAI案件を中心に実績を紹介しました。</p>
<p>ブースにお越しいただいた方々には、当社がITコンサルティング会社であるという強みを活かして、画像処理だけでなく幅広い分野での実績があることに興味を示してくださる方が多かったです。</p>
<img src="/images/2024/20240902a/PXL_20240807_063454560.MP_3.avif" alt="" width="1200" height="954" loading="lazy">

<h2 id="発表聴講">発表聴講</h2><p>参加メンバーのそれぞれが聴講した発表の中で印象に残ったものについていくつか紹介します。</p>
<h3 id="OS-1E-09-Human-drawable-and-Interpretable-Adversarial-Attack">[OS-1E-09] Human-drawable and Interpretable Adversarial Attack</h3><p>この研究では、人間が解釈可能な敵対的攻撃を得るために、人間が落書きとして再現しても誤分類を発生させるような敵対的攻撃の生成手法を提案しています。</p>
<p>従来の敵対的攻撃に関する研究では敵対的攻撃の解釈性よりも、どれだけ誤認識を引き起こせるか・どれだけ知覚しづらい攻撃かに主眼を置いており、結果として画像分類器が何故誤分類したかの理由について洞察を得ることが難しいという課題がありました。<br>本研究では、”敵対的落書き”と命名された人間がフリーハンドで再現可能な攻撃手法を提案しています。”敵対的落書き”はベジェ曲線の集合であり、入力画像にベジェ曲線の集合を重ねたものをモデルの入力とし、モデルが入力画像をターゲットクラスに誤分類するようにクロスエントロピー損失をとり、これを元にベジェ曲線のパラメータを最適化しています。本研究内の実験では、敵対的攻撃を成功させるために最適化されたベジェ曲線の集合を人間が真似して同じクラスの別画像に落書きをしたところ、モデルが同様の誤認識をすることを確認しました。</p>
<p>ユニークなアプローチで解釈性のある敵対的攻撃を実現したところが非常に興味深かったです。落書きもシンプルなもののみで構成されているため、敵対的攻撃が成功したものを人間が洞察し特徴を把握することを可能としていました。人間が再現して同じ誤りを引き起こすことに成功していることから、モデルの解析にも応用可能な技術と感じました。(勝村)</p>
<h3 id="IS-2-051-Symmetry-breaking-in-parallelized-MLP-Mixer">[IS-2-051]:Symmetry breaking in parallelized MLP-Mixer</h3><p>多層パーセプトロンのみを用いて、Attentionと同等の精度を出したMLP-Mixerの重みの対称性の破れと精度の関係についての研究です。<br>Hopfield-NetworkはCNNなどにみられるfeed-fowardなモデルではなく、実際の脳を模した神経学的なモデルです。<br>古典的なHopfield-Networkは解析的な解をもち、重み(相互作用)は単純な計算で求まります。これに対し、モダンなHopfield-Networkを3層重ねたものは解析的でない、非自明な解をもちます。この研究では、非自明かつ最もシンプルなネットワークとして、このモデルに着目しています。</p>
<p>通常、パーセプトロン間のエネルギー関数(コスト関数)の相互作用は、対称性をもちます。それに対し、今回のモデルには対称性を壊すようなパラメータを導入し、対称性の破れ具合と精度の関係性を調べています。</p>
<p>その結果、対称性の破れていないモデルでは精度があまり出ないことが分かりました。</p>
<p>つまり、今回のParallelized　MLP-Mixierの精度において対称性の破れが寄与しているという考察が得られます。これは、実際の脳のニューロンの相互作用が、対称性を持たないことに対してもコンシステントな結果であり、非常に面白いです。(発表者から聞いたのですが、ちゃんとしたソースは見つからず・・・)(市村)</p>
<h3 id="IS-2-150-非言語依存なフォントスタイル変換へ向けて">[IS-2-150]:非言語依存なフォントスタイル変換へ向けて</h3><p>未学習のフォントスタイルを用いて、未学習フォントを変換する手法を提案した研究です。学習済のフォントスタイルで未学習・学習済のフォントを変換する手法は、過去に研究されていましたが、変換元・変換先両方で未学習の手法は提案されていませんでした。</p>
<p>この研究では、フォントのスタイルの特徴を抽出するモデルと、フォントの生成部分をわけ、スタイル抽出分を工夫したことに新規性があります。</p>
<p>まず、第一段階としてスタイル抽出器にフォントが同じか異なるかを判定するモデルを結合し、事前学習します。その後、フォントの言語依存性を無くすために、後続に言語を判定するモデルを結合させ、学習を進めます。この時に言語情報が学習されるため、逆勾配を特徴抽出器にかけ、言語とは関係ないスタイルの本質を学習します。</p>
<p>この手法を用いることで、未学習スタイルで未学習フォントを変換することに成功しています。実際に画像を構成する要素として、いくつか軸が考えられますが、本質的に学習したい軸とそれ以外を分けて学習をするときに広く使える手法と考えられます。シンプルな構成ながらも発想が素晴らしい研究です。(市村)</p>
<h3 id="OS-1B-05-SimGlue-スケールや回転変化の大きい画像ペアに対するTransformerを用いた特徴点マッチング">[OS-1B-05] SimGlue: スケールや回転変化の大きい画像ペアに対するTransformerを用いた特徴点マッチング</h3><p>特徴点マッチングによる画像内のパターン抽出において、特徴点の特徴ベクトルを座標系を正規化したうえで求めることで、スケールや回転角の大きく異なるようなケースにおいても高精度な特徴点マッチングを可能とする手法を提案する研究でした。</p>
<p>従来の Transformer 系の位置エンコーディングは特徴点の位置座標に基づいており、スケールや回転角が大きく異なるとマッチすべきふたつの特徴点に対応する特徴ベクトルに全く異なる位置関係がエンコーディングされてしまい、マッチングに失敗するという問題点がありました。</p>
<p>そこでこの研究では、特徴点集合の座標の情報のみから回転中心、回転角、スケールを求め、それらを用いて正規化してから位置エンコーディングを行うことで上記の問題を回避していました。オブジェクトが画像のどこにどの向きで置かれているか、といったような問題はそこまで突飛でもないように思うので、これに対する古典的な手法としてどのようなものがあるのか、およびこの研究の手法がそのような問題にどの程度強いのか、などは気になりましたが、シンプルでありながらかなり妥当な手法に感じました。画像内から完全一致でなくとも似ているパターンを抽出する、といったような問題は様々なところで頻出かつバリエーションも豊富なので、方針や手法など参考になる部分の多い研究と感じました。(久保田)</p>
<h3 id="IS-1-079-馬術における動作認識手法の比較と評価">[IS-1-079] 馬術における動作認識手法の比較と評価</h3><p>本研究では、馬術競技における動作認識の課題を明らかにし、既存の人間動作認識手法を馬術に適用する試みを行いました。</p>
<p>馬術競技では運動の正確性が採点に重要であり、コンピュータによる動作認識が有用ですが、既存の手法は人間を対象としており、馬を主体とする馬術には適用が難しいです。</p>
<p>本研究では、馬術のデータセットを作成し、RGB画像、オプティカルフロー画像、関節位置ヒートマップの3つのモダリティを用いて動作認識の性能を評価しました。その結果、RGB画像とオプティカルフロー画像は同程度の精度を示したが、関節位置ヒートマップはやや精度が劣ることが判明しました。また、馬が正面または後ろを向いている場合や四肢部分にノイズがある場合に認識が失敗しやすいことが分かりました。今後は、これらの課題を解決することで、実用的なモデルの構築が期待されています。</p>
<p>馬術という新しい領域において人間の動作認識に用いられている既存のモデルを用い評価した興味深い研究であると感じました。正面から見た際に四肢が重なって見えるなど、人間とは異なる馬ならではの課題を明確にできたこと、独自でデータセットを作成したことも高く評価できる部分だと思います。(長山)</p>
<h3 id="IS-2-038-演奏音復元のための手書き邦楽譜文字認識">[IS-2-038] 演奏音復元のための手書き邦楽譜文字認識</h3><p>独自文字や記号が使用される手書き邦楽譜における文字認識の精度向上を目指し、物体検出技術を応用して文字を認識する研究です。<br>対象のデータは、数字・漢数字・記号といった異なる属性の文字を含んでいることから，手法としては多ラベル分類モデルと物体検出モデル（YOLOv8）を用いた二段階の文字認識を提案しています。</p>
<p>YOLOv8の単体手法と比較しても、本研究で提案している二段階での文字認識が数値的にも上回る結果となっています。まずは種類を大別することにより、各文字の種類のデータの偏りが減ったことが考えられ、後にそれらに特化したモデルで判別することへの恩恵があったと感じました。</p>
<p>全体的なスループットにどう影響するか等は気になりますが、複雑で難しいタスクにおいて、異なる属性で大別してからより特化したもので読みに行くという手法は有用だと感じました。(鈴木)</p>
<h3 id="IS-2-111-Erasing-Scene-Text-with-Foundation-Models">[IS-2-111] Erasing Scene Text with Foundation Models</h3><p>風景画像に映り込んだ文字領域を特定し、その領域を修正することで、文字を自然に削除する研究です。タスクとしては大きく2つに分かれており、（1）文字領域の特定、（2）特定箇所の修正によって構成されています。文字領域の特定においては、文字を囲う bounding boxの特定後、segmentationモデルを利用し、より正確な文字のストロークに沿ったマスクを取得することで、より忠実に背景領域の情報を保持します。修正フェーズでは、拡散モデルベースの手法を複数比較しています。</p>
<p>実験結果のうち興味深かったのが、この修正フェーズでのモデルごとの挙動の違いでした。単純に文字領域を消去し、代わりに背景と同色系に置換するモデルもあれば、その領域が文字領域であることを理解し、別の文字(っぽい形)を生成するモデルも存在しています。</p>
<p>文字に限らず、コンテキスト情報をコントロールした画像生成・変換手法の扱いを考える良い例になる研究であると感じました。(菅野)</p>
<h3 id="IS-1-182-Cross-Lingual-Learning-in-Multilingual-Scene-Text-Recognition">[IS-1-182] Cross-Lingual Learning in Multilingual Scene Text Recognition</h3><p>この研究では、STR（Scene Text Recognition）における、CLL（Cross-Lingual Learning）について、CLLの一般的な洞察がSTRのタスクにも適用されるかを広域的な実験を通じて調査しています。</p>
<p>一般的に、CLLでは(1)高リソース言語と低リソース言語を共同学習することで、低リソース言語の性能が低下する可能性がある、(2)共同学習は類型論的に類似した言語間で最も効果的に機能する可能性がある、という2つの洞察が存在します。しかしながら、本研究では複数の言語を用いたCLLを広域的に実験することで、これらの一般的な洞察がSTRには適用されないことが示されていました。</p>
<p>また実験を通じて、言語間の形状的類似性についてもSTRのCLLでは重要ではなく、真に重要であるのは言語の種類ではなく学習に用いる高リソース言語のデータ量であることが示されています。</p>
<p>直観的には言語の文字の形状が似ていることが学習にはポジティブに働きそうに感じていましたが、本研究ではそうではないと示されており非常に興味深かったです。また、言語情報を取り入れることができるようなマルチモーダルなモデルだとどのような結果になるのかも気になりました。(佐良)</p>
<h2 id="おわりに">おわりに</h2><p>本記事では、MIRU2024の参加記録を執筆させていただきました。</p>
<p>私自身が学生時代は自然言語処理の研究に携わっていたこともあり、画像処理系の学会に参加するのは今回が初めてだったのですが、興味が引かれる研究がたくさんあり、非常に楽しい学会期間を過ごすことが出来ました！</p>
<p>発表の中では、近年のLLMの発展の影響もあり、画像処理+言語処理のマルチモーダルな研究も多く見られた印象があります。LLMとのシナジーで画像処理分野の研究がどのような方向に発展をしていくのか非常に楽しみです。</p>
<p>SAIGでは技術と業務の両輪でAIの実社会応用を推進していく仲間を募集しています。<br>興味のある方、ぜひ一緒に働きましょう！</p>
<p>新卒採用 : https://www.future.co.jp/recruit/recruit/rec-fresh/<br>キャリア採用 : https://www.future.co.jp/recruit/recruit/rec-career/</p>
<p>熊本グルメも堪能しました。↓写真は馬肉<br><img src="/images/2024/20240902a/1000002297.jpg" alt="" width="1200" height="822" loading="lazy"></p>
]]></content>
    <summary type="html">第27回 画像の認識・理解シンポジウム(MIRU2024)に参加してきたので、その様子を報告します</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="Transformer" scheme="https://future-architect.github.io/tags/Transformer/"/>
    <category term="参加レポート" scheme="https://future-architect.github.io/tags/%E5%8F%82%E5%8A%A0%E3%83%AC%E3%83%9D%E3%83%BC%E3%83%88/"/>
    <category term="学会" scheme="https://future-architect.github.io/tags/%E5%AD%A6%E4%BC%9A/"/>
    <category term="機械学習" scheme="https://future-architect.github.io/tags/%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92/"/>
    <category term="画像処理" scheme="https://future-architect.github.io/tags/%E7%94%BB%E5%83%8F%E5%87%A6%E7%90%86/"/>
  </entry>
  <entry>
    <title>埋め込みベクトルでSlackのカスタム絵文字を分類・検索</title>
    <link href="https://future-architect.github.io/articles/20240828a/"/>
    <id>https://future-architect.github.io/articles/20240828a/</id>
    <published>2024-08-27T15:00:00.000Z</published>
    <updated>2024-08-27T15:00:00.000Z</updated>
    <author><name>王紹宇</name></author>
    <content type="html"><![CDATA[<p>夏の自由研究連載 2024の 2 日目です。</p>
<p>Slack のカスタム絵文字を AI で遊びました。</p>
<h2 id="前書き">前書き</h2><p>夏の自由研究連載 2023 の「Sentence-Transformers を使って YouTube 動画のセリフを検索する」では、テキストのセマンティック検索や文字資料に対して Q＆A に注目してデモしました。しかし Sentence-Transformers は、テキストだけではなく、画像や音声など異なる情報の組み合わせ、いわゆる <strong>マルチモーダル(multi-modal) AI</strong> のモデルです。</p>
<p>そのため、同一のモデルで、文字と画像を意味的な関連性を利用して、同一のベクトル空間に埋め込み(Embedding)することで、数学の計算（ベクトルの cosine 距離など）で近似度の評価が実現できます。</p>
<p>テキストと画像を検索のインプットとアウトプットの組み合わせで、以下の応用場面を例として挙げられます。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>検索キーワード</th>
<th>検索結果</th>
<th>応用場面</th>
</tr>
</thead>
<tbody><tr>
<td>テキスト</td>
<td>テキスト</td>
<td>意味的近似の文章検索（前回の文字のセマンティック検索はここ）</td>
</tr>
<tr>
<td>テキスト</td>
<td>画像</td>
<td>リギャラリーから文字で画像を検索</td>
</tr>
<tr>
<td>画像</td>
<td>テキスト</td>
<td>写真やイラストから、知らない動植物や星座の分類を検索</td>
</tr>
<tr>
<td>画像</td>
<td>画像</td>
<td>近似画像の検索、関連度分析</td>
</tr>
</tbody></table></div>
<p>今回は、前回割愛した画像に関するセマンティック検索について実践します。入力として Slack のカスタム絵文字を扱います。</p>
<p>仕事上でもよく使われる Slack では、ユーザが小さな画像もしくは画像化した文字をカスタム絵文字として自由にアップロードできます。ドアが開けっぱなしに思えますが、現在我々使っている Slack ワークスペースに、5000 個以上のカスタム絵文字が存在し、また日々増え続けており、重複や類似の絵文字がたくさん存在します。</p>
<p>また、アップロード時に絵文字の名称を指定する必要がありますが、一意であれば良いので少し雑な命名も多いです。名前での検索しても、使いたい絵文字はなかなか見つからないこともしばしばです。</p>
<p>例えば、↓ 最初の<code>a</code>から始まる絵文字を紹介します。具体例を見れば雰囲気がわかると思います。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>Name</th>
<th>Icon</th>
</tr>
</thead>
<tbody><tr>
<td>applied</td>
<td><img fetchpriority="high" src="/images/2024/20240828a/applied.png" alt="applied" width="128" height="128"></td>
</tr>
<tr>
<td>approve_done</td>
<td><img src="/images/2024/20240828a/approve_done.png" alt="approve_done" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>ara</td>
<td><img src="/images/2024/20240828a/ara.png" alt="ara" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>arara</td>
<td><img src="/images/2024/20240828a/arara.png" alt="arara" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>arch_alert_mentioin</td>
<td><img src="/images/2024/20240828a/arch_alert_mentioin.png" alt="arch_sbi_alert_mentioin" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>arch_todo</td>
<td><img src="/images/2024/20240828a/arch_todo.png" alt="arch_todo" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>ari</td>
<td><img src="/images/2024/20240828a/ari.png" alt="ari" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>ari_1</td>
<td><img src="/images/2024/20240828a/ari_1.png" alt="ari_1" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>ari_あり</td>
<td><img src="/images/2024/20240828a/ari_あり.png" alt="ari_あり" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>ari2</td>
<td><img src="/images/2024/20240828a/ari2.gif" alt="ari2" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>arigataya</td>
<td><img src="/images/2024/20240828a/arigataya.png" alt="arigataya" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>arigatogozaimasu</td>
<td><img src="/images/2024/20240828a/arigatogozaimasu.png" alt="arigatogozaimasu" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>arigatou</td>
<td><img src="/images/2024/20240828a/arigatou.png" alt="arigatou" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>ariyori</td>
<td><img src="/images/2024/20240828a/ariyori.png" alt="ariyori" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>aroha</td>
<td><img src="/images/2024/20240828a/aroha.png" alt="aroha" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>aruaru</td>
<td><img src="/images/2024/20240828a/aruaru.png" alt="aruaru" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>arunomi</td>
<td><img src="/images/2024/20240828a/arunomi.png" alt="arunomi" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>asaka_朝霞</td>
<td><img src="/images/2024/20240828a/asaka_朝霞.png" alt="asaka_朝霞" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>asakai</td>
<td><img src="/images/2024/20240828a/asakai.png" alt="asakai" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>aserazudeok</td>
<td><img src="/images/2024/20240828a/aserazudeok.png" alt="aserazudeok" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>ashita</td>
<td><img src="/images/2024/20240828a/ashita.png" alt="ashita" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>ashita_hennshinshimasu</td>
<td><img src="/images/2024/20240828a/ashita_hennshinshimasu.png" alt="ashita_hennshinshimasu" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>ashitore</td>
<td><img src="/images/2024/20240828a/ashitore.png" alt="ashitore" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>asu</td>
<td><img src="/images/2024/20240828a/asu.png" alt="asu" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>asu_onegai_shimasu</td>
<td><img src="/images/2024/20240828a/asu_onegai_shimasu.png" alt="asu_onegai_shimasu" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>at_mark</td>
<td><img src="/images/2024/20240828a/at_mark.png" alt="at_mark" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>atchannel_yamero</td>
<td><img src="/images/2024/20240828a/atchannel_yamero.png" alt="atchannel_yamero" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>atesaki_saisettei_alert_mentioin</td>
<td><img src="/images/2024/20240828a/atesaki_saisettei_alert_mentioin.png" alt="atesaki_saisettei_alert_mentioin" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>atode</td>
<td><img src="/images/2024/20240828a/atode.jpg" alt="atode" width="128" height="126" loading="lazy"></td>
</tr>
<tr>
<td>atodekakuninsimasu</td>
<td><img src="/images/2024/20240828a/atodekakuninsimasu.png" alt="atodekakuninsimasu" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>atsui</td>
<td><img src="/images/2024/20240828a/atsui.png" alt="atsui" width="128" height="128" loading="lazy"></td>
</tr>
<tr>
<td>attention</td>
<td><img src="/images/2024/20240828a/attention.png" alt="attention" width="128" height="128" loading="lazy"></td>
</tr>
</tbody></table></div>
<p>それになんとかしたい気持ちで、絵文字の重複検知、便利に使いたい絵文字を意味で検索できるために、セマンティック検索の AI 技術を応用してみました。</p>
<h2 id="データの準備">データの準備</h2><p>まずは、ローカルでデータを扱うように、Slack カスタム絵文字をクローリングでダウンロードします。</p>
<img src="/images/2024/20240828a/image.png" alt="image.png" width="1200" height="924" loading="lazy">

<p>絵文字を表示するときブラウザから投げだした API を fetch 句で拾って、以下になります。<br>（クレデンシャル情報やヘッダーなどを xxxx に書き換えています）。</p>
<img src="/images/2024/20240828a/image_2.png" alt="image.png" width="1200" height="588" loading="lazy">

<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title function_">fetch</span>(<span class="string">&quot;https://edgeapi.slack.com/cache/xxxx/emojis/list?fp=ba&amp;_x_num_retries=0&quot;</span>, &#123;</span><br><span class="line">  <span class="string">&quot;headers&quot;</span>: &#123;</span><br><span class="line">    <span class="string">&quot;content-type&quot;</span>: <span class="string">&quot;text/plain;charset=UTF-8&quot;</span>,</span><br><span class="line">    ...</span><br><span class="line">    &#125;,</span><br><span class="line">  <span class="string">&quot;referrerPolicy&quot;</span>: <span class="string">&quot;no-referrer&quot;</span>,</span><br><span class="line">  <span class="string">&quot;body&quot;</span>: <span class="string">&quot;&#123;\&quot;token\&quot;:\&quot;xxxx\&quot;,\&quot;count\&quot;:100,\&quot;marker\&quot;:\&quot;compliance_warning_コンプラ\&quot;,\&quot;enterprise_token\&quot;:\&quot;xxxx\&quot;&#125;&quot;</span>,</span><br><span class="line">  <span class="string">&quot;method&quot;</span>: <span class="string">&quot;POST&quot;</span>,</span><br><span class="line">  <span class="string">&quot;mode&quot;</span>: <span class="string">&quot;cors&quot;</span>,</span><br><span class="line">  <span class="string">&quot;credentials&quot;</span>: <span class="string">&quot;include&quot;</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>レスポンスがページネーションされて、100 件ずつ取っていることが分かりました。</p>
<p>その挙動をシミュレートする Python のスクリプトを作って、全量の絵文字名と URL を yaml ファイルに保存します。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> requests <span class="keyword">import</span> Session</span><br><span class="line"><span class="keyword">import</span> yaml</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">list_emojis_url = (</span><br><span class="line">    <span class="string">&quot;https://edgeapi.slack.com/cache/xxxx/emojis/list?fp=ba&amp;_x_num_retries=0&quot;</span></span><br><span class="line">) <span class="comment"># ブラウザ上コピーした実のfetch句のURLに合わせる</span></span><br><span class="line">cookie_string = <span class="string">&#x27;&lt;ログイン処理が面倒なので、ブラウザのクッキー情報を引っ張ってくる&gt;&#x27;</span></span><br><span class="line">token = <span class="string">&quot;xxxx&quot;</span> <span class="comment"># こちらもブラウザの情報を引っ張る</span></span><br><span class="line">s = Session()</span><br><span class="line"><span class="keyword">for</span> cookie <span class="keyword">in</span> cookie_string.split(<span class="string">&quot;; &quot;</span>):</span><br><span class="line">    name, value = cookie.split(<span class="string">&quot;=&quot;</span>, <span class="number">1</span>)</span><br><span class="line">    s.cookies.<span class="built_in">set</span>(name, value)</span><br><span class="line"></span><br><span class="line">marker = <span class="string">&quot;_doing&quot;</span> <span class="comment"># 1個目の絵文字名称</span></span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">    json_data = &#123;</span><br><span class="line">        <span class="string">&quot;token&quot;</span>: token,</span><br><span class="line">        <span class="string">&quot;enterprise_token&quot;</span>: token,</span><br><span class="line">        <span class="string">&quot;count&quot;</span>: <span class="number">100</span>,</span><br><span class="line">        <span class="string">&quot;marker&quot;</span>: marker,</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    response = s.post(url=list_emojis_url, json=json_data).json()</span><br><span class="line"></span><br><span class="line">    <span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">&quot;results.yaml&quot;</span>, <span class="string">&quot;a&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">        yaml.dump(response[<span class="string">&quot;results&quot;</span>], f)</span><br><span class="line">    marker = response.get(<span class="string">&quot;next_marker&quot;</span>)</span><br><span class="line">    <span class="keyword">if</span> marker <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">        <span class="keyword">break</span></span><br></pre></td></tr></table></figure>

<p>保存した yaml ファイルは以下のような形になります。<br>（うちの場合、5000+要素、約 770 KB）</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="bullet">-</span> <span class="attr">name:</span> <span class="string">_doing</span></span><br><span class="line">  <span class="attr">updated:</span> <span class="number">1642723962</span></span><br><span class="line">  <span class="attr">value:</span> <span class="string">https://emoji.slack-edge.com/T01310927L1/_doing/15ac6e3e64ce0764.png</span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">name:</span> <span class="string">-sherlock-holmes-costume</span></span><br><span class="line">  <span class="attr">updated:</span> <span class="number">1720678172</span></span><br><span class="line">  <span class="attr">value:</span> <span class="string">https://emoji.slack-edge.com/T01310927L1/-sherlock-holmes-costume/0d46d4d059e8f066.png</span></span><br><span class="line"><span class="bullet">-</span> <span class="string">...</span></span><br></pre></td></tr></table></figure>

<p>yaml に記載してあった <code>value</code> を URL として、<code>name</code> を保存先のファイル（拡張子は URL を尊重する）として、ローカルにダウンロードします。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> os</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"><span class="keyword">import</span> yaml</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">read_yaml_result</span>(<span class="params">filename</span>):</span><br><span class="line">    <span class="keyword">with</span> <span class="built_in">open</span>(filename) <span class="keyword">as</span> input_data:</span><br><span class="line">        <span class="keyword">return</span> yaml.safe_load(input_data)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">download_image</span>(<span class="params">file_path, url</span>):</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        response = requests.get(url)</span><br><span class="line">        response.raise_for_status()</span><br><span class="line">        <span class="keyword">with</span> <span class="built_in">open</span>(file_path, <span class="string">&quot;wb&quot;</span>) <span class="keyword">as</span> file:</span><br><span class="line">            file.write(response.content)</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;Downloaded <span class="subst">&#123;file_path&#125;</span>&quot;</span>)</span><br><span class="line">    <span class="keyword">except</span> requests.exceptions.RequestException <span class="keyword">as</span> e:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;Failed to download <span class="subst">&#123;name&#125;</span>: <span class="subst">&#123;e&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&quot;__main__&quot;</span>:</span><br><span class="line">    input_file_name = <span class="string">&quot;results.yaml&quot;</span></span><br><span class="line"></span><br><span class="line">    output_directory = <span class="string">&quot;images&quot;</span></span><br><span class="line">    os.makedirs(output_directory, exist_ok=<span class="literal">True</span>)</span><br><span class="line"></span><br><span class="line">    skip = <span class="literal">True</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> item <span class="keyword">in</span> read_yaml_result(input_file_name):</span><br><span class="line">        name = item[<span class="string">&quot;name&quot;</span>]</span><br><span class="line">        url = item[<span class="string">&quot;value&quot;</span>]</span><br><span class="line">        <span class="keyword">if</span> skip <span class="keyword">and</span> name == <span class="string">&quot;simple_smile&quot;</span>:</span><br><span class="line">            skip = <span class="literal">False</span></span><br><span class="line">        <span class="keyword">if</span> skip:</span><br><span class="line">            <span class="keyword">continue</span></span><br><span class="line">        _, ext = os.path.splitext(url)</span><br><span class="line">        file_path = os.path.join(output_directory, <span class="string">f&quot;<span class="subst">&#123;name&#125;</span><span class="subst">&#123;ext&#125;</span>&quot;</span>)</span><br><span class="line">        download_image(file_path, url)</span><br></pre></td></tr></table></figure>

<p>ファイルを正しくダウンロードできたことが確認できました。</p>
<img src="/images/2024/20240828a/image_3.png" alt="image.png" width="1200" height="1644" loading="lazy">

<h2 id="画像データのベクトル化">画像データのベクトル化</h2><p>Sentence-Transformers のこのページをベースとして参考して、画像をベクトルに Embedding しておきます。</p>
<p>※ ファイル数が多すぎますので、デモ用で 1000 ファイルのみ処理します。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> os</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> PIL <span class="keyword">import</span> Image</span><br><span class="line"><span class="keyword">from</span> sentence_transformers <span class="keyword">import</span> SentenceTransformer</span><br><span class="line"></span><br><span class="line"><span class="comment"># Set the path to your images directory</span></span><br><span class="line">images_dir = <span class="string">&quot;images&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Set a maximum number of images to process</span></span><br><span class="line">max_images = <span class="number">1000</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Load the model</span></span><br><span class="line">model = SentenceTransformer(<span class="string">&quot;clip-ViT-B-32&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># Get the list of image file paths</span></span><br><span class="line">image_files = [os.path.join(images_dir, file) <span class="keyword">for</span> file <span class="keyword">in</span> os.listdir(images_dir)][</span><br><span class="line">    :max_images</span><br><span class="line">]</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># Load images and compute embeddings</span></span><br><span class="line">images = []</span><br><span class="line">image_labels = []</span><br><span class="line"><span class="keyword">for</span> image_file <span class="keyword">in</span> image_files:</span><br><span class="line">    images.append(Image.<span class="built_in">open</span>(image_file))</span><br><span class="line">    base, ext = os.path.splitext(os.path.basename(image_file))</span><br><span class="line">    image_labels.append(base)</span><br><span class="line"></span><br><span class="line">img_emb = model.encode(images)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(img_emb)</span><br><span class="line"><span class="built_in">print</span>(img_emb.shape)</span><br></pre></td></tr></table></figure>

<p>実行結果です。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">python3 visualize.py</span></span><br><span class="line">[[ 0.3558431  -0.4127885  -0.38162816 ...  0.8868538  -0.24081565</span><br><span class="line">   0.11687451]</span><br><span class="line"> [ 0.35159412 -0.22937642 -0.28752807 ...  0.7736969  -0.5258111</span><br><span class="line">   0.40994892]</span><br><span class="line"> [ 0.23833637 -0.2584821  -0.3712055  ...  0.89749026  0.03570646</span><br><span class="line">  -0.2068485 ]</span><br><span class="line"> ...</span><br><span class="line"> [ 0.17339917 -0.16685665  0.13446489 ...  0.87421316 -0.18107425</span><br><span class="line">   0.39892197]</span><br><span class="line"> [ 0.17150897  0.18003528 -0.40643013 ...  0.9075323  -0.35873666</span><br><span class="line">   0.00515198]</span><br><span class="line"> [-0.26825747 -0.1587921   0.04072791 ...  0.9843429  -0.40589246</span><br><span class="line">   0.00923938]]</span><br><span class="line">(1000, 512)</span><br></pre></td></tr></table></figure>

<p>“clip-ViT-B-32”モデルで、1000 個の画像データをそれぞれ 512 次元のベクトルに変換できました。</p>
<p>そのベクトルを使って、画像間の距離計算、分類、検索など、色々なことができます。</p>
<p>その多次元のベクトルを主要要素を抽出して 2 次元に圧縮して、画面上に描画する方法を ChatGPT 先生に教えてもらいました。</p>
<img src="/images/2024/20240828a/image_4.png" alt="image.png" width="1200" height="1074" loading="lazy">

<p>たくさんオプションが教えられていますが、1 個目の TSNE でも良いでしょう。</p>
<p>早速描画してみましょう。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> matplotlib.pyplot <span class="keyword">as</span> plt</span><br><span class="line"><span class="keyword">from</span> sklearn.manifold <span class="keyword">import</span> TSNE</span><br><span class="line"></span><br><span class="line"><span class="comment"># Apply t-SNE to reduce dimensions to 2D</span></span><br><span class="line"><span class="comment"># Choosing a perplexity value appropriate for the dataset size</span></span><br><span class="line">perplexity_value = <span class="built_in">min</span>(<span class="number">30</span>, <span class="built_in">len</span>(img_emb) - <span class="number">1</span>)</span><br><span class="line"><span class="comment"># perplexity_value = 50</span></span><br><span class="line">tsne = TSNE(n_components=<span class="number">2</span>, perplexity=perplexity_value, random_state=<span class="number">0</span>)</span><br><span class="line">reduced_embeddings = tsne.fit_transform(img_emb)</span><br><span class="line"></span><br><span class="line">num_clusters = <span class="number">5</span>  <span class="comment"># Specify the number of clusters</span></span><br><span class="line">kmeans = KMeans(n_clusters=num_clusters, random_state=<span class="number">0</span>)</span><br><span class="line">cluster_labels = kmeans.fit_predict(reduced_embeddings)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># Plot the reduced embeddings</span></span><br><span class="line">plt.figure(figsize=(<span class="number">15</span>, <span class="number">9</span>))</span><br><span class="line">plt.scatter(reduced_embeddings[:, <span class="number">0</span>], reduced_embeddings[:, <span class="number">1</span>], alpha=<span class="number">0.5</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># Optional: Annotate points with image labels</span></span><br><span class="line"><span class="keyword">for</span> i, label <span class="keyword">in</span> <span class="built_in">enumerate</span>(image_labels):</span><br><span class="line">    plt.text(</span><br><span class="line">        reduced_embeddings[i, <span class="number">0</span>],</span><br><span class="line">        reduced_embeddings[i, <span class="number">1</span>],</span><br><span class="line">        label,</span><br><span class="line">        fontsize=<span class="number">8</span>,</span><br><span class="line">        alpha=<span class="number">0.6</span>,</span><br><span class="line">        fontname=<span class="string">&quot;YuMincho&quot;</span>, <span class="comment"># 日本語ファイル名を化けないようにフォントの設定</span></span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">plt.title(<span class="string">&quot;t-SNE Visualization of Image Embeddings&quot;</span>)</span><br><span class="line">plt.xlabel(<span class="string">&quot;t-SNE Dimension 1&quot;</span>)</span><br><span class="line">plt.ylabel(<span class="string">&quot;t-SNE Dimension 2&quot;</span>)</span><br><span class="line">plt.grid(<span class="literal">True</span>)</span><br><span class="line">plt.show()</span><br></pre></td></tr></table></figure>

<img src="/images/2024/20240828a/Figure_1.png" alt="Figure_1.png" width="1200" height="646" loading="lazy">

<p>うんん、なるほどの感じですね。多すぎてみにくいですね。<br>ある程度集団化（クラスタ）になっている傾向が見えます。</p>
<h2 id="空間的分類クラスタ">空間的分類クラスタ</h2><p>plotly を利用して、3D でも描画しようと思います。<br>今回は、クラスタを明らかにするため、K-means を使って、適当に 7 色でクラスタに塗りましょう。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> sklearn.cluster <span class="keyword">import</span> KMeans</span><br><span class="line"><span class="keyword">import</span> plotly.express <span class="keyword">as</span> px</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">num_clusters = <span class="number">7</span>  <span class="comment"># Specify the number of clusters</span></span><br><span class="line">kmeans = KMeans(n_clusters=num_clusters, random_state=<span class="number">0</span>)</span><br><span class="line">cluster_labels = kmeans.fit_predict(reduced_embeddings)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">fig = px.scatter_3d(</span><br><span class="line">    x=reduced_embeddings[:, <span class="number">0</span>],</span><br><span class="line">    y=reduced_embeddings[:, <span class="number">1</span>],</span><br><span class="line">    z=reduced_embeddings[:, <span class="number">2</span>],</span><br><span class="line">    color=cluster_labels,  <span class="comment"># Color points by cluster</span></span><br><span class="line">    text=image_labels,  <span class="comment"># Labels for each point</span></span><br><span class="line">    labels=&#123;<span class="string">&quot;x&quot;</span>: <span class="string">&quot;Component 1&quot;</span>, <span class="string">&quot;y&quot;</span>: <span class="string">&quot;Component 2&quot;</span>, <span class="string">&quot;z&quot;</span>: <span class="string">&quot;Component 3&quot;</span>&#125;,  <span class="comment"># Axis labels</span></span><br><span class="line">    title=<span class="string">&quot;3D t-SNE Visualization of Image Embeddings with Clusters&quot;</span>,</span><br><span class="line">    color_continuous_scale=px.colors.qualitative.G10,  <span class="comment"># A color scale for discrete colors</span></span><br><span class="line">)</span><br></pre></td></tr></table></figure>

<p>さっきのポケモンシリーズのクラスタを左になるように回転しておきました。</p>
<img src="/images/2024/20240828a/image_5.png" alt="image.png" width="1200" height="597" loading="lazy">

<p>結果はブラウザ上で閲覧しています。ズームや回転の操作はこんな感じです。</p>
<img src="/images/2024/20240828a/output.gif" alt="output.gif" width="2061" height="1236" loading="lazy">

<p>ファイル名の表示を隠して、細かく 20 分類(<code>num_clusters = 20</code>)にしてみたら、こんな感じです。</p>
<img src="/images/2024/20240828a/output2.gif" alt="output2.gif" width="1200" height="720" loading="lazy">

<h2 id="画像で画像を検索">画像で画像を検索</h2><p>近似画像を検索する手法は、データと同じくクエリ用の画像の特徴ベクトルを計算(Embedding)し、既存データのベクトルの類似度(今回のモデルは cosine 距離)を計算し、類似度高い順で結果を取得するという流れです。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line">query_emb = model.encode(Image.<span class="built_in">open</span>(<span class="string">&quot;images/白旗.png&quot;</span>))</span><br><span class="line"><span class="comment"># query_emb = model.encode(Image.open(&quot;images/天才.png&quot;))</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Compute cosine similarity between the query embedding and each image embedding</span></span><br><span class="line">similarities = model.similarity(query_emb, img_emb).reshape((-<span class="number">1</span>,))</span><br><span class="line"></span><br><span class="line"><span class="comment"># Get the indices of the most similar images</span></span><br><span class="line">k = <span class="number">5</span>  <span class="comment"># Number of nearest neighbors you want to find</span></span><br><span class="line">top_k_indices = <span class="built_in">reversed</span>(np.argsort(similarities)[-k:])</span><br><span class="line"></span><br><span class="line"><span class="comment"># Retrieve the top k similarities and corresponding images</span></span><br><span class="line">top_k_similarities = similarities[top_k_indices]</span><br><span class="line"></span><br><span class="line"><span class="comment"># Print the results</span></span><br><span class="line"><span class="keyword">for</span> i, (index, score) <span class="keyword">in</span> <span class="built_in">enumerate</span>(<span class="built_in">zip</span>(top_k_indices, top_k_similarities)):</span><br><span class="line">    <span class="built_in">print</span>(</span><br><span class="line">        <span class="string">f&quot;Rank <span class="subst">&#123;i + <span class="number">1</span>&#125;</span>: Image Name: <span class="subst">&#123;image_files[index]&#125;</span>, Similarity Score <span class="subst">&#123;score:<span class="number">.4</span>f&#125;</span>&quot;</span></span><br><span class="line">    )</span><br></pre></td></tr></table></figure>

<p><strong>結果例 1</strong></p>
<p>クエリ画像:<br><code>images/白旗.png</code></p>
<p>ヒットした Top5 の画像:</p>
<figure class="highlight txt"><table><tr><td class="code"><pre><span class="line">Rank 1: Image Name: images/pose_seiza_man.png, Similarity Score 0.8798</span><br><span class="line">Rank 2: Image Name: images/mushiba.png, Similarity Score 0.8741</span><br><span class="line">Rank 3: Image Name: images/ganka.png, Similarity Score 0.8697</span><br><span class="line">Rank 4: Image Name: images/リーゼント.png, Similarity Score 0.8454</span><br><span class="line">Rank 5: Image Name: images/しゃちく.png, Similarity Score 0.8415</span><br></pre></td></tr></table></figure>

<img src="/images/2024/20240828a/image_6.png" alt="image.png" width="1200" height="553" loading="lazy">

<p>今回のクエリ画像は、全体の 5000+の画像から選択した 1000 件に含まれていないため、Top1 がクエリ画像自身をヒットしていないです。</p>
<p>上位の 3 個のヒットは同一キャラクタのことが分かりますね。<br>4 番目のヤンキー少年と 5 番目のしゃちくさんは混入していますね。<br>真面目の青い服の青年の B サイド のことでしょう。ww</p>
<p><strong>結果例 2</strong></p>
<p>クエリ画像:<br><code>images/天才.png</code></p>
<p>ヒットした Top5 の画像:</p>
<figure class="highlight txt"><table><tr><td class="code"><pre><span class="line">Rank 1: Image Name: images/さすが.png, Similarity Score 0.9758</span><br><span class="line">Rank 2: Image Name: images/tomi.png, Similarity Score 0.9647</span><br><span class="line">Rank 3: Image Name: images/katatore.png, Similarity Score 0.9639</span><br><span class="line">Rank 4: Image Name: images/肉.png, Similarity Score 0.9570</span><br><span class="line">Rank 5: Image Name: images/作業中.png, Similarity Score 0.9537</span><br></pre></td></tr></table></figure>

<img src="/images/2024/20240828a/image_7.png" alt="image.png" width="1050" height="468" loading="lazy">

<p>近似度みんな高い(0.95 以上)です。画像の中の文字の意味が理解していない様子です。</p>
<p>印鑑系丸くて赤い文字が特徴でしょう。ただ、最後の「作業中」は丸くもないですけど。</p>
<p>肩トレの「レ」や「肉」文字の外側、ちょっと丸くなっている感が見えているのでしょう。</p>
<h2 id="文字で画像を検索">文字で画像を検索</h2><p>上記画像から画像の検索と似たように、同じモデルで、文字列も同様な Embedding 処理ができます。<br>ちょっと微修正したら、文字で画像を検索することが実現可能です（マルチモーダルのスゴさ）</p>
<p>ちなみに、日本語でも検索できるようにしたい場合は、多言語対応の“clip-ViT-B-32-multilingual-v1”モデルを使ったほうがいいそうです。</p>
<p>ただ、画像の Embedding は“clip-ViT-B-32”のままを使用するのが正しいです。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line">model2 = SentenceTransformer(<span class="string">&quot;clip-ViT-B-32-multilingual-v1&quot;</span>)</span><br><span class="line"></span><br><span class="line">query_emb = model2.encode(<span class="string">&quot;ポケモンボール&quot;</span>)</span><br><span class="line"><span class="comment"># query_emb = model2.encode(&quot;上は赤、下は白、球体&quot;)</span></span><br><span class="line"><span class="comment"># query_emb = model2.encode(&quot;ビーチボール&quot;)</span></span><br><span class="line"><span class="comment"># query_emb = model2.encode(&quot;ビール&quot;)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Compute cosine similarity between the query embedding and each image embedding</span></span><br><span class="line">similarities = model.similarity(query_emb, img_emb).reshape((-<span class="number">1</span>,))</span><br></pre></td></tr></table></figure>

<p>ただ、文字が画像の中身を抽象的な名称では、あまりヒットしなく、画像の形状や色、物体の表現のほうがヒットしやすいです。</p>
<p>例えば、以下具体の結果例:</p>
<figure class="highlight txt"><table><tr><td class="code"><pre><span class="line">クエリ文字: &quot;ポケモンボール&quot;</span><br><span class="line">Rank 1: Image Name: images/おっとっと.png, Similarity Score 0.2725</span><br><span class="line">Rank 2: Image Name: images/images.png, Similarity Score 0.2725</span><br><span class="line">Rank 3: Image Name: images/anpn_アンパンチ.png, Similarity Score 0.2682</span><br><span class="line">Rank 4: Image Name: images/piyo_mushin.png, Similarity Score 0.2675</span><br><span class="line">Rank 5: Image Name: images/piyo-mushin.png, Similarity Score 0.2675</span><br></pre></td></tr></table></figure>

<p>以下の色や形状の表現ならヒットします（ただ、近似度 0.26 は高くないです）。</p>
<figure class="highlight txt"><table><tr><td class="code"><pre><span class="line">クエリ文字: &quot;上は赤、下は白、球体&quot;</span><br><span class="line">Rank 1: Image Name: images/monster_ball.png, Similarity Score 0.2619</span><br><span class="line">Rank 2: Image Name: images/ポンパ君_スクロール.gif, Similarity Score 0.2521</span><br><span class="line">Rank 3: Image Name: images/redmine.png, Similarity Score 0.2512</span><br><span class="line">Rank 4: Image Name: images/alert.gif, Similarity Score 0.2495</span><br><span class="line">Rank 5: Image Name: images/spiderman2.jpg, Similarity Score 0.2492</span><br></pre></td></tr></table></figure>

<p>ただし、下記の特定な名称では、またヒットします。<br>おそらく、当時の訓練用のデータに依存していることでしょう。</p>
<figure class="highlight txt"><table><tr><td class="code"><pre><span class="line">クエリ文字: &quot;ビーチボール&quot;</span><br><span class="line">Rank 1: Image Name: images/monster_ball.png, Similarity Score 0.2570</span><br><span class="line">Rank 2: Image Name: images/おっとっと.png, Similarity Score 0.2544</span><br><span class="line">Rank 3: Image Name: images/images.png, Similarity Score 0.2544</span><br><span class="line">Rank 4: Image Name: images/panda_マスク.png, Similarity Score 0.2543</span><br><span class="line">Rank 5: Image Name: images/piyo_mushin.png, Similarity Score 0.2541</span><br></pre></td></tr></table></figure>

<p>最後に、みんなが大好きな「ビール」でテストしてみましょう。</p>
<figure class="highlight txt"><table><tr><td class="code"><pre><span class="line">クエリ文字: &quot;ビール&quot;</span><br><span class="line">Rank 1: Image Name: images/alphabet-white-b.png, Similarity Score 0.2633</span><br><span class="line">Rank 2: Image Name: images/nomuzo.png, Similarity Score 0.2517</span><br><span class="line">Rank 3: Image Name: images/アカン.png, Similarity Score 0.2511</span><br><span class="line">Rank 4: Image Name: images/ega.png, Similarity Score 0.2438</span><br><span class="line">Rank 5: Image Name: images/やっつけ.jpg, Similarity Score 0.2433</span><br></pre></td></tr></table></figure>

<img src="/images/2024/20240828a/image_8.png" alt="image.png" width="1200" height="255" loading="lazy">

<p>また笑い話になりますが、トップでヒットしたのは「ビー」の部分でした！<br>2 番目はひよこちゃんがビール持っているし、「あ缶」はまあまあ缶ビールに関連しているでしょう。<br>4 番目は芸能人の手のジェスチャーが間違えてビールを持っているように間違えたかなと思います。最後のやっつけは？ 言われてみれば、その背景がビールのと泡の色や状態にちょっと似ているかもしれません。</p>
<p>また、今回のデモでは、1 個のクエリベクトルに対して、全データ(1000 個)のベクトルとの近似度(Cosine Similarity)が計算して、ソートをかけてしまいました。もし事前にインデックスを立てたり、近似な結果も許されたりする場合、k-近傍法(k-NN)のもっと効率的なアルゴリズムもあります（割愛）</p>
<h2 id="まとめ">まとめ</h2><p>2023年の記事の続きとして、事前訓練された(pre-trained)マルチモーダル(multi-modal)の AI モデルを使った画像処理を実践してみました。</p>
<p>Slack のカスタム絵文字のデータを利用して、関連性によってクラスタ化して、可視化グラフを書いてみました。<br>人間の好みが関与したデータとして、ベクトル空間上で、均一にランダムの分散するではなく、集団化（クラスタ化）で分布していることが直感的に分かりました。</p>
<p>また、セマンティック検索について、検証の結果は指標化までできていませんが、直感的に、</p>
<ul>
<li>「画像 → 画像」の検索は、なんとなく精度が悪くなく</li>
<li>「文字 → 画像」の検索はすぐには実用化とはちょっと微妙</li>
</ul>
<p>そして、近似データや重複データの検知や排除する手法として、他の領域へも応用できそうだと思います。</p>
]]></content>
    <summary type="html">Slack のカスタム絵文字を AI で遊びました</summary>
    <category term="DataScience" scheme="https://future-architect.github.io/categories/DataScience/"/>
    <category term="Plotly" scheme="https://future-architect.github.io/tags/Plotly/"/>
    <category term="SentenceTransformers" scheme="https://future-architect.github.io/tags/SentenceTransformers/"/>
    <category term="Slack" scheme="https://future-architect.github.io/tags/Slack/"/>
    <category term="embedding" scheme="https://future-architect.github.io/tags/embedding/"/>
    <category term="クラスタリング" scheme="https://future-architect.github.io/tags/%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0/"/>
    <category term="画像処理" scheme="https://future-architect.github.io/tags/%E7%94%BB%E5%83%8F%E5%87%A6%E7%90%86/"/>
  </entry>
</feed>
