Safie Engineers' Blog!

Safieのエンジニアが書くブログです

屋外向けAIカメラを開発しました

こんにちは。Safieの画像認識チームでサブグループリーダーをしている柏木です。

今回は私が主担当としてAIアプリ開発に携わった、エッジAI搭載屋外向けクラウド録画カメラについて紹介します。

プレスリリースはこちらにあります。興味のある方はご覧ください。

エッジAI搭載屋外向けクラウドカメラについて

本製品は人物検出を行うAIアプリが搭載されたAIネットワークカメラで、i-PRO(アイプロ)株式会社(以下i-PRO)と共同開発したものです。i-PRO株式会社はパナソニックの技術を引き継いで2019年に設立した会社で、ネットワークカメラやセキュリティシステムの開発と販売を行っています。

今回i-PROのカメラにセーフィー独自のファームウェアおよびアプリを搭載することで、特別仕様のカメラの開発を行いました。

開発中のカメラ

こちらのカメラにはAI-App 人数カウント(旧名: Store People Detection Pack)が搭載されています。AI-App 人数カウントはSafie Oneで搭載されていたアプリであり、カメラに映る人物の検知や、UI上で設定したラインを通過する人数のカウントを行うことができます。技術的な詳細については過去のブログにまとまっています。本アプリに興味がある方はご覧ください。

アプリ開発上の違い

i-PROのカメラにおけるAI-App 人数カウントの開発は、Safie Oneで元々搭載していたアプリを移植した形になります。カメラが変わったことによるアプリの一番大きな違いは、Object Detection(物体検出)です。以下がアプリのシステム全体の構成です。

SafieOneとi-PRO、双方ともコードの大部分はC++で書かれており、これらに違いはあまりありません。特にTrackingとEvent Publishmentはほとんどそのままのコードで動作しました。

しかし、2つの機種ではカメラに搭載しているAIチップが異なります。SafieOneではQualcomm製のチップを搭載しており、SNPE (Snapdragon Neural Processing Engine) SDKというSDKを利用することでチップでの推論が可能となっていました。一方、i-PROではambarella社のチップを搭載しており、i-PROの提供している独自SDKを利用して開発をする必要がありました。

SNPEとi-PROのSDKで、機能面での違いはそこまで大きくないです。しかし細かい仕様の違いは結構ありました。具体的は以下の面で違いがありました。

  • モデル変換ツール

SNPEは独自形式への変換と量子化をステップごとに実行可能

i-PROは独自形式への変換と量子化がセット

  • モデル読み込み

SNPEはモデルをポインタで読み込む

i-PROはパスを指定し、ファイルを読み込む

  • 前処理の組み込み

SNPEは前処理があまり用意されていない

i-PROは一部前処理を組み込み可能

実装上の工夫

今回のアプリ開発はAI-App 人数カウントの移植だったため、実装上は大部分がSafie Oneのアプリと同じものでした。そこで、アプリのコードはi-PRO用に新規作成することはせず、SafieOneと同じコードで必要な箇所だけ分岐することにしました。

こうすることで保守コストを抑えることができます。例えばTrackingアルゴリズムの改修をする際はSafie Oneとi-PROの双方で適用することができます。

AI-App 人数カウントは、Make時にカメラ機種に応じてビルドタイプを変更してビルドしております。そこで機種で共通のIDetectorという検出用のInterfaceを作成し、機種専用のYoloV5がそれを継承する実装としました(今回の検出器ではYoloV5を用いています)。機種ごとに読み込むYoloV5のコードが格納されているディレクトリを分けることで実現していまます。

こうすることで、機種ごとの違いを意識せずにDetectorを扱うことができます。

classDiagram
    IDetector <|.. YoloV5_SafieOne
    IDetector <|.. YoloV5_iPro
class IDetector{
            + void Detect()
}
class YoloV5_SafieOne{
            - void preprocess
            + void Detect()
}
class YoloV5_iPro{
            - void preprocess
            + void Detect()
}

独自データセットによる学習

