はじめに
30代になって思うのは、技術の進化って本当に早いなということ。数年前まで機械学習といえばPythonでサーバーサイドで動かすのが当たり前だったのに、今やブラウザ上でAIが動く時代になっている。
今回紹介するTransformers.jsは、まさにその流れを象徴するライブラリだ。Hugging Faceが開発したこのライブラリを使えば、サーバーなしでブラウザ上で直接機械学習モデルを実行できる。個人的には、これがJavaScript開発者にとってAIを活用する最も手軽な方法だと思っている。
GitHubで15,000以上のスターを獲得しているだけあって、コミュニティも活発で安心して使える。
とはいえ、説明を読むより実際に動かした方が早いと思う。pipeline関数を使った感情分析をブラウザだけで実行できるサンプルを用意したので、先に触ってみたい方はこちらからどうぞ(モデルのダウンロードが入るため、初回の実行には少し時間がかかります)。
特徴・メリット
サーバー不要でブラウザで完結
一番のメリットは、APIサーバーを用意しなくてもいいという点。ユーザーのブラウザ上でモデルが動作するため、サーバーコストがかからない。個人開発やスタートアップには特に嬉しい話だと思う。
Python版と同等のAPI
Hugging FaceのPython版transformersライブラリと互換性のあるAPIを提供している。Pythonで機械学習を触ったことがある人なら、ほぼ同じ書き方でJavaScriptでもAIを動かせる。学習コストが低いのは正直ありがたい。
幅広いタスクに対応
自然言語処理だけでなく、画像認識や音声認識まで対応している。具体的には以下のようなタスクが可能だ。
- 自然言語処理: 感情分析、テキスト分類、質問応答、翻訳、要約、テキスト生成
- コンピュータビジョン: 画像分類、物体検出、セグメンテーション、深度推定
- 音声処理: 音声認識、音声分類、テキスト音声変換
- マルチモーダル: ゼロショット画像分類、ゼロショット物体検出
WebGPU対応で高速化
最新版ではWebGPUに対応しており、GPUを使った高速な推論が可能になっている。これ、意外と重要なポイントで、ブラウザでもそれなりの速度でモデルを動かせるようになった。
量子化オプション
リソースが限られたブラウザ環境では、モデルの量子化が効いてくる。fp32、fp16、q8、q4といったデータ型を選択でき、帯域幅の削減とパフォーマンス最適化ができる。
インストール方法
npm経由
npm install @huggingface/transformers
CDN経由
HTMLファイルで直接使う場合はこちら。
<script type="module">
import { pipeline } from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.8.1';
</script>
Transformers.jsのサンプルを動かす
説明の前に、まず動くものを触ってみてください。下のテキストエリアに英文を入力して「感情を分析する」ボタンを押すと、Transformers.jsのpipeline('sentiment-analysis', ...)がブラウザ内でモデルをロードし、その場でPOSITIVE / NEGATIVEの判定と確信度を返します。サーバーへのリクエストは一切発生しません。
注意点として、初回実行時はモデルの重み(数十MB)をHugging Face Hubからダウンロードするため、ネットワーク環境によっては読み込みに時間がかかります。 進行状況は画面とコンソール(console=openにしてあります)の両方に出るので、気長にお待ちください。2回目以降はブラウザにキャッシュされるため高速に起動します。
要点だけを先に見ておくと、pipeline()にタスク名とモデルIDを渡し、dtypeオプションで量子化レベル(ここではq8)を指定してモデルを軽量化しているのがポイントです。
import { pipeline } from '@huggingface/transformers'
// パイプラインを作成(初回はモデルをダウンロードしてブラウザにキャッシュする)
const classifier = await pipeline(
'sentiment-analysis',
'Xenova/distilbert-base-uncased-finetuned-sst-2-english',
{ dtype: 'q8' } // 量子化して軽量化する
)
const result = await classifier('I love using Transformers.js in the browser!')
console.log(result)
// [{ label: 'POSITIVE', score: 0.999... }]
実際に入力欄を書き換えて試せるのが下のサンプルです。英文であればどんな内容でも構いません。ポジティブな文章とネガティブな文章を交互に入れてみると、score(確信度)が判定に応じて変わるのが分かります。
Xenova/distilbert-base-uncased-finetuned-sst-2-englishは英語専用の感情分析モデルです。日本語で試したい場合は、後述するXenova/bert-base-multilingual-uncased-sentimentのような多言語対応モデルにモデルIDを差し替えれば同じコードでそのまま動きます。
基本的な使い方
感情分析の例
最もシンプルな使い方はpipeline関数を使う方法。Python版を使ったことがある人には馴染みのある書き方だと思う。
import { pipeline } from '@huggingface/transformers';
// 感情分析パイプラインを作成
const classifier = await pipeline('sentiment-analysis');
// テキストを分析
const result = await classifier('I love transformers!');
console.log(result);
// [{ label: 'POSITIVE', score: 0.999817686 }]
日本語対応モデルを使う
特定のモデルを指定することもできる。日本語を扱いたい場合は多言語対応モデルを指定する。
const classifier = await pipeline(
'sentiment-analysis',
'Xenova/bert-base-multilingual-uncased-sentiment'
);
const result = await classifier('この製品は素晴らしいです');
console.log(result);
WebGPUで高速化
GPUを使って高速に推論したい場合はdeviceオプションを指定する。
const classifier = await pipeline(
'sentiment-analysis',
'Xenova/distilbert-base-uncased-finetuned-sst-2-english',
{ device: 'webgpu' }
);
量子化モデルを使う
軽量なモデルを使いたい場合は、dtypeオプションで量子化レベルを指定できる。
const classifier = await pipeline(
'sentiment-analysis',
'Xenova/distilbert-base-uncased-finetuned-sst-2-english',
{ dtype: 'q4' }
);
実践的なユースケース
音声認識(Whisper)
OpenAIのWhisperモデルを使って音声からテキストに変換できる。
import { pipeline } from '@huggingface/transformers';
const transcriber = await pipeline(
'automatic-speech-recognition',
'Xenova/whisper-small'
);
const result = await transcriber(audioData);
console.log(result.text);
画像分類
画像をアップロードして、何が写っているか分類することもできる。
import { pipeline } from '@huggingface/transformers';
const classifier = await pipeline(
'image-classification',
'Xenova/vit-base-patch16-224'
);
const result = await classifier(imageUrl);
console.log(result);
// [{ label: 'cat', score: 0.95 }, ...]
テキスト翻訳
多言語翻訳もブラウザ上で実行可能だ。
import { pipeline } from '@huggingface/transformers';
const translator = await pipeline(
'translation',
'Xenova/nllb-200-distilled-600M'
);
const result = await translator('Hello, how are you?', {
src_lang: 'eng_Latn',
tgt_lang: 'jpn_Jpan'
});
console.log(result[0].translation_text);
物体検出
画像内の物体を検出し、位置を特定することもできる。
import { pipeline } from '@huggingface/transformers';
const detector = await pipeline(
'object-detection',
'Xenova/detr-resnet-50'
);
const result = await detector(imageUrl);
// [{ label: 'person', score: 0.99, box: { xmin, ymin, xmax, ymax } }, ...]
ゼロショット画像分類
事前に学習していないカテゴリでも分類できるのがゼロショット分類の強み。
import { pipeline } from '@huggingface/transformers';
const classifier = await pipeline(
'zero-shot-image-classification',
'Xenova/clip-vit-base-patch32'
);
const result = await classifier(imageUrl, ['猫', '犬', '鳥', '車']);
console.log(result);
埋め込み生成(テキストの類似度計算)
feature-extractionタスクを使うと、テキストを数百次元のベクトル(埋め込み)に変換できる。ベクトル同士のコサイン類似度を計算すれば、2つの文章がどれくらい意味的に近いかを数値化できる。検索やレコメンドの土台になる技術だ。ここでは軽量なXenova/all-MiniLM-L6-v2モデルを使う。
import { pipeline } from '@huggingface/transformers'
const extractor = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2')
const output = await extractor('猫はかわいい動物です', {
pooling: 'mean',
normalize: true,
})
console.log(output.data.length) // 384次元のベクトル
下のサンプルでは2つの文章を入力すると、それぞれをextractor()でベクトル化し、内積(normalize: trueにしているので内積がそのままコサイン類似度になる)で類似度を計算する。片方の文章を全く関係のない内容に書き換えると、バーが縮んで類似度が下がるのが分かるはずだ。
pooling: 'mean'はトークンごとのベクトルを平均して1つの文ベクトルにまとめるオプション。モデルをXenova/all-MiniLM-L6-v2から別の埋め込みモデルに差し替えれば、精度や対応言語の異なる埋め込みを同じコードで試せる。
テキスト分類(ゼロショット分類)
zero-shot-classificationタスクの面白いところは、事前に分類用のラベルを学習させたモデルを用意しなくても、任意のラベルを実行時に指定して分類できる点だ。Xenova/nli-deberta-v3-xsmallのような小型モデルでも、カンマ区切りでラベルを渡すだけで各ラベルへの該当度をスコアとして返してくれる。
import { pipeline } from '@huggingface/transformers'
const classifier = await pipeline(
'zero-shot-classification',
'Xenova/nli-deberta-v3-xsmall'
)
const result = await classifier(
'明日の会議室を予約してください',
['ビジネス', 'スポーツ', '料理']
)
console.log(result.labels, result.scores)
// スコアが高い順に並び替えられたラベルと確信度が返る
下のサンプルでは、テキストとラベル(カンマ区切り)を自由に書き換えてclassifier(text, labels)の結果をバーで表示する。ラベルの並びや語彙を変えると、同じ文章でも一番スコアの高いラベルが入れ替わるのを確認できる。
対応モデル
Transformers.jsは非常に多くのモデルアーキテクチャに対応している。主要なものを挙げると以下の通り。
- BERT系: BERT、DistilBERT、RoBERTa、ALBERT、DeBERTa
- GPT系: GPT-2、GPT-Neo、GPT-J
- T5系: T5、FLAN-T5、mT5
- Vision系: ViT、DeiT、ConvNeXT、ResNet、MobileNet
- Audio系: Whisper、Wav2Vec2、HuBERT
- Multimodal系: CLIP、OWL-ViT、SigLIP
Hugging Face Hubで「transformers.js」タグで検索すると、対応モデルを見つけることができる。
パフォーマンスTips
実運用で使う際のポイントをいくつか。
1. モデルのキャッシュ
一度ダウンロードしたモデルはブラウザにキャッシュされる。初回は少し時間がかかるが、2回目以降は高速に起動する。
2. 適切なモデルサイズ選択
大きなモデルほど精度は上がるが、ダウンロード時間とメモリ消費も増える。用途に応じて適切なサイズを選ぶのが重要だ。個人的にはdistil系のモデルから始めることをおすすめする。
3. Web Worker活用
重い処理はメインスレッドで実行するとUIがフリーズする。Web Workerで別スレッドで実行することで、スムーズなUXを実現できる。
// worker.js
import { pipeline } from '@huggingface/transformers';
let classifier;
self.onmessage = async (e) => {
if (!classifier) {
classifier = await pipeline('sentiment-analysis');
}
const result = await classifier(e.data);
self.postMessage(result);
};
まとめ
Transformers.jsは、JavaScript開発者がAI機能を手軽に実装できる強力なライブラリだ。サーバー不要で動作し、Pythonと同等のAPIで学習コストも低い。
正直なところ、数年前なら「ブラウザでAI」と言われても現実的じゃないと思っていた。でも今は違う。WebGPUの普及と、ライブラリの成熟によって、実用レベルで使える段階に来ている。
コスパ的にも、サーバーコストを削減できるのは大きい。特にプロトタイプや個人開発では、まずTransformers.jsで試してみて、スケールが必要になったらサーバーサイドに移行する、という流れがおすすめだ。
公式のデモサイトやサンプルアプリケーションも充実しているので、まずは触ってみるのがいいと思う。
