ブラキオカップ

ダンスDE猫ミーム【ぷな天】

https://github.com/punaten/Punaten

Go

TypeScript

C++

Python

GCP

楽しく踊った猫ミームダンスを実際の猫ミームに変換!踊り狂え!

Shunkicreate

mercy34mercy

yu:ka

推しアイデア

人間のダンスから猫ミームを生成!

作った背景

猫ミームってなんか癒されませんか?

推し技術

wasm,webGL,cloudFlare, 自作猫ミーム判定AIなどモリモリ技術をできるだけフロントエンドで動かしてます!

プロジェクト詳細

アーキテクチャ

当初の予定

使用技術

  • Remix(フルスタックアプリケーション)
  • tensorFlow(骨格検出)
  • ONNX(猫ミーム推定)
  • ffmpeg(動画合成、動画結合)
  • Cloud FlarePages(Remixのデプロイ)
  • Cloud Flare R2(オブジェクトストレージ)
  • Cloud Flare D1(データベース)
  • ScikitLearn・Python(機械学習)

コンセプト

とにかく、CloudFlare + Remixのフロントエンドでできる限りの処理を行う。→ ハイスペックPCでしか動かないかもしれないけどブラウザで全部動いてるってめっちゃ面白くないですか?

アーキテクチャ図

image

実際

実際には当初予定していた、フロントエンドに全部詰め込む!のコンセプトは力不足で一部しか達成できませんでした。 逆境を跳ね返すべき、より技術の無駄遣いをします!

  • ⭕️Remix
  • ⭕️tensorFlow → webGL版でいい感じに動いてます
  • ❌ONNX → javascriptでONNXを使った猫ミーム推論はデータの前処理などがうまくいかずに断念
  • ❌ffmpeg → ffmpegのwasm版を動かそうとしたがうまくいかず断念
  • ⭕️Cloud FlarePages(Remixのデプロイ)
  • ❌Cloud Flare R2(オブジェクトストレージ) → うまく使えず断念
  • ❌Cloud Flare D1(データベース) → うまく使えず断念
  • ⭕️ScikitLearn・Python(機械学習) → 学習モデルの作成は成功(精度は...)

image

実際に動いているアーキテクチャ図

使用技術

  • Python・Go・C++・TS(Remix・React)・wasm・Rust
  • Google Cloud Storage(オブジェクトストレージ)
  • Google Cloud SQL(データベース)
  • Cloud Run(Go、Python製サーバのデプロイ)
  • Docker(開発環境・デプロイ)
  • GitHub Actions(RemixアプリのCD)
  • Google Cloud Build(Python,Go製サーバのCD)
  • Google Artifact Registry(プロダクション用 docker image置き場)
  • Docker Hub(pythonとffmpegが入った自作Docker image置き場)
  • Cloud Flare Pages(Remixアプリのホスティング) image

猫ミーム生成ロジック

ほぼほぼ結局フロントエンドでやってます!web系技術の無駄使い!これが動かないPCで開発してるって???それは買い替え時だね! image

Python製サーバでの動画、音声結合

基本的にはffmpegを使っているが、MoviePyとPydubというffmpegをライブラリをWrapしたライブラリを使用している ffpmegを使えば背景画像の合成もできますが、そこはフロントエンドでやることで技術の無駄遣いしてます😭😭😭 image

技術のお話

TensorFlowのモデルロードの高速化

骨格検出では、TensorFlowでopenpose-multiと呼ばれるモデルを用いている。このモデルはデフォルトの設定では、TensorFlow側が準備しているサーバからモデルをロードするのだが、headerのmax-ageが0に設定されており、ブラウザ側でのキャッシュが効かないため、毎回20秒ほどロード時間があった。 そこで、モデルのロード先を独自にホスティングしたサーバに変更し、max-ageを長く設定することでブラウザキャッシュが効き初回ロード時以外はキャッシュがあるためロードがほぼ0msとなった image

猫ミーム判定

猫ミームは動画から取得できる骨格データを元にルールベースで判定しています。骨格検出にはwebGL、特徴抽出にJS,TS、ルールベースの判定にwasm化したC++を利用しています

利用している骨格データ

  • 手のスピード
  • 人の人数
  • 鼻と手の座標

判定ルール概要

  • 人の人数が一定時間以上(shikarareru)
  • 縦方向の動きが大きく、横の動きが少ない(yonezu happy)
  • 全体的に動きが大きく、縦の動きが特に大きい(happy happy)
  • 両手の位置が鼻より上だったら(girlfriend)
  • その他(edm)

image

クロマキー合成

ブラウザ上でのクロマキー合成の実現方法

クロマキー合成にはffmpegを代表とするかなり重めのツールやライブラリが有名であるが、どんなにハイスペックなPCを使ったとしてもクロマキー合成に数秒から数十秒かかってしまう。 そこで、ブラウザ標準のcanvasでクロマキー合成をすることで、軽量で待ち時間0でクロマキー合成を行えるようにした。 また。canvasでの描画はブラウザ標準のMediaRecorderで動画として保存されており、ユーザはcanvasで作成された猫ミームをダウンロードすることができる。

canvasを使う辛み

  1. 動画の結合がcanvasではできなかった(技術的には可能かもしれないが、実装できなかった)
  2. canvasでは、あくまでグラフィックの表示しかできないため、canvasで作成される動画をMediaRecorderでキャプチャしても音声がなくなってしまう。

辛みの解決方法