学習モデルは屋外向けに再学習しました。屋内をターゲットとしているSafieOneと、屋外を対象としているi-PROでは、同じアプリでも検出するシーンが異なります。SafieOneでは屋内に特化したオリジナルデータセットを作成して学習していました。以下の画像のようなものをイメージしていただければと思います。

屋内データセットのイメージ

一方で屋外では以下の画像のようなイメージです。そこで、屋外においても独自に新しく画像を収集し、データセットを作成しました。屋外では背景が屋内と比較して乱雑でシーンが多様であるため、検出がやや難しくなります。今回は、本カメラが設置されるであろうシーンをいくつか選定し、それらのシーンに注力したデータセットを作成・学習しました。

屋外データセットのイメージ(APhotoより)

屋内データセット、屋外データセットそれぞれに対して、屋内用モデル・屋外用モデルで評価を行いました。PR曲線などの評価指標では大きな改善となりました。以下に結果を載せておきます。

屋内データセットに対するPR曲線

屋外データセットに対するPR曲線

屋内データセットでは大きな劣化はなく、屋外データセットにおける精度向上が見込めました。

もちろん評価ではPR曲線のような物体検出の評価だけではなく、設定したラインやエリアを通過する人数のカウント精度や人検知精度など、アプリのEnd-to-Endな評価も行っております。

今後は実際に製品を使っていただいたお客様の声や、データをもとにさらなる精度改善を行う予定です。

終わりに

屋外向けAIカメラの開発について紹介しました。複数のカメラを扱っている、セーフィーならではのEdgeAIの開発の話をしたつもりです。これをきっかけに興味を持っていただければ嬉しいです。

セーフィーではエンジニアを積極的に募集しています。どのような職種があるのか気になる方はこちらをご覧ください。カジュアル面談から受け付けておりますので、気軽に応募いただければと思います。

サービス障害ハンドリングにおける工夫

こんにちは。セーフィーでセキュリティマネジメント業務をしている川部です。

今回はサービス障害ハンドリングについて記載したいと思います。

サービス障害とセキュリティ?と疑問に思った方もいるかもしれません。
セキュリティの基本的な考えにあるCIAの可用性の観点から、セキュリティマネジメント業務の一環としてサービス障害発生時の取りまとめを担当しています。
主な業務はエンジニアと協力し、事象の詳細確認や影響するお客様の洗い出し、対外的な対応など多義にわたります。

今回はサービス障害ハンドリングにおける工夫という観点でお話したいと思いますのでSaaS企業で障害対応される皆さんや障害対応を任された皆さんの一助になれば幸いです。

  • セーフィーを取り巻く環境
  • スピード感をもって対応するための施策
  • サービス品質の維持管理するための施策
続きを読む

DataVaultモデリングで遭遇した課題とその解決策

​データ分析基盤グループでデータエンジニアをしている平川です。 DataVaultに関する記事の第3回目となります。 第3回の記事は、DataVaultモデリングをしている際に困った状態の対処方法についてまとめていきます

第1回: DataVaultってなに?どんな特徴があるの?

第2回: automate_dvを使ってDataVaultモデリングの中心となるテーブルを作ってみてわかったこと 

第3回: BusinessVault、発展的なSatelliteテーブルやキーがNullだった場合の対処方法についてなど ← 今回はここ 

続きを読む

タイムゾーンと、Pythonでのその扱い方の注意点

サーバーサイドエンジニアの三村です。

弊社では2024年の初めから国外へサービス展開をする準備として、一年ほど前からシステムの国際化対応を行ってきました。 この準備には、サービスの多言語対応や日本標準時以外のタイムゾーンでサービスが利用できるようにする改修などが含まれますが、サーバーチームでは特に後者に苦労しました。

そこでこの改修で得たPythonでタイムゾーンを扱う際の知見の一部を、このブログ記事にまとめます。

続きを読む

Androidチームにおける品質改善③ 〜2023年のまとめ〜

はじめに

リリースから3年以上経過しようやくモダンな開発環境に近づけていく活動ができるようになるくらい体制が整って来ました。

