
環境
- Azure App Service (Linux) / Python 3.10
- Flask API(Gunicorn起動)
- DeepFace(年齢/性別/感情/※人種)+ OpenCV
- TensorFlow(CPU)
症状とエラーログ(時系列)
ImportError: libGL.so.1
OpenCV のランタイム依存がコンテナに入っていない。ModuleNotFoundError: deepface
Azure の Oryx が作る一時仮想環境と ZIP デプロイの噛み合わせで、パッケージ解決が不安定に。ModuleNotFoundError: tensorflow.keras
/WARNING: TF_USE_LEGACY_KERAS
mtcnn
がtensorflow.keras
を要求、しかし Keras 3 系の互換と混在して崩れる。- NumPy 2 系の地雷
AttributeError: _ARRAY_API not found
/numpy.core.umath failed to import
→ TensorFlow 2.1x は NumPy<2 を想定。途中でnumpy 2.x
が入ると崩壊。 WORKER TIMEOUT
→ 無限再起動
初回リクエストで DeepFace の巨大モデル(Race/FairFace ≒ 539MB)をDL&初期化 → Gunicorn 既定 30s を超過 → ワーカーKill → 再起動 → またDL…地獄。
最終的に安定した解
1) requirements.txt
を“TensorFlow 2.19 系 + NumPy<2”で固定
# Web
flask==3.0.3
flask-cors==4.0.1
gunicorn==23.0.0
# HTTP
requests==2.32.3
# 画像処理
pillow==10.2.0
opencv-python-headless==4.10.0.84
# DeepFace 本体(0.0.95 で検証)
deepface==0.0.95
# 数値計算(TF 2.19 と相性の良い組み合わせ)
numpy==1.26.4
scipy==1.11.4
# TensorFlow(CPU)
tensorflow==2.19.0
tf_keras==2.19.0
# 顔検出を `mediapipe` に寄せる(速くて安定)
mediapipe==0.10.21
# dotenv(任意)
python-dotenv==1.0.1
ポイント
numpy==1.26.4
に固定(<2
厳守)。これで_ARRAY_API
系エラーが消えます。tf_keras==2.19.0
+TF_USE_LEGACY_KERAS=1
を使うと DeepFace との相性が安定。- 検出器は
mtcnn
を使わずmediapipe
oropencv
にするとtensorflow.keras
依存の地雷を踏みにくい。
2) startup.sh
(Startup Command)で全部面倒を先回り
#!/bin/sh
set -e
# 1) OpenCV に必要なライブラリを入れる(初回のみ)
if [ ! -f /tmp/.apt_done ]; then
apt-get update
apt-get install -y libgl1 libglib2.0-0 libsm6 libxrender1 libxext6
touch /tmp/.apt_done
fi
# 2) DeepFace のキャッシュを永続領域へ
export DEEPFACE_HOME=/home/site/deepface
mkdir -p "$DEEPFACE_HOME"
# 3) TensorFlow/keras の互換を固定
export TF_USE_LEGACY_KERAS=1
export TF_CPP_MIN_LOG_LEVEL=2
# 4) モデルの事前DL&初期化(ここで重い処理を済ませる)
python - <<'PY' || true
import os
os.environ.setdefault("TF_USE_LEGACY_KERAS","1")
from deepface import DeepFace
detector = "mediapipe" # 実運用もこれに合わせる
# ★Race は約 540MB。不要ならコメントアウト
for m in ["Age", "Gender", "Emotion", "Race"]:
try:
print("Pre-building:", m)
DeepFace.build_model(m)
except Exception as e:
print("PREWARM FAIL", m, e)
PY
# 5) Gunicorn: タイムアウト延長&preloadで多重初期化を防ぐ
exec gunicorn --bind=0.0.0.0:${PORT:-8000} \
--workers=1 --threads=2 --preload \
--timeout=600 --graceful-timeout=120 \
app:app
Azure ポータルでの設定
- App Service → 構成 → 全般設定 → Startup Command に
/home/site/wwwroot/startup.sh
を設定(ZIP デプロイ先基準) - リポジトリ側で
startup.sh
に実行権限:chmod +x startup.sh
(CI で zip するときに属性が落ちても、App Service は shebang で動きます)
3) app.py
で環境変数&DeepFace呼び出しの最適化
# app.py (先頭付近)
import os
os.environ.setdefault("TF_USE_LEGACY_KERAS", "1")
os.environ.setdefault("DEEPFACE_HOME", "/home/site/deepface")
from flask import Flask, request, jsonify
from deepface import DeepFace
# ...
# 例: race が不要なら外す(初回 539MB ダウンロードを回避)
ACTIONS = ['age', 'gender', 'emotion'] # 'race' を削除
@app.post("/api/face-analyze")
def face_analyze():
# 画像の読み込み処理...(省略)
result = DeepFace.analyze(
img_path=img_or_np,
actions=ACTIONS,
detector_backend='mediapipe',
enforce_detection=False
)
return jsonify(result)
ポイント
detector_backend='mediapipe'
が CPU で速くて安定。race
が不要なら削る → 初回 539MB のDLが無くなり、タイムアウトの根本原因が消える。- どうしても
race
が必要なら、起動時プリウォームと--timeout=600
でOK。
4) GitHub Actions(ZIP デプロイ)のコツ
- 必要なファイルだけ ZIP(
venv
や.git
は除外) - Zip の中に
startup.sh
とアプリ一式が入っていることを確認
# 省略: checkout / setup-python / pip install
- name: Create deployment bundle
run: |
zip -r deploy.zip . \
-x "venv/*" ".venv/*" ".git/*" ".github/*" \
"__pycache__/*" "*.pyc" ".pytest_cache/*" \
"tests/*" "docs/*"
- name: Deploy to Azure Web App
uses: azure/webapps-deploy@v3
with:
app-name: <your-app-name>
slot-name: Production
package: deploy.zip
うまくいく理由(根治ポイント)
- OpenCV の共有ライブラリを apt で注入 →
libGL.so.1
消滅 - NumPy を
<2
に固定 → TF 2.19 と ABI が揃い、_ARRAY_API
地雷を回避 - Keras の互換を固定(
tf_keras==2.19.0
+TF_USE_LEGACY_KERAS=1
)→tensorflow.keras
の不整合を抑止 - Gunicorn を
--preload
+--workers=1
→ モデル初期化を1回だけに Race
先読み or 無効化 +--timeout=600
→ 初回重い処理で落ちない- DeepFace キャッシュを永続領域
/home/site
に退避 → 再起動しても再DLしない
よくある質問(運用Tips)
Q. 起動が遅い / タイムアウトする
A. Startup でプリウォーム + --timeout=600
。race
を外すのが最速。
Q. CPU でなるべく軽くしたい
A. detector_backend='mediapipe'
。OpenCV より検出精度・速度のバランスが良いです。
Q. 再起動のたびにモデルをDLしたくない
A. DEEPFACE_HOME=/home/site/deepface
(永続化)を必ず設定。
Q. それでも落ちる
A. App Service の Always On を有効化。SKU が小さすぎる場合はプランのメモリを増やすか、workers=1
のままにしてスループットはスケールアウトで対応。
仕上げチェックリスト
requirements.txt
は TF 2.19 / tf_keras 2.19 / numpy 1.26.4 に固定startup.sh
を Startup Command に設定(権限/パスOK)- Race不要なら除外、必要ならプリウォーム
DEEPFACE_HOME
を/home/site/deepface
に- Gunicorn は
--preload --workers=1 --timeout=600
- App Service「構成 → 全般 → Always On = On」
参考スニペット一式(貼るだけセット)
requirements.txt
→ 上記の最終版startup.sh
→ 上記の最終版app.py
冒頭:
import os
os.environ.setdefault("TF_USE_LEGACY_KERAS", "1")
os.environ.setdefault("DEEPFACE_HOME", "/home/site/deepface")
DeepFace呼び出し:
DeepFace.analyze(
img_path=img_or_np,
actions=['age','gender','emotion'], # race不要なら外す
detector_backend='mediapipe',
enforce_detection=False
)
LEAVE A REPLY