動画の結合がcanvasでできなかっため、クロマキー合成前の動画の結合をPython製サーバで行っている。また、問題2のために、結合せした音声ファイルも生成している。

音声がなくなってしまう問題については、上述した結合した音声データをMediaRecorderが収録する音声として設定することで、canvasで消えてしう音声データを再度結合している

概要図

image

Client Side Routing

今回のアプリケーションではCSRを利用しています。気づいた方もいるかもしれませんが、このアプリは最初のロード以外はブラウザのローディングアイコンが微動だにしません。 CSRを使っているため、通常のアプリケーションよりも少ない通信量で、かつシームレスなアプリ体験が出来ます。今回の猫ミームのようなインタラクション性の強いアプリケーションではロード時間がどうしても気になったり、アプリが重い!といってユーザがいらいらすることもあるでしょう。しかし、CSRではその課題を解決しています。 皆さんもリンクをポチポチ押して、このアプリケーションのシームレスな体験の良さをぜひ味わってみてください。

webGLとtensorFlowを用いた骨格検出

骨格検知はTensorflowのmovenetというモデルを利用しました。 https://github.com/tensorflow/tfjs-models/tree/master/pose-detection/src/movenet このTensofflow jsというものがあり、今回のモデルはwasm版とwebGL版がありました。 GPUを利用しながら処理してくれるwebGL版の方が実行速度が早かったので、こちらを採用しました。 このライブラリは骨格検知を行い、そのキーポイントの座標とキーポイントの名称と、推論の信頼度を取得できます。 このフレームワークの最も重いモデルを利用し、複数人検知ができるようにしています。そのため、アプリケーションの実行にはある程度のPCスペックが必要です。可愛い猫ミームが見られるので、そこはご了承ください。

cloud runでのコールドスタート高速化

コールドスタートを高速化するモチベーション

Cloud Runでは常時インスタンス数1以上にすれば、大量のリクエストが来ない限りコールドスタート問題が起こることはないが、大学生はお金がないので最小インスタンス数を0に設定したい!なのでコールドスタートを特に高速化する必要があります。

コールドスタートの課題

下記のようにデプロイするDockerコンテナ内で、baseimageに含まれないffmpegを使おうとすると、コンテナ起動時にffmpegのinstallが走ってしまい、かなり大きいffmpegのダウンロードに時間がかかってしまう 公式で、ffmpeg+pythonが含まれたimageが公開されておらずffmpegのinstallは基本的には必須事項である

# ビルドステージ FROM python:3.10-slim AS build-stage WORKDIR /app # 必要なパッケージのインストール COPY requirements.txt . RUN pip install -r requirements.txt # アプリケーションのソースコードをコピー COPY . . # 本番環境用のDockerイメージ FROM python:3.10-slim AS production-stage WORKDIR /app # FFmpegのインストール RUN apt-get update && \ apt-get install -y ffmpeg && \ rm -rf /var/lib/apt/lists/* # ビルドステージから必要なファイルをコピー COPY --from=build-stage /app /app COPY --from=build-stage /usr/local /usr/local # ポートの公開 EXPOSE 8080 # コンテナが起動するたびに実行されるコマンド CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]

解決策

  1. ローカルのPCでpythonのimageにffmpegをinstallした新しいDocker Imageを作成しDocker Hubに保存しておく
  2. この独自イメージをpython製サーバのデプロイに使用する
  3. コールドスタート時にffmpegがinstallされることなく、高速に起動することができる
  • ffmpeg+pythonのimageを作るためのDockerfile
# ビルドステージ FROM --platform=linux/amd64 python:3.10-slim AS build-stage WORKDIR /app # FFmpegのインストール RUN apt-get update && \ apt-get install -y ffmpeg && \ rm -rf /var/lib/apt/lists/*
  • コールドスタート改善後のDockerfile
# ビルドステージ FROM python:3.10-slim AS build-stage WORKDIR /app # 必要なパッケージのインストール COPY requirements.txt . RUN pip install -r requirements.txt # アプリケーションのソースコードをコピー COPY . . # 本番環境用のDockerイメージ FROM 独自イメージ:1.0 AS production-stage WORKDIR /app # ビルドステージから必要なファイルをコピー COPY --from=build-stage /app /app COPY --from=build-stage /usr/local /usr/local # ポートの公開 EXPOSE 8080 # コンテナが起動するたびに実行されるコマンド CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]

全部入りレポジトリ

レポジトリ構成

Go,Python,Remix,C++,Rustなどなど今回使った技術やコードは全て https://github.com/punaten/Punaten レポジトリに入っています。 ハッカソンでは、バックエンド、フロントエンド、インフラなど役割分担を分けがちですが、全員がバックエンド、フロントエンド、インフラなどをレポジトリの移動なく、スムーズに開発できるように全てを1つのレポジトリ(モノレポ的)に管理しています

レポジトリTips

今回は、レポジトリをpunatenというOrganization保有にしています。こうすることで、チームメンバーなら、自由にPaaSやSaaSとレポジトリを連記したり、レポジトリにSeacretを登録したりすることができます。個人保有のレポジトリだとレポジトリのオーナーだけしかこのような設定ができないため、開発効率の低下につながると考え、Organization保有にしました。

チームメンバ

マーシー

得意分野 : バックエンド、インフラ 26卒 image

ゆうか

得意分野 : フロントエンド 25卒 image

しゅんき

得意分野 : フロントエンド 24卒 image

Shunkicreate

@Shunkicreate