今回はAndroid版Safie Viewer for Mobileが2023年に行った改善活動の振り返りの話をしたいと思います。

続きを読む

SOTAセグメンテーションモデル PP-MobileSeg をSNPEで動かす

はじめに

セーフィー株式会社の AI Vision グループでテックリードを務めます橋本貴博です。セーフィーの一部のAIネットワークカメラは、Snapdragon Neural Processing Engine(SNPE)をランタイムに使ってエッジ推論を行っています。この記事では、SOTA セグメンテーションモデル PP-MobileSeg を SNPEで動かす方法を解説したいと思います。

PP-MobileSegとは?

PP-MobileSeg は、2023年4月に発表された、モバイル向けセマンティックセグメンテーションのSOTAモデルです。ADE20Kデータセットで学習がなされており、既存モデルと比較して低レイテンシ、かつ、認識性能(mIoU)が高いことが分かります。論文は こちら (arXiv) から読めます。

引用元: [PaddlePaddle/PaddleSeg (GitHub)](https://github.com/PaddlePaddle/PaddleSeg) / Apache License 2.0

引用元: PaddlePaddle/PaddleSeg (GitHub) / Apache License 2.0

モデル変換

大まかな流れ

PP-MobileSegのPyTorchモデルをONNXモデルに変換します。ONNXモデルで移植性向上のためのノード編集を行なった後、ONNXモデルからSNPEのネイティブフォーマット(DLC形式)に変換します。

PyTorch から ONNX への変換

mmsegmentation リポジトリ v1.1.2 で 公開(2023年9月)されている PP-MobileSeg-Tiny の PyTorchモデルを利用します。はじめに、Get started: Install and Run MMSeg を参考に環境構築を済ませておきます。 公式マニュアル に記載の手順にしたがって作業すれば、PyTorchモデルからONNXモデルに変換できます。

ONNX モデルの修正

ONNXモデルで使われている HardSigmoid オペレータ は、SNPEでサポートされないため、単純なオペレータの組み合わせに変換します。SNPEでサポートされるオペレータは 公式リファレンス から確認できます。 活性化関数に HardSigmoid が使われている。https://netron.app/ で可視化。

まず、今回のノード編集で利用する ONNX の opset バージョンを確認しておきます。opset versionによってオペレータの定義が異なるため、入力モデルの opset バージョンに揃えることにします。以下のスクリプトはモデルを読み込み opset バージョンを表示します。

import onnx

model = onnx.load(input_path)
for opset in model.opset_import:
    print(f"Model opset version: {opset.version}")

今回使用するモデルの opset バージョンは 11 ということが分かります。

model opset version: 11

次に、HardSigmoid オペレータを変換します。HardSigmoid の定義は、入力を x、出力を y として、

y = max(0, min(1, alpha * x + beta)) # alpha, beta はパラメータ

なので、ONNXの Mul、Add、Clip オペレータ を用いて分解できます。

x1 = Mul(alpha, x)
x2 = Add(x1, beta)
y = Clip(x2, 0, 1)

以下のスクリプトは、Mul、Add、Clip を用いて、ONNXモデルのすべての HardSigmoid を消去します。13か所で HardSigmoid が使われていることが分かります。

from onnx import TensorProto, defs, helper

count = 0
for pos, node in enumerate(model.graph.node):
    if node.op_type == "HardSigmoid":
    count += 1 # Count HardSigmoid operator

    # Create Mul node and insert
    n0_name = node.name
    x0_name = node.input[0]
    alpha = node.attribute[0].f
    alpha_name = n0_name + "_alpha"
    alpha_tensor = helper.make_tensor(alpha_name, TensorProto.FLOAT, [1], [alpha])
    y0_name = n0_name + "_mul"
    multiply_node = helper.make_node("Mul", [x0_name, alpha_name], [y0_name])
    model.graph.node.insert(pos, multiply_node)

    # Create Add node and insert
    y1_name = n0_name + "_add"
    beta_name = n0_name + "_beta"
    beta_tensor = helper.make_tensor(beta_name, TensorProto.FLOAT, [1], [0.5])
    add_node = helper.make_node("Add", [y0_name, beta_name], [y1_name])
    model.graph.node.insert(pos + 1, add_node)

    # Create Clip node and insert
    y2_name = node.output[0]
    min_name = n0_name + "_min"
    max_name = n0_name + "_max"
    min_tensor = helper.make_tensor(min_name, TensorProto.FLOAT, [1], [0.0])
    max_tensor = helper.make_tensor(max_name, TensorProto.FLOAT, [1], [1.0])
    clip_node = helper.make_node("Clip", [y1_name, min_name, max_name], [y2_name])
    model.graph.node.insert(pos + 2, clip_node)

    model.graph.node.remove(node) # Remove HardSigmoid node    
    model.graph.initializer.extend([alpha_tensor, beta_tensor, min_tensor, max_tensor])

print(f"# hardsigmoid nodes: {count}") # Outputs 13

作成されたモデルを検証して保存します。

onnx.checker.check_model(model) # Validation
onnx.save(model, output_path) # Save

変換後のONNXモデルを見ると、HardSigmoid オペレータが、Mul、Add、Clip オペレータに置き換わっていることが確認できます。

HardSigmoid が Mul/Add/Clip に変換されている。https://netron.app/ で可視化。

ONNX から DLC への変換

SNPE SDKに含まれるツール を使って、ONNXモデルからDLCモデルに変換が可能です。モデル実行時の入力テンソルのサイズを固定します。

snpe-onnx-to-dlc --input_network model.onnx --input_dim "input" 1,3,512,512

推論結果

当社のAIネットワークカメラ(Safie One)にモデルをインストールし、推論を行います。クラウド経由でモデルをアップロードできます。

SafieOne

推論が動作する様子をWebアプリ(Safie Viewer)から確認します。ここでは人物クラスを水色で表示しています。人物の輪郭が抽出されていることが分かります。

人物が水色でセグメンテーションされている

むすび

セマンティックセグメンテーションのSOTAモデル PP-MobileSeg をAI ネットワークカメラで動かしました。ONNXモデルからHardSigmoid オペレータを除去し、DLCモデルに変換する方法を詳しく解説しました。最後に、AIネットワークカメラ上の推論結果をWebアプリから確認しました。

セーフィーではエッジAIを用いたプロダクトの開発を行っています!

Androidチームにおける品質改善②〜アプリサイズの計測〜

Androidチームの品質改善の取り組みとして、今回はアプリサイズを計測した話をしたいと思います。

  • はじめに
  • 動作環境
  • rulerとは
  • rulerの導入方法
    • settings.gradleの編集
    • app/build.gradleの編集
  • analyzeタスクの実行
  • 継続的に計測する
    • ワークフロー
  • 最後に
続きを読む

Androidチームにおける品質改善①〜ユニットテストの導入〜

今回は直近のAndroidチームの品質改善の取り組みとして、ユニットテストを導入した件についてお話したいと思います。

  • はじめに
  • 実際にやった事
    • ユニットテストを書く
      • どこからユニットテストを書くか
      • 技術スタック
      • JUnit4 + Mockito-Kotlin + Truthを使用したテストコード
    • カバレッジ率の可視化
      • Jacocoの設定
      • Jacocoの出力
    • CIで自動でテストが実行される環境
      • 導入したアクション
      • ワークフロー
  • 最後に
続きを読む

セーフィーはPyCon APAC 2023に出展しました!

こちらはSafie Engineers' Blog! Advent Calendarの18日目の記事です。

こんにちは。セーフィー株式会社でバックエンドエンジニアをしている河津です。

私たちの会社は2023年10月27-28日に、PyCon APAC 2023への出展を行いました。この記事では、出展までの準備や当日の様子について紹介したいと思います!

  • PyConとは
  • 用意したデザインアイテム
  • 当日の様子
  • 出展デモ
    • Safie One
    • Safie Pocket2 Plus
    • Safie Connect
  • 撤収と振り返り
続きを読む

© Safie Inc.