メインコンテンツまでスキップ

Nougatモデルとは?

処理フロー
(画像は、Google AI Studioの「Nano Banana 2」モデルを用いて作成されたものです)

Nougatモデルの概要

Nougatモデルは2023年にMeta AIが開発した学術ドキュメント向けの視覚的言語モデル(VLM)で、PDFやスキャンされた文書を画像として読み取り、Markdown形式やLaTex形式に変換することができます。2022年に発表されたNaverのDonutモデルをベースに構築されており、DonutがレシートなどからJSON形式の構造化データを出力するモデルであるのに対して、Nougatはインラインの数式やブロック数式、表などをMarkdown形式で出力することができます。論文は"Nougat: Neural Optical Understanding for Academic Documents"です。

Nougatモデルの学習にはarXiv (約751万ページ)やPubMed Central (PMC) (約54万ページ)、Industry Documents Library (IDL) (約45万ページ)が用いられており、arXivでは、LaTexソースコードとPDFのペアを用いて学習を行っています。学習データはLaTexソースをHTMLに変換し、その後Markdown形式に変換するパイプラインを通じて学習データを作成しています。このプロセスによって複雑な数式や表を効率的に学習することが可能となっています。

Nougatモデルの処理概要

ブロック図
(画像は、Geminiを用いて作成されたものです)

NougatモデルはDonutモデルをベースとしており、基本的なアーキテクチャは同じです。入力画像に対してリサイズや正規化などの前処理を行った後、Swin Transformer EncoderでSelf-Attention処理を行い出力されます。一方で、ユーザーのプロンプトはBART Decoderに入力されて埋め込みベクトルに変換されます。その後、同じBART Decoder内で、Swin Transformerによって画像から抽出されたベクトル群とCross-Attentionを行い、トークンを順次生成することでMarkdownデータを出力します。

さらに詳しくNougatモデルの処理を理解するために、コードサンプルを用いて確認してみましょう。

サンプル画像読み込みコード

モデルの学習・評価にはIM2LATEX-100Kのデータセットを用います。 IM2LATEX-100Kは、ハーバード大学のYuntian Deng氏らがOpenAIの「Request for Research(研究リクエスト)」にこたえる形で、arXiv上のオープンアクセス論文から抽出・構築したデータセットです。(参考論文:"Image-to-Markup Generation with Coarse-to-Fine Attention")

データセットの利用ライセンスについて

本記事で使用する「IM2LATEX-100K」データセットは、パブリックドメイン(CC0)ライセンスの下で提供されており、クレジット表記不要で営利・非営利を問わず自由に利用可能です。

IM2LATEX-100Kデータセットは、CC0: Public Domain ライセンスの下で提供されています。

IM2LATEX-100KのデータセットはHugging Faceのdatasetsライブラリから簡単にダウンロードすることができます。

from datasets import load_dataset
import matplotlib.pyplot as plt

# Hugging Faceから 'yuntian-deng/im2latex-100k'をロード
dataset = load_dataset("yuntian-deng/im2latex-100k")


# 訓練セットの最初のサンプルを取得
sample_idx = 0

sample = dataset["train"][sample_idx]
raw_image = sample["image"] # PIL Image オブジェクト
latex_formula = sample["formula"] # 正解のLaTeX文字列

# 4. 画像の可視化
fig, ax = plt.subplots(figsize=(8, 10))
ax.imshow(raw_image)
ax.axis("off") # 軸の目盛りを消す
ax.set_title(f"im2latex-100k Train Sample #{sample_idx}", fontsize=14)
plt.show()

print(f"正解データ:LaTeX数式")
print(latex_formula)

上記のコードを実行すると数式の画像sample["image"]と正解のLaTex数式データsample["formula"]が表示されます。

dataset["train"]のインデックス0のsample["image"]

サンプル画像

dataset["train"]のインデックス0のsample["formula"]

