セーフィー株式会社のブログ - TECH PLAY

TECH PLAY

セーフィー株式会社

セーフィー株式会社 の技術ブログ

256

この記事は Safie Engineers’ Blog! Advent Calendar 2日目の記事です。 セーフィー株式会社テックリードの鈴木敦志です。 セーフィーでは開発者の積極採用を進めており、エンジニア組織の人数が2年間で約35名から約75名にまで成長しました。 開発者の人数増加に伴うチーム内のコラボレーションの問題に対応するため、アジャイル開発手法の一つであるスクラム開発をサーバー/インフラチーム内で導入し2年間ほど運用し、一定の成果を得られましたので経緯や実際の施策、結果などについて共有させていただきます。 スクラム導入前の課題 チーム内のコラボレーションが希薄 業務知識の属人化 スクラム導入 チームの分割 プロダクトバックログ スクラムイベントの実施 スクラム導入により解決された課題 チーム内コラボレーションの推進および知識移転の推進 解決されていない課題 機能横断型チーム プロダクトオーナー 今後の方針 さいごに スクラム導入前の課題 スクラム導入前の開発組織はおおよそ職能別のチームで構成されていました。 開発案件はプロジェクト単位に分割され、各プロジェクトごとに職能別チームから開発者を0~2名程度ずつ割り当てプロジェクトチームとしていました。 各チームメンバーはそれぞれ1~数個のプロジェクトに並列で参加することになります。 スクラム導入前のチーム構成 チーム内のコラボレーションが希薄 各開発者は職能別チームの中ではそれぞれ参加しているプロジェクトが異なり、プロジェクトチームの中では他メンバーと職能が異なるため必然的に単独で取り組むことになるため、チームメンバーとの協調作業が難しい状況でした。 例えば設計の相談やコードレビューの際も、相談を受ける側はプロジェクトの細かい要件や経緯を把握しているわけではないためどうしても形式的なものにならざるをえません。 業務知識の属人化 特定個人が特定のプロダクトやコードを触り続けることになるため、他のメンバーに知識が共有されづらくなります。 改修案件や質問対応、障害対応が集中しやすくなり、また転属や退職などでの混乱が発生しやすくなります。 スクラム導入 こういった状況を改善するため、サーバー/インフラ開発者内でスクラムの導入を行いました。 スクラムの導入には機能横断型チームの編成や開発案件の意思決定者としてのプロダクトオーナー制度の導入など組織構造の変更が必要になります。 スクラムの組織構成 今回は全社的な導入でなくあくまでサーバー/インフラ開発者の間でのボトムアップ的な導入であるため、こうした組織変更を伴う施策を行うことはできませんでした。 スクラムガイドでも否定的に言及されているスクラムの一部的な導入にとどまってしまい、いくつかのメリットを受けることができませんが、それらを抜きにしてもチーム内でのコラボレーション促進の効果を得られると思い導入を進めました。 実際に導入されたチーム構成 チームの分割 導入時点でサーバー/インフラチーム合計で11人のメンバーがおり、チームを2チームに分割しました (現在は4チーム)。 それぞれのチーム内の開発者一名が兼務でプロダクトオーナーとしてプロダクトバックログの管理およびステークホルダーとの協議を行います。 (このプロダクトオーナーは実際にプロジェクト/プロダクトに十分な権限を持つわけでなく、バックログの管理と各プロジェクトの会議体に出席し要件を整理する役割です) プロダクトバックログ プロダクトバックログおよびスプリントバックログはWrikeにより管理されています。 Wrikeはさほどスクラムに向いている感じではありませんが、前者共通のプロジェクト管理で使われていたためツールを合わせました。 スクラムイベントの実施 スプリントを2週間 (チームによっては1週間) とし下記スプリントイベントを実施しています。 スプリントプランニング (1回/スプリント) スプリントで行う開発の計画を行います デイリースクラム (毎日) 一日の作業の調整を行います スプリントレトロスペクティブ (1回/スプリント) KPT法で開発進捗やチームの状況について振り返りを行います バックログリファインメント (1回/スプリント) プロダクトバックログアイテムの詳細化を行います スクラム導入により解決された課題 チーム内コラボレーションの推進および知識移転の推進 開発者をプロジェクトに割り当てる習慣をやめ、スプリントプランニングおよびバックログリファインメントの場で開発項目を全員で議論し詳細化することで、チームの全員が各開発項目の実装を実装を進めることができるようになりました。 各人が別々のプロジェクトに割り当てられていた頃とくらべ、特定の技術や業務知識がある人とペアプロをしたり、各人の休暇や割り込み作業などにあわせてタスクを融通しあうなど、チーム内での協力と知識の移転を促進することができました。 チーム内でプランニングポーカーによるストーリーポイントの見積もりを行っており、見積り結果の値はまだ活用できていないものの、全員で見積りを行う行為自体が開発項目への理解を深めるのに役に立っていたように思います。 解決されていない課題 今回導入したスクラムは既存チーム内で完結するもののみで組織的なスクラム導入には至っていないため、スクラムにより解決が期待される課題の一部は残ったままです。 機能横断型チーム スクラムチームは機能横断型であり、必要な機能をすべて備えていることを求められます。 一方で現在の組織は職能別のチーム構成となっておりひとつの機能を実装するにはサーバーチーム、フロントエンドチーム、デバイスチームなど複数チーム間での情報共有や優先度や調整が必要になり、都度ロスが発生します。 プロダクトオーナー スクラムにおいてプロダクトオーナーはチームが開発するプロダクトに権限と責任をもつロールです。 現在の組織体制では開発案件の権限はプロジェクトマネージャーが持っており、スクラムのプロダクトオーナーに当てはめることはできません。 今回のスクラム導入の範囲ではチームの開発者のうち1名を便宜上プロダクトオーナーとし、各プロジェクトのミーティングへの出席やステークホルダーとの折衝およびプロダクトバックログの管理を行っています。 プロダクトに関する意思決定者がチームの近くにおらず判断に時間がかかりますし、開発業務と平行して複数プロジェクトのミーティングに出席するため非常に負荷が高くなります。 今後の方針 開発チームにスクラムを導入し、チーム内コラボレーションの促進および業務知識の属人化防止に一定の成果を得ることができました。 しかしボトムアップ的に始まったためスクラムのフレームワークすべてを導入できているわけではなく、チーム内でのスクラムイベントの実施などの一部のみにとどまっています。 スクラムのメリットを享受して組織課題を解決していくためには組織全体として対応していく必要があり、今後はスクラムの推進のための施策を進めていきます。 社内でのスクラムの普及 機能横断チームの編成 プロダクトオーナー制度の導入 専任スクラムマスター採用 各チームリーダーの認定スクラムマスター資格取得 さいごに スクラムにおいて一部の施策だけの導入は推奨されていませんが、とはいえ現場からボトムアップででもスクラム導入を進めていきたい場面もあると思います。 本件事例がそういった方々の役に立てば幸いです。 現在セーフィー株式会社ではソフトウェアエンジニアを積極採用中です。 興味のある方はぜひ下記ページよりご応募ください。 https://safie.co.jp/teams/
セーフィーCTOの森本です。 この記事は Safie Engineers' Blog! Advent Calendar 1日目の記事です 2020年2月より開始したセーフィーのテックブログですが、一時期運営が危機的な状況に陥ったこともありました。 しかし、有志からなる運営チームのガンバリにより2021年9月以降着実に更新を継続して行ってくれており、様々な会社さんからテックブログ継続の難しさを伺っている中、非常に喜ばしく感じている今日此頃となっています。 そんな中、運営チームが2022年の年末に向けてアドベントカレンダーをやろうと熱く提案してくれました。 月イチの更新すらままならなかった当初を知っているだけに、ホントに出来るのかという気持ちもありましたが、当社カルチャーでも「迷ったときはやってみる」と謳っていますのでこれはやるしか無いなと言うことでGOを掛けた次第です。 今回はそのトップバッターという事で、当社で今年初めから注力し開発している項目の一つである解析プラットフォームについて紹介致します。 セーフィーとは セーフィー解析プラットフォームについて 解析プラットフォームの今後 最後に セーフィーとは 既にテックブログで何度も紹介済みかとは思いますが、セーフィーはクラウド録画サービス「Safie(セーフィー)」を運営しています。 safie.jp カメラにより撮影した大量のデータをクラウド上に保存するとともに、必要に応じてユーザーへLive動画、過去動画を配信したり、動きや異常音が発生した場合にその旨を通知するような機能も提供しています。 インターネットに繋ぐだけで簡単に利用できますが、使いやすさやセキュリティを意識した作りとなっており、広くお客様にご利用頂いています。 現在17万台を超えるカメラを運用しており、20PBに迫るデータが当社システム上に蓄積されています。 Safieサービス概要 また、カメラから取得したデータを解析し、様々な現場の課題解決につなげるようなサービスも既に複数提供しています。 Safie AI People Count safie.jp Safie OneとStore People Detection Pack safie.jp engineers.safie.link engineers.safie.link このようなサービスを実現する上では、旧来の手法やAIを用いた画像解析技術の活用が必須となります。 最近はデバイス側で簡易的なAI処理が駆動できるような、所謂エッジAIカメラやエッジAIデバイスが販売されていますが、解析する内容によって必要なコンピューティングリソースも大きく異なり、ものによってデバイス側で実行出来ない事も多々あります。 また、エッジAIカメラはまだまだ普及している訳ではないので、AI機能を搭載していないカメラが大多数を占める状況となっていますが、当社ではデバイス、クラウド環境共に自分たちで開発、管理していますので、これらの画像解析をどちらでも適した環境で実現できるところに大きな強みがあります。 セーフィー解析プラットフォームについて 先程ご紹介したように、当社では複数の画像データ解析をベースとしたサービスを提供しています。 また、当社データを取得し画像解析を行うような連携サービスを提供しているパートナーさんも存在しています。 当社録画サービスをご利用中のお客様からご相談を頂く事も頻繁にあり、明確に画像データ解析のニーズの高まりを感じています。 一方で、現状では上記サービスそれぞれの開発に数ヶ月以上かかっている状況にあります。 例えば動画から特定の物体を検出するようなサービスを考えた場合にも、解析部分の開発だけでなく、データ入力IFの設計開発、解析エンジン駆動部分の設計開発、開発結果の保存部分、取得部分の設計開発、ものによっては結果を表示するUIの設計開発と多岐にわたる項目の開発が必要となります。 解析系のサービスはまだまだこれから市場開拓をしていく必要がある中で、もっと簡単にソリューション開発を実現出来なければ、大きく市場を広げて行く事は難しいと感じています。 上記の課題を解決するために、セーフィーでは解析プラットフォームの開発を進めています。 解析プラットフォームは主として以下の機能を提供します。 解析プラットフォームイメージ ①開発したAI等に基づく解析エンジンをセーフィーのクラウドシステムに登録 ②必要に応じ、セーフィークラウドシステム、セーフィー対応カメラに展開し解析を実行 ③解析結果をセーフィークラウドシステム上のデータベースに保存 ④解析結果をセーフィーAPI経由で取得し利用可能 現在システムの1stステップがほぼ完成しており、最初の解析サービスの開発を進めている状況となっています。 こちらの仕組みにより、自社、他社問わず解析エンジンだけ開発すればすぐに新しい解析サービスの提供が開始出来るようになると期待しています。 但し、画像解析系のサービスを広げていく上では他にも課題が存在しています。 解析系サービスでは精度が非常に重要な要素を占めますが、画像解析はカメラの設置された環境により精度が大きく影響を受けるという問題があります。 カメラの設置する画角や、設置環境の明るさ、設置環境に検知対象以外にどのようなものが映り込むかなど、様々な事柄により期待する精度が実現できない事があります。 これにより、設置コストやサポートコストが上がったりするだけでなく、結果的にお客様の期待値を裏切るような形になってしまうこともあり得ると考えており、解析サービスを広げていく上で合わせて解決が必要な問題と捉えています。 この問題を解決するために、セーフィーでは個別学習の仕組みの整備を検討しています。 個別再学習機能イメージ ⑤特定の環境下のカメラのデータを元に自動(目標)で個別学習を実行し、問題のある環境下でも精度の担保が出来るAIモデルを生成する この仕組みを合わせて整備する事により、設置コスト、サポートコストを抑える事が出来るだけでなくお客様の期待にきちんと向き合う事ができ、結果的に解析系サービスを広げていく事が本当の意味で実現出来ると期待しています。 解析プラットフォームの今後 上記にてご紹介した解析プラットフォームですが、現在も開発を継続しており、目下以下を目標に対応を進めています。 解析プラットフォームベースのソリューションを確実にリリースする パートナーさんにも解析プラットフォームベースのソリューション開発とリリースまで実化して頂く また、合わせて以下の項目も進めています。 ※解析プラットフォームそのものには含まないですが 多様なアプリケーション開発が簡単に行えるようセーフィーAPIやSDKの整備を進める AIモデル開発そのものがセーフィークラウドシステム内で完結して簡単に行えるような環境を整備する AIモデル開発まで一気通貫にサポート 解析プラットフォームにより、単一環境で容易に画像解析ベースのソリューションが構築できるようになるだけでなく、実運用時の環境要因による精度劣化を低減する事が出来るようになる事が期待できます。 ここまでやることにより本当の意味で解析サービスの利用が広がっていくのではと考えています。 最後に 上記解析プラットフォームの開発を更に進めると共に、2023年は上記を用いた解析サービスによる業界DXを確実に実現していきたいと考えています。 当社としては今後画像解析システムとの連携を更に強化していくべく開発業務に取り組んでいますが、まだまだエンジニアさんが足りていない状況です。ご興味がある方はお気軽にご連絡頂けますと幸いです。
こんにちは、セーフィー株式会社でサーバサイドのエンジニアをしている河津です。同時に、このSafie Engineers' Blog!の運営も行っています。 この度セーフィー株式会社 初の アドベントカレンダーを実施しようと思っており、告知も兼ねた記事を投稿させていただきます! 基本情報 アドベントカレンダーとは? 想定参加者は? 掲載媒体は? 執筆テーマは? 最後に 基本情報 セーフィー株式会社のアドベントカレンダーはこちらになります。 qiita.com なんと25枠全て埋まっており、初開催にしてかなりの盛り上がりを見せております! アドベントカレンダーとは? 元々の意味としては、クリスマスまでの日数をカウントダウンするために使われていたカレンダーで、12月1日からはじまり、25個ある「窓」を毎日1つずつ開けて中に入っている小さなお菓子やプレゼントを楽しむものになります。 このカレンダーに倣って、何か一つのテーマに対して技術記事を12/1から12/25までいろんな人が毎日投稿する、という風習がエンジニア界隈には存在しています。 そんな風習に、弊社も乗っかってみようという取り組みになります! 想定参加者は? セーフィー株式会社に勤める、プロダクト開発に関わる方々を対象にしています。 セーフィーには様々な職種のエンジニアが在籍しており、広い領域の技術話が集まってくるのではないかと(個人的に)期待しています! エンジニアの職種については、以前投稿したこちらの記事もご覧になってみてください。 engineers.safie.link また、「プロダクト開発に関わる方々」という言い方はエンジニアに限定していないというところもミソでして、デザイナー職種の方々、PdMの方々などからも広く記事を募集しております。 掲載媒体は? このブログ「Safie Engineers' Blog!」以外に、「Qiita」、「Zenn」、「note」での執筆もOKとしております。 なのでアドベントカレンダー期間中は、このブログ以外のところでもセーフィーの技術記事が上がっていくことになりますので、興味を持っていただける方は是非ともカレンダーをご確認ください。 執筆テーマは? 自由 としています。 元々このブログに掲載する場合でもそこまでテーマの縛りを設けているわけではありませんが、掲載媒体をSafie Engineers' Blog!にとどめない体制から、さらにフリーダムな記事が生まれるのではないかと思っています。 しっかりした技術話はもちろん、ライトめなものやポエム的なものまで歓迎としているので、ぜひ自由度の高い記事をお楽しみください。 最後に 是非ともセーフィー株式会社のアドベントカレンダーを、このブログ共々よろしくお願いいたします。 アドベントカレンダー終了時には、この記事に追記する形で振り返りの内容を掲載する予定ですのでお楽しみに! qiita.com
こんにちは!セーフィーでサーバーサイドエンジニアをしている神田です。 今回は2022/10/14、10/15に行われたPyCon JP 2022に参加した時のお話をしようと思います! 以下のアジェンダに沿って進めていきます! PyConはどのようなイベントか 参加企業の特徴 どんな人がイベントに参加していたか ブース運営の様子と感想 セッションに参加してみた感想 まとめ PyConはどのようなイベントか ざっくり言うと、Pythonユーザーが集まり、交流できるイベントです! さまざまな企業がブースを出していて、各プロダクトのどのような部分にPythonが使われているかなどお話を伺うことができます。 また、セッションではPythonのライブラリの活用方法やPythonを活かした簡単なプロダクトを作る、などといったお話を聞くことができます。 pycon2022 参加企業の特徴 ほぼ全ての企業ブースを回りましたが、メインでPythonを使用している企業もあれば、第二言語としてPythonを使用している企業もありました。活用方法もさまざまで、バックエンドの言語としてPythonを採用している企業もあれば、機械学習やデータ分析の部分でのみPythonを使用している企業もありました。 さまざまな企業ブースでお話を伺って、Pythonはさまざまな分野のエンジニアが選定する言語なのだな〜と改めて感じました。 今回は全部で22ブースありました。ブースでは企業の方とお話しするだけではなく、プロダクトを見せてもらったり、かわいく便利なノベルティをもらえたり、くじ引きやアンケートなども実施していてとても楽しかったです! どんな人がイベントに参加していたか Pythonユーザーの交流の場なので、Pythonが好き!という方がやはり多かったです。参加する前までは仕事でPythonを使っている人が大半だろうと思っていたのですが、案外仕事では使っておらず趣味で触っている程度という方もそれなりにいらっしゃいました。学習が難しくないPythonだからこそ、さまざまな人に興味を持ってもらえるイベントなのですね! また、中には学生も何人かいました。就活のためにPythonがどういうプロダクトで活用されているのか見にきたそうです。なんて意識の高い。。 ブース運営の様子と感想 セーフィーのブースはこんな感じでした! SafieOne と Pocket2 を展示して、Safie Viewerのマルチビューアーをモニターに映していました。 SafieOneについては下記の記事でも詳細をご確認いただけます! エッジAIカメラ「SafieOne」のアプリ「Store People Detection Pack」とは エッジAIカメラ「SafieOne」の画像認識 カメラのようなハードウェアを展示しているブースは少なく、これはなんだろう?と興味を持ってくれた方が多く立ち寄ってくださいました! エンジニア紹介資料 に沿って、セーフィーのクラウド録画がどのような現場で活用されているかを説明させていただきました。クラウド録画=防犯目的 のみと考えている方が非常に多かったのですが、実際には防犯以外の側面でも活用いただいていることを伝えられたのがよかったと思っています! お昼やセッションの合間の休憩時間には、ブース担当2人では足りないほどのにぎわいでした! ノベルティも好評で、特にステッカーはとても人気でした! セッションに参加してみた感想 2日目はブース担当ではなかったので、ほぼ1日セッションを聞いていました! 参加したセッションは以下です。 退屈なことはSlack botにやらせよう(ver.2) https://slides.takanory.net/slides/20221015pyconjp/#/ PyCon運営をする中で、運営のユーザーから何度も同じ質問に答える手間を無くそう!ということをテーマにSlackBotの簡単な作り方を学べるセッションでした。ユーモアあふれる話し方で聞き手をひきつけ、とても楽しく学ぶことができました! Pythonではじめる地理空間情報 geamapとleafmapを使用して簡単に地理情報を表示する方法について学べるセッションでした。もともと地理空間に関心があったので、ぜひ自分でも試してみようと思いました! データに関する堅牢性と可読性を向上させるpydanticとpanderaの活用方法の提案 データ分析においてデータのスキーマをpydanticとpanderaを用いて使いやすくする、といった内容のセッションでした。pydanticは業務でも使っていたのですが、QAセッションの中でさまざまなPythonユーザーのpydanticへの意見を聞くことができて、とても良い機会でした! はじめての量子コンピューター 量子コンピュータの基礎的な部分を学べるセッションでした。基礎とはいっても内容が難しかったのですが、非常に難しい計算をすばやく解くことができるということだけは理解できました。 どのセッションも匿名で質問を投稿することができ、質問したい人が多い項目から登壇者に答えていただくシステムでした。毎回質問が山ほど投げられており(わたしもたくさん投げていました)、非常に盛り上がっていました! セッションに参加したことで、今まで知らなかったPythonの活用方法を知ることができたのはもちろんのこと、イベントで代表に選ばれて登壇している方を直接目にしたり、多くの人が真剣にセッションを聞いている姿を見て、自分ももっと頑張りたいと思えたことがとてもよかったです! まとめ ブースの参加もセッションの参加も本当に楽しく、非常に充実した2日間を過ごすことができました。コロナウィルスの影響でここ数年はオフラインのイベントに参加できていませんでしたが、来場者の方や他の企業参加者の方と直接コミュニケーションをとることで得られるものも大きいな〜と感じました。 そしてなにより、PyConはPythonユーザーのためのイベントなので、初対面の人でもとりあえずPythonの話ができるため、人と話すのが苦手な自分でもたくさんの人と楽しくお話しできたことが本当に嬉しく、来年も絶対に参加したいなと思っています! また、さまざまな人から自社のプロダクトに興味を持っていただき、いいね!と言ってもらえることで日々の業務にやりがいを感じました!次回もたくさんの人と交流したいので、Pythonユーザーの皆さんはぜひPyConに参加してみてください!
サーバサイドエンジニアの松木 ( @tatsuma_matsuki ) です。 Safieでは、FastAPIを利用していくつかのサービスを開発しています。Safieのサービスの性質上、APIサーバで画像ファイルなどのオブジェクトを扱うことが多いです。 大きいサイズのオブジェクトをクライアントにダウンロードさせるAPIなどでは、FastAPIの StreamingResponse を使うのが便利ですが、このStreamingResponseの使い方を扱った良いリファレンスがネット上であまり見つからなかったので、この記事で実際にコードなどを示しながら実装例を共有していきたいと思います! StreamingResponse S3からオブジェクトをダウンロードして返す 同期・非同期イテレータでのダウンロード時間比較 他サービスAPIからオブジェクトをダウンロードして返す 単体テストの実装 まとめ StreamingResponse FastAPIのStreamingResponseは、HTTPのbodyとなるコンテンツをいくつかのチャンクに分割してストリームで返すために利用されるレスポンスクラスです。まずは、このStreamingResponseクラスのコンストラクタ引数についてまとめてみます。詳細は以下のリンクを参照ください。 https://github.com/encode/starlette/blob/0.21.0/starlette/responses.py#L224 引数 型 説明 content Iterator or AsyncIterable メインとなるオブジェクトのデータ(必須) status_code int ステータスコードを指定(デフォルトは200、省略可) headers Mapping レスポンスヘッダーを指定(省略可) media_type str 指定した値は、Content-Typeヘッダーの値として利用されます。headersでもContent-Typeを指定した場合は、headersの値が優先されます。(省略可) background BackgroundTask BackgroundTask を指定(省略可) メインとなるオブジェクトのデータはcontentの引数に渡します。content引数は、イテレータ、非同期イテレータ(もしくは、ジェネレータ、非同期ジェネレータ)を指定できますので、この仕様に合わせてcontentを渡してあげる必要があります。 S3からオブジェクトをダウンロードして返す オブジェクトを管理するオブジェクトストレージのサービスとしてまず思い浮かぶのはおそらくS3でしょう!APIサーバ上でS3からオブジェクトをダウンロードして、そのオブジェクトをクライアントに返すというような処理に、StreamingResponseが利用できます。 S3からオブジェクトをダウンロードして、それをStreamingResponseで返す処理は、例えば以下のような実装になります。S3からのオブジェクト取得には、 aiobotocore を利用しています。aiobotocoreは、botocoreとaiohttpによる 非同期の クライアント実装となっています。 StreamingResponseは、非同期イテレータと通常の同期イテレータの両方が使用可能なので、非同期ではないbotocoreを利用した場合とのダウンロード時間を比較した結果も後で紹介します。 ... async def s3_client ( settings: Settings = fastapi.Depends(get_settings), ) -> AsyncGenerator[aiobotocore.client.AioBaseClient, None ]: session = aiobotocore.session.AioSession() async with session.create_client( "s3" , endpoint_url=settings.aws_endpoint_url, aws_access_key_id=settings.aws_access_key_id, aws_secret_access_key=settings.aws_secret_access_key, verify=settings.aws_tls_verify, ) as client: yield client def s3_client_sync ( settings: Settings = fastapi.Depends(get_settings), ) -> botocore.client.BaseClient: session = botocore.session.Session() return session.create_client( "s3" , endpoint_url=settings.aws_endpoint_url, aws_access_key_id=settings.aws_access_key_id, aws_secret_access_key=settings.aws_secret_access_key, verify=settings.aws_tls_verify, ) @ router.get ( "/tasks/{task_id}/image" , summary= "Download Image" , response_class=StreamingResponse, ) async def get_image ( task_id: int = Path(..., title= "Task ID" ), settings: Settings = fastapi.Depends(get_settings), s3_client: aiobotocore.client.AioBaseClient = fastapi.Depends(s3_client), # s3_client_sync: botocore.client.BaseClient = fastapi.Depends(s3_client_sync), ): s3_bucket = settings.s3_image_bucket s3_key = f "test/{task_id}/image.jpg" try : image = await s3_client.get_object(Bucket=s3_bucket, Key=s3_key) # image = s3_client_sync.get_object(Bucket=s3_bucket, Key=s3_key) except Exception : raise HTTPException(status_code= 500 , detail= "Failed to get the image" ) return StreamingResponse( content=image[ "Body" ], # 非同期イテレータ media_type= "image/jpeg" , headers={ "content-length" : str (image[ "ContentLength" ]), "etag" : image[ "ETag" ]}, ) botocoreのget_object()のレスポンスはDict型で、"Body"キーの値(image["Body"])にオブジェクトのデータが返ってきます。 image["Body"]の型は aiobotocore.response.StreamingBody ですが、これは非同期イテレータとなっており、StreamingResponseのcontentにそのまま渡すことができます。 同期・非同期イテレータでのダウンロード時間比較 StreamingResponseは、通常の同期イテレータと非同期イテレータの両方に対応していますが、それぞれを利用した場合にどの程度オブジェクトのダウンロード時間が変わるのかを少し見てみたいと思います。 S3(今回はlocalstackを利用)上に10MBのオブジェクトをアップロードして、それを上記で実装したAPIでダウンロードします。 まずは、通常の同期イテレータ(botocore)を用いた場合の結果です。 $ time curl -sv http://localhost:30080/tasks/1/image -o image.jpg * Trying 127.0.0.1:30080... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 30080 (#0) > GET /tasks/1/image HTTP/1.1 > Host: localhost:30080 > User-Agent: curl/7.68.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < date: Wed, 28 Sep 2022 04:26:28 GMT < server: uvicorn < content-length: 10485760 < etag: "46f40f95feefb6ab49b2b3679b5ec0a2" < content-type: image/jpeg < { [1024 bytes data] * Connection #0 to host localhost left intact real 0m19.873s user 0m0.115s sys 0m0.300s 約20秒 ほどかかりました。次に、非同期イテレータ(aiobotocore)を用いた場合です。 $ time curl -sv http://localhost:30080/tasks/1/image -o image.jpg * Trying 127.0.0.1:30080... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 30080 (#0) > GET /tasks/1/image HTTP/1.1 > Host: localhost:30080 > User-Agent: curl/7.68.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < date: Wed, 28 Sep 2022 04:28:05 GMT < server: uvicorn < content-length: 10485760 < etag: "46f40f95feefb6ab49b2b3679b5ec0a2" < content-type: image/jpeg < { [3072 bytes data] * Connection #0 to host localhost left intact real 0m3.825s user 0m0.039s sys 0m0.198s こちらは 4秒弱 という結果でした!非同期イテレータをcontentに指定することでダウンロード時間がかなり早くなっています。 個人的には思ったよりも違いが出たので、API実装する上では、StreamingResponseに非同期のイテレータを渡すことが性能面でかなり重要になってきそうです。 他サービスAPIからオブジェクトをダウンロードして返す S3以外の実装例も紹介したいと思います。複数のサービス連携を実装する中では別サービスのAPIからオブジェクトをダウンロードして、それをStreamingResponseで返すようなシーンもありますので、その実装例も書いてみます。 ... async def get_exit_stack () -> AsyncGenerator[contextlib.AsyncExitStack, None ]: async with contextlib.AsyncExitStack() as stack: yield stack async def get_aiohttp_session () -> AsyncGenerator[aiohttp.ClientSession, None ]: async with aiohttp.ClientSession() as session: yield session @ router.get ( "/tasks/{task_id}/bytes/{size}" , summary= "Download bytes" , response_class=StreamingResponse, ) async def get_bytes ( task_id: int = Path(..., title= "Task ID" ), size: int = Path(..., title= "The number of Bytes to download" ), exit_stack: contextlib.AsyncExitStack = Depends(get_exit_stack), session: aiohttp.ClientSession = Depends(get_aiohttp_session), ): res = await exit_stack.enter_async_context( session.get(url=f "http://httpbin.org/stream-bytes/{size}" ) ) if res.status != 200 : raise HTTPException(status_code= 500 , detail= "Failed to download bytes" ) return StreamingResponse( content=res.content.iter_chunked( 1 * 1024 ), media_type=res.headers[ "content-type" ], ) HTTPクライアントの 非同期実装 である aiohttp を用いて、他サービスのAPIからオブジェクトを非同期でダウンロードする実装にしています。他サービスとして、今回は httpbin.org を利用しています。 aiohttp.ClientSessionでgetした際のレスポンス(ClientResponse)のcontentは、 aiohttp.streams.StreamReader 型となっています。これ自体非同期イテレータとして扱えるため、そのままStreamingResponseのcontentに渡してもOKですが、 iter_chunked(size: int) のメソッドを使って各イテレーションで扱うデータサイズを指定することもできます。 ちなみに、aiohttp.ClientSessionのレスポンスは、コンテキストマネージャーとして実装されており、そのままwith分を書くとwithブロックを抜けるタイミングでクローズされてしまい、contentをすべて読み込めないため、 contextlib.AsyncExitStack を用いて、レスポンスがクローズされるタイミングを遅らせています。 単体テストの実装 最後にmockを用いた単体テストの例も書いてみます。aiohttp.ClientSessionのメソッドをmockすることで他サービスからのResponseをmockしてテストを実装します。 ... class MockByteGenerator : async def iter_chunked (self, size: int ) -> AsyncGenerator[ bytes , None ]: for _ in range ( 5 ): yield b "x" * size class MockStreamResponse : def __init__ (self, content: Any, status: int , headers: Dict[ str , str ]): self.content = content self.status = status self.headers = headers async def __aenter__ (self): return self async def __aexit__ (self, exc_type, exc, tb): pass @ pytest.mark.asyncio async def test_get_bytes (test_client): with mock.patch( "aiohttp.ClientSession.get" ) as mock_get: mock_get.return_value = MockStreamResponse( content=MockByteGenerator(), status= 200 , headers={ "content-type" : "application/octet-stream" }, ) res = await test_client.get(f "/tasks/1/bytes/1" ) assert res.status_code == 200 assert res.content == b "x" * 1024 * 5 aiohttpのClientResponseをmockするclassであるMockStreamResponseは、ClientResponseと同じくコンテキストマネージャーとして実装する必要があり、 __aenter__ や __aexit__ のメソッドを追加しています。また、インスタンス変数として、contentを用意して、iter_chunked()のメソッドが非同期ジェネレータを返すように実装しています。 まとめ FastAPIでStreamingResponseを使って、オブジェクトをダウンロードするAPIの実装例を二つ書いてみました!StreamingResponseは、同期イテレータと非同期イテレータの両方をサポートしていますが、 非同期イテレータを渡してあげることで応答時間を改善することが可能です。S3クライアント、HTTPクライアント共に非同期の実装がすでに存在するので、それらを利用するだけで比較的容易に実装できるかと思います。これから、FastAPIを用いてAPI等を開発される方の参考になりますと幸いです!
こんにちは、フロントエンドエンジニアの沖です。 セーフィーには2022年1月にジョインし映像閲覧WebアプリであるSafie Viewer(以下Viewer)の開発を担当しています。 今回は、Viewerで利用しているフレームワークであるAngularのバージョンアップを9月末のリリース時に行ったのでその話をしたいと思います。 Viewerについて Viewerのアップデートサイクル 今回のアップデートによる変更点 Standalone Components Typed Forms 地味な変更点 アップデート作業について 今後試してみたい新機能 Standalone Components runInContext(Angular 14.1系) まとめ Viewerについて セーフィーのクラウド録画サービスは、カメラで撮影した映像をクライアントアプリケーションを用いて閲覧することが出来ます。クライアントアプリケーションはいくつかありますがその一つがViewerです。ViewerはWebブラウザで閲覧可能なWebアプリケーションとして提供されています。 機能としては、普通に映像が閲覧できる基本機能の他に複数のカメラの映像を同時に閲覧できるマルチビューアーだったりユーザーが独自の画面を作成し、閲覧できるダッシュボードだったり様々な機能があります。 このViewerでは下記の技術が導入されています。 言語:typescript フレームワーク:Angular CSS:Tailwind CSS Code Formatter:prettier Lint:eslint この度Viewerで利用しているフレームワークであるAngularを13から14へアップデートしました。 Viewerのアップデートサイクル Angularは約半年ごとにメジャーリリースが行われるので、セーフィーでは原則として新しいバージョンがリリースされてから1~2か月を目途にバージョンアップを行います。 Angular 13の時のIEサポート終了などインパクトが大きい変更がある場合にはリリーススケジュールが前後する可能性がありますが、出来るだけはやくバージョンアップできるようにしています。 マイナーバージョンについても随時Viewerのリリースサイクルに合わせてバージョンアップしています。 古いバージョンを使い続けることで安定性を担保するという考え方もありますが、最新バージョンに追従することで積極的に新しい機能を利用していくという面もセーフィーでは重要視しています。 今回のアップデートによる変更点 Angular 14の目玉と言ったらなんといってもStandalone Components(Standalone APIs)とTyped formsですね。 Standalone Components Standalone Componentsはmoduleを仲介しなくても直接呼び出せるcomponentで、今までmodule内で定義されていた暗黙的な依存がなくなるということで注目されている新機能です。 今まではNgModuleを定義してその中にcomponentと一緒に使うモジュール群をimportsに入れて定義しなければいけませんでしたが、NgModuleを介さずに直接componentを呼び出すことが出来るようになりました。 @Component({ selector: ‘sf-test’, template: ‘<div>standalone test</div>’, standalone: true // ここをtrueにすることでstandaloneとして扱うことが可能 }) export class TestComponent {} standaloneコンポーネントは直接呼び出せる一方で依存しているmoduleのimportを自身で行う必要があるため全てをstandaloneにするというより要所要所で利用していくのがいい印象です。 Typed Forms Typed formsはReactive Formsのvalueの型を指定できる機能です。 初期値を入れてFormControlを作成、もしくは型を指定してFormControlを定義しておくとそのControlのsetValueを呼ぶ際の型チェックやそのControlが属しているFormGroupのvalueChangesで型をつけることが出来ます。 const a = new FormControl(‘test’); a.setValue(true); // こういった場合にエラーとなってくれます。 地味な変更点 angular.jsonでのdefault projectが廃止になりました。 これにより今後ng buildやng serveの際に必ずprojectを指定する必要があります。 アップデート作業について 今回のアップデートは、あまり破壊的変更はなく新機能の追加がメインだったのでng updateで問題なくアップデートすることが出来ました。 default projectの部分は多くの人が作業が必要になるかと思われますが、それも大きな修正は必要ないため今回のアップデートは比較的気軽に出来るのではないかと思います。 今後試してみたい新機能 Standalone Components セーフィーのアプリケーションの性質上、ユーザーによって同じカメラを所有していたとしても利用できる機能が異なる場合があります。 現状もそのような場合にはLazyLoadingを利用して機能が必要のないユーザーに余計なモジュールをロードさせないような仕組みがあるのですが、その一部をStandalone Componentsに置き換えることで見通しのいいコードにできるのではないかと考えています。Developer previewが明けたら本格的に導入を考えたいと思います。 runInContext(Angular 14.1系) こちらは14.1の機能ですが、EnvironmentInjectorにrunInContextというメソッドが追加されました。この機能はrunInContextの中ではinjectメソッドを使うことによりEnvironmentInjectorでinject可能なサービスを取り出すことが出来るというものです。 今までは、DIで取り出すサービスを用いた処理は、InjectableなクラスやComponentなどAngularの管理下のクラス内で記述する必要がありましたが、これを用いることでサービスを用いたビジネスロジックもfunctionとして外に持たせることが可能となります。 const test = function() { const testService = inject(TestService); // testはただのfunctionですがこの中でinject出来ます。 } envirionmentInjector.runInContext(() => { test(); }); ビジネスロジックを外に出せるとテストの観点でも再利用の観点でもメリットが大きいので是非こちらは今後採用していこうと思っています。 まとめ 今回のAngularアップデートでは破壊的変更はあまりないものの新しい魅力的な機能が多数追加されているので、積極的にそれらを取り入れて使いやすく拡張性の高いアプリケーションにしていきたいと思っています。 フレームワークアップデートは場合によってはコストがかかる場合もありますが、保守性の向上やアプリケーションの最適化のためにも素早い追従が重要であると考えています。
こんにちは。セーフィー株式会社 モバイルエンジニアの渡部です。 今回は、モバイル開発のデザイン作成で活用しているツール「Figma」についてお話ししたいと思います。 Figmaとは 基本的な構成 Figma導入までのいきさつ Figmaで解決できたこと Figma vs XD XD Figma 最後に Figmaとは UIデザインやワイヤーフレーム作成のためのアプリケーションです。 デスクトップ版も用意されていますが、メインはWebアプリケーションとして提供されています。 動作が軽快で、リアルタイムでの共同編集が簡単に行えることが強みのツールです。 料金プランは現在3つ用意されており、安価なプランの順に、Starterプラン(無料)、Professionalプラン、Organizationプランがあります。 料金が上がるにつれ機能制限が無くなり、また扱える機能もより組織に向けた高度なものが増えていきます。 無料のStarterプランは作成できるファイル数に限りがありますが、編集権限を上限数無くユーザーに付与できます。 基本的な構成 画面サンプル キャンバス上にフレームを置き、フレーム上にボタンやテキスト等のパーツを追加していきます。上の画像だと、iPhone13をイメージした画面が2つキャンバス上に並んでいますが、これらがフレームです。 フレームやパーツの追加はツールバーから行います。繰り返し使うパーツはコンポーネント化(テンプレートのような機能。コンポーネント本体を編集すると、その複製も一括で編集される)もできます。 プロパティパネルでは、オブジェクトのスタイルを編集する他に、画像ファイルへの書き出しやプロトタイプ(モックのアニメーション)が作成できます。 また、ファイルに書き出すことなくその場で、選択中のオブジェクトのコード表記も確認できます。 Figma導入までのいきさつ モバイルチームでは従来、Adobe XDを用いてアプリデザインを行なっていました。 XDもUI/UXデザインツールとしては定番のアプリケーションです。 ツールを実際に活用するのはライセンスを割り当てられたデザイナーのみで、エンジニアはオンラインでの共有機能を使用して成果物の確認を行っていました。 しかし、XDを活用するにつれデザイナーとエンジニア双方から様々な要求と、それに伴う課題が挙がるようになりました。 成果物を手軽に共有したい XDの共有機能は、共有したいデータについてURLを発行することでオンライン上で閲覧が可能になるもので、データ作成者のみがURLを発行できます。 現状のチームの運用では、作成者と更新者が必ずしも一致しないので、URLをどこかに控えたり、発行を都度依頼する必要がありました。 また、データを更新すると、URLを据え置きにするか再発行するか選択できるはずなのですが、稀にその連携がうまくいかない場合が…… ファイル内のアートボード(アプリ画面)が増えても動作は軽いままがいい アプリ内デザインを一つのファイルに集約すると、それをXDで開く時点では問題無いのですが、共有URLで閲覧する際の動作が重くなります。 共有URLでの動作を軽くするために、ファイルを複数に分けていましたが、更新や管理が煩雑になりがちでした。 デザインデータとセットでコメントやメモを残したい 閲覧者もオンライン上のデータにコメントを残すことができますが、URLが削除されるとコメントも消える仕様でした。 完了したプロジェクトの共有URLは削除されることもあり、コメントを見返すことができないケースもありました。 軽微な修正をエンジニアも行えるように編集権限を与えたい 人数ごとにAdobeアカウントと利用料が必要となり、費用を考慮すると全員への付与は厳しいです。 これらを解決する代わりとなるツールを検討することになりました。 上記に加えて、検討の際に条件として上がったのは、 動作が軽快であること プロトタイプが作成できること お試しで運用がしやすいこと(無料プラン等が提供されている) などです。 結果、以上を満たして操作性や費用面を加味した上でFigmaに乗り換えることとなりました。 Figmaで解決できたこと Figmaに乗り換えてみて、先述した要求はかなり改善されました。 成果物を手軽に共有 原則としてブラウザ版を使用し、チーム全員に閲覧権限を付与することで、常に最新状態のデザインを確認できるようになりました。 例えばオンラインでのミーティングでも、各自がファイルを開きつつリアルタイムで変更点を話し合ったり編集することが可能になりました。 ファイル内のアートボード(アプリ画面)が増えても動作は軽いまま Figmaに移行するにあたって、XDで作成していたデータを1つのファイルにまとめました。下の画像のように、キャンバス内に全てのフレームを集約しています。 実際のファイルは更にフレームが増えていますが、読み込みも動作も軽快なままです。 ブラウザ上のファイル デザインデータとセットでコメントやメモを残す コメント機能も備わっており、デザイン決定までの経緯などをメモとして残せます。キャンバスを縮小してもコメントの存在を示すマーカーが表示され続けるので、どの部分にコメントが集中しているか視覚的に把握できます。 slackとの連携も可能で、自分へのメンションにも気付きやすいです。 編集権限に上限が無い 現在、モバイルチームではStarterプランを利用しています。 冒頭で書いた通りStarterプランは無料かつ編集権限に上限数が無いので、費用とアカウント数を気にせずエンジニアにも権限を付与できています。 実装過程で発生したデザイン上の軽微な修正や変更をエンジニアが行うことで、わざわざデザイナーに依頼してその作業待ちをすることが無くなり、全体の効率が上がりました。 また、当初は予想していなかった副次的に良かった点もありました。 採用・異動でチームの入れ替わりがあっても、仕様の共有が簡単になった 以前よりも成果物の共有と管理が楽になったことで、新しいメンバーにとっても仕様が把握しやすく、プロジェクトに参入しやすくなりました。 エンジニアのデザイン仕様に向ける関心が高くなった 編集を通じてエンジニアが直接的にデザインに関わる機会が増えたためか、当事者意識が高まった気がします。デザイナーとエンジニア双方が集まって意見を交わすことが増え、UIの検討が活発になりました。 エクスポート機能など、デザイン以外で便利な機能も多い 書き出しを介さないコード変換機能や画像出力機能など、デザイナーだけでなくエンジニアにとっても助かる機能が多々あります。 1ファイルが巨大になりがちな分、その一部分だけを扱う操作にも優れています。 Figma vs XD モバイルチームでは結果的にFigmaの特徴がうまく噛み合い活用できていますが、それまで活用していたXdにも利点はありました。XDのメリット、またどのようなケースであればそれを活かせるのかをFigmaと比較して考えてみました。 XD 編集権限はライセンス保持者のみに与え、閲覧者には簡易機能のみを許可できる 編集者と閲覧者で業務を明確に切り分けたい場合に有効。 成果物の共有ページ(共有URL)の機能がシンプル 操作が分かりやすいので、閲覧者が相当数いるチームでも活用しやすい。 他のAdobe製品と共通の操作性 チームが元々Adobe製品に馴染んでいる場合は導入しやすい。 プランによってはAdobe製品を横断して使用可能(CreativeCloud) UI/UX制作の他にも幅広くデザイン業務を行いたいケースでは便利。 Figma ユーザーに与えられる編集権限の上限数がない デザイナーに限らずメンバーが成果物に手を加えたい場合に有効。 コード変換機能やクリップボードへの直接書き出し機能など、ちょっとした機能が多数あり チームに開発者が多い場合、特に実装で役に立つ。 作成できるファイル数に限りがあるが無料プランあり 安価で運用したい少人数のチームにハマる。 そして、少し前になりますが、2022年9月16日にAdobeによるFigma買収が発表されました。驚きましたね… 個人的には、XDとFigmaは同じデザインツールといえどターゲットとするユーザーが異なると思っていたところだったので、両者の利点を生かしたままサービスが継続してくれればいいなと願っています。 最後に FigmaとXDの双方を使用してみてそれぞれの強みがあると実感しましたので、今後もツール選定の際は個々の特徴と自チームの目的が噛み合うか加味して決めていきたいなと思いました。 Figmaの特性である「共同編集に優れている」点は、実際使ってみることでデザインやUIに関わることの敷居を下げてくれ、非デザイナーがデザインに寄せる関心を高めることにも繋がっているなと、こうして振り返って思いました。 Figmaの理念は「すべての人がデザインを利用できるようにする」とのことで、まさしくそれを体感できたなと感じた次第です。 ここまで読んでいただきありがとうございました。
はじめに セーフィーで画像認識エンジニアをしている橋本です。本記事では、先日発売されたエッジAIカメラ SafieOne で利用可能なサービス 「Store People Detection Pack」 で開発した 画像認識システムとアルゴリズム について紹介したいと思います。 はじめに システムの概要 物体検出 学習時の工夫 量子化の工夫 トラッキング イベント発行と送信 まとめ 参考URL 「Store People Detection Pack」とは、小売業界の課題を解決するために作られた人物検出AIを使ったサービスです。 別記事 でも解説されていますので、是非合わせてご覧ください。 本サービスを利用することで、Webマーケティングでは当たり前に可視化できているコンバージョンにつながる顧客の行動を、リアルな店舗の映像から明らかでき、 小売業界での映像データの利活用が進む のではないかと期待しています。 Webサイトでは、どのようにページを遷移して商品を探し最終的な購入に至ったのかを把握できるため、「クリック率(逆に離脱率)がどのくらいなのか」といった情報から分析を行い、最適化が行いやすくなっています。一方で、リアルの店舗では、レジの売り上げ(POS)データで最終結果は分かるものの、購入に至るまでの経緯はブラックボックスになっています。 例えば、「今日は『かつ丼弁当』を食べよう」と思い立ってスーパーマーケットのお弁当コーナーに行き購入に至った目的買いのお客様と、店舗で様々なお弁当を検討して「かつ丼弁当」を購入したお客様の違いをPOSデータから見分けることはできません。本サービスを使えば 「かつ丼弁当」の前で立ち止まった人数を可視化でき、さらに録画映像を振り返って要因分析を行うことができます 。 システムの概要 本サービスの技術的な特徴は エッジAIを使った画像認識 を行っていることです。エッジAIというのは画像をアップロードしてサーバー上で推論するのではなく、カメラ毎に搭載されたプロセッサで推論するAIのことを指しています。一般的に、エッジデバイスには AIアクセラレータ が搭載されており、ニューラルネットワークを効率的に計算することができます。SafieOneの場合はQualcomm製のDSPが搭載されており、 SNPE(Snapdragon Neural Processing Engine)SDK を使ってネットワークの実行部分を実装しています。 本サービスがエッジAIを採用している理由としては、 低コストなリアルタイム処理が得意 デバイスごとに異なる賢さのAIをインストールできる(個別AI) の2点が挙げられます。 リアルタイム処理については、カメラの映像をデバイス内で直接処理できるのでアップロードが不要でレイテンシが少なく、専用アクセラレータを用いるためサーバー上の汎用ハードウェア(CPU、GPU)と比べてコストパフォーマンスに優れています。 また、個別AIについては、まだお見せできないのですが、 特定のユーザ・業種に対して専用のAIを簡単に作成してカメラ毎に異なる賢さを搭載できる ように開発を進めています。サーバー推論の場合はある程度のユーザ数で推論モデルと計算資源を共有することになるため、低コストな個別対応が難しいといった課題があるのですが、当社は自社でエッジAIカメラを販売しているため対応が行いやすくなっています。 システム全体の構成は上記のようになっています。SafieOneにはオプションを付けることで様々なアプリ(AI-App)がインストールできるようになっています。 PeopleDetection はエッジAIの本体でニューラルネットを使った画像認識を行うアプリです。 SafieEdgeAppFramework はSafieOneにインストールされるアプリのライフサイクル管理や、カメラ画像をアプリに送信する役割を持っています。 SafieClient はカメラハードウェアの制御、映像や検出結果(イベント)をサーバに送信するのが主な役割です。SafieEdgeAppFrameworkやSafieClientについては、 別記事 で解説されていますので是非合わせてご覧ください。 本サービスではエッジ側で画像認識結果をある程度集計して、ユーザが興味を持つ有益な事象(イベント)だけをサーバーに送って保存する仕組みになっています。ユーザーがSafieViewerを操作して検出結果の時系列グラフを見たいといったリクエストを送った場合には、サーバーに保存されているイベントを使って描画するという処理の流れになります。 エッジAI本体のPeopleDetectionは上のようなパイプラインで処理を行っています。物体検出( Object Detection )、追跡( Tracking )、イベント発行( Event Publishment )については次節以降で詳細を説明します。 物体検出 ライセンス: CC BY-SA 4.0 画像認識とは画像に含まれる意味や構造を抽出して、テーブルデータとして利活用できる状態にするプロセスのことを言います。画像認識のタスクはいろいろありますが、本サービスでは 物体検出 を利用しています。物体検出とは、 オブジェクトのカテゴリと位置と大きさを検出するタスク のことを言います。物体検出(object detection)は受け取った画像から、検出結果(raw detections)を計算して、次の追跡(tracking)処理に渡します。 SafieEdgeAppFrameworkにはビデオフレーム購読用のインターフェースが定められており、これをアプリ開発者が実装すると、当該メソッドが1 sec / 10 fps = 100ms間隔でcall backされて、アプリがカメラから画像を取得できる仕組みになっています。推論間隔が空いてしまう場合に、人物の動きが大きくなってトラッキングが不安定になるため、パイプライン全体のレイテンシの平均値と標準偏差を計測して、100msに収まるように ネットワークの選定とチューニング を行っています。 当社では、MobileNetV2-SSD、Yolov5、YoloXなどのアルゴリズム調査とチューニングを行い最も性能の良いネットワークと学習結果を採用しています。物体検出のアルゴリズムの進歩は早く、最近はPicoDet、Yolov7など新しいネットワークが登場していますので随時アップデートをしていきたいと考えています( ので エンジニアを鋭意募集 しております! )。 学習時の工夫 右画像のライセンス: CC BY-SA 3.0 画像認識の学習では、 推論環境と学習時で画像の分布を合わせることが重要 です。当社のカメラ(左)は天井に設置することが多く俯角が大きいことや、水平114° 垂直60°の広角レンズを使っているため、人物の見え方がCOCOのような汎用的なデータセット(右)とはかなり異なってきます。そこで、COCOをベースとしながら、 当社のドメインに合わせた画像を約21,000枚追加 したほか、画像回転のデータ拡張を強めにかけることで、パースによる人物の傾きに対応するようにしています。 量子化の工夫 エッジ実装では高速な演算と引き換えに、量子化誤差によって推論精度が低下することがあります。CPUでは32ビット浮動小数、GPUでhalf precisionを使った場合は16ビット浮動小数が利用できるため、丸め誤差を気にする必要はありませんが、SafieOneのDSPで 8ビット固定小数を利用した場合、256 段階の表現しかできないため考慮が必要 になります。量子化誤差を少なくするためのポイントは、 各レイヤーの出力の値域を絞る 出力の分散ごとにtensorを分ける ことです。 上の図はYolox-nanoの1・2番目の畳み込みレイヤーをnetronで可視化したものです。デフォルトのactivationは SiLU (左)となっていますが、上界がない(unboundedな)ため大きな値が出力される可能性があります。そうした場合に8bitで量子化するとステップ幅が大きすぎるためおおきな丸め誤差が発生し細かな諧調が失われる可能性があります。そこで、学習時に ReLU6 (右)など適当な閾値でクリップするようなactivationを使って値域を限定することで、学習時の性能(mAP)は下がりますが、8ビット変換時の量子化誤差を低減できました。 また、フレームワークに依存しますがchannel単位の量子化に対応していない場合(tensor単位の量子化しか対応していない場合)は注意が必要です。畳み込みの出力するtensorの分散がchannel毎に異なっていた場合、分散の大きなchannelにつられて量子化幅が決定され、分散の小さなchannelの情報が消えてしまいます。これを解決するには、分布が似ているチャネルごとにconvolutionの出力を分ける必要があります。 Yolox-nanoに416×416の画像を入力した場合に、一番大きな特徴量マップ(52×52)には、4チャネル(x, y, w, h)を出力する回帰用のヘッダ(左)、objectness(0~1)を出力する分類用のヘッダ(真ん中)、11クラスのスコア(0~1)を出力する分類用のヘッダ(右)が接続されています。回帰用のヘッダは値域が限定されないため、分類用のヘッダと同じtensorに纏めないほうが良いとされています。このネットワークでは、畳み込みは異なる経路で行っているため問題ないのですが、その後で1つのtensorにconcatする部分に注意する必要があります。1つのtensorにすることで量子化が再度行われ、丸め誤差が発生してしまうため、concatの前の出力をCPUの32ビット浮動小数点を使って計算することで精度の悪化を防ぐことができました。 物体検出では一般的に最終レイヤーで回帰と分類を行い、その後、デコード処理としてAddやMultiply、出力をまとめる目的でConcatenateが使われることが多いです。このような変換処理の度にtensor全体で再度量子化が行われ、丸め誤差が繰り返し発生してしまうため、 後処理の量子化実行には注意しておくと良い と思います。 トラッキング トラッキング処理は物体検出の結果(raw detections)を受け取って、人物IDのついた追跡結果(tracklets)を出力します。主な機能として、 同一人物に同じIDを割り当てる 検出漏れがあった場合に位置を推定して補間を行う を持っています。PeopleDetectionでは、軽量かつ性能も良いため SORTアルゴリズム を使っています。処理の流れは以下の通りです。 カルマンフィルタ を使って前フレームのtracklet(人物の位置と速度)から現フレームのtrackletを推定する 推定したtrackletとraw detectionを ハンガリアン法で二部マッチング する イベント発行と送信 イベント発行(Event Publishment)処理では、追跡処理で出力したtrackletsを受け取り、ユーザが興味を持つ有益な事象が発生した場合に、イベントとしてサーバに送信します。サーバーに送付するイベントは以下の3種類を定義しています。 設定した領域が滞留人数と時間の条件をみたした時に送信される PeopleDetectionEvent 設定した領域から人物が退出した時に送信される AreaLeaveEvent 設定した線分を人物が交差した時に送信される LineCrossEvent 上記のイベントがそれぞれ、 立ち入り検知 立ち入りカウント 通過人数カウント のサービスに利用されます。 PeopleDetectionEventは「 設定した領域で、N人以上、M秒以上の滞留が発生した場合 」にサーバーに送信されるイベントです。人物毎に滞留時間を計算することで、一時的にエリアに入った通行人を除くことができます。サンプル動画では3人以上10秒以上の条件を設定していますが、3人がエリアに入っただけでは条件をみたさず、最後に入った人物の滞留時間 t ≥ 10のときに条件が成立したと判定しているのが分かると思います。 このイベントが発生した時には、ユーザに通知を送る、Viewerのタイムラインにフラグとサムネイルを表示するといった処理が行われます。例えば、 レジ待ち行列が長くなったタイミングで通知を送ってレジ応援を呼ぶ といったオペレーションや、 映像の振り返りを効率化する といった活用方法を想定しています。 AreaLeaveEventは「 設定した領域から人物が退出したとき 」にサーバーに送信されるイベントで、イベントが発生した時刻のタイムスタンプと、人物がその領域に滞在した秒数を含んでいます。このデータをサーバで集計することで時間帯ごとにエリアに滞在していた人数を計算して、時系列グラフを表示できるようになっています。さらに、「N人以上、M秒以上」のクエリで絞り込むことで立ち止まりの人数だけを可視化することもできるため、 通行人と立ち止まりの比率を使ったファネル分析 といったご活用をしていただいています。 LineCrossEventは「 設定した線分を人物が交差したとき 」にサーバーに送信されるイベントで、イベントが発生した時刻のタイムスタンプと、線分を交差した方向を含んでいます。サンプル動画ではOut方向に2人、In方向に1人をカウントしています。 線分の前後でうろつく人物を過大にカウントするのを防止するため、線分を跨いだら同一人物に対して一定のクールダウン期間を設けるなど、フィールドテストで得られた知見から細かな改良を行ってきました。このデータもサーバーで集計されて時間帯ごとの入退場人数を計算して、時系列グラフを表示するのに使われます。 店舗入り口や通路に設置して人流の解析に使用する など、様々な用途でご活用をいただいています。 まとめ 本記事では、SafieOneで利用可能なサービス「Store People Detection Pack」で開発した画像認識システムやアルゴリズムについて紹介しました。当社のクラウドには、 15万台以上のカメラが常時接続されており、画像認識サービスを開発するのに恵まれた環境 だと思います。本記事で紹介したサービスの他にも、多様な映像サービスの考案と開発を進めていますので、 是非エントリーしてみてください 。 エントリーページ 参考URL かしこくなるAIカメラ Safie One(セーフィー ワン) SHIBUYA109渋谷店においてAIカメラ「Safie One」の実証実験を開始 セーフィー、ベルクと共同で「Safie One」を活用した実証実験を実施 セーフィー、エッジAIカメラ「Safie One」来店人数や混雑具合を可視化 | IT Leaders
こんにちは。セーフィー株式会社 バックエンドエンジニアの村田 ( @naofumimurata )です。 セーフィーには2020年9月に入社して今年の9月で2年が経ちました。入社後はインフラグループに配属となり、既存インフラの改善や新規サービスのインフラ設計/構築などサービスのインフラを支える仕事を担当していました。実は1年ほど前から自分の希望でチームを移動し、現在はサーバサイドの開発業務をメインで行っています。 今回はこれまでを振り返ってみて、サーバサイド開発に転向する上で大変だったことや良かったことなどを書いてみようと思います。 自己紹介 インフラグループでの仕事 スクラム開発の導入とサーバサイド開発へのチャレンジ なぜ転向したのか 実際やってみて 大変だったこと 良かったこと さいごに 自己紹介 まず、私自身の経歴について簡単にご紹介したいと思います。 大学院 CS専攻 を卒業 Web系企業に入社し SRE (Site Reliability Engineer) として2年半ほど勤務 セーフィーに入社 元々、低レイヤーの技術領域に関心があり、大学院ではデータベース管理システムの高性能化を研究していました。2018年に大学院を修士で卒業し、Web系企業に入社しました。入社後は SRE (Site Reliability Engineer) チームに配属され、サービスのインフラを管理する仕事を担当していました。2年半ほど経った頃に転職で今のセーフィーへと入社し現在に至ります。 インフラグループでの仕事 2020年9月にセーフィーに入社した後はインフラグループに配属となりました。インフラグループはセーフィーのクラウド録画サービスを支える全てのインフラの管理/改善などを行うチームで、主に以下の業務を行っています。 100万台規模のクライアントが接続するクラウド録画サービスを安定して提供できるアーキテクチャの設計・開発 サーバコストを抑えるための各種最適化 サービス・システムの監視やチューニング等の運用 参考: https://open.talentio.com/r/1/c/safie/pages/54192 セーフィーではインフラ環境としてAWSを利用しているのですが、自分が入社した当時はEC2インスタンスで稼働するアプリケーションのECS移行をまさに始めようとしている時期でした。入社直後はまずはその仕事を任せられることになり、いきなり重要な仕事を任せてもらえて嬉しかったことを覚えています。その後も既存インフラの改善から新規サービスのインフラ設計/構築、CI/CDの改善などいろんな仕事をやらせていただき、知識/技術を深めていくことができました。 スクラム開発の導入とサーバサイド開発へのチャレンジ インフラグループで1年ほど経った後、転機が訪れます。サーバ/インフラグループを中心に開発手法としてスクラムを導入することになり、チームの再編成が行われることになりました。これまでは人に対してプロジェクトを割り振るという開発スタイルだったために属人化や責任が集中してしまうといった問題があり、それを改善するべく認定スクラムマスターの資格を持ったメンバーを中心に導入することになりました。 参考: https://article.safie.link/safietimes/voice/2388 スクラムの導入にあたりチームが再編成されることになったのですが、その時の上司との1on1で、サーバサイド開発に挑戦したいという意向を伝えたところ(以前からそういう気持ちがあることを伝えてはいました)、いいタイミングだしサーバサイドの開発を行うチームに移るのが良いんじゃない?というお話しをいただき、はれてサーバサイドの開発を行うチームに異動することになりました。 なぜ転向したのか そもそもなんでサーバサイド開発をやりたかったの?という部分ですが、大きく以下の2つの動機がありました。 自分のキャリアに対する見識を広めたい 開発スキルを身につけ、セーフィーのシステム全体の理解度を高めたい まず1つめの動機についてですが、自分のエンジニアとしてのキャリアを考えるにあたって選択肢をなるべく増やせると良いかなと考えています。自分は今年でエンジニア歴5年目になりますが、これまでインフラの仕事しかしてきませんでした。元々、低レイヤーの技術領域が好きだったので、仕事内容に不満はなくそれなりに適性はあるのかなと思う一方で、ほんとにこの道が自分には合ってるのか?と悩む時もありました。色々悩んだ結果、そもそも他の技術領域をやったことないのに適性を判断するのは難しいので、色々やってみるのが良いんじゃないかという結論になりました。人生の時間は有限なので全ての領域にチャレンジするのは難しいですが、なるべく遠回りしていければ良いかなと思っています。 2つめの動機は単純で、開発を通してアプリケーション部分の理解を深めたいという思いです。これまでインフラチームでの仕事を進めるなかで、インフラ部分の知識や理解はついてきたのですが、各アプリケーションの具体的な動作やどう連携しているかについてはざっくりとしか把握できておらず、問題の調査がある段階までいくと難しくなったり、インフラに留まらない一歩踏み込んだ改善などができずにいました。開発業務を行わなくてもこれらの知識を深めることも可能だとは思いますが、やはり実際に自分で開発することで、より実感として得られるものがあるかなと考えました。 実際やってみて さて、実際にサーバサイドの開発業務を行うことになりましたが、いきなり全ての仕事をがらっと変えるというのではなく、ちょっとずつ開発の仕事をとっていくスタイルで進めていきました。徐々に開発業務の割合を増やしていき、現在はだいたい9割が開発業務という状態になっています。 ここでは、特に最初の頃を振り返ってみて大変だったこと、そして良かったことについて書いてみようと思います。 大変だったこと あたりまえですが、最初は技術面でキャッチアップすることが多くなかなか大変でした(今も苦労していますが)。これまで、TerraformやAnsibleといったいわゆるIaCのコードについては日常的に書いていましたが、アプリケーションのコードを書くという経験があまりなかったため、まず言語やフレームワークの使い方といった基本的なところから習得する必要がありました。 セーフィーのサーバサイドで稼働するアプリケーションには映像閲覧用のWeb/モバイルアプリケーション向けのAPIを提供するものや、カメラ映像を録画/配信を行うものなど様々なものがあります。前者ではPythonが使われており、後者ではJavaやGoなどが使われています。実際にサーバサイドの開発業務を始めるにあたり、まずは前者のPythonによるWeb APIの開発を行うこととなったため、まずはPythonの書籍を読みつつSQLやWeb APIの設計に関する書籍などを読んでいきました。具体的には、技術評論社の『Python 実践入門』、オライリー社の『Web API: The Good Parts』、『SQLアンチパターン』などです。カメラ映像の録画/配信を行う部分についても、少しずつ触れてきてはいますが、映像配信周りはかなり専門知識が求められる部分で難しく、その辺りのキャッチアップが自分の今後の課題です。 また、技術そのもの以外だと各アプリケーションのパッケージの構成やテストの書き方などについても最初キャッチアップするのに苦労したのを覚えています。このあたりは、歴史的な経緯でこうなってるみたいな部分もあり、背景を知るチームメンバーに教えてもらいつつ徐々に知識を付けていきました。 良かったこと まず、会社/チームからのサポートを得られたことが一番良かったことでした。未経験の技術領域にチャレンジするにあたって、自分のやりたい!という気持ちとは裏腹にチームとして受け入れてもらえるのか?という点が一つ懸念されることだと思いますが、その点が全く問題なかったのは良いことでした。短期的にみると、どうしてもパフォーマンスが下がってしまう可能性がありましたが、それよりも難しい課題に対してチャレンジすることを評価すると背中を押してもらえたので、会社からの評価が下がるといった不安なく仕事を進めることができました(実際、評価はむしろ上がりました)。 また、実際に開発業務をやるようになって、各アプリケーションの具体的な動作や連携方法などが以前よりもわかるようになり、システム全体の理解が深まったのも良かったです。これはそもそもの動機として挙げていた内の一つで、まだまだ把握できていないところは依然多いのですが、着実に達成されつつある実感があります。 さいごに 今回は、インフラ職からサーバサイド開発に転向している話をご紹介させていただきました。セーフィーに入社してまだ2年ですが、振り返ってみるといろいろ自由にやらせてもらっているなと感じました。まだ転向してから日が浅く、ちょっと道半ばな振り返りでしたが、同じようにキャリアについて悩んでいる方の参考になれば幸いです。ここまで読んでいただき、ありがとうございました。
こんにちは「Store People Detection Pack」のPdM(プロダクトマネージャー)の谷野です。 8/4にセーフィー初となるエッジAIカメラ、「 Safie One 」の製品発表を行いました! safie.co.jp 「SafieOne」では、エッジAIを利用する為の設定や結果を確認することができるブラウザアプリケーション「 AI-App(あいあっぷ) 」を使うことで、「映像×AIによる課題解決」ができる賢くなるカメラを目指しています。 その「AI-App」の第一弾として、「 Store People Detection Pack 」(AI-Appを使用できるようにするための、カメラと紐づくオプション)が小売り・飲食等向けに販売されます。 今回は、「AI-App」が目指すもの、そして「Store People Detection Pack」のコンセプトや機能に関して、PdM視点でご紹介させていただきます! 店舗におけるAIの役割 「Store People Detection Pack」のコンセプトとリリースまでの道のり Store People Detection Packの3つの機能 ①立ち入り検知 ②通過人数カウント ③立ち入りカウント 「AI-App」の今後 さいごに 店舗におけるAIの役割 セーフィーでは、「映像から未来をつくる」というビジョンのもと、防犯利用にとどまらずカメラが進化していく為のロードマップを5つのステップで提唱しています。「SafieOne」では、ステップ4の「映像×AIによる課題解決」を目指しています! 飲食や小売りの店舗様では、セーフィーのカメラを防犯用途はもちろんのこと、店舗運営のサポート、業務改善等にご活用いただいています。例えば、チェーン店等ではコンサルタントや本部の方が実際の店舗に訪問する+映像を確認することで、効率的かつ確度高く店舗の状態を把握したり、コンサルティングすることで、PDCAサイクルを早めることができます。 この映像を確認するきっかけとなるのが、下記のような場合です。 防犯:何かトラブルが発生した際に過去の映像を確認をする 業務改善:店舗のデータから気になる日時の映像を確認する 店舗でAIを使うと、リアルタイムにトラブルを発見出来たり、膨大な映像から知りたい映像にフラグが立てられ映像を探す時間が短縮されたり、検知結果の該当映像を確認することで新たな顧客の行動が発見されたり、店舗の既存システムでは取得できないデータを可視化したりすることができます。 店舗にとってAIは、店舗運営や課題解決に必要不可欠なものを見える化してくれるものだと思っています。 「Store People Detection Pack」のコンセプトとリリースまでの道のり 「Store People Detection Pack」は、誰もが手軽に店舗の課題解決につなげることができる機能とUI、価格であることをコンセプトとしています。 小売り・飲食のお客様から課題として多く声をいただいていたのが、主に下記3つです。「Store People Detection Pack」ではエッジAIの「人検出」を使い、それぞれを解決できる機能を盛り込んでいます。エッジAIは、カメラ側で人の検知を行いその情報を都度カメラからサーバーに送信します。そのため、利用者はリアルタイムに情報を受け取ることができます。 レジ混雑による機会損失をなくしたい →レジが混雑した場合に、検知を行い通知を受け取れる 棚レイアウトの効果検証手段がない →棚や商品の前に立ち止まった人数をカウントしグラフ化する 人員配置が適正かどうかわからない →店舗入口での入店、退店の人数をカウントしグラフ化する また、課題と共に多く声を頂いていたのが、価格です。複数のお客様から「課題を解決できるかもしれないAIカメラの提案を他社から受けたが、価格が非常に高く導入を見送った」と話しを伺い、「Store People Detection Pack」ではAIを手軽に使える価格での提供に努めました。 機能が形になってきた段階でフィールドテストを実施し、「店舗の課題が解決できる機能が盛り込まれているか」、「簡単に設定ができ、手軽に結果が取得できるか」等の確認を行いました。実は、初めてお客様に使ってもらった時、お客様だけでは、設定を完了することができませんでした。そのフィードバックを受け、現在は、設定時の遷移の仕方を改善することで、簡単に設定が完了できるようになっています。また、グラフも、知りたい情報が得られないとフィードバックがあり、グラフで表示される期間や集計単位がPOSデータと照らし合わせられる等、運用に合うようにるように改善を行っています。 また、「設定したエリアの中に立ち止まった人数をグラフ化する」という1つの側面においても、設計の試行錯誤がありました。設計にAIの画像処理側では、どの検知情報をどのタイミング(エリアに入ったorエリアを出たタイミングなど)でカメラからサーバーに送るか、サーバーでは時間をかけずにどう集計するか、フロントではどのように滞留時間でグラフを更新するかなど。 ここに記載の内容は本当に一例ですが、約7か月に渡るフィールドテストの期間を経て、機能、UI共に改善を繰り返し、リリースに至りました。 Store People Detection Packの3つの機能 SafieOneでは、エッジAIにて人を検知しています。「Store People Detection Pack」では上述した課題に応えるため、人検知を活用した以下3つの機能が盛り込まれています。 ①立ち入り検知 概要 :設定した条件に応じて、エリアに対して立ち入った人を検知し、通知する ユースケース :レジ混雑時に通知する、ディスプレイに立ち止まった人がいた場合に検知する、立ち入ってほしくないエリアに人が立ち入った場合に通知する ②通過人数カウント 概要 :設定したラインに対して、IN、OUTの人数をカウントしグラフ化する ユースケース :POSデータからの来店数ではなく、実際の入店数(日別や時間帯 別)から、人員配置の適正化をする ③立ち入りカウント 概要 :設定したエリアに対して、入った人数をカウントしグラフ化する 滞留時間での絞り込みが可能 ユースケース :特定の棚や商品前の立ち止まり人数で比較検証を行う ※画面は開発中のものです。仕様は予告なく変更される場合があります。 「AI-App」の今後 「Store People Detection Pack」では小売り・飲食のお客様から多く声をいただいた課題を解決できる機能を盛り込んでいますが、例えば、単に小売りと言っても業態はさまざまです。スーパーマーケット、百貨店、コンビニエンスストア、家電量販店、ドラックストア、ホームセンター、アパレル店など。抱えている課題も1つではありません。 今後、「AI-App」では、お客様の課題に応じたアプリケーションを準備していくことで、賢くなるカメラを目指しています。 さいごに 読んでいただきありがとうございました! 今回はPdM視点でAIアプリケーションに関してご紹介させていただきました。店舗の〇〇な課題を解決する為に作られたんだと伝わっていたら嬉しいです。 ご興味のある方やもっと技術的な内容が知りたいという方は、是非、お気軽にご連絡下さい。AI-Appは、引き続き、店舗の課題を解決できるアプリケーションを続々と!?作っていきますので、またこちらのブログにてお会いできる日を楽しみにしています。
こんにちは。セーフィー株式会社 エンジニア 谷口、江守です。 今回、セーフィーで初めての 社内ハッカソン を開催しました! 所属部門内に閉じた形ではありますが、事業成長とともに組織が変わっていく中で、組織活性化の手段として、また単純にハッカソンをやりたい!という個人的な思いを掛け合わせて実現させました。 その過程と実際に開催した内容をご紹介したいと思います。 ハッカソンをやりたいと思った理由 実施の承認を得る どのような形で開催するか 社内ハッカソン実施要項 目的 期間 参加者、チーム分け、作るもの 進め方 成果発表 その他 チーム分けと企画内容 途中経過 発表会 最後に ハッカソンをやりたいと思った理由 最近の組織変更で、所属部門に営業-企画-エンジニアといった複数の職能が集まる部門となり、同じ目標を共有するメンバーとして 一体感を醸成したい 思いがありました。 また、弊社は技術領域が広く、様々な職種のエンジニアがいます。 (詳細はこちら→ セーフィーにはどんな種類のエンジニアがいるの?職種別にエンジニアを紹介! - Safie Engineers' Blog! ) 私自身はフロントエンドですが、組織変更で組み込みやAIなどのエンジニアとも同じチームになったことで、それらについても知りたいと思うようになりました。 ただ、全く知識がない中でいきなり業務となるとハードルが高いので、まずは軽く触ってみる程度で知ることができる手段を考えたときに、ハッカソンを思いつきました。 実施の承認を得る これらの思いを上長との1 on 1で会話する中で快く賛同して頂き、社内ハッカソン開催に向けて準備することになりました。 どのような形で開催するか 私自身の経験としては、外部のハッカソンイベントに2回参加したことがあります。 しかし、いずれもエンジニアのみの参加で数日間で企画〜デモまで行うもので、大体の流れは把握していましたが、社内ハッカソンは初めてでした。 そこで社内ハッカソンを行った他社のブログをいくつか参考にさせて頂きつつ、実施要項を決めました。 決めるにあたって意識したことは以下です。 スモールスタートでやってみようということで、 所属部門内での開催 とすること。 営業や企画も参加しやすいように、普段の業務でこんなのできないかな?といった アイデア出しだけでもOK とすること。 デモをゴールとせず、競争要素も排除し、 コミュニケーション活性化 を目的とすること。 エンジニアは、一人で進めてしまうといったことがないように(目的であるコミュニケーション活性化につながらないため)、 担当技術領域以外にチャレンジ すること。 初めての開催でいきなり数日間業務を止めるのは難しそうなので、 薄く長く開催する こと。 忙しくて時間がとれなかった...がなるべく発生しないように、業務時間内に、 業務の一環として行う こと。 業務として行うので目標/評価に連動できるような開催期間とし、 目標に入れる こと。 モチベーションの維持のため挙手制とし、 モチベーションの高いメンバーのみで行う こと。 活動費用は会社負担 とすること。 社内ハッカソン実施要項 営業、企画、エンジニアでやりたい人が集まってアイデア出して何か作ってみよう アイデア出しだけでも参加OK、もちろん経験がないけど作ってみたいもOK 目的 営業含めたプチ案件や便利ツールを開発することによるコミュニケーション活性化 自分の保有していない技術領域に関して知見を得る場 期間 3ヶ月 参加者、チーム分け、作るもの 挙手制、参加者でやりたいことを持ち寄りチーム分け 進め方 例えば、チームごとに隔週2時間、スケジュールを先に抑えてその時間内で行う、など、業務時間内に、かつ忙しくて時間がとれなかった...がなるべく発生しないような仕組みにする 成果発表 所属部門内で発表会(デモ)を行う 順位付けなど競う要素はなし その他 必要な機材費等の費用は会社負担で購入 エンジニアは担当技術領域以外の開発にチャレンジすること チーム分けと企画内容 募集をかけ、参加者が確定したところで、まずはテーマ等を設定せず各人がやりたいことを持ち寄ってもらいました。 いくつか同じような内容があったのでマージしつつ、どのテーマに取り組みたいか記名してもらい、営業-企画-エンジニアのバランスをとりつつ、以下4チームになりました。 ラズパイとセンサーを組み合わせて、イベント検知とセーフィー映像の連携 Hey Siri, Safie Pocket2 でスナップショット撮って 宇宙 x Safie GO - 衛星通信対応SIMでの、どこでも繋がるGO センサー等連携ハブとしてのカメラ 営業、企画が参加してくれたことにより、顧客ニーズから自社サービスとしてこんなことできたらいいよね、といった 具体的でかつ色々な技術領域にチャンレジ できるとてもよい企画内容が出来上がりました。 途中経過 ハッカソン実施要項の「エンジニアは担当技術領域以外の開発にチャレンジすること」が意外によく効いていて、例えばフロントエンドエンジニアがラズパイとセンサーの組み合わせに取り組んだとき、そもそも、ラズパイとセンサーってどうやって繋げるの?ブレッドボードってなに?A/Dコンバーター??抵抗って...大きさは適当でOK??など、デバイス部分が全く分からず、ソフトウェアだけの、なんて狭い世界で生きてきたんだ...と打ちのめされていました。 ラズパイとセンサーの配線 接続した感圧センサー、センサー小さすぎ!こんな接続でよいのか謎 配線を終えようやくソフトウェアまで辿り着き、Pythonでロジック調整中 発表会 広めの会議室をとり、ハッカソン参加者と一部の出社していたメンバーは会議室で、他はオンラインで、といった形で発表会を実施しました。 発表にあたって決めたことは、1チームあたりの発表時間と発表順だけで、どのように見せるかや発表用の資料を作成するか、などは各チームに任せました。 デバイスをどう接続したのかなど、オンライン参加のメンバーにも伝わるように、事前に同じ会議室でリハーサルをしたり、意図が伝わるようにスライドを作成したりなど、自チームにとって今までの活動と成果が一番伝わる形を考え準備してくれました。 ハッカソンあるあるかもしれないですが、発表本番のデモで動かないといったことがままある中で、無事デモも見せることができ、大成功だったと思います。 発表内容を一部ご紹介します。 ラズパイとセンサーを組み合わせて、イベント検知とセーフィー映像の連携 荷受け場に、感圧センサー+ラズパイとSafieカメラを設置 荷物の重量変化を感圧センサー+ラズパイで検知する 「荷物が置かれた」「持って行った」をラズパイ上のPythonで判定し、Safie Viewerにイベントフラグを立て、Slack通知する Hey Siri, Safie Pocket2でスナップショット撮って 最後に ハッカソンが初めてのメンバーもいて、エンジニア以外の職種でも参加しやすい形や、参加は挙手制、デモすることを目的にしない、など、 とにかくゆるく、ただ何かしら発表はできるように 、を意識して運営しました。 一部のチームはデモまで辿り着けなかったのですが、今回の目的はそこではなくコミュニケーション活性化なので、一定程度達成できたのかなと思います。 やりたいことを快く賛同して後押ししてくれた上長、挙手制でしたが盛り上げるために目的を理解し参加してくれたメンバー、発表会に来てくれた事業部のみんな、何かの取り組みを皆で応援できることは素晴らしいことだと思います。 社内ハッカソンや何か社内での取り組みを考えられている方の参考になれば幸いです。 ありがとうございました!
こんにちは。セーフィー株式会社 バックエンドエンジニアの河津です。 セーフィーにはクラウドカメラやユーザーアカウントを一括管理できる統合環境である「 Safie Manager 」というサービスがあり、主にエンタープライズのお客様にご活用いただいています。 safie.link 7/7(木)には SSO(シングルサインオン)の機能をリリース しました! 今回はそのリリースされたばかりの新機能「シングルサインオン(以下SSO)」と、それを実現させる仕組み「SAML認証」について解説させていただきます。 SSOについて 1. 利便性が上がる 2. セキュリティリスクが下がる 3. IT部門での管理が容易になる SAML認証に関わる用語解説 SAML認証について 1: ユーザーがアプリケーションにアクセス 2: SAML認証要求を生成 3,4: IdPへのリダイレクト 5: SAML認証要求を受け取り、認証を試みる 6,7,8: ユーザー認証 9: SAML認証応答を作成 10: SPへの302 HTTP POST Binding 11,12,13: SAML認証応答を検証し、ユーザーログインを許可 14: ログイン成功 Safie ManagerとSSO まとめ SSOについて SSOとは、1度システム利用開始のユーザー認証 (ログイン) を行うと、複数のシステムを利用開始する際に、都度認証を行う必要がない仕組みのことです。 基本的に一つのWebサービスで使われるID・パスワードなどの認証情報はそれぞれ独立しており、Aのサービスを使用するにはAの認証情報、Bのサービスを使用するにはBの認証情報が必要です。 SSOを使用すると、この各サービスで分かれてしまう認証情報を統一して使用することができるようになります。 例えばAzure Active Directoryのような認証基盤を利用している場合、その認証基盤とWebサービスを連携させることで、認証基盤の方にログインするだけで様々なWebサービスを使うことができるようになります。 SSOのメリットは大きく3つあるかと思っています。 1. 利便性が上がる 認証基盤にログインさえしていれば、各WebサービスでIDやパスワードなどの情報を入力する必要がなくなるため、Webサービスの利便性が上がります。 2. セキュリティリスクが下がる 本当はあるべきではないですが、各WebサービスでIDやパスワードを使い回してしまうユーザーは一定数いるのではないかと思います。ただ、同じID・パスワードを各Webサービスで使い回すと、その分だけ流出する可能性を増やすことになります。 認証基盤を経由するSSOであれば、流出する可能性のあるサービスは認証基盤のみに絞られることになります。 この場合、認証基盤のID/Passwordが漏れた場合は全てのサービスにアクセス可能なリスクが残るものの、認証基盤には2要素認証機能やクライアント証明書の検証機能が含まれていることが多いため、それらの機能を併用する前提であればSSOを使用する方がセキュリティリスクが下がるのではないかと思います。 3. IT部門での管理が容易になる 各Webサービスの認証情報が認証基盤に集約されると、アカウントの停止やパスワードの変更などを行う際は認証基盤を操作するのみでよくなるため、とても楽になります。 SAML認証に関わる用語解説 SSOを実現するための認証手法はいくつかありますが、セーフィーから提供しているSafie ManagerではSAML認証をサポートしております。 これからSAML認証の解説をさせていただきたいと思っていますが、その前に解説に必要となる用語の説明をさせていただきます。 IdP(Identity Provider) : 認証情報を提供する側のシステムです。上の説明で出てきた「認証基盤」がこちらになります。 SP(Service Provider) : 認証情報を利用する側のシステムです。 Safie ManagerではSSO機能をサポートしていますが、本記事が公開された段階では認証基盤についてAzure Active Directoryを推奨とさせていただいております。上の用語に当てはめると、Safie ManagerはAzure Active Directoryを認証基盤として使用しSAML認証を行うことになるので、この場合はIdP=Azure Active Directory、SP=Safie Manager となります。 以降ではIdP・SPという用語を用いて解説をさせていただきます。 SAML認証について ここから本格的にSAML認証の話をしていきますが、SAML認証はそのフローの複雑さから初見で理解するのはかなり難しい処理だと(個人的に)思っています。 この記事を一度読むだけですと、もしかすると不明点だらけになってしまう恐れがあるため、2度・3度ほど読み返していただくことをおすすめします。 まずSAMLとは、Security Assertion Markup Languageの略称です。インターネットドメイン間でユーザー認証を行なうためのXML(マークアップ言語)をベースにした標準規格のことを指すのですが、「インターネットドメイン間でユーザー認証を行う」という点がまさしくSSOでやりたいことになります。SSOでは、IdPとSPという異なるドメイン同士で認証を確立させる必要があるためです。 SAML認証ではどのようなシーケンスで処理が行われるのでしょうか?シーケンス図を起こしてみました。 様々な処理が入り乱れていますね。 一つ一つ処理の内容を取り上げていきたいと思いますが、その前にSAML認証の事前準備の話をさせてください。 シーケンスを見ていただければ分かるとおり、SPからIdPにリダイレクトしたり、IdPからSPに戻ってきたりしているようです。このリダイレクト先は、事前にわかっていないとリダイレクトすることができません。SAML認証の事前準備として、SP・IdPそれぞれの認証エンドポイント情報を登録しあう必要があります。 また後に触れますが、IdPから送られてきた情報が正しいものであるのか検証するフローがあり、IdPより発行した公開鍵をSPに登録することも必要となります。それらの事前準備を経ることで、SAML認証が可能となります。 それでは、割り振った番号それぞれで行われている処理について解説します。 1: ユーザーがアプリケーションにアクセス ここでは、SAML認証を行うためのログインボタン押下などのアクションをイメージしていただけたらと思います。 2: SAML認証要求を生成 ユーザーがアプリケーションにアクセスした際に最初に行われるのは、SP側で SAML認証要求 が生成される処理です。 SAML認証要求 とはSPからIdPに「今からこのユーザーでSAML認証したいので許可をください」とIdPに要求するためのデータです。 フォーマットとしてはbase64エンコードされたXML形式のデータとなります。 < md : EntityDescriptor xmlns : md = "urn:oasis:names:tc:SAML:2.0:metadata" validUntil = "2022-02-10T08:51:19Z" cacheDuration = "PT604800S" entityID = "{SPのEntityID}" > < md : SPSSODescriptor AuthnRequestsSigned = "false" WantAssertionsSigned = "false" protocolSupportEnumeration = "urn:oasis:names:tc:SAML:2.0:protocol" > < md : SingleLogoutService Binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location = "{IdPの認証エンドポイント}" /> < md : NameIDFormat> urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified </ md : NameIDFormat> < md : AssertionConsumerService Binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location = "{SPの認証エンドポイント}" index = "1" /> </ md : SPSSODescriptor> </ md : EntityDescriptor> 上記の中には、SSOを行いたいSPに対する固有のIDや、IdP側の情報などが含まれており、この情報をIdPに渡します。IdPではこれらの情報が想定する情報かどうかを検証することになります。 SAML認証要求をIdPに渡すやり方は単純で、下記のようにIdPの認証エンドポイントに対して「 SAMLRequest 」というキー名のクエリパラメータをつけてリダイレクトすればOKです。 https://{idp_host}/{path}?SAMLRequest=xxxxxxxxxxxxx 3,4: IdPへのリダイレクト 上記にて発行されたURLにリダイレクトします。リダイレクトすると、次はIdP側での処理が始まります。 5: SAML認証要求を受け取り、認証を試みる IdP側では最初にSAML認証要求を受け取り、想定しているSPからのリクエストかどうかを検証します。 検証といっても、ここではXML内のEntityIDなどを突合するくらいの内容になります。 その後もしIdPにログインしていなければログイン画面を表示し、ユーザーにIdPへのログインを促します。 6,7,8: ユーザー認証 もしIdPにログインしていなければ、このタイミングでログインを行います。 ID・パスワードを入力しつつ、IdPによっては2要素認証が導入されていたり、クライアント証明書の有無によるIdPへのアクセス制御などの機能もあるかと思います。 9: SAML認証応答を作成 IdPにて認証が済んでいることが確認できると、IdPでは SAML認証応答 を生成します。 SAML認証応答 とは、IdPからSPに「IdP側の認証はOKなので、その証明を送るよ」といった形で、SP側で認証情報として取り扱える情報です。 こちらもSAML認証要求と同様、base64エンコードされたXML形式のデータです。 < samlp : Response ID = "{SessionIndex}" Version = "2.0" IssueInstant = "2022-07-14T08:50:33Z" Destination = "{SPの認証エンドポイント}" Consent = "urn:oasis:names:tc:SAML:2.0:consent:unspecified" InResponseTo = "xxx" xmlns : samlp = "urn:oasis:names:tc:SAML:2.0:protocol" > <Issuer xmlns = "urn:oasis:names:tc:SAML:2.0:assertion" > {Issuer} </Issuer> < samlp : Status> < samlp : StatusCode Value = "urn:oasis:names:tc:SAML:2.0:status:Success" /> </ samlp : Status> <Assertion xmlns = "urn:oasis:names:tc:SAML:2.0:assertion" ID = "{SessionIndex}" IssueInstant = "2022-07-14T08:50:33Z" Version = "2.0" > <Issuer> {Issuer} </Issuer> < ds : Signature xmlns : ds = "http://www.w3.org/2000/09/xmldsig#" > {署名の内容} </ ds : Signature> <Subject> <NameID Format = "urn:oasis:names:tc:SAML:1.1:nameid-format:xxx" > {NameID} </NameID> <SubjectConfirmation Method = "urn:oasis:names:tc:SAML:2.0:cm:bearer" > <SubjectConfirmationData InResponseTo = "xxx" NotOnOrAfter = "2022-07-14T08:53:33Z" Recipient = "{SPの認証エンドポイント}" ></SubjectConfirmationData> </SubjectConfirmation> </Subject> <Conditions NotBefore = "2022-07-14T08:50:28Z" NotOnOrAfter = "2022-07-14T09:50:33Z" > <AudienceRestriction> <Audience> {SPのEntityID} </Audience> </AudienceRestriction> </Conditions> <AttributeStatement> {IdPから取得できる属性情報} </AttributeStatement> <AuthnStatement AuthnInstant = "2022-07-14T08:50:33Z" SessionIndex = "{SessionIndex}" > <AuthnContext> <AuthnContextClassRef> urn:federation:authentication:windows </AuthnContextClassRef> </AuthnContext> </AuthnStatement> </Assertion> </ samlp : Response> 10: SPへの302 HTTP POST Binding IdPからSPにSAML応答の情報を渡すには、SP側で用意している認証エンドポイントに対しHTTP POST Bindingし、そのリクエストボディに SAMLResponse というキー名で指定し送信します。 ちなみにこの時HTTP POST BindingとなるかはSPから送るSAML認証要求の内容によって決定されます。 # この辺り <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location= Safie Managerは執筆時点ではHTTP POST Bindingのみ対応しています。 11,12,13: SAML認証応答を検証し、ユーザーログインを許可 SPには上記フォーマットのSAML認証応答が送られ、メールアドレスやユーザー名などの属性情報も含まれていますが、これらの情報をそのまま使用するわけにはいきません。 不正に変更されたSAML認証応答が送られてくる場合も考えられるためです。 SAML認証応答の中には署名の情報があるのですが、この署名情報を検証することで意図したIdPからの認証応答かどうかを確かめます。 検証するには事前にIdPよりダウンロードできる公開鍵が必要になりますので、この公開鍵をSPにあらかじめ登録しておくことが必要です。 14: ログイン成功 検証が成功すると晴れてSAML認証成功となります! この後は、SAML認証応答から取得できる情報を元に、SPにログインするための処理へと続いていくこととなります。 元々あるSPの認証基盤に合わせてSAML認証を組み込んでいくことになり、各SPによってIdPから取得しなければいけない属性情報に違いが出てくるため、SPごとに実装内容は分かれてくるところになるかと思います。 Safie ManagerとSSO SAML認証を行うには事前にSP・IdPそれぞれに認証エンドポイントや公開鍵などを登録し合うことが必要と書きましたが、私たちが提供しているサービス「Safie Manager」ではどのような画面になっているのでしょうか。 見てみたいと思います。 ほとんど黒で塗りつぶしてしまっていてすみません。 「IdPへの登録情報」という欄に書かれている情報を、IdPに登録するための情報として表示してあります。 逆に、IdP側の情報をSafieManagerに登録する欄として「IdP情報」という項目を設けてありますので、「ログインページのURL」「識別子のURL」「証明書」を登録することで、SafieManager(SP)側の準備は完了です。 今度はIdP側の情報を登録する箇所を見てみましょう。 ここでは例としてAzure Active Directoryを取り扱います。 基本的なSAML構成という箇所にSPの情報を入力し、 {アプリ名}のセットアップ(ここではsafie-manager-sso-testという名前)にSP側に登録する情報が乗っており、証明書もダウンロードできます。 まとめ 今回はSAML認証についての解説をさせていただきました。 SAML認証はかなり複雑な内容で、実装する際にはまず概念の理解に時間がかかってしまうため、この記事が理解の助けになれば幸いです。 サービスにSSO機能を組み込む際は、SAML認証を経た後、SP側のユーザーデータに対して新規登録や認証を行う処理につながってきます。その辺りはSPの既存の認証基盤の仕様によって実装の勘所が分かれる箇所だと思っています。その辺りにも試行錯誤ポイントがあるため、SSO機能の実装を予定されている方は、基本設計・詳細設計の時間を長めに取られることをおすすめします。 ここまで読んでいただきありがとうございました!
プロダクト基盤開発グループデバイスコアチーム、 組み込みエンジニア の楊(よう)です。 セーフィーのプロダクトというと、「 カメラ 」というイメージを持つ方も多いかもしれません。 そんなカメラを始めとしたデバイスの開発は、組み込みエンジニアが担当しています。 今回は 組み込みエンジニアの業務内容やカメラ開発の中身 をご紹介したいと思います。 セーフィー組み込みエンジニアの業務 Safieカメラ・デバイスの構成 Safie Client SDKの開発 カメラ・デバイスの開発 自社カメラの開発 他社市販カメラのSafie化開発 Safie Client SDKを外部へ提供 Safieエッジアプリやそのプラットフォームの開発 最後に セーフィー組み込みエンジニアの業務 以前、「 商品開発の歴史 」の記事でもご紹介したように、セーフィーでは創業以来さまざまなカメラとデバイスを開発してきました。 デバイス開発をメインで担当する組み込みエンジニアの業務・開発内容は、採用サイトにも記載があるように、主にこちらの6つになります。 カメラ・デバイス開発 Safie Client SDKの開発 エッジアプリプラットフォームの開発 CI/CD環境や開発環境の整備と改善 カメラ設定用各種ツール開発 カメラユーザーの問い合わせ・障害対応 今回は、上記のうち「 カメラ・デバイス開発 」、「 Safie Client SDKの開発 」、「 エッジアプリプラットフォームの開発 」にフォーカスし、Safieカメラの構成と併せて説明します。 Safieカメラ・デバイスの構成 セーフィーでは SafieClient という実行ファイルを各カメラ/デバイス向けにビルドして搭載しています。 当初、SafieClientはカメラの制御/映像の送信を担うだけでしたが、現在ではSafieエッジアプリを管理する機能も実装され、Safieプラットフォームの一部としての機能を日々進化させています。 SafieClientは大まかに下記三つのモジュールによって構成されています。 Safie Client SDK :サーバへの映像/音声の送信、サーバからの命令処理などSafieClientのコア機能がここに集約されています。 Camera I/F :各カメラ/デバイスの固有実装への対応を担います。映像/音声データを取得してSafie Client SDKに渡したり、Safie Client SDKからの命令に応じてカメラ/デバイスの制御を行ったりします。 SafieエッジアプリやEdgeAppFramework :Safieエッジアプリがセーフィー対応のカメラ/デバイスに配布可能なエッジアプリになります。EdgeAppFrameworkがSafieエッジアプリの動作管理を担っており、必要な一連の開発環境も含まれています。現在開発中のAIカメラ用のエッジアプリもこちらの仕組みを利用して開発しています。(厳密にはSafieClientとは別のプログラムですが、SafieClientによって制御される付随したモジュールになります。) Safie Client SDKの開発 Safie Client SDK の基本的な役割は、Safieクラウドとの接続管理と各カメラ/デバイス全体の管理です。そして、通信状態が悪くても映像を視聴できるように、また通信状態が復帰した時に映像をリカバーできるように色々工夫しています。また、Safie Client SDKはSafieが対応する全てのカメラに共通で使われているので、どのカメラでも動くよう汎用性のある設計・実装にする必要があります。 Safie Client SDKの機能を項目としてまとめると以下の通りです。 詳細の説明は割愛しますが、イメージをつかんでいただければ幸いです。 ・デバイスのクラウド接続時の自動認証 ・Safieクラウドとの安全・安定な接続・再接続 ・カメラの制御、カメラの状態管理 ・カメラの動画ストリームやイベント、通知のアップロード ・通信状態が悪い時のビットレート調整 ・通信切断状態の映像のバックアップと後のリカバリ ・LogやDebug情報のアップロード ・SafieClientまたは各カメラ/デバイスのシステムFW更新 ・WebRTCのシグナリング ・Safieエッジアプリの管理 また、カメラの数やユースケースの増加と共に、以下のような機能追加・改善を検討しています。 ・よりスマートなビットレート調整 ・通信状態によらず録画欠損の無いバックアップと後のリカバリ ・設置環境やニーズに合わせたハイブリッド映像配信(デバイス配信/サーバー配信) ・プラットフォーム化に伴うセキュリティ対策 ・Androidなど汎用プラットフォームへの対応 そして、今まではプロダクトを市場に出すことを優先してきたため、技術負債が溜まっています。 今後の市場拡大を考慮すると、より品質を担保するためにも負債を解消しなければなりません。 現在は、CI/CD環境の整備やエミュレーション環境の構築などを通して、負債の解消を目指しています。 カメラ・デバイスの開発 Safie Client SDKがSafieの共通機能をまとめて対応しているので、新規カメラ・デバイスの開発・対応が基本 Camera I/F でカメラ固有機能の開発になります。基本的に以下3つのパターンに分類されます。 自社製カメラの開発 他社市販カメラのSafie化開発 Safie Client SDKを外部へ提供 自社カメラの開発 自社製の代表的なカメラと言えば、 CC-2シリーズ 、 Safie Pocket2 、現在開発中のエッジAIカメラになります。 自社製と言ってもセーフィーでは、ハードウェアも含めて完全に社内で開発する訳ではなく、カメラ製品開発能力があるハードウェアベンダーとの協力開発になります。ハードウェアおよびOSなどのシステム周りの開発と製造を先方にしてもらって、セーフィーがその上位にあたるカメラ全体の制御や通信部分の開発を行うのが一般的です。 ただ、製品の開発元として全体を見通した工程管理を行う必要があるので、場合によってドライバレベルのデバッグや試作もハードウェアベンダーと一緒にやる必要があります。また、新しいハードウェアベンダーにもセーフィーにもノウハウがない技術の開発をする際は、我々組み込みエンジニアが先陣を切って勉強するところから始めなければなりません。これからは新しいカメラを開発する機会も増えてくるので、5G、手ぶれ補正、位置推測など技術的な挑戦をする機会がたくさんあります。 また、これからは事業の拡大とともに、理想的な製品や機能の開発、より安くて高い品質を保つためにも、当社の組み込みエンジニアがソフトウェア開発だけではなく、ハードウェアを設計する技術や生産管理のノウハウも積極的に貯めて守備範囲を拡げていく必要があります。 他社市販カメラのSafie化開発 「 商品開発の歴史 」の記事でもご紹介したように、セーフィーではユーザーぞれぞれの利用用途、設置環境のご要望に応えるため、またより多くの販路やパートナーを巻き込むため、自社製のカメラだけではなくトップメーカーであるAxis Communications社やVivotek社を始めとした、他社製市販のセキュリティカメラのSafie対応を行っています。 他社市販カメラはRTSPやONVIFといった映像を取得したり制御したりするために規格化されたインターフェースを持っていることが多く、さらにAxis Communications社のACAPやVivotek社のVADPのようなアプリケーションプラットフォーム機能を持っているカメラもあります。他社市販カメラのSafie対応は基本はRTSP /ONVIFあるいはそのカメラ特有のアプリケーションプラットフォーム機能を使うCameraI/F開発になります。 そして、各種他社市販カメラは基本的にはLinuxベースのデバイスになりますが、ToolchainやSDKがそれぞれ異なっているので、ビルド環境の整備や再現が大変です。今はDockerでカメラToolchainを管理するなど色々工夫をしています。 Safie化している他社市販カメラは、AXIS社とVivotek社のカメラだけで200機種以上、機能や仕様も様々です。多くの機種に対応することによって、Safieがカバーできる利用用途や設置環境はかなり増えますが、その分サポート対応が煩雑になります。 Safie Client SDKを外部へ提供 Safie対応のカメラはすべて自社で開発したわけではありません。条件次第で、積極的に Safie Client SDK を開発パートナーへ提供して共同開発をしています。当然、技術的なサポートは組み込みエンジニアから行います。 Safie対応カメラを増やしていく為には、様々な開発パートナーにより広くカメラ開発を行って頂くのが理想的ですが、今はまだSafie Client SDKが使いにくいなどの課題があるので、偶に密なコミュニケションしないと開発が進まないケースや自社で開発した方が早いケースがあります。なので、これからはSafie Client SDKをより使いやすくし、今後いずれオープンソース化などしてより誰でも使えるようにしていきたいと思います。 Safieエッジアプリやそのプラットフォームの開発 昨今ではカメラ(エッジ側)で処理できることが増えています。そのため多くのカメラをSafie化したとしても、機能追加できるのが自社のエンジニアだけになってしまうのはとてももったいないと考えています。 そのため、セーフィーではテックパートナーと協創できるプラットフォームの実現を目指しており、その一環として SafieEdgeAppFramework を開発。現在はエッジAIカメラ用のAIエッジアプリやWebRTC音声通話機能の開発環境として使っています。 SafieEdgeAppFrameworkは、SafieデバイスにデプロイできるSafieエッジアプリを動かす・開発するためのフレームワークになります。Safieエッジアプリを開発するためのツールとしては、以下の一連機能を提供しています。 ・アプリの自動生成 ・アプリのビルド・構築 ・単体テスト環境 ・実機デバッグ環境 ・アプリの登録・デプロイ そして、Safieエッジアプリの実装に関しては、以下の機能・ライブラリーを用意。カメラから映像などの情報を取得して解析をしたり SafieクラウドとRPC通信で連携するエッジアプリを作ることができます (現状Safieエッジアプリの実装は C++ だけサポートしています)。 ・アプリのリモート更新 ・アプリのリソース(推論モデルなど)のリモート更新 ・Safieクラウドからのアプリ設定 ・RPC通信(Safieクラウドから、他のSafieエッジアプリから、WebRTCなどのP2P通信から) ・イベントをSafieクラウドに送信・記録 ・カメラの映像・イベントを購読 ・カメラ制御・Overlay設定など ・3rd Party Libs(TensorflowLite、OpenCV、Dlibなど)、デバイス固有のSDK(SNPEなど) Safieエッジアプリの構成概要とSafieクラウド/カメラとの動作概要の全体像については、下図になります。 基本アプリのライフサイクルコールバックI/Fを実装し、上記機能・ライブラリーを使ってアプリの機能を実装すればアプリが出来上がるイメージです。 現状SafieEdgeAppFrameworkは社内のみの利用で、まだまだブラッシュアップ中です。完成度が上がり対応するカメラなどの条件が揃い次第、テックパートナーに公開していきたいと考えています。 ちなみに、SafieエッジアプリはWebRTC経由や Safie API 経由でも通信できる構想(妄想?)があります。例えば、顔検出のSafieエッジアプリを作って、Web側で下記のようなjavascriptコードで顔の検出通知をsubscribeしたり、検出したい顔の特徴をSafieエッジアプリに設定したりすることもできるかもしれません。 そうなると、Safie開発アカウントを持っていれば、Safieカメラと連携するフルスタック開発ができるので、面白いかもしれません。 // この顔見つけたら教えてね camera. edgeapp ( "FaceDetector" ) . subscribe (“FaceDetectedEvent”, (event) => { console. log ( "people in:" , event.face_name) }) camera. edgeapp ( "FaceDetector" ) . request (“StartFaceDetected”, face_data) 最後に ここまでで、多少理想語りも含めたセーフィーの組み込みエンジニアの業務・開発内容を紹介をしてみましたが、イメージは少し湧きましたでしょうか。 組み込みエンジニアの全ての努力は、Safieのカメラ・デバイスや開発環境を、より安全・安定でより手軽にインフラのように、顧客や共に開発するパートナーの身近に届けるためです。 そして、理想を語りながら、顧客ニーズや現実を見て調整し、確実に泥臭い現実課題を解決していくのがセーフィーの組み込みエンジニアの姿になると思います。 現在、一緒に働く組み込みエンジニアを募集しています。セーフィーのビジョンや組み込み、エンジニアの開発内容に共感・興味を持って頂けるようであれば、是非ともご連絡ください! 募集職種一覧/セーフィー株式会社
初めまして。セーフィーの伊原と申します。 今年で社会人3年目で、セーフィーには2021年11月に入社いたしました。 現在はビジネスユニット1にてフロントエンド開発を主に担当しています。 ビジネスユニット1は主に飲食・小売業のDX実現を目的とした部署で、多店舗経営者向けのクラウドカメラ管理アプリケーションや、店舗内の人を検知するAIを搭載したクラウドカメラの開発を行っています。 今回は私が所属しているフロントエンドチームにて実施しているスクラム開発についてご紹介いたします。 私にとってスクラム開発はセーフィーが初めての経験で、当初は慣れない事も多かったですがとても良い取り組みだと感じています。 本記事では初めにスクラムの簡単な説明をした後、開発現場で実践している開発フローについてご紹介いたします。その後、私が考えるスクラムの良さについて所感を述べます。 スクラム開発の概要 Safieのフロントエンドの開発フロー スクラム開発のメリット 最後に スクラム開発の概要 まず初めに、スクラム開発を知らない方に向けて簡単にスクラム開発の説明をいたします。 スクラム開発とは、スクラムと呼ばれるフレームワークを活用したソフトウェア開発のことです。チーム毎にスプリントと呼ばれる一定の期間を指定し、次の図の流れを繰り返すことでプロダクトのゴールを目指していきます。 ①バックログリファインメント プロダクトに必要なものを洗い出し、プロダクトバックログと呼ぶ一覧にします。新規機能の追加、機能改修など様々なものをまとめるため、抽象的な内容も含みます。 これはスプリント初めに行うのみでなく、適宜開催することもあります。 ②スプリントプランニング プロダクトバックログの内容をタスクレベルまで落とし込み、1スプリントの間に実施するタスク一覧に抽出します。ここで抽出されたものをスプリントバックログと呼びます。 選定の際には、チーム全員でタスクの作業量を見積もり、スプリント内で終わる現実的な量を抽出します。 ③スプリント期間 各メンバーにタスクを割り振り、開発を進めます。 タスクは最初に全て割り振ってしまうのではなく、メンバーが自主的にスプリントバックログから取得します。タスクが完了次第、新しいタスクを取っていく形です。 期間内はタスクの遂行を円滑にするためにデイリースクラムと呼ばれる集まりを毎日実施します。 スプリントの終了まで③を繰り返します。 ④スプリントレビュー 開発期間の終了時に、以下の2点を評価します。 期間内で完了したタスク量の算出:チームの生産性の計算 良かった点・改善点の洗い出し 評価の内容を踏まえ、再び②に戻ってサイクルを回します。 一連のスプリントを繰り返すことで徐々にプロダクトと開発フローを発展・洗練させていくのがスクラム開発です。 Safieのフロントエンドの開発フロー 私のチームにて実際に取り組んでいる開発フローを前述した図の①〜④に当てはめてご紹介します。 チームでは1スプリントを2週間として設定しています。 ①バックログリファインメント スプリントの初めに1度実施しており、本イベント後の同日に②のスプリントプランニングも実施しています。 ここでは開発チームメンバーで集まり、プロダクトに必要な機能を一覧化します。 タスクの進捗管理にはWrikeというツールを使っており、タスクを次の段階に分け、ボードで管理しています。 Backlog: プロダクトバックログ ToDo: スプリントバックログ Doing: 遂行中 Dev Review: レビュー中 QA Review: QAチーム確認中 Done: 完了したタスク Closed: スプリント中に完了したタスクの一覧 それぞれのリストにあるタスクは移動させられるようになっており、各自が自分の持っているタスクを段階に応じて移動させます。Doneまで移動させたらタスクは完了となります。 DoneからClosedへの移動は後述するデイリースクラムにて実施します。 ②スプリントプランニング 前回のスプリントにて完了したタスク量を目安に、スプリントバックログを作成します。 必要があれば、機能をタスクの粒度まで落とし込みます。例えばユーザ登録機能が必要な場合、「ユーザ登録」という機能単位ではなく、「画面開発」・「API連携」という単位に分割するような形です。 ここでは機能の優先度のみでなく、企画やサーバサイドの進捗状況に合わせて柔軟にタスクを選定するようにしています。 スプリントバックログの作成後、積んだタスクの見積もりをチーム全員で行います。見積もりはストーリーポイントで数値付けをしています。 ストーリーポイントとは相対見積の指標で、「このタスクだったらどれぐらいかかりそうか」の規模感をこれまでのタスクから考慮して設定します。ここで重要なのは、何人日・人月といった絶対値で見積もりをしないことです。 ストーリーポイントの決定にはプランニングポーカーという方法を採用しており、これは各メンバーの見積もった数値を一斉に開示するやり方です。 見積もりの数値はフィボナッチ数列から選択します。開示した際にメンバー間で見積もりが一致しなかった際には、互いに想定した理由を伝え合って議論します。ここで重要なのは、見積もり内容にメンバー全員が納得する事です。 見積もった結果として想定のタスク量との差が大きかった場合には、プロダクトバックログを再度見直してタスク量を調整します。 ③スプリント期間 スプリント期間内は毎朝15分程度のデイリースクラムを実施し、以下の3点をチームで共有しています。 前日にやったこと 本日やること 困っていること 報告の際にはWrikeのボードを画面共有し、各自が持っているタスクの総量を全員が把握できるように進めます。「本日やること」の報告の際に新しいタスクをスプリントバックログから取っていくのですが、この際にもタスク内容を宣言しておく事で、今後どういったタスクに取り組む予定かをチーム全員が知っているようにします。 また、WrikeにてDoneとなっているタスクを確認し、本当に完了で問題ないかをチームメンバー全員で確認するようにしています。これによって、本人が気付かないタスク漏れ等を防止しています。 ④スプリントレビュー スプリント中に完了したチケットを整理し、チームのベロシティを算出します。 また、以下4点に関してスプリント区間内の振り返りを行い、次のスプリントの改善を目指します。 Good: 良かった点 Problem: 課題点 Try: 改善策 Keep: 次回以降も続ける試み スクラム開発のメリット ここで、私がスクラム開発を実際に体験して良かったことを3つに分けて説明いたします。 1. 属人化の軽減 1つ目は、属人化(ノウハウが共有されない状態)を防ぐことができる点です。 スクラムではチームメンバー間でやっていることが共有されるため、各メンバーのタスクの全容が透明化されます。Aさんでないと/Bさんでないと分からない、というような事がなくなると共に、メンバー間での質問やアドバイス等が行いやすい環境が促進されます。 スクラム開発における最大のメリットはこの点であると私は考えています。 設計方針や実装方針の良し悪しを開発者間で積極的に話し合う事ができ、技術者として成長できる環境が整っていると感じました。 2. メンバーの負荷状況の可視化 「属人化の軽減」の項で透明化について述べましたが、透明化によってチーム内の負荷がかかっているポイントが明確になること、それが2つ目の良い点です。 デイリースクラムで困りごとを共有する機会を作ることで、課題に個人ではなくチームとして取り組む流れを自然に作り出す事ができます。また、手が空いている人が他の人のタスクを巻き取るなどの融通も効きやすいです。 3. 見積もり能力の向上 全てのタスクに見積もりが行われるため、実際に業務を遂行する中で予想より短い・多かったという事が必ず発生します。そこで「なぜ想定と異なったのか?」を考えて共有することで、チーム全体でタスクに対する見積もりの感覚が向上していきます。 ストーリーポイントを付ける際に他の方の意見を聞く機会も多く、見識が広まりやすいのも利点です。 また、チームがどの程度のタスク量をこなすことができるかも明確になるため、開発スケジュールに無理が無いかを早めに判断することができます。 最後に セーフィーでスクラム開発を経験してみて、開発を健全に進める上でチームに必要な要素を自然に促してくれるような、良い開発体制であると感じています。 各メンバーの自主性は求められますが、自主的に動く事の重要性はかなり大きいので、それも含めて成長する必要があると思っています。 セーフィーは厳格な上下関係が無い事もスクラム開発との相性がよく、開発として社内のコミュニケーションを取りやすく、開発していてとても楽しいです。 本記事で少しでもセーフィーの開発フローの良さがお伝えできていれば幸いです。 読んで頂きありがとうございました🙇‍♂️ 本記事の執筆に当たり、次のスクラムの解説記事を参考にさせていただきました。 詳細を理解する上で非常に勉強になる内容でした。 qiita.com
こんにちは! セーフィー株式会社 業務システム部でエンジニアをしている大林と申します。 業務システム部とは、その名の通り 業務系システムの開発・運用 を行なっている部署です。 以前の 職種別エンジニア紹介の記事 における「業務システムエンジニア」が所属しています。 ということで今回は、セーフィーのサービスそのものについてのお話ではなく、セーフィーのサービスを支える業務システムのお話です。 業務システムの全体像 業務フローに沿って紹介 1. 商談作成 2. 出荷 3. 売上作成 4. 請求書発行 DataSpider Cloud これから 業務システムの全体像 セーフィーはSaaSビジネスですが、 単純なサブスクリプション契約だけではなく、カメラや付属品などの「モノ」も取り扱う ことが業務システムにおける特徴です。 今回の記事では、セーフィーのカメラ・サービスをお客様に使っていただくまで・使っていただいている間、どのように業務システムが関わっているかの全体像についてご紹介します。 簡単にまとめた全体像が以下の図です。 セーフィーでは、2019年に、クラウド型のSFA(営業管理)・CRM(顧客管理)のプラットフォームであるSalesforceを導入して以降、現在は Salesforceを中心として各種システムと連携 しています。 数字は以下で説明する業務フローの流れと対応しています 業務フローに沿って紹介 ここからは実際にセーフィー社内のオペレーションがどのような流れで行われているかを、業務フローに沿ってご紹介します。 実際はマーケティング活動にもSalesforce等のシステムが使われているのですが、そちらはマーケティング部が主に管轄しているので今回の記事では割愛します。 以下が業務フローの大きな流れです。ここではカメラの販売商流の例でご紹介します。 Salesforceの商談を作成し注文情報を入力する 商談情報を元にカメラを出荷・キッティングする 出荷(もしくは工事)完了後に売上データを作成する 売上データを元に請求書を発行する 1つずつもう少し詳細に見ていきましょう。 1. 商談作成 お客様がセーフィーのカメラを購入するには、 ECサイト からの直接購入や、お問い合わせフォームからご連絡いただくなどしてセーフィーの営業担当者とやりとりの上でご購入いただくなど複数の経路がありますが、 注文情報はすべてSalesforceの商談で管理 されています。 ECサイトから購入する場合は、見積情報や受注情報がSalesforceの商談に自動連携されるようになっており、その連携部分はEAIツールであるDataSpider Cloud(詳しくは後述)を用いています。 営業担当者を通して購入する場合は、まず営業担当者がSalesforceで商談を作成します。そこから必要に応じて見積書を作成し、受注の運びとなった際には申込フォームを発行します。そしてお客様が申込フォームに入力し提出いただいた内容が、商談に自動で反映されるようになっています。 この段階で、 カメラの機種と録画プランの組み合わせや、カメラにひもづくオーナーアカウント、納品希望日・送付先などが管理 されます。 カメラとプランやオプションの組み合わせを登録する画面 2. 出荷 作成した商談情報を元に、出荷に必要な情報を作成します。 Salesforceのレポート機能を用いて、納品希望日やカメラの機種・台数・送付先などを倉庫での出荷担当者と連携しています。 出荷した後には、倉庫の出荷担当者が、出荷したカメラのシリアルナンバーをSalesforceに連携し、 どのカメラにどのプランやオプションが紐づいているか(キッティング情報)を管理 します。 カメラのキッティング情報の一例 この段階で、 Salesforceに格納されたキッティング情報をセーフィーのPlatformサーバーにもAPI連携 します。ここでいうPlatformサーバーとは、セーフィーのサービスやユーザー情報を管理しているサーバーです。 この連携を行うことで、お客様の元にカメラが届いた時点でスムーズに利用開始できるようにしています。 また、当日出荷した商談について、出荷のお知らせメールをお客様へ自動配信したりもしています。 Salesforce画面のボタンからキッティング情報を連携します (AgencyTool=Platformサーバーを利用した社内アプリケーションです) 3. 売上作成 出荷(工事を伴う商談の場合は工事)が完了すると、商談をクローズします。 この段階で、出荷や工事完了日に合わせた課金日が確定し、商談に設定された期間分の売上データが作成されます。 ここで作成された売上データを元に、経理などの経営管理部門が会社としての売上管理をしています。 ちなみに、現在ECサイトから購入した場合はクレジットカード決済が可能です。クレジットカードの決済情報は、月末時点の決済データを元にDataSpider Cloudを介してSalesforceに売上データを作成しています。 4. 請求書発行 毎月やお客様に合わせた請求書発行のタイミングで、売上データを元に請求データを作成します。 ここで作成された請求データを、セーフィーで利用している 請求管理ロボ というシステムに連携 し、請求書発行をします。 その後は請求管理ロボ上で入金消込をしたり、最終的に会計システムへ連携して会計処理をしたりします。 請求管理ロボ for Salesforceを利用しており、Salesforceで対象データを取得して連携します ここまでがカメラの販売商流のざっくりとした一連の流れの紹介でした。 今回紹介した内容以外にも、レンタル商流では、2020年に 従来のスプレッドシート管理からSalesforceでのシステム管理に移行 し、カメラの在庫管理なども行っています。 システム化以前は、いくつものファイルやシートに分かれ数式が絡み合っていたため、スプレッドシートがとてつもなく重くなっていたり、作業が属人化したりしていました。システム化によってオペレーションフローが整い、急速に成長するレンタル商流の管理にも対応できるようになりました。 DataSpider Cloud 大筋とは外れますが、せっかくの機会なので、1や3で出てきたDataSpider Cloudについて、もう少しだけご紹介します。 DataSpider Cloudは、種類の異なるシステムやアプリケーション間でデータのやり取りを行う際に、通常はプログラム開発、もしくは手作業でデータの移行や入力作業を行う処理を、GUIベースで作成することができるデータ連携サービスです。 (参考: ヘルプページ ) セーフィーでは、ECサイトからの連携以外にも複数箇所で利用しています。 例えば、 Webサイトのお問い合わせフォームからSalesforceへ連携しデータ作成 Excel形式の申込書を取り込んで商談を作成 AWSのS3に格納されているクレジットカード決済による入金データ(CSVファイル)を月次で取得して加工処理 などなどです。 GUIでの操作となるので、上記のような処理をノーコードで実現することができます。 このようなシステム連携を実現することによって、今までExcelファイルなどからシステムへ一つ一つ転記していた作業がなくなったり、Excel等での属人化した加工処理がなくなったりするなど、 オペレーションを効率化して手作業によるミスもなくす ことができるようになりました。 DataSpider 画面サンプル これから ここまででSalesforceを中心とした現在の業務フローをご紹介しましたが、現在の運用にも「不」があります。 キャンペーン施策などのたびにプログラム修正が必要となりSE対応 契約変更や契約更新が手作業 便宜上未来の売上データも作成しているため扱うデータが必要以上に多くなる などです。 今年は業務システム部総動員で、契約・請求管理システムの導入に取り組んでいます。 現在はSalesforceが中心となり業務システムの全体を担っていますが、今後はSalesforceはSFA(営業管理)の機能に寄った形にし、契約管理や売上・請求管理は新システムに移行したいと考えています。 柔軟なプライシング戦略や請求の自動化など、上記で挙げた不の解消に向けてプロジェクトが進行中です。 セーフィーのビジネスが拡大するにつれ、管理するデータ(顧客・カメラ・請求など)は膨大になっていきます。 社員が効率よくオペレーションができ、そしてお客様の満足度向上につながるように、 セーフィーの業務システムはこれからも進化していきます!
はじめに MDMとは 新3大 MDMを使ったiOSアプリの配布術 1. AppleID無しでアプリを配布できるMDM 【Safie事例】 2. 端末毎に異なる設定をしてアプリを配布できるMDM 【仮説】 3. iOSのバージョン更新を抑制できるMDM 【Safie事例】 最後に はじめに こんにちは。2021年5月に入社し、モバイルグループでiOSアプリ開発を担当している太田です。 好きなiOS SDKはExtensionsです👍 今回は、2021.9.17-19に開催されたiOSDCセッションの中から興味深かったテーマを当社サービスの事例を交えて簡単にご紹介します。 イベント開催から半年以上経ち今さらなによと思われた方もいると思います。 しかし、知っていましたか?iOSDCのセッション動画は1ヶ月経つと Youtubeに無料で公開 されるのです! イベントに参加した人もしていない人もこの機会にぜひぜひ本ブログと一緒に見て頂ければと思います。 ということで取り上げるテーマはこちらです!MDM! 参考にしたiOSDCのセッションは 「MDMを使って業務用アプリの初期設定を自動化する」 です。 取り上げた理由は、 以前の記事 「画像認識技術、サービスの自社利用」 で紹介した当社 SafieEntranceサービス を利用して頂いているお客様の環境でも導入していること 「MDM テックブログ」でググったところ、記事が少なかったこと なにより、開発者として SafieViewerアプリ や SafieEntranceアプリ をただ単に作るだけでなく 導入・運用するときの課題や苦労といった 現場の不 も認識しておきたかったこと です。 MDMとは ちなみに、MDMとは Mobile Device Management の略で、多数のモバイル端末を管理する仕組み、あるいはクラウドサービスのことを言います。iOSの場合はAppleが定めた MDM Protocol に従い、アプリの配布・端末OSの設定・遠隔操作などが実現できるものになっています。MDMが活躍する対象領域は図1のアプリを「導入する」「つかう」となっています。 図1. MDMの対象領域 余談ですが、MDMを使うにあたりAPNs(Apple Push Notification service)・ABM(Apple Business Manager)というサービスも重要になってきます。今回は、 現場の不 と それを解決できるMDM という内容をお伝えしたいと思うのでMDM-APNs-ABM連携の仕組みに関する説明は割愛致します。 それでは、SafieEntranceの事例も交えながらMDMで実現できる3つのことを紹介します! 新3大 MDMを使ったiOSアプリの配布術 1. AppleID無しでアプリを配布できるMDM 【Safie事例】 まず初めに開発者のみなさまにお伝えしたいことはAppleIDがないとiPad端末にアプリをインストールできないということ。 当たり前だよ!というツッコミ、ありがとうございます。 しかし待ってください!アプリをインストールするために、AppleIDを200台の端末に設定することを考えてみると、 AppleIDの登録作業が面倒 200台毎にAppleIDを作ると管理するのが面倒 AppleIDを使い回すにも端末上限は10台、しかもアカウントを共有するとある端末で出たアラート等が共有した他の端末でも表示されてしまうのが面倒 といった面倒に出くわすのであります。 そこで登場するのがMDM。 MDMを使えばAppleIDなしでも指定したiPadに一括でアプリを配布することができるのです。 正確にはAppleのVPP(Volume Purchase Program)とMDMの合わせ技。 VPP StoreからApp Storeに公開されているアプリを一括購入してMDMを使って配信するという流れになります。 2. 端末毎に異なる設定をしてアプリを配布できるMDM 【仮説】 続きまして、SafieEntranceの事例ではないのですが、iOSDCセッションを聞いて実現できそうだなと思った妄想事例を紹介したいと思います。 それはアプリの初回ログイン作業の手間を省くこと。 SafieEntranceアプリの場合、ログインした後は基本的にログアウトすることなくログイン後の顔認証画面を常時開いた状態にしてiPadを常設しておくという特徴があります。 つまり、基本的にログインする処理は導入時の1回のみ。 驚くことにiOSDCでは Managed App Configuration という機能を使いMDM上で { key : value } を設定するだけでその情報をアプリに設定した状態で端末毎にアプリを配布できるという事例が紹介されていました。 { key : value } の取得方法はiOS SDKの UserDefaults を使って取得できるとのこと。 もしかして、下記のように実装すればログイン作業も省けるのでは?と筆者は考えたのであります。 図2. Managed App Configurationを使った自動ログイン実装例 これにより、例えばiPadの設置工事の際にアプリを起動してもらえればログイン情報の入力が省けるという算段です。 3. iOSのバージョン更新を抑制できるMDM 【Safie事例】 無事に導入できたのも束の間、不穏な空気を感じている開発者もいると思います。 そう、iOSのバージョン更新であります。 iOS Developerであればこのバージョン更新に血と汗と涙を大量に流した方も多いことでしょう。 しかし、MDMはOSのバージョン更新をも抑制してアプリを配布することができる強者でもあったのです! iOSではアクセスポイントへのSSIDやパスワードなどの端末に必要な情報をXML形式で記述した 構成プロファイル というものを使って設定できるようになっています。 この構成プロファイルにOSのバージョンが自動で更新されないような記述をし、MDMからiPadに設定を流し込むということになります! 余談ですが、Siriを無効化させるということも構成プロファイルで設定できそうです... 図3. Apple Configurator 2 を使った構成プロファイルの設定 以上、新3大 MDMを使ったiOSアプリの配布術 の紹介でした。 正直に申しますと入社した時点では私自身がMDMのことを知りませんでした。今回、MDMの配布術を整理することで 現場の不 を考えながらモノづくりをすることが重要だということを改めて考えさせられた次第です。 アプリを導入する際の困りごとに関しては現場でその作業を聞いたり実際にやってみないと分からないことも多いと思います。紹介した事例は聞けば当たり前のことかもしれませんが意識しないと気づかないこととも思えます。 上記で紹介させて頂いた現場の事例以外でも、 常設して24時間動かしているiPadを定期的に拭き掃除してくれる業者さんがアプリを閉じないようにするためにアクセスガイド設定が必要。アクセスガイドを設定してアプリを起動させている場合、 SFSafariViewController を使ってWebブラウザを開くことはできるのか?ということも開発者は検討しなければいけないということもありました 😥 ソフトウェアエンジニアでも 現地・現物・現認という教えは大事だな と感じたところです。 最後に さて、ここまで読んで頂いてMDMを使ってみたいと思われた開発者のみなさまに残念なお知らせがあります。 それは、個人で利用できるMDMベンダーさんが調べた限り無いということ!(基本は法人契約) 安心してください。 それでもMDMを使った開発の一端に触れてみたいというエンジニアの方のために 入口 を用意してあります。詳しくは 👇 を覗いてみてください。 open.talentio.com これを機にあなたのDevelopmentの世界をExtensionしてみてはいかがでしょうか。 読んで頂きありがとうございました🙇‍♂️
初めまして。セーフィーの柏木です。 AI/画像処理エンジニアで、テックブログ運営チームにも所属しています。 今回は、セーフィーにおけるメイン事業であるクラウド録画サービスと各職種のエンジニアの業務について紹介します。 クラウド録画サービスシステムの全体像と、それぞれのエンジニアが一体何をやっているのか、わかりやすくお伝えできればと思います。 セーフィーのクラウド録画サービスシステム クラウド録画サービスの流れと、担当エンジニアの紹介 組み込みソフトウェアエンジニア サーバーサイドエンジニア/インフラ・SREエンジニア AI/画像処理 エンジニア フロントエンドエンジニア iOS/Androidエンジニア 業務システムエンジニア QAエンジニア データエンジニア 最後に セーフィーのクラウド録画サービスシステム セーフィーのクラウド録画サービスは、カメラで撮影した映像データがクラウドにアップロードされ、必要に応じてクライアントアプリケーション(フロントエンド、モバイル)に配信されており、幅広い領域の技術が組み合わさって構成されています。こういった領域に馴染みがないとなかなか複雑に感じるサービスかもしれません。 そこで今回はそのサービスの流れにそって、各領域のエンジニア業務を紹介していきます。 こちらがサービスの全体像に職種別のエンジニアを当てはめた図になります。 一つのサービスに対して非常に幅広い分野のエンジニアが関わっていることがわかりますね。それでは一つずつ紹介していきます。 クラウド録画サービスの流れと、担当エンジニアの紹介 組み込みソフトウェアエンジニア セーフィーではクラウドカメラを扱っています。 カメラがないとまず映像が撮れません。セーフィーで扱っているカメラの数は非常に多く、またメーカーも様々です。 これら幅広いカメラ機種に対応し、使いこなすためのファームウェア開発を行っているのが、「組み込みソフトウェアエンジニア」です。 使いこなすための機能として一例を挙げると、決められた時間にスナップショットの撮影を行いサーバーに保存を行うスナップショットスケジュール機能や、サーバーとの通信接続が切れたときに録画欠損を防ぐための本体録画バックアップ機能があります。また、撮影した映像をサーバーに送信する機能も画一化し実装しています。 新しいカメラを販売する際は真っ先に対応し最前線に立って実装するエンジニアです。 使用言語はC++。ライブラリではBoostも使用しています。 サーバーサイドエンジニア/インフラ・SREエンジニア カメラで撮影された映像はサーバーに送られ、録画されます。 ここでサーバーで行われる処理を実装するのが、「サーバーサイドエンジニア」です。 サーバーで録画される期間はプランによって異なるので、サーバーサイドエンジニアはプランに応じた録画データの保存処理を行っています。その後PC等フロント側に映像を送るための前処理も行っています。 また、 セーフィーで使用されるAPI全般の開発も行っており、フロントからの制御の大部分はサーバーを経由するため、サーバー側のAPIの開発が必須となります。 映像視聴アプリケーション向けの機能を実現するためのAPIのほか、各種管理アプリケーション向けのAPIの開発も行っています。合わせて保守・運用・改善も継続的に実施しています。 使用言語は主にPython。一部Go、Javaも使っています。 サーバーサイドエンジニアが利用している膨大な数のサーバーを構築・管理・運用するのが、「インフラ・SREエンジニア」です。 インフラ・SREエンジニアの役割は主に4つあります。  1.新しいシステムに対するインフラの設計  2.コードによるインフラ管理  3.システム・サーバーのアプリケーションに対する監視  4.デプロイの改善 セーフィーではインフラの規模が非常に大きく、1000台を超えるサーバーを扱っています。 今後も新しいプロダクト・アプリケーションが増えてくるため、これらの管理・改善は必須の作業です。 使用ツールはTerraform、Ansible。監視にはPrometheus, Grafana, Amazon CloudWatch, StatusCakeなどを使います。デプロイではGitHub Actionsを使うこともあります。 AI/画像処理 エンジニア 撮影された映像はAI機能を用いて解析することができます。 例えば映像内の人数を数えるオプションサービス「Safie AI People Count」がそれにあたります。解析はカメラのエッジデバイス内で行うこともあれば、サーバー内で行うこともあります。 それぞれのタスクに対して効率的な処理のパイプラインを作成し、 最適なアルゴリズムの調査・実装・改善を行うのが「AI/画像処理エンジニア」です。 アルゴリズムでは、Deep Learningを使用することもあれば、ルールベースの画像処理を扱うこともあります。 Deep Learningを使用する際は、データの収集やアノテーションなども担当します。 使用言語はPythonまたはC++。ライブラリはOpenCVやPytorchを使うことが多いです。 フロントエンドエンジニア 撮影された映像はWebブラウザで見ることができます。この 映像視聴アプリケーションの開発は「フロントエンドエンジニア」の担当です。 映像はカメラの状態によって、Live配信が切れたり、録画映像が存在しない可能性があり、快適な視聴のために複雑なエラーハンドリングを行っています。 従来の非クラウド型VMS(Video Management System)で一般的なマルチビューアー(複数台のカメラ映像同時視聴)や、高解像度・大型モニターでの視聴に対応しており、多くのカメラを扱えます。大量な情報を処理しつつ、ユーザーの使い勝手を向上する工夫を随所に凝らしています。 このアプリケーションの他に、企業・販売代理店向け管理アプリケーションの開発もしています。 使用言語はTypeScriptで、利用しているフレームワークはAngular、Vue.jsです。 iOS/Androidエンジニア 映像データはモバイル端末(スマートフォン、タブレット)からも見ることができます。 このモバイルアプリの開発を担当しているのが、「iOS/Androidエンジニア」です。 モバイル端末向けアプリにおけるUIの構築や画面の遷移、動画ストリーミングの制御、SafieのサーバーAPIとの通信や、カメラとのBluetooth通信制御などを行っています。 近年はモバイル端末用アプリを使用するユーザーが増え、一日に数万人が利用しており、Webアプリの利用ユーザーを超える人数となっています。 アプリのデザインについては、基本的にデザイン担当の部署から仕様を受け取りますが、UI/UXの改善案をエンジニア側から提案することもあります。 開発言語はiOSがSwift、AndroidはKotlinを使用しています。 業務システムエンジニア 顧客管理や受注〜出荷〜請求という一連のオペレーションに用いる社内システムを開発・運用しているのが、「業務システムエンジニア」です。 現在セーフィーではSalesforceをメインのシステムに据え、他システムと連携しています。 ECサイトからの注文情報をSalesforceに連携したり、お客様に出荷するカメラと録画プランを紐付けた上でセーフィーの基幹システムと連携したり、売上の情報を請求管理システムに連携したりなど、サービスをより円滑にお客様のもとへ届けるための仕組みづくりをしています。 クラウドカメラサービスの開発とは直接関わりませんが、今後のセーフィーの成長を下支えするために必須のエンジニアとなっています。 QAエンジニア ここまでご紹介したとおり、セーフィーの製品はフロントからデバイス、サーバーなど非常に幅広い分野にまたがっております。 これらの製品を出すためには、品質の保証を行うエンジニアが必要です。セーフィーでは QCDMT(Quality(品質)、Cost(費用)Delivery(納期)Managment Team)チームを作り、QAエンジニアが役割を担っています。 QAエンジニアは、開発した製品全般に対してテストを行っており、開発とのテスト内容のすり合わせ、テストスケジュールの調整など、品質のチェックにあたって様々な対応を行っています。 セーフィーのQAはデバイス・フロントアプリ・サーバーAPI・サービス(商品) など、広範囲にわたって仕様を理解する必要があるため非常に難しいQAとなります。しかし開発メンバーと距離が近いので、テスト時実施方法の相談や、実施結果についての不明点などを迅速に話し合える環境があります。 また、現在は効率のよいテストの実行に向けて、一部テストケースの自動化進めるなどの仕組みの効率化を進めるなどの取り組みも行っています。 個人の裁量で必要に応じてJavaScriptやSQLを利用するなど、幅広いスキルを活かした働き方も可能です。 データエンジニア セーフィーのサービスレベルを向上させて行くためには、感覚だけに頼るのではなく各種リアルな情報に基づいた分析が必要です。 必要な各種データを分析し様々な活動に活かすためのシステム基盤を開発しているのが「データエンジニア」になります。 例えばユーザーの契約、解約状況やサービスの利用動向などの集計、分析を行っています。 現在はAmazon RedShiftを利用しており、アナリストと連携しこれらの業務にあたっています。使用言語はPython、SQLです。 最後に 今回は、セーフィーのクラウド録画サービスのシステムの全体像と、各領域のエンジニアの役割について紹介しました。 今後、本ブログでも自分の領域とは馴染みのないエンジニアの記事が出てくることがあるかと思いますが、この記事をふり返ることで「あ~こんな仕事をしているんだな~」と思いながら読んでいただければ嬉しいです。 採用も積極的に行っておりますので、セーフィーに興味を持っていただいた方はぜひご応募ください。 article.safie.link
こんにちは。 セーフィー株式会社 バックエンドエンジニアの河津です。 先日ご縁あって、Node-REDをテーマにしたミートアップで簡単なLT(ライトニングトーク)をさせていただく機会がありました。 Node-REDというのはフローベースのビジュアルプログラミングツールでして、ノーコード/ローコードなアプリケーションの開発を行うことができるツールです。(詳しくは後述します。) どのような登壇内容にするか迷っていたのですが、当社で提供しているサービス「Safie API」とNode-REDが、ノーコード/ローコード開発の観点から相性いいのではなかろうかと思い立ち、これらを連携して会議室の空き状況を確認するシステムのプロトタイプを作りました。 今回はその内容に触れつつ、Safie APIとNode-REDの連携活用例について紹介させていただきます。 今回作るもの Safie APIとは? Node-REDとは? Safie APIの使用準備 Node-REDでのシステム構築 1.Slack in ノード 2.Switch ノード 3.functionノード 4.http requestノード 5.functionノード 6.Slack outノード やってみた感想 ちなみに、こちらの記事は enebular Advent Calendar 2021 に、24日目の記事として参加させていただいています。 また、こちらの内容は上述のミートアップコミュニティにてアーカイブされています。詳細な部分など口頭での説明もありますので、良ければ合わせてご覧ください。 www.youtube.com 今回作るもの Slackで「会議室の空き状況を教えて」などのようにコメントすると、現在の混雑状況を教えてくれるBotを作成したいと思います。 上記のコメントをSlackのWebhookで受け取った際に、Safie APIにて現在会議室にどれだけ人がいるかの情報を取得し、その情報をベースに「現在〇〇人が会議室を使っています」といった情報をSlack Botが答えてくれる、というようなシステムを作ってみることを目指します。 SlackのWebhook先を設定するには、本来何かしらAPIを実装してそれを設定する必要があるのと、APIを動作させるためのサーバも構築しなければなりませんが、この中継地点となるサーバおよびエンドポイントの役割を、今回はNode-REDに担ってもらいます。 下記のようなシーケンスで作成していきます。 Safie APIとは? Safie APIは、セーフィーのカメラから得られる情報を取得・更新することができるAPIです。 セーフィーではSafieViewerという、カメラに映った映像などの情報を見ることができるアプリケーションを提供しているのですが、アプリケーションとしてだけではなく、ユーザーが普段使っている業務システムにも組み込めるように、SafieViewerで提供している各機能をAPIとして提供しています。 developers.safie.link 例えば、ストリーミング映像データを取得することができたり、静止画の取得、動画のダウンロードなどを行うことができます。 テックブログ内に、「Safie APIの始め方と動作方法の紹介」というSafie APIについて解説された記事がありますので、こちらも合わせて読んでいただければと思います! engineers.safie.link Node-REDとは? Node-REDは元々IBMにて開発されたIoT向けのフローベースドプログラミングツールです。 現在はOSSとして寄贈されているため、インストールすれば誰でも使うことができます。 インストールの手順などは公式のこちらのページなどが参考になります。 nodered.org ちなみに今回僕はenebularというサービスを使い、クラウド上のNode-RED環境を使いました。 www.enebular.com Node-REDは、「ノード」という機能単位の箱(例えば、Webhookを受け取る、外部APIと通信する、Slackにメッセージを送る、など)を、「フロー」という線で組み合わせることで、いわゆるビジュアルプログラミングのような形でシステムを組むことができます。 また、細かな処理を追加したい場合はその部分だけコードを書くことができるので、ノーコード・ローコードで作りたい機能を実現することができます。 Node-REDはIoTアプリケーション開発に使われるケースが多いですが、サーバサイドの処理を任せる使い方もできます。 このNode-REDを利用して、会議室の空き状況を教えてくれるBotの作成をしていきます。 Safie APIの使用準備 前述した「 Safie APIの始め方と動作方法の紹介 」の記事内にて、Safie APIを使用するための手順が記載されていますので、良ければこちらをご覧ください。 ※2021/12/17現在、Safie APIは一部のユーザーにのみ利用を開放しており、申し込みいただいても全員が使用できるわけでないためご注意ください。 記事内の手順からアクセストークンを取得して、準備完了です。 Node-REDでのシステム構築 繰り返しですが、今回は「Slackで会議室の空き状況を聞くと、空き状況を答えてくれる」機能を作成します。そのために、Saife APIの「人物検出結果一覧API」を使用します。 今回使用するカメラにはこのような会議室が映っています。 「人物検出結果一覧API」は、このカメラに映った映像から人物を検出し、「一定期間の間に映った人の数」をカウントすることができます。 この「人物検出結果一覧API」を使用することで、直近1分間に会議室を使っていた人の数(のべ人数)を出しつつ、それをSlackで返答するようにします。 Node-REDのフローを、こんな風に組んでみました。 処理の流れとして、 Slackへのメッセージ送信検知(Slack inノード) 特定のワードのみ反応するようにする(「振り分け」という名前のSwitchノード) Safie APIにリクエストするためのパラメータ作成(「Safie人物検知API送信準備」という名前のfunctionノード) Safie APIへのリクエスト(「Safie人物検知API疎通」という名前のhttp requestノード) レスポンス内容を整形して現在会議室にいる人を算出(「返信文」という名前のfunctionノード) Slackにメッセージを送る(Slack outノード) という流れになります。 一つ一つ、どのような処理になっているかを解説します。 1.Slack in ノード Slackにメッセージが送られたことをhookしてくれる機能です。 Slack Bot作成の際に作られるAPI Tokenと、投稿されたら発火するチャンネル名を設定することができます。 2.Switch ノード 「会議室の利用状況を教えて」などの、特殊なメッセージにのみ反応してほしいため、このSwitchノードで処理の分岐を行っています。 メッセージの内容が「会議室の利用状況を教えて」だった場合に、次のノード処理に移ります。 3.functionノード Safie APIで人物検出結果を取得するためのリクエストパラメータを作成します。 functionノードではNode.jsでコードを書くことができ、今回は、会議室を映すカメラ固有のID「device_id」を設定しつつ、直近1分間に映った人の数をカウントするようにパラメータを作成します。 4.http requestノード Safie APIへのリクエストを行います。 このノードにAPIのエンドポイントやアクセストークンを設定して、認証を通るようにします。 5.functionノード Safie APIからのレスポンスをこのノードで整形します。 データには1分間に映った人数データが入っているので、それを集計しのべ人数としています。 当然この中には同じ人がカウントされているデータもまとめて集計しているのですが、今回はプロトタイプということで許容しています。 またこの処理の中で、次のノードであるSlackに送るメッセージを組み立てます。 6.Slack outノード Slackにメッセージを送るノードです。 こちらにもSlack inノードと同様、BotのAPI Tokenと、通知するチャンネルを設定することで、下記のようなメッセージを飛ばすことができます。 やってみた感想 ここまでご紹介したようにNode-REDを使うことで、少しコードを書くだけでここまでの仕組みを構築することができました。 本来はSlackとの連携や、Safie APIとの連携を行うためには中継の役割となるサーバが必要になりますが、Node-REDがそこを代替しているためかなり作成工数は抑えられています。 一方で、Node-REDにはアクセストークンをベタ書きにしており、そこをどう自動で更新していくかという点や、APIから取得したデータのうまい使い方を模索する必要があるなと感じました。 ノーコード・ローコードの仕組みは開発箇所を絞れて工数を抑えられる反面、ツールを使う上で出てくる仕様上の縛りとうまく向き合う必要があります。 クオリティ向上のためにコードを書いて追加開発を行うにも限界があるため、ノーコード・ローコードのままいかに機能を組み合わせ拡充していくかという考え方・工夫が必要になってきそうだなと感じました。
こんにちは! このたびセーフィー株式会社でインターンをさせていただきました、吉田と申します。 この記事を通して、インターンで得た学びや、会社の雰囲気などが伝われば嬉しいです。 インターンをした経緯・目的 セーフィーのどこに興味をもったのか 選考 インターンの概要 やったこと 行動認識の既存モデルの検証 機械学習モデルの量子化 学んだこと・感想 インターンをした経緯・目的 私は就職活動において、大企業よりもベンチャー企業に魅力を感じていました。 ベンチャー企業のほうが、お客さんとも関われるし、事業全体に幅広く関わったり、新しいことにチャレンジできたりしそうだと思ったからです。 ただ、実際にベンチャー企業で働いてみた経験はなかったので、職場の雰囲気や業務内容がどうなのか体験してみたく、インターンをすることしました。 セーフィーは現在の研究テーマにあっていて、かつベンチャー企業ということで、大学の就職担当の方を通して紹介していただきました。 セーフィーのどこに興味をもったのか 私は、機械学習や神経科学を使って人間の知能について研究している研究室に所属しており、そのあたりの分野に関わりのある企業を探して就活をしていました。 セーフィーは、単に映像を扱っているだけでなく、将来的に「映像プラットフォーム」を作ろうとしています。 これは、複数のカメラの映像を一元管理し、膨大な映像を言語で検索したり、様々なアプリを使って解析したりできる場を作ろうというものです。 連続的な映像データから、起きたイベントなどの抽象的な情報を取り出して言語で検索できるようにするというのは、人間が見たものの意味を理解するということと共通する点が多いと感じ、興味を持ちました。 また、映像プラットフォームでは、他社製を含む映像解析アプリのプラットフォームを作り、そこから自由に選んで自社のデータに使えるようにするという構想があり、ビジネスの発展性という点からも面白い企業だなと思いました。 選考 インターンにあたり、面談とコーディングテストを受けました。 面談は会社説明を兼ねたカジュアルなもので、給与面や、私個人の将来についてのことも含め、いろいろ相談させていただきました。 コーディングテストは初めてだったので緊張していましたが、思ったよりも軽めのもので、ゆるく競技プログラミングに触れていたこともあり通過することができました。 インターンの概要 プロダクト開発部のイメージングチームに加えていただき、10月から12月にかけて週に2日、計16日間の日程でインターンを行いました。 出社するかリモート勤務にするかは自分で決めることができ、今回はどちらも経験してみようということで、リモートと出社を半分ずつで行いました。 業務は会社から貸与されたラップトップで行いました。 チームのエンジニアの方にメンターとしてついてもらい、課題に取り組みました。 業務中は基本的にSlackでコミュニケーションをとりながら作業しました。 勤務時間の終わりにはミーティングを行い、作業ログを見ながらその日の振り返りをしつつ、次回以降の方針を決めました。このように毎回密にフィードバックを貰えたのは心強かったです。 また、Googleドキュメントにレポートの雛型を作っておき、それを埋めていくというドキュメントベースの形で作業を進めました。こうすることで、あとどのくらいで終わりそうかという見通しが立ち、短い期間の中でも安心感がありました。 レポートは最後に共有会を行い、エンジニアチームのほか、企画や営業の方からもフィードバックをいただきました。 出社した日には毎回いろんな部署の方とランチの予定が組まれていて、緊張もしましたが、どの方も気さくに話しかけてくれたので楽しかったです。 やったこと 私の興味がある分野と、社内の課題とを照らし合わせ、事前にいくつかタスクを準備していただいていました。 面談の際に、将来やってみたいこととして、映像解析の技術を応用してライフログの解析をしてみたいと伝えていたので、関係しそうなものとして、行動認識アルゴリズムの実用性を評価するというタスクをすることになりました。 行動認識の既存モデルの検証 行動認識とは、映像中に映っている人を検知し、その人が何をしているのかラベル付けするというタスクです。 店内に設置したカメラで顧客の行動から興味があるか判別してマーケティングに活かしたり、社員の姿勢や動きを認識してより働きやすいオフィスづくりに活かしたりするなどのニーズが考えられます。 今回は、PoseC3D、SlowFast Networksという2つの既存モデルに対して、社内カメラのデータを使って評価しました。 PoseC3Dは、人物の骨格を検出するスケルトンベースの行動認識アルゴリズムです。人物ごとのスケルトンと、映像全体がどんなシーンかというラベルを出力します。 github.com PoseC3Dの出力結果 SlowFast Networksは、2段階の時間解像度で映像を認識することでより正確に・効率的に認識をするという行動認識アルゴリズムです。人物ごとに行動のラベルを出力します。 github.com SlowFast Networksの出力結果 個人ごとに行動を認識できるSlowFast Networksについて、より詳しく評価を行うと以下のような結果となりました。 被写体の距離 距離が遠かったり、画面の端のほうにいたりすると人物検知されにくく、行動認識の精度も低下した。 遮蔽物がなく全身が映っていればある程度認識できた。 被写体の行動 立ち上がる、座るなどの姿勢が大きく変化する動作だと行動認識の精度が低下した。 映像の画質 画質(圧縮方式)を変更することで、同時に検知される人数が増加した。 映像の画角 急な角度で見下ろすような画角の場合、人物検知、行動認識の精度がともに低下した。 被写体と水平になるようにカメラを設置することで改善した。 今後より実用的な状況で使うためには、以下のような工夫が考えられます。 対象の全身が大きく映るようカメラ位置を調節する。 特殊な画角の場合はファインチューニング*を行う。 認識したい行動に絞って再学習する。 *ファインチューニング: 学習済みモデルの一部を再利用してネットワークを再構築する方法。 ユースケースを想定しながら実サービスとしてサーバーで運用する場合のコストの試算を複数のパターン行いました。行動認識における推論処理を定常的に行い続けるとコストが高くなるため、動体検知と組み合わせてイベントが起こったタイミングの映像でだけ推論を行うことで、コストパフォーマンスを上げるアプローチも考えました。 機械学習モデルの量子化 時間が余ったため、ほかに提案していただいていたタスクである、機械学習モデルの量子化の実験も行いました。 量子化とは、ネットワークのパラメータをより少ないビット数で表現することでモデルの軽量化を行う技術です。 通常は32bitの浮動小数点数として扱う数値を、もう少し粗くして、8bitや16bitなどの固定小数点数で表現することで、機械学習のモデルサイズを抑えることができます。結果としてメモリ消費量を軽減できたり、計算を高速化したりできる利点があります。 サーバーではなくカメラ側で画像認識を行う「エッジAI」で特に重要な技術です。 今回は、PyTorchで実装された物体検知モデルを、エッジデバイス向けの推論ライブラリであるTensorflow Liteのモデルに変換して量子化し、量子化による計算時間や推論性能の変化を調べました。 苦労した点としては、Tensorflow Liteはエッジデバイスで使われるARMプロセッサ向けに最適化されていて、intelプロセッサのPCで実行すると遅くなってしまうという落とし穴がありました。これは、Tensorflow Liteをintelプロセッサ向けのオプションをつけてビルドすることである程度緩和されました。 機械学習モデル自体の研究ではなかなか量子化やエッジAIの技術に触れることがなかったので、勉強になりました。 そのほかにも、セーフィー製品を使っている企業の見学に同行したり、協業企業とのミーティングに参加したり、社内の勉強会に参加したりと、貴重な体験をいくつもさせていただきました。 社内で定期的に開かれている勉強会では、メンバーが自分の専門分野や最近触っている技術について気軽に共有していて、とても良い文化だと感じました。 学んだこと・感想 今まで企業でしっかり実務に携わった経験がなかったこともあり、新鮮な経験ばかりで、あっという間に終わってしまったなという感じでした。 特に、実サービスを想定したサーバー運用コストの試算や削減については、研究ではほとんど意識しないことだったので新鮮でした。研究も、実用的に使われてこそ意味があるものなので、このあたりの感覚を持っていることは大事な気がしました。 また、会議やミーティングでは、大人数が参加する場であっても立場の上下なく若い人が積極的に発言していて、フランクで働きやすい雰囲気だなと感じました。 インターン期間を通して、いろいろな方が進路の相談に乗ってくださって、大変励みになりました。みなさんキャリア設計をきちんと考えていて、私ももっと自分の将来を具体的に考えなければと思わされました。 最後になりますが、メンターの方をはじめ、面倒を見ていただいたイメージングチームの皆様、そのほかお世話になった社員の皆様、本当にありがとうございました!
企画部 商品企画 今野です。Safie APIのプロジェクトの企画を担当しています。 Safie APIは現在β版として公開していますが、それを正式版にすることが近々の私の業務目標となっています。私の業務区分は、企画立案・プロジェクトマネージメントですので、バリバリの技術屋の方々に比べるとテックブログを書くには力不足感が正直否めませんが、今回、Safie APIの紹介の場を頂けるとのことで、こうして筆を取らせて頂くことになりました。 本投稿では、Safie APIの概要と簡単な動作お試し方法をご紹介します。よろしくお願いいたします。 2023.11.6 追記: 最新のSafie APIの紹介として「 Safie API v2(正式版)の始め方とトライアル方法の紹介 」を投稿しています。この記事の内容は古いものになっていますので、最新の情報は上記記事を確認ください。 Safie APIとは? Safie APIを利用するには? Safie APIを動かしてみる ①カメラ所有者に接続許可をもらう ②Code情報を使ってTokenを取得する ③アクセスできるデバイス一覧を取得する 最後に Safie APIとは? Safie APIは、セーフィーが提供するクラウド録画サービスのデータを、外部のサーバから取得したり、情報を書き足したりする機能を提供するものです。詳細な情報を知りたい方は、 Safie Develpersサイト にある APIドキュメント を参照ください。大まかには、以下の2つのことができるものと理解して頂ければ、概ね誤りはないかと思います。 カメラから動画や静止画、検知したイベント(音や動体検知、など)を取得する 動画にイベント(何かが起こった時間を記録するもの)を登録する 注意頂きたいこととして、Safie APIは外部サーバからの呼び出しを原則としているため、ブラウザから呼び出すことはできないことがあります。ブラウザから呼び出したい場合は、Safie APIの利用プランに含まれている Safie web components をご利用ください。 Safie APIを利用するには? Safie APIの新規利用をご希望の際は、 Developerサイト の「お問い合わせ>API導入前のお問い合せ」の項目よりフォームを開いて頂き、項目「API新規利用」を「希望する」にし、他、必要情報を入力の上、送信ください。情報を受けて弊社より案内を差し上げ、手続きが進みます。Safie APIの利用には以下の2つの前提条件がありますので、お問い合わせの際にはご注意ください。 クラウド録画プランを契約すること、既に契約していること Safie APIを利用するシステムがWebのページを持っていること 1は、Safie APIがカメラ毎に利用許可を管理しているために付いている条件です。利用者の方にカメラのシリアルナンバーを提供頂き、弊社側の管理システムにてそのカメラに権限付与を行います。 2は、認証に必要な情報をAPI利用者側のWebページに向けて送信しなくてはいけない手続きが、認証プロセス中にあるために付いている条件です。利用者の方より用意されたWebページのURIを提供頂き、弊社側の管理システムに事前に登録をします。 それぞれ事前に準備されていると手続きがスムーズに進みます。 手続きが完了すると、認証用のClient IDとClient Secretが記載された通知書が手元に届き、APIが使用できるようになります。 図1:Developerサイト お問い合わせ ここで大変申し訳ないお話をしなければなりません。現在、Safie APIは運用キャパシティの関係で、問い合わせを頂いた全ての方々に提供することができていません。また、法人向け公開に限定しており、個人のお問い合わせはお断りしております。β版が正式版となった際にはより多くの方々にご利用頂けるよう、現在プロジェクトを推進しております。現状はご了承頂ければと思います。 Safie APIを動かしてみる 具体的にどのように動作するのか、私の方で実際に動かしてみた手順を紹介させて頂きます。REST APIですので、呼び出し方は多種多様に可能な訳ですが、あまりこの分野に明るくない方もいらっしゃるかと思います。そのような方にとって、どのようなものなのかの感触を掴む一助になれれば幸いです。動作環境の影響はほぼないかとは思いますが、参考に実際に動作させた環境を以下に記載しておきます。 MacBook Pro (13-inch, M1, 2020) macOS Monterey version 12.0.1 Google Chrome version 95.0.4638.69 (Official Build) (arm64) Postman Version 9.0.3 (9.0.3) https://www.postman.com/ カメラにはトライアル用のSafie APIプランを付与 ①カメラ所有者に接続許可をもらう ※今回は許可を出すのは自分自身 最初にカメラ所有者から接続許可をもらう必要があります。以下のURLに指定のQuery Paramsを付与し、カメラ所有者よりカメラ所有者のSafie Viewerのメールアドレス, パスワードを入力してもらいます。 https://openapi.safie.link/v1/auth/authorize 私はPostmanを使用してQuery Paramsを設定することで、Query Paramsを含んだURLを作成しました(図2)。 図2:接続許可をもらうURLを生成(Postman) ※client_idとredirect_uriは利用者のものを使用すること そのURLをコピー&ペーストでGoogle ChromeのURL欄に貼り付けることで、接続許可の画面が表示されます(図3)。 図3:接続許可をするための認証画面(Google Chrome) 今回はカメラ所有者が自分なので、自分のSafie Viewerのメールアドレス, パスワードを打ち込みました。カメラ所有者が別の人の場合は、URLを送付し、メールアドレス, パスワードを打ち込んで許可をもらう必要があります。図3の画面にて許可を行うと、redirect_uriで指定した画面に遷移します。遷移した先では、Query ParamsのKey: Codeの文字列が付与されます。以下のように「?code=」の後に16進数の羅列が付与されますので、「?code=」の後から「&status=」の前までの文字列を記録しました。 ~~~?code=XXXXXXXXXXXX(16進数の羅列)&status= ②Code情報を使ってTokenを取得する Postmanに下記URLを入力し、マニュアルに記載された指定の各パラメータを設定します。codeは記録したものを使用しました。 https://openapi.safie.link/v1/auth/token POSTメソッド、かつ、パラメータもBodyに設定することなど指定が多いので単純にブラウザでは実行できないため、Postman上から実行しています。私はBodyのデータ形式設定を誤り一度詰まりました。正確に「x-www-form-urlencoded」を指定します。 図4:Tokenを取得(Postman) ※各パラメータは利用者のものを使用すること 成功するとPostmanのResponseにaccess_tokenが表示されます。ここで、access_tokenの文字列を記録しました。 図5: Access token 正常系Response (Postman) ③アクセスできるデバイス一覧を取得する Tokenを無事に取得できたので、アクセス可能なデバイス一覧を取得します。デバイス一覧取得は特にパラメータ指定はないため、以下URLとToken設定のみを行います。 https://openapi.safie.link/v1/devices TokenはAuthorizationのタブを選択し、Access Tokenの枠に②で記録した文字列を記入しました。Header Prefixは②のResponseに従いBearerに設定しました。実行するとデバイス一覧がResponseに表示されます。表示された一覧から操作したいデバイスを探し、そのdevice_idの文字列を記録しました。 図6:Authorizationの設定(Postman) ④静止画像を撮影してみる デバイスを操作してみます。今回は静止画撮影を行っています。以下のURLの[device_id]の部分に先ほど記録したdevice_idの文字列を設定しました。 https://openapi.safie.link/v1/devices/[device_id]/image ③の操作同様、Authorizationのタブ下にTokenを設定しました(図7)。実行すると、Responseに撮影した画像が表示されます。実際に、図7のResponseで静止画像が表示されたことを確認できました。 図7:静止画の取得(Postman) 最後に いかがでしたでしょうか。β版では運用キャパシティに限界があり、あまり大々的な広報ができない状況ですが、今回、テックブログということで簡単に紹介をさせて頂きました。紹介が主な内容だったということで、技術者の方にとっては若干物足りなかったかもしれません。今後、弊社技術者より「Safie API使ってXXXしてみた」といったような内容の記事が投稿される予定となっていますので、より技術的な内容を知りたい方は、そちらの記事も是非閲覧頂ければと思います。β版が正式版になった際は、多くの人が利用できる環境を提供でき、情報展開も大きくしていける予定です。どうぞご期待ください。