🌟

Azure Container AppsでNDL古典籍OCR Liteを用いたスケーラブルOCR処理システム

に公開

⚠️ 重要な利用上の注意

本記事で紹介するシステムは、外部サーバーに負荷をかける可能性があります。利用時は十分ご注意ください。

  • サーバー負荷: 並列リクエストは対象サーバーに負荷を与えます
  • DoS攻撃のリスク: 大量の同時アクセスはDoS攻撃と誤解される可能性があります
  • 推奨アプローチ: 事前に画像をローカルにダウンロードし、OCR処理のみを並列実行することを推奨します
  • 利用規約の確認: 対象サーバーの利用規約を必ず確認し、必要に応じて事前許可を取得してください
  • 適切なレート制限: 実運用では慎重な並列数設定(5-10並列程度)を強く推奨します
  • 責任ある利用: サーバー管理者や他の利用者への配慮を忘れずに

本記事は技術的な実証実験の記録です。読者の皆様には責任を持った利用をお願いします。

はじめに

本記事では、国立国会図書館(NDL)が開発したNDL古典籍OCR Liteを活用し、Azure Container AppsでスケーラブルなOCR処理システムを構築した事例を紹介します。クラウドネイティブなアーキテクチャにより、従量課金とオートスケーリングを実現したシステムの設計と実装について解説します。

システム概要

アーキテクチャ

IIIF画像 → Azure Container Apps → NDL古典籍OCR → TEI XML出力
              ↓
         オートスケーリング
         (0-30レプリカ)

主要コンポーネント

  • OCRエンジン: NDL古典籍OCR Lite(日本古典籍特化)
  • インフラ: Azure Container Apps(サーバーレスコンテナ)
  • API設計: REST API(画像URL → OCR結果)
  • 出力形式: TEI P5準拠XML
  • スケーリング: 需要に応じた自動スケーリング

NDL古典籍OCR Liteの特徴

日本古典籍に最適化されたOCR

  • 縦書きレイアウト対応: 古典籍特有の縦書き文書構造
  • 読み順序最適化: 右から左、上から下の日本語読み順
  • 古典文字認識: くずし字や変体仮名への対応
  • 軽量実装: Docker化によりクラウドデプロイ対応

Azure Container Appsの選択理由

サーバーレスコンテナの利点

# スケーリング設定例
scale:
  minReplicas: 0      # アイドル時: コスト0
  maxReplicas: 30     # 需要時: 自動拡張
  cooldownPeriod: 300 # 5分でスケールダウン

コスト最適化

  • 従量課金: 使用した分のみ課金
  • 0レプリカ: アイドル時は完全にコスト0
  • 自動スケーリング: 需要に応じたリソース調整

システム実装

サーバーサイド実装

# Flask + NDL OCR統合
from flask import Flask, request, jsonify
from flask_restx import Api, Resource
from simple_ocr_service import OCRService

app = Flask(__name__)
api = Api(app, doc='/docs/')

@api.route('/api/image')
class ImageOCR(Resource):
    def get(self):
        image_url = request.args.get('image_url')
        # NDL OCRで画像処理
        result = ocr_service.process_single_image(image_url)
        return result

読み順序アルゴリズム

def sort_japanese_reading_order(lines):
    """日本古典籍の読み順序ソート"""
    return sorted(lines, key=lambda line: (
        -line["bbox"][0],  # x座標降順(右→左)
        line["bbox"][1]    # y座標昇順(上→下)
    ))

TEI XML出力

<?xml version="1.0" encoding="UTF-8"?>
<TEI xmlns="http://www.tei-c.org/ns/1.0">
  <teiHeader>
    <fileDesc>
      <titleStmt>
        <title>桐壺</title>
      </titleStmt>
      <respStmt>
        <resp>Automated Transcription</resp>
        <name ref="https://github.com/ndl-lab/ndlkotenocr-lite">
          NDL古典籍OCR Lite
        </name>
      </respStmt>
    </fileDesc>
  </teiHeader>
  <facsimile>
    <surface xml:id="surface-1">
      <zone xml:id="zone-1-1" ulx="3391" uly="1141" 
            lrx="3727" lry="2924" cert="0.799"/>
    </surface>
  </facsimile>
  <text>
    <body>
      <div type="transcription">
        <pb n="1" facs="#surface-1"/>
        <lb n="1.1" corresp="#zone-1-1" cert="high"/>
        いづれの御時にか
      </div>
    </body>
  </text>
