公開日: 2024 年 1 月 13 日
これは、LLM と chatbot に関する 3 部構成のシリーズの第 2 回です。前回の記事では、オンデバイス LLM とブラウザ内 LLM のメリットとデメリットについて説明しました。
クライアントサイド AI について理解が深まったところで、ToDo リスト ウェブ アプリケーションに WebLLM を追加しましょう。コードは GitHub リポジトリの web-llm
ブランチにあります。
WebLLM は、ML コンパイルが提供する LLM 用のウェブベースのランタイムです。WebLLM をスタンドアロン アプリケーションとして試すことができます。このアプリケーションは、Gemini などのクラウド バックアップのチャット アプリケーションにヒントを得ていますが、LLM 推論はクラウドではなくデバイスで実行されます。プロンプトとデータはデバイスから送信されることはなく、モデルのトレーニングに使用されることはありません。
デバイスでモデル推論を実行するため、WebLLM は WebAssembly と WebGPU を組み合わせています。WebAssembly では中央処理装置(CPU)で効率的な計算が可能ですが、WebGPU ではデバイスのグラフィック プロセッシング ユニット(GPU)に低レベルでアクセスできます。
WebLLM をインストールする
WebLLM は npm パッケージとして利用できます。このパッケージを ToDo リスト アプリケーションに追加するには、npm install @mlc-ai/web-llm
を実行します。
モデルの選択
次に、ローカルで実行する LLM を決定する必要があります。さまざまなモデルが用意されています。
決定するには、次の主な用語と数字を把握しておく必要があります。
- トークン: LLM が処理できるテキストの最小単位。
- コンテキスト ウィンドウ: モデルが処理できるトークンの最大数。
- パラメータまたは重み: トレーニング中に学習された内部変数。数十億単位でカウントされます。
- 量子化: 重みを表すビット数。ビット数が多いほど精度は高くなりますが、メモリ使用量も増加します。
- 浮動小数点数形式: 32 ビットの浮動小数点数(フル精度、F32)は精度が高く、16 ビットの浮動小数点数(半精度、F16)は速度が速くメモリ使用量が少ない一方で、互換性のあるハードウェアが必要です。
これらのキーワードは、モデル名の一部になる傾向があります。たとえば、Llama-3.2-3B-Instruct-q4f32_1-MLC
には次の情報が含まれます。
- モデルは LLaMa 3.2 です。
- このモデルには 30 億のパラメータがあります。
- 指示やプロンプト スタイルのアシスタント(Instruct)向けにファインチューニングされています。
- 4 ビット(q4)均一(_1)量子化を使用します。
- フル精度の 32 ビット浮動小数点数を使用します。
- これは、ML コンパイルで作成された特別なバージョンです。
ユースケースに適したモデルを判断するには、さまざまなモデルをテストする必要があります。
30 億個のパラメータとパラメータあたり 4 ビットのモデルの場合、この記事の執筆時点ではファイルサイズが 1.4 GB にも達する可能性があります。このモデルを初めて使用する前に、アプリでユーザーのデバイスにダウンロードする必要があります。30 億個のモデルでも動作しますが、翻訳機能や雑学知識に関しては、70 億個のモデルのほうが優れた結果が得られます。3.3 GB 以上の場合は、サイズが大幅に大きくなります。
WebLLM エンジンを作成して、ToDo リスト チャットボットのモデルのダウンロードを開始するには、次のコードをアプリケーションに追加します。
import {CreateMLCEngine} from '@mlc-ai/web-llm';
const engine = await CreateMLCEngine('Llama-3.2-3B-Instruct-q4f32_1-MLC', {
initProgressCallback: ({progress}) => console.log(progress);
});
CreateMLCEngine
メソッドは、モデル文字列とオプションの構成オブジェクトを受け取ります。initProgressCallback
メソッドを使用して、モデルのダウンロード プログレスをクエリし、ユーザーが待機している間に表示できます。
Cache API: LLM をオフラインで実行する
モデルはウェブサイトのキャッシュ ストレージにダウンロードされます。Cache API は、ウェブサイトやウェブ アプリケーションをオフラインで実行できるようにするために、Service Workers とともに導入されました。これは、AI モデルをキャッシュに保存するための最適なストレージ メカニズムです。HTTP キャッシュとは対照的に、Cache API はデベロッパーが完全に制御できるプログラム可能なキャッシュです。
ダウンロードが完了すると、WebLLM はネットワーク経由でモデルファイルをリクエストするのではなく、Cache API からモデルファイルを読み取るため、WebLLM は完全にオフラインで動作できるようになります。
すべてのウェブサイト ストレージと同様に、キャッシュはオリジンごとに分離されます。つまり、2 つのオリジン(example.com と example.net)が同じストレージを共有することはできません。これらの 2 つのウェブサイトで同じモデルを使用する場合は、モデルを別々にダウンロードする必要があります。
DevTools を使用してキャッシュを検査するには、[Application] > [Storage] に移動して、キャッシュ ストレージを開きます。
会話を設定する
モデルは、一連の初期プロンプトで初期化できます。一般に、メッセージのロールには次の 3 つがあります。
- システム指示: この指示は、モデルの動作、役割、キャラクターを定義します。また、グラウンドングにも使用できます。つまり、トレーニング セットに含まれないカスタムデータ(ドメイン固有のデータなど)をモデルにフィードします。指定できるシステム プロンプトは 1 つだけです。
- ユーザー プロンプト: ユーザーが入力したプロンプト。
- アシスタント プロンプト: アシスタントからの回答(省略可)。
ユーザー プロンプトとアシスタント プロンプトは、LLM の動作や応答方法に関する自然言語の例を LLM に提供することで、N ショット プロンプトに使用できます。
以下に、ToDo リスト アプリの会話を設定する最小限の例を示します。
const messages = [
{ role: "system",
content: `You are a helpful assistant. You will answer questions related to
the user's to-do list. Decline all other requests not related to the user's
todos. This is the to-do list in JSON: ${JSON.stringify(todos)}`
},
{role: "user", content: "How many open todos do I have?"}
];
最初の質問に回答する
チャット完了機能は、前に作成した WebLLM エンジンのプロパティとして公開されます(engine.chat.completions
)。モデルがダウンロードされたら、このプロパティで create()
メソッドを呼び出してモデル推論を実行できます。このユースケースでは、レスポンスをストリーミングして、生成中にユーザーが読み取りを開始できるようにし、待ち時間の認識を短縮します。
const chunks = await engine.chat.completions.create({ messages, stream: true, });
このメソッドは、非表示の AsyncIterator
クラスのサブクラスである AsyncGenerator
を返します。for await...of
ループを使用して、チャンクが届くのを待ちます。ただし、レスポンスには新しいトークン(delta
)のみが含まれるため、完全なレスポンスを自分で組み立てる必要があります。
let reply = '';
for await (const chunk of chunks) {
reply += chunk.choices[0]?.delta.content ?? '';
console.log(reply);
}
ウェブでは常にストリーミング レスポンスを処理する必要がありました。DOMImplementation などの API を使用して、これらのストリーミング レスポンスを処理し、HTML を効率的に更新できます。
結果は純粋に文字列ベースです。JSON または他のファイル形式として解釈するには、まず解析する必要があります。
ただし、WebLLM にはいくつかの制限があります。アプリケーションは初回使用前に巨大なモデルをダウンロードする必要がありますが、このモデルはオリジン間で共有できないため、別のウェブアプリが同じモデルを再度ダウンロードしなければならない場合があります。WebGPU はネイティブに近い推論パフォーマンスを達成しますが、ネイティブの速度には達しません。
デモ
これらの欠点は、Google が提案した探索 API である Prompt API によって解消されます。この API はクライアントサイドで実行されますが、Chrome にダウンロードされた一元化されたモデルを使用します。つまり、複数のアプリケーションが同じモデルを最大実行速度で使用できます。
詳しくは、次の記事の Prompt API を使用した chatbot 機能の追加をご覧ください。