正解データ:LaTeX数式
\widetilde \gamma _ { \mathrm { h o p f } } \simeq \sum _ { n > 0 } \widetilde { G } _ { n } { \frac { ( - a ) ^ { n } } { 2 ^ { 2 n - 1 } } }

Nougatはsample["image"] の画像を入力し、sample["formula"]のMarkdownを出力できるようにモデルを学習します。

Nougatモデルの実装(概念的なシンプルな実装)

実際のNougatモデルは上述のようにEncoderにはSwinEncoder、DecoderにはBART Decoderを用いていますが、 Nougatモデルの原理を理解するためにSwinEncoderをPyTorchのnn.TransformerEncoder、BART Decoderの代わりにnn.TransformerDecoderに置き換えてモデルを0から学習・評価してみましょう。

Nougat Encoderの実装

まずはEncoderをシンプルなTransformer Encoder(PyTorchのnn.TransformerEncoderを利用)で実装してみます。

import torch
import torch.nn as nn


class SimpleNougatEncoder(nn.Module):
def __init__(self, hidden_dim=128, num_layers=2, nhead=4, max_seq_len=1024):
super().__init__()
# 数式画像は横長(例: 幅320px、高さ64px)が多いため、パッチサイズ16x16で分割
self.patch_embed = nn.Conv2d(in_channels=3, out_channels=hidden_dim, kernel_size=16, stride=16)
self.pos_embed = nn.Parameter(torch.randn(1, max_seq_len, hidden_dim))
encoder_layer = nn.TransformerEncoderLayer(d_model=hidden_dim, nhead=nhead, batch_first=True)
self.transformer_encoder = nn.TransformerEncoder(encoder_layer, num_layers=num_layers)

def forward(self, x):
x = self.patch_embed(x)
x = x.flatten(2).transpose(1, 2)
seq_len = x.size(1)
x = x + self.pos_embed[:, :seq_len, :]
return self.transformer_encoder(x)

SimpleNougatEncoderでは、self.patch_embedというnn.Conv2d層を用いて、入力画像を16×16のパッチに分割し、特徴量を抽出しています。kernel_size=16, stride=16と設定することで、重なりのないパッチ画像を作成し、それをhidden_dim次元のベクトルへと投影しています。

forwardメソッドでは、まず画像データxを受け取り、self.patch_embed(x)によってパッチ分割を行います。この時点でのテンソル形状は(batch_size, hidden_dim, patch_height, patch_width)となりますが、これをx.flatten(2).transpose(1, 2)で変換することで、Transformerが扱える(batch_size, パッチ数, hidden_dim)の形式に整形しています。

さらに、入力画像内での各パッチの相対的な位置情報を与えるため、self.pos_embedから位置エンコーディングを加算しています。最後に、これらの情報をself.transformer_encoderに入力することで、画像パッチ間でのSelf-Attentionを実行し、文書の視覚的な特徴を相互に考慮したコンテキスト表現を抽出しています。

Nougat Decoderの実装

次にDecoderをTransformer Decoder(PyTorchのnn.TransformerDecoderを利用)で実装してみます。

## nn.TransformerDecoderによるシンプルなNougat Decoderの実装
class SimpleNougatDecoder(nn.Module):
def __init__(self, vocab_size, hidden_dim=128, max_seq_len=1024):
super().__init__()
self.embedding = nn.Embedding(vocab_size, hidden_dim)
self.pos_embed = nn.Parameter(torch.randn(1, max_seq_len, hidden_dim))
self.decoder_layer = nn.TransformerDecoderLayer(d_model=hidden_dim, nhead=4, batch_first=True)
self.transformer_decoder = nn.TransformerDecoder(self.decoder_layer, num_layers=2)
self.lm_head = nn.Linear(hidden_dim, vocab_size)

def forward(self, input_ids, encoder_hidden_states):
seq_len = input_ids.size(1)
device = input_ids.device
tgt_embed = self.embedding(input_ids)
tgt_embed = tgt_embed + self.pos_embed[:, :seq_len, :]