</TEI>

処理結果事例

小規模テスト処理(桐壺)

  • 対象: 東京大学所蔵「桐壺」
  • ページ数: 32ページ
  • 処理時間: 約30秒
  • 成功率: 100%
  • 並列数: 10並列
  • コスト: 約$0.05

パフォーマンス特性

処理時間 = 約1秒/ページ(並列処理時)
コスト効率 = $1.5〜2.0/1000ページ
スケーリング = 数秒で0→20レプリカ

システムの技術的特徴

1. コールドスタート対応

async def process_with_retry(image_url, max_retries=3):
    """コールドスタート時の自動リトライ"""
    for attempt in range(max_retries + 1):
        try:
            if attempt > 0:
                wait_time = 2 ** (attempt - 1)
                await asyncio.sleep(wait_time)
            return await ocr_request(image_url)
        except (HTTPError, TimeoutError) as e:
            if attempt == max_retries:
                raise e

2. 設定の外部化

# 環境変数による設定
OCR_API_URL=https://your-ocr-service.azurecontainerapps.io
DEFAULT_MAX_CONCURRENT=10
DEFAULT_CONFIDENCE_THRESHOLD=0.3
DEFAULT_OUTPUT_FORMAT=xml

3. Swagger UI統合

# API仕様の自動生成
api = Api(app, 
    version='1.0', 
    title='NDL古典籍OCR API',
    description='日本古典籍専用OCR処理API',
    doc='/docs/'
)

デプロイメント

Azure Container Appsデプロイ

# コンテナアプリ作成
az containerapp create \
  --name ocr-service \
  --resource-group rg-ocr \
  --environment container-env \
  --image registry.azurecr.io/ocr-app:latest \
  --target-port 80 \
  --ingress external \
  --min-replicas 0 \
  --max-replicas 30 \
  --cpu 2.0 \
  --memory 4Gi

Docker化

FROM python:3.11-slim

# NDL OCRモデル配置
COPY model/ /app/model/
COPY config/ /app/config/

# アプリケーション設定
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .
EXPOSE 80

CMD ["gunicorn", "--bind", "0.0.0.0:80", "app:app"]

運用とモニタリング

パフォーマンスメトリクス

  • レスポンス時間: 平均2-3秒/画像
  • スループット: 10-15画像/秒(20レプリカ時)
  • 成功率: 99%以上
  • コスト効率: アイドル時$0、処理時のみ課金

ログ監視

# Container Appsログ確認
az containerapp logs show \
  --name ocr-service \
  --resource-group rg-ocr \
  --follow

今後の展望

技術的改善点

  • 画像キャッシュ: 重複処理の削減
  • バッチ処理: 効率的な大量処理
  • GPU対応: OCR処理の高速化
  • メトリクス強化: 詳細な性能分析

応用可能性

  • デジタルアーカイブ: 図書館・博物館での活用
  • 研究支援: 人文学研究のデジタル化
  • 教育分野: 古典文献の教材化
  • 文化保存: 貴重資料のデジタル保存

まとめ

NDL古典籍OCR LiteとAzure Container Appsを組み合わせることで、コスト効率とスケーラビリティを両立した古典籍OCRシステムを構築できました。サーバーレスアーキテクチャにより、従量課金と自動スケーリングを実現し、実用的なデジタルヒューマニティーズツールとして活用可能です。

キーポイント

  • コスト最適化: 使用時のみ課金
  • 自動スケーリング: 需要に応じたリソース調整
  • TEI P5準拠: 標準的なXML出力
  • 古典籍特化: 日本古典籍に最適化されたOCR
  • API設計: シンプルで拡張しやすい設計

本システムは技術実証として開発されました。実運用では対象サーバーへの負荷を十分考慮し、適切なレート制限と利用規約の遵守をお願いします。

参考資料

Discussion