TECH PLAY

株式会社RevComm

株式会社RevComm の技術ブログ

171

こんにちは、 RevComm Research Dept. Development Groupの id:tmotegi です。趣味は積読と日本酒を嗜んでおります。昨日は 仙禽の雪だるま を飲みました。現世で2度目のアドベントカレンダーなので緊張します。 この記事は RevComm Advent Calendar 2023  、15日目の記事です。昨日の記事は豊崎さんによる「 CodemagicでFlutterアプリをビルドする 」でした。 私達のチームは、 チームトポロジー のイネイブリングチームに相当するチームとして組織されており、他のチームに対してサポート・ツール・サービスを提供し、効果的かつ効率的に業務を遂行できるようにする役割を担っています。 今回は私が取り組んだ、 AWS EC2 Inf2インスタンスを使った推論の高速化 をご紹介します。 TL;DR 背景 音声感情認識 音声感情認識機能 音声感情認識モデル 実験 環境設定 データセット 指標 実験結果 推論のパフォーマンス比較 モデルサイズ・ロード時間比較 まとめ TL;DR AWS EC2 Inf2インスタンスにより、音声感情認識モデルの推論は爆速化し、コストも削減され、精度は維持されることが分かった。 G5インスタンス (ONNX) に比べ、Inf2インスタンスは2倍以上高速に推論することができる。 G5インスタンス (ONNX) に比べ、Inf2インスタンスはコストを80%弱削減できる。 背景 私達はMiiTelのコアバリューである音声認識・話者分離・音声感情認識などの機能を実現するために最新の深層学習モデルを利用しています。このような深層学習モデルは推論時に大量の演算を必要とするため、その性能向上のために一般的にGPUが利用されます。しかし、GPUインスタンスはCPUインスタンスに比べてコストが高くなる傾向があります。一方、AWSは Inf2インスタンス という推論に特化したインスタンスを提供しています。Inf2インスタンスは AWS Neuron SDK を用いて作成した専用のモデルをデプロイすることで、パフォーマンスの向上とコスト削減を同時に実現することが可能となっています。 私はGPUインスタンスのコストがかさむ問題に対して、Inf2インスタンスを導入することで解決を試みました。具体的には、MiiTelで使われている音声感情認識モデルをONNXやGPUインスタンス、Inf1およびInf2インスタンスを使った推論を行い、結果を比較することでInf2インスタンスが導入可能かどうか検討しました。 音声感情認識 私が取り上げた音声感情認識について簡単に紹介します。 音声感情認識機能 音声感情認識機能は、話し手のポジティブ・ネガティブな感情を可視化します。話し方からポジティブ・ネガティブを認識し、オレンジからブルーのグラデーションで帯として表示します。これによって会話した当事者以外でも、ネガティブな内容の会話にいち早く気づくことができます。(下記の図の赤いドットの角丸矩形が感情を示すグラデーション) emotion gradation bar 詳細は以下のプレスリリース記事で紹介されています。 音声解析AI電話「MiiTel」、音声感情認識機能をリリース 会話のポジティブ、ネガティブな感情をAIが可視化 prtimes.jp 音声感情認識モデル 紹介した音声感情認識機能で実際に使われているモデルは、論文 "Speech Emotion Recognition based on Attention Weight Correction Using Word-level Confidence Measure" 1 で提案された "confidence measure (CM) as weighting correction" になります。 詳細は以下のブログで紹介されています。 https://tech.revcomm.co.jp/2022/07/13/voice-emotion-recognition/ tech.revcomm.co.jp 実験 この実験の目的は、AWS EC2 Inf2インスタンスを使用して、音声感情認識モデルの推論速度を改善することです。これにより、同じ品質のアウトプットを保ちつつコストと時間を節約し、効率性を向上させることを期待しました。 環境設定 c6in.2xlarge, g5.xlarge, inf1.xlargeは東京リージョンで起動し、inf2.xlargeのみまだ東京リージョンでは提供されていないため、バージニア北部リージョンで起動しました。 Instance type GPU AWS Inferentia Software c6in.2xlarge No No torch, onnxruntime g5.xlarge Yes No torch, onnxruntime, onnxruntime-gpu inf1.xlarge No Yes torch, torch-neuron inf2.xlarge No Yes torch, torch-neuronx データセット プライベートなデータセットを使ってモデルの評価を行いました。データセットは3つの感情 (happiness, anger, neutral) を含み、音声の合計長は74分です。また各クラスの事例数は次の表のとおりです。 Class # Samples happiness 201 anger 206 neutral 270 指標 音声感情認識のPyTorchモデルをCPUインスタンスで実行した結果を基準 2 とし、相対的な指標で評価します。 高速化率 新しく導入したモデルが既存のモデルと比較して、どれだけ推論速度が改善したかを示します。「PyTorchモデルをCPUで実行したときの1推論あたりの平均レイテンシー / 各モデルの1推論あたりの平均レイテンシー」で計算します。 コスト削減率 新たに導入したモデルが既存のモデルと比較して、どれだけコストを削減できたかを評価します。「1 - 各モデルの1推論あたりの平均コスト / PyTorchモデルをCPUで実行したときの1推論あたりの平均コスト」で計算します。 平均コストは平均レイテンシーとオンデマンドインスタンスの価格表から算出しました。 精度変化 新たに導入したモデルが既存のモデルと比較して、どの程度精度が変化したかを評価します。「PyTorchモデルをCPUで実行したときのaccuracy(精度)- 各モデルのaccuracy」で計算します。 モデルファイルサイズ変化率 新たに導入したモデルのファイルサイズが、既存のモデルと比較してどれだけ変化したかを評価します。モデルのファイルサイズは、一般的にストレージやメモリ上のリソース使用量に影響を与えます。「 ONNX or AWS Neuronでコンバート後のモデルのファイルサイズ / PyTorchモデルのファイルサイズ」で計算します。 モデルロード時間高速化率 新たに導入したモデルをロードするのに要する時間が、既存のモデルと比較してどれだけ速くなったかを評価します。これは、モデルを使用する前に必要な初期化時間に直結します。「PyTorchモデルのロード時間 / ONNX or AWS Neuronでコンバート後のモデルのロード時間」で計算します。 実験結果 推論のパフォーマンス比較 前処理(スペクトログラムや単語ベクトル作成)以外の推論部分についてレイテンシーおよび速度を測定し比較しました。 Model PyTorch ONNX ONNX ONNX PyTorch ONNX AWS Neuron AWS Neuron Instance c6in.2xlarge c6in.2xlarge c6in.2xlarge c6in.2xlarge g5.xlarge g5.xlarge inf1.xlarge inf2.xlarge 浮動小数点数 32 bit floating point (fp32) fp32 int8 uint8 fp32 fp32 16 bit brain floating point (bf16) bf16 高速化率 - 1.19 2.01 1.93 9.57 23.57 9.58 57.55 コスト削減率 - 0.16 0.50 0.48 0.73 0.89 0.94 0.98 精度変化 - 0.000 -0.005 -0.006 -0.007 -0.007 -0.008 -0.008 高速化 音声感情認識モデルはONNXやGPU、Inf1 & Inf2インスタンスを使うことで高速化を達成できることが分かりました。特にinf2.xlargeを使った推論はONNXモデルをGPUで動かした場合の推論速度より2倍程度早くなっています。Inf1 & Inf2インスタンスではbf16以外の データタイプ も使えるのですが、推論のレイテンシーはbf16と同程度となりました。 コスト削減 Inf1 & Inf2インスタンスのコスト削減率が高いことが分かります。これは1推論あたりの平均レイテンシーが短いことや、インスタンスの価格がGPUインスタンスより安価であることが挙げられます。 精度変化 Inf1 & Inf2ではモデルパラメータの浮動小数点数としてbf16を利用しました。ONNXやInf1 & Inf2インスタンスを使った場合には、浮動小数点数の変更はモデルの精度への影響が少ないようです。Inf1 & Inf2インスタンスではbf16以外のデータタイプも使えるのですが、ほかのデータタイプを使用してもbf16を使用した場合と同程度の精度変化が見られました。 モデルサイズ・ロード時間比較 ONNXやInf1 & Inf2インスタンスを使うことで、モデルのファイルサイズやモデルのロード時間がどのように変化したか記録しました。 Model PyTorch ONNX ONNX ONNX PyTorch ONNX AWS Neuron AWS Neuron Instance c6in.2xlarge c6in.2xlarge c6in.2xlarge c6in.2xlarge g5.xlarge g5.xlarge inf1.xlarge inf2.xlarge 浮動小数点数 fp32 fp32 int8 uint8 fp32 fp32 bf16 bf16 モデルファイルサイズ変化率 - 0.96 0.24 0.24 1.00 0.96 0.52 0.50 モデルロード時間高速化率 - 28.99 133.73 143.42 0.88 29.85 17.51 7.61 モデルファイルサイズ モデルファイルサイズは浮動小数点数に連動して小さくなりました。モデルのパラメータを16ビットで表す場合は元のモデルのファイルサイズの約1/2、8ビットで表す場合は約1/4になりました。 モデルロード時間 ONNXモデルではファイルサイズと同様に浮動小数点数の精度を下げることで、モデルロード時間が短くなる結果になりました。また、AWS Neuron SDKを用いて作成したモデルは、ONNXモデルよりは遅いものの、PyTorchのモデルのロード時間よりは早くなりました。 まとめ MiiTelで使われている音声感情認識モデルの推論をInf系インスタンスで実行し、推論速度や精度について比較しました。Inf2インスタンスを利用することで、今までの精度を維持する一方で高速で低コストな推論ができることを確認しました。また、モデルファイルサイズやモデルロード時間も既存モデルに対して改善することを確認しました。 これらの結果は、既存モデルに対する改善を示しています。品質を維持したまま推論速度を上げることで、音声感情認識の速度を高め、結果としてユーザー体験の向上が期待できます。また、コスト削減により長期の運用コストを抑えることが可能となります。 今後の課題としては、既存モデルを実際にInf2インスタンスで置き換え、音声感情認識の高速化とコスト削減に取り組むことがあげられます。また、他の深層学習を使った機能やサービスに対して、同様の最適化手法を適用することも推進する予定です。 Santoso, J., Yamada, T., Makino, S., Ishizuka, K., Hiramura, T. (2021). Speech Emotion Recognition Based on Attention Weight Correction Using Word-Level Confidence Measure. Proc. INTERSPEECH, 1947-1951, doi: 10.21437/Interspeech.2021-411 ↩ 現在の音声感情認識モデルはCPUインスタンスで実行されてるため。 ↩
アバター
この記事は RevComm Advent Calendar 2023  14 日目の記事です。 RevComm でフロントエンド開発をしている豊崎 朗です。MiiTel Analytics、MiiTel Mobile Phone、MiiTel RecPod というプロダクトに携わっています。フロントエンドチームに籍を置いていますが、バックエンド、モバイルアプリ開発もやっています。 (フルスタックチームは、別であります。) MiiTel Mobile Phone、MiiTel RecPod はモバイルアプリであり、Flutter を用いて開発を行っています。この記事では、これらのプロダクトで利用している CI/CD サービスである Codemagic について紹介します。 目次 Codemagic について やってみよう 初期設定 ~ App の設定 Workflow の設定 トリガーの設定 (Build triggers) キャッシュの設定 (Dependency caching) その他の設定 テスト Codemagic の設定のバックアップについて まとめ Codemagic について Codemagic は、Flutter, ReactNative, native iOS, native Android, Unity, Kotlin Multiplatform, Ionic といったようなモバイルアプリのためのクラウドベースの CI/CD プロダクトになります。 ビルド, テスト, Apple App Store, Google Play などの App Store へのデプロイメントのプロセスを自動化することが出来ます。 プロセスのトリガーとして、GitHub などのリポジトリへ push, Tag の追加, PR のマージといったアクションを指定することが出来ます。 また、個人で利用する場合、月に無料で 500 分、mac OS (M1 マシン) を動かすことができるので個人でアプリ開発をしているユーザーにとって、大変お財布に優しくなっています。 やってみよう 今回は、以下の想定で Codemagic で Flutter アプリをビルドしてみます。 リポジトリ: GitHub トリガー: main ブランチにマージされたタイミング アプリ: Flutter アプリ 初期設定 ~ App の設定 Codemagic では、App(Application) 単位で設定を行います。 App には、一つのリポジトリが紐づくという仕様になります。 Sign up画面 から Codemagic へ Sign up を行う。 Sign up が完了すると、 管理画面 に遷移する。 App の設定を行う。 画面の右上にある、 Add application ボタンをクリック Appの設定を開始 GitHub を選択し Next: Select repository をクリック リポジトリの選択 Select repository の Github integration をクリック。ダイアログが開くので、Codemagic でビルドしたいリポジトリを選択する。 ビルドするリポジトリの選択 Select project では、 Flutter App (via Workflow Editor) を設定する 全体の設定 Finish: Add application をクリックする。 以下のようにリポジトリの設定がされていれば完了となります。 設定完了の様子 Workflow の設定 ここからは、Workflow の設定に移ります。 Codemagic では、App に複数の Workflow を設定することができ、App 作成後はデフォルトで Default workflow という名前の Workflow が存在します。 それでは、Default workflow を main ブランチに PR がマージされたタイミングで走らせるような設定をしてみましょう。 トリガーの設定 (Build triggers) Build triggers を開く。 Automatic build triggering の Trigger on push をチェック Watched branch patterns に以下を設定し、Add pattern ボタンをクリック Add new pattern: main Include or Exclude: Include Source or Target: Target トリガーの設定 キャッシュの設定 (Dependency caching) キャッシュの設定をしておくと、依存パッケージをインストール時の速度が向上するため、設定しておきましょう。 * キャッシュは、最大で 14 日間キャッシュをします。 Enable dependency caching をチェック 以下のパスを追加する。 $FLUTTER_ROOT/.pub-cache $HOME/.gradle/caches $HOME/Library/Caches/CocoaPods キャッシュの設定 その他の設定 Codemagic は、他にも様々な設定ができ柔軟性があります。ここでは紹介に留めておきます。 Workflow は以下の流れで実行され、様々な設定をすることができます。 * 太字の部分は、今回デフォルトの設定から変更していない機能になります。 ビルドトリガー (Build triggers) 環境変数 (Environment variables) キャッシュ設定 (Dependency caching) Post-clone スクリプト (Post-clone script) Pre-test スクリプト (Pre-test script) テスト (Tests) Post-test スクリプト (Post-test script) Pre-build スクリプト (Pre-build script) ビルド (Build) Flutter version, Xcode version, CocoaPods version, Android build format, Build mode, Build arguments が設定可 Post-build スクリプト (Post-build script) Pre-publish スクリプト (Pre-publish script) ディストリビューション (Distribution) Google Play, App Store Connect, Firebase App Distribution へのアプリ配信も自動化することができます。 RevComm では、weekly でアプリを自動ビルドし、それぞれへ配信しています。 通知 (Notifications) デフォルトでは、メールへビルド結果の通知が配信されるようになっています。 オプションで、Slack への通知が出来ます。 設定し終えたら、画面の右上から Save changes をクリックします。 ビルド設定は以上になります。 テスト 適当な PR を立てて、CI が走るかどうかテストしてみます。 PRをマージする様子 PR がマージされると、Codemagic の Builds ページから CI が走っているかどうか確認することができます。 workflowが起動された様子 詳細画面は、以下のような感じになります。 実行中のworkflow 完了後のworkflow 問題無く、ビルドが完了していることがわかります 🎊 今回は、Post-build スクリプトやディストリビューションを設定していないため、ビルドした成果物を詳細画面からダウンロードすることぐらいしか出来ません。 RevComm では、Post-build スクリプトに DeployGate の API を叩くようにし dev 環境を構築したり、ディストリビューションに Google Play と Apple Store Connect を連携させて、Closing testing, TestFlight で stg 環境を構築しています。 余力がありましたら、是非試してみてください。 Codemagic の設定のバックアップについて Codemagic で設定した App の Workflows を GitHub で管理したい時があると思います。 Codemagic API では、 Applications API を用いることで、Workflow Editor で設定した情報を json でバックアップすることが出来ます。 しかし、リストアに関しては対応していないため、あくまで設定した情報をバックアップするという用途でしか使えません。 * Workflow Editor を利用せず、設定したリポジトリに配置した codemagic.yaml を参照するといった設定も出来ます。この方法であれば、バックアップとリストアもすることが出来ます。細かい設定をする人は、こちらの方が向いているかもしれません。 RevComm では、GitHub Actions から Codemagic API を実行し、定期的にバックアップを取るようにしています。 ここでは、そちらを共有します。 以下の GitHub Actions ファイルを .github/workflows/sync-codemagic-settings.yaml として保存する。 name : Sync codemagic-settings on : schedule : - cron : '0 0 * * *' # Every day at 00:00 UTC workflow_dispatch : jobs : sync : name : Sync codemagic-settings runs-on : ubuntu-latest env : CODEMAGIC_APP_ID : <Your codemagic app id> steps : - name : Checkout uses : actions/checkout@v4 with : ref : main - name : Fetch codemagic-settings run : | curl -s -H "Content-Type: application/json" \ -H "x-auth-token: ${CODEMAGIC_TOKEN}" \ --request GET https://api.codemagic.io/apps/${CODEMAGIC_APP_ID} > codemagic-settings.json env : CODEMAGIC_TOKEN : ${{ secrets.CODEMAGIC_TOKEN }} - name : Diff check continue-on-error : true id : diff_check run : git diff --exit-code # only run if there are changes - name : Commit changes and create pull request if : ${{ steps.diff_check.outcome == 'failure' }} run : | NOW=$(date +"%Y%m%d%H%M") git config --global user.name "action@github.com" git config --global user.email "65916846+actions-user@users.noreply.github.com" git checkout -b feature/update-codemagic-settings-${NOW} git add codemagic/workflows.json git commit -m "Update codemagic-settings" git push origin feature/update-codemagic-settings-${NOW} gh pr create -B develop -H feature/update-codemagic-settings-${NOW} --title 'Update codemagic-settings' --body 'Updated codemagic-settings by github-actions' env : GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }} sync-codemagic-settings.yaml の CODEMAGIC_APP_ID: <Your codemagic app id> の部分の置き換え Codemagic の App の設定ページのアドレスバー ( https://codemagic.io/app/<app id>/workflow/<workflow id>/settings ) から、 <app id> を取得し、そちらを利用する。 Codemagic の API トークンを取得し、GitHub Actions の Secret として設定する。 Codemagic の左のメニューから、Teams をクリック → Personal Account をクリック → General settings の Integrations をクリック → Codemagic API から API トークンを取得する。 Codemagic apiトークンの取得 GitHub リポジトリの Settings ページ → Secrets and variables → Repository secrets に Name: CODEMAGIC_TOKEN, Secret: 先ほど取得したトークンを設定する。 設定は以上になります。 毎日 0 時に GitHub Actions が定期実行され、リポジトリに保存されている設定と Codemagic の Workflow に差分があった時のみ、PR が自動的に作成されます。 また、 workflow_dispatch の設定も入れているため、任意のタイミングで GitHub Actions を実行することもできます。 まとめ Codemagic で Flutter アプリをビルドし、Codemagic の設定ファイルを GitHub Actions でバックアップをしました。 Codemagic を使っていると、手元でアプリをビルドするという運用には戻れなくなります。(私は、戻れなくなりました 😊) Codemagic は、設定も柔軟に出来ますし、App Store へ成果物を自動的にアップロードしてくれるので、個人的には満足しています。 まだ、モバイルアプリ開発者で CI/CD を導入していない方は、是非 Codemagic を使ってみてください! それでは、また 👋
アバター
Introduction As a professional developer, you encounter something new every day: new coding techniques, new ways of organizing projects, new bugs, new tools, etc. The amount of knowledge the world has to offer is too much, so we write it down as a note in a Jira ticket or as a comment in a PR. We recall certain patterns and internalize the frequent ones; we unconsciously discard the rare to the bottom of our long-term memory. And then it happens. That little hack comes to bite back again, and you have a hunch of how to solve it. You may have bookmarked the solution in Stack Overflow, or was it a ChatGPT conversation? When did that bug happen anyway? What was the context? I’ve experienced this many times. In this post, I’ll describe a solution to this conundrum: “a knowledge portfolio.” A knowledge portfolio Your knowledge portfolio describes all the information you’ve encountered throughout your career. In a sense, it determines your identity as an engineer. The Pragmatic Programmer [1] offers clear-cut guidelines to build a successful portfolio. In this post, I’ll comment on the most impactful points that kept mine robust and updated. Tips Write an engineering daybook We use daybooks to take notes in meetings, to jot down what we’re working on, to note variable values when debugging, to leave reminders where we put things, to record wild ideas, and sometimes just to doodle. - Andy and Dave, The Pragmatic Programmer An engineering daybook is a recount of your day as an engineer. It could be ramblings about what you’ve done, a loose set of links of all you’ve seen, or wild ideas barely connected. Whatever the form, storing that information is crucial so it can be accessed anywhere, anytime. I especially recommend writing your thoughts, as it’s like teaching something. Just by doing it, you organize and consolidate the ideas floating around. If you hate writing, just a one-liner or a link is a good starting point. Choose tools you’re comfortable with I use Evernote to keep my portfolio, but any tool you’re familiar with is enough. Some essential functions any such tool should have are: Export to plain text (food for your future super-intelligent AI butler) Synchronization across devices (you might want that info in your phone) Tagging system (to categorize your knowledge) Task reminding feature (to plan your learning) I also recommend Readwise to highlight anything from the internet. You can write a script to export everything to Evernote. Tag everything Was that some new feature in React? Ok, append the React tag. Tag everything so that you can find things more easily. If you can subcategorize tags, it’s even better. Evernote does it like this: Maintain a "bugdex" Because of optimism, we usually expect the number of bugs to be smaller than it turns out to be. Therefore, testing is the most mis-scheduled part of programming. - Frederik P. Brooks Jr., The Mythical Man-Month [2] Bugs are Software Engineering’s necessary evil. We spent a great deal of our time fixing them. Document every bug; you’ll never know when it’ll pop up again. Isolate the bug and track it on your favorite source control. There are two caveats. First, only some bugs can be isolated. In that case, at the very least, describe what happened (context, cause, and solution), your future self will be grateful. Furthermore, start to classify them by framework or programming language. Make time for testing wild ideas The most daunting piece of paper is the one with nothing written on it - Andy and Dave, The Pragmatic Programmer [1] Take advantage of your knowledge. If you find some interesting idea, don’t let it float around. Use your chosen tool’s reminder feature to test that idea later or to practice something you’ve bookmarked recently. Conclusion In this post, I’ve described my experience with maintaining a knowledge portfolio. Every person is different: the crafters who keep everything clean and organized, the pragmatics who just want the information to be stored somewhere. Find what works for you; in the end, storing and centralizing the data is the essential part. And if you never use that data, at least you now have a kind of work memoir for your family and friends: old traditions are getting cooler again. About the author Hi, I'm Jose @juanjo12x , and I work as a Backend Engineer here at Revcomm. I spend my days writing Python and thinking about what to learn next. References [1] Andy Hunt and Dave Thomas. The Pragmatic Programmer 20th Anniversary Edition. [2] Frederik P.Brooks, Jr. The Mythical Man-Month.
アバター
こんにちは! RevComm のフロントエンドエンジニアの小山功二です。 私が RevComm に入社する前に担当した開発案件は、どれも国内のユーザーにしか使われていないものばかりでした。一方で、RevComm の提供する MiiTel は、日本はもちろんインドネシアやアメリカでも使われています。 私の担当する MiiTel CallCenter というプロダクトは今年リリースしたのですが、こちらもリリース当初から海外で利用できることが求められていました。 開発時からタイムゾーンを扱うのは大変そうだよねというのは感じていたのですが、想定よりも大変でした。 そこで今回はタイムゾーン周りの理解を深めるために、Day.js のタイムゾーンを変更する関数である tz という関数について整理していきたいと思います。 似たような4種の書き方ができる Day.js の tz 関数 まず tz 関数を使えるようにする準備をしましょう。 Day.js でtz関数を使えるようにするには timezone パッケージをインストールする必要があります。また、場合によって customParseFormat パッケージが必要になるケースもあります。 ここでは yarn を使っています。 $ yarn add dayjs timezone $ yarn add customParseFormat dayjsを拡張します。 import dayjs from 'dayjs' ; import timezone from 'dayjs/plugin/timezone' ; import timezone from 'dayjs/plugin/customParseFormat' ; dayjs.extend ( timezone ); dayjs.extend ( customParseFormat ) これで tz 関数を使えるようになりました。 この tz 関数は公式ドキュメントの中では3つページに記載があり、それぞれ別の使い方があることが示されています。 Time Zone Parsing in Zone Converting to Zone 私はこの公式ドキュメントにない書き方をしてしまったのですが、それが Parsing in Zone に近い書き方で第一引数にDate型の値を入れてしまった書き方です。 Parsing in Zone には以下のように書いてあるので、第一引数がstring でくる前提のように見えます。 Parse date-time string in the given timezone and return a Day.js object instance. 一方で、tzの型をVSCode上で見てみると、以下のようになっていました。 const tz: dayjs.DayjsTimezone ( date: string | number | dayjs.Dayjs | Date | null | undefined , timezone?: string | undefined ) => dayjs.Dayjs ( + 1 overload ) 第一引数はstring以外も許容しています。 この点、具体的なコードをみた方が比較しやすいと思うので、 いくつかの記法を並べてみましょう。 // [記法1] ローカルタイムゾーンで '2023-12-25 00:00:00'を'Pacific/Honolulu'のタイムゾーンに変換 dayjs ( "2023-12-25 00:00:00" ) .tz ( "Pacific/Honolulu" ) // [記法2] '2023-12-25 00:00:00'を'Pacific/Honolulu'のタイムゾーンでパース dayjs.tz ( "2023-12-25 00:00:00" , "Pacific/Honolulu" ) // [記法3] 記法2と同じ日時をdate型で指定したもの dayjs.tz (new Date ( '2023-12-25 00:00:00' ), "Pacific/Honolulu" ) // [記法4] 文字列のフォーマットを解析して'Pacific/Honolulu'のタイムゾーンを設定(customParseFormatが必要) dayjs.tz ( "12-25-2023 00:00:00" , "MM-DD-YYYY ss:mm:HH" , "Pacific/Honolulu" ) 記法2が Parsing in Zone に記載がある使い方で、記法3 が私が書いてしまったコードと同様の書き方です。 試しに、実際にどんな値が返ってくるか format 関数を使って見てみましょう。 なお、日本のタイムゾーンであるAsia/TokyoはUTC+09:00であり、以下のコードの中に出てくるPacific/Honoluluの中で設定しているPacific/HonoluluはUTC-10:00です。2つのタイムゾーンの時差は19時間です。 // [記法1] 日本時間2023-12-25 00:00:00のPacific/Honoluluでの時間を返す。 dayjs ( "2023-12-25 00:00:00" ) .tz ( "Pacific/Honolulu" ) .format ( "YYYY-MM-DDTHH:mm:ssZ" ) => "2023-12-24T05:00:00-10:00" // [記法2] Pacific/Honoluluのタイムゾーンの2023-12-25 00:00:00を返す。 dayjs.tz ( "2023-12-25 00:00:00" , "Pacific/Honolulu" ) .format ( "YYYY-MM-DDTHH:mm:ssZ" ) => "2023-12-25T00:00:00-10:00" // [記法3] Pacific/Honoluluのタイムゾーンの2023-12-25 00:00:00を返して欲しかったのですが、そうなっていない... dayjs.tz (new Date ( '2023-12-25 00:00:00' ), "Pacific/Honolulu" ) .format ( "YYYY-MM-DDTHH:mm:ssZ" ) => "2023-12-24T05:00:00-10:00" // [記法4] Pacific/Honoluluのタイムゾーンにて、“12-25-2023” という文字列が "MM-DD-YYYY" というフォーマットになっていると解釈した値を返す。 dayjs.tz ( "12-25-2023" , "MM-DD-YYYY" , "Pacific/Honolulu" ) .format ( "YYYY-MM-DDTHH:mm:ssZ" ) => "2023-12-25T00:00:00-10:00" 記法2と3の結果が一致しませんでした。 tz 関数の実処理をコードから確認 なぜこうなるかわからなかったので、Day.jsのコードをみてみました。 https://github.com/iamkun/dayjs/blob/dev/src/plugin/timezone/index.js 以下は tz 関数の該当コードの抜粋です。 d.tz = function ( input , arg1 , arg2 ) { const parseFormat = arg2 && arg1 const timezone = arg2 || arg1 || defaultTimezone const previousOffset = tzOffset ( +d (), timezone ) if (typeof input !== 'string' ) { // timestamp number || js Date || Day.js return d ( input ) .tz ( timezone ) } const localTs = d.utc ( input , parseFormat ) .valueOf () const [ targetTs , targetOffset ] = fixOffset ( localTs , previousOffset , timezone ) const ins = d ( targetTs ) .utcOffset ( targetOffset ) ins.$x.$timezone = timezone return ins } typeof input !== 'string' のとき、たとえば date 型を引数として設定した場合、 d(input).tz(timezone) を返す処理になっています。これは記法1のタイムゾーンを変換する処理と同じ結果になります。 ドキュメントにはこの点の記載がないので、Day.jsのリポジトリに改善提案の issue を立てました。 終わりに まとめると以下のようになります。 // [記法1] dateTimeString を timezone に変換 dayjs ( dateTimeString ) .tz ( timezone ) // [記法2] dateTimeString を timezone でパース dayjs.tz ( dateTimeString , timezone ) // [記法3] dateObject を timezone に変換(記法2に似てますが、記法1と同じ結果なので注意が必要) dayjs.tz ( dateObject , timezone ) // [記法4] dateTimeStringをcustomParseFormatで解析して、timezoneでパース dayjs.tz ( dateTimeString , customParseFormat , timezone ) 今回は、Day.js の tz 関数について整理をすることができました。 これからもタイムゾーンとしっかり向き合い、日本でも国外でも多くの方々に使われるプロダクトに成長させられるように向き合っていきたいです。
アバター
概要 想定読者 MiiTelのOutgoingWebhook 機能について 本記事で紹介しているGoogleCalendar連携について 利用想定 開発者向け情報 概要 全体の処理シーケンス GoogleCalendarAPI利用時に認証tokenを保存するための処理 通話完了からGoogleCalendarへイベントを登録する処理 事前準備 GoogleCalendarAPIの利用設定 OutgoingWebhookの利用設定 連携サーバの構築 構成情報 GCPでサーバ構築 PHPのインストール Nginxの設定 OAuth用の処理 カレンダー登録処理 おわりに 概要 株式会社RevCommのCorporateEngineeringチームの登尾です。 この記事は 株式会社RevComm Advent Calendar 2023 の 11日目の記事です。 MiiTelのOutgoingWebhook機能を使い応対履歴をGoogleCalendarに残す方法について紹介します。 想定読者 MiiTel製品の導入検討中の方 : MiiTelのOutgoingWebhook機能でどのようなことができるか知りたい方 MiiTel製品導入済みの方 : 自社の業務にあわせてMiiTelのカスタマイズを検討している方。カスタマイズの作業を行う開発者の方 MiiTelのOutgoingWebhook 機能について トーク解析AI の MiiTelには様々な機能があります。 詳しくは MiiTel 機能紹介ページをご覧ください。 様々な機能の中の1つの OutgoingWebhook は、「MiiTel Analytics」プラットフォームで解析した結果を、他社システムへ連携可能にします。 https://miitel.com/jp/archives/4907 本記事で紹介しているGoogleCalendar連携について 本記事では「MiiTel Analytics」プラットフォームで解析した結果をGoogleCalendarに連携する方法について紹介します。 具体的には、電話が完了し、音声解析が終了すると、GoogleCalendarに通話の応対履歴が自動で登録されます。 流れをスクリーンショットと共に見ていきましょう。 MiiTelPhoneで電話をかける 2. 応対履歴が作成される 3. GoogleCalendarに応対履歴が連携される。GoogleCalendarの説明文に登録されたリンクからMiiTelの応対履歴ページに戻ることができる 利用想定 この仕組みを使うことで、営業支援システムを導入していない企業様が電話による営業活動を効率化できます。営業担当者の応対履歴がGoogleCalendarに同期され、GoogleCalendarを見ることで誰がどの取引先にどのくらい時間を使ったかを簡易的に見ることができるようになります。 開発者向け情報 概要 OutgoingWebhookを使ってGoogleCalendar連携するには下の2つの実装が必要となります。 GoogleCalendarにイベント(タイトル、開始時間、終了時間、参加者などの情報を含むカレンダー上のイベント) を登録するための処理 GoogleCalendarAPI を利用します。GoogleCalendarAPIを使って イベント を登録するには Google の OAuth認証 も必要です。OAuth認証用の処理も作成する必要があります。 Google の OAuth Appについての詳細は OAuth App Verification Help Center を確認してください。 MiiTelのOutgoingWebhookのリクエストを受けつけるための処理 実装する際には MiiTel OutgoingWebhookのサポートページ で詳細をご確認ください。 全体の処理シーケンス GoogleCalendarAPI利用時に認証tokenを保存するための処理 今回は簡単に構築するために、 tokenを連携サーバ内にファイルとして保存しました。実際に運用をする際には検討が必要な部分です(図の9番の処理) 通話完了からGoogleCalendarへイベントを登録する処理 事前準備 GoogleCalendarAPIの利用設定 GoogleCloudの左メニューからGoogleCalendarAPIを選択し GoogleCalendarAPIを有効にします 右上のボタンより認証情報を作成します 承認済みの JavaScript 生成元 と 承認済みのリダイレクト URI に 連携サーバのものを指定します OAuth同意画面で公開ステータスをテスト、テストユーザーにこの連携で利用するメールアドレスを追加します OAuthのスコープを指定します OutgoingWebhookの利用設定 MiiTelAdminの外部連携機能で事前にOutgoingWebhookの設定を行います 設定完了画面 連携サーバの構築 💡 セキュリティ上の注意: サーバを構築する際は、Firewallで不要なポートへのアクセスやアクセス元IPアドレスを制限すること、脆弱性のある古いバージョンのライブラリは利用しない等、セキュリティには十分注意してください。 構成情報 構築環境: GCP(Google Cloud Platform) アプリケーション: PHP (フレームワークは Slim を利用), nginx ドメイン: お名前.comで取得 GCPでサーバ構築 Compute Engine → Compute Engineを有効化 → VM インスタンス → 新規作成 からサーバを作成します CloudDNSでお名前.comで取得したドメインと紐付けます https://over40.work/entry/gcp-clouddns/ (こちらのページを参考にさせていただきました。ありがごうございました) PHPのインストール sudo apt update sudo apt install php-cli php-fpm php-json php-common php-mbstring curl unzip curl -sS https://getcomposer.org/installer | php sudo mv composer.phar /usr/local/bin/composer sudo timedatectl set-timezone Asia/Tokyo mkdir relation_app cd relation_app composer require slim/slim:"4.*" composer require slim/psr7 composer require guzzlehttp/guzzle composer require google/auth composer require google/apiclient Nginxの設定 インストール sudo apt install nginx sudo systemctl start nginx sudo systemctl enable nginx # 証明書に無料の Let’s encript を利用 sudo apt install certbot python3-certbot-nginx nginxのconf設定 # HTTPのリクエストをHTTPSにリダイレクト server { listen 80; listen [::]:80; server_name **********; location / { return 301 https://$host$request_uri; } } # HTTPSの設定 server { listen 443 ssl; server_name **********; root /home/sh-noborio/relation_app; index index.php index.html index.htm index.nginx-debian.html; ssl_certificate /etc/letsencrypt/live/**********/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/**********/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { try_files $uri =404; fastcgi_pass unix:/run/php/php7.4-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } OAuth用の処理 シーケンス図 PHPのコード(一部抜粋) ルーティング処理、他APIの呼び出し <?php namespace calendar; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Slim\Factory\AppFactory; require __DIR__ . '/vendor/autoload.php' ; $ app = AppFactory :: create () ; // GoogleOAuthLogin画面へ遷移するためのページ // シーケンス図 3番,4番の処理 $ app -> get ( '/google_oauth' , function ( Request $ request , Response $ response , $ args ) { $ client = new GoogleOAuthClient () ; $ url = $ client -> getAuthUrl () ; $ response -> getBody () -> write ( '<button onclick="window.location.href= \' ' . $ url . ' \' ;">Google OAuth</button>' ) ; return $ response ; }) ; // OAuthのcodeを受け取ってtokenを保存するための処理 // シーケンス図 6番〜9番の処理 $ app -> get ( '/google_oauth_callback' , function ( Request $ request , Response $ response , $ args ) { $ params = $ request -> getQueryParams () ; if ( isset ( $ params [ 'code' ])) { $ authCode = $ params [ 'code' ] ; $ client = new GoogleOAuthClient () ; $ token = $ client -> fetchAndSaveToken ( $ authCode ) ; $ response -> getBody () -> write ( "Token saved successfully!" ) ; return $ response ; } else { $ response -> getBody () -> write ( "Error: No authorization code received." ) ; return $ response -> withStatus ( 400 ) ; } }) ; GoogleOAuth用の処理 <?php namespace calendar; use GuzzleHttp\Client; use Google\Auth\OAuth2; class GoogleOAuthClient { const CLIENT_ID = '************' ; const SCOPES = 'https://www.googleapis.com/auth/calendar openid email' ; const REDIRECT_URI = 'https://**********/google_oauth_callback' ; const CLIENT_SECRET = '***' ; public function getAuthUrl () { $ oauth2 = new OAuth2 ([ 'clientId' => self :: CLIENT_ID, 'authorizationUri' => 'https://accounts.google.com/o/oauth2/v2/auth' , 'redirectUri' => self :: REDIRECT_URI, 'tokenCredentialUri' => 'https://oauth2.googleapis.com/token' , 'scope' => self :: SCOPES, ]) ; return $ oauth2 -> buildFullAuthorizationUri () ; } /** * codeを使ってアクセストークンを取得しファイルとして保存する * シーケンス図 7番〜9番の処理 */ public function fetchAndSaveToken ( $ authCode ) { $ oauth2 = new OAuth2 ([ 'clientId' => self :: CLIENT_ID, 'redirectUri' => self :: REDIRECT_URI, 'tokenCredentialUri' => 'https://oauth2.googleapis.com/token' , 'grant_type' => 'authorization_code' , ]) ; $ oauth2 -> setCode ( $ authCode ) ; // アクセストークンを取得 $ client = new Client () ; $ response = $ client -> post ( $ oauth2 -> getTokenCredentialUri () , [ 'form_params' => [ 'code' => $ authCode , 'client_id' => self :: CLIENT_ID, 'client_secret' => self :: CLIENT_SECRET, 'redirect_uri' => self :: REDIRECT_URI, 'grant_type' => 'authorization_code' , 'access_type' => 'offline' , 'prompt' => 'consent' , ] ]) ; $ token = json_decode ( $ response -> getBody () , true ) ; $ mail = $ this -> getEmailFromToken ( $ token ) ; // トークンをファイルに保存 file_put_contents ( $ this -> getTokenPath ( $ mail ) , $ token [ 'access_token' ]) ; return $ token ; } public function getEmailFromToken ( $ token ) { if ( isset ( $ token [ 'id_token' ])) { $ idToken = $ token [ 'id_token' ] ; list ( $ header , $ payload , $ signature ) = explode ( '.' , $ idToken ) ; // Decode payload $ decodedPayload = json_decode ( base64_decode ( strtr ( $ payload , '-_' , '+/' )) , true ) ; return $ decodedPayload [ 'email' ] ?? null ; } return null ; } カレンダー登録処理 シーケンス図 PHPのコード(一部抜粋) ルーティング処理、他APIの呼び出し <?php namespace calendar; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Slim\Factory\AppFactory; require __DIR__ . '/vendor/autoload.php' ; $ app = AppFactory :: create () ; // webhookリクエストを受け付け // シーケンス図 3番〜6番の処理 $ app -> post ( '/webhook' , function ( Request $ request , Response $ response , $ args ) { $ body = $ request -> getBody () -> getContents () ; $ webhook_response = new OutgoingWebhookResponse ( $ body ) ; // 外線発信以外 または Email が取れない場合は処理停止 if ( !$ webhook_response -> isOutGoingCall ()   || !$ webhook_response -> getEmailAddress ()) { return $ response ; } // 初回のチャレンジレスポンスのための処理 if ( $ webhook_response -> getChallenge ()) { $ response -> getBody () -> write ( $ webhook_response -> getChallenge ()) ;          $ response -> withHeader ( 'Content-Type' , 'text/plain' ) ;          return $ response ; } $ title = $ webhook_response -> getCompanyName () . ':' . $ webhook_response -> getName () . '様' ; $ start_date = $ webhook_response -> getAnsweredAt () ; $ end_date = $ webhook_response -> getEndsAt () ; $ id = $ webhook_response -> getId () ; // GoogleCalendarにEventを登録 $ googleOAuthClient = new GoogleOAuthClient () ; $ event = $ googleOAuthClient -> createEvent ( $ mail , $ title , $ id , $ start_date , $ end_date ) ; $ response -> withHeader ( 'Content-Type' , 'text/plain' ) ; return $ response ; }) ; OutgoingWebhookのResponse用の処理 <?php namespace calendar; /** * @see 音声認識終了時にチェックを入れた場合のペイロード https://support.miitel.jp/hc/ja/articles/13050493066905-Outgoing-Webhook */ class OutgoingWebhookResponse { private $ data ; public function __construct ( $ json ) { $ this -> data = json_decode ( $ json , true ) ; } public function getEmailAddress () { if ( $ this -> data [ 'call' ][ 'details' ][ 0 ][ 'call_type' ] === 'OUTGOING_CALL' ) { foreach ( $ this -> data [ 'call' ][ 'details' ][ 0 ][ 'participants' ] as $ participant ) { if ( $ participant [ 'from_to' ] === 'FROM' ) { return $ participant [ 'name' ] ?? null ; } } } return null ; } public function getChallenge () { return $ this -> data [ 'challenge' ] ?? null ; } public function getAnsweredAt () { return $ this -> data [ 'call' ][ 'details' ][ 0 ][ 'dial_answered_at' ] ?? null ; } public function getEndsAt () { return $ this -> data [ 'call' ][ 'details' ][ 0 ][ 'dial_ends_at' ] ?? null ; } public function getCompanyName () { if ( $ this -> data [ 'call' ][ 'details' ][ 0 ][ 'call_type' ] === 'OUTGOING_CALL' ) { foreach ( $ this -> data [ 'call' ][ 'details' ][ 0 ][ 'participants' ] as $ participant ) { if ( $ participant [ 'from_to' ] === 'TO' ) { return $ participant [ 'company_name' ] ?? '' ; } } } } public function getName () { if ( $ this -> data [ 'call' ][ 'details' ][ 0 ][ 'call_type' ] === 'OUTGOING_CALL' ) { foreach ( $ this -> data [ 'call' ][ 'details' ][ 0 ][ 'participants' ] as $ participant ) { if ( $ participant [ 'from_to' ] === 'TO' ) { return $ participant [ 'name' ] ?? '' ; } } } } public function getId () { return $ this -> data [ 'call' ][ 'id' ] ?? '' ; } public function isOutGoingCall () { return isset ( $ this -> data [ 'call' ][ 'details' ][ 0 ][ 'call_type' ]) && $ this -> data [ 'call' ][ 'details' ][ 0 ][ 'call_type' ] === 'OUTGOING_CALL' ; } } GoogleCalendarにEventを登録する処理 <?php namespace calendar; use GuzzleHttp\Client; use Google\Auth\OAuth2; class GoogleOAuthClient { const CLIENT_ID = '************' ; const SCOPES = 'https://www.googleapis.com/auth/calendar openid email' ; const REDIRECT_URI = 'https://**********/google_oauth_callback' ; const CLIENT_SECRET = '***' ; const MIITEL_URL = 'https://***********/miitel.jp' ; /** * @see https://developers.google.com/calendar/api/v3/reference/events/insert?hl=ja */ public function createEvent ( $ mail , $ title , $ id , $ startDateTime , $ endDateTime ) { // Googleクライアントの初期化 $ client = new \Google_Client () ; $ client -> setClientId ( self :: CLIENT_ID ) ; $ client -> setClientSecret ( self :: CLIENT_SECRET ) ; $ client -> setRedirectUri ( self :: REDIRECT_URI ) ; $ client -> addScope ( self :: SCOPES ) ; // 保存されているトークンの読み込み $ tokenPath = $ this -> getTokenPath ( $ mail ) ; $ accessToken = file_get_contents ( $ tokenPath ) ; $ client -> setAccessToken ( $ accessToken ) ; // Googleカレンダーにイベントを登録 $ service = new \Google_Service_Calendar ( $ client ) ; $ url = self :: MIITEL_URL . "/app/calls/ { $ id } " ; $ event = new \Google_Service_Calendar_Event ([ 'summary' => $ title , 'description' => $ url , 'start' => [ 'dateTime' => $ startDateTime ] , 'end' => [ 'dateTime' => $ endDateTime ] ]) ; $ createdEvent = $ service -> events -> insert ( 'primary' , $ event ) ; return $ createdEvent ; } } おわりに いかがでしたでしょうか。 OutgoingWebhookを使えば、他のサービスとの連携ができ、様々な応用が可能になります。 例えばAsanaとの連携によるタスク管理の実現も可能です。 MiiTel Outgoing Webhook の使い方: タスク管理ツールとの連携サンプル をご覧ください。 MiiTelをより効果的に、より深く活用したい企業様は、OutgoingWebhookの機能をぜひご活用ください。
アバター
こんにちは。PBXチームの山崎です。 振り返ると前回のブログからちょうど1年経ってしまいました。来年はブログのアウトプットも増やしていきたいですね。 さて早速ですが、今回のブログの概要です。 死活監視の一環で、STUNというバイナリベースのプロトコルのクライアントを実装してみた Python3.10で入ったパターンマッチングがバイナリプロトコルの解析に便利だった 前半でSTUNを軽く触って動作を確認し、後半でPythonを使って実装してみます。 目次 目次 STUNについて STUN のパケット構造 やってみよう Pythonのパターンマッチングについて バイナリデータに対するパターンマッチング PythonでSTUNやってみる まとめ STUNについて STUNは主に以下の特徴を持つプロトコルです。 WebRTCでよく使われる、NAT越しに通信するためのプロトコル(の一部) 相手から見た自分のグローバルアドレスなどを知ることができる RFC 8489 バイナリベース STUN のパケット構造 プロトコルの理解には、実際にリクエスト・レスポンスを観察してみると捗ります。 実際にパケットを送信するために、必要な情報を集めていきましょう。 RFC 8489の "2. Overview of Operation” を読むと、まずはクライアントからBinding Requestを送りたまえ、と書かれています。 Binding Requestとは何ぞ?と読み進めると、5章にその構造が定義されています。 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0 0| STUN Message Type | Message Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Magic Cookie | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | Transaction ID (96 bits) | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Figure 2: Format of STUN Message Header 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Type | Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Value (variable) .... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Figure 4: Format of STUN Attributes 20バイト(固定長)のヘッダの後ろに、0個以上のアトリビュートが続く構成です。 ヘッダの各フィールドの定義を以下に抜粋します STUN Message Type: Binding Requestは 0x0001、Responseは 0x0101 Message Length: ヘッダを除いた STUNメッセージの長さ Magic Cookie: 0x2112_A442 (固定値) Transaction ID: 12bytes の乱数 そしてアトリビュートはタイプに長さと(タイプごとに定義される)データが続く、よくある構成ですね。 アトリビュートタイプが取りうる値は、18.3. STUN Attributes Registry に定義されています。 今回使う値を以下に抜粋します。 0x0020: XOR-MAPPED-ADDRESS やってみよう なんとなく構造がわかったので、試しにリクエストを送ってみましょう。GoogleがSTUNサーバーを公開してくれているので、ありがたく利用させていただきます。 # リクエストデータは先頭から... # 00 01: Binding Request # 00 00: Length # 21 12 a4 42: Magic Cookie # 00 01 ... 11: Transaction ID (乱数作るの面倒なので適当に) # RFCにはリクエストにSOFTWARE Attributeを含めたまえ (SHOULD) とあるけど、面倒なので省略 bash$ printf ' \x00\x01\x00\x00\x21\x12\xa4\x42\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11 ' | \ socat - UDP:stun.l.google.com:19302 | hexdump -C 00000000 01 01 00 0c 21 12 a4 42 00 01 02 03 04 05 06 07 |....!..B........| 00000010 08 09 10 11 00 20 00 08 00 01 99 a3 17 ba 65 4b |..... ........eK| 00000020 手抜きをしてSOFTWARE Attributeを省略しましたが、ちゃんとレスポンスを返してくれました。読んでみましょう。先頭から... ヘッダ部 01 01 : Binding Response 00 0c : 長さは12 (Big Endian) 21 12 a4 42 : Magic Cookie 00 01 ... 11 : Transaction ID アトリビュート部 00 20 : XOR-MAPPED-ADDRESS 00 08 : 長さは8 00 01 99 a3 17 ba 65 4b : アトリビュートの中身 XOR-MAPPED-ADDRESS なるものとして 00 01 99 a3 17 ba 65 4b というデータが取得できました。 そろそろゴールが見えてきそうですね。心躍らせながらXOR-MAPPED-ADDRESSの仕様を確認して読み解いてみましょう。 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0 0 0 0 0 0 0 0| Family | X-Port | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | X-Address (Variable) +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Figure 6: Format of XOR-MAPPED-ADDRE SS Attribute 今回は 99 a3 が(サーバから見た)ポート番号、その後ろ 17 ba 65 4b が(サーバから見た)IP アドレスになります。 どちらもMagic CookieとXORをとった値とあるので戻してみましょう。XORはもう一回かけると元の値に戻りますね。 bash$ echo $((0x17 ^ 0x21)).$(( 0xba ^ 0x12 )).$(( 0x65 ^ 0xa4)).$(( 0x4b ^ 0x42 )) 54.168.193.9 私のIPアドレスは 54.168.193.9 のようです。 答え合わせをしてみましょう。 bash$ curl httpbin.org/ip # 自分の IP アドレスを返してくれるWebAPI { " origin " : " 54.168.193.9 " } 正解でした! Pythonのパターンマッチングについて ここからはもう一つの主題である、パターンマッチングについてみていきます。 PythonのパターンマッチングはPEP 622で定義され、Python3.10で実装されました。 例をPEP 622から転載します。if elseよりもすっきりと表現できていますね。 match response.status: case 200 : do_something(response.data) # OK case 301 | 302 : retry(response.location) # Redirect case 401 : retry(auth=get_credentials()) # Login first case 426 : sleep(DELAY) # Server is swamped, try after a bit retry() case _: raise RequestError( "we couldn't get the data" ) バイナリデータに対するパターンマッチング Pythonでバイナリデータを扱う場合はbytes型がよく登場します。 ところが、パターンマッチングではbytes型を扱うことができません。 PEP 622から引用: To match a sequence pattern the subject must be an instance of collections.abc.Sequence, and it cannot be any kind of string (str, bytes, bytearray). It cannot be an iterator. collections.abc.Sequenceであれとのことなので、組み込み関数の memoryview() を使います。 memoryview() を使うと、コピーせずにシーケンスとして扱うことができます。 例として、「先頭2bytesがメッセージタイプ、その後ろ2bytesが長さ、その後ろにボディ」というデータを考えます。 これは以下のようにパースできます。 msg = b ' \x01\x02 ' + b ' \x00\x02 ' + b ' \x02\x03 ' match memoryview (msg): # "_" で読み飛ばすことができる # *data のように書くと、残り全てを受け入れる case [ 0x01 , 0x01 , _, _, *data]: print (f "type=Hello data={data}" ) # if を続けてバリデーションを書くこともできる # 2*len みたいに、長さを指定することはできない case [ 0x01 , 0x02 , len0, len1, *data] if len (data) == (len0 << 8 ) + len1: print (f "type=NewTransaction data={data}" ) case _: print ( "invalid message" ) # => type=NewTransaction data=[2, 3] サンプルデータ (msg) の先頭が 0x0102 なので、2つ目のcaseにマッチしています。 これをif文で書いたものと比較してみます。match文ではデータ構造が表現されていて、見通しがいいですね。 # 2つ目の case です if msg[: 2 ] == b ' \x01\x02 ' and len (msg[ 4 :]) == (msg[ 2 ] << 8 ) + msg[ 3 ] data = msg[ 4 :] print (f "type=NewTransaction data={data}" ) PythonでSTUNやってみる これで必要なパーツが揃いました。組み上げていきましょう。 まず、リクエストを送信してレスポンスを受け取る部分です。 def stun_binding_request_udp (sock: socket.socket, hostname: str , port: int ) \ -> tuple [ bytes , bytes ]: message_type = b ' \x00\x01 ' length = b ' \x00\x00 ' magic = bytes (MAGIC_COOKIE) transaction_id = RAND_bytes( 12 ) req = message_type + length + magic + transaction_id sock.sendto(req, (hostname, port)) res = sock.recv( 2048 ) return res, transaction_id 実際に作る際はTransport classみたいなのを作ってレイヤを分けるとか色々考えると思いますが、今回はサンプルなのでベタっと書いていきます。 でもってこのレスポンスの解析をパターンマッチングを使って書いてみます def stun_parse_response (message: bytes , transaction_id: list [ int ]) -> None : header = message[: 20 ] attr_data = message[ 20 :] # ヘッダの情報を元に、レスポンスが壊れていないかチェック match memoryview (header): case [ 0x01 , 0x01 , length0, length1, 0x21 , 0x12 , 0xA4 , 0x42 , *_tid] \ if _tid == transaction_id and \ len (attr_data) == (length0 << 8 ) + length1: logger.debug( "valid stun response" ) case _: logger.warning(f "invalid response: {message}" ) return # XOR-MAPPED-ADDRESS Attribute を抽出 # TODO : ~~面倒~~サンプルなので先頭に XOR-MAPPED-ADDRESS があると仮定 match memoryview (attr_data): case [ 0x00 , 0x20 , length0, length1, *value]: length = (length0 << 8 ) + length1 body = value[ 0 :length] logger.info(f "type: XOR-MAPPED-ADDRESS" ) _stun_parse_xor_mapped_address(value) case [type0, type1, *_]: logger.warning( f "unknown attribute: type=0x{type0:02X}{type1:02X}" ) そして最後に _stun_parse_xor_mapped_address() を実装したら完成です def _stun_parse_xor_mapped_address (attribute: list [ int ]) -> tuple [ bytes , int ]: match attribute: case [ 0x00 , 0x01 , xport0, xport1, *xaddress] if len (xaddress) == 4 : xport = (xport0 << 8 ) + xport1 port = xport ^ int .from_bytes( MAGIC_COOKIE[: 2 ], byteorder= "big" , signed= False ) address: str = "." .join( [ str (x ^ y) for x, y in zip (xaddress, MAGIC_COOKIE)] ) logger.info(f "global address: {address}:{port}" ) case _: logger.warning(f "unknown data: {attribute}" ) 足りない部分を補って動かしてみましょう。 import socket from logging import getLogger, StreamHandler, INFO, Formatter from ssl import RAND_bytes logger = getLogger(__name__) handler = StreamHandler() formatter = Formatter( "%(filename)s:%(lineno)s - %(levelname)s - %(message)s" ) logger.setLevel(INFO) handler.setFormatter(formatter) logger.addHandler(handler) MAGIC_COOKIE = ( 0x21 , 0x12 , 0xA4 , 0x42 ) # snip. def main (): stun_server = "stun.l.google.com" stun_port = 19302 af = socket.AF_INET with socket.socket(af, socket.SOCK_DGRAM) as sock: sock.settimeout( 5 ) response, transaction_id = stun_binding_request_udp( sock, stun_server, stun_port ) logger.info(f "local address: {sock.getsockname()}" ) stun_parse_response(response, list (transaction_id)) main() bash$ python3. 10 ~/stun-check0.py stun-check0.py:79 - INFO - local address: ( ' 0.0.0.0 ' , 53603 ) stun-check0.py:47 - INFO - type: XOR-MAPPED-ADDRESS stun-check0.py:26 - INFO - global address: 54 . 168 . 193 .9:53603 よさそうですね。 まとめ 実際にプロトコルを実装することで、普段漫然と使っていたSTUNの理解が深まりました。 また、パターンマッチングを使うことで、データの構造を表現し、if elseを見通しよく記述できました。積極的に使っていきたい機能ですね。
アバター
この記事は RevComm Advent Calendar 2023 7日目の記事です。 RevComm Research の加藤 集平です。音声合成を中心に、音声信号処理の研究開発に携わっています。 昨今、生成AIを利用したフェイク動画(偽動画)が世の中を騒がせています。先日も、岸田首相のフェイク動画がSNSで話題となりました。この動画は内容が明らかに偽物であったこと、動画像が稚拙であったこと、合成音声の質がさほど高くなかったことなどから、視聴者が比較的簡単に偽物と見抜けるものでした。しかし、昨今の技術革新のスピードからすると、近い将来、簡単には偽物と見抜けない動画が出回ることは十分に考えられます。 このような状況に対して現在、国際的な法規制が検討されています。一方で、技術的な対抗手段の研究開発も目覚ましい発展を遂げています。本記事では、フェイク動画を構成する要素のうち、 フェイク音声を検出する技術 の現在について調査しました。 フェイク音声はどのようにして作られるのか フェイク音声に求められる条件 条件1: 声色・声の調子が本人に似ていること 条件2: 任意の内容を話すことができること、あるいは本物の音声の一部を改竄できること 音声合成 音声変換(声質変換) 最新の技術でフェイク音声はどの程度検出できるのか 最新の技術ではどのようにしてフェイク音声を見抜いているのか 検出処理の流れ 評価実験 これからのフェイク音声検出 まとめ フェイク音声はどのようにして作られるのか 本題の検出技術の話題に入る前に、そもそもフェイク音声はどのようにして作られるのかについて説明します。なお、筆者自身は悪意を持ってフェイク音声を作ったことがなく、以下はあくまでフェイク音声検出の専門家が現時点で想定している事柄にとどまることにご注意ください。 フェイク音声に求められる条件 悪意を持ってフェイク音声を作ろうとした場合、フェイク音声に求められる条件とは何でしょうか。筆者の知る限り確立された見解はありませんが、筆者は以下のように考えます。 条件1: 声色・声の調子が本人に似ていること フェイク音声の目的が 特定の個人そっくりの声で偽の内容を話させること だとすれば、声色や声の調子が似ていることは必須の条件でしょう。少なくとも、人間の耳で本物の音声かどうかの判別が難しければ、悪意を持った作成者の意図に合致するでしょう。 条件2: 任意の内容を話すことができること、あるいは本物の音声の一部を改竄できること 任意の内容を話させることができれば、悪意を持った作成者に都合のよい、偽の内容を話させることができます。本物の音声の一部を改竄することでも、悪意を持った作成者の目的を達成できるかもしれません。 音声合成 上の2つの条件を満たすものの一つに、音声合成があります。音声合成のうち広く使われているのはテキスト音声合成 (text-to-speech; TTS) で、テキストを入力すると、テキストの内容を読み上げた音声が出力されます。テキスト音声合成は、電話の自動応答・公共交通機関の自動アナウンス・スマートスピーカーなど、すでに日常生活のさまざまな場面で利用されています。 テキスト音声合成はその半世紀以上にわたる歴史の中で、さまざまな手法が提案されてきました。中でもフェイク音声の文脈で重要なのは、深層学習(ディープラーニング)に基づく手法です。深層学習に基づく手法は従来の手法よりもより自然な声を合成することができます。音声合成が人間と同等の自然性を持つこと(=あたかも人間が話しているように聞こえる)については、2017年に発表された Tacotron 2 という手法により、限られた条件下ではあるもののすでに達成されています。さらに、2023年には、目標話者(声を模倣したい話者)の音声をわずか3秒だけ用意すれば、その話者の声に類似した音声合成が可能となる手法も発表されています ( VALL-E )。さらに、テキスト情報を手がかりに、音声の一部を編集できるような手法も提案されています ( SpeechPainter )。 研究者は決して悪用するために研究をしているわけではありません。しかしながら、最新の手法はその自然性の高さから悪用が懸念されており、たとえばVALL-Eには誰でも試せるような公式のデモシステムや公式実装は存在しません。一方で、 VALL-Eの論文は公開されている ことから、再現実装や劣化版訓練済モデル *1 は存在します。 音声変換(声質変換) もう一つの方法に、音声変換(声質変換, voice conversion)があります。音声変換は多くの場合、ある話者の音声を入力とし、それを別の話者に類似した音声に変換したものを出力とします *2 。音声変換の手法も深層学習の応用でめざましく発展しており、VTuberなどの分野で、すでに広く利用されています。 悪用の懸念としては、SNSなどに投稿された声(特に、有名人の声など)を訓練データとして音声変換モデルを訓練し、その人の声に類似した音声を出力できるようにして悪用することが想定されています。 最新の技術でフェイク音声はどの程度検出できるのか 結論から言うと、深層学習に基づく手法で作成されたフェイク音声のデータセット(後述)に対して人間の音声かフェイク音声かを判別するタスクにおいて、記事執筆時点(2023年12月時点)でおよそ3%〜4%の等価誤り率 (equal error rate; EER) が達成されています(論文: Automatic Speaker Verification Spoofing and Deepfake Detection Using wav2vec 2.0 and Data Augmentation )。このデータセットは ASVspoof 2021 という自動話者認証・なりすまし攻撃への対抗手段のチャレンジ(競技会)で提供されたものです。ASVspoof 2021の参加チームのうち最も優れた手法の性能はEER = 15%程度でしたから、わずか2年で劇的に性能が向上していることが分かります。 なお、同じデータセットに対して人間がどの程度フェイク音声を見抜けるかのデータは見つけることができませんでした。ただし、同じく深層学習に基づく手法で作成された別のデータセットに対して、全体的な正解率 (overall accuracy) が70%程度(つまり30%程度は間違えた)であるという研究があります。データセットが異なるので直接の比較はできませんが、最新の技術では人間が判別できないようなフェイク音声を見抜ける可能性があります。 最新の技術ではどのようにしてフェイク音声を見抜いているのか ここでは、上述した Automatic Speaker Verification Spoofing and Deepfake Detection Using wav2vec 2.0 and Data Augmentation という論文で提案されている、およそ3%〜4%のEERが達成されている手法を紹介します。 検出処理の流れ 検出処理の流れ システムに入力された音声は、 wav2vec 2.0モデル *3 で変換されたのち、RawNet2ベースのエンコーダーに通され、 の特徴表現となります(Cはチャネル数、Fはスペクトルのビン数、Tは時間方向のフレーム数)。 エンコーダーから出力された埋め込み表現は、 2次元のself-attention (SA) から得られるattention mapを元に 、周波数方向に着目した特徴表現 ( f ) と、時間方向に着目した特徴表現 ( t ) の2つに変換されます。 そして、fとtはgraph attention networkというグラフ構造で表現されるデータを処理できるネットワークで処理され、最終的に人間の音声か (real) フェイク音声か (fake) が出力されます。 なお、本論文ではwav2vec 2.0と2次元のself-attentionを用いていますが、本論文のベースとなっている AASIST というモデルでは、それぞれsinc layerとmax poolingを用いています。さらに、本論文では RawBoost という手法を使って訓練データの拡張 (data augmentation; DA) を行っています。 評価実験 ASVspoof 2021で使用されたデータセットのうち、LA (logical access) データベースがモデルの訓練に用いられました。評価には、LAデータベースの評価セットのほか、DF (deep fake) データベースの一部も用いられました。 ここでは、フェイク音声を想定したDFデータベースによる評価結果を紹介します(EERのカッコ内は異なる3個のrandom seedによる結果の平均で、カッコ外は最もよい結果)。 評価結果 ( source ) まず、sinc-layerに代えてwav2vec 2.0を導入することにより、大幅にEERが改善しています。これは、wav2vec 2.0のような大規模な事前学習モデルを用いることにより、限られたデータセットだけで(特徴量抽出を含めた)モデル全体の訓練を行うよりも汎化性能がよいためだと推察されています。また、2次元のself-attention (SA) およびdata augmentation (DA) もEERの改善に寄与しています。 これからのフェイク音声検出 フェイク音声検出に関連するイベントとして、 ASVspoof という自動話者認証・なりすまし攻撃への対抗手段のチャレンジ(競技会)が2015年より隔年で開催されています。本記事の冒頭で紹介したように、深層学習の発展により人間が見抜けないようなフェイク音声が登場するリスクはますます高まっています。一方で、フェイク音声を検出する技術もASVspoofのコミュニティを中心に劇的な発展を遂げています。 部分的に改竄された音声 (partially spoofed audio) の検出 など、より難しいタスクの研究も進んでいます。また、音楽生成の分野ではありますが、 AIによって生成された音楽に透かしを埋め込む手法 など、生成AI側からの提案もなされています。このような手法は、AIによって生成された音楽や音声の判別をより簡単にするほか、作成者の意図に反した改竄を防ぐことにもつながると考えられます。 まとめ 本記事では、フェイク音声の検出技術の現在について簡単な解説を行いました。RevCommでフェイク音声に関連する機能は今のところ提供していませんが、筆者は音声合成の研究開発をする者としてフェイク音声のリスクに対して無関係ではありません。法規制・技術的対抗手段について、これからも関心を寄せていきたいと思います。 *1 : VALL-Eの論文ではおよそ6万時間の訓練データを使用していますが、いくつかある再現実装ではおよそ600時間の訓練データが使用されているようです。 *2 : より一般には、音声を入力として、何らかの変換を施した音声を出力とします。たとえば、構音障害(発音器官やその動きに問題があり発音がうまくできない障害)の人の音声を、健常者のような音声に変換する研究もあります。 *3 : 大規模な事前学習モデルであるwav2vec 2.0 XLS-R(人間の音声だけで訓練されている)を、フェイク音声を含む訓練データでファインチューニングしたモデルが使用されています。
アバター
この記事は RevComm Advent Calendar 2023 6日目の記事です。 はじめに RevCommのバックエンドエンジニアの中島です。 前回は PyCon APAC 2023への参加レポート を寄稿しました。今回もイベント参加のレポートになります。 今回は 2023年11月25日(土) に開催された ISUCON13 に、弊社内でフロントエンドエンジニア1名+バックエンドエンジニア2名、計3名のチームで参加しました。 isucon.net 私はISUCONには過去数回参加したことがありますが他の2名は参加なしという経験値で、結果としては最終スコア 7,749点、参加チーム数 694組中 314位でした。 なんとも言い難い順位ですが、参加レポートという形で忘備録として未来の参加者に知見を残せればと思います。 キックオフ 中島は8月入社ですが、8月下旬に社内のエンジニアが全員入っているSlackチャンネルで下記を投稿しました。 このようにRevCommではチームや組織を超えたコミュニケーションが活発で、社内Slackを通して日々情報交換や交流がされています。 ISUCONの参加登録が始まる前に何気なく投稿したものだったのですが、 エンジニアとして活躍する美馬さん、大谷さんにリアクションいただきました。 例年参加希望者が参加枠を大幅に上回っており、ISUCONの最も高いハードルは参加登録とも言われます。 メンバーの美馬さんがその恒例の連打バトルに見事に勝ち切ってくれましたので、参加が決定し、私たち3名は正式にチームとして発足することになりました。 早速それぞれの持っている情報を共有したり役割やチーム名を決めたりと、当日までに必要な準備が始まりました。 このとき、私たちが決めた目標は以下の4つになります。 failureしない 計測する 計測を元に一番大きいボトルネックを潰す 本番までに社内ISUCONやりたい このうち、4. の「社内ISUCON」は社内からのみアクセスできる環境構築の準備に手間取ってしまい、本番に向けた練習時間を確保するために計画が頓挫し、開催できませんでした。 しかし、今でも興味があり私の悲願なのでいつかやりたいです。 当日まで まずは「達人が教えるwebパフォーマンスチューニング」を全員各自で読むことにしました。 多くの知見が詰め込まれている有名な本で、基本的なツールの使い方や典型的なチューニング方法や計測の重要性を学びました。 次に公式の情報や勉強会の情報、過去問の改善方法まとめなどの、役に立ちそうな記事についてそれぞれが情報共有する打ち合わせを数回行いました。 このとき、ISUCONの練習環境を社内で利用しているAWSアカウントに準備したりと、ありがたく社内のリソースも利用させていただきました。 日々忙しくチーム揃って手を動かした練習というのは本番一週間前から2時間ずつ3回に分けて行ないました。 練習の内容としては当日を意識した素振りを意識しており、「Git・SSHの設定」「alpやpt-query-digestのインストールや利用」「DBインデックスの活用」「EC2の複数台構成」などを行いました。 利用言語はGolangの予定でしたので、下記のサイトを参考にNew Relic APM Agentを入れて今回のISUCONのゴールドスポンサーでもあるNew Relicの威力も確認できました。 newrelic.com New Relicは非常に便利でこれさえあればアプリケーションのほとんどの計測ができてしまうわけですが、 チーム内では alp や pt-query-digest といったツールと併用することを決めました。 本番当日 ISUCON 13は 10:00-18:00 で競技が行われました。 特に大きな障害などはなくスケジュール通りに進行が行われ、運営の努力を感じました。 参加者が快適に競技に集中できる環境を用意いただけていたと思います。 実際の時間や作業内容は前後していると思いますが、覚えている限りの当日のスケジュールを書いてみます。 9:00 - 9:30 起床・オンラインで集合 10:00 - 11:00 RepositoryやGit・SSHの準備。最初のベンチマーク取得。アプリケーションのドキュメントの確認。 11:00 - 13:00 alpとNewRelicの計測結果から、icon周りの改善を試みる。「304 Not Modified」の実装をした。テーブル構造やインデックスの有無を把握し、データベース周りの理解を進める。 13:00 - 14:00 休憩 14:00 - 14:30 改めてコードを読んだり改善策を探す。どこから修正すべきか議論しながら、できることからやっていくことに。 14:30 - 17:00 DBのスロークエリにインデックスを貼り始める。中間テーブルの削除を検討したり、DNS周りの最適化ができないか考えたり試したり。スコアがじわじわと伸びていく。 17:00 ランキングが隠れる。己との勝負が始まる。 17:00 - 18:00 この時追加でインデックス貼ったりログを切ったりしながら、少しずつスコアを上げていく。再起動後にベンチを回して通過したところでタイムアップとなる。 あとでポータルを確認してみると 16:53 の時点で 5,576 点だったようで、最後の1時間で2,000点以上スコアを更新していることになります。 ISCUON 13 Portal 最後畳みかけるように改善を行いましたが、やりたいことはまだまだあったので、本当に時間が足りなかったです。 振り返り 初回参加のメンバーが多いので、来年再挑戦できれば多くの点で改善できそうだなと感じました。 今回ざっくりと役割分担はあるものの、ほとんどの改善をチーム全員で確認をしながら行いました。 そのため、もっと手分けし並列に進めるようにすると上手に時間を活用できると思いました。 Miroで振り返り 4つの目標のうち以下の3つを達成できたので、大方ヨシ!とします。 Failureしない 計測する 計測を元に一番大きいボトルネックを潰す 本番までに社内ISUCONやりたい これらの目標を達成するために、私たちのチームでは競技終了直前に再起動テストを実施したり、コマンドラインツールだけでなく New Relic を活用した計測に力を入れました。 まとめ 今回は ISUCON 13 に社内でメンバーを組んで参加したというレポートになりました。 ISUCONというコンペに挑戦する場合でも弊社の社員は非常に協力的で、特にネットワークチームには社内環境を準備する際のアドバイスなどもいただけました。 スコアは物足りない部分がありますが、来年はもっと高得点が取れるように自身のスキルを磨きたいです。 最後になりますが、ISUCON 13の作問に携わって下さった方、運営の皆様、スポンサーの皆様ありがとうございました!
アバター
こんにちは、小島です。この記事はRevComm Advent Calendar 2023 12/5 分の記事です。 qiita.com 2023年のRevCommに起きた大きな変化のひとつは、英語話者(日本語の読み書きや会話を前提としない)のエンジニア採用を始めたことです。 昨年までは日本語能力の採用要件がありましたが、今年からその要件なしで採用するようになりました。そのため、日本語を母語とする僕もチームメンバーに英語話者が増えていくにつれて適応することになりました。 僕自身は今までまったく英語学習に興味がなく、英語で仕事をすることになるなどとは思ってもみなかったです。そんな人が実際に業務をやってみてどう感じているかについて書こうと思います。 なお、この記事ではRevCommの業務での英語の使われ方や、自分視点での英語を使った業務を進めることへの感想を書きます。英語学習のTipsといった話はこの記事では書きません。 まえおき 2023年12月現在、日本語が公用語の会社に一部英語話者もいるという状態の組織です すべてのエンジニアに英語の読み書き・会話が求められているわけではありません 言語のスキルも含めてチームを編成をするよう努力をしています 僕が所属しているVideoチーム(MiiTel Meetings開発チーム)を前提にした記事となっています 社内の日英話者混合の別チームで異なる体制をとっているチームもあります 筆者の英語スキル 前提として筆者の英語スキルを書いておきます。 正式に受験したことはないのですが、TOEICの問題集を買って模試をやってみたところだいたい600点ちょっとくらいでした。つまり別に良くもないし、悪くもない、普通といったところです。 受けたのは英語学習をちゃんと始める前(今年の5月ごろ)のスコアですが、現時点でもスコアとしてはそんなものではないかなと思います。 自分の自認としては、 読み書きは遅いけどできる、リスニング、スピーキングはあんまりできない コードレビューで一言コメントとかは英語学習をちゃんとする以前からできてた 長文を書くのはだいぶ難しい 会話の経験はほぼないので、議論をするみたいなことは基本できない ただ何言っているのかの大意はわかる。賛成か反対かとか という感じです。イメージとしては、受験勉強をちゃんとやった大卒社会人が持っている感じの英語力は最初から持っていた、と想像してもらえれば。 今年起きた変化 僕の所属するチームで今年起きたことを簡単に書いておきます。 2022年まで 2023年12月現在 ミーティング 日本語のみ 基本英語に。ただ日本語を話してもOK Slack 日本語のみ 特定のチャンネルでの会話は英語に。チーム同士の会話は日本語話者どうしでも英語で行う機会が増えた GitHubのPRタイトル 特に指定なし 英語のみ チーム内のドキュメント 日本語のみ 翻訳して日英対応を適宜実施。新規ドキュメントは英語のみのものもある。 これらがある日を境に一斉に起きたわけではないのですが、徐々に変わっていき現在はこのような形になりました。もちろん日本語の読み書きも自然と行いますが、開発に関することで日本語を書くことはだいぶ減った印象です。 英語で仕事をして思ったこと 純粋に学習に時間がかかる シンプルに英語学習には時間がかかることがわかりました。 AWSのIAMとかで権限設定しているJSONを読み解けるようになるのって、そんなに根詰めて勉強しなくても1, 2ヶ月あれば自ずと意味がわかってくると思います(諸説あります)。しかし、英語は3ヶ月与えられても目に見える成果を出すのは結構難しいです。 自然言語って難しいですね(遠い目) 主体的にならない限り、仕事中にスキルはあがらない 当たり前なんですが、仕事中は仕事を進めるのが重要です。英語の学習になるからと回り道をさせてもらうなんてことはありません。 ということで、意思疎通が難しければ通訳(僕のチームの場合はPjMがバイリンガル)をしてもらったり、あとでSlackで聞き直したりとかで仕事は十分に前に進みます。別に会話の機会とかも増やそうとしなければ増えません。 一方で業務外で勉強した表現を仕事で使うとか、業務外でインプットした表現が実際に同僚の口から出てくる、といったアウトプットの補助/インプットの強化という観点でスキルを上げる機会を作ることはできると思いました。 リモートでの会議がよりむずかしく感じる 日本語でもビデオ会議は対面での会議とは異なるクセがあると想うのですが、英語だとそれがさらに強く出る気がしています。 これは英語(僕にとっての外国語)のせいなのか、ビデオ会議のせいなのか、はたまたその両方同時にあるからなのかは正直わからないです。 なんとなく英語話者の傾向として、一度話し始めるとこちらが止めない限り止まらないことが多いように思います *1 。そこで一度、相手の話を止めて深掘りするとか、自分のわからないところを伝えて詳細を話してもらうとかいうのが必要だと思うのですが、思っているだけでなかなか行動に移すことができません。 仕事の話をしてないからかもしれませんが、飲み会とか対面で会った時のほうが英語を話しやすい感じがします。 テクノロジーのサポート(Google Meetの自動字幕など)はなにもないはずなのに、なにもない方が外国語を喋れるというのは不思議なものですね。 チームに新たな風が吹く 課題ばかり挙げてしまったのでよいところも書くと、チームの中に新たな視点がもたらされるのでそこはとてもエキサイティングです。 例えば、あるエンジニアがフロントエンドのアーキテクチャーに抜本的な指摘をしたりとか、ブランチ戦略の改善を考えないかと提案してもらったりとか。普段なかなか意識しない、議題にあがらないことを議論のテーブルに挙げてくれる人がいて助かっています。 必ずしも英語話者じゃないとできない指摘ではないのですが、持っている知見や過去開発していたバックグラウンドが日本人チームで日本語を使って開発してきた僕とは明白に違うので、意見をあげてくれてその背景を解説してくれるのはとても勉強になります。 具体的にはFeature FlagやDesign Doc、Trunk ベース開発について、教えてもらったりしました。 相手も外国語学習に苦労してる 弊社で採用している英語話者の場合、英語話者といっても母語が英語とは限りません。たとえば、母語はスペイン語やインドの言語という人が第二外国語として英語を学習し英語を話している、という人の方が多いです。 そんなわけで、外国語学習って大変だよねという意見には多くの人が共感してくれます。 弊社のSlackには #club-language-exchange というチャンネルがあり、日本語についての質問や英語についての質問、英語で雑談を振るなど自由に使われています。そういう場に、英語話者の人がさっと現れてニュアンスの違いを説明してくれたり、逆に日本語話者の僕らも日本語の質問に答えたりします。 基本的にほぼ全員がなんらかの外国語を勉強したことがあるので、質問にはみんなとても優しく答えてくれます。 RevCommに入社してくる英語話者の方は来日が前提になっているのもあり、日本に関心が高い人が多いです。そういう方は日本語の学習も熱心だったりするので、一緒に高め合おうという会話をしたりもします。 終わりに この記事ではRevCommの英語話者エンジニアとの仕事について書きました。 もちろん課題や難しいところもありつつも、複数の言語の交流は複数の文化の交流で楽しい側面もたくさんあります。メキシコのお祭りの話を聞いたり、スイスの列車の話を聞いたりしながら業務ができるのは楽しいです。 異文化交流に興味がある人がこの記事を読んで、日本にも面白い環境があるんだなと思っていただければ幸いです。 *1 : ファシリテーターのPMは、何を言ったかを全部覚えられないのでたまにノートとったりしているそうです。
アバター
この記事は RevComm Advent Calendar 2023 4日目の記事です。 弊社は Notion を使っています。 Notion は Mermaid が使えて最高なのですが、 flowchart の theme がアルファベットに若干弱い *1 です。というわけで theme をいじって解決します。 これを書くだけです。 %%{init:{'themeCSS':'line-height:1.1rem;'}}%% *1 : この問題はいつか直るでしょう
アバター
この記事は RevComm Advent Calendar 2023 1日目の記事です。 RevCommでバックエンド開発をしている小門 照太です。 MiiTelにおける認証基盤を担うマイクロサービス(MiiTel Account)に携わっています。 MiiTelでは外部のIDプロバイダー(IdP)と連携したシングルサインオン(SSO)によるログインに対応しています。 この記事ではMiiTelのお客様がSSOログインを利用する際に必要となる手順とAccountチームの運用について紹介します。 SSO利用までのステップ 現在MiiTelではOpen ID Connect(OIDC)という認証規格によるSSOに対応しています。 システム基盤にはAWSを使っており、認証機能のバックエンドとしてAmazon Cognitoを採用しています。 お客様がSSOを利用開始するまでに以下の手順があります。 IdP上でOAuthアプリケーションの作成(お客様が実施) Cognitoに1. の設定情報を登録 MiiTelで発行した認可リダイレクトURLをお客様に伝達&IdPに登録 OIDCに対応したIdPとして有名なものにはMicrosoft Entra ID(旧 Azure AD)やGoogle Workspaceがあります。 同じAccountチームの同僚が以前OIDC SSOに関する解説の記事を書いていますので、ぜひご覧ください。 Cognito user pool で OpenID Connect を利用した外部 ID Provider によるサインインを実現する - RevComm Tech Blog 上記の手順においてRevCommとしては2. の作業が必要になります。 サービスの構成管理 MiiTel AccountのWebサービスは社内において独立したマイクロサービスであり、AWS上で構築しています。 上述したCogitoをはじめECS/Fargate、ALBなどのインフラリソース一式は基本的にIaCで構成管理しています。IaCにはTerraformを用いています。 インフラの構成変更、つまりAWSサービスの設定変更やリソース追加/変更/削除などはTerraformコードを変更して適用する運用としています。 Terraformコードを修正するPull Requestを作成し、マージされると設定変更が自動適用されるCI/CDの仕組みを整備しています(詳しくは後述します)。 AccountチームにおけるSSOセットアップ MiiTelのお客様に対するSSO利用開始のためにはCognitoの構成変更が必要となるため、上述したTerraformを用いた構成変更による運用をしています。 OIDC IdPの追加 お客様のIdP設定情報(前述の手順2.)はCognitoユーザープールにおける「アイデンティティプロバイダー」として登録します。 参考 - ユーザープールへの OIDC ID プロバイダーの追加 - Amazon Cognito Terraformでは aws_cognito_identity_provider リソースです。 aws_cognito_identity_provider | Resources | hashicorp/aws | Terraform | Terraform Registry resource "aws_cognito_identity_provider" "azure_customer_A" { user_pool_id = "ap-northeast-1_XXXX" provider_name = "for-Customer-A" provider_type = "OIDC" ... provider_details = { client_id = "1234aaaa-bbbb-cccc-dddd-eeeeeeeeeeee" client_secret = "dummy" ... } } 上述したステップ1. でお客様が作成したOAuthアプリケーションのパラメーターを provider_details に設定します。なお client_secret は秘匿情報と見なし、Terraformコードではダミーの値を入れるようにしています。 変更の適用 Terraformコードを変更したらPull Requestを作成します。 CI/CDの自動化として、GitHub Actionsを利用して構成変更のレビューおよび適用できる仕組みを整備しています。 参考 - Automate Terraform with GitHub Actions Pull Requestを作成するとCIのジョブが起動してlint( terraform fmt )、dry run( terraform plan )などの実行結果がコメントに追記されます。 GitHub Pull Requestのキャプチャ Show Plan で terraform plan の出力結果を確認できます。 ... # module.~~~~~~~~~~~~~~~~~ will be created + resource "aws_cognito_identity_provider" "oidc_google" { + attribute_mapping = { + "email" = "email" + "given_name" = "given_name" + "username" = "sub" } + id = (known after apply) + provider_name = "for-Customer-A" + provider_type = "OIDC" + user_pool_id = "ap-northeast-1_xxxx" ... } ... Plan: 1 to add, 1 to change, 0 to destroy. 変更内容に問題ないことを確認してPull Requestのレビューを受けた後、マージすることでリリース( terraform apply )も自動実行されます。 リリースの実行確認後、client_secretをマネジメントコンソールから手動修正、そして前述のステップ3.「MiiTelで発行した認可リダイレクトURLをお客様に伝達&IdPに登録」して頂ければSSOを利用開始することができます。 まとめ MiiTelにおけるSSOをご利用頂くにあたる開発チームとしての運用をご紹介しました。 本記事で紹介した各ステップは、作り込み次第では手順をより少なくできたり完全自動化するような方法もあるかと思います。 しかし本機能の利用シーンは1か月あたり数件程度であり、過度な作り込みはせずまずは属人化を防ぎつつリードタイムの少ない方式を確立することを優先し、現在の運用に至っています。
アバター
This article is the English version of Yuta Takase's blog post . Table of contents Table of contents 1. Introduction 2. What is YOLO? 3. YOLOv8 4. YOLOv8 model size 5. Changes with YOLOv5 6. YOLOv8's building and inference execution Inference on images Inference on videos Supplement Supported video formats Text output of detection results Model inputs 7. Overview of the inference results for each model 8. Summary References 1. Introduction Hello, I am Takase, a Research Engineer at the RevComm Research division. In this blog post, I will introduce YOLOv8, the famous object detection framework released by Ultralytics in early January 2023. I will also compare the changes with previous versions and show how to run it. 2. What is YOLO? As many people might know, YOLO is an object detection method proposed in the paper You Only Look Once: Unified, Real-Time Object Detection presented by Joseph Redmon et al. at CVPR2016. The name YOLO stands for You Only Look Once. YOLO improves the slow processing speed of object detection methods by simultaneously detecting and identifying objects. This feature made it a pioneer in real-time object detection with breakneck inference speed. This method is a must-see among the various techniques introduced to date for anyone interested in the topic. This article does not provide a detailed explanation of YOLOv8 – there are already superb explanatory materials on the internet. 3. YOLOv8 YOLOv8 is the latest version of the YOLO model released by Ultralytics, the publisher of YOLOv5. YOLOv8 allows object detection, segmentation, classification tasks, and training on large data sets. It can run on a variety of hardware, including CPUs and GPUs. It also features a new backbone, loss function, anchor-free detection head, and backward compatibility, allowing us to switch between different versions and compare performance. Currently, v3, v5, and v8 configurations are available in the official repository . As of this writing, the YOLOv8 paper is yet to be published. 4. YOLOv8 model size YOLOv8 has five pre-trained model patterns with different model sizes: n, s, m, l, and x. The number of parameters and COCO mAP (accuracy) below show that the accuracy has improved considerably from YOLOv5. In particular, for the larger model sizes l and x, the accuracy improved while the number of parameters was reduced [ reference ]. The table below shows the other models' parameters [ reference ]. 5. Changes with YOLOv5 YOLOv8 has several changes from YOLOv5, but two stand out from the rest at the time of this blog post: Introduction of C2f layer Decoupled head and removal of the objectness branch. In addition, some conv modules have been removed; kernel size has been changed, among other minor improvements. Although not official, a diagram of the YOLOv8 detection model architecture published by RangeKing is a helpful guide. YOLOv8 detection model's architecture by RangeKing [ Reference ] 6. YOLOv8's building and inference execution In this chapter, I will install and play some examples in YOLOv8. This time, I will use a pre-trained model to verify how well it works in a M1 MacBook Pro CPU environment. My environment is as follows: MacBook Pro (13-inch, M1, 2020) 16GB Mac OS Monterey First, you can install YOLOv8 with the command below. pip install ultralytics Now that the installation is complete, let's run it. This time, we will try the inference with a Python script. Inference on images First, let's enter the input. This article will use an image showing a bus and a person . The image size is 810x1080. from ultralytics import YOLO # load pre-trained model. model: YOLO = YOLO(model= "yolov8n.pt" ) # inference # set save=True to store the resulting image with the inferred results. result: list = model.predict( "https://ultralytics.com/images/bus.jpg" , save= True ) YOLOv8n's inference results Inference on videos Let's try inference on videos with YOLOv8x , since we used YOLOv8n for images. The interface is the same, but we pass the path of the video file as an argument. from ultralytics import YOLO # load pre-trained model. model: YOLO = YOLO(model= "yolov8x.pt" ) # set save=True to store the inferred results. result: list = model.predict( "MOT17-14-FRCNN-raw.mp4" , save= True ) This time, we will use the video from the MOT Challenge MOT17 test set . The MOT17 video file is in WebM format, so we converted it to mp4 in advance. The converted video is 30 seconds long, and the frame rate is 30, so inference is performed on 900 images. YOLOv8x's inference results Supplement Supported video formats The image and video file formats supported by YOLOv8 are as follows. Images: "bmp", "dng", "jpeg", "jpg", "mpo", "png", "tif", "tiff", "webp", "pfm" Video: "asf", "avi", "gif", "m4v", "mkv", "mov", "mp4", "mpeg", "mpg", "ts", "wmv" Definitions of supported file formats in the code are here . Text output of detection results When performing inference, saving the detection results as text is often desirable. # Output an image with the detection results drawn and in text model.predict( "https://ultralytics.com/images/bus.jpg" , save= True , save_txt= True ) # Output the detection result and the confidence of each object in the text model.predict( "https://ultralytics.com/images/bus.jpg" , save_txt= True , save_conf= True ) Other arguments can be set to the prediction function. Please refer to the official documentation . Model inputs Although we have specified a single video path to check the operation, you can pass multiple ones as a list. source_list: list = [ "./sample1.jpg" , "./sample2.jpg" ] result: list = model.predict(source_list, save= True ) 7. Overview of the inference results for each model Now that we have built an environment and performed inference let's try it on the YOLOv8 s to l models. In addition to YOLOv5, we will also compare the output results of YOLOv6 and YOLOv7, released within the past year. This time, we want to compare the accuracy of each model rather than the output of each model from a bird's-eye view. I will not go into the details of YOLOv5, YOLOv6, and YOLOv7, but if you are interested in these models, please check them out. YOLOv6 (v3.0) is used as the version for YOLOv6 since it was released almost simultaneously with YOLOv8. YOLOv8's sample images are used as the target images. The following is a summary of the images depicting the detection results of each model, information on the detected objects, and the inference speed. YOLOv8 YOLOv7 YOLOv6 (3.0) YOLOv5 YOLOv8l and x can detect the bicycle in the upper right corner of the image, which was not seen by YOLOv5l and x. The confidence of the detected objects in YOLOv8 shows that it has improved over YOLOv5. All models are fast, although YOLOv7 is slower. 8. Summary This article has provided an overview of YOLOv8, the differences from previous versions, and a brief description of how to use it. My impressions of YOLOv8 are: It is easy to install (run pip install ), easy to use, and has a well-organized interface. It is simple to convert to onnx, torchscript, etc. YOLOv5 was also user-friendly, but v8 has improved further in that regard. Although I have yet to mention model export , it is a valuable tool for exporting models in various formats and executing them efficiently. References https://github.com/ultralytics/ultralytics https://docs.ultralytics.com/ https://github.com/meituan/YOLOv6 https://github.com/WongKinYiu/yolov7 https://github.com/ultralytics/yolov5 https://github.com/ultralytics/ultralytics/issues/189 https://motchallenge.net/data/MOT17/ https://blog.roboflow.com/whats-new-in-yolov8/
アバター
RevComm Research の加藤集平です。8月下旬に音声処理のトップカンファレンスである INTERSPEECH で発表するため、また引き続いて行われた ISCA Speech Synthesis Workshop (SSW) に参加するためにヨーロッパに出張をしてきました。今回の記事では、INTERSPEECH, SSWおよび私の発表について紹介いたします。 加藤集平(かとう しゅうへい) シニアリサーチエンジニア。RevCommには2019年にジョインし、音声処理を中心とした研究開発を担当。ADHDと付き合いつつ業務に取り組む2児の父。 個人ウェブサイト X → 過去記事一覧 INTERSPEECH 会議の概要 International Speech Communication Association (ISCA) が主催する国際会議で、音声処理分野を専門に扱う国際会議としては最大級の規模です。2004年にそれまで行われていた2つの国際会議European Conference on Speech Communication and Technology (EUROSPEECH) とInternational Conference on Spoken Language Processing (ICSLP) を正式に統合した国際会議としてINTERSPEECHが開催され、以降毎年開催されています。 開催期間 2023年8月20日〜24日(チュートリアル1日+発表4日) 開催地 The Convention Centre Dublin、ダブリン(アイルランド) 対象分野 音声処理・音声コミュニケーション全般(音声認識・音声合成・音声変換・音声翻訳・音声符号化・音声対話システム・音声知覚・音声生成など) 発表件数 1,097件(採択率49.7%) 参加人数 およそ2,000人 会場の様子 4日間で1,000件を超える発表を行うため、7つのオーラルセッション(口頭発表)と4つのポスターセッションが並行しての進行でした。 8月22日のプログラム( INTERSPEECH2023のウェブサイトより引用 ) 会場の大きさは様々でしたが、どの会場も多くの参加者で賑わっていました。 口頭発表会場の例(写真は比較的小さな会場) ポスターセッションの会場 私の発表について 題目(リンク先は論文のアーカイブです) Speech-to-Face Conversion Using Denoising Diffusion Probabilistic Models (ノイズ除去拡散確率モデルを用いた音声から顔への変換) 本研究の主な貢献 Speech-to-face(音声を入力として、それに適した顔画像を出力するタスク)において、初めて拡散モデル(ノイズ除去拡散確率モデル)を導入しました。その結果、よりシンプルかつ柔軟なシステムで、これまでの研究よりも高解像度 (512×512) の顔画像を生成することに成功しました。 ポスター資料 いただいた質問 2時間の発表時間中ほぼ途切れることなく来客があり、以下のような質問をいただきました。 どのような応用先を考えているか? 将来的に、コールセンター等での応用を考えている。カスタマーサポート(特にクレーム対応)などの顔を出せないような場面で、声に適した顔を生成することでコミュニケーションを円滑にするといったことが考えられる。 顔画像の生成にはどの程度の時間がかかるか? GPUを使って1枚あたり数分かかる。ノイズ除去のステップ数が多いためであり、ステップ数を削減するための技術を応用することで短縮が可能であると考えている。 データセットはバイアスを内在しているのではないか?内在しているとすれば、何か対処をしているか? 今回モデルの訓練および評価に使用したデータセット ( AVSpeech および FFHQ Dataset ) は多様な人々や言語を対象として集められたものであるが、それでも見た目や性別等のバイアスは存在する。今回は特に対処していないが、実用化においては重要な問題だと考えている。 ISCA Speech Synthesis Workshop (SSW) 会議の概要 INTERSPEECHのサテライトワークショップ(付随して開催される小さな会議)として、 ISCA Speech Synthesis Special Interest Group (SynSIG) によって開催されているものです。音声合成を専門に取り扱っており、1990年から3年おき、2019年からは隔年で開催されています。 開催期間 2023年8月26日〜28日(INTERSPEECH閉幕の2日後から3日間) 29日に同じ会場でBlizzard Challengeが開催 開催地 グルノーブル・アルプ大学、グルノーブル(フランス) 対象分野 音声合成・音声変換 発表件数 通常発表(査読あり)36件(採択率82.2%) Late Breaking Reports(査読なし)7件 参加人数 110人 会場の様子 発表件数も参加者も小規模であり、すべての発表はシングルトラックで進行されました。 口頭発表会場 ポスターセッションの会場 INTERSPEECHとの違い SSWは音声合成専門のワークショップということで参加人数が小規模でした(110人)。コーヒーブレイクだけでなく昼食も会場内で提供され、休憩時間にもお互い気軽に話しかけられる雰囲気でした。全員が音声合成を専門としているので、話も盛り上がります。 1日目の終わりに開催された懇親会の様子 ポスターセッションも枚数が少ないため(1時間半の枠で12枚)、すべてのポスターを見て回ることができました。INTERSPEECHを含む昨今のトップカンファレンスでは発表件数が非常に多いためにすべての発表を見て回るのは不可能ですが、SSWのように分野を絞って開催されるワークショップは違った雰囲気を楽しむことができました。 Blizzard Challenge SSWとしてのプログラムは8月26日〜28日の開催でしたが、引き続いて29日には同じ会場で音声合成の競技会である Blizzard Challenge の発表が行われました。Blizzard ChallengeはSSWと同じくSynSIGが主催するイベントで、所定の期間内に、与えられたデータセットを利用して音声合成器を作成し、その品質を競う競技会です。音声合成の技術発展を目的として2005年から毎年開催されており(2022年のみ不実施)、今年の課題はBlizzard Challengeでは初めてとなるフランス語の音声合成でした。 冒頭、今年のBlizzard Challengeの概要と結果の発表が主催者からありました。今年の参加者は18チームで、各チームが提出した音声を元に主催者が聴取実験(音声を多数の人間が聞いて評価する)を実施し、その品質が競われました。品質(人間の音声らしいかどうか)は722人の評価者により、1から5の5段階で評価されました。 結果としては、自然音声(人間の音声)とほとんど同等であるという評価を受けたチームから、自然音声とかなり差があると評価されたチームまで、バラツキがありました。 評価結果の説明 主催者による概要と結果の発表に引き続き、各チームから手法の説明が口頭発表の形式で行われました。上位を獲得したチームの発表にはやはり注目が集まりましたが、あえてユニークな手法で挑戦したチームもあり、成功例・失敗例とも大いに参考になるものでした。 会の最後には、次回のBlizzard Challengeの課題の参考とするために、参加者にアンケートが取られました。実は音声合成の分野では、ここ数年の急速な技術革新により、単一話者・単一言語(特に英語などよく研究されている言語)の原稿を読み上げた音声(読み上げ音声)については、十分な訓練データがあれば自然音声(人間の音声)とほとんど同等の品質が達成できる状況になっています。Blizzard Challengeは音声合成の技術発展を目的としたイベントですから、音声合成コミュニティーとして目指すべき次の方向性を探るべくアンケートが取られたわけです。 アンケートの結果としては、「低資源・ゼロショット」(訓練データが少ない、あるいは未知の話者や方言に対応する)、「(原稿を読み上げた音声との対比としての)自発的・会話的音声※」に多くの票が集まったようです。 ※記事執筆時点(2023年11月)では、音声合成モデルの訓練には一般的に「原稿を読み上げた音声(読み上げ音声)」が使われます。これに対して、原稿なしで発話された音声を録音したものを自発的音声 (spontaneous speech)、2人以上の会話を録音したものを会話的音声 (convasational speech) などと呼ぶことがあります。 アンケートの結果 まとめ 8月下旬に音声処理のトップカンファレンスであるINTERSPEECHで発表するため、また引き続いて行われたISCA Speech Synthesis Workshop (SSW) に参加するためにヨーロッパに出張をしてきました。2,000人の参加者で賑わったINTERSPEECH、110人の参加者でお互いの顔の見えたSSW(そしてBlizzard Challenge)、それぞれに違った楽しみがありました。 INTERSPEECHでの発表では多くの方と有意義な議論をすることができました。今回の発表もチーム内で議論してベストなものを発表しましたが、世界中の研究者と議論することで新たな課題や方向性が見つかるものだということを改めて実感する機会となりました。 RevComm Research では、今後も継続的に研究発表を行っていきます。一緒に働きたい方を募集しています。
アバター
This blog post is the work of Hongkai Li, edited by Tolmachev Arseny. The authors belong to Works Applications and are working for RevComm. TL;DR Background Evaluation Metrics Experiments Datasets and Systems Results Correlation Among the Metrics Micro Analysis: Relevance-Based Metrics Micro Analysis: Factual Consistency-Based Metrics Evaluating Factual Consistency of Reference Summaries Performance Differences by Dataset ChatGPT’s Behavior FactSumm’s Behavior Dialogue vs. Narrative . TL;DR We tried different summarization metrics with four datasets and summarization models. Our findings are: Relevance metrics give different results from factual consistency metrics. Some metrics, especially factual consistency metrics, perform differently between dialogue summarization and conversational summarization. It is essential to choose different metrics according to the purpose of the evaluation, especially from the industrial perspective. Many metrics are not easy to adapt to other languages, especially those that require fine-tuning models. Background During the development of summarization systems, we need to measure the performance of the system and compare it to different systems. We use various performance metrics for this. Probably, the most important direction to compare is the quality of summarization itself. In this blog article, we give a very brief overview of several summarization evaluation metrics and our experiments on evaluating those metrics with a focus on summarizing dialogues. We investigated various existing summarization evaluation metrics, focusing on relevance and factual consistency, across several systems and datasets by comparing the scores and correlations between each other. Here, we would like to share our results and findings. Document summarization is the process of reducing the size of a document while keeping the main concepts. ROUGE and BLEU are widely used as evaluation metrics for the summarization task. ROUGE and BLEU do not capture paraphrased expressions (same meaning but different words). Several scores have been proposed in recent years to address this issue. Most proposed scores are word-based methods such as BERTScore . However, other methods have been proposed for the past three years. For example, there are evaluation methods using information extraction and question-answering . Evaluation Metrics There are a lot of aspects for evaluating a summary, such as coherence, consistency, fluency, and relevance, as suggested in this article and this article . Most works focus on relevance or/and (factual) consistency. Relevance measures how well the summary captures the key points of the source document. It focuses on whether all and only the important aspects are contained in the summary. The key points are usually included in reference summaries. So, relevance scores are usually calculated with system summary and reference summary pairs. Factual consistency is defined as the factual alignment between the summary and the summarized source. A factually consistent summary contains only statements that are entailed by the source document. So, factual consistency scores are usually calculated with system summary and source text pairs. The example below describes the two very well. The summary in the first row fails in relevance, and the second has a factual error. Figure 1. Examples of relevance and factual consistency errors ( source ) Figure 2. Difference between relevance and factual consistency metrics ( source ) For years most papers have been using ROUGE to measure summaries. Recently, especially since 2019, researchers have focused on factual consistency of summarization. LLMs such as ChatGPT further contributed to this trend because there are often hallucinations in their outputs. So, we focused on both aspects and chose the existing evaluation metrics listed below. A very brief description of those metrics is provided in Figure 2. Table 1. Relevance metrics Metric Japanese? TL;DR ROUGEcode Perfect Exact n-gram overlap (ROUGE-n) or longest common sequence (ROUGE-L) between 2 texts (e.g. summary and reference) BERTScorecode Yes, needs BERT model Calculate similarities between 2 sentences and get recall and precision scores using contextual embeddings from a pre-trained BERT model. MoverScorecode Yes, needs BERT model Extension of BERTScore that uses hard alignments between sentences. With Word Mover Distance (WMD) developed from Earth Mover Distance (EMD), MoverScore finds the minimum effort to transform a text to the other to get soft alignments. BARTScorecode Maybe, needs fine-tuning Weighted log probability of one text given another text Table 2. Factual consistency metrics Metric Japanese? TL;DR OpenIE *code Maybe. needs a Japanese entity relationship extractor Extracts triples from both the summary and source document and evaluate whether the triples of the summary are included in those of the source document FactCCcode Maybe. Needs data or data generation scripts. FactCC: A classifier to judge whether a summary is factually consistent with the source document.FactCCX: I think the X means explanation, meaning this model is able to explain why the summary is wrong. DAEcode Maybe, needs Japanese dependency parsing and model training. Dependency Arc Entailment. DAE views dependency arcs as semantic units and each arc is judged independently based on whether the relation it implies is entailed by the source sentence. QAGS *code Maybe, needs Japanese QA and QG models. QAGS is based on the intuition that if we ask questions about a summary and its source, we will receive similar answers if the summary is factually consistent with the source. CoCocode Maybe, needs BART CoCo selects key tokens in summary and masks the tokens in the source document. The masked source document is then fed to the scoring model. If the scoring model is still able to generate the masked token with a high possibility, it means that the token is more likely to come from the scoring model instead of the source document. Therefore a penalty should be added. SummaCcode Maybe, needs training/fine-tuning Sentence level alignment. FactGraphcode Maybe, needs Japanese AMR FactGraph uses abstract meaning representation to form the graph of a sentence and then uses the model above to give the final score. * For OpenIE and QAGS, we use the implementation from a toolkit called FactSumm . Experiments Datasets and Systems We conducted experiments on the following datasets and systems. The aim of the experiments is to Investigate the advantages and disadvantages of each metric Compare the results between relevance and factual consistency-focused metrics We used the following datasets for the experiments. Samsum dataset contains instant messenger-like conversations with summaries. Conversations were created and written down by linguists fluent in English. CNN / DailyMail Dataset (CNNDM) is an English-language dataset containing just over 300k unique news articles written by journalists at CNN and the Daily Mail. XSUM consists of online articles from the British Broadcasting Corporation (BBC) and single-sentence summaries. Specifically, each article is prefaced with an introductory sentence (aka summary), which is professionally written, typically by the article's author. DialogSum consists of three public dialogue corpora, as well as an English speaking practice website. These datasets contain face-to-face spoken dialogues that cover a wide range of daily-life topics, including schooling, work, medication, shopping, leisure, and travel. Table 3. Dataset summary   DialogSum Samsum CNNDM XSUM Num. of documents in the train dataset 12,460 14,732 287,113 204,045 Num. of documents in the test dataset 1,500 819 11,490 11,334 Num. of tokens in a source document 210 157 868 487 Num. of tokens in a summary 35 26 66 26 Compression Rate 17.80% 21.40% 9.20% 9.50% Table 4. Scope of experiment; ”o” means the target Dataset\System ChatGPT GPT3 Flan-T5 T5 Samsum ○ ○ ○ ○ CNNDM ○ - ○ ○ XSUM ○ - ○ ○ DialogSum ○ - ○ ○ For Flan-T5 and T5, we either used existing fine-tuned models or fine-tuned flan-t5-large or t5-large with the datasets by ourselves. The models used for the Samsum dataset are: philschmid/flan-t5-base-samsum jaynlp/ t5-large-samsum Results Correlation Among the Metrics Figure 3. Heatmap of Pearson correlation among the metrics Figure 3 shows the Pearson correlation among the metrics. Metrics from rouge1 to bart_hypo_ref are categorized as relevance metrics, and metrics from dae to factcc are factual consistency metrics. We can clearly see that relevance metrics correlate with each other while having a low correlation with factual consistency metrics, except the bart_hypo_ref score. Factual consistency metrics only correlate with factual consistency metrics as well. For relevance metrics, some metrics have precision, recall, and F1 scores. We can find recall scores ( bert-r-r , bart_hypo_ref , etc.) have a relatively low correlation with precision scores ( bert-r-p , bart_ref_hypo , etc.). In most cases, the ROUGE scores seem enough to reflect the performance at the system level. The low correlation between retrieval and factual metrics can be explained because they focus on different aspects. Sometimes, a summary may get a high relevance score because it is extremely similar to the reference summary with only a 1-word difference. However, this word is very important and changes the whole meaning of the summary. Factual consistency metrics are able to capture this kind of error. Additionally, some summarizers may output more information that is not included in the reference summary, but according to the source text, the information is true and consistent. This will also contribute to the low correlation. See the example below. Source Dialogue Rudi: Hetta, did you see the last trump video Henrietta: nope Henrietta: what did he do now? Rudi: <file_video> Henrietta: OMG Henrietta: what a jerk Rudi: it gets worse Rudi: <file_other> Rudi: the whole interview is here Henrietta: can't believe he said that about a congress woman Rudi: yeah Henrietta: do you wonder where the limit is? Rudi: wdym Henrietta: if he will say something that will actually get him kicked out of the white house Rudi: not really Henrietta: fuck Rudi: yeah Reference Summary Trump is acting like a contemptible fool and it is getting worse. Rudi has sent Henrietta the link to his interview. System Summary Rudi and Henrietta discuss a video of Trump insulting a congresswoman, and wonder if he will say something that will get him kicked out of the White House. ROUGE LSUM 0.1632653061 FactCC 1 CoCo 0.441158 Here, the system summary includes more facts (e.g. White House) than the reference one, so it gets a better FactCC score than the reference one. Micro Analysis: Relevance-Based Metrics As mentioned above, the bart_hypo_ref score correlates with neither other relevance metrics nor factual consistency metrics. It is defined as recall, which is the probability of generating the reference summary from the system summary, according to the BARTScore paper. So, we can find it relatively correlates with   bert-r-r , bert-d-r , and bart_cnn_hypo_ref . By investigating and comparing the scores of each sample of different systems, we found that for example, the range of the bart_hypo_ref scores of Flan-T5 with Samsum was (-13, -0.7), while that of ChatGPT was (-8.6, -0.8). As a result, the average score of ChatGPT was higher than Flan-T5, even though Flan-T5 outperformed ChatGPT in other metrics. BARTScore seems very risky because it does not have a specific range. Micro Analysis: Factual Consistency-Based Metrics When investigating the scores from DAE, we found that more than 90% of the samples scored more than 0.90 (90%). Take the sample from Samsum below, for example: The T5 output had only one thing wrong: the neighbors are only Ricky’s new neighbors but not Frederick and Ricky’s. Since dae is based on dependency arcs, it is relatively easy to understand that most arcs match the source text, so the score was extremely high. On the other hand, factcc is a binary classifier. If the sentence contains any wrong information, the whole sentence will be false. And since the T5 output only had one sentence, the final score was 0. The factsumm-qa  is based on facts (QA pairs) extracted from the source text and the system summary and can recognize that some parts of the sentence are true while some are false. This remains a problem whether we should allow partially correct summaries or reject summaries containing any false information ( factcc  vs. factsumm-qa ). Evaluating Factual Consistency of Reference Summaries Factual consistency-based metrics calculate scores with the source document and system summary pairs, while relevance-based metrics use system and reference summary pairs. We are pretty curious about whether reference summaries can get high scores in factual consistency-based metrics, so we fed some of the evaluators with source documents and reference summary pairs of Samsum corpus. Here are the results. Metrics Ref ChatGPT GPT-3 Flan-T5 T5 FactSumm-src-fact 0.0122 0.0147 0.0119 0.0142 0.0159 FactSumm-src-qa 0.2786 0.2731 0.2644 0.2963 0.3186 FactSumm-src-triple 0.0348 0.0514 0.0428 0.0739 0.1096 FactCC 22.1 21.25 27.11 21.37 18.93 DAE 95.16 93.78 91.82 93.4 94.71 CoCo 24.64 27.7 24.82 30.61 34.55 Red  = Worst, Blue  = Best Interestingly, reference summaries even got the worst scores in some of the metrics. It may be because the evaluators failed to extract facts from the source document or summary. From this perspective, DAE may be the best or most convincing evaluation metric. Performance Differences by Dataset We used four datasets with different properties for our experiments and observed that systems performed differently among the datasets. ChatGPT’s Behavior From our observation, ChatGPT tends to output more information than needed to make perfect answers. Regarding summarization, it tends to output longer summaries than other systems. This results in 2 main consequences: ChatGPT got relatively higher recall scores, such as the hypo-ref direction of BARTScore, which is defined as ‘recall’ in BARTScore’s paper, and recall scores of BERTScore. And conversely, the precision scores, such as the ref-hypo direction of BARTScore are extremely low. ChatGPT got higher factual consistency scores in certain metrics with some of the datasets. Since ChatGPT tends to output more information, and considering ChatGPT’s ability to extract information from the input, the extra information is also consistent with the source text, making factual consistency scores relatively high. This is especially obvious for the XSUM dataset because each reference for each document is only one sentence. Flan-t5 and t5 models have been fine-tuned with XSUM’s training data, so the two models only produce one-line summaries as well. On the other hand, summaries from ChatGPT always include several sentences, so ChatGPT got relatively high scores in recall and extremely high scores in factual consistency, while other relevance scores were very low. FactSumm’s Behavior We have also observed that some evaluation metrics performed differently among the datasets. Take FactSumm, for example. We got extremely low scores with all systems among all datasets except CNNDM. We consider it was because FactSumm extracts information from source texts and summaries to compare the pairs. Since both source texts and summaries of CNNDM are relatively long and formal, FactSumm can extract more facts from both. When we investigated the results of FactSumm for other datasets, we found that many summaries were scored 0 because FactSumm failed to extract any entity from the data. We consider this as a big disadvantage of FactSumm (or OpenIE, to be precise). Dialogue vs. Narrative From our observation, information extraction-based metrics such as OpenIE or DAE failed to extract important information because the person name of the speaker is in the front of their lines. Abstractive summarizers can summarize the lines with the correct speaker name, but extractive methods sometimes fail to recognize that, resulting in low scores. Below is a simple example of this phenomenon by FactSumm (OpenIE, QAGS): Input Input Source Text Jack killed John. Jack: I killed John. (*3) Input Summary Text Jack killed John. factsumm-fact (*1) Facts None Fact Score 0 factsumm-qa Answers based on SOURCE [Q] Who killed John? [Pred] Jack [Q] Who did Jack kill? [Pred] John [Q] Who killed John? [Pred] <unanswerable> [Q] Who did Jack kill? [Pred] John Answers based on SUMMARY [Q] Who killed John? [Pred] Jack [Q] Who did Jack kill? [Pred] John QAGS Score 1 0.5 factsumm-triple SOURCE Triples ('Jack', 'killed', 'John') None SUMMARY Triples ('Jack', 'killed', 'John') None (*2) Triple Score 1 0 *1. For factsumm-fact, since both samples got the same results, the details are omitted. *2. FactSumm only outputs common triples of source and summary. *3. When we changed the input source text to ‘Jack said that he killed John.’, the results were the same as ‘Jack: I killed John.’ This is considered to be able to be avoided by fine-tuning with dialogue data.
アバター
Introduction Hi! My name is Jose, a software engineer working for RevComm. In this blog post, I'll discuss four takeaways from my first PyCon APAC and the most interesting talks I attended. What is PyCon APAC? PyCon APAC is a non-profit annual Python conference organized in countries of the Asia-Pacific Region. The 2023 edition in Tokyo consisted of four days: one tutorial, two conferences, and one development sprint. Lessons 1. Plan ahead Every PyCon exhibits the most varied collection of talks, from obscure tricks of the language to the technical marvels of frameworks. This year, there were more than fifty presentations in English and Japanese across five tracks. To get the best out of them, prepare an agenda. Read each talk's description; sometimes, the title is enough, and choose where you are going. Creating a calendar for the event in iCal or gCal is especially useful for coordinating with friends. Just so you know, the schedule above took me around forty-five minutes. 2. Take time for the sponsor booths My first major mistake was forgetting about the sponsor booths. I skipped the last two tracks of Day 2 to go around, and It was worth it! Check them out. They are a fantastic reference for the country's Python market – what different companies are doing, their stack, and who is hiring. You might be as surprised as I was to find unexpected sponsors. The stamp rally was a great motivator, too. 3. Talk to people Any major conference is an opportunity to engage with the community. Talk to people. I met so many charming characters and learned a considerable amount. If you don't have time on the conference days, the official and unofficial parties are ideal for networking. 4. Join the developer sprint As the famous proverb says: After two days of conference and drinking parties, the developer sprint sounds like a stretch. It’s not. You will be surprised how productive you are in a couple of hours. For instance, my team merged a PR to the cPython's official repo! macOS CI for CPython now supports `free-threaded` mode CI as the conditional CI. It was done during the PyCon APAC sprint. https://t.co/rrcRxtkw7K #pyconapac pic.twitter.com/7pULkgP9By — Donghee Na (@dongheena92) October 29, 2023 Coding along with people you've just met is as open-source as it gets. Talks I attended eight talks, seven in English and one in Japanese. For brevity, I'd like to discuss the ones who impressed me the most. Write Python for Speed by Yung-Yu Chen https://2023-apac.pycon.jp/timetable?id=WNN9WG www.youtube.com This talk goes deep into optimizations for speeding up your Python programs. Although the field of application was outside my current job, Chen's passion and wit made me follow it until the end. I loved some of his quotes: "Python is the second-best language for everything." "To go fast, you do dangerous things." Couldn't agree more. Beaming up to the flow! by Thu Ya Kyaw https://2023-apac.pycon.jp/timetable?id=KKELHA www.youtube.com An enlightening talk about data streaming, the basics of Apache Beam, and the feature engineering process at Google. The expositor was also present at the Google Cloud booth, so I got to ask many questions. Debugging and Troubleshooting Python Applications by Neeraj Pandey https://2023-apac.pycon.jp/timetable?id=C7HGZS www.youtube.com This talk deepens into logging, profiling, and debugging in monolithic and distributed systems. I was blown away by OpenTelemetry. What does your application need to run on production? by Shota Kokado https://2023-apac.pycon.jp/timetable?id=FHTQDR www.youtube.com After years of working in Software Engineering, this talk was a good refresher on all the basics any production-ready application should have. The talk is in Japanese, but you can extract the vital information from the slides. So for next year… Indonesia will host next year's PyCon APAC. We also have the annual PyCon JP. And many more! Check pycon asia's website for more information. Special thanks Huge thanks to RevComm for supporting me throughout the event, to my colleagues whom I went with, to the more than fifty members of the APAC organizing committee, and, of course, to all the new people I met. Each of them made the conference for me. You can follow me at twitter ( @juanjo12x ). See you next year! References PyCon APAC 2023 official website : https://2023-apac.pycon.jp/timetable Check the official PyCon JP’s YouTube channel for all the conference talks : https://www.youtube.com/@PyConJP/featured
アバター
RevCommの中島です。 2023年10月26日(木)から29日(日)に開催された PyCon APAC 2023 に参加しました。 弊社からは陶山 嶺、小門 照太、松土 慎太郎(兼 コアスタッフ)の3名が登壇しました。 今回はConferenceの振り返りとして登壇者らのコメントとトークの感想をお送りします。 登壇振り返り Pythonはどのようにデータベースと繋がるのか 概要: Webアプリケーション開発で何気なく使っているO/Rマッパーやデータベースアダプタのライブラリはとても便利です。 数々のライブラリが、我々がプログラムとネットワークはどのように繋がっているのかを考える必要なくデータベースと繋がることを助けてくれています。 このトークでは、ソケット通信でつながる方法を深掘りしていく他、複数のライブラリでの実現方法、PEP249で決められているルール、非同期処理をどのように実現しているか、最新のO/Rマッパーやデータベースアダプタのライブラリ事情などを紹介していきます。 登壇者: Shintaro Matsudo( shintaromatsudo ) 発表資料: Pythonはどのようにデータベースと繋がるのか www.youtube.com 登壇者の感想 Shintaro Matsudo 日々Webアプリケーションを開発している中で疑問に思っていることからテーマを決めました。資料を作る中で多くのことを学ぶことができました。 聞いてくれた方々もなにかを得てくれていたら嬉しいです。 また、今年はPyCon APACだったので日本以外からの参加者とも多く交流することができました。 来年のPyCon APACにも発表を英語でできるようになってプロポーザルを提出しようと思っています。今年出会えた方々とまた来年会えることを楽しみにしています。 Pythonで一歩踏み出すバイナリの世界 概要:コンピュータの世界はゼロとイチで成り立っています。 この文章もPythonのロゴ画像もみなさんが書いているプログラムもすべてゼロとイチで表現されています。 ということはみなさん知っているでしょう。 しかし、そのことを意識したことがなかったり、「バイナリ」や「バイト列」という言葉に苦手意識を感じる方も多いのではないでしょうか。 本セッションでは、Pythonの対話モードやprint()、structモジュールなどを使ってバイナリの世界を覗いてみます。 バイナリに慣れるとより深くコンピュータを知ることができ、目の前の世界が一気に広がります。 本セッションを通じて、その最初の一歩を踏み出しましょう。 登壇者: Rei Suyama ( rhoboro ) 発表資料: Pythonで一歩踏み出すバイナリの世界 www.youtube.com 登壇者の感想 Rei Suyama 今年はPyCon APAC 2023レビュアーの評価観点を参考に、初心者だった頃の自分を振り返りながら発表テーマを決め、プロポーザルを提出しました。 発表資料や内容に関しても、最初の一歩ということでセッションを聴講してくれる方々を置いていってしまわないよう丁寧な説明を心がけ構成を練りました。 その甲斐もあってかXのポストや懇親会で感想を聞いた印象では、想像以上に参加者の方々に楽しんでもらえていて嬉しかったです。 時間の関係で非表示にしてスキップしたスライドも多くありましたので、ぜひ発表資料を見ていただければと思います。 あなたのアプリケーションを本番システムで動かすために 概要: Webアプリケーションの開発と運用において必要な知識は多岐に渡ります。 フレームワークの使い方を覚えることはもちろん重要ですが、開発したアプリケーションは本番システムにリリースして実際に稼働することになります。 そして、リリースしたシステムは継続的に運用していく必要があります。 このセッションでは、本番システムでの運用を見据えたアプリケーション開発に必要な知識や勘所を紹介します。 登壇者: Shota Kokado( skokado ) 発表資料: あなたのアプリケーションを本番システムで動かすために www.youtube.com 登壇者の感想 Shota Kokado 普段からWebサービスの開発、運用する中で「一つのことだけやっていれば良い」ということは無く、様々な知識やバックグランドが武器になることを実感しています。 今回のトークがエンジニア入門者の方々にとって役に立てば光栄です。 当日の質疑応答に対する補足を個人の参加レポートに記載していますので、そちらもぜひご覧ください。 PyCon APAC 2023に参加&登壇してきました @skokado | Qiita 登壇者の感想は以上です! 他にも、中島が視聴して興味深かった登壇をいくつか紹介させていただければと思います。 Dev Containers時代のPython開発環境のあり方 登壇者: Yoshiki Shibukawa https://2023-apac.pycon.jp/timetable?id=M8QP3X 一般的に言語やパッケージのバージョンが異なるプロジェクトを開発していると環境分離が大切になります。 pipenv、poetry、hatchなど、これまでPythonのパッケージ管理ツールは標準であるvenvでの仮想化をベースにして開発されてきましたが、それらのツール群や選択肢が却ってPythonの環境構築の難易度を上げています。 登壇者のShibukawaさんは「環境構築の手間が楽」「必要以上に柔軟性を与えるのをよしとしない」「深く考えない状態でも難しくなく使える」という観点から、VSCode上のDev Containersに注目し、その場で環境構築を実践しながら紹介されていました。 普段 Docker で開発環境を用意することが多い私ですが、Shibukawaさんの実践を見ながら手元のPCでもDev Containersを試してみますと、すぐに環境が起動し動かすことができたので、今後カスタマイズなどを学んで活用していこうと思いました。 ModuleNotFoundErrorの傾向と対策: 仕組みから学ぶImport https://2023-apac.pycon.jp/timetable?id=9TKP3P 登壇者: Toshifumi Tsutsumi Pythonを使っていると誰でも経験したことのあるModuleNotFoundErrorについて、基本的な要素から噛み砕きながら深掘りしていて、非常に分かりやすい発表内容でした。 本登壇を聴講した方はModuleNotFoundErrorが何も怖くない状態になったことと思います。 PythonのImportの役割と仕組みを分解し、以下の技術などについて段階的に解説されてます。 ModulesSpec PathFinder sys.path 何気なくImportを記述するとエラーが解決するので、意識したことのない言語仕様、特にImport周りを理解することができ、よりPythonに詳しくなれました。 まとめ このようなイベントに参加するのは初めてだったため不安な部分もありましたが、会場やイベントは終始ウェルカムな雰囲気で参加者同士の交流も盛んでした。 そんな雰囲気に後押しされ、私も積極的にポスターセッションやスポンサーのブースをたくさん回り、たくさんの方に話を聞かせていただき、たっぷりと楽しむことができました。 公式グッズのTシャツとバッグとタオル また、非常の多くの方が集った本イベントはスタッフやスポンサー様に支えられて開催されています。 イベントを支えてくださった登壇者、スタッフの皆さん、スポンサー様や関係者の方々、本当にありがとうございました! 来年は登壇者として参加できれば良いな、と強く感じました。 左から小門、松土、中島、陶山、大谷、ホセ 最後に RevCommは電話営業や顧客応対を可視化する音声解析AI搭載型のクラウドIP電話「MiiTel(ミーテル)」を開発しています。 プロダクトの開発においてWebアプリケーション、機械学習/深層学習などの領域でPythonが広く使用されています。 「コミュニケーションを再発明し人が人を想う社会を創る」というミッションを達成するべく、一緒にプロダクトを開発して頂けるエンジニアを募集しています! hrmos.co
アバター
Photo by Luke Chesser on Unsplash Introduction (This article is a translation of the Japanese article titled "MiiTel AccountのSLO: 測定と継続的な最適化の方法") I'm Kei Usami from RevComm. We develop and provide an AI-powered phone system "MiiTel" and an AI-powered online meeting analysis tool "MiiTel Meetings." I work in the MiiTel authentication platform (MiiTel Account) team, serving as a Project Manager and Software Engineer. Previous Articles: Cognito user pool で OpenID Connect を利用した外部 ID Provider によるサインインを実現する - RevComm Tech Blog Webアプリケーションの国際化対応をバックエンドからフロントエンドに移行した話 - RevComm Tech Blog In this article, I'd like to introduce the measures we are taking to ensure the stable operation of the MiiTel Account service, while also discussing its relationship with SLO (Service Level Objectives). SLO - What is it? In a nutshell, SLO can be described as "objectives on service reliability." Generally, companies providing web services or systems strive to minimize disruptions in order to offer users a better experience. However, since systems are not infallible, occasional outages or system issues are inevitable. This is where SLO comes into play. SLO represents the quality objectives set by service providers (such as companies offering web services like MiiTel). It is based on the quality levels users can expect when using the service. Actual SLOs are expressed as specific numerical values. For example, “guaranteeing 99.9% uptime” or “maintaining a response time of 2 seconds or less for 99.9% of all requests”. These metrics serve as indicators to assess how comfortably customers can use the service. Related terms - SLI and SLA SLI (Service Level Indicator) and SLA (Service Level Agreement) are closely related to SLO, and are also important concepts. SLI (Service Level Indicator) : SLI is a specific and quantitative metric used to measure the performance and quality of a service. It includes metrics such as average response time and error rates. SLA (Service Level Agreement) : SLA is a contract or agreement between the service provider and the customer. It typically specifies what quality metrics the service provider should meet and includes compensation arrangements in case the goals are not achieved. SLO (Service Level Objective) : SLO is a quality target set based on SLIs. It defines the performance and quality of a service in specific numerical terms. While often used as an internal target, some services publicly disclose their SLOs. In summary, SLI quantifies the state of a service, SLA defines the agreement between the service provider and the customer, and SLO sets the quality goals the service should achieve. These metrics are key to enhancing the reliability between service providers and customers. The difference between SLO and SLI is clearly illustrated on the Google Cloud website as follows: SLO and SLI - Google Cloud Now, let's explore how MiiTel Account sets SLOs and what specific measures are being taken to achieve them. Role of MiiTel Account First, let me explain the role of MiiTel Account within MiiTel. MiiTelの技術スタックとアーキテクチャ変遷を紹介します(2023年5月版) - RevComm Tech Blog MiiTel architecture MiiTel Account corresponds to what was introduced as the "Authentication Infrastructure Application" in this article. MiiTel Account handles the authentication functions for the entire MiiTel platform. If an issue were to occur with MiiTel Account, it would result in the inability to access any of the services that make up MiiTel. Since MiiTel is used for calls and inbound interactions, even a few seconds of service downtime can have a significant impact on users. Therefore, it is a service that must operate robustly and stably above all else. However, on the other hand, there is a dilemma between maintaining service stability and swiftly adding authentication-related features to meet business needs. SLO provides a framework to effectively manage this. By setting higher SLOs than regular services, you can ensure stability while allowing for some aggressive feature development as long as the SLOs are met. By formalizing goals through SLO and visualizing the current state of service performance and quality, you can somewhat alleviate the tension between stable operation and feature additions. SLO in MiiTel Account So, what SLOs are set for MiiTel Account in practice? MiiTel utilizes Datadog as a monitoring tool and currently has the following target values set: The percentage of 5XX errors in the total request count should be within 0.2%. The average response time should be under 3 seconds. *Both of the above criteria should be met for 99.9% or more within the last 90 days. These are quite strict numbers. However, as of October 2023, the error percentage exceeds 99.999%, and the response time is 100%, surpassing the targets. With a considerable error budget, there is room for proactive feature development while maintaining the stability of the system. SLO API errors - past 90 days SLO slow response - past 90 days Datadog is a valuable tool, particularly when combined with APM (Application Performance Monitoring) , as it makes setting and monitoring SLOs straightforward. It automatically calculates monitoring metrics and allows you to configure alerts according to your preferences, making it highly convenient. Efforts Toward Achieving SLOs To maintain SLOs, various initiatives and operational strategies are necessary. Here, I'll introduce some of the efforts within MiiTel Account. Setting Various Metrics and Monitoring Alerts One of the most effective and easy-to-implement measures is setting up metrics and monitoring alerts. While various tools can accomplish this, as mentioned earlier, RevComm utilizes Datadog as its monitoring tool. You can set thresholds to trigger alerts in cases where there are anomalies in request counts or when infrastructure metrics, such as those from AWS, are more critical than usual. These alerts can be configured to notify you via platforms like Slack. docs.datadoghq.com Datadog memory usage alert Datadog request count alert Moreover, Datadog allows for creating simple scenarios to run end-to-end tests periodically, which can be used for health checks to ensure the login functionality is working correctly. When setting up alerts, it's advisable to differentiate notification channels between production and non-production environments. This way, you can easily discern whether immediate attention is required, preventing development environment alerts from getting lost in the mix. Regular Metric Checks in Meetings The MiiTel Account team conducts bi-weekly meetings where they discuss task progress, share insights, and address concerns. To foster constant awareness of SLOs and various metrics, the team begins each meeting by checking the SLO dashboard in Datadog. SLO dashboard - Datadog With Datadog APM set up, you can access dashboards that display time-series data for metrics like request counts, error rates, and latency. This is highly effective in understanding the current state of the service. In some cases, analyzing the trends of request counts and response times for each API endpoint and using this data to consider effective measures for improvement may be necessary. Sometimes, abnormalities are detected during these regular meetings. Anomaly requests An example of this was noticed by Shota Kokado (@skokado, previous article: Amazon Inspectorによるプラットフォーム診断とコンテナイメージ改善の取り組み - RevComm Tech Blog ), who has appeared in this blog on several occasions. At that time, request count alerts as mentioned earlier had not been set up. However, during a routine dashboard check in a meeting, an abnormal tenfold increase in requests was observed. Due to web server auto-scaling and other measures, there was no significant impact on the service, and the issue was resolved through the use of security features like WAF. If it hadn't been discovered promptly, there could have been potential service disruption due to resource constraints in the infrastructure. Automation of Integration Tests and E2E Tests After Release While enhancing monitoring and alerting is essential, most incidents tend to occur shortly after a release. There might also be bugs that are only noticeable when working with the actual environment and database, as unit tests can't detect them. To mitigate these risks, MiiTel Account has automated API integration tests and E2E tests to run after a release. These tests are configured for each environment (we have three major environments), allowing them to check for any unexpected bugs before a production release. Integration Tests: Comprehensive testing of nearly all API endpoints for normal operation. E2E Tests: UI tests for critical functionality using Autify. Upon completion of these tests, notifications are sent to Slack as follows: E2E testing result The automation framework for tasks like these has been developed by Raman Yachi (@r-ym). He has recently summarized the details in a blog post, which you can refer to for more in-depth information. E2E Testing system for MiiTel Account - RevComm Tech Blog (English) MiiTel AccountチームのE2Eテスト自動化 - RevComm Tech Blog (日本語) Thanks to this system, which significantly reduces the need for manual testing, releases can now be carried out with greater safety and reduced psychological burden. These tests have significantly enhanced the service's security, allowing the team to transition from weekly night releases to releasing during the day whenever necessary. Deployment frequency is an important metric, especially emphasized in the Four Key Metrics of DevOps Research and Assessment (DORA), so this initiative holds significance not only in terms of SLOs but also in improving development productivity. Looking Ahead Thanks to these measures, we've been fortunate to achieve SLOs and maintain a higher level of metrics. While operating a web system, it's inevitable that there will be occasional disruptions and temporary drops in service performance. However, with the strategies mentioned earlier, you can control this risk and maintain high productivity while continuing to develop new features. Looking ahead, the goal is to not only maintain SLOs but also enrich the metrics for more detailed service health checks and enhance development productivity. www.revcomm.co.jp
アバター
Photo by Luke Chesser on Unsplash はじめに RevCommの宇佐美です。 RevCommでは、音声解析AI電話「MiiTel(ミーテル)」やAI搭載オンライン会議解析ツール「MiiTel Meetings」を開発・提供しています。 私はMiiTelの認証基盤 (MiiTel Account) 開発チームで、Project Manager兼Sortware Engineerとして活動しています。 過去記事: Cognito user pool で OpenID Connect を利用した外部 ID Provider によるサインインを実現する - RevComm Tech Blog Webアプリケーションの国際化対応をバックエンドからフロントエンドに移行した話 - RevComm Tech Blog 今回は、MiiTel Accountというサービスを安定的に運営するためにどのような取り組みをしているのか、SLO (Service Level Objective) と絡めて紹介したいと思います。 SLOとは何か SLOは直訳すると"サービス信頼性目標"です。 一般的に、Webサービスやシステムを提供している会社は、ユーザーによりよい体験を提供するため障害を最小限に抑えるよう努力しています。 ただシステムである以上、サービスは常に100%の信頼性を持って稼働できるというわけではなく、どうしても時々障害やシステム不具合が発生します。そこで登場するのがSLOです。 SLOは、サービス提供者(例えばMiiTelのようなWebサービスを提供する会社)が設定するサービスの品質目標です。これは、ユーザーがサービスを利用する際に期待する品質レベルをもとに表現されます。 実際のSLOは、正確な数字で表現されます。例えば、99.9%の正常稼働時間を保証するとか、全リクエストのうちの99.9%のレスポンスタイムを2秒以内に維持する、のような形です。これらは顧客がサービスをどれだけ快適に利用できるかを評価するための指標です。 関連用語 - SLIとSLA SLOに関連して、SLI (Service Level Indicator) とSLA (Service Level Agreement) もよく似ていますが重要な概念です。 SLI (Service Level Indicator) : サービスの性能や品質を測定する具体的かつ定量的な指標です。例えば、平均応答時間やエラー率などが含まれます。 SLA (Service Level Agreement) : サービス提供者と顧客との間で合意される契約ないし取り決めです。通常、サービスの提供者が顧客に対してどの品質指標をどのくらい満たすべきかが明記され、目標が満たされなかった場合の補償を含みます。 SLO (Service Level Objective) : SLOはSLIに基づいて設定される品質目標であり、サービスの性能や品質を具体的な目標数値で設定します。内部的な目標として使われることが多いですが、サービスによっては公表されています。 まとめると、SLIはサービスの定量的な状態を示し、SLAはサービス提供者と顧客の合意事項を定義し、SLOはサービスが達成すべき品質目標を設定する役割を果たします。これらの指標が、サービス提供者と顧客の信頼性を高める鍵となっています。 Google CloudのWebサイトでは、下記のようにSLOとSLIの差がわかりやすく図で示されています。 SLO と SLI の関係を示すグラフ - Google Cloud SLO を定義する  |  アーキテクチャ フレームワーク  |  Google Cloud ここからはMiiTel AccountがどのようにSLOを設定していて、その達成に向けて具体的にどんな取り組みをしているかをご紹介します。 MiiTel Accountの位置づけ まず、MiiTelにおけるMiiTel Accountの位置づけについて説明します。 MiiTelの技術スタックとアーキテクチャ変遷を紹介します(2023年5月版) - RevComm Tech Blog MiiTel architecture MiiTel Accountは、こちらの記事で紹介があった「認証基盤アプリケーション」というものにあたります。 MiiTel AccountはMiiTel全体の認証機能を担っているため、もし障害が発生するとMiiTelを構成するどのサービスにもアクセスできません。MiiTelは通話や受電に使われるため、数秒のサービス停止であってもユーザーに大きな影響を及ぼしてしまいます。 そのため、何よりも堅牢かつ安定的に稼働することが求められるサービスだといえます。ただ一方で、認証関連の機能追加もビジネス的なニーズによって迅速に行なっていく必要があり、ここでサービスの安定稼働とのジレンマが生じます。 これをうまくコントロールするために使える枠組みがSLOです。 通常のサービスよりも高いSLOを設定することで安定稼働を担保しつつ、SLOが達成できていて余裕があるうちは、ある程度攻めの機能追加開発も可能になります。 SLOという形で目標を明確化するとともに、サービスの性能や品質についての現状を可視化しながら運用することによって、安定稼働と機能追加の緊張関係をある程度緩和することができます。 MiiTel AccountにおけるSLO ではMiiTel Accountでは、実際にどのようなSLOを設定しているのでしょうか。 MiiTelではモニタリングツールとしてDatadogを活用しており、ここで今は以下のような目標値を設定しています。 総リクエスト数における5XXエラーの割合が0.2%以内 レスポンスタイムの平均値が3秒以内 *いずれも直近90日以内の99.9%以上で上記を満たすこと かなりシビアな数字ではありますが、2023年10月現在の実績値としてはエラーの割合のほうが99.999%、レスポンスタイムの方は100%と目標を達成しています。エラーバジェットにもかなりゆとりがあるため、ある程度積極的な機能開発ができる状態を保てています。 SLO API errors - past 90 days SLO slow response - past 90 days Datadogは、 APM (Application Performance Monitoring) を入れておけばSLOの設定も容易で、こういったモニタリング数値なども自動で計算してくれて、アラートの設定も思いのままなので非常に便利です。 SLO 達成に向けた取り組み SLOを保つためには、様々な取り組みや運用上の工夫が必要です。ここからは、MiiTel Accountでの取り組みの一部を紹介します。 各種メトリクス・モニタリングアラートの設定 まず簡単にできてかつ効果が高いものとして、メトリクスやモニタリングアラートの設定があります。これは色々なツールで実現できますが、上記のとおりRevCommではDatadogを監視ツールとして使っています。 リクエスト数に異常値があった場合や、AWSなどのインフラのメトリクスが通常より逼迫している場合などに、閾値を設定してSlackなどにアラートを送るように設定することができます。 docs.datadoghq.com Datadog memory usage alert Datadog request count alert またDatadogでは、簡易的なシナリオを作ってE2Eテストを定期実行することができるため、これを活用してログイン機能が正常に動いているかどうかをヘルスチェック的に運用しています。 アラートを設定する場合は、本番環境とそれ以外の環境の通知チャンネルを分けておくと、至急対応が必要なものかどうかわかりやすく、開発環境のアラートで埋もれてしまうことも避けられるのでおすすめです。 定例ミーティングでのメトリクスチェック MiiTel Accountチームでは週に2回の定例ミーティングを行っており、タスクの進捗状況や相談・共有事項などについて会話します。 普段からSLOや各種メトリクスについて意識するため、ミーティングの冒頭で毎回DatadogのSLOダッシュボードをチェックしています。 SLO dashboard - Datadog Datadog APMを設定しているとダッシュボードが確認でき、リクエスト数やエラーレート、レイテンシーなどの値が時系列で一覧できるため、サービスの現状を把握するために非常に有効です。 場合によってはAPIエンドポイントごとのリクエスト数の推移や、レスポンスタイムなどを分析して、改善が必要な場合にこのデータを元に効果的な施策を検討することもあります。また、ときにはこの定例ミーティングでのチェックから異常が見つかることもあります。 Anomaly requests これは、過去に何度かこのブログでも登場している Shota Kokado (@skokado) (過去記事: Amazon Inspectorによるプラットフォーム診断とコンテナイメージ改善の取り組み - RevComm Tech Blog ) が気づいてくれた事例です。 このときはまだ前述のリクエスト数アラートを設定していなかったのですが、定例ミーティングでのダッシュボードチェックで通常時の10倍ほどの異常なリクエスト増が確認されました。 Webサーバーのオートスケーリングなどのおかげでサービスへの顕著な影響はなく、結果的にはWAFなどのブロックによって対応できました。もしすぐに発見されていなければ、どこかでインフラのリソースが逼迫してサービスに影響が出ていた可能性があります。 リリース後のインテグレーションテストと E2E テストの自動化 監視やモニタリングを充実させることも重要ですが、一方で障害の多くはリリース直後に起きることが多いです。また、実環境やデータベースを使わないとユニットテストでは気づけないようなバグなどが混じっていることもあります。 MiiTel Accountではこういったリスクを低減するため、リリース後のAPIインテグレーションテストとE2Eテストを自動実行するようにしています。これは各環境 (大きく分けて3つの環境があります) ごとに設定しており、本番リリース前に予期しないバグなどが起きていないかどうか確認することができます。 インテグレーションテスト: ほぼ全APIエンドポイントへの正常系テスト E2Eテスト: Autifyを使ったクリティカルな機能のUIテスト テストが完了すると、それぞれ以下のようにSlackに通知が来ます。 E2E testing result このあたりの自動実行の仕組みは Raman Yachi (@r-ym) が構築したもので、最近ブログにまとめてくれているので、詳細はこちらをご覧ください。 E2E Testing system for MiiTel Account - RevComm Tech Blog (English) MiiTel AccountチームのE2Eテスト自動化 - RevComm Tech Blog (日本語) この仕組みによって手作業で動作確認する手間がかなり省けたため、より安全かつ心理的な負担も少ない中でリリースが行えるようになりました。 これらのテストで安全性がかなり担保されるようになったため、元々週次夜間に行っていたリリース作業を現在は日中随時に行うよう切り替えています。 デプロイ頻度はDevOps Research and Assessment (DORA) のFour keys metricsでも特に重要視されている指標なので、SLOだけではなく開発生産性という意味でも大きな意味がある施策だったと考えています。 今後に向けて 以上のような施策によって、幸運にも今のところはSLOを達成したうえでさらに高い水準の指標をキープできています。 Webシステムを運営していく以上は障害やサービスのパフォーマンスが一時的に落ちることは避けられない面もありますが、これまで述べてきたような施策によってこのリスクをコントロールしつつ、高い生産性を保って新機能開発を続けていくこともできるはずです。 今後はSLOを保ったまま、さらに指標を充実させてより詳細なサービスのヘルスチェックができるようになったり、開発生産性を向上させていくことを目指しています。 RevCommでは機能開発だけではなく、こういった運用面の知見を深めたり新しい取り組みを行う機会が豊富にあります。興味がある方は、下記から採用情報をチェックしてみてください。 www.revcomm.co.jp
アバター
RevComm Research Dept. Development Groupの高橋典生です。先日開催された、NIKKEI Tech Talkの 【日経×コドモン×RevComm】サービスの安定性、信頼性を高めるDevOps/SREの取り組み に登壇しましたので、紹介させていただきます。 NIKKEI Tech Talkとは NIKKEI Tech Talkとは、日本経済新聞社 CDIO室が開催する技術勉強会です。毎回テーマを変えて様々なトピックで開催されています。私が登壇したのは以下の回でした。 nikkei.connpass.com これ以後も、 nikkei.connpass.com nikkei.connpass.com と興味深いラインナップで続いてますので、興味があればぜひご参加ください。 発表内容の概要 Feature Flagを私のチームで導入した経験を踏まえて、どのように検討、導入、運用したかという点についての説明が発表の大まかな内容です。 私の所属するRevComm Research Dept. Development Groupというチームは、研究開発の部門の中にあります。 「機械学習の研究成果を製品に組み込み、ユーザーに価値を届ける」 というのがチームのミッションの一つになっています。RevCommは音声解析分野の機械学習の研究を社内で続けており 1 、そういった研究成果を MiiTelの製品群に組み込み、ユーザーに新たな価値を提供し続けられるように努めています。したがって、私のチームが開発するサービスの多くは機械学習を使ったサービスになります。 こういった背景の中、機械学習サービス固有の機能・非機能面の不確実性への対応をとりつつ、他のチームの開発に依存せず開発が継続できるようにするためにFeature Flag を導入しました。このあたりのモチベーションは、 こちらのスライド 付近にまとめています。また、そもそもFeature Flagと言ってもその役割や性質に応じて質的に異なるものと認識した方が良いということを検討フェーズで学びました。この点は 「Feature Flagって4種類あんねん」 というキーワードとともにMartin Fowlerの引用を元に こちらのスライド 以降にまとめています。最後のハイライトは導入後の運用面です。Feature Flag導入後、使わなくなったFeature Flagを消すための工夫に関して こちらのスライド にまとめました。 スライドの最後にも書きましたが、今後はA/Bテストや全社的な切り替えをPdMが行えるような仕組みに発展させていく可能性があるので、ここで検討した内容を踏まえ、よりユーザーに価値を安定的に届けていける形を目指そうと思います。 登壇資料はこちらにアップロードされていますので、ご興味のある方はご覧ください。 speakerdeck.com チームに仕組みを入れてDevOpsを加速させる RevComm Researchでは、SREというロールはなく 、EM(Engineering Manager) を除くIC(Individual Contributor) 個々人が主体となって、SRE的な視点を持ってDevOpsの改善を図っています。 最近では、Platform Engineeringというキーワードもよく目にするようになりました。もちろん、大規模な組織の場合Platform Engineer(or SRE) 専任、のようなパターンはありますが、そのようなパターンであっても(社外の) ユーザーの使うアプリケーションを作っている開発者がSRE的な視点を意識する ことがより良い DevOpsの改善に重要 だと私は考えています。 とはいえ、「ちゃんとDevOpsやっていこう」という精神論だけでは、再現性もないですし、チームとしてうまく行動することができません。そうならないためには、 チームに仕組みを入れる 必要があります。私のチームでは、 「小さな改善活動」 というルールがあり、それがDevOpsを推進する仕組みの一例になっています。チームとしてのコミットメントは最優先なものの、チームの合意が必要になるような大きな変更でなければ、自由にこういった運用の改善、バグの修正、CI/CDの改善などを行うことができます。Feature Flagの対応もこの「小さな改善活動」の中から生まれたものでした。 登壇のメリット RevCommではDevRelを支えてくださっている方もいらっしゃいますし、個人的にもこういった登壇の機会はメリットが大きいのでどんどん挑戦しようと考えています。 こういった場での発表を行うことで、知っていることを共有して、知らないことを共有してもらうことができます。ソフトウェアの進化の歴史がまさしくそうであったように、これはソフトウェアエンジニア全体の利益になると思います。 あまり意識されない登壇者のみのメリットもあります。発表内容に詳しくなるのはもちろんですが、私はここで、別の点も強調したいと思います。まずは、社内に閉じた専門知識を世の中における一般的な水準で位置付ける良い機会になります。これによって、視野が広くなり、社内の問題解決にも新たな視点で対応できる可能性が増えます。また、発表することで、良い点・悪い点を指摘してもらうことができます。これにより自分一人では思いつかなかった観点での考えを知ることができ、より深く技術を見つめることができます。 こういった場は大好きなので、今後も発表したり参加者として楽しんだりできればうれしいなと思っています。 以下は発表後の最後の締めの様子です(みんな楽しそう) 発表後の Zoom の様子 最後に 最後にNIKKEI Tech Talkの参加者のみなさま、運営者・登壇者のみなさま、社内でDevRel対応をしてくださった方、レビューしてくださった方に感謝の意を示して締めさせていただきます。 我々は “コミュニケーションを再発明し、人が人を想う社会を創る” というミッションを掲げて日々励んでいます。そのためにはたくさんの優秀な仲間が必要です。今回のこういった活動を見て、RevCommに興味を持ってくださった方は 採用ページ もぜひご確認いただけると幸いです。 「Forbes AI 50 2023」に選出 アジアで唯一、最も有望なAI活用企業として表彰されました ( https://prtimes.jp/main/html/rd/p/000000158.000037840.html ) ↩
アバター
2023年10月27日(金)〜28日(土)に開催される PyCon APAC 2023 に RevComm のエンジニアの陶山 嶺と小門 照太と松土 慎太郎が登壇します。 イベント概要 https://2023-apac.pycon.jp/ 公式サイトより引用 https://2023-apac.pycon.jp/ PyCon APACは、プログラミング言語「Python」を中心としたボランティアによる非営利の年次カンファレンスです。このカンファレンスの目的は、Pythonプログラミング言語とその周辺技術を探求し、議論・実践できる場を提供することです。運営チームは、アジア太平洋地域における国または地域が主体となり、現在では、シンガポール、マレーシア、インドネシア、フィリピン、タイ、韓国、香港、ベトナム、日本、台湾、インド、バングラデシュが毎年交代して開催され、2023年は日本のメンバーが主体となり運営します。そして、日本での開催は2013年以来の10年ぶりとなります。 日程: 2023年10月27日(金)~28日(土) 会場 TOC有明コンベンションホール 参加申し込みはこちら 主催: 一般社団法人 PyCon JP Association 登壇情報 Pythonはどのようにデータベースと繋がるのか Webアプリケーション開発で何気なく使っているO/Rマッパーやデータベースアダプタのライブラリはとても便利です。 数々のライブラリが、我々がプログラムとネットワークはどのように繋がっているのかを考える必要なくデータベースと繋がることを助けてくれています。 このトークでは、ソケット通信でつながる方法を深掘りしていく他、複数のライブラリでの実現方法、PEP249で決められているルール、非同期処理をどのように実現しているか、最新のO/Rマッパーやデータベースアダプタのライブラリ事情などを紹介していきます。 日時: 2023年10月27日(金) 13:40~13:55 登壇者: Shintaro Matsudo リンク: https://2023-apac.pycon.jp/timetable?id=8XZDC7 Pythonで一歩踏み出すバイナリの世界 コンピュータの世界はゼロとイチで成り立っています。 この文章もPythonのロゴ画像もみなさんが書いているプログラムもすべてゼロとイチで表現されています。 ということはみなさん知っているでしょう。 しかし、そのことを意識したことがなかったり、「バイナリ」や「バイト列」という言葉に苦手意識を感じる方も多いのではないでしょうか。 本セッションでは、Pythonの対話モードやprint()、structモジュールなどを使ってバイナリの世界を覗いてみます。 バイナリに慣れるとより深くコンピュータを知ることができ、目の前の世界が一気に広がります。 本セッションを通じて、その最初の一歩を踏み出しましょう。 日時: 2022年10月28日(土) 11:30~12:00 登壇者: Rei Suyama リンク: https://2023-apac.pycon.jp/timetable?id=QEHREX あなたのアプリケーションを本番システムで動かすために Webアプリケーションの開発と運用において必要な知識は多岐に渡ります。 フレームワークの使い方を覚えることはもちろん重要ですが、開発したアプリケーションは本番システムにリリースして実際に稼働することになります。 そして、リリースしたシステムは継続的に運用していく必要があります。 このセッションでは、本番システムでの運用を見据えたアプリケーション開発に必要な知識や勘所を紹介します。 日時: 2022年10月28日(土) 14:10~14:40 登壇者: Shota Kokado リンク: https://2023-apac.pycon.jp/timetable?id=FHTQDR 最後に RevComm は電話営業や顧客応対を可視化する音声解析AI搭載型のクラウドIP電話「MiiTel(ミーテル)」を開発しています。 プロダクトの開発において Web アプリケーション、機械学習/深層学習などの領域で Python が広く使用されています。 「コミュニケーションを再発明し人が人を想う社会を創る」というミッションを達成するべく、一緒にプロダクトを開発して頂けるエンジニアを募集しています! hrmos.co
アバター