tgt_mask = torch.full((seq_len, seq_len), float('-inf'), device=device)
tgt_mask = torch.triu(tgt_mask, diagonal=1)

decoder_outputs = self.transformer_decoder(
tgt=tgt_embed, memory=encoder_hidden_states, tgt_mask=tgt_mask
)
return self.lm_head(decoder_outputs)

SimpleNougatDecoderでは、Encoderで抽出された画像特徴を受け取り、Markdown形式のテキストを生成するためのTransformer Decoderを構築しています。

forwardメソッドでは、生成途中のトークン列input_idsと、Encoderの出力であるencoder_hidden_statesを引数に取ります。まず、self.embeddingself.pos_embedを用いて、トークンIDをベクトル化し、位置情報を付与しています。

デコーダーにおける重要な要素として、tgt_mask(因果マスク)の生成があります。torch.triuを使用して上三角行列を作成し、-infで埋めることで、予測対象のトークンが自分自身より未来のトークンを「カンニング」できないように制御しています。

実際の推論はself.transformer_decoderで行われます。ここでは、ターゲットとなるトークン列tgt内でのSelf-Attentionに加え、memory=encoder_hidden_statesを介して画像特徴とのCross-Attentionが実行されます。これにより、画像内のどの領域が現在の生成トークンに対応するかをモデルが学習します。最後に、self.lm_head(線形層)を通じて、ボキャブラリサイズに応じたロジットを出力し、次のトークンの出現確率を予測します。

Nougatモデルの実装

EncoderとDecoderの定義が完了したため、これらを組み合わせた最終的なNougatモデルを実装してみましょう。

class ConceptualNougatModel(nn.Module):
def __init__(self, vocab_size, pad_token_id):
super().__init__()
self.encoder = SimpleNougatEncoder()
self.decoder = SimpleNougatDecoder(vocab_size)
self.loss_fn = nn.CrossEntropyLoss(ignore_index=pad_token_id)

def forward(self, image_tensors, decoder_input_ids, decoder_labels):
encoder_outputs = self.encoder(image_tensors)
logits = self.decoder(input_ids=decoder_input_ids, encoder_hidden_states=encoder_outputs)
loss = self.loss_fn(logits.view(-1, logits.size(-1)), decoder_labels.view(-1))
return loss

def generate(self, image_tensors, start_prompt_id, eos_id, max_length=150):
encoder_outputs = self.encoder(image_tensors)
generated_ids = [start_prompt_id]

for _ in range(max_length):
input_ids = torch.tensor([generated_ids]).to(image_tensors.device)
logits = self.decoder(input_ids, encoder_outputs)
next_token_id = torch.argmax(logits[0, -1, :]).item()
generated_ids.append(next_token_id)
if next_token_id == eos_id:
break
return generated_ids

ConceptualNougatModelは、これまでに定義したSimpleNougatEncoderSimpleNougatDecoderを統合したEnd-to-Endのモデルです。

forwardメソッドは学習時に使用され、効率的な学習のために「Teacher Forcing」を採用しています。画像から抽出したencoder_outputsと、正解ラベルを一つずらしたdecoder_input_idsをデコーダーに渡すことで、モデルは「前のトークンが正解だった場合、次のトークンは何か」を学習します。損失関数にはnn.CrossEntropyLossを使用し、ignore_index=pad_token_idを指定することでパディングトークンに対する損失計算をスキップしています。

一方、generateメソッドは推論(テキスト生成)時に使用されます。こちらは「自己回帰的(Auto-regressive)」なプロセスとなっており、最初に出力開始トークン(start_prompt_id)を与え、モデルが予測した直前のトークンを次のステップの入力として繰り返しフィードします。torch.argmaxを用いて最も確率の高い次のトークンを選択し、終了トークン(eos_id)が出現するか、最大長(max_length)に達するまで生成を継続します。

