RAG のデスクトップ
1. はじめに
古いPCに、FAISS と Dify を使用したRAG環境を構築します。NVIDIA GeForce などのグラフィックボードを搭載していないため、FAISS は最高性能ではありませんが、個人で使用するには十分です。LLM は、クラウドの OpenAI を使用します。
以前に書いた Docker Desktop、Dify のインストールの記事はこちら。
qiita.com
以前に書いた FAISS のインストールの記事はこちら。今回は NVIDIA ドライバをインストールしません。
qiita.com
qiita.com
RAG を実行するためのアプリケーションは他にもありますが、問い合わせ(テキスト)と登録した文書(テキスト)の、より正確なマッチングを行うために、単にコサイン類似度を計算したいので、FAISS を使用します。
文書の埋め込み(embedding)には、クラウドの OpenAI text-embedding-3-large を使用します。NVIDIA GeForce グラフィックボードを搭載した別のPCで、Alibaba qwen3-embedding-8b のようなローカルの embedding を使用することも可能です。
2. Xubuntu インストール
PC電源投入時、
起動メニュー F12キー
BIOS F2キー
デスクトップの使い易さのために Xubuntu を使用しています。日本語入力をセットアップしますが、画面は英語のままにしています。
xubuntu-26.04.1-desktop-amd64.iso
Rufus を使って起動 USB メモリを作成(DVD からだとアクセスが頻発して正常に動作しなかった)
PCの電源を入れて F12キーを押して USB から立ち上げる
デスクトップに表示される Install Xubuntu 26.04.1 LTS アイコンをダブルクリックして、PCへのインストールを開始
Language: English
Keyboard: Japanese
Connect to the internet: Connect to a Wi-Fi network ※ 先にメニューバーから接続しておく
An update is available for the installer: Update now ※ インストーラーを再開
Interactive installation
Xubuntu Desktop
Erase disk and install Xubuntu
Select drive: sda - 500GB SSD-PSTA/D BUFFALO
No encryption
Your name: webmaster
Your computer's name: noble34
Your username: webmaster
Password: **
Confirm password: **
Select your timezone: Asia/Tokyo
インストールが終わったら、USB メモリを外して起動
OS アップデート
sudo apt-get update
sudo apt-get upgrade
sudo apt-get dist-upgrade
再起動
SSH インストール
sudo apt update
sudo apt install openssh-server
外部から SSH で接続
ssh -l webmaster 192.168.1.41
password: **
Xfce メニュー
メニューから Panel Profiles、Xfce 4.16、Apply Configuration ボタン押下
Application -> Settings -> Xfce Screensaver
60 minutes
Application -> Settings -> Language Support
追加のインストールのためにパスワードを入力
Install / Japanese、Password
但し、画面表示は英語のままで使用する
再起動
ログイン後、バー右上、右クリック、Preference -> Input Method -> Add
Japanese -> Mozc
Preference -> General -> Keyboard Shortcuts
<Super>space から <Control>space に変更、Apply ボタン
バー右上、左クリックで Input Mode を Direct input から Hiragana に変更
固定IP
Wifi 接続の場合は、メニューバー右上でマウス右クリック、Edit Connections から設定する
Address: 192.168.1.34
Netmask: 255.255.255.0
Gateway: 192.168.1.1
DNS: 999.999.99.99, 888.888.888.88 ※プロバイダから入手
再起動
よく使うコマンド
pwd
ls -alF
ip addr show
nano .env(矢印キーでカーソル移動、保存Ctrl+S、終了Ctrl+X)
sudo reboot
sudo shutdown -h now
画面キャプチャ PrtSc、範囲指定 Shift+PrtSc、アクティブウィンドウのみ Ctrl+PrtSc ※ Alt が機能しないため Settings - Keyboard - Application Shortcuts で Ctrl に変更
3. Docker Desktop
下記リンクの手順に従って、Ubuntu に Docker Desktop をインストールします。
docs.docker.com
1.Docker の APT レポジトリの設定
# Add Docker's official GPG key
# Add the repository to Apt sources
2.Docker パッケージのインストール
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
3.hello-world イメージの実行
sudo docker run hello-world
docs.docker.com
sudo apt install gnome-terminal
docker-desktop-amd64.deb をダウンロード
sudo apt-get update
sudo apt install ./docker-desktop-amd64.deb
再起動
メニューから Development > Docker Desktop で起動。または systemctl --user start docker-desktop で起動
ユーザー登録は行わず、skip、skip で Docker Containers の画面が表示される
Docker Desktop のコンテナーのメモリ制限を、2GB(デフォルト)から4GBに変更する
<img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="600">
Docker Desktop の自動起動
Docker Engine は、Xubuntu 標準のものと、Dify のためにインストールした Docker Desktop のものがあります。次のコマンドでどちらを使用しているか確認できます。
docker context ls
webmaster@noble01:~$ docker context ls
NAME DESCRIPTION DOCKER ENDPOINT ERROR
default Current DOCKER_HOST based configuration unix:///var/run/docker.sock
desktop-linux * Docker Desktop unix:///home/webmaster/.docker/desktop/docker.sock
Docker Desktop は、ユーザーがログインした後でないと起動できません。GUI で以下を設定します。
Settings、Session and Startup、Application Autostart
Add
Name: Docker Desktop
Comment: Docker Desktop 起動
Command: /opt/docker-desktop/bin/docker-desktop
Docker Desktop を起動すると、Dify のコンテナが自動的に起動します。
4. Dify
docs.dify.ai
mkdir Repos
cd Repos
git clone --branch 1.18.0 https:\/\/github.com/langgenius/dify.git
cd dify/docker
cp .env.example .env
openssl rand -base64 32
表示されたキーを .env の DIFY_AGENT_LOCAL_SANDBOX_AUTH_TOKEN に記入する
nano .env
docker compose up -d
インストールが完了すると、Docker Desktop で実行中になる
<img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="450">
ブラウザで 192.168.1.34 または localhost を表示
管理者アカウントの設定
Email address
Username
Password
ブラウザで 192.168.1.34 または localhost を表示
Email と Password でログイン
LLMモデルの設定
連携 - モデルプロバイダーをインストール
OpenAI
API Key:****
デフォルトのモデルは gpt-5.4-mini
従来との互換性のために gpt-4.1 を選択
HTTPS 化(手順はこちら)
ドメインを取得し、ホスト名を登録する
ルーターの80と443のポートフォワードを、このPCにする
自分のドメインでこのPCの http:\/\/localhost/ が表示されることを確認する
docker/.env の編集。.env に、説明にある赤字の項目を設定する
コマンドの実行(Docker Desktop が立ち上がっていること)
cd dify/docker
docker compose --profile certbot up --force-recreate -d
コンテナが作成された後に、
docker compose exec -it certbot /bin/sh /update-cert.sh
docker/.env の(再)編集。.env に以下を設定する
NGINX_HTTPS_ENABLED=true
コマンドの実行
docker compose --profile certbot up -d --no-deps --force-recreate nginx
外部から your_domain.com で見れることを確認する
SSL 証明書の更新
docker compose exec -it certbot /bin/sh /update-cert.sh
docker compose exec nginx nginx -s reload
<img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="450">
5. FAISS
Anaconda
anaconda.com
ホームページでメールを登録すると、ダウンロードリンクが届きます
Linux、現在 Python 3.14.4
Anaconda3-2026.07-1-Linux-x86_64.sh
をダウンロード。home ディレクトリにファイルを移動
bash ~/Anaconda3-2026.07-1-Linux-x86_64.sh
./anaconda3/bin/conda init
次のターミナルの起動から、conda 環境(base)になります
<img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="600">
FAISS 用に、Python のバージョンを 3.12 にします
conda create -n faiss python=3.12 -y
conda activate faiss
echo 'conda activate faiss' >> ~/.bashrc
<img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="600">
解除は conda deactivate
ベクトルデータベース(faiss)のインストール
facebookresearch/faiss
事前準備
sudo apt install unzip
faiss-cpu インストール
conda install -c pytorch -c conda-forge faiss-cpu=1.15.1
※ バージョンは FAISS のウェブページに表示されているもの
動作確認のために、faiss のページにある DOWNLOAD ZIP からプログラムコード一式をダウンロードします
<img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="700">
unzip faiss-main.zip
cd faiss-main/tutorial/python
(faiss) webmaster@noble34:~/faiss-main/tutorial/python$ ls -1
1-Flat.py
10-FaissCuvsExample.ipynb
11-SVS.py
2-IVFFlat.py
3-IVFPQ.py
4-GPU.py
5-Multiple-GPUs.py
6-HNSW.py
7-PQFastScan.py
8-PQFastScanRefine.py
9-RefineComparison.py
python 1-Flat.py
True
100000
[[ 0 393 363 78]
[ 1 555 277 364]
[ 2 304 101 13]
[ 3 173 18 182]
[ 4 288 370 531]]
[[7.6293945e-06 7.1751785e+00 7.2076302e+00 7.2511673e+00]
[0.0000000e+00 6.3235664e+00 6.6845779e+00 6.7999382e+00]
[3.8146973e-06 5.7964020e+00 6.3917236e+00 7.2815170e+00]
[3.8146973e-06 7.2779007e+00 7.5279808e+00 7.6628418e+00]
[0.0000000e+00 6.7638016e+00 7.2951088e+00 7.3688126e+00]]
[[ 381 207 210 477]
[ 526 911 142 72]
[ 838 527 1290 425]
[ 196 184 164 359]
[ 526 377 120 425]]
[[ 9900 10500 9309 9831]
[11055 10895 10812 11321]
[11353 11103 10164 9787]
[10571 10664 10632 9638]
[ 9628 9554 10036 9582]]
python 2-IVFFlat.py
[[ 9900 9309 9810 10048]
[11055 10895 10812 11321]
[11353 10164 9787 10719]
[10571 10664 10632 10203]
[ 9628 9554 9582 10304]]
[[ 9900 10500 9309 9831]
[11055 10895 10812 11321]
[11353 11103 10164 9787]
[10571 10664 10632 9638]
[ 9628 9554 10036 9582]]
python 3-IVFPQ.py
[[ 0 78 424 608]
[ 1 555 1063 380]
[ 2 179 304 33]
[ 3 265 527 139]
[ 4 288 531 827]]
[[1.5948839 6.2905183 6.3059173 6.5697308]
[1.282814 5.9320083 5.9512424 6.5773916]
[1.698801 6.1244454 6.2004113 6.401427 ]
[1.82021 6.721145 6.8056335 6.995647 ]
[1.4857421 5.8346977 6.303232 6.400938 ]]
[[ 8746 9380 10914 9842]
[10913 11373 9014 10507]
[10719 11291 10600 11353]
[11578 9671 10709 10664]
[ 9229 9878 9905 9459]]
PostgreSQL インストール
sudo apt update
sudo apt install postgresql postgresql-contrib
psql --version
sudo -i -u postgres
psql
postgres=#
CREATE USER admin WITH PASSWORD '<font color="green">mypassword</font>' SUPERUSER;
CREATE USER webmaster WITH PASSWORD '<font color="green">mypassword</font>';
CREATE DATABASE webmaster OWNER webmaster;
\q
で抜ける
exit
で postgres ユーザーを抜ける
psql -U webmaster -d webmaster -h localhost
CREATE TABLE knowledge_documents (
id UUID PRIMARY KEY,
knowledge_id TEXT NOT NULL,
content TEXT NOT NULL,
title TEXT NOT NULL,
metadata JSONB,
created_at TIMESTAMP DEFAULT now()
);
\q
で抜ける
\d knowledge_documents (テーブル一覧)
\l (データベース一覧)
\c (現在接続しているデータベース)
SELECT * FROM knowledge_documents;
TRUNCATE TABLE knowledge_documents;
faiss_service の作成
次のように作成します。
|項目|ツール|
|---|---|
|文書データベース|PostgreSQL|
|ベクトルデータベース・検索|faiss-cpu|
|埋め込み(Embeddings)|OpenAI API(text-embedding-3-small)<br>ナレッジIDを指定して切り替え可能|
|ウェブサーバー|Python Flask|
# 一旦、通常の Ubuntu 環境に戻す
conda deactivate
sudo apt update
sudo apt install -y build-essential libpq-dev python3-dev
# conda 環境で実行
conda activate faiss
pip install flask psycopg2 openai flasgger ollama
mkdir faiss_service
cd faiss_service
nano faiss_service.py
[faiss_service.py を他のPCからコピーして入手]
LangChain を使用したチャンク分割(upload_files_chunk)は行わないこととし、upload_files_chunk の部分を削除します。また、LangChain の API_KEY も設定しません。
faiss_gpu から faiss_cpu への変更
# 変更前
res = faiss.StandardGpuResources() # use a single GPU
gpu_index = faiss.index_cpu_to_gpu(res, 0, index)
index = faiss.index_gpu_to_cpu(gpu_indexes[knowledge_id])
# 変更後
#res = faiss.StandardGpuResources() # コメントアウトまたは削除
gpu_index = index # 3か所
index = gpu_indexes[knowledge_id] # 1か所
export PSQL_DB_PASSWORD="..."
export OPENAI_API_KEY="..."
python faiss_service.py
<img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="450">
ウェブページを表示
http:\/\/192.168.1.34:8000/apidocs/
<img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="650">
コンテンツエディター
登録済みのコンテンツ(テキスト)を確認・編集するためのウェブページを作成します。[保存して更新]ボタンを押下すると、faiss_service の delete と add を呼び出します(Faiss を使用しているため、登録済みの内容は変更ではなく、再登録します)。
pip install requests
mkdir content_editor
cd content_editor
nano app.py
[app.py を他のPCからコピーして入手]
mkdir templates
nano templates/index.html
nano templates/edit.html
[index.html と edit.html を他のPCからコピーして入手]
[ 実行 ]
export PSQL_DB_PASSWORD="**"
python app.py
[ 表示 ]
localhost
または、
192.168.1.34
(他のPCからIPアドレスを指定)
<img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="450">
<img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="650">
<img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="650">
Ubuntu 起動時に Python プログラムを実行する
参考ページ1:
udemy.benesse.co.jp
cd ~
nano py_app_service.sh
export PSQL_DB_PASSWORD="..."
export OPENAI_API_KEY="..."
/home/webmaster/anaconda3/envs/faiss/bin/python /home/webmaster/faiss_service/faiss_service.py &
/home/webmaster/anaconda3/envs/faiss/bin/python /home/webmaster/content_editor/app.py &
wait
chmod 744 py_app_service.sh
bash py_app_service.sh
参考ページ2:
note.com
cd /etc/systemd/system
sudo nano run_python.service
[Unit]
Description=python run
After=network.target
[Service]
Type=simple
User=webmaster
WorkingDirectory=/home/webmaster/faiss_service
ExecStart=/bin/bash /home/webmaster/py_app_service.sh
Restart=on-failure
KillMode=control-group
[Install]
WantedBy=multi-user.target
※ データファイルを読み込むため、ワーキングディレクトリを faiss_service に設定する
sudo systemctl daemon-reload
sudo systemctl enable run_python.service
sudo systemctl start run_python.service
sudo systemctl status run_python.service
sudo systemctl stop run_python.service
多数のファイルを一度に登録する
faiss_service の画面では、最大20個のファイルを手動で指定し、登録できるようにしています。実際は、別に Python プログラムを作成し、テキストファイル(input.txt)に記述したファイル一覧をもとに、一括登録できるようにしています。input.txt の1行目には、すべてのファイルに共通するナレッジIDを記入し、2行目以降には登録するファイル名を記述します。プログラムは faiss_service.py の upload_files をもとに作成しいますが、ここでは内容を割愛します。
ファイル一覧の作成:
ls *.txt > input.txt
nano input.txt
1行目にナレッジIDを記入
2行目以降はファイル名
python upload_files.py
Dify と FAISS を接続
Dify で外部ナレッジベースの設定を行って、faiss_service に接続します。
ナレッジ
「外部ナレッジベースと連携 →」
<img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="450">
外部ナレッジベース連携APIを追加
API Key は未使用なので ABCdef など
<img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="450"><br>
<img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="450">
外部ナレッジベース名: ローカルRAG
外部ナレッジベースID: AAA-BBB-CCC
「連携 →」ボタン押下
事前準備(以前からの修正)
従来は Dify 1.13.0 を使用していましたが、1.18.0 に変更したところ、以下の対応が必要でした。
SSRF プロキシ対応
cd dify/docker
nano .env
変更前:
SSRF_PROXY_ALLOW_PRIVATE_IPS=
変更後:
SSRF_PROXY_ALLOW_PRIVATE_IPS=192.168.1.34
設定の反映
docker compose up -d --force-recreate ssrf_proxy
確認
docker exec docker-ssrf_proxy-1 \
cat /etc/squid/dify_allow_private.conf
faiss_service.py、retrieval のレスポンスにおける score の型変換
変更前:
records.append({
"score": score
変更後:
records.append({
"score": float(score)
6. その他
□ ファイアウォール
sudo ufw enable
sudo ufw allow 'Nginx Full'
sudo ufw allow OpenSSH
sudo ufw reload
sudo ufw status
sudo ufw status numbered
sudo ufw delete 3
□ ブルートフォース攻撃対策
sudo apt update
sudo apt install fail2ban
sudo nano /etc/fail2ban/jail.d/sshd.local
[sshd]
enabled = true
backend = systemd
port = ssh
filter = sshd
maxretry = 5
findtime = 600
bantime = 86400
10分間に5回以上SSH認証に失敗したIPアドレスを、24時間遮断する設定になる
sudo systemctl enable --now fail2ban
sudo systemctl restart fail2ban
sudo systemctl status fail2ban
以上、
英語論文や技術PDFのレイアウト崩れを防いで翻訳する方法:2段組・表・数式の破損パターンと対策
英語の学術論文や技術仕様書のPDFを読む際、段落の途切れや表の崩壊、数式の文字化けに悩まされる問題を解決します。
PDF内部のテキスト配置構造を紐解きながら、なぜ翻訳時にレイアウト破損が起こるのか、その4大原因を検証します。
論文の2段組や表・数式を適切に扱えるツールの特徴と、翻訳後に確認すべき重要チェックポイントがわかります。
Wordのファイルには、どの単語が段落を構成し、どの単語が表に属しているかの構造情報が記録されています。しかし、多くのPDFにはそれがありません。PDFが持っているのは文字コードと、その文字を紙面(画面)上に描画する座標情報だけです。段落や表、文といった構造は、読む人間の目が補完して認識しています。
一部のPDFにはアクセシビリティタグが付与されていますが、学術論文を含め付いていないものも数多く存在します。そのため、2段組レイアウト、複数列にまたがる見出し、次ページへと続く文章といった構造は、翻訳を行う前に正しく組み直す必要があります。そのうえで、翻訳によって長さが変わった訳文を元のレイアウトに収め直さなければなりません。書式が崩れるのは、まさにこの工程です。
手元のファイルに応じた基本的な選択肢は以下のとおりです:
- 元の .docx や .pptx がある場合:PDFではなく、その元ファイルを翻訳するのが確実です。
- 表が少なく文字中心のPDF(10 MB未満):Google 翻訳のドキュメント機能を手軽に試せます。
- 表・数式・2段組を含む論文や技術レポート:レイアウトを再構築するタイプの翻訳ツールを利用し、後述する4つのチェックポイントを確認してください。
- スキャンデータ(テキスト選択不可):事前にOCR処理が必要です。DeepLはスキャンデータにも対応していますが、Google 翻訳ではスキャンページは未翻訳のまま残ります。
1. 翻訳ツールはPDFの内部をどう見ているのか
PDFからテキストを取り出す際、内部で何が起きているのかを可視化するため、arXivに公開されているAI言語モデルの論文2本(LLaMA と Mistral 7B)を例に取ります。一般的なオープンソースPDFツールである MuPDF の mutool でテキストを抽出した結果を見てみましょう。レイアウトを考慮しないツールが翻訳処理に渡しているのは、おおよそ次のようなデータです。
1.1 表は単なる数字の列に分解される
LLaMA 論文の表3(Table 3)では、10個のモデルを8つのベンチマークテストで比較しています。

これをテキスト抽出すると102行のデータになります。ヘッダーの後に数値が1行ずつ並びます。
BoolQ
PIQA
SIQA HellaSwag WinoGrande ARC-e
ARC-c
OBQA
GPT-3
175B
60.5
81.0
-
78.9
70.2
68.8
51.4
57.6
Gopher
どの数値がどのテストに対応しているのかを示す情報は完全に失われています。これをそのまま翻訳ボックスに貼り付けても、表としての構造は戻ってきません。
1.2 1つの文の中に表データが丸ごと混入する
LLaMA 論文の3ページ目末尾の文は、"we need to" で途切れています。

その続きは、4ページ目左欄の表3の下に現れます。

抽出されたテキストを見ると、脚注や改ページ、表3の102行、さらに表題が、1つの文の真ん中に挟み込まれています。
To fully benefit from this optimization, we need to
2https://github.com/facebookresearch/xformers
BoolQ
PIQA
…
Table 3: Zero-shot performance on Common Sense Reasoning tasks.
reduce the memory usage of the model by using
順序通りに機械的に処理するツールでは、文の途切れと表の混入を見分けることができず、不自然に分割された訳文が生成されてしまいます。
1.3 添字や分数が別の文字・数値に化ける
Mistral 論文では、変数 h に添字 i が付けられています(hᵢ)。

テキスト抽出を行うと添字の位置情報が失われ、単なる hi という文字列になります。
former to attend information beyond the window size W. The hidden
state in position i of the layer k, hi, attends to all hidden states from
LLaMA 論文でも、4d の3分の2(⅔·4d)という重ね組みの分数が次のように抽出されます。

improve the performance. We use a dimension of
2
34d instead of 4d as in PaLM.
位置情報が脱落した結果、「4dの3分の2」が「34d」という全く異なる数値になってしまいます。
1.4 単語が行末ハイフンで分断される
2段組の論文では行末のハイフネーションが多用されます。

We introduce LLaMA, a collection of founda-
tion language models ranging from 7B to 65B
…
(175B) on most benchmarks, and LLaMA-
65B is competitive with the best models,
founda-tion はハイフンを除去して繋ぐ必要がありますが、モデル名である LLaMA-65B のハイフンは保持しなければなりません。
2. PDF翻訳ツールの選択肢と特徴
| 選択肢 | 長所 | 限界 |
| --- | --- | --- |
| 翻訳ボックスへのコピー&ペースト | 無料ですぐに使える | 表、数式、レイアウトが失われ、文が途中で切れることが多い |
| Google 翻訳(ドキュメント) | 無料。.docx、.pdf、.pptx、.xlsx に対応 | 10 MB・300ページまで。画像内文字やスキャンページは翻訳されない。モバイル非対応 |
| DeepL(ファイル翻訳) | Web/デスクトップ/API対応。スキャンデータ対応。Proプラン等で.docx変換可能 | アカウントが必要。プランごとに翻訳ファイル数制限あり。CAD由来PDFなどは非対応 |
| Word等に変換してから翻訳 | 翻訳前に元ファイルを修正できる | 変換時点でレイアウト崩れが発生した場合、誤りがそのまま残る |
| レイアウト再構築型の翻訳ツール | 表、数式、分割された文を構造として認識 | 元ファイルと同一の配置にはならない。訳文の長さに応じて改行やフォントサイズが変化する |
私たちが開発している Equalang のドキュメント翻訳は、このレイアウト再構築アプローチを採用しています。ページの切れ目で分断された文章を翻訳前に結合し、表構造を1列に潰さずに維持したまま再構築します。また、数式を文字化けとして破棄せず、数式最適化のオプションも提供しています(対応言語:日本語、英語、中国語、韓国語、スペイン語、フランス語など)。
ただし、言語によって翻訳後の文字量が変わるため、元ファイルと完全に一致するわけではありません。文字が溢れたり改行位置が変わる箇所は、目視での確認が必要です。
3. PDF翻訳後に必ず確認すべき4つのポイント
1. 表の整合性:列ヘッダーと数値の対応がずれていないか確認します。
2. 改ページと表前後のテキスト:ページの最終行や表の直後に、文頭・文末が途切れた不自然な文がないか確認します。
3. 数式と記号:文中のインライン変数や分数が、一般的な英単語や誤った数字に化けていないか点検します。
4. ページ数とハイパーリンク:訳文の膨張でページが予期せず増えていないか、目次や参照リンクが正常に飛べるかを確認します。
この記事はドキュメント翻訳ツールを開発している Equalang チームが執筆しました。
参考資料
- Touvron et al., "LLaMA: Open and Efficient Foundation Language Models", arXiv:2302.13971v1, CC BY 4.0.
- Jiang et al., "Mistral 7B", arXiv:2310.06825v1, CC BY 4.0.
- Google 翻訳 ヘルプ, Translate documents & websites, 2026年10月7日確認.
- DeepL ヘルプセンター, Translate PDF files, 2026年10月7日確認.
- 実測方法: テキストは2026年10月7日に MuPDF 1.25.6 で抽出(コマンド mutool draw -q -F txt -o out.txt in.pdf)。図は論文ページの切り抜きで、強調は筆者が入れたものです。
Hyperagents
Self-improving AI systems aim to reduce reliance on human engineering by learning to improve their own learning and problem-solving processes. Existing approaches to self-improvement rely on fixed, handcrafted meta-level mechanisms, fundamentally limiting how fast such systems can improve. The Darwin G\"odel Machine (DGM) demonstrates open-ended self-improvement in coding by repeatedly generating and evaluating self-modified variants. Because both evaluation and self-modification are coding tasks, gains in coding ability can translate into gains in self-improvement ability. However, this alignment does not generally hold beyond coding domains. We introduce \textbf{hyperagents}, self-referential agents that integrate a task agent (which solves the target task) and a meta agent (which modifies itself and the task agent) into a single editable program. Crucially, the meta-level modification procedure is itself editable, enabling metacognitive self-modification, improving not only the task-solving behavior, but also the mechanism that generates future improvements. We instantiate this framework by extending DGM to create DGM-Hyperagents (DGM-H), eliminating the assumption of domain-specific alignment between task performance and self-modification skill to potentially support self-accelerating progress on any computable task. Across diverse domains, the DGM-H improves performance over time and outperforms baselines without self-improvement or open-ended exploration, as well as prior self-improving systems. Furthermore, the DGM-H improves the process by which it generates new agents (e.g., persistent memory, performance tracking), and these meta-level improvements transfer across domains and accumulate across runs. DGM-Hyperagents offer a glimpse of open-ended AI systems that do not merely search for better solutions, but continually improve their search for how to improve.
Comments: Code at facebookresearch/Hyperagents
OmniFaceRig: Fully Automatic Inner-Mouth-Aware Face Rigging Across Diverse 3D Character Topologies
Facial rigging--creating Facial Action Coding System (FACS) blendshapes and inner-mouth geometry (teeth, gums, and tongue)--remains a major bottleneck in 3D character production. We present OmniFaceRig, a fully automatic end-to-end pipeline that converts a static surface-only 3D character mesh, with no pre-modeled oral cavity, into an inner-mouth-aware FACS rig with up to 155 blendshapes, procedurally fitted teeth, gums, and tongue, and re-packed UV/texture. It supports humans, humanoids, and long- and short-muzzled animals with no manual landmarks, user-provided templates, or per-asset setup. OmniFaceRig combines a hybrid vision-language and computer vision riggability checker, a four-model face segmentation ensemble, keypoint-driven template registration, procedural inner-mouth construction, and collision-aware blendshape transfer. For non-human characters, it selects topology-specific templates with a nose-landmark-free design and uses as-rigid-as-possible deformation with signed-distance-field constraints to reduce teeth-face intersections. We also introduce Omni-Bench, an open-source benchmark of more than 1,000 biped 3D characters rigged with FACS blendshapes and inner-mouth geometry, spanning humans, humanoids, cats, dogs, and other animals. Experiments show high rigging success, nearly complete face detection recall, low inner-mouth penetration, and 20-30 s end-to-end latency per asset on a single A100 GPU.
Comments: 36 pages, 19 figures, 9 tables. Accepted to ACM Transactions on Graphics (SIGGRAPH Asia 2026). v2: revised text and appendix, updated Omni-Bench description for the public dataset release, corrected references. Project page: omnifacerig.github.io ; Dataset: facebookresearch/omnifacerig
Selecting or Solving? What Best-of-N Verification Delivers in Video Reasoning
Answering a complex question about a long video is a grounding problem: the answer turns on a few seconds of evidence, and vision-language models remain well below human accuracy at finding them. The standard way to spend extra test-time compute on this kind of video reasoning is best-of-N selection: sample several chain-of-thought answers from a fixed model, then let a second model re-watch the video and pick one. Such pipelines are reported by a single headline number, their margin over a majority vote. That number conflates two effects with opposite deployment consequences: the benefit the second model adds by selecting among candidates, and the benefit it would have supplied by solving the question itself. We separate them, measuring the Selection Increment (SI) -- selection accuracy minus the same verifier's accuracy with the candidates withheld -- alongside the margin over self-consistency, across five long-video benchmarks. The Selection Increment is largest for the weakest verifiers: a verifier that solves poorly on its own leaves the candidates the most room to help. Beating the majority vote follows the opposite profile: where the vote already sits near its ceiling no verifier we test improves on it; below that ceiling only the strongest do. On Video-Holmes, the two come apart on a single pool of candidates -- a weak verifier gains +19.3 points from the candidates yet lands 7.1 points below the vote, while the frontier verifier gains the least and beats the vote. The weakest verifier also shows a failure mode: on EgoSchema it picks by where an option sits in the list rather than by what the video shows. Read as a merit score, SI puts a verifier that fails to beat a majority vote at the top of its ranking; read as an audit, it says which of the two effects a headline number delivers. Code is available at facebookresearch/best-n-selection-video-reasoning.
Comments: Accepted at NeurIPS 2026 VLM4WRD workshop
GSLM2: Multi-Stream Speech Representation Learning and Generative Spoken Language Modeling
Generative spoken language models (SLMs) offer a route to learning linguistic structure purely from speech, yet they lag far behind text-based models in both capability and data scaling efficiency. We identify two bottlenecks underlying this gap: the limited linguistic quality of existing speech units and the reliance on a single stream of discrete units to represent speech. Multiple codebooks are widely used to encode acoustic features but rarely to represent speech semantics. We present GSLM2, which learns and models complementary properties of speech at multiple levels of abstraction. Its encoder, SpidR 2.0, uses self-supervised learning with differentiable prediction heads to induce high-quality discrete units at multiple levels. A multi-stream SLM then jointly models these units using a shared temporal backbone, stream-specific predictors, and an autoregressive head that captures cross-stream dependencies. Across training data sizes and model scales, up to 6M hours and 6.5B parameters, GSLM2 consistently improves linguistic competence while scaling more efficiently with data. As a result, it substantially narrows the gap between spoken and text-based LMs; across read and conversational speech domains, we shrink the gap by about two orders of magnitude on sWuggy, sBLIMP, and tSC, while also outperforming competitive speech-text systems on all three tasks. We open-source the training code and model checkpoints at facebookresearch/gslm2.
Comments: Equal contribution by Yosuke Higuchi and Tom Fizycki. Core contribution by Mahi Luthra, Charles-\'Eric Saint-James and Azeez Syed
Inflearnが自動で字幕を生成するまで(AI/インフラ編)
!
この記事は2023年10月31日に執筆されたものです。
こんにちは。InflabのDevOpsエンジニア、SunBです。
2023年9月、Inflearnに字幕とスクリプトの機能が追加されました。皆さん、活用されていますか? 今回追加された字幕機能は、動画の音声データをもとに自動で字幕を生成する部分と、生成された字幕を受講画面に表示する部分の、大きく2つに分けられます。
今日は、このうち私が実装を担当した字幕生成について、どのような技術をもとに、どのような過程を経て実装したのかをお話しします。
2日で字幕機能を作ってデモする
まず、「DevOpsエンジニアが字幕機能を実装したの?」と思われる方もいらっしゃると思うので、今回の字幕機能の実装プロジェクトがどのように始まったのかをご紹介します。
Inflabでは今年から、Infthonという名前で社内ハッカソンを開催しています。応募者をランダムに4人1組のチームに分け、約2日間でアイデアの議論とMVPの実装を行ったあとに発表する、という形式です。
ところが偶然(?)、Inflearnの講座プレイヤーやVODインフラを多く手がけていたFE開発者のPapicoと私が同じチームになり、自然と講座の再生に関するアイデアを議論することになりました。そして、第1回Infthonのテーマだった「チームの生産性向上、またはAIを活用したサービス改善」に最も合うと考えた講座のAI字幕機能をアイデアとして選びました。
まず、AIベースの字幕生成機能を実装するにあたって、最低限の条件として次のことを考えました。
字幕生成がオフラインで動作すること(データの外部送信を防ぐ)
字幕生成にコンピューティングリソース以外の追加費用がかからないこと(オープンソースモデルを自前で実行)
字幕生成にかかる時間が動画の長さを超えないこと(ライブデモができるくらい速いこと)
これらの条件を満たす技術を探してみたところ、OpenAIのWhisperというモデルが目に留まりました。Whisper以外に検討した技術は以下のとおりです。
KoSpeech: Archived
OpenSpeech + KsponSpeech: 自分たちで学習させてモデルを作るには、技術への理解度もまだ低く、時間もかなりかかると予想された
KakaoのPORORO: Archived
MetaのSeamlessM4T: テスト用の講座を使ったPoCの過程で、SeamlessM4T largeモデルはWhisper large-v2モデルに比べて精度が劣ることを確認
NaverのCLOVA SpeechなどのAPIベースのサービス: データの外部送信とAPI料金が発生
Infthon以前にも、MacWhisperなどのツールで、OpenAIのSTTモデルであるWhisperの存在とその精度の高さは知っていましたが、深く調べたことはありませんでした。実装期間が2日と短かったため、仕組みを深く理解することよりも、素早く適用してデモできるかどうかを重視して作業を進めました。その結果、すべての処理を私のMac上でオフラインで動かす構成になりました。その際、Pythonで実装されたOpenAIのWhisperは遅すぎたため、代わりにC++に移植されたwhisper.cppを使いました。
こうして、次の流れを短期間で実装できました。
動画をアップロードする
ffmpegで16-bit WAVの音声データを抽出する
whisper.cpp + large-v2モデルで字幕を書き起こし、srtファイルとして保存する
受講画面でこのsrtファイルを再生する
さらに、FE開発者のPapicoの活躍で、スクリプトの表示と再生位置の移動、字幕の修正依頼と修正依頼の管理機能までデモでき、第1回Infthonで1位という栄誉を手にしました。
こうして楽しい経験として幕を閉じたと思っていたのですが……
正式プロジェクトとして採用
ある意味当然のことながら、字幕機能はすぐに正式プロジェクトとして採用され、新たなスタートを切りました。
Infthonですでにデモまで終えていたので大きな心配はありませんでしたが、引っかかる点が3つありました。
Shaka Playerでm3u8のHLSプレイリストとsrt字幕ファイルを同時に表示すると、字幕の同期がずれる問題
AWSのインフラでWhisperをまだ動かしたことがなかった点
韓国語字幕の1行あたりの長さと改行位置が適切でなく、読みにくい問題
1つ目は、FE開発者のPapicoが字幕の表示処理をShaka Playerの機能を使わずにReactで新たに実装し、きれいに解決してくれました。一方、2つ目と3つ目は、そのまま現実の問題として降りかかってきます。
インフラ上でWhisperを動かす
Infthonのときとは違い、今回は実際のユーザーにサービスを提供するため、まずは私たちのインフラ上で機能を動かす必要がありました。
エンコーディングインフラの改善記録
字幕生成インフラについてお話しする前に、まず動画エンコーディングインフラを改善した過程をご紹介します。
私たちは2022年10月まで、動画のエンコーディングにAWS MediaConvertを使っていましたが、コスト削減とエンコーディングオプションのカスタマイズのために、EC2 c6i.xlarge Spot InstanceベースのAWS Batch構成に移行しました。MediaConvertのReserved Queueなど、さまざまな代替案も試しましたが、予約したエンコーディングの開始が遅すぎたり、4Kなど一部のオプションが使えないといった制約があったりして、要件を満たすのは難しいと判断し、自分たちで構成する方向を選びました。
結果として、インフラ構成の変更は効果がありました。長さ28分の1080p動画を540p、720p、1080pにエンコードする場合、AWS Batchを使ったときとMediaConvertを使ったときにかかる時間と費用は、以下のとおりでした。
AWS Batch (ECS EC2 c6i.xlarge Spot)
MediaConvert (On-Demand Pro)
差
時間
約10分
約7分
約3分 (x0.7)
費用
約$0.021
約$1.895 (SD x 1, HD x 2)
約$1.874 (x90.2)
動画の長さと比べれば、エンコーディング時間の差はわずかですが、費用はなんと90倍以上の差があることを確認しました。
AWS Batch構成で、EC2インスタンスタイプごとの費用と性能を分析した結果は以下のとおりです。(長さ28分の1080p動画を540p、720p、1080pにエンコードする場合、Spot Instance未適用)
インスタンスタイプ
オンデマンドの1時間あたりの費用 (A)
エンコーディングの実行時間 (B)
実際の費用 (A x B)
c6i.xlarge
$0.192
10分
$0.032
c6g.xlarge
$0.154
12分47秒
$0.033
c6i.2xlarge
$0.384
5分57秒
$0.038
c6i.4xlarge
$0.768
4分23秒
$0.056
g5g.xlarge
$0.5166
5分1秒
$0.043
g5.xlarge
$1.237
3分15秒
$0.067
エンコーディングインフラと同じ構成でwhisper.cppを試す
上記の改善したエンコーディングインフラをもとに、字幕インフラも同じ構造で構成してみました。AWS Batch上のc6i.xlargeインスタンスで28分の動画に対してwhisper.cppを実行したところ、結果はなんと69分3秒と、予想よりもはるかに遅いものでした。
Infthonのデモ用にMac Studio(M1 Ultra)で同じ動画をwhisper.cppで処理したときは、3分30秒でした。これを見て、すぐにGPUインスタンスのPoCに取りかかりました。
GPUインスタンスのPoC
最初は、g5インスタンスより安いARMベースのg5g.xlargeインスタンスを使ってみようとしました。ところが、NVIDIAドライバーやCUDAのバージョンをいくら変えても、PyTorchからCUDAを認識できませんでした。CUDA 11のPython cuDNNライブラリはARMアーキテクチャをサポートしておらず、PyTorchの正式版はCUDA 12をサポートしていなかったため、PyTorch Nightly + CUDA 12 cuDNNの構成を試しましたが、torch.cuda.is_available() が False を返す状態が続きました。そんな中、AWS BatchではまだARMアーキテクチャベースのGPUインスタンスをサポートしていないというドキュメントを見つけ、g5gインスタンスの利用はひとまず諦めました。
その後、g5.xlargeインスタンスでOpenAIのPythonベースのWhisperを実行してみたところ、7分17秒かかりました。動画の長さに比べれば許容範囲でしたが、Mac Studioでwhisper.cppを使ったときは3分30秒だったことを考えると、ほかに方法はないかと考えるようになりました。そして、SeamlessM4Tについて調べていたとき、偶然Hacker NewsでWhisperXに言及しているコメントを見かけました。
WhisperXへの移行
WhisperXを使って、g5.xlargeインスタンスで28分の動画の字幕生成を試してみたところ、59秒で完了し、最も速い結果となりました。その出力結果も、Whisperやwhisper.cppと比べて精度が劣るということはなく、それぞれ一長一短がありました。
以下は、出力結果を比較した当時に書いたメモの一部です。
Whisper、WhisperXはg5.xlargeで、whisper.cppはMac Studioで抽出したバージョン
3つともかなり違いがあるが、どれか1つが最も優れているというわけではなく、それぞれにうまく書き起こせている部分がある。
WhisperXが正確に抽出した部分
뽑았는데 (Whisper: 꼽았는데)
등허리 (Whisper: 등어리)
복부 (Whisper: 복구)
whisper.cppが正確に抽出した部分
Eye Reflect (WhisperX: I Reflect)
Whisperが正確に抽出した部分
Z-Remesh (WhisperX: gremesher)
아이리플렉트 (WhisperX: I Reflect)
WhisperXはほかの2つよりはるかに速く実行でき、音節単位でalignするので行の再構成に有利であり、字幕の修正依頼機能の有効性も比較的高くなると推定されることを考えると、WhisperXを使うのが最も良いと思われる。
ただし、ときどき複数の文を早口で話す部分で抜け落ちる文があるが、精度が低いと判断して意図的に除外しているように見える。
まとめ
最初に試したwhisper.cpp + c6i.xlargeを基準に、試した組み合わせとの差をまとめると次のとおりです。(large-v2モデルを使って28分の音声データを書き起こした場合)
ツール
マシン
実行時間
差(速度)
whisper.cpp
c6i.xlarge
69分3秒
- (x1)
Whisper
c6i.xlarge
時間がかかりすぎて計測を中断
-
WhisperX
c6i.xlarge
実行中にエラーが発生
-
whisper.cpp
Mac Studio
3分30秒
65分33秒 (x19.7)
Whisper
Mac Studio
時間がかかりすぎて計測を中断
-
WhisperX
Mac Studio
15分26秒
53分37秒 (x4.5)
whisper.cpp(cuBLASビルド)
g5.xlarge
17分25秒
51分38秒 (x4)
Whisper
g5.xlarge
7分17秒
61分46秒 (x9.5)
WhisperX
g5.xlarge
59秒
68分4秒 (x70.2)
最終的に、WhisperX + g5.xlargeの組み合わせを選びました。
こうして最初の絶望を乗り越え、速度を70倍以上改善し、インフラ上で字幕生成機能を正常に動かせるようになりました。その過程でGPUインスタンスや動画エンコーディングに関する分析も行い、エンコーディング関連のプロセスも改善できました。
(試行錯誤の跡)
字幕の長さと読みやすさの改善
字幕をどう生成するかという課題は、音声データからテキストを抽出するだけでは終わりませんでした。
whisper.cpp、Whisper、WhisperXのいずれにも、--max_line_width のような1行の長さを制限するオプションがあったのですが、問題はこのオプションが動作しないことでした。(……)おそらく韓国語だから動作しないのだろうと推測しています。
そのため、モデルが出力した字幕データは行ごとに長さがバラバラで、文の終わりで改行されることもほとんどなく、読みやすさは最悪でした。
これを改善するために、ピリオド/疑問符/感嘆符があれば改行する案、一定の文字数以上なら単純に空白を基準に半分に分割する案、形態素解析によって行を再構成する案など、さまざまな方法を模索しました。
そんな中、WhisperXに移行して音節単位で時間を追跡できるようになったことで、いっそすべての行を一から作り直そうと考えました。そこで以下の基準を定め、WhisperXの実行から行の構成までを一度に行うPythonスクリプトを実装しました。
WhisperXが時間の追跡に失敗した音節の時間は、時間の追跡に成功した最も近い前後の音節の時間、または文の開始・終了時間から線形補間する。(wav2vecの韓国語モデルベースだったため、ハングル以外は音節の時間を追跡できないという問題がありました。)
直前の単語までの行の長さが0.5秒未満であれば、ほかのどの条件を満たしていても改行しない。
直前の単語までの行の長さが10秒を超えたら、現在の単語から新しい行にする。
現在の単語を加えると行が10文字を超え、かつ形態素解析の結果で文の数が変わる場合は、現在の単語から新しい行にする。
現在の単語を加えると行が50文字を超える場合は、現在の単語から新しい行にする。
文の開始が直前の文の終わりから0.5秒以内の場合は、文の開始時間として直前の文の終了時間を代わりに使う。
実は、このうち形態素解析で文の数を計算し、それをもとに改行する基準は最後に作ったものです。この基準を決めるまでは、WhisperXをCLIで実行したあと、JSONで保存されたデータを読み込んで行を構成する処理をすべてGoで実装していました。しかし、形態素解析と文の数の計算にKiwiを使うことになったため、WhisperXをPython内で直接実行するようにし、行の構成もPythonで実装し直しました。そしてGoは、このPythonスクリプトを実行し、最終的に構成された字幕データをストレージに保存するという、AWS Batch内の1つのジョブのライフサイクル管理だけを担う構造にしました。
こうして、現在提供している字幕のように、読みやすさが大きく改善された字幕データを生成できるようになりました。
GPUインスタンス不足の問題を回避する
問題はすべて解決したと思い、これまでにアップロードされた講座を対象に、実際に字幕を一括生成しようとしました。ところが、AWS Batchにジョブを投入していくら待っても、EC2インスタンスが起動しませんでした。Spot Requestを確認してみると、ソウルリージョンにg5.xlargeインスタンスのSpot Capacityがなく、起動できていなかったのです。
Spot Instanceとは?
Spot Instanceは、AWSで使われていないコンピューティングリソースを最大90%割引した価格で提供する機能です。実行中のSpot Instanceがときどき中断されることもありますが、AWS Batchなどを使ってワークフローの耐障害性を確保していれば、Spot Instanceを適用するだけで60%以上のコスト削減効果を得られます。
実際に、動画エンコーディングインフラにSpot Instanceを適用することで平均70%のコストを削減できていたので、そもそも費用のかさむGPUインスタンスを使ううえで、Spot Instanceの適用は必須でした。
Spot Capacityを求めて
GPUインスタンスが足りないという話はよく耳にしていましたが、実際に経験したのは初めてでした。3日待っても起動しなかったので、別の方法を探し始めました。
最初に、Spot Placement Scoreという機能を使ってみました。米国のバージニア、オハイオ、オレゴンリージョンはg5.xlargeインスタンスが最も安く、Placement Scoreも高く出ていたので、まずはバージニアリージョンで試してみました。
初めて使うリージョンで何もなかったため、VPC、Subnet、EIP、NAT Gatewayをはじめ、AWS Batch関連の各種リソースをすべて新しく作成しました。ところが実行してみると、同じようにSpot Capacityがないというエラーが発生しました。しまった!と思い、すぐ隣のオハイオリージョンにも同じ構成を作ってみましたが、やはりSpot Capacityがないというエラーが発生しました。(……)
Placement Scoreは当てにならないなと思って調べてみたところ、スポットインスタンスアドバイザーというものを見つけました。g5.xlargeスポットインスタンスの中断頻度が低いリージョンを探してみると、オレゴンリージョンが該当することが分かりました。
バージニア、オハイオリージョンに作ったものはすべて削除し、オレゴンリージョンに構成して実行してみると、ようやく字幕生成ジョブが動き始めました。一括処理のために2,000台のg5.xlargeインスタンスを同時に起動する計画でしたが、オレゴンリージョンでさえインスタンス不足で最大500台ほどしか起動できませんでした。それでも、約4時間で字幕の一括生成を完了できました。
一括処理のコスト
基盤
単価
費用
差
AWS Batch (g5.xlarge Spot)
-
$807.22
- (x1)
AWS Batch (g5.xlarge On-Demand)
-
約$2,690
約$1,883 (x3.3)
OpenAI Whisper API
$0.006 / minute
約$8,700
約$7,893 (x10.8)
Naver CLOVA CSR API
$0.012 / minute
約$17,400
約$16,593 (x21.6)
字幕の一括生成作業にかかった費用は $807.22 で、約24,000時間に及ぶ動画の音声データをAPIベースのサービスで処理する場合と比べて、10分の1以下のコストで字幕を生成できる構成を実現できました。
結論
以上のような過程を経て、約2か月で字幕生成機能を無事に実装できました。Infthonをきっかけに、2日間でアイデアの選定から技術調査、デモ用の実装までを終え、その後の2か月間で、それをユーザーにリリースできるレベルまで引き上げるためにさまざまな試みをしました。貴重な経験でした。
字幕生成に関する技術的な部分も注目に値しますが、特に強調したいのは、1人が短期間でこなしたにしては、インフラ関連の作業量がかなり多かったことです。何のリソースもないリージョンを3回も渡り歩き、VPCからAWS Batch環境までを一晩で構成できたのは、何かが準備されていなければ不可能なことです。特に、受講権限を持つユーザーにのみ字幕データを提供する対応や、字幕のストレージをS3からMongoDBに移行する作業など、本文には書いていない数多くのインフラ作業がありました。それらに触れなかったのは、ほとんど悩むことなく素早く対応できたからです。
これが可能だったのは、これまで懸命に構築してきたIaCのおかげだと思います。私たちがどのようにIaCを構築したかについては、(今度こそ本当に)近日公開予定の「InflabのIaC構築記(Part 1)」の記事でご覧いただけます。AWS CDKからTerraformへの記事でTerragruntとTerratestについての記事を予告しておきながら、1年以上新しい記事を投稿できなかった理由も、その記事で詳しく書いていますので、IaCに興味のある方はぜひ読んでみてください。
ありがとうございました。
JEPA: qué es la arquitectura de LeCun que no genera píxeles
Yann LeCun lleva años insistiendo en que los modelos generativos, los mismos que producen texto o imágenes token por token, no son el camino hacia una inteligencia artificial con sentido común. El 29 de octubre de 2026 publicó, junto a Randall Balestriero, la prueba matemática de esa intuición. Su paper en arXiv demuestra que la arquitectura JEPA que ambos diseñaron converge a la misma representación del mundo sin importar la modalidad de entrada, algo que la predicción de próximo token logra con mucha menos eficiencia.
Esa demostración no es el tema de este artículo. Lo que importa para un desarrollador es entender qué hace distinta a esta arquitectura, que Meta ya usa en producción en I-JEPA y V-JEPA. Su apuesta central es predecir representaciones en vez de píxeles.
TL;DR
- JEPA predice la representación latente de una parte oculta, sin reconstruir píxeles ni tokens.- Meta usa este diseño en I-JEPA para imágenes y en V-JEPA para video en producción.- Un codificador objetivo con pesos EMA y stop-gradient evita el colapso representacional.- Las vistas positivas necesitan 42 veces menos muestras que el next-token prediction para alinear representaciones.- A diferencia de la difusión, JEPA predice embeddings para entender el mundo, no para generar contenido nuevo.
¿Qué es la arquitectura JEPA?
La arquitectura JEPA es una familia de modelos de aprendizaje autosupervisado que predice la representación latente de una parte faltante de los datos a partir de una parte visible, sin generar los datos originales pixel por pixel. LeCun la propuso en 2022 como alternativa a los generativos.
LeCun presentó la idea en su ensayo A Path Towards Autonomous Machine Intelligence, donde argumentaba que un sistema inteligente necesita un modelo del mundo capaz de predecir sin gastar cómputo en detalles irrelevantes. Reconstruir cada píxel de un video, por ejemplo, obliga al modelo a aprender ruido de cámara o texturas de fondo que no ayudan a entender la escena.
JEPA evita ese desperdicio prediciendo en el espacio de las representaciones (embeddings) en lugar del espacio de los datos crudos. En la práctica significa entrenar dos codificadores que nunca comparten gradiente directo y un predictor que conecta ambos. El resultado es un modelo que aprende qué información importa de una escena sin que nadie le diga qué es importante.
Por qué importa el enfoque predictivo de LeCun
El problema que resuelve JEPA es concreto: entrenar modelos de visión sin millones de etiquetas humanas. Los modelos generativos de imágenes (difusión, autoencoders variacionales) también aprenden sin etiquetas, pero gastan su capacidad reconstruyendo cada textura y cada pixel de ruido, justo lo que después hay que ignorar para tareas como clasificación o segmentación.
El paper de Balestriero y LeCun le pone números a esa intuición. Usando un corpus de 145.000 descripciones de imágenes y 940 millones de imágenes web, encontraron que las vistas positivas (dos observaciones de la misma escena) alinean representaciones usando 42 veces menos muestras que el next-token prediction entrenado sobre el mismo texto.
Eso explica por qué los modelos de lenguaje alinean con la visión solo a gran escala. La predicción de próximo token es, según los propios autores, una JEPA con "vistas malas", fragmentos de un mismo documento en lugar de observaciones reales de una escena compartida. Un modelo de texto de apenas 109 millones de parámetros entrenado con vistas buenas alineó mejor con los encoders de imagen de DINOv2 y CLIP que cualquier modelo de lenguaje evaluado, incluso uno de 72.000 millones de parámetros.
Para quien entrena modelos con presupuesto limitado la lección es práctica. Elegir una arquitectura que prediga en espacio latente ahorra cómputo y datos etiquetados, dos recursos que escasean fuera de los laboratorios grandes.
Cómo funciona JEPA por dentro
La arquitectura tiene tres piezas. El codificador de contexto procesa la parte visible de la entrada, un bloque de parches de una imagen o un clip de video. El codificador objetivo procesa la parte oculta, pero sus pesos no se entrenan por gradiente, se actualizan como un promedio móvil exponencial (EMA) de los pesos del codificador de contexto. El predictor toma la salida del codificador de contexto y trata de adivinar la salida del codificador objetivo.
flowchart TD
A["Entrada (imagen o video)"] --> B["Codificador de contexto"]
A --> C["Codificador objetivo (EMA)"]
B --> D["Embedding de contexto"]
C --> E["Embedding objetivo"]
D --> F["Predictor"]
F --> G["Embedding predicho"]
G --> H["Perdida en espacio latente"]
E --> H
La pérdida de entrenamiento compara esa predicción contra el embedding objetivo real, casi siempre con una distancia L2 o smooth L1, nunca contra los píxeles originales. Como el codificador objetivo nunca recibe gradiente directo y el predictor ve menos información que el codificador objetivo, el sistema no puede memorizar una salida constante para hacer trampa, y ese detalle es lo que previene el colapso representacional, el fracaso más común de este tipo de entrenamiento.
> 💭 Clave: Sin la asimetría entre el codificador de contexto y el codificador objetivo (EMA más stop-gradient), el modelo encuentra el camino más corto: predecir siempre el mismo vector y minimizar la pérdida sin aprender nada.
I-JEPA divide una imagen en parches y oculta varios bloques grandes y contiguos, no parches sueltos al azar. Ocultar bloques grandes obliga al predictor a razonar sobre la estructura de la escena, dónde termina un objeto, qué hay detrás, en lugar de copiar textura del parche vecino, que es lo que pasa si el hueco es minúsculo.
flowchart LR
A["Imagen dividida en parches"] --> B["Bloque de contexto visible"]
A --> C["Bloques objetivo ocultos"]
B --> D["Codificador de contexto"]
C --> E["Codificador objetivo"]
D --> F["Predictor predice embeddings de C"]
E --> G["Embeddings reales de C"]
F --> H["Comparar con perdida L2"]
G --> H
V-JEPA extiende la misma idea al tiempo. En vez de ocultar solo una región espacial, oculta bloques que se extienden a lo largo de varios cuadros consecutivos, así el predictor tiene que modelar tanto la estructura de la escena como su evolución, el primer paso hacia lo que Meta llama un modelo de mundo.
Ejemplos prácticos: así se ve una predicción de JEPA en código
El mecanismo central de JEPA, predecir un embedding a partir de otro, se puede ilustrar con un fragmento mínimo en PyTorch. No es el código real de los repositorios de Meta, es un esqueleto que muestra la forma del problema.
import torch
import torch.nn as nn
class Predictor(nn.Module):
def __init__(self, dim=768):
super().__init__()
self.proj = nn.Linear(dim, dim)
def forward(self, context_embedding, mask_tokens):
return self.proj(context_embedding + mask_tokens)
context_embedding = torch.randn(1, 196, 768) # embeddings del bloque visible
mask_tokens = torch.randn(1, 196, 768) # tokens posicionales del bloque oculto
predictor = Predictor()
predicted_embedding = predictor(context_embedding, mask_tokens)
print(predicted_embedding.shape)
La salida es torch.Size([1, 196, 768]): un batch, 196 parches (14x14 en una imagen de 224x224 con parches de 16 píxeles) y 768 dimensiones por embedding. Esa misma forma es la que debe tener el embedding objetivo real para poder compararlos con la función de pérdida.
El codificador objetivo nunca recibe gradiente directo, solo un promedio móvil exponencial.
Cómo empezar con I-JEPA y V-JEPA
Para correr el código oficial necesitás Python 3.9 o superior, Git y, para entrenar en serio, una GPU con soporte CUDA. Para solo cargar un checkpoint preentrenado alcanza con CPU, aunque mucho más lento. Los pasos siguientes son para Linux y macOS; en Windows corren igual dentro de WSL.
git clone https://github.com/facebookresearch/ijepa.git
cd ijepa
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
Para V-JEPA el repositorio es distinto: git clone https://github.com/facebookresearch/jepa.git, seguido de los mismos tres pasos de entorno virtual e instalación.
No hay una forma de confirmar la instalación con un solo comando genérico, porque cada repositorio expone su propio script de evaluación. La señal de que todo cargó bien es que ese script termine e imprima la métrica final (la accuracy del linear probe, en el caso de I-JEPA) en vez de interrumpirse con un traceback de dependencias faltantes.
JEPA vs. modelos generativos y contrastivos
JEPA no es la única forma de aprender sin etiquetas. Comparado con otras dos familias, la diferencia queda más clara.
EnfoqueQué prediceVentajaLimitaciónJEPA (I-JEPA, V-JEPA)Embedding de una parte oculta a partir de una parte visibleNo gasta capacidad en detalles irrelevantes; más eficiente en datosNecesita trucos anticolapso (EMA, stop-gradient); no genera contenidoModelos generativos (difusión, autoregresivos de píxeles)Los datos originales completos, pixel por pixel o token por tokenSirven para crear contenido nuevo directamenteMás cómputo y datos para la misma calidad de representaciónAprendizaje contrastivo (SimCLR, CLIP)Si dos vistas vienen de la misma imagen, comparando embeddings completosRepresentaciones robustas sin reconstruir nadaDepende de aumentaciones manuales y bancos grandes de negativosNext-token prediction (LLMs de texto)El siguiente token de una secuenciaEscala muy bien con datos y cómputo en lenguajeEs una JEPA con vistas malas y alinea con otras modalidades solo a gran escala
flowchart TD
subgraph Generativo["Modelo generativo"]
P1["Entrada parcial"] --> P2["Decodificador"]
P2 --> P3["Reconstruccion en espacio de pixeles"]
end
subgraph JEPA["Arquitectura JEPA"]
J1["Entrada parcial"] --> J2["Predictor"]
J2 --> J3["Prediccion en espacio latente"]
end
La elección no es ideológica. Si el objetivo final es generar una imagen o un texto, un modelo generativo sigue siendo la herramienta correcta. Si el objetivo es que un sistema entienda una escena para después actuar sobre ella, un robot, un auto autónomo, predecir en espacio latente rinde más por cada muestra de entrenamiento.
Casos de uso reales: de la clasificación de imágenes a los modelos de mundo
Meta publicó I-JEPA en 2023 como su primer modelo de visión entrenado con esta arquitectura, pensado para tareas de clasificación y segmentación con pocas etiquetas disponibles. El paper original lo mostró compitiendo con modelos contrastivos usando una fracción de su cómputo de entrenamiento.
V-JEPA oculta bloques que se extienden en el tiempo, no solo en el espacio.
V-JEPA, publicado en 2024, extendió la idea a video para tareas como reconocimiento de acciones y comprensión de movimiento físico. El paper de V-JEPA lo presenta como un paso hacia modelos que entienden causa y efecto en el mundo físico, lo que LeCun describe como "modelos de mundo": sistemas capaces de predecir qué pasa después de una acción sin haber visto exactamente esa secuencia antes.
El caso de uso más concreto hoy es el preentrenamiento: entrenar primero con JEPA sobre datos sin etiquetar y después afinar una cabeza pequeña para la tarea final, con muchas menos imágenes o videos etiquetados que los que necesitaría un modelo entrenado desde cero.
Errores comunes y buenas prácticas
El error más citado en la literatura de aprendizaje autosupervisado es el colapso representacional: el modelo aprende a producir el mismo embedding para cualquier entrada, minimizando la pérdida sin aprender nada útil. JEPA lo evita con la asimetría entre codificadores, pero esa asimetría no es automática. Si el codificador objetivo se actualiza demasiado rápido (un EMA con momentum bajo) o demasiado lento, el riesgo de colapso vuelve.
Otro error común es confundir JEPA con aprendizaje contrastivo. SimCLR y CLIP necesitan pares negativos, ejemplos que NO deben parecerse, y aumentaciones de datos cuidadosamente diseñadas. I-JEPA y V-JEPA no usan negativos explícitos; la asimetría arquitectónica hace ese trabajo.
> ⚠️ Ojo: La limitación real, y la razón por la que JEPA no reemplaza a los modelos generativos, es que sus embeddings no sirven para generar contenido directamente. Si el proyecto necesita un generador de imágenes o un chatbot, un modelo generativo sigue siendo la pieza correcta.
Profundizando: la hipótesis platónica y el teorema de representación
El resultado más fuerte del paper de Balestriero y LeCun es lo que llaman el teorema de representación platónica. Los autores demuestran que dos JEPA entrenadas por separado sobre modalidades distintas, texto e imagen, por ejemplo, convergen a la misma representación salvo una rotación, siempre que sus pares positivos sean "vistas buenas", dos observaciones reales de la misma escena. Con vistas malas, fragmentos arbitrarios de un documento, la convergencia tiene un límite acotado pero no desaparece.
La consecuencia práctica, no solo teórica, es que esa rotación se puede calcular sin reentrenar nada. Los autores tomaron un encoder de texto y un encoder de imagen entrenados por separado, calcularon la rotación que los alinea y construyeron un generador de descripciones que obtuvo un CIDEr de 0,838 en COCO, sin que los dos encoders hubieran visto jamás un par imagen-texto durante el entrenamiento. En un benchmark sin pares, ese mismo text JEPA superó el zero-shot de todos los modelos de lenguaje evaluados hasta 8.000 millones de parámetros, con 64% contra un máximo de 56% top-5 en ImageNet-100.
Esto no significa que la arquitectura JEPA resuelva la hipótesis platónica de LeCun por completo. El propio paper aclara que el límite de desalineación depende de qué tan "buena" sea la vista, y construir vistas buenas para cada modalidad nueva, audio, sensores de robots, sigue siendo un problema de diseño abierto, no una receta universal.
📖 Resumen en Telegram: Ver resumen
Tu próximo paso: cloná el repositorio de I-JEPA, cargá un checkpoint preentrenado y corré el script de linear probing sobre un dataset chico propio para ver cuántas etiquetas necesitás realmente para una accuracy aceptable.
Preguntas frecuentes
¿La arquitectura JEPA reemplaza a los transformers generativos?
No. JEPA resuelve el problema de aprender representaciones sin etiquetas; los transformers generativos siguen siendo la herramienta cuando el objetivo final es producir texto, imagen o audio nuevo. Son complementarios, no rivales directos.
¿Qué diferencia a I-JEPA de V-JEPA?
I-JEPA trabaja sobre imágenes estáticas y oculta bloques espaciales de parches. V-JEPA extiende la idea a video, ocultando bloques que se extienden en el tiempo para que el modelo aprenda también la dinámica de una escena.
¿JEPA necesita pares negativos como el aprendizaje contrastivo?
No. SimCLR y CLIP comparan pares positivos contra negativos explícitos. I-JEPA y V-JEPA evitan el colapso con la asimetría entre el codificador de contexto y el codificador objetivo, sin necesitar negativos.
¿Por qué next-token prediction alinea peor con la visión, según el paper de LeCun?
Porque sus pares de entrenamiento son fragmentos de un mismo documento de texto, no dos observaciones reales de una escena compartida. El paper lo describe como una JEPA con "vistas malas", y por eso necesita mucha más escala para alinear con modelos de imagen.
¿Se puede usar JEPA para texto, no solo para imágenes y video?
Sí. El propio paper de Balestriero y LeCun entrena un text JEPA de 109 millones de parámetros con vistas positivas y lo compara directamente contra modelos de lenguaje de hasta 72.000 millones de parámetros.
¿JEPA sirve para generar imágenes o video nuevo?
No directamente. Sus embeddings describen una escena, pero no están pensados para reconstruir píxeles. Generar contenido nuevo a partir de esos embeddings requiere acoplar un decodificador o un modelo generativo aparte.
Referencias
- Balestriero y LeCun, "Proving and Improving the Platonic Representation Hypothesis with JEPAs" (arXiv, 2026): el paper que motiva este artículo.- Assran et al., "Self-Supervised Learning from Images with a Joint-Embedding Predictive Architecture" (arXiv, 2023): el paper original de I-JEPA.- Bardes et al., "V-JEPA: Video Joint-Embedding Predictive Architecture for Self-Supervised Visual Learning" (arXiv, 2024): el paper original de V-JEPA.- Repositorio oficial de I-JEPA en GitHub: código y checkpoints preentrenados.- Repositorio oficial de V-JEPA en GitHub: código y checkpoints preentrenados.
📱 ¿Te gusta este contenido? Únete a nuestro canal de Telegram @programacion donde publicamos a diario lo más relevante de tecnología, IA y desarrollo. Resúmenes rápidos, contenido fresco todos los días.
PDFを翻訳するとレイアウトが崩れる理由と確認すべき4か所
本記事はEqualangチームが執筆しています。Wordファイルと異なり、大半のPDFは「どの単語が段落を構成し、どの単語が表に属しているか」という構造情報を保持していません。PDFが持っているのは文字と、その文字を描画する座標だけです。
二段組の段組み、複数列にまたがる見出し、次ページへと続く文章といった構造に見えるものはすべて、翻訳の前に組み直す必要があります。そのうえで、長さが変わった訳文を元のレイアウトに収め直さなければなりません。書式が崩れるのは、この「構造解析」と「再配置」の2つの工程のどこかです。
手元にあるドキュメントに応じた適切な選択肢は以下の通りです:
元の .docx や .pptx がある場合:PDFではなく元ファイルを翻訳するのが確実です。
表の少ない文字中心のPDF(10 MB未満):Google 翻訳のドキュメントアップロード機能などが手軽な選択肢になります。
表・数式・二段組を含む論文やマニュアル:レイアウトを再構築する専門ツールを選び、後述する4か所のポイントを確認してください。
文字選択ができないスキャンPDF:翻訳の前に文字認識(OCR)が必要です。DeepLなどはスキャンデータを受け付けてOCRも自前で処理しますが、Google 翻訳ではスキャンページが未翻訳のまま残る場合があります。
1. 翻訳ツールはPDFの中に何を見ているのか
版面(レイアウト)を読み取らない一般的なツールがどのようなテキストを翻訳の材料にしているのか、具体的な例を見てみます。ここでは arXiv の論文2本(LLaMA および Mistral 7B)を用意し、オープンソースPDFツール MuPDF の mutool でテキストを抽出しました。
1.1 表は単なる数字の列に分解される
LLaMA 論文の表3(10個のモデルを8つのテストで比較した表)を例にとります。
これをテキスト抽出すると、102行の連続した文字列に変わります。
BoolQ
PIQA
SIQA HellaSwag WinoGrande ARC-e
ARC-c
OBQA
GPT-3
175B
60.5
81.0
-
78.9
70.2
68.8
51.4
57.6
Gopher
どの数値がどのテストに対応しているかをツールに伝える手がかりは失われます。これをそのまま翻訳ボックスに貼り付けても表構造は復元されず、単語は翻訳されても表そのものは消えてしまいます。
1.2 文の途中に表全体が割り込む
LLaMA 論文3ページの右欄末尾は "we need to" で途切れています。
続きは4ページ左欄、表3を挟んだ下部にあります。
抽出されたテキストストリームでは、文の途中に脚注や改ページ、表3の102行とそのキャプションがすべて割り込んでいます。
To fully benefit from this optimization, we need to
2facebookresearch/xformers
BoolQ
PIQA
…
Table 3: Zero-shot performance on Common Sense Reasoning tasks.
reduce the memory usage of the model by using
ページごとや抽出順のまま翻訳するツールでは、この離れた2つの断片をつなぎ合わせることができません。結果として、ページ下部で切れた文と、表の下に唐突に現れる文の後半が別々に翻訳されます。
1.3 添字と分数が別文字に化ける
Mistral 論文の変数 h_i(添字 i 付きの変数)を抽出すると、添字情報が失われて単なる英単語 hi に変化します。
former to attend information beyond the window size W. The hidden
state in position i of the layer k, hi, attends to all hidden states from
ツールにとって hi は一般的な英語単語と区別がつきません。
さらに複雑なのが分数です。LLaMA 論文のある箇所では、4d の 3分の2(\frac{2}{3}\cdot 4d)という重ね組みの分数が書かれています。
improve the performance. We use a dimension of
2
34d instead of 4d as in PaLM.
4d の 3分の2 が 34d に変わってしまっています。上付き・下付き文字や分数記号は描画位置情報に依存しているため、座標を考慮しない抽出では全く異なる値になってしまいます。
1.4 単語が行末ハイフネーションで分断される
二段組の論文では行末での単語分割が多く発生します。LLaMA 論文では、ハイフンで分割された一般単語が242行にのぼります。
We introduce LLaMA, a collection of founda-
tion language models ranging from 7B to 65B
…
(175B) on most benchmarks, and LLaMA-
65B is competitive with the best models,
founda- と tion はハイフンを外して1つの単語につなぎ直す必要がありますが、LLaMA- と 65B の間のハイフンはモデル名の一部として保持しなければなりません。
2. どのような選択肢があるか
選択肢
長所
限界
翻訳ボックスにコピー&ペースト
手軽に即座に試せる
表、数式、レイアウトが失われ、文が途中で切れることも多い
Google 翻訳の「ドキュメント」タブ
手軽に利用可能。.docx、.pdf、.pptx、.xlsx に対応
10 MB・300ページ上限。画像内文字やスキャンページは翻訳対象外。小型画面非対応
DeepL のファイル翻訳
Web版・デスクトップ版・API対応。スキャン対応。特定プランで編集可能 .docx 出力可能
アカウントが必要。プランごとに翻訳ファイル数の上限あり。CAD出力PDF等は非対応
Word に変換してから翻訳する
翻訳前に Word 上で修正・調整が可能
PDFからWord変換時に生じた誤りや崩れがそのまま残る
レイアウトを再構築する翻訳ツール
表、数式、分割された文を構造として扱う
元ファイルと完全に同一にはならず、テキスト長の変化による改行やフォント調整が生じる
※ Google 翻訳と DeepL についての記述は、各サービスの公式ヘルプページ(2026年10月7日確認時点)に基づきます。
私たちが開発している Equalang のドキュメント翻訳は、まさにこの「レイアウト再構築型」のアプローチをとっています。ページの切れ目で分割された文をつなぎ直し、結合セルや複数行ヘッダーを持つ表も構造を保ちながら再構築します。数式最適化オプションも用意しており、日本語、英語、中国語、韓国語、スペイン語、フランス語などに対応しています。
なお、Equalangは新規登録で200クレジットが付与されるため、手元のPDFで実際の再現性を確認していただけます。
3. PDFを翻訳したら確認すべき4つのポイント
どのようなツールを用いた場合でも、翻訳後には以下の4か所を確認することをおすすめします。
表の整合性:ヘッダー行が対応する列の上にあるか、数値が変わっていないか。
改ページ部と表の下のテキスト:ページ下部や表の直後で文が途切れたままになっていないか。
数式と変数:文中の記号が英単語に化けていないか、分数が別の数字になっていないか。
ページ数とリンク:ページ数が不自然に増減していないか、目次リンクが正常に動作するか。
参考資料
Touvron et al., "LLaMA: Open and Efficient Foundation Language Models", arXiv:2302.13971v1, CC BY 4.0.
Jiang et al., "Mistral 7B", arXiv:2310.06825v1, CC BY 4.0.
Google 翻訳 ヘルプ, Translate documents & websites, 2026年10月7日確認.
DeepL ヘルプセンター, Translate PDF files, 2026年10月7日確認.
実測方法: テキストは2026年10月7日に MuPDF 1.25.6 で抽出(コマンド mutool draw -q -F txt -o out.txt in.pdf)。図は論文ページの切り抜きで、強調は筆者が入れたものです。
SAM 2: Put Text Behind Moving People | GitHub Repos You Should Know #022
Put text behind a moving person, then keep that person in colour. Both edits use actual masks from our local SAM 2 test.
Project: facebookresearch/sam2
Classification: Worth Knowing
We gave SAM 2.1 Hiera Small one positive point on the first frame of a six-second clip. It tracked the person across 90 frames, without manual mask corrections. SAM 2 produces selections; our compositor adds the text and selective-colour effects. The same test is replayed in different explanatory views.
Hair, fingers and foreground occlusions need checking. This is not a perfect-matting claim. This is an established project, not a new-release or active-maintenance claim.
Footage: Mixkit, Woman Dancing and Mopping Her Living Room (101054), Stock Video Free License.
mixkit.co
SAM 2 code/checkpoint: Apache 2.0; see the project licence.
#OpenSource #GitHub #SAM2 #VideoEditing
3 likes · 2 comments · 956 views
Mentions
RAG のデスクトップ 1. はじめに 古いPCに、FAISS と Dify を使用したRAG環境を構築します。NVIDIA GeForce などのグラフィックボードを搭載していないため、FAISS は最高性能ではありませんが、個人で使用するには十分です。LLM は、クラウドの OpenAI を使用します。 以前に書いた Docker Desktop、Dify のインストールの記事はこちら。 qiita.com 以前に書いた FAISS のインストールの記事はこちら。今回は NVIDIA ドライバをインストールしません。 qiita.com qiita.com RAG を実行するためのアプリケーションは他にもありますが、問い合わせ(テキスト)と登録した文書(テキスト)の、より正確なマッチングを行うために、単にコサイン類似度を計算したいので、FAISS を使用します。 文書の埋め込み(embedding)には、クラウドの OpenAI text-embedding-3-large を使用します。NVIDIA GeForce グラフィックボードを搭載した別のPCで、Alibaba qwen3-embedding-8b のようなローカルの embedding を使用することも可能です。 2. Xubuntu インストール PC電源投入時、 起動メニュー F12キー BIOS F2キー デスクトップの使い易さのために Xubuntu を使用しています。日本語入力をセットアップしますが、画面は英語のままにしています。 xubuntu-26.04.1-desktop-amd64.iso Rufus を使って起動 USB メモリを作成(DVD からだとアクセスが頻発して正常に動作しなかった) PCの電源を入れて F12キーを押して USB から立ち上げる デスクトップに表示される Install Xubuntu 26.04.1 LTS アイコンをダブルクリックして、PCへのインストールを開始 Language: English Keyboard: Japanese Connect to the internet: Connect to a Wi-Fi network ※ 先にメニューバーから接続しておく An update is available for the installer: Update now ※ インストーラーを再開 Interactive installation Xubuntu Desktop Erase disk and install Xubuntu Select drive: sda - 500GB SSD-PSTA/D BUFFALO No encryption Your name: webmaster Your computer's name: noble34 Your username: webmaster Password: ** Confirm password: ** Select your timezone: Asia/Tokyo インストールが終わったら、USB メモリを外して起動 OS アップデート sudo apt-get update sudo apt-get upgrade sudo apt-get dist-upgrade 再起動 SSH インストール sudo apt update sudo apt install openssh-server 外部から SSH で接続 ssh -l webmaster 192.168.1.41 password: ** Xfce メニュー メニューから Panel Profiles、Xfce 4.16、Apply Configuration ボタン押下 Application -> Settings -> Xfce Screensaver 60 minutes Application -> Settings -> Language Support 追加のインストールのためにパスワードを入力 Install / Japanese、Password 但し、画面表示は英語のままで使用する 再起動 ログイン後、バー右上、右クリック、Preference -> Input Method -> Add Japanese -> Mozc Preference -> General -> Keyboard Shortcuts <Super>space から <Control>space に変更、Apply ボタン バー右上、左クリックで Input Mode を Direct input から Hiragana に変更 固定IP Wifi 接続の場合は、メニューバー右上でマウス右クリック、Edit Connections から設定する Address: 192.168.1.34 Netmask: 255.255.255.0 Gateway: 192.168.1.1 DNS: 999.999.99.99, 888.888.888.88 ※プロバイダから入手 再起動 よく使うコマンド pwd ls -alF ip addr show nano .env(矢印キーでカーソル移動、保存Ctrl+S、終了Ctrl+X) sudo reboot sudo shutdown -h now 画面キャプチャ PrtSc、範囲指定 Shift+PrtSc、アクティブウィンドウのみ Ctrl+PrtSc ※ Alt が機能しないため Settings - Keyboard - Application Shortcuts で Ctrl に変更 3. Docker Desktop 下記リンクの手順に従って、Ubuntu に Docker Desktop をインストールします。 docs.docker.com 1.Docker の APT レポジトリの設定 # Add Docker's official GPG key # Add the repository to Apt sources 2.Docker パッケージのインストール sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin 3.hello-world イメージの実行 sudo docker run hello-world docs.docker.com sudo apt install gnome-terminal docker-desktop-amd64.deb をダウンロード sudo apt-get update sudo apt install ./docker-desktop-amd64.deb 再起動 メニューから Development > Docker Desktop で起動。または systemctl --user start docker-desktop で起動 ユーザー登録は行わず、skip、skip で Docker Containers の画面が表示される Docker Desktop のコンテナーのメモリ制限を、2GB(デフォルト)から4GBに変更する <img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="600"> Docker Desktop の自動起動 Docker Engine は、Xubuntu 標準のものと、Dify のためにインストールした Docker Desktop のものがあります。次のコマンドでどちらを使用しているか確認できます。 docker context ls webmaster@noble01:~$ docker context ls NAME DESCRIPTION DOCKER ENDPOINT ERROR default Current DOCKER_HOST based configuration unix:///var/run/docker.sock desktop-linux * Docker Desktop unix:///home/webmaster/.docker/desktop/docker.sock Docker Desktop は、ユーザーがログインした後でないと起動できません。GUI で以下を設定します。 Settings、Session and Startup、Application Autostart Add Name: Docker Desktop Comment: Docker Desktop 起動 Command: /opt/docker-desktop/bin/docker-desktop Docker Desktop を起動すると、Dify のコンテナが自動的に起動します。 4. Dify docs.dify.ai mkdir Repos cd Repos git clone --branch 1.18.0 https:\/\/github.com/langgenius/dify.git cd dify/docker cp .env.example .env openssl rand -base64 32 表示されたキーを .env の DIFY_AGENT_LOCAL_SANDBOX_AUTH_TOKEN に記入する nano .env docker compose up -d インストールが完了すると、Docker Desktop で実行中になる <img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="450"> ブラウザで 192.168.1.34 または localhost を表示 管理者アカウントの設定 Email address Username Password ブラウザで 192.168.1.34 または localhost を表示 Email と Password でログイン LLMモデルの設定 連携 - モデルプロバイダーをインストール OpenAI API Key:**** デフォルトのモデルは gpt-5.4-mini 従来との互換性のために gpt-4.1 を選択 HTTPS 化(手順はこちら) ドメインを取得し、ホスト名を登録する ルーターの80と443のポートフォワードを、このPCにする 自分のドメインでこのPCの http:\/\/localhost/ が表示されることを確認する docker/.env の編集。.env に、説明にある赤字の項目を設定する コマンドの実行(Docker Desktop が立ち上がっていること) cd dify/docker docker compose --profile certbot up --force-recreate -d コンテナが作成された後に、 docker compose exec -it certbot /bin/sh /update-cert.sh docker/.env の(再)編集。.env に以下を設定する NGINX_HTTPS_ENABLED=true コマンドの実行 docker compose --profile certbot up -d --no-deps --force-recreate nginx 外部から your_domain.com で見れることを確認する SSL 証明書の更新 docker compose exec -it certbot /bin/sh /update-cert.sh docker compose exec nginx nginx -s reload <img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="450"> 5. FAISS Anaconda anaconda.com ホームページでメールを登録すると、ダウンロードリンクが届きます Linux、現在 Python 3.14.4 Anaconda3-2026.07-1-Linux-x86_64.sh をダウンロード。home ディレクトリにファイルを移動 bash ~/Anaconda3-2026.07-1-Linux-x86_64.sh ./anaconda3/bin/conda init 次のターミナルの起動から、conda 環境(base)になります <img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="600"> FAISS 用に、Python のバージョンを 3.12 にします conda create -n faiss python=3.12 -y conda activate faiss echo 'conda activate faiss' >> ~/.bashrc <img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="600"> 解除は conda deactivate ベクトルデータベース(faiss)のインストール facebookresearch/faiss 事前準備 sudo apt install unzip faiss-cpu インストール conda install -c pytorch -c conda-forge faiss-cpu=1.15.1 ※ バージョンは FAISS のウェブページに表示されているもの 動作確認のために、faiss のページにある DOWNLOAD ZIP からプログラムコード一式をダウンロードします <img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="700"> unzip faiss-main.zip cd faiss-main/tutorial/python (faiss) webmaster@noble34:~/faiss-main/tutorial/python$ ls -1 1-Flat.py 10-FaissCuvsExample.ipynb 11-SVS.py 2-IVFFlat.py 3-IVFPQ.py 4-GPU.py 5-Multiple-GPUs.py 6-HNSW.py 7-PQFastScan.py 8-PQFastScanRefine.py 9-RefineComparison.py python 1-Flat.py True 100000 [[ 0 393 363 78] [ 1 555 277 364] [ 2 304 101 13] [ 3 173 18 182] [ 4 288 370 531]] [[7.6293945e-06 7.1751785e+00 7.2076302e+00 7.2511673e+00] [0.0000000e+00 6.3235664e+00 6.6845779e+00 6.7999382e+00] [3.8146973e-06 5.7964020e+00 6.3917236e+00 7.2815170e+00] [3.8146973e-06 7.2779007e+00 7.5279808e+00 7.6628418e+00] [0.0000000e+00 6.7638016e+00 7.2951088e+00 7.3688126e+00]] [[ 381 207 210 477] [ 526 911 142 72] [ 838 527 1290 425] [ 196 184 164 359] [ 526 377 120 425]] [[ 9900 10500 9309 9831] [11055 10895 10812 11321] [11353 11103 10164 9787] [10571 10664 10632 9638] [ 9628 9554 10036 9582]] python 2-IVFFlat.py [[ 9900 9309 9810 10048] [11055 10895 10812 11321] [11353 10164 9787 10719] [10571 10664 10632 10203] [ 9628 9554 9582 10304]] [[ 9900 10500 9309 9831] [11055 10895 10812 11321] [11353 11103 10164 9787] [10571 10664 10632 9638] [ 9628 9554 10036 9582]] python 3-IVFPQ.py [[ 0 78 424 608] [ 1 555 1063 380] [ 2 179 304 33] [ 3 265 527 139] [ 4 288 531 827]] [[1.5948839 6.2905183 6.3059173 6.5697308] [1.282814 5.9320083 5.9512424 6.5773916] [1.698801 6.1244454 6.2004113 6.401427 ] [1.82021 6.721145 6.8056335 6.995647 ] [1.4857421 5.8346977 6.303232 6.400938 ]] [[ 8746 9380 10914 9842] [10913 11373 9014 10507] [10719 11291 10600 11353] [11578 9671 10709 10664] [ 9229 9878 9905 9459]] PostgreSQL インストール sudo apt update sudo apt install postgresql postgresql-contrib psql --version sudo -i -u postgres psql postgres=# CREATE USER admin WITH PASSWORD '<font color="green">mypassword</font>' SUPERUSER; CREATE USER webmaster WITH PASSWORD '<font color="green">mypassword</font>'; CREATE DATABASE webmaster OWNER webmaster; \q で抜ける exit で postgres ユーザーを抜ける psql -U webmaster -d webmaster -h localhost CREATE TABLE knowledge_documents ( id UUID PRIMARY KEY, knowledge_id TEXT NOT NULL, content TEXT NOT NULL, title TEXT NOT NULL, metadata JSONB, created_at TIMESTAMP DEFAULT now() ); \q で抜ける \d knowledge_documents (テーブル一覧) \l (データベース一覧) \c (現在接続しているデータベース) SELECT * FROM knowledge_documents; TRUNCATE TABLE knowledge_documents; faiss_service の作成 次のように作成します。 |項目|ツール| |---|---| |文書データベース|PostgreSQL| |ベクトルデータベース・検索|faiss-cpu| |埋め込み(Embeddings)|OpenAI API(text-embedding-3-small)<br>ナレッジIDを指定して切り替え可能| |ウェブサーバー|Python Flask| # 一旦、通常の Ubuntu 環境に戻す conda deactivate sudo apt update sudo apt install -y build-essential libpq-dev python3-dev # conda 環境で実行 conda activate faiss pip install flask psycopg2 openai flasgger ollama mkdir faiss_service cd faiss_service nano faiss_service.py [faiss_service.py を他のPCからコピーして入手] LangChain を使用したチャンク分割(upload_files_chunk)は行わないこととし、upload_files_chunk の部分を削除します。また、LangChain の API_KEY も設定しません。 faiss_gpu から faiss_cpu への変更 # 変更前 res = faiss.StandardGpuResources() # use a single GPU gpu_index = faiss.index_cpu_to_gpu(res, 0, index) index = faiss.index_gpu_to_cpu(gpu_indexes[knowledge_id]) # 変更後 #res = faiss.StandardGpuResources() # コメントアウトまたは削除 gpu_index = index # 3か所 index = gpu_indexes[knowledge_id] # 1か所 export PSQL_DB_PASSWORD="..." export OPENAI_API_KEY="..." python faiss_service.py <img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="450"> ウェブページを表示 http:\/\/192.168.1.34:8000/apidocs/ <img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="650"> コンテンツエディター 登録済みのコンテンツ(テキスト)を確認・編集するためのウェブページを作成します。[保存して更新]ボタンを押下すると、faiss_service の delete と add を呼び出します(Faiss を使用しているため、登録済みの内容は変更ではなく、再登録します)。 pip install requests mkdir content_editor cd content_editor nano app.py [app.py を他のPCからコピーして入手] mkdir templates nano templates/index.html nano templates/edit.html [index.html と edit.html を他のPCからコピーして入手] [ 実行 ] export PSQL_DB_PASSWORD="**" python app.py [ 表示 ] localhost または、 192.168.1.34 (他のPCからIPアドレスを指定) <img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="450"> <img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="650"> <img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="650"> Ubuntu 起動時に Python プログラムを実行する 参考ページ1: udemy.benesse.co.jp cd ~ nano py_app_service.sh export PSQL_DB_PASSWORD="..." export OPENAI_API_KEY="..." /home/webmaster/anaconda3/envs/faiss/bin/python /home/webmaster/faiss_service/faiss_service.py & /home/webmaster/anaconda3/envs/faiss/bin/python /home/webmaster/content_editor/app.py & wait chmod 744 py_app_service.sh bash py_app_service.sh 参考ページ2: note.com cd /etc/systemd/system sudo nano run_python.service [Unit] Description=python run After=network.target [Service] Type=simple User=webmaster WorkingDirectory=/home/webmaster/faiss_service ExecStart=/bin/bash /home/webmaster/py_app_service.sh Restart=on-failure KillMode=control-group [Install] WantedBy=multi-user.target ※ データファイルを読み込むため、ワーキングディレクトリを faiss_service に設定する sudo systemctl daemon-reload sudo systemctl enable run_python.service sudo systemctl start run_python.service sudo systemctl status run_python.service sudo systemctl stop run_python.service 多数のファイルを一度に登録する faiss_service の画面では、最大20個のファイルを手動で指定し、登録できるようにしています。実際は、別に Python プログラムを作成し、テキストファイル(input.txt)に記述したファイル一覧をもとに、一括登録できるようにしています。input.txt の1行目には、すべてのファイルに共通するナレッジIDを記入し、2行目以降には登録するファイル名を記述します。プログラムは faiss_service.py の upload_files をもとに作成しいますが、ここでは内容を割愛します。 ファイル一覧の作成: ls *.txt > input.txt nano input.txt 1行目にナレッジIDを記入 2行目以降はファイル名 python upload_files.py Dify と FAISS を接続 Dify で外部ナレッジベースの設定を行って、faiss_service に接続します。 ナレッジ 「外部ナレッジベースと連携 →」 <img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="450"> 外部ナレッジベース連携APIを追加 API Key は未使用なので ABCdef など <img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="450"><br> <img src="qiita-image-store.s3.ap-northeast-1.amazonaws.com" width="450"> 外部ナレッジベース名: ローカルRAG 外部ナレッジベースID: AAA-BBB-CCC 「連携 →」ボタン押下 事前準備(以前からの修正) 従来は Dify 1.13.0 を使用していましたが、1.18.0 に変更したところ、以下の対応が必要でした。 SSRF プロキシ対応 cd dify/docker nano .env 変更前: SSRF_PROXY_ALLOW_PRIVATE_IPS= 変更後: SSRF_PROXY_ALLOW_PRIVATE_IPS=192.168.1.34 設定の反映 docker compose up -d --force-recreate ssrf_proxy 確認 docker exec docker-ssrf_proxy-1 \ cat /etc/squid/dify_allow_private.conf faiss_service.py、retrieval のレスポンスにおける score の型変換 変更前: records.append({ "score": score 変更後: records.append({ "score": float(score) 6. その他 □ ファイアウォール sudo ufw enable sudo ufw allow 'Nginx Full' sudo ufw allow OpenSSH sudo ufw reload sudo ufw status sudo ufw status numbered sudo ufw delete 3 □ ブルートフォース攻撃対策 sudo apt update sudo apt install fail2ban sudo nano /etc/fail2ban/jail.d/sshd.local [sshd] enabled = true backend = systemd port = ssh filter = sshd maxretry = 5 findtime = 600 bantime = 86400 10分間に5回以上SSH認証に失敗したIPアドレスを、24時間遮断する設定になる sudo systemctl enable --now fail2ban sudo systemctl restart fail2ban sudo systemctl status fail2ban 以上、
英語論文や技術PDFのレイアウト崩れを防いで翻訳する方法:2段組・表・数式の破損パターンと対策 英語の学術論文や技術仕様書のPDFを読む際、段落の途切れや表の崩壊、数式の文字化けに悩まされる問題を解決します。 PDF内部のテキスト配置構造を紐解きながら、なぜ翻訳時にレイアウト破損が起こるのか、その4大原因を検証します。 論文の2段組や表・数式を適切に扱えるツールの特徴と、翻訳後に確認すべき重要チェックポイントがわかります。 Wordのファイルには、どの単語が段落を構成し、どの単語が表に属しているかの構造情報が記録されています。しかし、多くのPDFにはそれがありません。PDFが持っているのは文字コードと、その文字を紙面(画面)上に描画する座標情報だけです。段落や表、文といった構造は、読む人間の目が補完して認識しています。 一部のPDFにはアクセシビリティタグが付与されていますが、学術論文を含め付いていないものも数多く存在します。そのため、2段組レイアウト、複数列にまたがる見出し、次ページへと続く文章といった構造は、翻訳を行う前に正しく組み直す必要があります。そのうえで、翻訳によって長さが変わった訳文を元のレイアウトに収め直さなければなりません。書式が崩れるのは、まさにこの工程です。 手元のファイルに応じた基本的な選択肢は以下のとおりです: - 元の .docx や .pptx がある場合:PDFではなく、その元ファイルを翻訳するのが確実です。 - 表が少なく文字中心のPDF(10 MB未満):Google 翻訳のドキュメント機能を手軽に試せます。 - 表・数式・2段組を含む論文や技術レポート:レイアウトを再構築するタイプの翻訳ツールを利用し、後述する4つのチェックポイントを確認してください。 - スキャンデータ(テキスト選択不可):事前にOCR処理が必要です。DeepLはスキャンデータにも対応していますが、Google 翻訳ではスキャンページは未翻訳のまま残ります。 1. 翻訳ツールはPDFの内部をどう見ているのか PDFからテキストを取り出す際、内部で何が起きているのかを可視化するため、arXivに公開されているAI言語モデルの論文2本(LLaMA と Mistral 7B)を例に取ります。一般的なオープンソースPDFツールである MuPDF の mutool でテキストを抽出した結果を見てみましょう。レイアウトを考慮しないツールが翻訳処理に渡しているのは、おおよそ次のようなデータです。 1.1 表は単なる数字の列に分解される LLaMA 論文の表3(Table 3)では、10個のモデルを8つのベンチマークテストで比較しています。  これをテキスト抽出すると102行のデータになります。ヘッダーの後に数値が1行ずつ並びます。 BoolQ PIQA SIQA HellaSwag WinoGrande ARC-e ARC-c OBQA GPT-3 175B 60.5 81.0 - 78.9 70.2 68.8 51.4 57.6 Gopher どの数値がどのテストに対応しているのかを示す情報は完全に失われています。これをそのまま翻訳ボックスに貼り付けても、表としての構造は戻ってきません。 1.2 1つの文の中に表データが丸ごと混入する LLaMA 論文の3ページ目末尾の文は、"we need to" で途切れています。  その続きは、4ページ目左欄の表3の下に現れます。  抽出されたテキストを見ると、脚注や改ページ、表3の102行、さらに表題が、1つの文の真ん中に挟み込まれています。 To fully benefit from this optimization, we need to 2https://github.com/facebookresearch/xformers BoolQ PIQA … Table 3: Zero-shot performance on Common Sense Reasoning tasks. reduce the memory usage of the model by using 順序通りに機械的に処理するツールでは、文の途切れと表の混入を見分けることができず、不自然に分割された訳文が生成されてしまいます。 1.3 添字や分数が別の文字・数値に化ける Mistral 論文では、変数 h に添字 i が付けられています(hᵢ)。  テキスト抽出を行うと添字の位置情報が失われ、単なる hi という文字列になります。 former to attend information beyond the window size W. The hidden state in position i of the layer k, hi, attends to all hidden states from LLaMA 論文でも、4d の3分の2(⅔·4d)という重ね組みの分数が次のように抽出されます。  improve the performance. We use a dimension of 2 34d instead of 4d as in PaLM. 位置情報が脱落した結果、「4dの3分の2」が「34d」という全く異なる数値になってしまいます。 1.4 単語が行末ハイフンで分断される 2段組の論文では行末のハイフネーションが多用されます。  We introduce LLaMA, a collection of founda- tion language models ranging from 7B to 65B … (175B) on most benchmarks, and LLaMA- 65B is competitive with the best models, founda-tion はハイフンを除去して繋ぐ必要がありますが、モデル名である LLaMA-65B のハイフンは保持しなければなりません。 2. PDF翻訳ツールの選択肢と特徴 | 選択肢 | 長所 | 限界 | | --- | --- | --- | | 翻訳ボックスへのコピー&ペースト | 無料ですぐに使える | 表、数式、レイアウトが失われ、文が途中で切れることが多い | | Google 翻訳(ドキュメント) | 無料。.docx、.pdf、.pptx、.xlsx に対応 | 10 MB・300ページまで。画像内文字やスキャンページは翻訳されない。モバイル非対応 | | DeepL(ファイル翻訳) | Web/デスクトップ/API対応。スキャンデータ対応。Proプラン等で.docx変換可能 | アカウントが必要。プランごとに翻訳ファイル数制限あり。CAD由来PDFなどは非対応 | | Word等に変換してから翻訳 | 翻訳前に元ファイルを修正できる | 変換時点でレイアウト崩れが発生した場合、誤りがそのまま残る | | レイアウト再構築型の翻訳ツール | 表、数式、分割された文を構造として認識 | 元ファイルと同一の配置にはならない。訳文の長さに応じて改行やフォントサイズが変化する | 私たちが開発している Equalang のドキュメント翻訳は、このレイアウト再構築アプローチを採用しています。ページの切れ目で分断された文章を翻訳前に結合し、表構造を1列に潰さずに維持したまま再構築します。また、数式を文字化けとして破棄せず、数式最適化のオプションも提供しています(対応言語:日本語、英語、中国語、韓国語、スペイン語、フランス語など)。 ただし、言語によって翻訳後の文字量が変わるため、元ファイルと完全に一致するわけではありません。文字が溢れたり改行位置が変わる箇所は、目視での確認が必要です。 3. PDF翻訳後に必ず確認すべき4つのポイント 1. 表の整合性:列ヘッダーと数値の対応がずれていないか確認します。 2. 改ページと表前後のテキスト:ページの最終行や表の直後に、文頭・文末が途切れた不自然な文がないか確認します。 3. 数式と記号:文中のインライン変数や分数が、一般的な英単語や誤った数字に化けていないか点検します。 4. ページ数とハイパーリンク:訳文の膨張でページが予期せず増えていないか、目次や参照リンクが正常に飛べるかを確認します。 この記事はドキュメント翻訳ツールを開発している Equalang チームが執筆しました。 参考資料 - Touvron et al., "LLaMA: Open and Efficient Foundation Language Models", arXiv:2302.13971v1, CC BY 4.0. - Jiang et al., "Mistral 7B", arXiv:2310.06825v1, CC BY 4.0. - Google 翻訳 ヘルプ, Translate documents & websites, 2026年10月7日確認. - DeepL ヘルプセンター, Translate PDF files, 2026年10月7日確認. - 実測方法: テキストは2026年10月7日に MuPDF 1.25.6 で抽出(コマンド mutool draw -q -F txt -o out.txt in.pdf)。図は論文ページの切り抜きで、強調は筆者が入れたものです。
Hyperagents Self-improving AI systems aim to reduce reliance on human engineering by learning to improve their own learning and problem-solving processes. Existing approaches to self-improvement rely on fixed, handcrafted meta-level mechanisms, fundamentally limiting how fast such systems can improve. The Darwin G\"odel Machine (DGM) demonstrates open-ended self-improvement in coding by repeatedly generating and evaluating self-modified variants. Because both evaluation and self-modification are coding tasks, gains in coding ability can translate into gains in self-improvement ability. However, this alignment does not generally hold beyond coding domains. We introduce \textbf{hyperagents}, self-referential agents that integrate a task agent (which solves the target task) and a meta agent (which modifies itself and the task agent) into a single editable program. Crucially, the meta-level modification procedure is itself editable, enabling metacognitive self-modification, improving not only the task-solving behavior, but also the mechanism that generates future improvements. We instantiate this framework by extending DGM to create DGM-Hyperagents (DGM-H), eliminating the assumption of domain-specific alignment between task performance and self-modification skill to potentially support self-accelerating progress on any computable task. Across diverse domains, the DGM-H improves performance over time and outperforms baselines without self-improvement or open-ended exploration, as well as prior self-improving systems. Furthermore, the DGM-H improves the process by which it generates new agents (e.g., persistent memory, performance tracking), and these meta-level improvements transfer across domains and accumulate across runs. DGM-Hyperagents offer a glimpse of open-ended AI systems that do not merely search for better solutions, but continually improve their search for how to improve. Comments: Code at facebookresearch/Hyperagents
OmniFaceRig: Fully Automatic Inner-Mouth-Aware Face Rigging Across Diverse 3D Character Topologies Facial rigging--creating Facial Action Coding System (FACS) blendshapes and inner-mouth geometry (teeth, gums, and tongue)--remains a major bottleneck in 3D character production. We present OmniFaceRig, a fully automatic end-to-end pipeline that converts a static surface-only 3D character mesh, with no pre-modeled oral cavity, into an inner-mouth-aware FACS rig with up to 155 blendshapes, procedurally fitted teeth, gums, and tongue, and re-packed UV/texture. It supports humans, humanoids, and long- and short-muzzled animals with no manual landmarks, user-provided templates, or per-asset setup. OmniFaceRig combines a hybrid vision-language and computer vision riggability checker, a four-model face segmentation ensemble, keypoint-driven template registration, procedural inner-mouth construction, and collision-aware blendshape transfer. For non-human characters, it selects topology-specific templates with a nose-landmark-free design and uses as-rigid-as-possible deformation with signed-distance-field constraints to reduce teeth-face intersections. We also introduce Omni-Bench, an open-source benchmark of more than 1,000 biped 3D characters rigged with FACS blendshapes and inner-mouth geometry, spanning humans, humanoids, cats, dogs, and other animals. Experiments show high rigging success, nearly complete face detection recall, low inner-mouth penetration, and 20-30 s end-to-end latency per asset on a single A100 GPU. Comments: 36 pages, 19 figures, 9 tables. Accepted to ACM Transactions on Graphics (SIGGRAPH Asia 2026). v2: revised text and appendix, updated Omni-Bench description for the public dataset release, corrected references. Project page: omnifacerig.github.io ; Dataset: facebookresearch/omnifacerig
Selecting or Solving? What Best-of-N Verification Delivers in Video Reasoning Answering a complex question about a long video is a grounding problem: the answer turns on a few seconds of evidence, and vision-language models remain well below human accuracy at finding them. The standard way to spend extra test-time compute on this kind of video reasoning is best-of-N selection: sample several chain-of-thought answers from a fixed model, then let a second model re-watch the video and pick one. Such pipelines are reported by a single headline number, their margin over a majority vote. That number conflates two effects with opposite deployment consequences: the benefit the second model adds by selecting among candidates, and the benefit it would have supplied by solving the question itself. We separate them, measuring the Selection Increment (SI) -- selection accuracy minus the same verifier's accuracy with the candidates withheld -- alongside the margin over self-consistency, across five long-video benchmarks. The Selection Increment is largest for the weakest verifiers: a verifier that solves poorly on its own leaves the candidates the most room to help. Beating the majority vote follows the opposite profile: where the vote already sits near its ceiling no verifier we test improves on it; below that ceiling only the strongest do. On Video-Holmes, the two come apart on a single pool of candidates -- a weak verifier gains +19.3 points from the candidates yet lands 7.1 points below the vote, while the frontier verifier gains the least and beats the vote. The weakest verifier also shows a failure mode: on EgoSchema it picks by where an option sits in the list rather than by what the video shows. Read as a merit score, SI puts a verifier that fails to beat a majority vote at the top of its ranking; read as an audit, it says which of the two effects a headline number delivers. Code is available at facebookresearch/best-n-selection-video-reasoning. Comments: Accepted at NeurIPS 2026 VLM4WRD workshop
GSLM2: Multi-Stream Speech Representation Learning and Generative Spoken Language Modeling Generative spoken language models (SLMs) offer a route to learning linguistic structure purely from speech, yet they lag far behind text-based models in both capability and data scaling efficiency. We identify two bottlenecks underlying this gap: the limited linguistic quality of existing speech units and the reliance on a single stream of discrete units to represent speech. Multiple codebooks are widely used to encode acoustic features but rarely to represent speech semantics. We present GSLM2, which learns and models complementary properties of speech at multiple levels of abstraction. Its encoder, SpidR 2.0, uses self-supervised learning with differentiable prediction heads to induce high-quality discrete units at multiple levels. A multi-stream SLM then jointly models these units using a shared temporal backbone, stream-specific predictors, and an autoregressive head that captures cross-stream dependencies. Across training data sizes and model scales, up to 6M hours and 6.5B parameters, GSLM2 consistently improves linguistic competence while scaling more efficiently with data. As a result, it substantially narrows the gap between spoken and text-based LMs; across read and conversational speech domains, we shrink the gap by about two orders of magnitude on sWuggy, sBLIMP, and tSC, while also outperforming competitive speech-text systems on all three tasks. We open-source the training code and model checkpoints at facebookresearch/gslm2. Comments: Equal contribution by Yosuke Higuchi and Tom Fizycki. Core contribution by Mahi Luthra, Charles-\'Eric Saint-James and Azeez Syed
Inflearnが自動で字幕を生成するまで(AI/インフラ編) ! この記事は2023年10月31日に執筆されたものです。 こんにちは。InflabのDevOpsエンジニア、SunBです。 2023年9月、Inflearnに字幕とスクリプトの機能が追加されました。皆さん、活用されていますか? 今回追加された字幕機能は、動画の音声データをもとに自動で字幕を生成する部分と、生成された字幕を受講画面に表示する部分の、大きく2つに分けられます。 今日は、このうち私が実装を担当した字幕生成について、どのような技術をもとに、どのような過程を経て実装したのかをお話しします。 2日で字幕機能を作ってデモする まず、「DevOpsエンジニアが字幕機能を実装したの?」と思われる方もいらっしゃると思うので、今回の字幕機能の実装プロジェクトがどのように始まったのかをご紹介します。 Inflabでは今年から、Infthonという名前で社内ハッカソンを開催しています。応募者をランダムに4人1組のチームに分け、約2日間でアイデアの議論とMVPの実装を行ったあとに発表する、という形式です。 ところが偶然(?)、Inflearnの講座プレイヤーやVODインフラを多く手がけていたFE開発者のPapicoと私が同じチームになり、自然と講座の再生に関するアイデアを議論することになりました。そして、第1回Infthonのテーマだった「チームの生産性向上、またはAIを活用したサービス改善」に最も合うと考えた講座のAI字幕機能をアイデアとして選びました。 まず、AIベースの字幕生成機能を実装するにあたって、最低限の条件として次のことを考えました。 字幕生成がオフラインで動作すること(データの外部送信を防ぐ) 字幕生成にコンピューティングリソース以外の追加費用がかからないこと(オープンソースモデルを自前で実行) 字幕生成にかかる時間が動画の長さを超えないこと(ライブデモができるくらい速いこと) これらの条件を満たす技術を探してみたところ、OpenAIのWhisperというモデルが目に留まりました。Whisper以外に検討した技術は以下のとおりです。 KoSpeech: Archived OpenSpeech + KsponSpeech: 自分たちで学習させてモデルを作るには、技術への理解度もまだ低く、時間もかなりかかると予想された KakaoのPORORO: Archived MetaのSeamlessM4T: テスト用の講座を使ったPoCの過程で、SeamlessM4T largeモデルはWhisper large-v2モデルに比べて精度が劣ることを確認 NaverのCLOVA SpeechなどのAPIベースのサービス: データの外部送信とAPI料金が発生 Infthon以前にも、MacWhisperなどのツールで、OpenAIのSTTモデルであるWhisperの存在とその精度の高さは知っていましたが、深く調べたことはありませんでした。実装期間が2日と短かったため、仕組みを深く理解することよりも、素早く適用してデモできるかどうかを重視して作業を進めました。その結果、すべての処理を私のMac上でオフラインで動かす構成になりました。その際、Pythonで実装されたOpenAIのWhisperは遅すぎたため、代わりにC++に移植されたwhisper.cppを使いました。 こうして、次の流れを短期間で実装できました。 動画をアップロードする ffmpegで16-bit WAVの音声データを抽出する whisper.cpp + large-v2モデルで字幕を書き起こし、srtファイルとして保存する 受講画面でこのsrtファイルを再生する さらに、FE開発者のPapicoの活躍で、スクリプトの表示と再生位置の移動、字幕の修正依頼と修正依頼の管理機能までデモでき、第1回Infthonで1位という栄誉を手にしました。 こうして楽しい経験として幕を閉じたと思っていたのですが…… 正式プロジェクトとして採用 ある意味当然のことながら、字幕機能はすぐに正式プロジェクトとして採用され、新たなスタートを切りました。 Infthonですでにデモまで終えていたので大きな心配はありませんでしたが、引っかかる点が3つありました。 Shaka Playerでm3u8のHLSプレイリストとsrt字幕ファイルを同時に表示すると、字幕の同期がずれる問題 AWSのインフラでWhisperをまだ動かしたことがなかった点 韓国語字幕の1行あたりの長さと改行位置が適切でなく、読みにくい問題 1つ目は、FE開発者のPapicoが字幕の表示処理をShaka Playerの機能を使わずにReactで新たに実装し、きれいに解決してくれました。一方、2つ目と3つ目は、そのまま現実の問題として降りかかってきます。 インフラ上でWhisperを動かす Infthonのときとは違い、今回は実際のユーザーにサービスを提供するため、まずは私たちのインフラ上で機能を動かす必要がありました。 エンコーディングインフラの改善記録 字幕生成インフラについてお話しする前に、まず動画エンコーディングインフラを改善した過程をご紹介します。 私たちは2022年10月まで、動画のエンコーディングにAWS MediaConvertを使っていましたが、コスト削減とエンコーディングオプションのカスタマイズのために、EC2 c6i.xlarge Spot InstanceベースのAWS Batch構成に移行しました。MediaConvertのReserved Queueなど、さまざまな代替案も試しましたが、予約したエンコーディングの開始が遅すぎたり、4Kなど一部のオプションが使えないといった制約があったりして、要件を満たすのは難しいと判断し、自分たちで構成する方向を選びました。 結果として、インフラ構成の変更は効果がありました。長さ28分の1080p動画を540p、720p、1080pにエンコードする場合、AWS Batchを使ったときとMediaConvertを使ったときにかかる時間と費用は、以下のとおりでした。 AWS Batch (ECS EC2 c6i.xlarge Spot) MediaConvert (On-Demand Pro) 差 時間 約10分 約7分 約3分 (x0.7) 費用 約$0.021 約$1.895 (SD x 1, HD x 2) 約$1.874 (x90.2) 動画の長さと比べれば、エンコーディング時間の差はわずかですが、費用はなんと90倍以上の差があることを確認しました。 AWS Batch構成で、EC2インスタンスタイプごとの費用と性能を分析した結果は以下のとおりです。(長さ28分の1080p動画を540p、720p、1080pにエンコードする場合、Spot Instance未適用) インスタンスタイプ オンデマンドの1時間あたりの費用 (A) エンコーディングの実行時間 (B) 実際の費用 (A x B) c6i.xlarge $0.192 10分 $0.032 c6g.xlarge $0.154 12分47秒 $0.033 c6i.2xlarge $0.384 5分57秒 $0.038 c6i.4xlarge $0.768 4分23秒 $0.056 g5g.xlarge $0.5166 5分1秒 $0.043 g5.xlarge $1.237 3分15秒 $0.067 エンコーディングインフラと同じ構成でwhisper.cppを試す 上記の改善したエンコーディングインフラをもとに、字幕インフラも同じ構造で構成してみました。AWS Batch上のc6i.xlargeインスタンスで28分の動画に対してwhisper.cppを実行したところ、結果はなんと69分3秒と、予想よりもはるかに遅いものでした。 Infthonのデモ用にMac Studio(M1 Ultra)で同じ動画をwhisper.cppで処理したときは、3分30秒でした。これを見て、すぐにGPUインスタンスのPoCに取りかかりました。 GPUインスタンスのPoC 最初は、g5インスタンスより安いARMベースのg5g.xlargeインスタンスを使ってみようとしました。ところが、NVIDIAドライバーやCUDAのバージョンをいくら変えても、PyTorchからCUDAを認識できませんでした。CUDA 11のPython cuDNNライブラリはARMアーキテクチャをサポートしておらず、PyTorchの正式版はCUDA 12をサポートしていなかったため、PyTorch Nightly + CUDA 12 cuDNNの構成を試しましたが、torch.cuda.is_available() が False を返す状態が続きました。そんな中、AWS BatchではまだARMアーキテクチャベースのGPUインスタンスをサポートしていないというドキュメントを見つけ、g5gインスタンスの利用はひとまず諦めました。 その後、g5.xlargeインスタンスでOpenAIのPythonベースのWhisperを実行してみたところ、7分17秒かかりました。動画の長さに比べれば許容範囲でしたが、Mac Studioでwhisper.cppを使ったときは3分30秒だったことを考えると、ほかに方法はないかと考えるようになりました。そして、SeamlessM4Tについて調べていたとき、偶然Hacker NewsでWhisperXに言及しているコメントを見かけました。 WhisperXへの移行 WhisperXを使って、g5.xlargeインスタンスで28分の動画の字幕生成を試してみたところ、59秒で完了し、最も速い結果となりました。その出力結果も、Whisperやwhisper.cppと比べて精度が劣るということはなく、それぞれ一長一短がありました。 以下は、出力結果を比較した当時に書いたメモの一部です。 Whisper、WhisperXはg5.xlargeで、whisper.cppはMac Studioで抽出したバージョン 3つともかなり違いがあるが、どれか1つが最も優れているというわけではなく、それぞれにうまく書き起こせている部分がある。 WhisperXが正確に抽出した部分 뽑았는데 (Whisper: 꼽았는데) 등허리 (Whisper: 등어리) 복부 (Whisper: 복구) whisper.cppが正確に抽出した部分 Eye Reflect (WhisperX: I Reflect) Whisperが正確に抽出した部分 Z-Remesh (WhisperX: gremesher) 아이리플렉트 (WhisperX: I Reflect) WhisperXはほかの2つよりはるかに速く実行でき、音節単位でalignするので行の再構成に有利であり、字幕の修正依頼機能の有効性も比較的高くなると推定されることを考えると、WhisperXを使うのが最も良いと思われる。 ただし、ときどき複数の文を早口で話す部分で抜け落ちる文があるが、精度が低いと判断して意図的に除外しているように見える。 まとめ 最初に試したwhisper.cpp + c6i.xlargeを基準に、試した組み合わせとの差をまとめると次のとおりです。(large-v2モデルを使って28分の音声データを書き起こした場合) ツール マシン 実行時間 差(速度) whisper.cpp c6i.xlarge 69分3秒 - (x1) Whisper c6i.xlarge 時間がかかりすぎて計測を中断 - WhisperX c6i.xlarge 実行中にエラーが発生 - whisper.cpp Mac Studio 3分30秒 65分33秒 (x19.7) Whisper Mac Studio 時間がかかりすぎて計測を中断 - WhisperX Mac Studio 15分26秒 53分37秒 (x4.5) whisper.cpp(cuBLASビルド) g5.xlarge 17分25秒 51分38秒 (x4) Whisper g5.xlarge 7分17秒 61分46秒 (x9.5) WhisperX g5.xlarge 59秒 68分4秒 (x70.2) 最終的に、WhisperX + g5.xlargeの組み合わせを選びました。 こうして最初の絶望を乗り越え、速度を70倍以上改善し、インフラ上で字幕生成機能を正常に動かせるようになりました。その過程でGPUインスタンスや動画エンコーディングに関する分析も行い、エンコーディング関連のプロセスも改善できました。 (試行錯誤の跡) 字幕の長さと読みやすさの改善 字幕をどう生成するかという課題は、音声データからテキストを抽出するだけでは終わりませんでした。 whisper.cpp、Whisper、WhisperXのいずれにも、--max_line_width のような1行の長さを制限するオプションがあったのですが、問題はこのオプションが動作しないことでした。(……)おそらく韓国語だから動作しないのだろうと推測しています。 そのため、モデルが出力した字幕データは行ごとに長さがバラバラで、文の終わりで改行されることもほとんどなく、読みやすさは最悪でした。 これを改善するために、ピリオド/疑問符/感嘆符があれば改行する案、一定の文字数以上なら単純に空白を基準に半分に分割する案、形態素解析によって行を再構成する案など、さまざまな方法を模索しました。 そんな中、WhisperXに移行して音節単位で時間を追跡できるようになったことで、いっそすべての行を一から作り直そうと考えました。そこで以下の基準を定め、WhisperXの実行から行の構成までを一度に行うPythonスクリプトを実装しました。 WhisperXが時間の追跡に失敗した音節の時間は、時間の追跡に成功した最も近い前後の音節の時間、または文の開始・終了時間から線形補間する。(wav2vecの韓国語モデルベースだったため、ハングル以外は音節の時間を追跡できないという問題がありました。) 直前の単語までの行の長さが0.5秒未満であれば、ほかのどの条件を満たしていても改行しない。 直前の単語までの行の長さが10秒を超えたら、現在の単語から新しい行にする。 現在の単語を加えると行が10文字を超え、かつ形態素解析の結果で文の数が変わる場合は、現在の単語から新しい行にする。 現在の単語を加えると行が50文字を超える場合は、現在の単語から新しい行にする。 文の開始が直前の文の終わりから0.5秒以内の場合は、文の開始時間として直前の文の終了時間を代わりに使う。 実は、このうち形態素解析で文の数を計算し、それをもとに改行する基準は最後に作ったものです。この基準を決めるまでは、WhisperXをCLIで実行したあと、JSONで保存されたデータを読み込んで行を構成する処理をすべてGoで実装していました。しかし、形態素解析と文の数の計算にKiwiを使うことになったため、WhisperXをPython内で直接実行するようにし、行の構成もPythonで実装し直しました。そしてGoは、このPythonスクリプトを実行し、最終的に構成された字幕データをストレージに保存するという、AWS Batch内の1つのジョブのライフサイクル管理だけを担う構造にしました。 こうして、現在提供している字幕のように、読みやすさが大きく改善された字幕データを生成できるようになりました。 GPUインスタンス不足の問題を回避する 問題はすべて解決したと思い、これまでにアップロードされた講座を対象に、実際に字幕を一括生成しようとしました。ところが、AWS Batchにジョブを投入していくら待っても、EC2インスタンスが起動しませんでした。Spot Requestを確認してみると、ソウルリージョンにg5.xlargeインスタンスのSpot Capacityがなく、起動できていなかったのです。 Spot Instanceとは? Spot Instanceは、AWSで使われていないコンピューティングリソースを最大90%割引した価格で提供する機能です。実行中のSpot Instanceがときどき中断されることもありますが、AWS Batchなどを使ってワークフローの耐障害性を確保していれば、Spot Instanceを適用するだけで60%以上のコスト削減効果を得られます。 実際に、動画エンコーディングインフラにSpot Instanceを適用することで平均70%のコストを削減できていたので、そもそも費用のかさむGPUインスタンスを使ううえで、Spot Instanceの適用は必須でした。 Spot Capacityを求めて GPUインスタンスが足りないという話はよく耳にしていましたが、実際に経験したのは初めてでした。3日待っても起動しなかったので、別の方法を探し始めました。 最初に、Spot Placement Scoreという機能を使ってみました。米国のバージニア、オハイオ、オレゴンリージョンはg5.xlargeインスタンスが最も安く、Placement Scoreも高く出ていたので、まずはバージニアリージョンで試してみました。 初めて使うリージョンで何もなかったため、VPC、Subnet、EIP、NAT Gatewayをはじめ、AWS Batch関連の各種リソースをすべて新しく作成しました。ところが実行してみると、同じようにSpot Capacityがないというエラーが発生しました。しまった!と思い、すぐ隣のオハイオリージョンにも同じ構成を作ってみましたが、やはりSpot Capacityがないというエラーが発生しました。(……) Placement Scoreは当てにならないなと思って調べてみたところ、スポットインスタンスアドバイザーというものを見つけました。g5.xlargeスポットインスタンスの中断頻度が低いリージョンを探してみると、オレゴンリージョンが該当することが分かりました。 バージニア、オハイオリージョンに作ったものはすべて削除し、オレゴンリージョンに構成して実行してみると、ようやく字幕生成ジョブが動き始めました。一括処理のために2,000台のg5.xlargeインスタンスを同時に起動する計画でしたが、オレゴンリージョンでさえインスタンス不足で最大500台ほどしか起動できませんでした。それでも、約4時間で字幕の一括生成を完了できました。 一括処理のコスト 基盤 単価 費用 差 AWS Batch (g5.xlarge Spot) - $807.22 - (x1) AWS Batch (g5.xlarge On-Demand) - 約$2,690 約$1,883 (x3.3) OpenAI Whisper API $0.006 / minute 約$8,700 約$7,893 (x10.8) Naver CLOVA CSR API $0.012 / minute 約$17,400 約$16,593 (x21.6) 字幕の一括生成作業にかかった費用は $807.22 で、約24,000時間に及ぶ動画の音声データをAPIベースのサービスで処理する場合と比べて、10分の1以下のコストで字幕を生成できる構成を実現できました。 結論 以上のような過程を経て、約2か月で字幕生成機能を無事に実装できました。Infthonをきっかけに、2日間でアイデアの選定から技術調査、デモ用の実装までを終え、その後の2か月間で、それをユーザーにリリースできるレベルまで引き上げるためにさまざまな試みをしました。貴重な経験でした。 字幕生成に関する技術的な部分も注目に値しますが、特に強調したいのは、1人が短期間でこなしたにしては、インフラ関連の作業量がかなり多かったことです。何のリソースもないリージョンを3回も渡り歩き、VPCからAWS Batch環境までを一晩で構成できたのは、何かが準備されていなければ不可能なことです。特に、受講権限を持つユーザーにのみ字幕データを提供する対応や、字幕のストレージをS3からMongoDBに移行する作業など、本文には書いていない数多くのインフラ作業がありました。それらに触れなかったのは、ほとんど悩むことなく素早く対応できたからです。 これが可能だったのは、これまで懸命に構築してきたIaCのおかげだと思います。私たちがどのようにIaCを構築したかについては、(今度こそ本当に)近日公開予定の「InflabのIaC構築記(Part 1)」の記事でご覧いただけます。AWS CDKからTerraformへの記事でTerragruntとTerratestについての記事を予告しておきながら、1年以上新しい記事を投稿できなかった理由も、その記事で詳しく書いていますので、IaCに興味のある方はぜひ読んでみてください。 ありがとうございました。
JEPA: qué es la arquitectura de LeCun que no genera píxeles Yann LeCun lleva años insistiendo en que los modelos generativos, los mismos que producen texto o imágenes token por token, no son el camino hacia una inteligencia artificial con sentido común. El 29 de octubre de 2026 publicó, junto a Randall Balestriero, la prueba matemática de esa intuición. Su paper en arXiv demuestra que la arquitectura JEPA que ambos diseñaron converge a la misma representación del mundo sin importar la modalidad de entrada, algo que la predicción de próximo token logra con mucha menos eficiencia. Esa demostración no es el tema de este artículo. Lo que importa para un desarrollador es entender qué hace distinta a esta arquitectura, que Meta ya usa en producción en I-JEPA y V-JEPA. Su apuesta central es predecir representaciones en vez de píxeles. TL;DR - JEPA predice la representación latente de una parte oculta, sin reconstruir píxeles ni tokens.- Meta usa este diseño en I-JEPA para imágenes y en V-JEPA para video en producción.- Un codificador objetivo con pesos EMA y stop-gradient evita el colapso representacional.- Las vistas positivas necesitan 42 veces menos muestras que el next-token prediction para alinear representaciones.- A diferencia de la difusión, JEPA predice embeddings para entender el mundo, no para generar contenido nuevo. ¿Qué es la arquitectura JEPA? La arquitectura JEPA es una familia de modelos de aprendizaje autosupervisado que predice la representación latente de una parte faltante de los datos a partir de una parte visible, sin generar los datos originales pixel por pixel. LeCun la propuso en 2022 como alternativa a los generativos. LeCun presentó la idea en su ensayo A Path Towards Autonomous Machine Intelligence, donde argumentaba que un sistema inteligente necesita un modelo del mundo capaz de predecir sin gastar cómputo en detalles irrelevantes. Reconstruir cada píxel de un video, por ejemplo, obliga al modelo a aprender ruido de cámara o texturas de fondo que no ayudan a entender la escena. JEPA evita ese desperdicio prediciendo en el espacio de las representaciones (embeddings) en lugar del espacio de los datos crudos. En la práctica significa entrenar dos codificadores que nunca comparten gradiente directo y un predictor que conecta ambos. El resultado es un modelo que aprende qué información importa de una escena sin que nadie le diga qué es importante. Por qué importa el enfoque predictivo de LeCun El problema que resuelve JEPA es concreto: entrenar modelos de visión sin millones de etiquetas humanas. Los modelos generativos de imágenes (difusión, autoencoders variacionales) también aprenden sin etiquetas, pero gastan su capacidad reconstruyendo cada textura y cada pixel de ruido, justo lo que después hay que ignorar para tareas como clasificación o segmentación. El paper de Balestriero y LeCun le pone números a esa intuición. Usando un corpus de 145.000 descripciones de imágenes y 940 millones de imágenes web, encontraron que las vistas positivas (dos observaciones de la misma escena) alinean representaciones usando 42 veces menos muestras que el next-token prediction entrenado sobre el mismo texto. Eso explica por qué los modelos de lenguaje alinean con la visión solo a gran escala. La predicción de próximo token es, según los propios autores, una JEPA con "vistas malas", fragmentos de un mismo documento en lugar de observaciones reales de una escena compartida. Un modelo de texto de apenas 109 millones de parámetros entrenado con vistas buenas alineó mejor con los encoders de imagen de DINOv2 y CLIP que cualquier modelo de lenguaje evaluado, incluso uno de 72.000 millones de parámetros. Para quien entrena modelos con presupuesto limitado la lección es práctica. Elegir una arquitectura que prediga en espacio latente ahorra cómputo y datos etiquetados, dos recursos que escasean fuera de los laboratorios grandes. Cómo funciona JEPA por dentro La arquitectura tiene tres piezas. El codificador de contexto procesa la parte visible de la entrada, un bloque de parches de una imagen o un clip de video. El codificador objetivo procesa la parte oculta, pero sus pesos no se entrenan por gradiente, se actualizan como un promedio móvil exponencial (EMA) de los pesos del codificador de contexto. El predictor toma la salida del codificador de contexto y trata de adivinar la salida del codificador objetivo. flowchart TD A["Entrada (imagen o video)"] --> B["Codificador de contexto"] A --> C["Codificador objetivo (EMA)"] B --> D["Embedding de contexto"] C --> E["Embedding objetivo"] D --> F["Predictor"] F --> G["Embedding predicho"] G --> H["Perdida en espacio latente"] E --> H La pérdida de entrenamiento compara esa predicción contra el embedding objetivo real, casi siempre con una distancia L2 o smooth L1, nunca contra los píxeles originales. Como el codificador objetivo nunca recibe gradiente directo y el predictor ve menos información que el codificador objetivo, el sistema no puede memorizar una salida constante para hacer trampa, y ese detalle es lo que previene el colapso representacional, el fracaso más común de este tipo de entrenamiento. > 💭 Clave: Sin la asimetría entre el codificador de contexto y el codificador objetivo (EMA más stop-gradient), el modelo encuentra el camino más corto: predecir siempre el mismo vector y minimizar la pérdida sin aprender nada. I-JEPA divide una imagen en parches y oculta varios bloques grandes y contiguos, no parches sueltos al azar. Ocultar bloques grandes obliga al predictor a razonar sobre la estructura de la escena, dónde termina un objeto, qué hay detrás, en lugar de copiar textura del parche vecino, que es lo que pasa si el hueco es minúsculo. flowchart LR A["Imagen dividida en parches"] --> B["Bloque de contexto visible"] A --> C["Bloques objetivo ocultos"] B --> D["Codificador de contexto"] C --> E["Codificador objetivo"] D --> F["Predictor predice embeddings de C"] E --> G["Embeddings reales de C"] F --> H["Comparar con perdida L2"] G --> H V-JEPA extiende la misma idea al tiempo. En vez de ocultar solo una región espacial, oculta bloques que se extienden a lo largo de varios cuadros consecutivos, así el predictor tiene que modelar tanto la estructura de la escena como su evolución, el primer paso hacia lo que Meta llama un modelo de mundo. Ejemplos prácticos: así se ve una predicción de JEPA en código El mecanismo central de JEPA, predecir un embedding a partir de otro, se puede ilustrar con un fragmento mínimo en PyTorch. No es el código real de los repositorios de Meta, es un esqueleto que muestra la forma del problema. import torch import torch.nn as nn class Predictor(nn.Module): def __init__(self, dim=768): super().__init__() self.proj = nn.Linear(dim, dim) def forward(self, context_embedding, mask_tokens): return self.proj(context_embedding + mask_tokens) context_embedding = torch.randn(1, 196, 768) # embeddings del bloque visible mask_tokens = torch.randn(1, 196, 768) # tokens posicionales del bloque oculto predictor = Predictor() predicted_embedding = predictor(context_embedding, mask_tokens) print(predicted_embedding.shape) La salida es torch.Size([1, 196, 768]): un batch, 196 parches (14x14 en una imagen de 224x224 con parches de 16 píxeles) y 768 dimensiones por embedding. Esa misma forma es la que debe tener el embedding objetivo real para poder compararlos con la función de pérdida. El codificador objetivo nunca recibe gradiente directo, solo un promedio móvil exponencial. Cómo empezar con I-JEPA y V-JEPA Para correr el código oficial necesitás Python 3.9 o superior, Git y, para entrenar en serio, una GPU con soporte CUDA. Para solo cargar un checkpoint preentrenado alcanza con CPU, aunque mucho más lento. Los pasos siguientes son para Linux y macOS; en Windows corren igual dentro de WSL. git clone https://github.com/facebookresearch/ijepa.git cd ijepa python -m venv venv source venv/bin/activate pip install -r requirements.txt Para V-JEPA el repositorio es distinto: git clone https://github.com/facebookresearch/jepa.git, seguido de los mismos tres pasos de entorno virtual e instalación. No hay una forma de confirmar la instalación con un solo comando genérico, porque cada repositorio expone su propio script de evaluación. La señal de que todo cargó bien es que ese script termine e imprima la métrica final (la accuracy del linear probe, en el caso de I-JEPA) en vez de interrumpirse con un traceback de dependencias faltantes. JEPA vs. modelos generativos y contrastivos JEPA no es la única forma de aprender sin etiquetas. Comparado con otras dos familias, la diferencia queda más clara. EnfoqueQué prediceVentajaLimitaciónJEPA (I-JEPA, V-JEPA)Embedding de una parte oculta a partir de una parte visibleNo gasta capacidad en detalles irrelevantes; más eficiente en datosNecesita trucos anticolapso (EMA, stop-gradient); no genera contenidoModelos generativos (difusión, autoregresivos de píxeles)Los datos originales completos, pixel por pixel o token por tokenSirven para crear contenido nuevo directamenteMás cómputo y datos para la misma calidad de representaciónAprendizaje contrastivo (SimCLR, CLIP)Si dos vistas vienen de la misma imagen, comparando embeddings completosRepresentaciones robustas sin reconstruir nadaDepende de aumentaciones manuales y bancos grandes de negativosNext-token prediction (LLMs de texto)El siguiente token de una secuenciaEscala muy bien con datos y cómputo en lenguajeEs una JEPA con vistas malas y alinea con otras modalidades solo a gran escala flowchart TD subgraph Generativo["Modelo generativo"] P1["Entrada parcial"] --> P2["Decodificador"] P2 --> P3["Reconstruccion en espacio de pixeles"] end subgraph JEPA["Arquitectura JEPA"] J1["Entrada parcial"] --> J2["Predictor"] J2 --> J3["Prediccion en espacio latente"] end La elección no es ideológica. Si el objetivo final es generar una imagen o un texto, un modelo generativo sigue siendo la herramienta correcta. Si el objetivo es que un sistema entienda una escena para después actuar sobre ella, un robot, un auto autónomo, predecir en espacio latente rinde más por cada muestra de entrenamiento. Casos de uso reales: de la clasificación de imágenes a los modelos de mundo Meta publicó I-JEPA en 2023 como su primer modelo de visión entrenado con esta arquitectura, pensado para tareas de clasificación y segmentación con pocas etiquetas disponibles. El paper original lo mostró compitiendo con modelos contrastivos usando una fracción de su cómputo de entrenamiento. V-JEPA oculta bloques que se extienden en el tiempo, no solo en el espacio. V-JEPA, publicado en 2024, extendió la idea a video para tareas como reconocimiento de acciones y comprensión de movimiento físico. El paper de V-JEPA lo presenta como un paso hacia modelos que entienden causa y efecto en el mundo físico, lo que LeCun describe como "modelos de mundo": sistemas capaces de predecir qué pasa después de una acción sin haber visto exactamente esa secuencia antes. El caso de uso más concreto hoy es el preentrenamiento: entrenar primero con JEPA sobre datos sin etiquetar y después afinar una cabeza pequeña para la tarea final, con muchas menos imágenes o videos etiquetados que los que necesitaría un modelo entrenado desde cero. Errores comunes y buenas prácticas El error más citado en la literatura de aprendizaje autosupervisado es el colapso representacional: el modelo aprende a producir el mismo embedding para cualquier entrada, minimizando la pérdida sin aprender nada útil. JEPA lo evita con la asimetría entre codificadores, pero esa asimetría no es automática. Si el codificador objetivo se actualiza demasiado rápido (un EMA con momentum bajo) o demasiado lento, el riesgo de colapso vuelve. Otro error común es confundir JEPA con aprendizaje contrastivo. SimCLR y CLIP necesitan pares negativos, ejemplos que NO deben parecerse, y aumentaciones de datos cuidadosamente diseñadas. I-JEPA y V-JEPA no usan negativos explícitos; la asimetría arquitectónica hace ese trabajo. > ⚠️ Ojo: La limitación real, y la razón por la que JEPA no reemplaza a los modelos generativos, es que sus embeddings no sirven para generar contenido directamente. Si el proyecto necesita un generador de imágenes o un chatbot, un modelo generativo sigue siendo la pieza correcta. Profundizando: la hipótesis platónica y el teorema de representación El resultado más fuerte del paper de Balestriero y LeCun es lo que llaman el teorema de representación platónica. Los autores demuestran que dos JEPA entrenadas por separado sobre modalidades distintas, texto e imagen, por ejemplo, convergen a la misma representación salvo una rotación, siempre que sus pares positivos sean "vistas buenas", dos observaciones reales de la misma escena. Con vistas malas, fragmentos arbitrarios de un documento, la convergencia tiene un límite acotado pero no desaparece. La consecuencia práctica, no solo teórica, es que esa rotación se puede calcular sin reentrenar nada. Los autores tomaron un encoder de texto y un encoder de imagen entrenados por separado, calcularon la rotación que los alinea y construyeron un generador de descripciones que obtuvo un CIDEr de 0,838 en COCO, sin que los dos encoders hubieran visto jamás un par imagen-texto durante el entrenamiento. En un benchmark sin pares, ese mismo text JEPA superó el zero-shot de todos los modelos de lenguaje evaluados hasta 8.000 millones de parámetros, con 64% contra un máximo de 56% top-5 en ImageNet-100. Esto no significa que la arquitectura JEPA resuelva la hipótesis platónica de LeCun por completo. El propio paper aclara que el límite de desalineación depende de qué tan "buena" sea la vista, y construir vistas buenas para cada modalidad nueva, audio, sensores de robots, sigue siendo un problema de diseño abierto, no una receta universal. 📖 Resumen en Telegram: Ver resumen Tu próximo paso: cloná el repositorio de I-JEPA, cargá un checkpoint preentrenado y corré el script de linear probing sobre un dataset chico propio para ver cuántas etiquetas necesitás realmente para una accuracy aceptable. Preguntas frecuentes ¿La arquitectura JEPA reemplaza a los transformers generativos? No. JEPA resuelve el problema de aprender representaciones sin etiquetas; los transformers generativos siguen siendo la herramienta cuando el objetivo final es producir texto, imagen o audio nuevo. Son complementarios, no rivales directos. ¿Qué diferencia a I-JEPA de V-JEPA? I-JEPA trabaja sobre imágenes estáticas y oculta bloques espaciales de parches. V-JEPA extiende la idea a video, ocultando bloques que se extienden en el tiempo para que el modelo aprenda también la dinámica de una escena. ¿JEPA necesita pares negativos como el aprendizaje contrastivo? No. SimCLR y CLIP comparan pares positivos contra negativos explícitos. I-JEPA y V-JEPA evitan el colapso con la asimetría entre el codificador de contexto y el codificador objetivo, sin necesitar negativos. ¿Por qué next-token prediction alinea peor con la visión, según el paper de LeCun? Porque sus pares de entrenamiento son fragmentos de un mismo documento de texto, no dos observaciones reales de una escena compartida. El paper lo describe como una JEPA con "vistas malas", y por eso necesita mucha más escala para alinear con modelos de imagen. ¿Se puede usar JEPA para texto, no solo para imágenes y video? Sí. El propio paper de Balestriero y LeCun entrena un text JEPA de 109 millones de parámetros con vistas positivas y lo compara directamente contra modelos de lenguaje de hasta 72.000 millones de parámetros. ¿JEPA sirve para generar imágenes o video nuevo? No directamente. Sus embeddings describen una escena, pero no están pensados para reconstruir píxeles. Generar contenido nuevo a partir de esos embeddings requiere acoplar un decodificador o un modelo generativo aparte. Referencias - Balestriero y LeCun, "Proving and Improving the Platonic Representation Hypothesis with JEPAs" (arXiv, 2026): el paper que motiva este artículo.- Assran et al., "Self-Supervised Learning from Images with a Joint-Embedding Predictive Architecture" (arXiv, 2023): el paper original de I-JEPA.- Bardes et al., "V-JEPA: Video Joint-Embedding Predictive Architecture for Self-Supervised Visual Learning" (arXiv, 2024): el paper original de V-JEPA.- Repositorio oficial de I-JEPA en GitHub: código y checkpoints preentrenados.- Repositorio oficial de V-JEPA en GitHub: código y checkpoints preentrenados. 📱 ¿Te gusta este contenido? Únete a nuestro canal de Telegram @programacion donde publicamos a diario lo más relevante de tecnología, IA y desarrollo. Resúmenes rápidos, contenido fresco todos los días.
PDFを翻訳するとレイアウトが崩れる理由と確認すべき4か所 本記事はEqualangチームが執筆しています。Wordファイルと異なり、大半のPDFは「どの単語が段落を構成し、どの単語が表に属しているか」という構造情報を保持していません。PDFが持っているのは文字と、その文字を描画する座標だけです。 二段組の段組み、複数列にまたがる見出し、次ページへと続く文章といった構造に見えるものはすべて、翻訳の前に組み直す必要があります。そのうえで、長さが変わった訳文を元のレイアウトに収め直さなければなりません。書式が崩れるのは、この「構造解析」と「再配置」の2つの工程のどこかです。 手元にあるドキュメントに応じた適切な選択肢は以下の通りです: 元の .docx や .pptx がある場合:PDFではなく元ファイルを翻訳するのが確実です。 表の少ない文字中心のPDF(10 MB未満):Google 翻訳のドキュメントアップロード機能などが手軽な選択肢になります。 表・数式・二段組を含む論文やマニュアル:レイアウトを再構築する専門ツールを選び、後述する4か所のポイントを確認してください。 文字選択ができないスキャンPDF:翻訳の前に文字認識(OCR)が必要です。DeepLなどはスキャンデータを受け付けてOCRも自前で処理しますが、Google 翻訳ではスキャンページが未翻訳のまま残る場合があります。 1. 翻訳ツールはPDFの中に何を見ているのか 版面(レイアウト)を読み取らない一般的なツールがどのようなテキストを翻訳の材料にしているのか、具体的な例を見てみます。ここでは arXiv の論文2本(LLaMA および Mistral 7B)を用意し、オープンソースPDFツール MuPDF の mutool でテキストを抽出しました。 1.1 表は単なる数字の列に分解される LLaMA 論文の表3(10個のモデルを8つのテストで比較した表)を例にとります。 これをテキスト抽出すると、102行の連続した文字列に変わります。 BoolQ PIQA SIQA HellaSwag WinoGrande ARC-e ARC-c OBQA GPT-3 175B 60.5 81.0 - 78.9 70.2 68.8 51.4 57.6 Gopher どの数値がどのテストに対応しているかをツールに伝える手がかりは失われます。これをそのまま翻訳ボックスに貼り付けても表構造は復元されず、単語は翻訳されても表そのものは消えてしまいます。 1.2 文の途中に表全体が割り込む LLaMA 論文3ページの右欄末尾は "we need to" で途切れています。 続きは4ページ左欄、表3を挟んだ下部にあります。 抽出されたテキストストリームでは、文の途中に脚注や改ページ、表3の102行とそのキャプションがすべて割り込んでいます。 To fully benefit from this optimization, we need to 2facebookresearch/xformers BoolQ PIQA … Table 3: Zero-shot performance on Common Sense Reasoning tasks. reduce the memory usage of the model by using ページごとや抽出順のまま翻訳するツールでは、この離れた2つの断片をつなぎ合わせることができません。結果として、ページ下部で切れた文と、表の下に唐突に現れる文の後半が別々に翻訳されます。 1.3 添字と分数が別文字に化ける Mistral 論文の変数 h_i(添字 i 付きの変数)を抽出すると、添字情報が失われて単なる英単語 hi に変化します。 former to attend information beyond the window size W. The hidden state in position i of the layer k, hi, attends to all hidden states from ツールにとって hi は一般的な英語単語と区別がつきません。 さらに複雑なのが分数です。LLaMA 論文のある箇所では、4d の 3分の2(\frac{2}{3}\cdot 4d)という重ね組みの分数が書かれています。 improve the performance. We use a dimension of 2 34d instead of 4d as in PaLM. 4d の 3分の2 が 34d に変わってしまっています。上付き・下付き文字や分数記号は描画位置情報に依存しているため、座標を考慮しない抽出では全く異なる値になってしまいます。 1.4 単語が行末ハイフネーションで分断される 二段組の論文では行末での単語分割が多く発生します。LLaMA 論文では、ハイフンで分割された一般単語が242行にのぼります。 We introduce LLaMA, a collection of founda- tion language models ranging from 7B to 65B … (175B) on most benchmarks, and LLaMA- 65B is competitive with the best models, founda- と tion はハイフンを外して1つの単語につなぎ直す必要がありますが、LLaMA- と 65B の間のハイフンはモデル名の一部として保持しなければなりません。 2. どのような選択肢があるか 選択肢 長所 限界 翻訳ボックスにコピー&ペースト 手軽に即座に試せる 表、数式、レイアウトが失われ、文が途中で切れることも多い Google 翻訳の「ドキュメント」タブ 手軽に利用可能。.docx、.pdf、.pptx、.xlsx に対応 10 MB・300ページ上限。画像内文字やスキャンページは翻訳対象外。小型画面非対応 DeepL のファイル翻訳 Web版・デスクトップ版・API対応。スキャン対応。特定プランで編集可能 .docx 出力可能 アカウントが必要。プランごとに翻訳ファイル数の上限あり。CAD出力PDF等は非対応 Word に変換してから翻訳する 翻訳前に Word 上で修正・調整が可能 PDFからWord変換時に生じた誤りや崩れがそのまま残る レイアウトを再構築する翻訳ツール 表、数式、分割された文を構造として扱う 元ファイルと完全に同一にはならず、テキスト長の変化による改行やフォント調整が生じる ※ Google 翻訳と DeepL についての記述は、各サービスの公式ヘルプページ(2026年10月7日確認時点)に基づきます。 私たちが開発している Equalang のドキュメント翻訳は、まさにこの「レイアウト再構築型」のアプローチをとっています。ページの切れ目で分割された文をつなぎ直し、結合セルや複数行ヘッダーを持つ表も構造を保ちながら再構築します。数式最適化オプションも用意しており、日本語、英語、中国語、韓国語、スペイン語、フランス語などに対応しています。 なお、Equalangは新規登録で200クレジットが付与されるため、手元のPDFで実際の再現性を確認していただけます。 3. PDFを翻訳したら確認すべき4つのポイント どのようなツールを用いた場合でも、翻訳後には以下の4か所を確認することをおすすめします。 表の整合性:ヘッダー行が対応する列の上にあるか、数値が変わっていないか。 改ページ部と表の下のテキスト:ページ下部や表の直後で文が途切れたままになっていないか。 数式と変数:文中の記号が英単語に化けていないか、分数が別の数字になっていないか。 ページ数とリンク:ページ数が不自然に増減していないか、目次リンクが正常に動作するか。 参考資料 Touvron et al., "LLaMA: Open and Efficient Foundation Language Models", arXiv:2302.13971v1, CC BY 4.0. Jiang et al., "Mistral 7B", arXiv:2310.06825v1, CC BY 4.0. Google 翻訳 ヘルプ, Translate documents & websites, 2026年10月7日確認. DeepL ヘルプセンター, Translate PDF files, 2026年10月7日確認. 実測方法: テキストは2026年10月7日に MuPDF 1.25.6 で抽出(コマンド mutool draw -q -F txt -o out.txt in.pdf)。図は論文ページの切り抜きで、強調は筆者が入れたものです。
SAM 2: Put Text Behind Moving People | GitHub Repos You Should Know #022 Put text behind a moving person, then keep that person in colour. Both edits use actual masks from our local SAM 2 test. Project: facebookresearch/sam2 Classification: Worth Knowing We gave SAM 2.1 Hiera Small one positive point on the first frame of a six-second clip. It tracked the person across 90 frames, without manual mask corrections. SAM 2 produces selections; our compositor adds the text and selective-colour effects. The same test is replayed in different explanatory views. Hair, fingers and foreground occlusions need checking. This is not a perfect-matting claim. This is an established project, not a new-release or active-maintenance claim. Footage: Mixkit, Woman Dancing and Mopping Her Living Room (101054), Stock Video Free License. mixkit.co SAM 2 code/checkpoint: Apache 2.0; see the project licence. #OpenSource #GitHub #SAM2 #VideoEditing