Nougatモデルの学習と予測

最後にConceptualNougatModelを用いた学習及び予測の処理を実装します。

import torch.optim as optim
from torchvision import transforms
from transformers import NougatProcessor


# 本物のNougatトークナイザーをロード
processor = NougatProcessor.from_pretrained("facebook/nougat-base")
tokenizer = processor.tokenizer
vocab_size = len(tokenizer)

# LaTeX文字列のトークンID化
tokens = tokenizer.encode(latex_formula)

# デバイス設定
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

model = ConceptualNougatModel(vocab_size=vocab_size, pad_token_id=tokenizer.pad_token_id)
model.to(device)
optimizer = optim.AdamW(model.parameters(), lr=5e-4)

# 数式画像用の前処理(横長のアスペクト比にリサイズしてテンソル化)
transform = transforms.Compose([
transforms.Resize((64, 320)), # IM2LATEX標準の数式サイズ感に合わせる
transforms.ToTensor(),
transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])
])

# PIL画像をRGBに変換してから前処理を適用(バッチ次元を追加)
image_tensor = transform(raw_image.convert("RGB")).unsqueeze(0).to(device)
tokens_tensor = torch.tensor(tokens).unsqueeze(0).to(device)

# Teacher Forcing用の入出力ペア
decoder_input_ids = tokens_tensor[:, :-1]
decoder_labels = tokens_tensor[:, 1:]


model.train()
epochs = 200
print("モデルの学習開始")

for epoch in range(1, epochs + 1):
optimizer.zero_grad()
loss = model(image_tensor, decoder_input_ids, decoder_labels)
loss.backward()
optimizer.step()

if epoch % 20 == 0 or epoch == 1:
print(f"Epoch {epoch:03d}/{epochs} - Loss: {loss.item():.4f}")
print("学習完了")

print("モデル評価")
model.eval()

with torch.no_grad():
predicted_ids = model.generate(
image_tensors=image_tensor,
start_prompt_id=tokenizer.bos_token_id,
eos_id=tokenizer.eos_token_id,
max_length=len(tokens) + 10
)

# 特殊トークンを除外してテキストに復元
predicted_latex = tokenizer.decode(predicted_ids, skip_special_tokens=True)
target_latex = tokenizer.decode(tokens, skip_special_tokens=True)

print("【モデルの予測結果】")
print(target_latex)
print("【本来の正解データ")
print(predicted_latex)

if predicted_latex.strip() == target_latex.strip():
print("予測と正解データが一致しました。")
else:
print("予測と正解データが一致しませんでした。")

ここでは、構築したカスタムモデルを実際に動かすための学習および評価パイプラインを実装しています。

まず、トークナイザーとして公式のfacebook/nougat-baseNougatProcessorを利用しています。これにより、モデルが扱うボキャブラリと、今回のLaTex数式データを共通のトークンID体系で管理できます。画像の前処理にはtorchvision.transformsを使用し、数式画像に適した(64, 320)サイズへのリサイズと、ピクセル値の正規化(-1.0〜1.0)を行っています。

学習ループでは、最適化アルゴリズムとしてAdamWを採用し、epochs = 200の反復計算を行っています。各エポックでmodel.forwardを呼び出し、予測ロジットとターゲットラベルの間の誤差(Loss)を最小化するように重みを更新します。

学習完了後、model.eval()モードに切り替えて、model.generateによる推論テストを実施します。得られたトークンIDのリストをtokenizer.decodeで元のテキストに復元し、skip_special_tokens=Trueを指定することで、学習に使用したボキャブラリに基づいた純粋なLaTex文字列として結果を確認できます。最後に予測結果と正解データを比較し、モデルが数式画像を正しくMarkdown(LaTex)形式へと変換できているかを検証しています。

モデルが正しく学習されると、以下のようにクロスエントロピー誤差がepochとともに減少します。 今回は動作の理解のため学習に用いた訓練サンプルのMarkdownの結果と予測結果が一致するかを確認すると、一致することが確認できた。

モデルの学習開始
Epoch 001/200 - Loss: 10.8126
Epoch 020/200 - Loss: 5.6297
Epoch 040/200 - Loss: 2.7499
Epoch 060/200 - Loss: 1.0036
Epoch 080/200 - Loss: 0.3588
Epoch 100/200 - Loss: 0.1623
Epoch 120/200 - Loss: 0.1013
Epoch 140/200 - Loss: 0.0728
Epoch 160/200 - Loss: 0.0572
Epoch 180/200 - Loss: 0.0474
Epoch 200/200 - Loss: 0.0392
学習完了
モデル評価
【モデルの予測結果】
\widetilde \gamma _ { \mathrm { h o p f } } \simeq \sum _ { n > 0 } \widetilde { G } _ { n } { \frac { ( - a ) ^ { n } } { 2 ^ { 2 n - 1 } } }
【本来の正解データ
\widetilde \gamma _ { \mathrm { h o p f } } \simeq \sum _ { n > 0 } \widetilde { G } _ { n } { \frac { ( - a ) ^ { n } } { 2 ^ { 2 n - 1 } } }
予測と正解データが一致しました。

実際のHugging Faceモデルを用いた推論テスト

ここまではNougatモデルの仕組みを理解するためにシンプルな概念モデルをゼロから構築してきましたが、実際の開発ではHugging Faceのtransformersライブラリを利用することで、すでに学習済みの強力なモデルを数行のコードで呼び出すことができます。

モデルの概念説明ではIM2LATEX-100Kのデータセットを用いましたが、Hugging FaceのNougatのモデルではIM2LATEX-100Kの数式から正しいマークダウンを予測することができません。 Nougatモデルは、論文の「縦長1ページ丸ごと(A4やレターサイズ)」を入力として受け取ることを前提に設計・学習されています。モデルの内部では、入力された画像を 896 x 672(縦長アスペクト比 約4:3) の固定サイズに変換して処理します。一方で、IM2LATEX-100Kの画像: 数式1行だけが切り取られた「極端な横長」(例: 320x64、アスペクト比 5:1)であり、これをNougatの入力サイズ 896x672(縦長)に無理やりはめ込もうとすると、横方向がギュッと潰れ、縦方向に異常に引き伸ばされてしまいます。文字や \sum などの記号の形が完全に歪んでしまうため、Nougatの目(Swin Transformer)が形を認識できず、予測が完全に破綻しまいます。このため本記事では、A4サイズのPDFのサンプルとしてPMCから、論文をダウンロードしたものを用いて予測を行います。

以下のコードでは、テストデータセットの画像を入力し、実際のNougatモデルがどのようにMarkdownをを抽出するかを確認します。

サンプル論文の利用ライセンスについて

本推論テストで使用するサンプル論文PDFは、クリエイティブ・コモンズ(CC BY 4.0)ライセンスの下で提供されています。ライセンス要件に従い、適切なクレジット表記が必要となります。詳細は記事の末尾に記載しています。

import pypdfium2 as pdfium
import torch
from PIL import Image
from transformers import VisionEncoderDecoderModel, NougatTokenizerFast
from torchvision import transforms


device = "cuda" if torch.cuda.is_available() else "cpu"
model_id = "facebook/nougat-base"


print("モデルとトークナイザーの読み込み")
tokenizer = NougatTokenizerFast.from_pretrained(model_id)
model = VisionEncoderDecoderModel.from_pretrained(model_id).to(device)
model.eval()


# PDFをPIL画像に変換する関数(scale=2に設定することで、数式や細かい文字をクリアにレンダリング)
def convert_pdf_page_to_image(pdf_path, page_idx=0, scale=2):
pdf = pdfium.PdfDocument(pdf_path)
if page_idx >= len(pdf):
raise ValueError(f"指定されたページ番号 {page_idx} はPDFの総ページ数({len(pdf)}ページ)を超えています。")

page = pdf[page_idx]
bitmap = page.render(scale=scale)
pil_img = bitmap.to_pil()
return pil_img.convert("RGB")


nougat_transform = transforms.Compose([
transforms.Resize((896, 672)), # Nougatの規定入力サイズ (height, width)
transforms.ToTensor(),
transforms.Normalize(
mean=[0.485, 0.456, 0.406], # 標準的な輝度平均
std=[0.229, 0.224, 0.225] # 標準偏差
)
])

# ※検証に用いるPMCのpdfファイル
# 論文名: Machine learning in medicine: a practical introduction
# 著者: Jenni A. M. Sidey-Gibbons and Chris J. Sidey-Gibbons
# 出典: BMC Medical Research Methodology (2019) 19:64 (https://doi.org/10.1186/s12874-019-0681-4)
# ライセンス: 本論文は [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/deed.ja) ライセンスの下で公開されており、原著作者のクレジットを表示することで複製・再配布が許可されています。
pdf_filename = "12874_2019_Article_681.pdf"

# 論文の「1ページ目(インデックス0)」を画像化
image = convert_pdf_page_to_image(pdf_filename, page_idx=0, scale=2)

# テンソル化、バッチ次元の追加
pixel_values = nougat_transform(image).unsqueeze(0).to(device)

print(f"『{pdf_filename}』を解析...")

with torch.no_grad():
outputs = model.generate(
pixel_values,
min_length=1,
max_new_tokens=2000, # 1ページ全体の文章と数式を出力するため長めに設定
decoder_start_token_id=tokenizer.bos_token_id,
eos_token_id=tokenizer.eos_token_id,
pad_token_id=tokenizer.pad_token_id,
)

# トークン列をMarkdownテキストに直接デコード
predicted_markdown = tokenizer.batch_decode(outputs, skip_special_tokens=True)[0]
print("解析結果")
print(predicted_markdown)

まず、NougatTokenizerFastVisionEncoderDecoderModel を用いて、Meta AIが公開している事前学習済みモデル facebook/nougat-base をロードしています。Nougatはモデルサイズが大きいため、.to(device) でGPU(利用可能な場合)に転送して高速化を図っています。

PDFの処理には pypdfium2 を使用したカスタム関数 convert_pdf_page_to_image を定義しています。Nougatは画像を直接入力として受け取るため、PDFをレンダリングして画像化する必要があります。ここでは scale=2 とすることで、数式などの細かい部分を潰さずに高精細な画像として抽出しています。

画像の前処理を担う nougat_transform では、transforms.Resize((896, 672)) によってNougatが学習時に使用した規定の縦長アスペクト比にリサイズしています。前述の通り、このサイズを誤ると数式などの認識精度が著しく低下するため、非常に重要な工程です。

推論を実行する model.generate では、max_new_tokens=2000 と長めに設定することで、1ページ全体の膨大なテキストと複雑な数式を一度にMarkdown形式で生成させています。最後に tokenizer.batch_decode を実行することで、モデルが出力したトークン列を、数式(LaTeX)や構造化された文章(Markdown)へと復元しています。

上記のコードを実行すると以下の結果が得られ、論文の記述内容とモデルによって読み取られた内容が一致することを確認できます。

『12874_2019_Article_681.pdf』を解析...
解析結果
# Machine learning in medicine: a practical introduction

Jenni A. M. Sidey-Gibbons

# Abstract

**Background:** Following visible successes on a wide range of predictive tasks, machine learning techniques are attracting substantial interest from medical researchers and clinicians. We address the need for capacity development in this area by providing a conceptual introduction to machine learning alongside a practical guide to developing and evaluating predictive algorithms using freely-available open source software and public domain data.

**Methods:** We demonstrate the use of machine learning techniques by developing three predictive models for cancer diagnosis using descriptions of nuclei sampled from breast masses. These algorithms include regularized General Linear Model regression (GLMs), Support Vector Machines (SVMs) with a radial basis function kernel, and single-layer Artificial Neural Networks. The publicly-available dataset describing the breast mass samples (\(N=683\)) was randomly split into evaluation (\(n=456\)) and validation (\(n=227\)) samples.

We trained algorithms on data from the evaluation sample before they were used to predict the diagnostic outcome in the validation dataset. We compared the predictions made on the validation datasets with the real-world diagnostic decisions to calculate the accuracy, sensitivity, and specificity of the three models. We explored the use of averaging and voting ensembles to improve predictive performance. We provide a step-by-step guide to developing algorithms using the open-source R statistical programming environment.

**Results:** The trained algorithms were able to classify cell nuclei with high accuracy (94 - 96), sensitivity (97 - 99), and specificity (85 - 94). Maximum accuracy (96) and area under the curve (97) was achieved using the SVM algorithm. Prediction performance increased marginally (accuracy=97, sensitivity = 99, specificity = 95) when algorithms were arranged into a voting ensemble.

**Conclusions:** We use a straightforward example to demonstrate the theory and practice of machine learning for clinicians and medical researchers. The principals which we demonstrate here can be readily applied to other complex tasks including natural language processing and image recognition.

**Keywords:** Medical informatics, Classification, Supervised machine learning, Programming languages, Diagnosis, Computer-assisted, Decision making, Computer-assisted

## Background

Driven by an increase in computational power, storage, memory, and the generation of staggering volumes of data, computers are being used to perform a wide-range of complex tasks with impressive accuracy. Machine learning (ML) is the name given to both the academic discipline and collection of techniques which allow computers to undertake complex tasks. As an academic discipline, ML comprises elements of mathematics, statistics, and computer science. Machine learning is the engine which is helping to drive advances in the development of artificial intelligence. It is impressively employed in both academia and industry to drive the development of 'intelligent products' with the ability to make accurate predictions using diverse sources of data [1]. To date, the key beneficiaries of the 21st century explosion in the availability of big data, ML, and data science have been industries which were able to collect these data and hire

12874_2019_Article_681.pdfの1ページ目(抜粋) テスト画像

まとめ

本記事では、学術ドキュメントの視覚的理解に特化したNougatモデルについて、その背景から実装までを詳しく解説しました。

記事を通じて、以下の内容を学習・実践しました。

  • Nougatモデルのアーキテクチャ: Donutモデルを継承し、Swin Transformer(Encoder)とBART(Decoder)を組み合わせることで、画像から直接MarkdownやLaTeXを出力する仕組みを理解しました。
  • データセットと学習背景: arXivなどの膨大な学術リソースを活用し、複雑な数式や表を効率的に学習している点を確認しました。
  • 概念モデルの実装: PyTorchを用いて、パッチ分割や位置エンコーディング、Cross-Attentionを含むモデルの内部構造をコードレベルで再現しました。
  • Hugging Faceによる実用的な推論: 事前学習済みモデルを活用し、実際のPDF論文から高度な構造を維持したままテキストを抽出できることを検証しました。

Nougatは、従来のOCRでは困難だった高度な学術ドキュメントのデジタル化において、非常に高いポテンシャルを持っています。研究データの整理や自動解析など、文書理解を必要とする幅広い分野での活用が期待されます。


出典・ライセンスについて

  • IM2LATEX-100Kデータセット: Yuntian Deng氏らによって作成された IM2LATEX-100K(CC0 1.0 Public Domain)を使用しています。
  • 推論テスト用のサンプル論文: 論文 "Machine learning in medicine: a practical introduction" (Jenni A. M. Sidey-Gibbons and Chris J. Sidey-Gibbons, BMC Medical Research Methodology (2019) 19:64) を使用しています。この論文および関連する図表は CC BY 4.0 ライセンスの下で公開されています。

本記事の文章・構成の一部に生成AIを使用しています。