TECH PLAY

NTTドコモビジネス

NTTドコモビジネス の技術ブログ

613

はじめに 皆様こんにちは。イノベーションセンター SkyWay DevOps プロジェクト所属の @sublimer です。 私達のチームは、1月31日に新しいSkyWayをリリースしました。 skyway.ntt.com 新しいSkyWayでは、公式サイトや、アプリケーションを管理するコンソールも全く新しいものとなっています。 今回は、新しいSkyWayの公式サイトやコンソールの死活監視に利用している、Google Cloudの「稼働時間チェック」機能についてご紹介します。 稼働時間チェックとは 稼働時間チェックは、Google CloudのCloud Monitoringが提供している機能の1つです。 予め設定したエンドポイントに対して、HTTP・HTTPS・TCPのいずれかのプロトコルで定期的にリクエストを送り、そのレスポンスがアラート条件を満たした場合に通知してくれるサービスです。 監視対象のエンドポイントはURLやIPアドレスでも設定できるので、Google Cloud以外の環境に対して監視したい場合でも活用できます。 稼働時間チェックの特徴として、アラート条件を柔軟に設定できる点が挙げられます。 単純にステータスコード等をチェックするだけでなく、レスポンスのJSONの特定のキーが予め指定された値になっているか等の条件も設定できます。 また、比較的大きめの無料枠が提供されている点も特徴として挙げられます。 稼働時間チェックは、1,000回の実行につき$0.30という料金設定ですが、Google Cloudのプロジェクト1つあたり100万回の実行まで毎月無料で利用できます。 cloud.google.com 3つのリージョンから毎分チェックを実行した場合の1ヶ月間の実行回数は、 3リージョン x 60分 x 24時間 x 31日 = 133,920回なので、だいたい7個のエンドポイントに対して無料でチェックができます。 稼働時間チェックの設定方法 監視対象の設定 稼働時間チェックは、以下のURLから設定できます。 https://console.cloud.google.com/monitoring/uptime/create 基本的には入力欄を埋めていくだけで設定が完了するのですが、一点だけ注意点があります。 設定画面の「More target options」をクリックするとより詳細な設定画面が表示されるのですが、「Regions」の設定はデフォルトで「グローバル」となっています。 Regionsは、最低3箇所、最大6箇所の範囲で自由に決めることができます。 実行回数はリージョン数との掛け算で決まるため、無料枠の範囲内に収めるためには3リージョンを設定するのが望ましいです。 今回は、以下の画像のように、アジア太平洋(シンガポール)、ヨーロッパ(ベルギー)、米国(オレゴン)を設定しました。 レスポンスの検証の設定 レスポンスの検証の設定画面は以下の画像のようになっています。 ここでは、以下の項目を設定しています。 タイムアウト時間は10秒 レスポンスのJSONの status というキーの値が "OK" と完全に一致すること レスポンスのステータスコードが200であること したがって、10秒以内にステータスコード200で、 status というキーの値が "OK" のJSONがレスポンスとして返されていれば正常と判定されます。 コンテンツマッチの設定は、上記のJSON Pathによるものの他、特定の文字列が含まれているかどうかや正規表現によるチェックもできます。 なお、JSON Pathで指定したキーについて文字列で値が返される場合は、Response Contentの設定は、ダブルクオーテーション ( " ) を含めて設定する必要があります。 通知先の設定 「アラートと通知」の設定画面では、アラートの通知先を設定できます。 稼働時間チェックの通知先は、「通知チャンネル」として予め設定した通知先の中から選択できます。 通知チャンネルには、SlackやEmailの他、Cloud Pub/SubやPagerDutyを設定することもできます。 今回はSlackを通知先として設定することにしました。 ここまで設定できたら、最後に確認画面で「TEST」ボタンを押し、正しくレスポンスのチェックができているかを確認します。 アラートのカスタマイズ Slackの通知メッセージの変更 Slackに通知されるメッセージの内容は、以下のURLからアラートポリシーを開き、編集画面の「通知と名前」から変更できます。 https://console.cloud.google.com/monitoring/alerting 今回は、チャンネル全体へのメンションと、いくつかのラベルを表示させるため、以下のように設定しました。 <!channel> ${policy.display_name} Checker Location: ${metric.label.checker_location} Target Host: ${resource.label.host} Slackの @channel のメンションは、 <!channel> で設定できます。 メッセージ内で利用できる変数は、以下のドキュメントに記載されています。 cloud.google.com リクエスト送信元ごとのアラート条件を設定する アラートポリシーの設定画面で「時系列のグループ化の基準」に checker_location を追加すると、稼働時間チェックのリクエスト送信元ごとに条件判定ができるようになります。 動作確認 動作確認として、あるリージョンからのリクエストのみを受け付けないようにして、正常に通知が行われるかを確かめます。 今回、チェック対象は私の自宅にあるWebサーバーとしたので、Webサーバーのnginxで ASIA_PACIFIC からのリクエストを拒否するように設定します。 稼働時間チェックの送信元IPアドレスの一覧は、以下のURLの「稼働時間チェックを作成」の左隣にある下向き矢印をクリックするとダウンロードできます。 https://console.cloud.google.com/monitoring/uptime テキストファイルとしてダウンロードされますが、中身はJSONのファイルなので、jqを使ってシュッと ASIA_PACIFIC のIPアドレスだけ抜き出します。 cat uptime-source-ips.txt | jq -c '.[] | select(.region == "ASIA_PACIFIC").ipAddress' -r あとは、これらのアドレスをnginxの設定ファイルで以下のように追記すれば、 ASIA_PACIFIC からのリクエストのみを拒否する設定ができます。(IPアドレスは例示用のダミーの値です。) deny 203.0.113.1; deny 203.0.113.2; deny 203.0.113.3; deny 203.0.113.4; deny 203.0.113.5; deny 203.0.113.6; deny 203.0.113.7; deny 203.0.113.8; deny 203.0.113.9; allow all; nginxの設定変更後、少し経つと以下のようなアラート通知がSlackに送られるはずです。 おわりに 新しいSkyWayの公式サイトやコンソールの死活監視に利用している「稼働時間チェック」機能について、設定例も交えながら紹介しました。 今回、新しいSkyWayにおいて死活監視をどのように行うかを検討する上で様々なSaaSについて比較検討を行いましたが、チェックのリクエストを送る間隔の短さや監視設定の柔軟さという点で、稼働時間チェックが一番使いやすい印象を受けました。 シンプルな死活監視であれば比較的簡単に設定ができるので、とりあえずお手軽に死活監視をしたい場合は稼働時間チェック機能を使ってみてはいかがでしょうか? 稼働時間チェック機能には設定可能な項目がいろいろあるので、ある程度凝った監視をしたい場合でも役立つのではないかと思います。 稼働時間チェック機能でしっかり監視をしている新しいSkyWayを、ぜひ使ってみてください!! 参考サイト Create public uptime checks  |  Cloud Monitoring  |  Google Cloud List uptime-check server IP addresses  |  Cloud Monitoring  |  Google Cloud Using Markdown and variables in documentation templates  |  Cloud Monitoring  |  Google Cloud
はじめに こんにちは、イノベーションセンターの鈴ヶ嶺です。 普段はクラウドサービスをオンプレミス環境でも同様のUI/UXで使用を可能とするハイブリッドクラウド製品の技術検証をしています。 過去に我々はAWS Outposts ラックの検証内容を公開しました。 engineers.ntt.com 今回本記事では、新たに導入したAWS Outposts サーバーの仕様、導入方法、利用方法について徹底解説します。 AWS Outposts とは AWS Outpostsは、AWSのハイブリッドクラウド製品です。オンプレミス上に製品を設置してPublic AWSと同じような操作性でインフラストラクチャとサービスを作成できます。 主なユースケースは次の4つのケースが想定されます。 低レイテンシーコンピューティング 最寄りのパブリッククラウドサーバーでは通信遅延要件を満たさない場合、近距離地点にAWS Outpostsを設置することで低遅延な高速処理を実現できます。 データレジデンシー 規制や情報セキュリティ上の理由から特定の所在地に保存する必要があるデータ(例えば金融・ヘルスケア情報など)について、AWS Outpostsを利用することでデータの常駐場所の制御を可能とします。 移行とモダナイゼーション 移行が難しいオンプレミスのレガシーシステムについて、クラウドへの移行準備ができるまでのホスティング先として利用できます。AWSへの接続性を活用して、クラウド移行を計画し、完了できます。 ローカルデータ処理 ローカルでプライベート処理することでセキュリティ上のリスクを低減します。コストやネットワーク帯域幅の問題により従来では処理不可能なデータセットを処理可能です。 Public AWSとAWS Outpostsの関係を示した図が次のようになります。物理的には独立していますが、論理的にはVPCを共有しAWS Outposts上にSubnetが作成されるような形式となります。また、コントロールプレーンは既存のPublic AWSのコンソールやAPIから利用します。つまり各拠点にAWS環境が延伸されるようなものとして考えるとわかりやすいかと思います。 2023年3月時点ではAWS Outposts ファミリーには以前紹介した AWS Outposts ラック と今回新たに紹介する AWS Outposts サーバー の2つがメンバーとして存在しています。 AWS Outposts サーバーとは 引用(OGP): https://aws.amazon.com/jp/blogs/news/new-aws-outposts-servers-in-two-form-factors/ AWS Outposts サーバーはAWS Outposts ラックとは異なり、1Uもしくは2Uの専用サーバーをデータセンターなどのオンプレミス環境に設置して使用します。 今までの「ラック」は、データセンターなどへの持ち込みラックの設置準備やサーバーに比べると高い使用料金が課題でしたが、サーバ型はそれらの課題を解消したモデルになっていると思われます。 ラックとサーバの価格設定の詳細については以下の詳細を参照してください。 AWS Outposts サーバーの価格設定 AWS Outposts ラックの料金 以下がAWS Outposts サーバーでサポートされるサービス一覧です。 AWS Outposts サーバーでサポートされるサービス一覧 Amazon EC2 Amazon ECS AWS IoT Greengrass Amazon Sagemaker Edge Manager Amazon Virtual Private Cloud また、次のようにAWS Outposts ラックではサポートされていた機能が一部サーバーではサポートされていないためそれぞれの違いに注意が必要です。 AWS Outposts サーバーではサポートされていないサービス一覧 Amazon Elastic Kubernetes Service (EKS) Amazon Simple Storage Service (S3) Amazon Relational Database Service (RDS) Amazon Elasticache Amazon EMR フォームファクタ 次の表が、2023年3月時点で利用可能なサイズ一覧です。 プロセッサにはx86やArm/Graviton2などのアーキテクチャが選択可能です。特にArm/Graviton2については低消費電力が大きな特徴のため、電力制約の規制が厳しいエッジ環境への設置やカーボンニュートラルへの取り組みにおける活用が期待されます。 Outpost リソース ID ラックユニットの高さ EC2 容量 プロセッサ/アーキテクチャ vCPU メモリ ローカル NVMe SSD ストレージ ネットワークアップリンク 消費電力 重量 電源タイプ OR-STBKRBE 1U c6gd.16xlarge Graviton2 / Arm 64 128 GiB 3.8 TB 10 Gbps 0.8 kVA 13 kg AC OR-LMXAD41 2U c6id.16xlarge インテル Ice Lake/x86 64 128 GiB 3.8 TB 10 Gbps 1.5 kVA 16 kg AC OR-KOSKFSF 2U c6id.32xlarge インテル Ice Lake/x86 128 256 GiB 7.6 TB 10 Gbps 1.5 kVA 16 kg AC ネットワーク設計 AWS Outposts サーバーはPublic AWSと接続する管理系のリンクであるservice linkとローカル環境と接続するためのlocal network interface (LNI) linkがあります。次の図のように付属のQSFPブレイクアウトケーブルを利用しラベル1をLNI linkとして使用し、ラベル2をservice linkとして使用します。ラベル3-4のケーブルについては現時点では未使用となります。 引用: https://docs.aws.amazon.com/outposts/latest/server-userguide/install-server.html#install-network 次の図がネットワークの概要図です。 まずservice linkを用いてサーバーをアクティベートする必要があります。AWS Outposts サーバーには固定IPアドレスを設定する方法がないため、service linkにDHCPを用いてIPアドレスを設定します。その後、シリアル接続したコンソールから outposts.[設置region].amazonaws.com エンドポイントへの疎通確認やIAM認証情報を用いてAWSと接続することでアクティベートが完了します。 1 ローカル環境と接続されるLNI LinkはNetwork Interfaceに紐づく形で利用されます。利用するためには、まずAWS Outposts サーバー上のSubnetでLNIとして利用するNetwork Interface Indexを設定します。その後新たにNetwork Interfaceを作成し、該当のIndexとしてアタッチしてIPアドレスを設定することでローカル環境と接続できるようになります。実際の利用方法は後述するEC2の起動検証でも詳しく説明します。 引用: https://docs.aws.amazon.com/outposts/latest/server-userguide/local-network-interface.html EC2の起動検証 AWS CLIベースで次の一連の処理を行いEC2の起動を検証します。 VPCの作成 AWS Outposts Subnetの作成 SubnetのLNI有効化 EC2 Instanceの起動 user-dataによるLNI NetworkのIPアドレスとデフォルトルートの設定 ローカル環境との疎通確認 # 事前設定 ## AWS Outposts サーバーARN OUTPOST_ARN = ' arn:aws:outposts:ap-northeast-1:XXXXXXXXXXXX:outpost/op-XXXXXXXXXXXXXXXX ' ## sshのためのkeypair KEYPAIR = ' XXXXX ' ## AWS Outposts サーバーのLNI Network(ローカル環境のNetwork)を192.168.10.0/24と想定 OUTPOST_LNI_EC2_IP = ' 192.168.10.2 ' OUTPOST_LNI_SUBNET = ' 24 ' OUTPOST_LNI_GATEWAY_IP = ' 192.168.10.1 ' # 1. VPCの作成 VPC_ID = $( aws ec2 create-vpc --cidr-block 10 . 0 . 0 . 0 / 16 \ --tag-specifications " ResourceType=vpc, Tags=[{Key=Name,Value=Outposts-Server-VPC}] " \ --query Vpc.VpcId --output text ) # 2. AWS Outposts Subnetの作成 SUBNET_ID = $( aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 10 . 0 . 1 . 0 / 24 \ --availability-zone ap-northeast-1a --outpost-arn $OUTPOST_ARN \ --tag-specifications " ResourceType=subnet, Tags=[{Key=Name,Value=Outposts-Server-Subnet01}] " \ --query Subnet.SubnetId --output text ) # 3. SubnetのLNI有効化 aws ec2 modify-subnet-attribute --subnet-id $SUBNET_ID --enable-lni-at-device-index 1 # 4. EC2 Instanceの起動 ## Security Group作成 SG_ID = $( aws ec2 create-security-group --group-name Outposts-Server-SG \ --description " Default Security group " --vpc-id $VPC_ID \ --tag-specifications " ResourceType=security-group, Tags=[{Key=Name,Value=Outposts-Server-SG}] " \ --query GroupId --output text ) ## Ubuntu22.04の最新AMIを取得 UBUNTU_AMI = $( aws ec2 describe-images --owners 099720109477 \ --filters " Name=name,Values=ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64* " \ --query " reverse(sort_by(Images, &CreationDate))[0].ImageId " --output text ) ## 4.1 user-dataによるLNI NetworkのIPアドレスとデフォルトルートの設定 cat << EOF > user-data.txt #!/bin/bash set -xe # 固定IPの設定 ip addr add $OUTPOST_LNI_EC2_IP / $OUTPOST_LNI_SUBNET dev ens6 # デフォルトゲートウェイの設定 ip route add default via $OUTPOST_LNI_GATEWAY_IP EOF ## ENI作成 ENI_ID0 = $( aws ec2 create-network-interface --subnet-id $SUBNET_ID --groups $SG_ID \ --tag-specifications " ResourceType=network-interface, Tags=[{Key=Name,Value=Outposts-Server-ENI0}] " \ --query NetworkInterface.NetworkInterfaceId --output text ) ENI_ID1 = $( aws ec2 create-network-interface --subnet-id $SUBNET_ID --groups $SG_ID \ --tag-specifications " ResourceType=network-interface, Tags=[{Key=Name,Value=Outposts-Server-ENI1}] " \ --query NetworkInterface.NetworkInterfaceId --output text ) ## EC2 Instance作成 INSTANCE_ID = $( aws ec2 run-instances --image-id $UBUNTU_AMI --instance-type c6id.8xlarge \ --key-name $KEYPAIR --user-data file://user-data.txt \ --network-interfaces " [{ \" DeviceIndex \" :0, \" NetworkInterfaceId \" : \" $ENI_ID0 \" },{ \" DeviceIndex \" :1, \" NetworkInterfaceId \" : \" $ENI_ID1 \" }] " \ --tag-specifications " ResourceType=instance, Tags=[{Key=Name,Value=Outposts-Server-Instance}] " \ --query ' Instances[0].InstanceId ' --output text ) # 5. ローカル環境との疎通確認 ssh ubuntu@ $OUTPOST_LNI_EC2_IP 作成したEC2は次のスクリーンショットのようにAWS Management Consoleから確認できます。 EC2の画面からはPublic AWSかAWS Outposts サーバーのインスタンスかを判断できないためSubnetを確認します。 次のようにSubnetの詳細画面を見るとOutpost IDが紐づいていることが分かるため、AWS Outposts サーバーのインスタンスが正常に起動していることを確認しました。 また、LNIを有効化したネットワークインターフェイスはインターフェイスのタイプが「ローカルネットワークインターフェイス」と記述されていることが分かります。 ちなみに 5. ローカル環境との疎通確認 でSecurity Groupのインバウンド設定をしていないのになぜsshでEC2と疎通できるのか気になった方もいると思います。 これは以下のようにLNIはSecurity Groupを利用しない仕様のためです。 セキュリティグループとローカルネットワークインターフェイス 設計上、ローカルネットワークインターフェイスは VPC 内のセキュリティグループを使用しません。セキュリティグループは、インバウンドとアウトバウンドを制御します。VPC トラフィック。ローカルネットワークインターフェイスは、VPC にアタッチされていません。ローカルネットワークインターフェイスは、ローカルネットワークにアタッチされています。ローカルネットワークインターフェイスでインバウンドおよびアウトバウンドトラフィックを制御するには、他のオンプレミス機器でファイアウォールまたは同様の戦略を使用します。 引用: https://docs.aws.amazon.com/ja_jp/outposts/latest/userguide/how-servers-work.html まとめ 本記事では AWS Outpostsについて AWS Outposts サーバーについて EC2の起動検証 について記載しました。 AWS Outposts サーバーは省スペースや電力規制が厳しい状況においても設置可能な新たなAWSのハイブリッドクラウド製品です。AWS環境をエッジに延伸しクラウドと同様の開発体験で低遅延処理やセキュリティ課題を解決する場合にはこれを機に AWS Outposts サーバーの利用を検討してみてはいかかでしょうか? https://docs.aws.amazon.com/ja_jp/outposts/latest/userguide/install-server.html#authorize-3 ↩
はじめに こんにちは、NTTコミュニケーションズの現場受け入れ型インターンシップに参加した奥です。 現在は大学でLinuxマルウェアの動的解析について研究しています。 今回私は2023年2月6日から2月17日の2週間、イノベーションセンターのNetwork Analytics for Security(通称NA4Sec)プロジェクトに参加し、 Cobalt Strikeを悪用した攻撃事例の調査、またCobalt Strikeのペイロード配布に利用される攻撃インフラの発見・追跡を体験しました。 この記事では、インターンシップ参加の経緯やインターンシップ期間中に取り組んだ内容について紹介します。 インターンシップ参加の経緯 私がこのインターンシップに応募したのは、夏に他社のインターンシップに参加した際に、他の学生たちがNTTのインターンシップを推していた記憶があり、応募しておけばよかった..と悔やんでいたためです。 後に調べてみると、冬季インターンシップも2週間という期間にわたって現場での業務体験ができ、セキュリティ分野だけでも様々な内容のポストがあることを知り、充実した経験ができると確信を持って応募しました。 しかし、実際に選考を受けてみると「私はただものではない」エピソードがないことに悩まされたり、インフラ関係のポストに応募したにもかかわらず、ネットワークの知識が全然ないことに不安を覚えたりしました。 そんな時、一次面接でNA4Secプロジェクトリーダーの神田さんとお話しし、とても穏やかな雰囲気の中、プロジェクトやインターンシップで取り組む内容について詳しく聞けました。一次面接は人事の方が担当することが多いイメージでしたが、初めに現場の方とお話しし、インターンシップの具体的なイメージができたことは、選考を受ける中で大きなモチベーションとなりました。 NA4Secプロジェクトとは 私が参加したNA4Secプロジェクトとは、「NTTはインターネットを安心・安全にする社会的責務がある」を理念として、攻撃インフラの解明、撲滅を目指すプロジェクトです *1 。 Tier1 ISP(Internet Service Provider)であり、MSSP(Managed Security Service Provider)でもあるNTTの強みを活かし、攻撃インフラを追跡するとともに、解析のための新たな技術を開発しています。 インターンシップで取り組んだこと 2週間で体験したインターンシップの内容をまとめます。 1. Cobalt Strikeの理解 Cobalt Strikeについての知識がなかったため、そもそもCobalt Strikeがどういったもので、なぜ攻撃に使われるのかを理解することからスタートしました。 「 Cobalt Strike 」はサイバー攻撃を再現し、システムや組織のセキュリティを評価するために使用される商用のセキュリティツールです。 一方で、Cobalt Strikeはクラック版(不正利用のために改変されたもの)が出回ったことにより、悪意のある攻撃にも広く利用されています。 主な機能として、システム侵入後に対象システムに Cobalt Strike Beacon (以下、Beacon)と呼ばれるバックドアプログラムを埋め込み、稼働させることでBeaconを介してPowerShellスクリプトの実行や、スクリーンショットの記録、ファイルのダウンロードなどの強力な攻撃モジュールを提供します。また、ネットワーク設定を調整することで通信を秘匿したり、初期アクセスのためのフィッシングメールを作成する機能も備えています。 攻撃者から見た時のCobalt Strikeの魅力として、攻撃技術の洗練度や人的・金銭的リソースの豊富さに関わらず、迅速に攻撃を行えることが挙げられます。また、広く利用されているために、正規のペネトレーションテストとの判別や、攻撃グループの特定を困難にする効果を狙っているケースもあるかもしれません。 2. Cobalt Strikeを悪用した攻撃事例の調査 次に、Cobalt Strikeを悪用した過去の攻撃事例を整理し、 脅威インテリジェンス としてまとめました。 具体的には攻撃グループや攻撃の手口、どういった行動を誰に対して行っているのかといった観点で情報を整理し、そのパターンから活動の背景や動機などを考察しました。 これらの情報を活用することにより、攻撃側が有利なサイバーセキュリティにおいて、防御側は攻撃被害が発生する前により効果的と考えられる対抗手段を取って攻撃に備えることができます。 今回は、攻撃事例の情報を整理するために、 ダイヤモンドモデル というサイバー攻撃のパターン分析手法を用いました。ダイヤモンドモデルは、以下の4つの特徴でサイバー攻撃を定義づけます。 攻撃グループ(Adversary) 攻撃者に関する情報(呼称,アカウント,関連するグループなど) 被害者(Victim) 被害者に関する情報(組織名,システム名,IPアドレスなどのネットワーク資産,デバイス,アカウントなど) 攻撃基盤(Infrastructure) 攻撃に際して使われた基盤(サービスアカウント,IPアドレス,ドメイン名,メールアドレスなど) 能力(Capability) 具体的な攻撃手法やツール(マルウェアやその送信方法,悪用された脆弱性など) 実際に、Cobalt Strikeに関する直近25件の攻撃事例をダイヤモンドモデルに当てはめてみました。情報源としては、 Microsoft Defender Threat Intelligence が無償で得られる情報の範囲でも多くの攻撃事例に対するレポートをまとめてくれており、効率的な情報の収集に役立ちました。 図1 ダイヤモンドモデルに基づき作成した表の一部 調査の結果、Cobalt Strikeは国家のスパイや犯罪グループにも利用されており、大規模な攻撃に使われていることが分かりました。 また、そのような国家を背景とした犯罪グループは、政府機関や重要インフラを狙うことが多く、標的とされる国にも特徴が見られました。 侵入経路としては、フィッシングメールや侵害したWebサイト、または脆弱性を利用することで最初のペイロードをダウンロードさせ、それを使うことでCobalt Strike Beaconを標的システムに配布していました。その後は、Cobalt Strikeの機能を使うことで、権限を昇格したり、特徴的なマルウェアをダウンロードする場合が多く見られました。 3. Cobalt Strike C2サーバの探索 Cobalt Strikeを悪用する攻撃者はインターネット上にTeam Serverと呼ばれるサーバを公開し、Beaconからの通信を待ち受けています。 このようなサーバを一般的にC2(Command & Control)サーバと言います。 インターンシップ後半では、主にインターネットスキャナ系検索エンジンを用いてCobalt Strike C2サーバの発見に挑戦しました。 インターネットスキャナ系検索エンジン 世の中にはインターネット上を定期的にスキャンして得られたデータを検索可能にしている検索エンジンサービスがあります。 例えば Censys は、毎日40億以上のIPv4ホストやWebサイトを定期的にスキャンしており、インターネット上に接続されている機器の情報(OSやソフトウェアのバージョン、IPアドレス、AS、ドメイン名、SSL/TLSサーバ証明書に関する情報)等で検索できます。 今回はCensysの他に Shodan 、 ZoomEye を加えた3つの検索エンジンを用い、それらを比較しました。 検索クエリの作成 膨大なデータベースの中からCobalt Strike C2サーバを見つけるためには、その特徴に合わせて効果的に条件を指定する必要があります。 ここでは、 Censys を用いて検索する方法を紹介します。 SSL/TLSサーバ証明書 最も誤検知を抑えてCobalt Strike C2サーバを探す方法の1つは、SSL/TLSサーバ証明書がCobalt Strikeでよく使われる証明書と一致しているものに絞ることです。 攻撃者がそれらのSSL/TLSサーバ証明書を使用している場合は、この方法で発見できます。 services.certificate: { "64257fc0fac31c01a5ccd816c73ea86e639260da1604d04db869bb603c2886e6", "87f2085c32b6a2cc709b365f55873e207a9caa10bffecf2fd16d3cf9d94d390c" } OR services.tls.certificates.leaf_data.issuer.common_name: "Major Cobalt Strike" OR services.tls.certificates.leaf_data.subject.common_name: "Major Cobalt Strike" 1~3行目 SSL/TLSサーバ証明書のFinger Print 4~5行目 SSL/TLSサーバ証明書の発行元(issuer)と主体者(subject) 実際にこの条件でフィルターをかけたところ、583件のCobalt Strike C2サーバと見られるIPv4ホストを発見できました(3月15日時点)。 図2 SSL/TLSサーバ証明書で絞った検索結果 ポート番号とHTTPヘッダ SSL/TLSサーバ証明書に基づく探索は、確実である反面、カスタマイズされた証明書が使われている場合や、HTTPなどのSSL/TLSで暗号化を行わない通信プロトコルの場合に発見できなくなるという弱点があります。 Cobalt Strike C2サーバのポート番号やHTTPヘッダに見られる特徴を組み合わせることで、そのような場合であってもCobalt Strike C2サーバである可能性の高いIPv4ホストを見つけられます。 services.port: 50050 AND services.http.response.status_code: 404 AND services.http.response.headers.content_type: text/plain AND services.http.response.headers.content_length: 0 AND NOT services.http.response.headers.server 1行目 使用ポートの条件はCobalt Strikeのデフォルトポートである50050ポート 2~5行目 HTTPヘッダの内容 実際に、インターンシップ用に立てられたCobalt Strike C2サーバに対してスキャンしてみたところ、図3の赤枠内のHTTPヘッダを持つレスポンスが得られました。 これは一般的なCobalt Strike C2サーバのHTTPヘッダの特徴と一致しています。 図3 Cobalt Strike C2サーバからのレスポンス 実際にこの条件でフィルターをかけたところ、294件のサーバにヒットしました(3月15日時点)。 それぞれのIPv4ホストについて詳しく見てみると、多くがCobalt Strikeの証明書や自己署名証明書を利用しているなど、攻撃インフラの可能性が十分に考えられるものでした。 図2 ポート番号とHTTPヘッダで絞った検索結果 検体の解析によるC2の発見 Censysにはない機能として、ShodanやZoomEyeはスキャン対象となるサーバからBeaconを入手し、解析することによってCobalt Strike C2サーバかどうかを判定しています。また、以下のように解析結果を得ることも可能です。 Cobalt Strike Beaconの解析結果(Shodan) インターネットスキャナ系検索エンジンの比較 今回用いた3種類のインターネットスキャナ系検索エンジンについて、Cobalt Strike C2サーバを探索する際の長所と短所をまとめます。 情報源 pros cons Censys スキャンしているポートの数が多い(50050ポートの結果を得られる),スキャン頻度が高い Beaconの入手と解析はしていない Shodan Beaconの解析結果が得られる、スキャン頻度が比較的高い スキャンしているポートの数が少ない ZoomEye Beaconの解析結果が得られる スキャン頻度が低い、中国サーバのスキャン結果が表示されない インターンシップを振り返って サイバーセキュリティの最前線で長年戦ってきた方に、2週間の間マンツーマンで指導していただけたことは、本当に贅沢な経験だったと思います。 ネットワークの基礎的な構成技術から、研究で注目している新たな技術まで、幅広く深く触れることのできた密度の濃い2週間でした。 脅威を見定め、能動的に情報を収集して防御に活用する アクティブサイバーディフェンス という、今まで私の中になかった視点を得ることができたこと、 そのための情報収集の方法と活用の仕方を学んだことは、今後サイバーセキュリティの世界で活動していく上で、大きな助けになると思います。 NTTコミュニケーションズの皆さん、神田さん、本当にありがとうございました。 参考文献 C2: When Attackers Use Our Weapons Against Us Hunting Cobalt Strike Servers *1 : NA4Secプロジェクトについては 別のブログ記事 でも紹介しています
はじめに こんにちは、NTTコミュニケーションズの現場受け入れ型インターンシップに参加した奥です。 現在は大学でLinuxマルウェアの動的解析について研究しています。 今回私は2023年2月6日から2月17日の2週間、イノベーションセンターのNetwork Analytics for Security(通称NA4Sec)プロジェクトに参加し、 Cobalt Strikeを悪用した攻撃事例の調査、またCobalt Strikeのペイロード配布に利用される攻撃インフラの発見・追跡を体験しました。 この記事では、インターンシップ参加の経緯やインターンシップ期間中に取り組んだ内容について紹介します。 インターンシップ参加の経緯 私がこのインターンシップに応募したのは、夏に他社のインターンシップに参加した際に、他の学生たちがNTTのインターンシップを推していた記憶があり、応募しておけばよかった..と悔やんでいたためです。 後に調べてみると、冬季インターンシップも2週間という期間にわたって現場での業務体験ができ、セキュリティ分野だけでも様々な内容のポストがあることを知り、充実した経験ができると確信を持って応募しました。 しかし、実際に選考を受けてみると「私はただものではない」エピソードがないことに悩まされたり、インフラ関係のポストに応募したにもかかわらず、ネットワークの知識が全然ないことに不安を覚えたりしました。 そんな時、一次面接でNA4Secプロジェクトリーダーの神田さんとお話しし、とても穏やかな雰囲気の中、プロジェクトやインターンシップで取り組む内容について詳しく聞けました。一次面接は人事の方が担当することが多いイメージでしたが、初めに現場の方とお話しし、インターンシップの具体的なイメージができたことは、選考を受ける中で大きなモチベーションとなりました。 NA4Secプロジェクトとは 私が参加したNA4Secプロジェクトとは、「NTTはインターネットを安心・安全にする社会的責務がある」を理念として、攻撃インフラの解明、撲滅を目指すプロジェクトです *1 。 Tier1 ISP(Internet Service Provider)であり、MSSP(Managed Security Service Provider)でもあるNTTの強みを活かし、攻撃インフラを追跡するとともに、解析のための新たな技術を開発しています。 インターンシップで取り組んだこと 2週間で体験したインターンシップの内容をまとめます。 1. Cobalt Strikeの理解 Cobalt Strikeについての知識がなかったため、そもそもCobalt Strikeがどういったもので、なぜ攻撃に使われるのかを理解することからスタートしました。 「 Cobalt Strike 」はサイバー攻撃を再現し、システムや組織のセキュリティを評価するために使用される商用のセキュリティツールです。 一方で、Cobalt Strikeはクラック版(不正利用のために改変されたもの)が出回ったことにより、悪意のある攻撃にも広く利用されています。 主な機能として、システム侵入後に対象システムに Cobalt Strike Beacon (以下、Beacon)と呼ばれるバックドアプログラムを埋め込み、稼働させることでBeaconを介してPowerShellスクリプトの実行や、スクリーンショットの記録、ファイルのダウンロードなどの強力な攻撃モジュールを提供します。また、ネットワーク設定を調整することで通信を秘匿したり、初期アクセスのためのフィッシングメールを作成する機能も備えています。 攻撃者から見た時のCobalt Strikeの魅力として、攻撃技術の洗練度や人的・金銭的リソースの豊富さに関わらず、迅速に攻撃を行えることが挙げられます。また、広く利用されているために、正規のペネトレーションテストとの判別や、攻撃グループの特定を困難にする効果を狙っているケースもあるかもしれません。 2. Cobalt Strikeを悪用した攻撃事例の調査 次に、Cobalt Strikeを悪用した過去の攻撃事例を整理し、 脅威インテリジェンス としてまとめました。 具体的には攻撃グループや攻撃の手口、どういった行動を誰に対して行っているのかといった観点で情報を整理し、そのパターンから活動の背景や動機などを考察しました。 これらの情報を活用することにより、攻撃側が有利なサイバーセキュリティにおいて、防御側は攻撃被害が発生する前により効果的と考えられる対抗手段を取って攻撃に備えることができます。 今回は、攻撃事例の情報を整理するために、 ダイヤモンドモデル というサイバー攻撃のパターン分析手法を用いました。ダイヤモンドモデルは、以下の4つの特徴でサイバー攻撃を定義づけます。 攻撃グループ(Adversary) 攻撃者に関する情報(呼称,アカウント,関連するグループなど) 被害者(Victim) 被害者に関する情報(組織名,システム名,IPアドレスなどのネットワーク資産,デバイス,アカウントなど) 攻撃基盤(Infrastructure) 攻撃に際して使われた基盤(サービスアカウント,IPアドレス,ドメイン名,メールアドレスなど) 能力(Capability) 具体的な攻撃手法やツール(マルウェアやその送信方法,悪用された脆弱性など) 実際に、Cobalt Strikeに関する直近25件の攻撃事例をダイヤモンドモデルに当てはめてみました。情報源としては、 Microsoft Defender Threat Intelligence が無償で得られる情報の範囲でも多くの攻撃事例に対するレポートをまとめてくれており、効率的な情報の収集に役立ちました。 図1 ダイヤモンドモデルに基づき作成した表の一部 調査の結果、Cobalt Strikeは国家のスパイや犯罪グループにも利用されており、大規模な攻撃に使われていることが分かりました。 また、そのような国家を背景とした犯罪グループは、政府機関や重要インフラを狙うことが多く、標的とされる国にも特徴が見られました。 侵入経路としては、フィッシングメールや侵害したWebサイト、または脆弱性を利用することで最初のペイロードをダウンロードさせ、それを使うことでCobalt Strike Beaconを標的システムに配布していました。その後は、Cobalt Strikeの機能を使うことで、権限を昇格したり、特徴的なマルウェアをダウンロードする場合が多く見られました。 3. Cobalt Strike C2サーバの探索 Cobalt Strikeを悪用する攻撃者はインターネット上にTeam Serverと呼ばれるサーバを公開し、Beaconからの通信を待ち受けています。 このようなサーバを一般的にC2(Command & Control)サーバと言います。 インターンシップ後半では、主にインターネットスキャナ系検索エンジンを用いてCobalt Strike C2サーバの発見に挑戦しました。 インターネットスキャナ系検索エンジン 世の中にはインターネット上を定期的にスキャンして得られたデータを検索可能にしている検索エンジンサービスがあります。 例えば Censys は、毎日40億以上のIPv4ホストやWebサイトを定期的にスキャンしており、インターネット上に接続されている機器の情報(OSやソフトウェアのバージョン、IPアドレス、AS、ドメイン名、SSL/TLSサーバ証明書に関する情報)等で検索できます。 今回はCensysの他に Shodan 、 ZoomEye を加えた3つの検索エンジンを用い、それらを比較しました。 検索クエリの作成 膨大なデータベースの中からCobalt Strike C2サーバを見つけるためには、その特徴に合わせて効果的に条件を指定する必要があります。 ここでは、 Censys を用いて検索する方法を紹介します。 SSL/TLSサーバ証明書 最も誤検知を抑えてCobalt Strike C2サーバを探す方法の1つは、SSL/TLSサーバ証明書がCobalt Strikeでよく使われる証明書と一致しているものに絞ることです。 攻撃者がそれらのSSL/TLSサーバ証明書を使用している場合は、この方法で発見できます。 services.certificate: { "64257fc0fac31c01a5ccd816c73ea86e639260da1604d04db869bb603c2886e6", "87f2085c32b6a2cc709b365f55873e207a9caa10bffecf2fd16d3cf9d94d390c" } OR services.tls.certificates.leaf_data.issuer.common_name: "Major Cobalt Strike" OR services.tls.certificates.leaf_data.subject.common_name: "Major Cobalt Strike" 1~3行目 SSL/TLSサーバ証明書のFinger Print 4~5行目 SSL/TLSサーバ証明書の発行元(issuer)と主体者(subject) 実際にこの条件でフィルターをかけたところ、583件のCobalt Strike C2サーバと見られるIPv4ホストを発見できました(3月15日時点)。 図2 SSL/TLSサーバ証明書で絞った検索結果 ポート番号とHTTPヘッダ SSL/TLSサーバ証明書に基づく探索は、確実である反面、カスタマイズされた証明書が使われている場合や、HTTPなどのSSL/TLSで暗号化を行わない通信プロトコルの場合に発見できなくなるという弱点があります。 Cobalt Strike C2サーバのポート番号やHTTPヘッダに見られる特徴を組み合わせることで、そのような場合であってもCobalt Strike C2サーバである可能性の高いIPv4ホストを見つけられます。 services.port: 50050 AND services.http.response.status_code: 404 AND services.http.response.headers.content_type: text/plain AND services.http.response.headers.content_length: 0 AND NOT services.http.response.headers.server 1行目 使用ポートの条件はCobalt Strikeのデフォルトポートである50050ポート 2~5行目 HTTPヘッダの内容 実際に、インターンシップ用に立てられたCobalt Strike C2サーバに対してスキャンしてみたところ、図3の赤枠内のHTTPヘッダを持つレスポンスが得られました。 これは一般的なCobalt Strike C2サーバのHTTPヘッダの特徴と一致しています。 図3 Cobalt Strike C2サーバからのレスポンス 実際にこの条件でフィルターをかけたところ、294件のサーバにヒットしました(3月15日時点)。 それぞれのIPv4ホストについて詳しく見てみると、多くがCobalt Strikeの証明書や自己署名証明書を利用しているなど、攻撃インフラの可能性が十分に考えられるものでした。 図2 ポート番号とHTTPヘッダで絞った検索結果 検体の解析によるC2の発見 Censysにはない機能として、ShodanやZoomEyeはスキャン対象となるサーバからBeaconを入手し、解析することによってCobalt Strike C2サーバかどうかを判定しています。また、以下のように解析結果を得ることも可能です。 Cobalt Strike Beaconの解析結果(Shodan) インターネットスキャナ系検索エンジンの比較 今回用いた3種類のインターネットスキャナ系検索エンジンについて、Cobalt Strike C2サーバを探索する際の長所と短所をまとめます。 情報源 pros cons Censys スキャンしているポートの数が多い(50050ポートの結果を得られる),スキャン頻度が高い Beaconの入手と解析はしていない Shodan Beaconの解析結果が得られる、スキャン頻度が比較的高い スキャンしているポートの数が少ない ZoomEye Beaconの解析結果が得られる スキャン頻度が低い、中国サーバのスキャン結果が表示されない インターンシップを振り返って サイバーセキュリティの最前線で長年戦ってきた方に、2週間の間マンツーマンで指導していただけたことは、本当に贅沢な経験だったと思います。 ネットワークの基礎的な構成技術から、研究で注目している新たな技術まで、幅広く深く触れることのできた密度の濃い2週間でした。 脅威を見定め、能動的に情報を収集して防御に活用する アクティブサイバーディフェンス という、今まで私の中になかった視点を得ることができたこと、 そのための情報収集の方法と活用の仕方を学んだことは、今後サイバーセキュリティの世界で活動していく上で、大きな助けになると思います。 NTTコミュニケーションズの皆さん、神田さん、本当にありがとうございました。 参考文献 C2: When Attackers Use Our Weapons Against Us Hunting Cobalt Strike Servers *1 : NA4Secプロジェクトについては 別のブログ記事 でも紹介しています
イノベーションセンターの三島です。 本記事では、RFC や Internet-Draft に準拠したコントローラーやプロトコルライブラリの開発について、 NTT Com が公開中の Segment Routing (SR) 用のコントローラー、 Pola PCE の開発経験を基にご紹介します。 商用機器と相互接続可能なコントローラー・プロトコルライブラリを開発してみたい方、SR をはじめとするネットワークを運用中で、機能拡張が可能なコントローラーを導入してみたい方は是非ご覧ください! 以降では、コントローラー開発手順の概要を Pola PCE の実装例を基に解説した後、プロトコルライブラリの作り方と機能追加の方法、相互接続試験と OSS へのマージまでの流れを解説します。 例として扱う Pola PCE 自体の詳細や活用例については解説しないため、詳細を知りたい方は下記の資料をご参照ください。 Pola PCE の開発経緯と OSS 化 Segment Routing 用 Stateful PCE を フルスクラッチで開発した話 NTT Com で OSS を作って公開してみた - やったことリスト共有 PCE・コントローラーの利用例 大規模 SR 網の運用を効率化するネットワークコントローラーの開発 Pola PCE で SR 網の TE を体験してみよう! コントローラー・プロトコルライブラリを作ってみよう! コントローラーはソフトウェアによりネットワークを集中管理する役割を持ち、主に運用やサービス提供の効率化などを目的として用いられます。 特に、大規模商用網のように複数のルーターが存在する環境においては、機器の一元管理による運用コストの低減や、スケーラビリティの高い運用が期待されます。 また、このようなネットワークは複数のベンダーの機器を用いて構成されることもあります。 これらの理由から、本記事では下記のポイントを満たすコントローラーを開発します。 複数のクライアントを収容可能なサーバー セッションごとに状態を管理し、並行処理可能な実装 各ベンダーの商用機器と相互接続可能な、RFC 準拠なプロトコルライブラリ プロトコルの構造や基本的なパケット操作の実装 以降の節では、要件を満たすようなサーバー機能の開発手順と、RFC 準拠なプロトコル実装について解説します。 コントローラーとプロトコルライブラリの開発方法をご紹介するにあたり、SR のコントローラーである Path Computation Element (PCE) を例として用います。 PCE は、SR を初めとする Traffic Engineering (TE) 技術で構成されたネットワークにおいて、TE を管理するためのコントローラーであり、TE により網全体の性能を考慮した QoS の向上や SFC 提供などを実現する役割を持ちます。 サーバー開発の概要 まずは、コントローラーのサーバー機能を開発する上で必要となるソケットプログラミングや並行処理、セッション管理の手法についての概要をご紹介します。 ソケットプログラミングによる TCP サーバー実装 PCEP は TCP ベースのプロトコルであり、TCP ソケットプログラミングが必要となります。 一般的なソケットプログラミングの概要を示します。 図の通り、一般的なソケットプログラミングにおけるサーバー実装では、ソケットを作成する socket 、機器のアドレス・ポートとソケットを紐付ける bind 、当該ポートで TCP の待ち受けを行う listen 、クライアントからの接続を受け入れてセッションを構築する accept という流れで TCP セッションを構成します。 Pola PCE では Go の net パッケージを利用し、 pkg/server/server.go の Serve メソッドとして実装を行なっています。 net.ListenTCP が socket・bind・listen を行い、 ListenTCP の返り値である *TCPListener の AcceptTCP() メソッドにより accept を行います。 並行処理とセッション管理 PCE のようなコントローラーでは、複数のクライアントを管理することが求められます。 そのため、サーバー機能として 並列処理 と セッション管理 の機能が必要となります。 図に Pola PCE の並行処理とセッション管理の実装例を示します。 Pola PCE では、セッションは pkg/server/session.go に実装した Session 構造体を用いて管理を行なっています。 Session 構造体では、セッション管理に必要となるクライアントのアドレスやソケットの情報に加え、SRP-ID や Stateful PCE として管理するクライアントの SR Policy、Keepalive の間隔など、クライアントごとに固有のパラメータを全て管理させています。 並列処理は goroutine により実現しています。 TCP サーバーが AcceptTCP() を実行した後、そのセッションを管理するための Session 構造体を作成します。 その後 goroutine を作成して Session 構造体の Established() メソッドを呼び出し、PCE としてのメッセージ送受信や SR Policy の発行など、そのクライアントに対する PCE 機能を提供します。 この仕組みにより、複数のクライアントを区別しつつ複数収容するコントローラーを構成することが可能となります。 プロトコルライブラリ開発 RFC 準拠のプロトコルライブラリの開発について、Pola PCE への Close メッセージの追加 を例に解説します。 RFC の読み解きによるプロトコルの確認 Open/Close/Keepalive などのPCEP メッセージは RFC5440 で提案されています。 4.2.7 節に記載されている通り、Close メッセージは PCEP の通信において TCP セッションを終了させるために用いられます。 本記事ではプロトコルライブラリに Close を実装した後、Pola PCE から特定のピアに Close メッセージ送り、PCEP のセッションを切断する実装を追加します。 以降の説明のため、PCEP の基本構造を図に示します。 図の通り、PCEP は単一の common header と複数の object から構成されます。 common header にはそれが何の PCEP メッセージであるかを示す message type が格納されています。 RFC5440 の 6.1 節の通り、主なメッセージは 7 種類存在し、今回実装する Close の message type は 7 と定義されています。 各 object は common object header と object body から構成されています。 common object header には、その object を示す object class と object type が格納されています。 RFC5440 の 7.17 節に、object class は 15、object type は 1 と定義されています。 RFC5440 の 6.8 節には、Close メッセージは 1 つの CLOSE object を含むと書かれています。 message type・object class・object type など、プロトコルで決められたリソースは、IANA が管理しています。IANA は管理するリソースを https://www.iana.org にまとめて掲載しているため、プロトコル開発等の際はこちらを参照すると良いです。 PCEP の場合は Path Computation Element Protocol (PCEP) Numbers を参照してください。 プロトコルライブラリの実装 - Pola PCE への Close メッセージの追加 ここからは実際に Pola PCE へ Close メッセージを追加します。 message type は pkg/packet/pcep/message.go に、object class は pkg/packet/pcep/object.go に実装済みのため今回は追加不要です。 const ( MT_CLOSE uint8 = 0x07 // RFC5440 ) const ( OC_CLOSE uint8 = 0x0f // RFC5440 ) Close メッセージの構造体とパケット操作に関するメソッドを追加します。 Pola PCE では、広く用いられる BGP ライブラリである GoBGP と同様のパケット操作メソッドを採用しています。 パケット操作メソッドとしては、バイト列を構造体に格納する DecodeFromBytes() 、構造体をバイト列に変換する Serialize() の 2 つのメソッドと、新たに構造体を作成する NewCloseMessage 関数が必要となります。 // Close Message type CloseMessage struct { CloseObject *CloseObject } func (m *CloseMessage) DecodeFromBytes(messageBody [] uint8 ) error { var commonObjectHeader CommonObjectHeader if err := commonObjectHeader.DecodeFromBytes(messageBody); err != nil { return err } closeObject := &CloseObject{} if err := closeObject.DecodeFromBytes(messageBody[COMMON_OBJECT_HEADER_LENGTH:commonObjectHeader.ObjectLength]); err != nil { return err } m.CloseObject = closeObject return nil } func (m *CloseMessage) Serialize() [] uint8 { closeMessageLength := COMMON_HEADER_LENGTH + m.CloseObject.getByteLength() closeHeader := NewCommonHeader(MT_CLOSE, closeMessageLength) byteCloseHeader := closeHeader.Serialize() byteCloseObject := m.CloseObject.Serialize() byteCloseMessage := AppendByteSlices(byteCloseHeader, byteCloseObject) return byteCloseMessage } func NewCloseMessage(reason uint8 ) (*CloseMessage, error ) { o, err := NewCloseObject(reason) if err != nil { return nil , err } m := &CloseMessage{ CloseObject: o, } return m, nil } 同様に、close object の object type と構造体とメソッド群も実装します。 こちらも message と同じメソッドに加え、Object 長の計測のため、 Len() メソッドを実装します。 // Close Object (RFC5440 7.17) const ( OT_CLOSE_CLOSE uint8 = 0x01 ) const ( R_NO_EXPLANATION_PROVIDED uint8 = 0x01 R_DEADTIMER_EXPIRED uint8 = 0x02 R_RECEPTION_OF_A_MALFORMED_PCEP_MESSAGE uint8 = 0x03 ) type CloseObject struct { Reason uint8 } func (o *CloseObject) DecodeFromBytes(objectBody [] uint8 ) error { o.Reason = objectBody[ 3 ] return nil } func (o *CloseObject) Serialize() [] uint8 { closeObjectHeader := NewCommonObjectHeader(OC_CLOSE, OT_CLOSE_CLOSE, o.getByteLength()) byteCloseObjectHeader := closeObjectHeader.Serialize() buf := make ([] uint8 , 4 ) buf[ 3 ] = o.Reason byteCloseObject := AppendByteSlices(byteCloseObjectHeader, buf) return byteCloseObject } func (o *CloseObject) Len() uint16 { // CommonObjectHeader(4byte) + CloseObjectBody(4byte) return COMMON_OBJECT_HEADER_LENGTH + 4 } func NewCloseObject(reason uint8 ) (*CloseObject, error ) { o := &CloseObject{ Reason: reason, } return o, nil } close object は RFC5440 の 7.17 節で下記のように定義されています。 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Reserved | Flags | Reason | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | // Optional TLVs // | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ また、7.17節では Reserved 領域と Flag 領域は 0 でパディングし、read 時には無視と規定されています。 そのため、close object の構造体である type CloseObject には、Reason 領域だけを uint8 で用意しておき、 DecodeFromBytes() 、 Serialize() は Reason のみを扱うように実装します。 次に、Close メッセージの受信処理を追加します。 pkg/server/session.go の func (ss *Session) ReceivePcepMessage() に、message type が Close であるメッセージを受信した場合の処理を追加します。 case pcep.MT_CLOSE: byteCloseMessageBody := make ([] uint8 , commonHeader.MessageLength-pcep.COMMON_HEADER_LENGTH) if _, err := ss.tcpConn.Read(byteCloseMessageBody); err != nil { return err } closeMessage := &pcep.CloseMessage{} if err := closeMessage.DecodeFromBytes(byteCloseMessageBody); err != nil { return err } ss.logger.Info( "Received Close" , zap.String( "session" , ss.peerAddr.String()), zap.Uint8( "reason" , closeMessage.CloseObject.Reason), zap.String( "detail" , "See https://www.iana.org/assignments/pcep/pcep.xhtml#close-object-reason-field" )) // Close session if get Close Message return nil まず byteCloseMessageBody という byte 列を作成し、 ss.tcpConn.Read() により read した object を格納します。その後 DecodeFromBytes() メソッドにより、 closeMessage 構造体に受信した close message を格納しています。 Close を正しく受信・デコードした後、ログに close を受信した旨と受信した close の Reason を記録した後 ReceivePcepMessage() から return することで、 Established() に戻りセッションの close 処理を行います。 以上で、RFC に準拠したパケットフォーマットの定義と TCP セッションからの read/write 処理、close の処理が全て実装できました。 サーバー機能の実装 - Pola PCE への Close メッセージ生成コマンドの追加 運用・検証時に任意のタイミングで特定のピアとの Close を行うため、 gRPC API の追加 と、 コマンドを介した Close メッセージの送信機能を実装 します。 func (ss *Session) SendClose(reason uint8) error { closeMessage, err := pcep.NewCloseMessage(reason) if err != nil { return err } byteCloseMessage := closeMessage.Serialize() ss.logger.Info("Send Close", zap.String("session", ss.peerAddr.String()), zap.Uint8("reason", closeMessage.CloseObject.Reason), zap.String("detail", "See https://www.iana.org/assignments/pcep/pcep.xhtml#close-object-reason-field")) if _, err := ss.tcpConn.Write(byteCloseMessage); err != nil { return err } return nil } 今回必要となるのはあるセッションに対するメッセージの送信処理であるため、 pkg/server/session.go 内に、 Session 構造体の SendClose() メソッドとして実装します。 SendClose では、 NewCloseMessage() 関数で close message を作成し、 Serialize() メソッドにより byte 列に変換、 ss.tcpConn.Write() によりソケットへと write します。 Pola PCE はマイクロサービスとしての活用を前提とし、gRPC API を有しています。また、標準コマンドとして、デーモンである polad に対する gRPC client となる pola コマンドを提供しています。 ここでは、 pola に pola session del <Address> オプションを実装し、指定したピアへ SendClose を送信可能とします。 まず、 api/grpc/pola.proto に DeleteSession の RPC を作成します。 rpc DeleteSession (Session) returns (RequestStatus) {}; 次に、polad 側の処理として pkg/server/grpc_server.go に DeleteSession メソッドを作成します。 func (c *APIServer) DeleteSession(ctx context.Context, input *pb.Session) (*pb.RequestStatus, error) { ssAddr, _ := netip.AddrFromSlice(input.GetAddr()) s := c.pce ss := s.SearchSession(ssAddr) if err := ss.SendClose(pcep.R_NO_EXPLANATION_PROVIDED); err != nil { return &pb.RequestStatus{IsSuccess: false}, err } // Remove session info from PCE server s.closeSession(ss) return &pb.RequestStatus{IsSuccess: true}, nil } このメソッドは、gRPC により DeleteSession が実行された際、当該セッションに対して SendClose 処理を実行し、成功/失敗のステータスを送信します。 次に、pola コマンドが用いる gRPC client 側の関数を cmd/pola/grpc_client.go に実装します。 func deleteSession(client pb.PceServiceClient, session *pb.Session) error { ctx, cancel := withTimeout() defer cancel() _, err := client.DeleteSession(ctx, session) if err != nil { return err } return nil } deleteSession() 関数が実行されると、gRPC client として DeleteSession メソッドが実行されます。 最後に、pola コマンドに session del オプションを追加します。 pola コマンドは Cobra を用いて実装しています。 まず、pola session コマンドに del オプションを追加します。 cmd/pola/session.go の newSessionCmd() 関数に newSessionDelCmd() の呼び出しを追加します。 func newSessionCmd() *cobra.Command { cmd := &cobra.Command{ Use: "session" , RunE: func (cmd *cobra.Command, args [] string ) error { if err := showSession(jsonFmt); err != nil { return err } return nil }, } cmd.AddCommand(newSessionDelCmd()) return cmd } 次に cmd/pola/session_del.go に del コマンドそのものである newSessionDelCmd() を実装します。 package main import ( "fmt" "net/netip" pb "github.com/nttcom/pola/api/grpc" "github.com/spf13/cobra" ) func newSessionDelCmd() *cobra.Command { return &cobra.Command{ Use: "del" , SilenceUsage: true , RunE: func (cmd *cobra.Command, args [] string ) error { if len (args) < 1 { return fmt.Errorf( "requires session address \n Usage: pola session del [session address]" ) } ssAddr, err := netip.ParseAddr(args[ 0 ]) if err != nil { return fmt.Errorf( "invalid input \n Usage: pola session del [session address]" ) } if err := delSession(ssAddr, jsonFmt); err != nil { return err } return nil }, } } func delSession(session netip.Addr, jsonFlag bool ) error { ss := &pb.Session{ Addr: session.AsSlice(), } err := deleteSession(client, ss) if err != nil { return err } if jsonFlag { fmt.Printf( "{ \" status \" : \" success \" } \n " ) } else { fmt.Printf( "success! \n " ) } return nil } newSessionDelCmd は、 pola session に del オプションが指定された時に、 func delSession() を実行します。 func delSession() は cmd/pola/grpc_client.go の deleteSession() を実行することで、gRPC client としてセッション削除の gRPC API を実行します。 これにより、 pola session del <Address> オプションによる Close 機能を追加できました。 動作試験 機能を追加した Pola PCE とベンダー機器との相互接続試験を行います。 今回は WIDE Project の高田さん( @Enigamict )に作成していただいた example/containerlab/sr-mpls_pcep を使用し、下記のトポロジーを用いて検証します。 ここでは、PCEP の検証用に Cisco/Juniper/FRRouting の PE が 1 台ずつ存在する環境を作成しています。 このトポロジーをはじめ、SR-MPLS や SRv6 で TE の検証が可能な環境を example として公開しています。 機能を追加した Pola PCE を Docker コンテナとしてビルドすることで、これらの環境を使って検証できます。 Linux + Docker 環境があれば試せるので、是非手元で動かしてみてください。 Docker を用いたネットワークエミュレータツールである Containerlab のインストールや、各イメージの準備方法、ネットワークの起動などの流れは REAME.md にまとめています。 起動したネットワーク上で Pola PCE のコンテナに入り、 polad コマンドで Pola PCE の起動&セッションの構築後、 pola session コマンドで確認します。 # polad -f polad.yaml > /dev/null 2>&1 & # pola session sessionAddr(0): 10.0.255.1 sessionAddr(1): 10.0.255.3 sessionAddr(2): 10.0.255.2 次に、今回追加した pola session del コマンドを実行し、IOS XR/Junos/FRRouting Close メッセージを送信します。 以下では IOS XR に対する Close を実施します。 root@pola-pce:/# pola session del 10.0.255.1 success! また、動作試験のため Wireshark を利用して PCEP パケットをキャプチャします。下記に、SSH 経由で Containerlab 環境からパケットキャプチャを実施する例を示します。 ssh $clab_host "sudo -S ip netns exec clab-srv6_te_l3vpn-pe01 tcpdump -U -nni eth1 -w -" | wireshark -k -i - キャプチャした結果、実装通りに Close メッセージが送られ、TCP も Close していることが確認できます。 これにより、実装した Close 機能が各ルーターと正しく相互接続可能なことを確かめられました。 Let's contribute! 最後に、今までに実装した機能を Pola PCE へ Pull Request として提出しましょう。 テンプレートに従って GitHub PR を作成します。 今回の例にあげた Close 機能は PR #66 で取り込まれています。 この PR では、同時に PCErr 機能も追加されています。もし興味があれば、是非そちらの読み解きにもチャレンジしてみてください。 また、今回の例にあげた Close 機能は Pola PCE v1.2.1 でリリース済みのため、 最新の Docker イメージ や、それを用いた example でも試せます! まとめと今後の予定 本記事では、Pola PCE の実装例を基に、RFC/I-D 準拠のコントローラーやプロトコルライブラリ開発の進め方についてご紹介しました。 記事を通じてプロトコルライブラリやコントローラーの実装に興味を持たれた方は、是非我々と共に Pola PCE を開発しましょう! 次のステップとして、 uSID や Flex-Algo を用いた Dynamic TE の実装を目指しています。実装予定の機能は issue や milestone として整備していますので是非ご確認ください。 本記事を読んでコントローラーやプロトコルライブラリの開発に興味をもった方や、拡張可能な PCE を求めている方がいましたら、Pola PCE にコントリビューションしてみませんか? もしご興味をお持ちの方がいれば、是非気軽にご連絡や PR/Issue の作成をお願いします!
はじめに こんにちは、インターン生の 山口雄翔 です。 この度2023年2月6日から2週間、NTTコミュニケーションズのインターンシップに、 エンタープライズ向け大規模クラウドサービスを支えるネットワーク開発 というテーマで参加させていただきました。 この記事ではその体験について書かせていただきます。 インターンシップについて NTTコミュニケーションズでは、 SDPFクラウド/サーバー というエンタープライズ向けクラウドサービスを提供しています。 このサービスでは、仮想的なL2ネットワークを自由に構築し、そこにベアメタルサーバ・VM・ストレージなどを(論理的に)接続させて使うことができます。 もちろんインターネット接続やロードバランサなどをサービスとして利用することもできます。 そのクラウドの内部のネットワークを制御するSDNコントローラの改善というのが、本インターンシップのテーマでした。 前半1週間はこのクラウド内のネットワークやSDNとその関連技術について教えてもらいながら学び、後半1週間でコントローラの性能改善に取り組みました。 クラウド内のネットワークとSDNについて 概要 クラウド内のネットワーク構成はこのようになっています。(紫で印をつけた部分がSDNコントローラ) クラウドを構成するデータセンタのスイッチは全て隣接するスイッチとBGPで接続していて、全体に対して疎通性があります。 機能を持つノード(ハイパーバイザ・ベアメタルサーバ・ゲートウェイ等)はLeafスイッチの下にあります。 VMを収容するハイパーバイザが乗っているマシン上では、VMに関係する経路情報をやり取りするための仮想ルータが動いています。 EVPN/VXLAN VMやベアメタルサーバ同士のL2接続性を確保するために、VXLANとEVPNを利用しています。 EVPN(Ethernet VPN)とは、仮想的にL2接続性を提供するためのVPNのことです。 仮想L2ネットワークに接続するノードのMACアドレス VPNのエンドポイントのIPアドレス 仮想L2ネットワークの識別子 などをMP-BGPに乗せて交換することで、L2接続に必要な情報を共有し、ネットワークをスケールさせることができます。 https://datatracker.ietf.org/doc/html/rfc8365 https://datatracker.ietf.org/doc/html/rfc7432 VXLANはパケットをカプセル化することで、L3ネットワーク上に論理的なL2ネットワークを構築するトンネリングプロトコルです。 MACアドレスなどの情報をEVPNで交換したのち、VXLANでL2トンネルを作ることによって、L2接続性を実現しています。 図のようにencap/decapを行うことで、仮想L2ネットワークを実現しています。 (encap/decapをするVXLANトンネルのエンドポイントのことを、VTEPと呼びます。) このように仮想ネットワークが実現できるような経路制御の管理をするのも、SDNコントローラの重要な役割のひとつです。 (次項参照) SDNコントローラ SDPFクラウド/サーバーでは、SDNコントローラに Tungsten Fabric を採用しています。 SDNコントローラは、 仮想L2ネットワーク等のリソース作成のためのインターフェースの提供およびVTEPへの設定投入 経路情報の計算と広告 コントローラ自身やリソース情報のメトリクスの収集 を持っています。 (3についてはインターンシップで扱っていないため、この記事では触れません。) 1について クラウド内の仮想計算機基盤はOpenStackを利用して作られています。 OpenStackのネットワーク周りを管理するNWコントローラとTungsten Fabricを連携させることにより、仮想基盤側から投入された設定が、SDNコントローラを経由してネットワークに入るような設計を実現しています。 2について SDNコントローラは、クラウドのネットワーク内で仮想L2ネットワークを作るための経路情報の計算・広告をする役割を担っています。 以下の図は、コントローラとネットワークの各コンポーネントの論理的な繋がりを示しています。 コントローラと仮想ルーターの経路情報のやり取りでは、XMPPというプロトコルに乗せてEVPNの経路情報のやり取りをしています。 物理ルータがVTEPとなっている箇所については、Route Reflector(以下RRと示す)がコントローラと物理ルーターの双方とBGPピアを張ってEVPNの経路情報を交換することで、コントローラからの経路情報をRR経由でVTEPに伝えることができます。 対外発表資料 SDPFクラウド/サーバーについての技術的な対外発表の資料を以下にまとめましたので、ご興味のある方はぜひご覧ください。 JANOG: EVPN Anycast Gateway を 商⽤導⼊した話 : https://www.janog.gr.jp/meeting/janog48/evpn/ JANOG: エンタープライズ向けクラウドのSDN基盤の安定化への挑戦 : https://www.janog.gr.jp/meeting/janog44/program/sdnclg/ NTT Com Open TechLunch: クラウドの作り方 : https://speakerdeck.com/toby06/how-to-create-cloud-service 今回取り組んだ問題について コントローラ内での経路の保持と複製処理 SDNコントローラはクラウドネットワークの経路情報を全て把握しています。 コントローラの内部では、各仮想ネットワークごとのルーティングテーブル(VRF)とFabric全体の経路を保持するグローバルルーティングテーブルを持っており、EVPNについてもこの構成で経路を保持しています。 そしてVRFテーブルとグローバルルーティングテーブルの間での経路の複製処理がイベントドリブンで実行されるようになっているのですが、コントローラのこの動作が時間のかかる処理となっています。 (Tungsten Fabric は複数コアを用いたマルチスレッドに対応していますが、経路複製がスレッドセーフでない処理を含むため、1コアのみを用いて順番に処理を行うタスクキューに入るようになっており、時間がかかってしまいます。) ライブマイグレーションなどに伴う経路計算の際に、この部分の計算時間がボトルネックとなって経路計算の完了が遅れ、それによって通信ができない時間が発生してしまいます。 それを防ぐためには経路複製処理の速度の改善が必要であり、今回のインターンシップではその問題に取り組みました。 作業 実は経路複製処理のコード改善というのはインターンシップの前からチームで取り組まれていて、upstreamにmergeされている変更もあります。 (その説明は こちらの資料 に書いてあります。) その中で同じ関数内に更なる改良の余地がありそうだとが分かり、自分はそれに取り組ませていただきました。 まずは教えてもらった関数内の処理内容を把握した上で、部分ごとに分けて時間を測りました。 この関数の中には、 経路を複製すべき宛先テーブルを種々の条件から絞る処理 宛先テーブルをRouteTarget等から決定する処理 実際に経路情報をメモリコピーする処理 などが含まれており、それらの処理ごとの時間をログに出力したのちpythonスクリプトを使って結果を見やすく表示しました。 (下はその様子です。) そして、 計測結果・プログラムのコード・そこで扱われる経路情報 の3つを見ながら考えて、処理時間を短縮できそうな箇所を見つけました。 コード改善 アルゴリズム コントローラが保持している経路(BGP route)には、複数のpathを持つものがあります。 例えば3つのRRから同じ経路を受け取った際、src addrだけ異なる3つのpathがrouteに登録されます。 ある1つのrouteの複製は、含まれるpathごとにループで行われる実装となっていて、その中でpathの複製先EVPNテーブルを選定していました。 (pathの中の拡張コミュニティに含まれるRouteTarget等の情報からテーブルを探索し、複製先テーブルリストを作っています。) ですが同じrouteに属するpathは(自分が検証環境でチェックした限りでは)複製先テーブルは同じであったため、ここの処理を1つにまとめることで、性能改善ができるのではないかと考えました。 この効果は、多量(ほぼ全て)のVRFテーブルに複製する必要がある EVPN Type1経路 において顕著に現れました。 (EVPN Type1経路はマルチホーミングの情報を広告するためのものです。) 実装結果・考察 改善前と後のパフォーマンス計測の結果 before after この写真は経路複製をする関数の中の部分ごとの処理時間を出力したものです。 印をつけた部分が複製先EVPNテーブルを選定して該当するテーブルをリストに挿入している操作なのですが、コード改善後に処理時間が大幅に短縮されていることが分かります。 この関数全体の処理時間(左端の数値)は1割程度の削減でき、性能として10%程度の改善を実現できたと言えます。 ( 数値の単位は全てマイクロ秒です。 ) 処理の測定、実装を通して想定通り性能改善を得ることはできました。 一方で、インターンシップの間ではその他に極端にボトルネックとなっているような処理を見つけることはできず、処理速度の大幅改善の難しさなども実感しました。 課題 時間がなくてできませんでしたが、複製先テーブル計算の処理をまとめても本当に大丈夫かというのを、ロジック・動作検証の両面から確認してゆく必要があるかなと思いました。 (商用環境へのデプロイまでには他にも様々な段階を踏んだ検証・テストが必要で、今回自分が書いたコードがそのまま乗ることはありません。) 感じたこと 大規模ネットワークを制御するSDNコントローラを作る難しさ プログラム中の本当に些細なロジックの誤りであっても、コントローラから経路情報が流れる中でその影響がクラウド内に広く波及して、全体として見た時に大きなエラーになってしまうことが多々あると思いました。(実際自分も検証環境を壊しかけました。) 大規模SDNコントローラだからこそコード1行1行にこだわって書かなければいけないなと思いましたし、そのような環境で日々コードを書かれているチームメンバーの皆さんの、コードを検証する時の鋭さを強く感じました。 また小規模な検証環境で動かした時には気にならなかった少しの遅延が、大規模環境に移した途端顕著になるということも経験し、コードを最適化する重要性を身をもって体験できました。 デバッグ SDNを用いる場合、コントロールプレーンでのエラーは基本SDNコントローラに原因があります。 原因となるコンポーネントの特定という意味では分かりやすい反面、ロジックの難しさやネットワークの状態管理の煩雑さが全てこのソフトウェアの内部に含まれるため、コードや挙動が非常に複雑です。 またそもそもエラーを再現すること自体が難しく、デバッグに高度な技術力や経験が必要であるなと感じました。 人間よりも機械の気持ちが分かる(他称)というある先輩は、エラーが起こった時迷いなくgdbでこの巨大でステートフルなプログラムの動作を見に行っていました。つよい... 謝辞 インターンシップに向けて検証環境整備や資料準備をしてくださり、期間中は丁寧に業務のことを教えてくださったチームの皆さんのおかげで、濃くて楽しい2週間になりました。本当に本当にありがとうございました。 本来は自分が参加した部署ではインターンブログを書くことはあまりないそうなのですが、とても面白くて素晴らしい体験ができたので、技術的なことを含めて是非共有したいと思い、無理を言って書かせていただきました。 (メールで質問攻めにしてしまいすみません。) 長い文章となってしまいましたが、多くの方にこのブログを読んでいただけると嬉しいです。
はじめに シェル芸勉強会について 問題と解説 Q1(@butackle66さんから) 解答例1 解答例2 Q2(@butackle66さんから) 解答例1 解答例2 Q3 解答例1 解答例2 Q4 解答例1 解答例2 Q5 解答例 Q6 解答例 LT LT1 curlでTelegram botを操作 (やべえ @yabeenico) LT2 音声合成してみよう (たいちょー @xztaityozx_001) おわりに はじめに こんにちは。デジタル改革推進部データドリブンマネジメント推進部門の江川尋喜 (Hiroki Egawa / @yabeenico ) です。 第63回ビッグハンドタウンシェル芸勉強会が2023年02月25日に開催されました。 今回は NTT Com のオフィスビル、大手町プレイスを会場提供させていただきました。 このブログエントリでは、勉強会で出題された問題の解答と解説をします。 問題データ ryuichiueda/ShellGeiData/vol.63 Twitter まとめ 第63回ビッグハンドタウンシェル芸勉強会 - Togetter YouTube 第63回シェル芸勉強会 - YouTube イベントサイト jus共催 第63回ビッグハンドタウンシェル芸勉強会 | Doorkeeper イベントリンク集 jus共催 第63回シェル芸勉強会リンク集 | 上田ブログ 大手町会場の様子 シェル芸勉強会について まずシェル芸について、提唱者の上田隆一 ( @ryuichiueda ) 先生がこう定義しています。 [シェル芸とは] シェル芸の定義バージョン1.1 マウスも使わず、ソースコードも残さず、GUIツールを立ち上げる間もなく、あらゆる調査・計算・テキスト処理をCLI端末へのコマンド入力一撃で終わらすこと。あるいはそのときのコマンド入力のこと。 要は Unix系OSのシェル上でのワンライナーのことです。勝手に名前つけてすんません。 https://b.ueda.tech/?page=01434 シェル芸勉強会はシェル芸を極めたい人、すなわちシェルスクリプトやコマンドの愛好家が参加し、交流します。 参加者のバックグラウンドはコマンド開発者、インフラエンジニア、研究者、学生等様々です。 シェル芸勉強会は次の流れで進行します。 上田先生が作ってきた問題を出題 参加者が Twitter に #シェル芸 を付けて解答を投稿 上田先生が解答を解説 #シェル芸 をつけてつぶやくとシェル芸bot ( @minyoruminyon ) が実行結果を表示してくれます。 また、入力に使うデータは ryuichiueda/ShellGeiData/vol.63 にあります。 今回紹介する解答は私が考えたものと、他の人の考えを取り入れたものがあります。 また、文字数がなるべく少なくなる解答を用意しました。 それでは問題、解答及び解説を見ていきましょう。 問題と解説 Q1( @butackle66 さんから) 1x1〜9x9の九九の答えをすべて足し合わせてください。 https://twitter.com/ryuichiueda/status/1629339996028018688?s=20 解答例1 文字数が少ないです。 $ echo {1..9}*{1..9}+ 0|bc 2025 解説 bash のブレース展開で計算式を出力し、bc で計算しています。 検索ワード: ブレース展開 / brace expantion / sequence expantion $ echo {1..9} 1 2 3 4 5 6 7 8 9 $ echo {1..9}{1..9} 11 12 13 14 15 16 17 18 19 21 22 23 24 25 26 27 28 29 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46 47 48 49 51 52 53 54 55 56 57 58 59 61 62 63 64 65 66 67 68 69 71 72 73 74 75 76 77 78 79 81 82 83 84 85 86 87 88 89 91 92 93 94 95 96 97 98 99 $ echo {1..9}*{1..9}+ 0 1*1+ 1*2+ 1*3+ 1*4+ 1*5+ 1*6+ 1*7+ 1*8+ 1*9+ 2*1+ 2*2+ 2*3+ 2*4+ 2*5+ 2*6+ 2*7+ 2*8+ 2*9+ 3*1+ 3*2+ 3*3+ 3*4+ 3*5+ 3*6+ 3*7+ 3*8+ 3*9+ 4*1+ 4*2+ 4*3+ 4*4+ 4*5+ 4*6+ 4*7+ 4*8+ 4*9+ 5*1+ 5*2+ 5*3+ 5*4+ 5*5+ 5*6+ 5*7+ 5*8+ 5*9+ 6*1+ 6*2+ 6*3+ 6*4+ 6*5+ 6*6+ 6*7+ 6*8+ 6*9+ 7*1+ 7*2+ 7*3+ 7*4+ 7*5+ 7*6+ 7*7+ 7*8+ 7*9+ 8*1+ 8*2+ 8*3+ 8*4+ 8*5+ 8*6+ 8*7+ 8*8+ 8*9+ 9*1+ 9*2+ 9*3+ 9*4+ 9*5+ 9*6+ 9*7+ 9*8+ 9*9+ 0 $ echo 1 + 2 | bc 3 解答例2 ブレース展開と bc のどちらも利用しない別解です。 ブレース展開では変数が使えないので、変数が使いたシチュエーションで利用できます。 $ join -j9 <(seq 9) <(seq 9) | awk '$0=a+=$1*$2' | tail -n1 2025 解説 join -j9 <(seq 9) <(seq 9) -> 列結合を利用して 1 1 から 9 9 までの組を作っています。 ### サンプルデータ $ cat <(printf '1 a\n2 b\n3 c\n4 d\n') <(printf '1 e\n2 f\n3 g\n4 h') 1 a 2 b 3 c 4 d 1 e 2 f 3 g 4 h ### 1列目で結合 $ join -j1 <(printf '1 a\n2 b\n3 c\n4 d\n') <(printf '1 e\n2 f\n3 g\n4 h') 1 a e 2 b f 3 c g 4 d h ### 存在しない列で結合すると full join となる $ join -j9 <(printf '1 a\n2 b\n3 c\n4 d\n') <(printf '1 e\n2 f\n3 g\n4 h') 1 a 1 e 1 a 2 f 1 a 3 g 1 a 4 h 2 b 1 e 2 b 2 f 2 b 3 g 2 b 4 h 3 c 1 e 3 c 2 f 3 c 3 g 3 c 4 h 4 d 1 e 4 d 2 f 4 d 3 g 4 d 4 h ### 1 1 から9 9 までの組を出力 (途中は sed で削除) $ join -j9 <(seq 9) <(seq 9) | sed 4,78d 1 1 1 2 1 3 9 7 9 8 9 9 awk '$0=a+=$1*$2' -> 累積和を計算しています。 参考: awk 基礎 ### a に累積和を保存 $ seq 4 | awk '{a+=$1; print a}' 1 3 6 10 ### (a+=$1) は代入後の a の値に評価される $ seq 4 | awk '{print a+=$1}' 1 3 6 10 ### $0 に a を代入し、間接的に a を print ### pattern = $0=(a+=$1), action = 暗黙的に {print $0} となる $ seq 4 | awk '$0=(a+=$1)' 1 3 6 10 tail -n1 -> 最後の1行を抽出しています。 Q2( @butackle66 さんから) 9132円の支払いに10000円札で払ったときのおつりの出し方をひとつ(できるひとはたくさん)画面に出力してみてください。 https://twitter.com/ryuichiueda/status/1629340985389125632?s=20 解答例1 文字数が少ないです。 また、出すコインの枚数が最小になります。 $ printf %s\\n 500 100 50 10 5 1|awk 'BEGIN{t=10000-9142}{t-=$0*(a=int(t/$0))}$0=$0" "a' 500 1 100 3 50 1 10 0 5 1 1 3 解説 printf %s\\n 500 100 50 10 5 1 -> 6種類のコインを出力しています。 ### `printf` は第1引数のフォーマットを第2引数以降の全てに適用する $ printf '%s\n' 500 100 50 10 5 1 500 100 50 10 5 1 $ printf '%s/' 500 100 50 10 5 1 500/100/50/10/5/1/ awk 'BEGIN{t=10000-9142}{t-=$0*(a=int(t/$0))}$0=$0" "a' -> 以下の python3 コードをワンライナーにしています。 参考: awk 基礎 t = 10000 - 9142 for d0 in [500, 100, 50, 10, 5, 1]: # $0 a = int(t / d0) # a=int(t/$0) t = t - d0 * a # t-=$0*(...) d0 = str(d0) + " " + str(a) # $0=$0" "a print(d0) 解答例2 ネタです。 コインの枚数の組み合わせを金額が858円になるまでランダムに探索しています。 $ tr -dc 0-9</dev/urandom|fold -w6|awk -F '' '500*$1+100*$2+50*$3+10*$4+5*$5+1*$6==10000-9142'|head -n1 071928 出力の見方: 500円玉0枚, 100円玉7枚, ..., 1円玉8枚 解説 tr -dc 0-9</dev/urandom|fold -w6 -> 6桁のランダムな数字を生成しています。 ### /dev/urandom はランダムなデータを返す $ cat /dev/urandom | head -c10 ȱ�KH$繀 ### tr -d: 削除, -c: 以外を -> 0-9 以外を削除 -> 0-9 のみ抽出 $ cat /dev/urandom | tr -dc 0-9 | head -c10 0597488882 ### fold で6桁に切り詰める $ cat /dev/urandom | tr -dc 0-9 | fold -w6 | head -n3 764711 039900 491372 awk -F '' '500*$1+100*$2+50*$3+10*$4+5*$5+1*$6==10000-9142' -> 入力の6桁の数字のうち金額が858円となるものを抽出しています。 ### -F '' で文字単位にフィールド分割 $ echo abc | awk -F '' '{print $2}' b また、pattern/action が以下となります。 pattern: 500*$1+100*$2+50*$3+10*$4+5*$5+1*$6==10000-9142 action: 暗黙的に {print $0} Q3 次のLaTeXの原稿で、\labelと\refがペアになっていない(参照していない/されていない)ものを抽出してください。 https://twitter.com/ryuichiueda/status/1629347379219689473?s=20 題意としては、参照されていない図表、図表の無い参照を見つけたいということです。 また、今回は \label が0個で \ref が2個のように片方が0個で片方がn個のようなシチュエーションの考慮は不要です。 参照されていない図表の例 \label{hoge} はあるが \ref{hoge} がない 図表のない参照の例 \ref{hoge} はあるが \label{hoge} がない 解答例1 文字数が少ないです。 $ grep -oP '(label|ref)\K[^}]*' genkou.tex|sort|uniq -u {eq:state_equation_linear {eq:state_equation_nonlinear {fig:typhoon 解説 grep -oP '(label|ref)\K[^}]*}' genkou.tex -> ファイルから \label{...} や \ref{...} の部分を抽出しています。 ### -o: マッチした部分のみ抽出 $ echo 12344321 | grep -o .3 23 43 ### lable または ref から } が現れる直前までを抽出 (-P は後述) $ grep -oP '(label|ref)[^}]*' genkou.tex | head -n3 label{eq:state_transition_model label{eq:state_transition_model2 ref{eq:state_transition_model ### -P: perl 拡張正規表現を利用 -> \K と | を使うため ### \K: \K より左をマッチとして出力しない ### ..3 にマッチさせて... $ echo 12344321 | grep -oP '..3' 123 443 ### 最初の1文字を出力したくない場合 $ echo 12344321 | grep -oP '.\K.3' 23 43 ### \K を使って label と ref を出力から除外 $ grep -oP '(label|ref)\K[^}]*' genkou.tex| head -n3 {eq:state_transition_model {eq:state_transition_model2 {eq:state_transition_model sort|uniq -u -> 重複のないユニークな行のみを抽出しています。 ### サンプルデータ $ seq 1 3; seq 2 4 1 2 3 2 3 4 ### ユニークな行のみを抽出 ### なお、uniq は直前の行との比較のみを行うので、あらかじめ sort が必須 $ (seq 1 3; seq 2 4) | sort | uniq -u 1 4 uniq の便利なオプション ### 重複排除 $ (seq 1 3; seq 2 4) | sort | uniq 1 2 3 4 ### ユニークな行のみを抽出 (再掲) $ (seq 1 3; seq 2 4) | sort | uniq -u 1 4 ### 重複した行のみを抽出 $ (seq 1 3; seq 2 4) | sort | uniq -D 2 2 3 3 ### 重複した行のみを抽出し、重複排除して出力 $ (seq 1 3; seq 2 4) | sort | uniq -d 2 3 ### 重複個数をカウント $ (seq 1 3; seq 2 4) | sort | uniq -c 1 1 2 2 2 3 1 4 解答例2 勉強会で解説された方法です。 sort と uniq のフィールド機能を活用しています。 $ cat genkou.tex | grep -oE '(ref|label){.*}' | tr '{}' ' ' | sort -k2,2 | uniq -u -f1 label eq:state_equation_linear label eq:state_equation_nonlinear ref fig:typhoon 解説 ### `grep -oE` までは基本的に解答例1と同じ。| を使うために -E を指定 $ cat genkou.tex | grep -oE '(ref|label){.*}' | head -n3 label{eq:state_transition_model} label{eq:state_transition_model2} ref{eq:state_transition_model} ### tr で { と } をスペースに変換 $ cat genkou.tex | grep -oE '(ref|label){.*}' | tr '{}' ' ' | head -n3 label eq:state_transition_model label eq:state_transition_model2 ref eq:state_transition_model ### sort -k2,2 で2フィールド目で並べ替え $ cat genkou.tex | grep -oE '(ref|label){.*}' | tr '{}' ' ' | sort -k2,2 label eq:state_equation_linear label eq:state_equation_nonlinear label eq:state_transition_model ref eq:state_transition_model ref eq:state_transition_model ref eq:state_transition_model label eq:state_transition_model2 ref eq:state_transition_model2 ref eq:state_transition_model2 ref eq:state_transition_model2 ref eq:state_transition_model2 ref eq:state_transition_model2 ref eq:state_transition_model2 label fig:motion ref fig:motion ref fig:typhoon ### uniq -u -f1 で1フィールド目を無視してユニークな行を抽出 $ cat genkou.tex | grep -oE '(ref|label){.*}' | tr '{}' ' ' | sort -k2,2 | uniq -u -f1 label eq:state_equation_linear label eq:state_equation_nonlinear ref fig:typhoon Q4 次のファイルから、「東西南北」がワンセットになっている部分を探してください。東西南北の順番は問いません。 https://twitter.com/ryuichiueda/status/1629355288145920001?s=20 例: 東西南北西東 という入力文字列から 1 東西南北 , 3 南北西東 を出力する。 何文字目から始まるかの情報も出力する。 解答例1 愚直に解くとこうなるでしょう。 $ awk '{while(a=substr($0,++i,4)){print i,a}}' tonnan.txt|awk '/東/*/西/*/南/*/北/' 3 西南北東 12 南北西東 33 南東西北 41 西北南東 43 南東北西 54 東北南西 55 北南西東 56 南西東北 57 西東北南 58 東北南西 63 南西東北 64 西東北南 68 東南西北 71 北西南東 72 西南東北 97 西北東南 awk '{while(a=substr($0,++i,4)){print i,a}}' -> 入力文字列を4文字ずつ切り出しています。 a=substr($0, ++i, 4) で a (東西南北の文字列) と i (インデックス) を以下のように設定しています。 南西西南北東東西東... (入力) 南西西南 == a, i == 1  西西南北 == a, i == 2   西南北東 == a, i == 3    南北東東 == a, i == 4     北東東西 == a, i == 5      東東西東 == a, i == 6 実行結果 $ awk '{while(a=substr($0,++i,4)){print i,a}}' tonnan.txt | head -n5 1 南西西南 2 西西南北 3 西南北東 4 南北東東 5 北東東西 awk '/東/*/西/*/南/*/北/' -> 東西南北が4つとも含まれている行のみ抽出しています。 pattern の /regex/ は $0 ~ /regex/ と等価です。 すなわち、入力行を正規表現マッチした結果を 0 or 1 の数値に評価します。 よって、以下の式は等価です。 /東/*/西/*/南/*/北/ ($0 ~ /東/) && ($0 ~ /西/) && ($0 ~ /南/) && ($0 ~ /北/) 解答例2 eban さんの解答 を解説します。 文字数が少ないです。 「東西南北が含まれている」の判定を「1行に同じ文字が2回出現しない」で行っています。 $ sed ':a;p;s/.//;ta' tonnan.txt|grep -o ^....|grep -vnE '(.).*\1' 3:西南北東 12:南北西東 33:南東西北 41:西北南東 43:南東北西 54:東北南西 55:北南西東 56:南西東北 57:西東北南 58:東北南西 63:南西東北 64:西東北南 68:東南西北 71:北西南東 72:西南東北 97:西北東南 解説 sed ':a;p;s/.//;ta' -> パターンスペースの1文字目の削除と print を繰り返しています。 パターンスペースの解説はここではやりませんが、tonnan.txt の中身で初期化された文字列型の変数と考えて下さい。 この sed は以下4つのコマンドから成り立っています。 :a # ラベル p # パターンスペースを print s/.// # パターンスペースの最初の1文字を削除 ta # 直前の置換が成功したら :a に戻る 実行結果 $ sed ':a;p;s/.//;ta' tonnan.txt | tail 東南東東西北東南 南東東西北東南 東東西北東南 東西北東南 西北東南 北東南 東南 南 grep -o ^.... -> 先頭4文字を切り出しています。 $ sed ':a;p;s/.//;ta' tonnan.txt | grep -o ^.... | tail 南東東北 東東北南 東北南東 北南東南 南東南東 東南東東 南東東西 東東西北 東西北東 西北東南 grep -vnE '(.).*\1' -> 同じ文字が含まれていない行のみを抽出しています。 \1 は (.) と同じ文字にマッチします (後方参照といいます)。 例えば (.)(.)(.)\3\2\1 は abccba にマッチします。 ### (.).*\1 -> 同じ文字が少なくとも2文字含まれている行 ### -v -> 以外を ### -n -> 行番号付きで表示 ### -E は () を使うために指定 $ sed ':a;p;s/.//;ta' tonnan.txt|grep -o ^.... | grep -vnE '(.).*\1' 3:西南北東 12:南北西東 33:南東西北 41:西北南東 43:南東北西 54:東北南西 55:北南西東 56:南西東北 57:西東北南 58:東北南西 63:南西東北 64:西東北南 68:東南西北 71:北西南東 72:西南東北 97:西北東南 Q5 つぎのリバーシの盤面について、E6とG7に❌を打ちたいです。 $ cat reversi.txt  12345678 A         B         C   ⚪     D   ⚪⚫    E   ⚫⚫    F    ⚪⚫   G         H         つぎのワンライナーを完成させてください。(Perl使える人もこの問題はsedでお願いします。) $ cat reversi.txt | sed あるsedのコード | sed 最初のsedのコードと同じコード https://twitter.com/ryuichiueda/status/1629363762879758336?s=20 題意はこんな感じです。 sed でリバーシの実装をしたい。 ⚪ が置ける場所に印をつけたい。 今回のスコープは左斜上に探索して判定する処理。 期待する出力  12345678 A         B         C   ⚪     D   ⚪⚫    E   ⚫⚫❌   F    ⚪⚫   G      ❌  H         解答例 勉強会で解説されたものです。 別解の余地は無いでしょう。 $ cat reversi.txt | sed -Ez 's/(⚪.{10}(⚫.{10})+) /\1❌/g' | sed -Ez 's/(⚪.{10}(⚫.{10})+) /\1❌/g'  12345678 A         B         C   ⚪     D   ⚪⚫    E   ⚫⚫❌   F    ⚪⚫   G      ❌  H         解説 -z オプションで改行を無視しています。 C 言語で2次元配列を扱うのと同じ要領で探索しています。 reversi.txt の横幅が10文字であることを利用しています。 こんなパターンを見つけたら全角スペースを❌に変換しています。 ⚪(任意の10文字)⚫(全角スペース) ((任意の10文字)⚫) を+で繰り返すことで、⚫が2個続くパターンを検知 sed -z の実行例 $ printf 'abc\ndef\nghi' abc def ghi ### & はマッチ全体 -> マッチした部分の後ろに x を追記 $ printf 'abc\ndef\nghi' | sed -z 's/b.../&x/' abc dxef ghi Q6 Q5のワンライナーに続けて、⚪と❌の間の⚫を⚪にしてください。 https://twitter.com/ryuichiueda/status/1629369189843750912?s=20 解答例 勉強会で解説されたものです。 合理的な別解は恐らくありません。 $ cat reversi.txt | sed -Ez 's/(⚪.{10}(⚫.{10})+) /\1❌/g' | sed -Ez 's/(⚪.{10}(⚫.{10})+) /\1❌/g' | tr -d '\n' | perl -CSD -Mutf8 -pe 's/⚫(?=.{9}(⚫.{9})*❌)/⚪/g' | fold -b27  12345678 A         B         C   ⚪     D   ⚪⚪    E   ⚫⚪❌   F    ⚪⚪   G      ❌  H         解説 perl を使いますが、改行無視は sed -z のような感じではなく、tr と fold で行っています。 perl -CSD -Mutf8 -pe 's/⚫(?=.{9}(⚫.{9})*❌)/⚪/g' -> コンセプトは Q5 とだいたい同じ。 -CSD -Mutf8 -> マルチバイト対応 ⚫(?=.{9}(⚫.{9})*❌) -> (?=...) は肯定先読み。 検索対象だがマッチしたとはみなさない。 今回の場合、検索対象だが置換対象でなくなる。 -> 先頭の⚫のみが⚪への置換対象となる。 LT LT ( Long Talk) が2件ありました。 LT1 curlでTelegram botを操作 (やべえ @yabeenico ) Twitter YouTube 東京会場から 私が登壇しました。 初めてのシェル芸勉強会での LT 発表でした。 チャットアプリ Telegram を curl で操作する方法を紹介しました。 LT2 音声合成してみよう (たいちょー @xztaityozx_001 ) Twitter YouTube 大阪サテライトから 自作初音ミクみたいなことをしていました。 たいちょーさんの音声を返す REST API エンドポイントが立ち上がっていたので、みんなでたいちょーさんの音声を合成しました。 おわりに Q1~Q4 は試行錯誤できてが楽しかったです。 Q5 Q6 は難しいのに加えて別解の余地がなかったので厳しかったです。 シェル芸勉強会の問題を解くときは、厳密な解答より、シチュエーションをイメージしてそれにマッチするものを考えると良いです。 例えば Q3 では、私は次のシチュエーションをイメージしました。 「図表の参照のアンマッチが存在することを知ったのでとりあえずその一覧が欲しい」 そのため、Q3 解答例1では { が先頭に残っていたり、 ref と label を区別できませんが、シチュエーションにマッチするのでそれでいいのです。 また、勉強会でも言及されていますが、問題が解けなくても解くまでに試行錯誤したこと自体に学びがあります。 問題を解くまでのプロセスを大切にしていきましょう。 以上、第63回ビッグハンドタウンシェル芸勉強会の問題と解説でした。
1.はじめに このブログを読んで下さっている皆様、こんにちは。 プラットフォームサービス本部 クラウド&ネットワークサービス部 開発オペレーション部門の丹野(入社10年目)です。 この記事では、NTTコミュニケーションズに入社してから業務内容の変化に適応するため、必要なスキルを獲得してきた私の体験(リスキリング体験)と、最近自分で立ち上げて運営している社内での育成の取り組みについて紹介します。 2.私のスキル習得の体験(リスキリング体験) 最初に私の入社してからの業務経歴を簡単に紹介します。 ①入社1~3年目は、プリセールスエンジニアという立場でグローバルネットワークサービスを販売する営業組織を支援。 ②入社4~7年目は、 Software Defined Networking のサービスオーダーからお客様の利用開始までのプロセス構築と運用(以下、SOデリバリと呼ぶ)の立上げ。  当時、Software Defined Networkingというサービスを世に出すためのプロジェクトが立ち上がった頃に、私は参画しました。  サービス全体のプロジェクトの中でSOデリバリに関する部分を任され、プロジェクトリーダー的な仕事もこなしていました。 ③入社8~10年目は、リリースしたサービスのSOデリバリプロセスの維持運用と改善や、部内サービスの課題発掘とその改善のためにUX/UIデザインやデータサイエンスのスキルを身に付けて業務で活かしています。 上記より、私の業務アサインメントの変化に伴い、業務で求められるスキルの軸が多岐に渡って変わってきているというイメージが湧いてくるのではないかと思います。 (①ネットワークや英語⇒②プロジェクトマネジメント⇒③UI/UXデザインやデータサイエンス) このように、会社や業務で求められるスキルは多岐に渡ります。 特にUI/UXデザインやデータサイエンスについては、NTTコミュニケーションズでもここ2~3年の間で、これからのサービス開発や販売に必要なスキルとして力を入れている分野になります。 UI/UXデザイン分野での取り組み事例として上げられるのは、 デザインスタジオ KOEL が NeWork というサービスに対し、ユーザーリサーチ/コンセプトの仮説検証/プロトタイプ/ユーザーテスト等に対しデザインスキルを十二分に発揮して貢献している事例があります。 その他の活躍も幅広く、 リンク先の事例 を是非ご覧ください。 また、データサイエンス分野での取り組み事例として上げられるのは、全社でのデータ活用を促進することを目指すデータドリブンマネジメント推進部門(以下、DDM推進部門)です。 DDM推進部門では、全社のデータを集約して活用できるデータマートや分析基盤の構築と、データを分析して社内の課題解決に生かすコンサル業務とデータ分析できる人材の育成をしています。 本記事のポイントとして会社や上述のような組織や一緒に働く仲間からもしっかりサポートがあり 、そのサポートを私も受けて今に至っています。 例えば、社内OJTという制度があり、自身が手を挙げるとDDM推進部門等の専門性の高い組織へ行き、仕事を通し専門スキルを身に着ける制度があります。 OJTとして、専門性の高い組織で新分野にどっぷり浸かり十分なスキルを身に着けた上で自部署の業務に戻り、身につけた力を発揮できます。 さらに、OJT等の社内制度とは関係なく、 部署を超えて社員同士がデザインやデータ活用について自発的に取り組み、ノウハウの横展開やスキルアップが盛んに行われています。 (以前、本ブログで紹介した 分析コンペ もその1つです) 私自身も、様々な新しいチャレンジや業務を始めるにあたり、自分自身のスキル転換に悩むこともありました。 しかし、結論だけ言うと業務における幅も広がったので、スキル転換をして良かったと思います。 部内チームや社内OJTを通してスキル転換を図りつつ、色々な人と出会うことができ、身につけたスキルを今の仕事に活かすことができています。 そして、後述する新しいチャレンジに取り組みつつ得たスキルを業務で活かしながら、社外資格も取る事で社内外的に知識や業務経験があることを証明できたと実感しています! 例えば、 ・ Python3エンジニア認定基礎試験 ・ Python3エンジニア認定データ分析試験 ・ 人間中心設計スペシャリスト です。 NTTコミュニケーションズでは 認定された社外資格に対し資格取得の支援制度があります。 認定された資格に合格すると会社から受験料の支援があるのでチャレンジしやすい環境にあります。 さらに、会社から研修受講/団体登録/受験といった資格維持や更新のために必要な費用の負担等を支援してもらえます。 3.社内での育成の取り組み 私自身の体験も活かしつつ、自部の仲間たちのリスキリングにも貢献したいと思い、2021年10月から私の所属する部内でデータ分析人材の育成を開始しました。 このデータ分析人材の育成プログラムは習熟度により現時点でSTEP1/STEP2/STEP2.5と段階を分けています。 STEP1とSTEP2.5は、私を含めた社員による内製プログラムで研修を企画開催しています。 STEP2では、社内の事例共有会でデータ分析を役立てている事例発表会を開催し、幹部含めて実務でデータ分析を活用しているベストプラクティスを紹介して受講社員のインプットだけではなくアウトプットする機会を作り、スキルの定着や周りの社員達の仲間づくりを促進しています。 STEP1の内製研修は, CRISP-DM を基に、 ・データ分析へ至るための設計方法 ・データ分析で用いる統計基礎や手法の使い方と注意点 ・データ分析結果の表現(バイアスや伝え方の注意点) を実施し、第1~11回で、延べ431名の方に受講いただきました。 STEP1の狙いとして、データ分析の初心者向けにデータ分析プロジェクトの各フェーズでの考え方や統計基礎といった基礎力身に付けてもらうこと です。 業務でプロジェクトをこなす、または参加する際にどう進めればよいか戸惑うことがなくなり、プロジェクトで出てくる統計値の見方や気にすべきポイントが分かることを目指したプログラムにしました。 社内研修なので多少内部バイアスがかかっているかもしれませんが、下図の CSポートフォリオ分析 から、どの項目も満足度が5点満点中4以上となっています。 特に受講者の方からは内容について好評をいただきました。 この内製研修により受講頂いた方々も新しいスキルに挑戦でき、データ分析プロジェクトに対する戸惑いのハードルを乗り越えられると感じて頂けたのではないかと分析しています。 この内製研修を実施したことで部内でのデータ活用が更に広がる機会の1つになったと思います。 現在は、STEP1で基本的なデータリテラシ知識を習得した受講者の方も含め2022年10月からSTEP2.5として、Pythonによるデータ加工/前処理や機械学習を取り入れた「データ分析内製研修-シーズン2-」を企画開催しています。 「データ分析内製研修-シーズン2-」では、データ加工/前処理や機械学習の基本知識はもちろん、 社内で業務効率化や判断の適正化に繋がる題材(例:アソシエーション分析/退会予測/線形回帰モデルによる予測 等)のハンズオンも取り入れて業務に応用しやすいプログラム を組んでいます。 さらに、 実際の社内業務で使っているデータも取り扱っているため、業務への成果とスキルが直結する実感を得てもらえる ように取り組んでいます。 今後も、育成の取り組み等を通じて各部と連携しながら、組織全体の学習の最大化へ貢献できる活動をしていきたいです。 4.最後に このように、NTTコミュニケーションズでは、スキル習得に対する様々な取り組みや環境整備がなされています。 入社してから10年の間で、仕事で求められるスキルが変わり、国や社会でも求められている事も刻々と変化しています。 時代で求められるスキルや知識の変化に適応していくことも重要 だと感じます。 これからも私自身コミュニティ等を通じリスキリングをしていきつつ、学んだことを業務で活かしたり、内製研修の企画開催やコミュニティ運営という形で学んだことを社内に還元していきます。 また、社内事例の紹介では、事例記事を書いて社内ポータルへの掲載やライトニングトーク会を開催し事例のシェアを行い、スキルの具体的な活用方法を広める活動も継続していきます。 最近、文部科学省が出している 「情報Ⅱ」の教員研修用教材 を読みました。私の高校時代には無かった科目です。 内容を確認してみると、私の大学時代に履修した内容を既に高校生の時点で取り組んでいました。 国や社会のITに対する期待が高く、今の若い世代は我々の世代と比べて新しいスキルを持って社会に出てくるのだと改めて実感し、 10年後や20年後には、会社や社会で求められていくITスキルやIT知識のベースラインが変わってくる という事を肌で感じました。 今まで以上にリスキリングへ取り組み、これからも時代についていけるよう、もっと日々精進をしなければいけないと私自身、気合が入ります。 これからも会社の皆と一緒に研修やコミュニティなどを通じ、新しいスキルを身に付けて、それを役立てるように私自身も頑張っていきます。
目次 目次 はじめに ECCV2022のトラッキング論文 ピックアップした論文 Towards Grand Unification of Object Tracking Tracking Objects As Pixel-Wise Distributions Particle Video Revisited: Tracking through Occlusions Using Point Trajectories XMem: Long-Term Video Object Segmentation with an Atkinson-Shiffrin Memory Model 最後に はじめに この記事は前回の記事の後編です。ECCV2022で紹介されたトラッキングに関する論文をいくつかご紹介します。 engineers.ntt.com ECCV2022のトラッキング論文 1645本の論文の中で"tracking"や"tracker"という単語がタイトルに含まれているものは、以下の表に示した通り30件ありました。 これに限らず、Video Segmentationなどの文脈で物体追跡をおこなっている論文もあるようでした。 2次元物体追跡 論文タイトル リンク ⭐️ Towards Grand Unification of Object Tracking abst GitHub ⭐️ Tracking Objects as Pixel-wise Distributions abst GitHub ⭐️ Particle Video Revisited: Tracking Through Occlusions Using Point Trajectories abst GitHub ⭐️ XMem: Long-Term Video Object Segmentation with an Atkinson-Shiffrin Memory Model abst GitHub AiATrack: Attention in Attention for Transformer Visual Tracking abst GitHub Joint Feature Learning and Relation Modeling for Tracking: A One-Stream Framework abst GitHub Backbone is All Your Need: A Simplified Architecture for Visual Object Tracking abst GitHub Hierarchical Feature Embedding for Visual Tracking abst GitHub MOTR: End-to-End Multiple-Object Tracking with TRansformer abst GitHub Tracking Every Thing in the Wild abst Bayesian Tracking of Video Graphs Using Joint Kalman Smoothing and Registration abst ByteTrack: Multi-Object Tracking by Associating Every Detection Box abst GitHub Robust Multi-Object Tracking by Marginal Inference abst Towards Sequence-Level Training for Visual Tracking abst GitHub Tracking by Associating Clips abst Graph Neural Network for Cell Tracking in Microscopy Videos abst GitHub Robust Visual Tracking by Segmentation abst GitHub FEAR: Fast, Efficient, Accurate and Robust Visual Tracker abst GitHub HVC-Net: Unifying Homography, Visibility, and Confidence Learning for Planar Object Tracking abst Robust Landmark-based Stent Tracking in X-ray Fluoroscopy abst 3次元物体追跡 論文タイトル リンク CMT: Context-Matching-Guided Transformer for 3D Tracking in Point Clouds abst Towards Generic 3D Tracking in RGBD Videos: Benchmark and Baseline abst GitHub SpOT: Spatiotemporal Modeling for 3D Object Tracking abst 3D Siamese Transformer Network for Single Object Tracking on Point Clouds abst GitHub Large-displacement 3D Object Tracking with Hybrid Non-local Optimization abst GitHub PolarMOT: How far can geometric relations take us in 3D multi-object tracking? abst project その他 論文タイトル リンク 概要 MOTCOM: The Multi-Object Tracking Dataset Complexity Metric link project データセットの難易度評価 The Fish Counting Dataset: A Benchmark for Multiple Object Tracking and Counting link GitHub 新しいデータセットの提案 Large scale Real-world Multi Person Tracking link GitHub 新しいデータセットの提案 BodySLAM: Joint Camera Localisation, Mapping, and Human Motion Tracking link video 画像から人物の姿勢、3Dメッシュなどを推定 AvatarPoser: Articulated Full-Body Pose Tracking from Sparse Motion Sensing link GitHub 体につけた少数のVRトラッカから全身の姿勢を推定 ピックアップした論文 以下では、リストアップした中で私たちが特に興味を持った4つの論文について詳細に見ていきます。 Towards Grand Unification of Object Tracking 概要 シングルカメラのトラッキングには似て非なる以下の4つのタスクがあります。本論文ではこれらのいずれにも適用可能なモデルが提案されています。 Single Object Tracking (SOT) 動画の冒頭にユーザーがバウンディングボックスで指定した単一の物体を追跡するタスク。カテゴリの指定が無く半教師的な推論を必要とする。 サーベイ論文: Single Object Tracking: A Survey of Methods, Datasets, and Evaluation Metrics 関連データセット: TrackingNet 1 , LaSOT 2 Multiple Object Tracking (MOT) 特定のカテゴリに属する複数の物体をバウンディングボックスで追跡するタスク。車両のトラッキングなど、同じカテゴリで似通った物体を混同せずに追跡する必要がある。 関連データセット: MOT17 3 , BDD100K 4 Video Object Segmentation (VOS) 動画の冒頭にユーザーがセグメンテーションマスクで指定した物体を追跡するタスク。 関連データセット: DAVIS(Densely Annotated Video Segmentation)-2016 & DAVIS-2017 5 Multi Object Tracking and Segmentation (MOTS) 特定のカテゴリに属する複数の物体をセグメンテーションマスクで追跡するタスク。 関連データセット: MOTS20 Challenge 6 , BDD100K MOTS Challenge 研究のモチベーション 著者の問題意識として以下の2点が挙げられています。 現状最新の手法は特定のタスクに特化しすぎて汎用性に欠けている 独立してモデル設計をしているため、パラメーターが冗長化している 上記のタスクを同一のネットワークで解くことにより、これらを解決しようとしています。 関連研究 以下のようにSOTとVOTを同時に解ける手法や、MOTとMOTSを同時に解ける手法などがこれまで提案されてきましたが、4つのタスクを全て同時に解く手法は本論文が初めてだと主張しています。 SOTとVOTを同一ネットワークで解いた研究 D3S-a discriminative single shot segmentation tracker 7 , In CVPR2020 Siam R-CNN: Visual Tracking by Re-Detection 8 , In CVPR2020 MOTとMOTSを同一のネットワークで解いた研究 TrackFormer: Multiobject tracking with transformers 9 , In CVPR2021 Track to detect and segment: An online multi-object tracker 10 , In CVPR2021 提案手法 以下の図に示したネットワークはUnicornと名付けられています。まず初めに、Reference FrameとCurrent Frameの両方を解像度そのままでFPN(Feature Pyramid Network)に入力し、次に説明するUnified EmbeddingやUnified Headに渡します。 Unified Embedding このコンポーネントでは特徴マップからフレーム間をピクセルレベルで対応付けます。 まず図中のI(Interaction)の部分ではVision Transformer (ViT)を用いることで、タイムスタンプが離れているReference FrameとCurrent Frameに対して正確な対応関係を抽出します。単なるViTでは計算量が増えてしまうので、Deformable Attention Transformerと呼ばれるAttention範囲を自由に変形しながら効率よく重要な領域を参照するモデルを使っています。 Unified Head 上で得られた対応関係はタスクによって異なる活用がなされます。 SOTとVOSでは図中のP(Propagation)の部分で、ユーザーがReference Frameに与えたセグメンテーションマスクから(バウンディングボックスが与えられた場合は四角いマスクとみなし同様に処理します)、計算したピクセルの対応関係に基づいて、Current Frameにおいて物体のありそうな位置の事前分布を計算します。この事前分布は物体検出モジュールであるUnified Headの直前に適用され、画像の注目すべき箇所を示しています。 一方、MOTとMOTSでは物体検出後の図中のA(Association)の部分で、ピクセルレベルの対応関係をもとにインスタンスレベルでのオブジェクト同士の紐付けを行い、追跡中のターゲットとCurrent Frameから検出した物体の対応づけを行います。 このようにひとつの出力を4つのタスクそれぞれに流用できることがこの手法の特長です。 学習方法 全体の学習方法はSOT-MOT合同学習とVOS-MOTS合同学習の2つの段階で行われます。初めにSOT-MOT合同学習では、SOTとMOTのデータセットからエンドツーエンドにUnified Embeddingのピクセルレベルの対応損失とUnified Headの検出損失を用いてネットワークを最適化します。次のVOS-MOTS合同学習では、マスクブランチ 11 , 12 を追加して他のパラメータを固定してVOSとMOTSのデータセットを用いてマスク損失を最適化することで学習します。 実験結果 学習には16台のNVIDIA Tesla A100で回しています。論文には書かれていませんでしたが、推論もおそらく学習時と同じ環境を使っていると思われます。 各タスクそれぞれについて専門的に学習したモデルと同程度の性能を持ち、A100で入力解像度640x1024に対し20FPSというリアルタイム推論も達成しています。 感想 本来4つのモデルが必要であるところを1つのモデルで完結させることができ、トレーニングコストの面でも推論コストの面でも有用だと言えます。また、異なるタスクを単一のモデルに解かせることで、汎化性能の高いモデルが獲得できているのではないかとも感じました。 Tracking Objects As Pixel-Wise Distributions 概要 この論文では、Multi-object tracking (MOT)においてバウンディングボックスや中心点による従来のトラッキング手法と異なり、オブジェクト位置の分布をピクセル単位に推定してトラッキングする手法P3AFormerを提案しています。ピクセル単位に推定することで小さなオブジェクトにオクルージョンが発生した場合も正しくトラッキングすることが可能になります。 提案手法 次の図は、提案手法のオブジェクト位置の分布をピクセル単位で予測する方法を示しています。まず、ResNetやSwin-Transformer 13 などのBackboneが用いられ画像特徴を抽出します。そこからPixel DecoderにはDETR 14 のdecoderが用いられ、アップサンプリングを適用することでピクセル単位の表現を生成します。次に、フロー間の特徴をまとめるためにFlowNet 15 , 16 を用いて前フレームからピクセル単位の特徴伝搬(Pixel-wise Propagation)を行います。最終的にTransformer Decoderを用いてピクセル単位のオブジェクト位置の分布を予測します。 次の図は、ピクセル単位で推定されたオブジェクト位置の分布を用いてフレームごとの関連付けを行う概要です。基本的な枠組みはカルマンフィルター 17 とハンガリアンアルゴリズムを利用する一般的な方法と同様です。ハンガリアンアルゴリズムのコスト関数は式(6)のように定義されています。式(6)の右辺括弧内が、これまでの時刻で追跡されたオブジェクト と時刻 で検出された候補オブジェクトiに定義されるコストです。 は予測クラスのクロスエントロピー誤差です。 はピクセルのヒートマップを表しており、真のヒートマップ はオブジェクト中心に位置するように設定されたガウス関数が用いられます。ガウス関数の半径はオブジェクトの大きさに比例するように設定されます。つまり式(6)は、既に追跡されたオブジェクト集合と時刻 で新たに検出された候補オブジェクト集合の総当たりペアのうち、予測されたクラスラベルが正しくかつヒートマップの重なりが大きいものが同一物体として対応付けられるよう設計された関数であると言えます。 実験結果 次の図は(a)MOTR 18 , (b)TransCenter 19 , (c)提案手法のP3AFormerのトラッキング結果を示しています。画像右上に小さく表示されている人物に注目してください。(a)は小さな人物の検出に失敗しています。(b)は青枠で示しているようにオクルージョンが発生した場合IDが誤って割り当てられます。これに対して(c)の提案手法はピクセル単位のオブジェクト位置の推定によりオクルージョン下においても小さな人物を頑健にトラッキングしていることが分かります。 次の図はP3AFormerのピクセル単位で推定した中心ヒートマップとトラッキング結果を可視化しています。オブジェクトの中心は全貌が大きく隠れた場合でも正しく推定できており、結果として隠れに頑健な追跡につながっていることが分かります。 感想 トラッキングにピクセル単位の推定を用いることでオクルージョンが頑健になり性能を向上させている点が面白かったです。 Particle Video Revisited: Tracking through Occlusions Using Point Trajectories 概要 任意のピクセルをターゲットとしてトラッキングを行う論文です。この手法をベースに、ユーザーに指定されたセグメンテーションマスクのそれぞれのピクセルを追跡することでVOTタスクを解くことができます。同じくピクセルレベルの密なトラッキングが可能なoptical flowよりもオクルージョンに強く、長いフレームにわたって対象を追跡できるという特長があります。 背景 モーション推定のアプローチは2通りに分けられます。 feature matchingで特徴点の対応をとる 離れたフレーム間でも対応可能 推定が疎であり、狙ったピクセルのトラッキングができない optical flowで各ピクセルのモーションベクトルを得る optical flowの計算を繰り返せば狙ったピクセルをトラッキングできる あくまで局所的なピクセルの変化しか追えない 追跡対象の手前を何かが通り過ぎた時、手前の物にトラッカーが移るなどして破綻する 追跡中のピクセルが少しずつずれていく そしてこの2つのアプローチの中間をとった2006年のparticle video 20 では、画面全体にトラッカーを配置しフレームごとにお互いの位置関係を調整させることで、feature matchingよりも密でoptical flowよりも長期間安定したモーション推定が可能になりました。 しかしその手法は依然としてオクルージョンに対応しきれておらず、追跡対象が隠れたことは検知できるもののそのまま見失ってしまうという問題がありました。 本論文ではそれをディープラーニングベースに拡張し、任意のピクセルを独立に追跡できるうえ、一時的なオクルージョンなら再追跡ができるようになっています。 提案手法 フレームの連続画像と、トラッキングしたい点(トラッカーと呼びます)の初期座標を入力として、各フレームにおけるトラッカーの座標と、トラッカーが隠れているかどうかを示すオクルージョンフラグを推定します。原理的には追跡対象が隠れても フレーム以内にまた現れれば見つけ出せることが期待できます。 全体設計はoptical flow推定器のRAFT 21 に似ており、更新関数を繰り返し適用して次のフレームの予測値を収束させるという方法をとっています。 まずRAFTと同じネットワークを利用し、各フレーム独立に特徴マップ(feats)を作成します。 次に初期フレームでの座標 とその位置の特徴 を用意し、 フレームにわたる予測値を全てそれらに初期化します( )。これはちょうどトラッカーが フレームの間全く動いていないと仮定していることになります。 そしてIterative inferenceで囲われている処理によって各時刻におけるトラッカーの座標 , 特徴 , オクルージョンフラグ が少しずつ最適化されていき、 回のイテレーションの後に得られた予測値 を最終的な予測とします。 Iterative inferenceではイテレーションごとに次のような操作が行われます。初めに、現状のトラッカーの推定特徴 と特徴マップfeatsとのdot productをとり、トラッカーと入力画像との類似度マップを生成します。次に、類似度マップからトラッカーの推定位置 の周り の範囲を切り出します。この時切り出す解像度は 種類用意しており、1つのトラッカーに対して のshapeを持つテンソルが手に入ります。 そして、ナイーブな手法を考えるならその中で最大値を取る(つまり最も類似度の高い)点が一番もっともらしいトラッカー位置だと言えますが、本手法ではMLP Mixerと呼ばれるニューラルネットを用いてトラッカーの位置 , 特徴 , オクルージョンフラグ を推定します。以上の操作を繰り返すことで予測を少しずつ最適化していきます。 フレームの推論を終えた後、次の フレームを入力し追跡を続けることになります。しかし単に最後の予測値 を次の初期値にすると、見た目の一時的な変化(すなわち特徴量の変化)のせいでトラッカーがずれるという問題や、その時対象が隠れていた場合見失ってしまうという問題があります。そこで、オクルージョンフラグを参照し一番よく見えている時刻 の座標と、初期値の を用いて再追跡を行います。 デモ 以下のデモ動画では馬のかかとを追跡させており、提案手法では足が手前の柱に隠れても見失っていないことがわかります。 https://particle-video-revisited.github.io/videos/horse_all.mp4 particle-video-revisited.github.io 感想 物体のカテゴリによらずピクセルレベルで追跡ができるというのは魅力的に感じました。物体検出タスクなどにおけるアノテーション支援にも使えそうです。 XMem: Long-Term Video Object Segmentation with an Atkinson-Shiffrin Memory Model 概要 この論文は、1968年に提唱されたAtkinson–Shiffrin memory model 22 という感覚記憶、作業記憶、長期記憶の3つからなる記憶モデルに触発された長時間映像用のVOS手法XMemを提案しています。 この手法の特長はGPUメモリの消費が少ない点と長時間の映像にも対応できる点です。次の図は、短時間の映像データセットDAVISと、合計7000フレーム以上の3つのビデオを含む長時間の映像データセットLong-time Video dataset 23 を用いた実験結果です。左のグラフではモデルが使用するGPUメモリとVOS性能の関係、右では入力映像長を変化させたときの性能の変化が示されています。左から、提案モデルは既存モデルよりもメモリ使用量が少ないにも関わらず高い性能であることが分かります。また右から、既存手法は入力映像長が長くなると性能が劣化する一方で、提案手法の性能は劣化するどころかむしろ向上していることが分かります。STM 24 , AOT 25 , STCN 26 のように特徴メモリが急激に増加する既存手法では、メモリに保存する頻度を落として使用せざるをえず長時間入力に対して安定した性能を発揮できていません。 次の図はSTCNとXMemのスケーリング挙動を詳細に示しています。横軸がフレーム数で、縦軸が精度です。フレームが増加するとSTCNは文脈の欠落により性能が低下するが、XMemは十分な文脈を保持し安定していることが分かります。 提案手法 次の図はXMemの全体像を示しています。この手法はAtkinson–Shiffrin memory modelと同様にSensory memory, Working memory, Long-term memoryの3つのメモリストアから構成されています。Sensory memoryは毎フレーム更新され、非常に局所的な時間の特徴を保存します。Working memoryは 枚ごとに情報を蓄積し、事前に設定された最大保持フレームを超えると情報を圧縮した上でLong-term memoryに移行します。Long-term memoryは事前に設定した最大フレーム数(およそ数千フレーム)を超えると特徴を忘れる機能を持ちます。以上のように超短期、短期、長期の3つのメモリストアを活用することで非常に長い映像でも少ないGPUメモリ使用量で高品質な特徴を捉えることができます。 次の図は1フレームにおける処理をより具体的に示したものになります。 Memory reading 全体像で示されているMemory reading操作は上図のQuery, Affinity, Readout featuresの一連の流れに該当し、Working memoryとLong-term memoryから最適な特徴量 を取り出し、Decoderを通すことで推定マスクを生成します。 Working memoryとLong-term memoryで使われているメモリは、既存手法のSTCNと同様のものです。ここにはQuery encoderによってエンコードされた入力画像をkeyとし、Value encoderによってエンコードされた出力マスクをvalueとする辞書が保存されており、新しく入力されエンコードされた画像に最も適合するvalueを次の方法で読み出しています。 まずQuery encoderから出力される Query と、Working/Long-term Memoryに保存されているkey との比較から得られる類似度行列に対してsoftmaxを適用することで、Affinityと呼ばれる行列 を生成します。そしてそれを基にMemory中のvalue を重みづけたもの をMemory readingの出力 とします。 このAffinityを計算するとき、STCNで指摘されているように類似度行列の計算にL2距離を利用するとdot product 27 よりも安定するようです。しかし、次の図の(a)で示しているように全てのメモリ要素を一律に考慮しているためそれぞれの信頼度を符号化できない表現力の乏しさが難点です。そこで提案手法では収縮項 , 選択項 を用いて次の式(2)のように類似度を表現することで図の(c), (d)のように複雑な類似度関係のモデリングを可能としています。 次の節ではWorking memoryとLong-term memoryの更新方法を説明します。 Working memory Working memoryは高解像度の特徴を一時的に保存しています。上述の通り入力画像のエンコード結果であるQuery と予測されたマスクのエンコード結果であるValueの辞書からなり、 フレームごとにQueryとValueの組(以降エントリと呼びます)が追加されます。 メモリ節約のために、エントリ数がある閾値 を超えると、新しめのいくつかのエントリと、ユーザーにアノテーションされたフレームがエンコードされている最初のエントリのみを残してLong-term memoryに引き渡します。 Long-term memory Working-memoryから渡されたエントリたち は、次の図ようにプロトタイプと呼ばれるエントリたち に圧縮されてからLong-term memoryの辞書に保存されます。 まず図中のPrototype selectionにあたる部分で 組のエントリを のグリッドに分割して、その 個の中からこれまでに最も多くアクセスされた 個のパッチをプロトタイプのkey として選択します。この時アクセス数は、これまで計算したAffinityの累積和を取ることで計算しています。 次にPotentiationとして、プロトタイプのkeyに対応するvalueを からうまく重み付けして生成します。具体的にはプロトタイプのkey(図中の星マーク)に類似するグリッドを検索し、特徴量を集約してそのkeyに対応するvalue(金色で囲っている星マーク)を生成します。その結果としてプロトタイプのエントリがLong-term memoryに保存されます。 次の図は、Long-term memoryの処理を可視化したものです。最上段の画像がWorking memoryから渡されたエントリに対応する入力フレームです。黄色の十字がプロトタイプの位置を表しており、それに類似する箇所は赤色で表示されています。また、プロトタイプを示すフレームは赤枠で表示されています。具体的な連結処理では、白鳥のクチバシ(2行目)、植生の一部(3行目)、川岸の一部(4行目)、植生と川岸の境界(5行目)、水面の一部(6行目)という意味のある情報が集約されています。 Sensory memory Working/Long-term memoryから読み出した値をデコードする際に、Sensory memoryと呼ばれる、Working memoryよりもさらに短期間の情報を保持するメモリから時間局所性の高い特徴量をデコーダに加えています。このSensory memoryの更新は以下のように行われます。 次の図はSensory memory の更新を示しています。Decoderからのマルチスケール特徴をダウンサンプリングしてGRUへの入力として連結します。 フレームごとにWorking memoryの更新とともに行われるDeep Updateでは、Working memoryへの入力と別のGRUを使ってメモリを更新します。これにより既にWorking memoryに保存されたであろう冗長な情報を、最小限のオーバーヘッドでSensor memoryから破棄できます。 以上がXMemの処理内容です。Working memoryで短期的な記憶を、Long-term memoryを長期的な記憶を保持し、それらから取り出した特徴をSensory memoryの情報と合わせることで推論の時間的連続性を担保していることがわかると思います。 デモ GitHubページ にデモが載っています。10分もある動画に対してもうまく対象の人物をマスクできていることがわかります。 感想 Atkinson-Shiffrin memory modelの3つの記憶モデルを適切なネットワークに落とし込んで設計している点が興味深かったです。 最後に 本ブログでは、私たちが興味を持ったECCV2022の論文についてご紹介しました。NTT Comでは、今回ご紹介した論文調査、画像や映像、更には音声言語も含めた様々なメディアAI技術の研究開発に今後も積極的に取り組んでいきます。 アカデミックな研究に注力したくさん論文を書きたい 最新の技術をいち早く取り入れ実用化に結び付けたい AIアルゴリズムに加え、AI/MLシステム全体の最適な設計を模索したい という方々に活躍していただけるフィールドがNTT Comには多くあります。新卒採用の情報については こちらのページ をご覧ください。 今後も私たちの取り組みをブログ等で発信していきますので、興味を持ってくださった方は是非今後もご注目ください! Muller, M., Bibi, A., Giancola, S., Alsubaihi, S., Ghanem, B.: Trackingnet: A largescale dataset and benchmark for object tracking in the wild. In: ECCV (2018) 1, 9, 10, 20 ↩ Fan, H., Lin, L., Yang, F., Chu, P., Deng, G., Yu, S., Bai, H., Xu, Y., Liao, C., Ling, H.: LaSOT: A high-quality benchmark for large-scale single object tracking. In: CVPR (2019) 1, 4, 9, 10, 20 ↩ Milan, A., Leal-Taix´e, L., Reid, I., Roth, S., Schindler, K.: MOT16: A benchmark for multi-object tracking. arXiv preprint arXiv:1603.00831 (2016) 1, 4, 10, 11, 20 ↩ Yu, F., Chen, H., Wang, X., Xian, W., Chen, Y., Liu, F., Madhavan, V., Darrell, T.: BDD100K: A diverse driving dataset for heterogeneous multitask learning. In: CVPR (2020) 1, 2, 4, 10, 11, 12, 20 ↩ Pont-Tuset, J., Perazzi, F., Caelles, S., Arbel´aez, P., Sorkine-Hornung, A., Van Gool, L.: The 2017 davis challenge on video object segmentation. arXiv preprint arXiv:1704.00675 (2017) 1, 4, 11, 20 ↩ Voigtlaender, P., Krause, M., Osep, A., Luiten, J., Sekar, B.B.G., Geiger, A., Leibe, B.: MOTS: Multi-object tracking and segmentation. In: CVPR (2019) 2, 4, 12, 13, 20 ↩ Lukezic, A., Matas, J., Kristan, M.: D3S-a discriminative single shot segmentation tracker. In: CVPR (2020) 2, 4, 10, 12 ↩ Voigtlaender, P., Luiten, J., Torr, P.H., Leibe, B.: Siam R-CNN: Visual tracking by re-detection. In: CVPR (2020) 2, 3, 4, 10, 12 ↩ Meinhardt, T., Kirillov, A., Leal-Taixe, L., Feichtenhofer, C.: TrackFormer: Multiobject tracking with transformers. arXiv preprint arXiv:2101.02702 (2021) 2, 3, 4, 11, 13 ↩ Wu, J., Cao, J., Song, L., Wang, Y., Yang, M., Yuan, J.: Track to detect and segment: An online multi-object tracker. In: CVPR (2021) 2, 4, 5, 11, 13 ↩ Wang, Q., Zhang, L., Bertinetto, L., Hu, W., Torr, P.H.S.: Fast online object tracking and segmentation: A unifying approach. In: CVPR (2019) 2, 4, 5, 12 ↩ Lukezic, A., Matas, J., Kristan, M.: D3S-a discriminative single shot segmentation tracker. In: CVPR (2020) 2, 4, 11, 12 ↩ Liu, Z., Lin, Y., Cao, Y., Hu, H., Wei, Y., Zhang, Z., Lin, S., Guo, B.: Swin transformer: Hierarchical vision transformer using shifted windows. In: Proceedings of the IEEE/CVF International Conference on Computer Vision. pp. 10012–10022 (2021) ↩ Zhu, X., Su, W., Lu, L., Li, B., Wang, X., Dai, J.: Deformable detr: Deformable transformers for end-to-end object detection. arXiv preprint arXiv:2010.04159 (2020) ↩ Dosovitskiy, A., Fischer, P., Ilg, E., Hausser, P., Hazirbas, C., Golkov, V., Van Der Smagt, P., Cremers, D., Brox, T.: Flownet: Learning optical flow with convolutional networks. In: Proceedings of the IEEE international conference on computer vision. pp. 2758–2766 (2015) ↩ Zhu, X., Wang, Y., Dai, J., Yuan, L., Wei, Y.: Flow-guided feature aggregation for video object detection. In: Proceedings of the IEEE international conference on computer vision. pp. 408–417 (2017) ↩ Meinhold, R.J., Singpurwalla, N.D.: Understanding the kalman filter. The American Statistician 37(2), 123–127 (1983) ↩ Zeng, F., Dong, B., Wang, T., Zhang, X., Wei, Y.: Motr: End-to-end multipleobject tracking with transformer. arXiv preprint arXiv:2105.03247 (2021) ↩ Xu, Y., Ban, Y., Delorme, G., Gan, C., Rus, D., Alameda-Pineda, X.: Transcenter: Transformers with dense queries for multiple-object tracking. arXiv preprint arXiv:2103.15145 (2021) ↩ Peter Sand and Seth Teller: Particle Video: Long-Range Motion Estimation using Point Trajectories. In: CVPR (2006) ↩ Zachary Teed and Jia Deng: RAFT: Recurrent All-Pairs Field Transforms for Optical Flow. In: ECCV (2020) ↩ Atkinson, R.C., Shiffrin, R.M.: Human memory: A proposed system and its control processes. In: Psychology of learning and motivation, vol. 2, pp. 89–195. Elsevier (1968) ↩ Liang, Y., Li, X., Jafari, N., Chen, J.: Video object segmentation with adaptive feature bank and uncertain-region refinement. In: NeurIPS (2020) ↩ Oh, S.W., Lee, J.Y., Xu, N., Kim, S.J.: Video object segmentation using space-time memory networks. In: ICCV (2019) ↩ Yang, Z., Wei, Y., Yang, Y.: Associating objects with transformers for video object segmentation. In: NeurIPS (2021) ↩ Cheng, H.K., Tai, Y.W., Tang, C.K.: Rethinking space-time networks with improved memory coverage for efficient video object segmentation. In: NeurIPS (2021) ↩ Oh, S.W., Lee, J.Y., Xu, N., Kim, S.J.: Video object segmentation using space-time memory networks. In: ICCV (2019) ↩
こんにちは。ソリューションサービス部 スマートエンジニアリング部門の加藤( @katomasa23 )です。 新卒2年目で、普段はパブリッククラウド上に構築しているサービス提供基盤の運用自動化に携わっています。 今回私は、普段の業務を飛び出して、ドコモグループのエンジニアが日々の業務から得た学びなどを共有するイベント「dcc Engineer Day 23」 1 の運営に携わりました。 この記事では、イベントの様子や、自ら手を挙げてイベント運営に参加したことで得た学び・知見を紹介します。 dcc Engineer Day 23とは? dcc Engineer Day 23は、NTTドコモ・NTTコミュニケーションズ・NTTコムウェア3社の社員が技術を軸に交流を深める場として開催したイベントです。今年は2023年1月24日に開催し、昨年に続き2回目となります。 今回のビジョンは 「こえてあつまる こえてつながる こえてうみだす」 です。ドコモグループとして「dcc間の壁」や「職種」を こえてあつまり 、 つながり ができ、そして、新たな行動や企画が うみだされる ことを目指しています。 イベント当日の詳細は後ほど詳しく述べますが、反響を簡単に共有します。365名の方が事前登録し、イベント用に作成したSlackチャンネルへの参加は372名、ライブ配信の最大同時接続は210名でした。アンケートでは、「参加できなかった同僚に勧めたいか?(n=77)」という問いに対してNPS 2 50.6と、事務局側としては高い評価をいただくことができたと思っています。 イベント後には、会社をこえて登壇者にcoffee chat 3 を申し込んでみたという声も聞こえてきており、ビジョン達成に少しでも近づけたのではないかと考えています。 当日のコンテンツ 外部からスピーカーを招いた基調講演を2セッション、社員セッションを8セッション実施しました。 基調講演の1セッション目はNTT東日本 特殊局員の登 大遊さんをお迎えし、「世界に普及可能な日本初のサイバー技術の生産手段の確立」をテーマに講演いただきました。これからの日本が自ら新しいクラウドサービスやセキュリティ技術などを生み出す必要性やその方法論について、ご自身の経験などを交えながら紹介いただきました。サーバーラックに神棚が置いてある様子や、配線ばかりで足の踏み場もない居室の写真などを見て、現場の面白さ、技術の奥深さなどを感じました。 基調講演の2セッション目は株式会社クレディセゾン CTOの小野 和俊さんをお迎えし、「CSDX: クレディセゾンのDXへの取り組み」をテーマに講演いただき、その後、NTT Com 技術顧問の及川 卓也さん、イベント事務局の岩瀬さんを交えたパネルディスカッションを行いました。講演では、クレディセゾンのDXへの取り組みの全体像や、デジタル人材の育成手法などについて紹介いただきました。私の印象に残ったのは、バイモーダル戦略の説明です。新卒2年目の私は、バイモーダル戦略は事業計画などマクロな視点での話だと思っていましたが、身近な業務やチーム作りでも参考にできる考え方だと、講演を聞いて思いました。 また、パネルディスカッションでは撤退基準の話が盛り上がりました。講演の中で、「新しい取り組みをする時には撤退基準を決めておき、その基準を下回ったらきちんと撤退することが大事」という話がありました。その話を踏まえ、パネルディスカッションでは、小野さんが自ら始め、ある程度軌道に乗っていたサービスを自らの手で撤退したエピソードが語られました。サービスを撤退するとなると、撤退した人の責任が問われることも多いようですが、そのようなネガティブな印象・評価が付かない、失敗を許容し、チャレンジしやすくなる評価制度への変革や文化の醸成が必要だというコメントが印象に残りました。 社員セッションもすべて詳しくご紹介したいところですが、NTT Comの開発者ブログということもありまして、NTT Com社員のセッションに絞って紹介します。 コミュニケーション&アプリケーションサービス部の宇田川拓郎さんからは「テキスト解析ソリューション開発におけるスクラムの実態」をテーマに発表がありました。COTOHA APIを活用したソリューションのプロトタイプをスクラムで開発する中で、スクラムを機能させるために様々な課題をどう乗り越えたか、というのが主なトピックでした。雑談部屋やSlack上での分報、Coffee Chatの取り組みも紹介があり、私の業務チームはスクラムチームではないものの、チームの関係性向上のためにも導入してみるのは良さそうだと感じました。 ヒューマンリソース部の三村正法さんからは「育成システムの価値を最大化しユーザーに届けるためのHR社員の挑戦」をテーマに発表がありました。社内での循環型の学び合い文化を目指した「みんなの学びシェア」施策を開発する中で、プロダクト組織ではないヒューマンリソース部でもプロダクトマネジメントを活用することができ、実践から得られた学びが主なトピックでした。社内で私もユーザーとして利用することがある施策ですが、それを実例にプロダクトマネジメントについて学ぶことができ、私も日々の仕事に取り入れてみたいと感じました。 私が運営に携わったきっかけ ここからは、私が入社2年目で「dcc Engineer Day 23」の運営に携わった経緯や、運営の立場から得た学び・知見を紹介していきます。 まず、私が運営に携わったきっかけは、全社のエンジニア向けSlackワークスペースでふと見かけた岩瀬さん( @Iwashi86 )のこの投稿でした。 この投稿があったのが8月上旬。 私はちょうど7月に今の部署に異動してきたこともあり、まだ部署の雰囲気に慣れていなかったり、上長との関係構築もまだまだだったりと、応募するにはかなり高いハードルが待ち受けていました。 しかし、以前から度々名前を目にしていた岩瀬さんや、NTT Comだけでなく、ドコモ・コムウェアのつよつよエンジニアの方々と接点を持って、もっと視野を広げたい!面白いことをしたい!という気持ちの方が強く、気がつけば上長に相談DMを送っていました。 配属直後のお願いにも関わらず、上長からはOKの返信をいただき、岩瀬さんにDM。岩瀬さんからも歓迎の返信をいただき、運営事務局にアサインされることになりました。 初回ミーティングから圧倒…いつもと違うメンバーでの仕事を経験してみて 9月ごろから事務局としての活動が始まりました。 事務局の活動は基本オンラインで、週に1回のミーティングがベースです。 初回はチームビルディングということで、miroを用いたアイスブレイク等を実施しました。 普段の業務ではmiroを使ったミーティングをすることがないのと、初対面の方がたくさんいらっしゃるので超緊張です。ましてや、NTT Comから参加の岩瀬さん、水嶋さん( @mizuman_ )とも会ったことがないので何かやらかしたらどうしよ…と思っていました。 しかし、実際に始まってみると、たった1時間でアイスブレイクからイベントビジョンの骨子策定まで終わっていました。 普段の業務で参加している会議とはジャンルが違うので比較にはなりませんが、初対面の人同士で、かつオンラインでこんなスピードで物事が決まっていくのか、とただただ圧倒されました。 何回か週1回の定例を経たのち、10月ごろに細かな役割分担をしました。私は会場のメイン担当をすることになりました。会場担当で特に難しかったのは、どの会社でオンサイト会場を設けるか、という調整です。各社の広めの会場を教えてもらい、全体ミーティングで話し合いをするのですが、なかなか決まらない週が続きました。様々な観点がメンバーから毎週のように出てくるのに加え、自分自身も「2年目なので…」というやや受け身な姿勢が影響していました。 そこで一旦、受け身な姿勢をやめて、ビジョンを反映した「つながり」が会場で生まれやすいかどうか、現地・オンライン参加者の両方のUXが良くなるか、といった考えを念頭に、判断軸(オンライン配信設備の有無など)を立てることを提案しました。事務局の皆さんには受け入れていただき、そこから判断に必要な情報のみに絞って検討した結果、約1か月かけてオンサイト会場がNTT Com会場に決まりました。事務局では各メンバーが自担当に対して自律的に動く必要があったので、もう少し早い段階から積極的に動いてもよかったと反省しました。 年末年始のコロナウイルスの流行の影響を鑑み、オンサイト会場はパブリックビューイング会場としました。登壇者はリモート、あるいはNTT Com社内の会議室から発表してもらい、オンサイト会場は講演を見ながら参加者同士のコミュニケーションを取ってもらう場としました。一時はオンラインのみにするという話も出ましたが、一度ビジョンに立ち返ることで出てきた案であり、「New Normal」への第一歩を踏み出すことができたと思います。 当日、会場面では大きなトラブルもなく、来ていただいた方から「NTT Comの会場、いいですね」「来年もここでやりましょう」といった声をいただきました。ネットワーキングスペースの配置や、様々なレイアウトを試行錯誤するなどしたことで、会場自体の魅力+αの評価をいただけて嬉しかったです。また、今回、普段の業務と違うメンバーとイベントを作り上げることで、普段の仕事の進め方などを見直すきっかけにもなり、非常に収穫の多い経験となりました。 おわりに 今回は新卒2年目が所属部署を超えて、ドコモグループのエンジニアイベントの運営に携わった話を紹介しました。普段はソリューションに関わる業務をしていますが、発表はサービス・プロダクト開発の話が多く、ドコモグループ、ひいてはNTTはサービスの会社だなと改めて感じました。 ただ、サービス・ソリューションの両輪を持っている企業として、次回以降はソリューション側の話題も入って、両者のナレッジが交わるようなイベントにもなったらいいなと思うところです。(所属部署の定例でこのコメントを述べたところ、「来年は登壇者になったらいいじゃない!」と言われたのはここだけの話…笑) 今回の経験で視野が広がったので、日々の業務などを通して、エンジニアとしてパワーアップしていきたいと思います。 また、NTT Com社内では、今回のような本業を超えてナレッジを共有したり、社員同士のコラボを促すイベントを実施したりする雰囲気があり、その様子を少しでもこの記事を通して感じていただければ嬉しいです。 最後にお知らせですが、NTT Comは一緒に働く仲間を募集中です。詳しくは下のバナーから採用情報をご確認いただけると嬉しいです! dccとは、NTTドコモ(docomo)・NTTコミュニケーションズ(Communications)・NTTコムウェア(Comware)の3社の頭文字を取って、3社を表現する言葉です。一般的呼称というよりも、社内で表現する際に使う言葉です。 ↩ NPSとは、Net Promoter Scoreの略で、顧客ロイヤルティを図る指標。(参考: NPS®とは(ネットプロモータースコア)顧客満足度に変わる新指標 - NPSソリューション | NTTコム オンライン ) ↩ coffee chatとは、GitLab社の文化として根付いている、非同期コミュニケーションを円滑にするための雑談。(参考: GitLabで学んだ最高の働き方 Developers Summit 2022-02-18 ) ↩
はじめに こんにちは、ソリューションサービス部ICTイノベーション部門の安部、江口、谷内です。 私たちのチームでは2022年7月より「脳の健康チェックフリーダイヤル」サービスの機能開発を担当し、世界アルツハイマーデーである同年9月21日に無償トライアルを開始しました。ニュースリリースをはじめ、TVや新聞等の各種メディアで取り上げられたこともあり、現時点で約45万回以上ご利用いただいています。 本記事では開発に至る経緯や、システム構成・開発体制ならびに今後の展望まで、プロジェクトの全体像をご紹介させていただきます。今後の開発のご参考になれば幸いです。 脳の健康チェックフリーダイヤルのご紹介 脳の健康チェックフリーダイヤルは、電話をかけて日付と年齢を発話するだけで、AIが20秒程度で認知症の疑い有無を判定できる無料のサービスです。 サービスの詳細は こちらのURL をご参照ください。 ここから、本サービスの成り立ちなどを少しだけご紹介させていただきます。 プロジェクトのはじまり 「認知症で不安になる本人・家族・企業が少なくなる社会へ」をコンセプトに作ったサービスです。 NTT Com の社内ビジネスコンテストから生まれ、プロジェクト(以下:PJと記述)の中心メンバーの祖父母が認知症になった経験から、認知症で大変な思いをする人が少しでも減るようにという想いが込められています。 サービスコンセプト 高齢の方にも気軽に使っていただけるように、Web上やアプリではなく、電話で利用できることにこだわって制作しました。 脳の健康チェックフリーダイヤルサービスには以下のような特長があります。 事前の登録やダウンロードが不要 自宅の固定電話や携帯電話で利用できる 誰にも知られずに試すことが可能 サービスリリースから多くの方にご利用いただけているのも、手軽に認知機能の変化を確認できる仕組みだからこそだと思っています。 システムの紹介 構成図 脳の健康チェックフリーダイヤルは、電話を受けるクラウドIVRと、そのバックエンドを担うGCPおよび外部APIを中心に構成されています。 ここでは詳細な説明は控えますが、構成図の上側はユーザーが電話をかけてサービスを利用する経路、下側は管理者がサービスの利用状況を確認する経路となります。 認知機能の判定 認知症の疑い有無の判定については、音声から音声特徴量を抽出し、認知機能の変化をチェックする 日本テクトシステムズ社のONSEI と連携することで実現しています。 ユーザーが発話した音声を利用し、ONSEIのAPIと連携して認知機能の判定結果を取得します。この判定結果をIVRに音声発話させる仕組みを作り、ユーザーに認知機能の変化をお伝えしています。 ログデータの保存 ログデータの保存には、今後の開発でデータベースの構造を変更する可能性があることや、部分的なログデータを取得・更新することを考慮し、GCPのFirestoreを使用しています。 また、ログ参照用のWebアプリを独自で開発しており、こちらのフロントエンドフレームワークにはReactとNext.jsを使用しています。これらはWebサーバー機能を持つフレームワークの中でもJavaScriptを利用するため学習コストが低く、高速描画が可能なため、採用しました。 画面のデザインやコンポーネントの部分には、ReactのUIライブラリであるMaterial-UIを使用しています。 また、開発メンバー全員でログ参照用のWebアプリを利用しながらシステムの改善点を話し合う取り組みも行っており、実際に一部の不具合の改修や追加機能の開発に繋げることもできました。 アプリケーションの実行環境について GCPのアプリケーション実行環境としては、Cloud Run, Cloud Functions, Google Kubernetes Engineなど複数の候補がありますが、今回はGoogle Kubernetes Engine(以下:GKEと記述)を採用しています。 今回GKEを選択した大きな理由を、以下にまとめました。 コンテナ死活監視による自己修復機能 24時間利用可能なサービスのため ローリングアップデートが可能 ダウンタイムなしで継続的なアップデートを行いたいため 自動スケールアウトが可能 通常時とメディア紹介時などでユーザの利用量が数十倍単位で変動するため 脳の健康チェックフリーダイヤルは24時間利用可能なサービスとして提供しているため、ダウンタイムを極力発生させないことが最も重要な観点でした。また、マニフェストファイルベースでリソースを管理することで、環境構築が容易になる、環境間での差分がコード上で確認できるなどのメリットも得られました。 Kubernetesの利用は学習コストが高いイメージでしたが、GKE Autopilotを用いてプロジェクト固有のオペレーション部分のみ設定値を追加して運用することで、短期間で本番環境向けの基盤を構築できました。 開発体制の紹介 すでに多くの方々にご利用いただいている脳の健康チェックフリーダイヤルですが、開発チームは2年目社員2名、1年目社員1名、パートナー社員1名のかなり若いメンバーで構成されています。 本章では、このような開発経験の浅いチームが、2カ月という構築期間の中でサービスリリースを達成するまでに直面した課題と、その解決にいたった成功要因を紹介いたします。 若いチームならではの課題 開発経験に乏しいチームの課題として、真っ先に直面するものは、多くは経験の少なさによるものかと思います。本PJは、2022年9月21日の世界アルツハイマーデーにリリースするという、スケジュールが決まったウォーターフォール型のPJとしてスタートしました。しかし、私たちのチームではウォーターフォールでの開発経験がなかったため、開発プロセスの習熟面に課題がありました。また、チームとしてインフラ構築を中心としたシステム開発の知見に乏しく、メンバー間でも知識に差がある、といったスキル面での課題がありました。 一方で、今回のチームならではの強みもありました。それは、チームビルディングの面と、スクラムでの開発経験値です。今回の開発メンバーは、別案件のスクラムチームのメンバーがほぼそのままアサインされる形だったため、すでにお互いのスキルや開発環境の把握、関係性の構築などが完了している状態でした。また、ウォーターフォール開発には疎いものの、スクラムのフレームワークに対する共通認識は持つことができていました。 そのため、私たちは実際の開発に着手する前段階として、今回のウォーターフォール開発PJを、どうにかして自分達の慣れているスクラム”風”に進められないかを考えるところからスタートしました。 開発プロセスの課題解決につながったこと スクラム風に開発を進める ここではスクラムフレームワークに関する説明は省きますが、スクラムは柔軟に変化に適応するための開発手法のため、成果物と納期が明確になっているウォーターフォール型PJには本来適応できません。しかし、本PJのPMがスクラムに理解のある方だったこともあり、開発メンバーからスクラムの様に開発を進めたい旨を伝えると、快く相談に乗っていただけました。結果的に、以下のような取り組みのもと、擬似的にスクラムの様に進めることができました。 WBS(進捗管理表)の中項目をプロダクトバックログ(プロダクトの改善に必要なもの)と見立てた PMが定める各項目の期日について理由を確認しつつ、各スプリント(スクラムにおける開発期間の単位。本PJでは一週間)での対応範囲についてPMとの意識合わせを行なった WBSの進捗の遅れに対するステークホルダーとの調整を、PMに柔軟に行なっていただいた 1つのスクラムチームに集中する スクラム風に進めていくと決定した訳ですが、開発着手直後はそれまで所属していたスクラムチームと兼任する形になってしまいました(PJ立ち上げ時にはよくある話かと思います)。しかし、複数のスクラムチームの兼任は基本的にご法度です。スクラムではスクラムイベントと呼ばれる活動に開発期間の20%以上の時間を費やすため、仮に2つのスクラムチームを兼任すると、実作業時間が80%から少なくとも60%以下に減少します(複数案件による認知負荷の増加を考えると、作業効率も悪くなります)。 開発チームとしてはそういった問題を初期段階から認識していたため、ステークホルダーとの相談により3スプリント目(≒3週目)からメンバー全員が本スクラムチームに専念できました。アジリティ高く兼任問題に対応できた点は、スクラムに対する共通認識を持てている本チームの強みが発揮された場面だと感じています。 スキル面の課題解決につながったこと メンバー間のスキル格差を埋める スクラムにおいては、開発メンバー全員がどんなスプリントバックログ(≒開発タスク)にも着手できる状態が理想です。しかし、開発経験が浅い本チームでは、初めて経験するような作業も多く、特定のメンバーしか着手できないようなタスクになってしまう危険性がありました。 その対策として、本チームでは意識的に情報発信の手段を増やし、その頻度を高めています。具体的には以下の内容に継続して取り組んでいます。 タスク着手時にSlack上で作業状況を実況するスレッドを立てる 後続タスクを進める上で必要になる情報、ノウハウがあればNotion上に開発備忘録としてまとめる スプリント内でマージされたコードに対して、スプリント最終日に全員でコードリーディングを行う 定期的に全員でアプリケーションのリファクタリングを兼ねたコードリーディングを行う 毎週不安のある技術要素などについて勉強会を行う これらの活動は、時間的コストがもちろんかかるのですが、特に経験の浅いチームにおいては、最終的に費用対効果がプラスになると感じています。チームメンバー全員の理解の助けになることも勿論ですが、何かしらのアウトプットを伴うことで、タスクに着手したメンバー本人の理解度も向上し、結果的に後続タスクの実施速度も上がるためです。 実際に達成したベロシティ(タスクの重さの相対的な見積もり値)の推移を見てみると、スプリントが進むにつれ大きくなっていく結果になりました。 これには、スキル共有や自発的なアウトプットにより、PMに管理されなくても開発メンバーが率先して動くことができる、自己管理型のチームとして動けたこともプラスにはたらいていると感じています。 経験値のあるメンバーを最大限活かす 一方で、若手メンバーだけでは解決できない技術課題があったことも事実です。システムのセキュリティ対策や、根が深いエラーの調査など、対応難易度が高いタスクについては、経験を積んでいるパートナー社員の方に集中的に対応していただく機会が多かったです。 これは経験値のあるメンバーに丸投げするという話ではなく、各スプリントのベロシティを最大化するためにどのように行動するのが最適かを、開発メンバーが自律的に判断して出した結果になります。スキルを持つメンバーに技術難度の高い課題にフルコミットしてもらえるように、チームとして柔軟に動くことが出来た点も、短期間でのリリースに繋がったと感じています。 まとめ 私たちのチームでは、開発経験の浅いチームによくあるであろう課題について、以下のように取り組みました。少しでも参考になる取り組みが見つかれば幸いです。 ウォーターフォールでの開発経験がない スクラム”風”開発のためのステークホルダーへのはたらきかけ 1つのスクラムチームに集中するためのはたらきかけ システム開発のスキルに乏しい 開発メンバーの自発的なアウトプットの仕組み作り チームのベロシティを最大化する意識付け 脳の健康チェックフリーダイヤルの今後 脳の健康チェックフリーダイヤルは、少しでも多くの方に、より早く使っていただきたいという思いから、まずは最小限の機能でリリースをしています。 一方で、より「認知症で不安になる本人・家族・企業が少なくなる社会」の実現を目指して、現在も開発を続けております。その内容を一部、ご紹介させていただきます。 サービス機能の拡充 認知症の一層の早期発見・早期治療を促していくため、認知症の一歩手前の状態「軽度認知障害」、もしくは「MCI(Mild Cognitive Impairment)」といわれる状態を検知する仕組みを検討しています。こちらの仕組みを実現し、脳の健康チェックフリーダイヤルへ組み込むことを目指して、日々開発に取り組んでいます。 また、データの収集/分析の機能を組み込み、「データ利活用」ができる仕組みとすることで、より社会貢献につながるサービスを目指しています。 パートナー企業様との協業 このサービス単体で何かを成し遂げるには限界があるため、利用者の悩みを解決できるようなパートナー企業様との協業を、本格的に実施していきます。 とてもありがたいことに、2022年9月21日のニュースリリースの段階で、この取り組みに対して多くのパートナー企業様に共感・賛同いただきました。「認知症で困る本人・家族・企業が少なくなる社会」の実現に向けたさまざまな分野での取り組みを加速するため、認知症に関する社会課題解決にともに取り組んでいただけるパートナー企業様を引き続き募集しております。 おわりに 今回は「脳の健康チェックフリーダイヤル」サービスの開発の裏側をご紹介しました。 今後はサービスをより多くの人に使って頂けるよう、パートナー企業様と連携しながら、日々改善に取り組んでいく所存です。2023年3月末まで無料で利用可能の予定ですので、皆様も是非ご自身やご家族などの健康増進にご活用ください! 最後までお読み頂き、ありがとうございました。
JANOG51参加報告 イノベーションセンターの田島です。サービスプロバイダーネットワーク網の技術検証から検証用 AS の設計・構築・運用まで担当しています。 2023/01/25 ~ 27 の日程で富士吉田市にて開催されました JANOG51 に登壇し、参加された方々と議論しました。 この記事ではまず田島が登壇したセッション内容について振り返り、加えて NTT Com の他のメンバが登壇したセッションについてもいくつか紹介します。 JANOG51はアーカイブ動画が 2023/02/28 まで配信中です。 この記事以外でも NTT Com からパネリスト参加や LT での発表もありますので、 プログラム一覧 から資料や録画を是非ご覧ください。 もし本番ネットワークをまるごと仮想環境に"コピー"できたらうれしいですか? TIS 株式会社、ビッグローブ株式会社、NTT Com の3社協同プロジェクトで取り組んでいる、ネットワークトポロジーをモデルへ抽象化して処理する取り組みについての発表でした。 以前、本ブログの記事 ネットワークをモデルとして抽象化しオペレーションを高度化するチャレンジ でも紹介しましたが、さらに内容が深まっています。 発表内容については JANOG51 のプログラムページから資料が閲覧できますので詳しくはそちらをご参照ください。 実際にユースケースを動かしてみたターミナルの動画もリンクがあります。 簡単に振り返ると、このセッションでは我々が考案したネットワークの各レイヤーをグラフとして捉えて抽象化する、トポロジーモデルを介した検証環境の立ち上げについて発表し議論しました。 既存の本番環境の設定からモデルデータへ抽象化することで、使用するアプライアンスやネットワーク OS が本番環境と検証環境で違っていても相互変換可能にしました。 この仕組みを用いると十数台のキャリアルーターからなる本番環境であっても、操作可能な検証環境を数分で起動できました。 議論も活発に行われ、モデルによる抽象化の功罪や、検証環境に求める要件、そしてこのシステムを普及させるための方法など、参加者の方々と共に問題についての理解が深まりました。 このプロジェクトでの途中成果物は GitHub で既に公開しています。 現在はまだドキュメントの整備などが追いついていませんが、今後更新し、サンプルの検証シナリオをみなさまの PC 上で体験できるようにする予定です。ご期待ください。 ホワイトボックス伝送の導入に向けたキャリアの取り組み このセッションではホワイトボックス伝送装置の NOS、他ベンダー相互接続性、設計・制御ソフトウェアについてキャリアとしての観点での評価結果と課題を、イノベーションセンターの木村と張が発表しました。また、本取り組みに関連するコミュニティである TIP( Telecom Infra Project )、IGF( IOWN Global Forum )での我々の活動も紹介しました。 議論ではホワイトボックス伝送、ディスアグリゲーションモデルの訴求点に関して参加者の方々と意見交換を行い、課題について理解が深まりました。 今後は新たなホワイトボックス伝送装置や周辺ソフトウェアを評価し、伝送ネットワークのオープン化に向けての技術開発を継続していきます。 CUEとKubernetesカスタムオペレータを用いた新しいネットワークコントローラをつくってみた このセッションでは、我々が開発したネットワークコンフィグの宣言的管理を可能にするシステムについて、イノベーションセンターの奥井が発表しました。 このツールを用いることで、高レベルなインテントベースのコンフィグ作成、静的解析や構成テスト、GitOps が可能となり、アプリケーションインフラのマニフェストと同じようにネットワークコンフィグを管理・デリバリできます。 クラウドネイティブなアプリケーション開発で培われた、Infrastructure as Code と GitOps のプラクティスやオープンソース(Kubernetes、CUE、FluxCD など)を駆使して実装されています。 議論では、Kubernetes カスタムオペレータの使い方の是非について活発な意見交換が行われ、装置状態を観測しつつ管理ライフサイクルを隠蔽するための案として Ansible Operator を用いるのはどうか、といったコメントもいただき、さらなる取組に向けて大変有意義なものになりました。 現時点では gNMI/OpenConfig を用いたデバイス限定、かつコンフィグ管理に限定した利用となりますが、GitHub 上で公開していますので、ご興味があればご覧いただけると嬉しいです。今後は、対象デバイスの拡張や実運用を見据えた機能拡充を進めていく予定です。 おわりに 上記以外にも多数の興味深いセッションがありますので、是非公開期限の 2/28 までに JANOG51 プログラムページからアーカイブ動画をご覧ください。
はじめに こんにちは。イノベーションセンター、テクノロジー部門、データ分析コンサルティングPJの更科です。 この記事では、2022年12月08日にβ版フリートライアルキャンペーンが始まった Node-AI で時系列データの因果分析・重要度可視化・要因分析などをしてみようと思います。 Node-AIは時系列データの分析をするNTT Communicationsの内製開発サービスで、製造業を中心に様々な領域で活用されています。Node-AIについて詳しくは「 ノーコードAIモデル開発ツール Node-AI 」や「 ノーコードAI開発ツールNode-AIの紹介 」をご覧ください。 読んでほしい人 ノーコード(ローコード)AI開発ツールに興味がある人 時系列データの可視化に興味がある人 因果分析、特徴量重要度、要因分析に興味がある人 伝えたいこと Node-AIを使ってデータの様々な情報を可視化できる! Node-AIを使って因果分析・重要度可視化・要因分析ができる! 重要度可視化やニューラルネットワーク(Multilayer perceptron、以下「MLP」)の要因分析ではNTT Comの独自技術が使われている! 用いるデータ 今回は こちら の、シエーヴル(ベルギー)にある住宅における消費電力、気温、湿度等のデータを使っていきます。 データには以下の情報が含まれています。 date : 日時/時刻(10分刻み) Appliances : 家電の消費電力(Wh) (AIモデルで予測する対象) lights : 照明設備が消費する電力(Wh) T1 : キッチンの気温(°C) RH_1 : キッチンの湿度(%) T2 : リビングの気温(°C) RH_2 : リビングの湿度(%) T3 : 洗濯室の気温(°C) RH_3 : 洗濯室の湿度(%) T4 : オフィスルームの気温(°C) RH_4 : オフィスルームの湿度(%) T5 : 浴室の気温(°C) RH_5 : 浴室の湿度(%) T6 : 住宅の外(北側)の気温(°C) RH_6 : 住宅の外(北側)の湿度(%) T7 : アイロン室の気温(°C) RH_7 : アイロン室の湿度(%) T8 : 子供部屋の気温(°C) RH_8 : 子供部屋の湿度(%) T9 : 両親の部屋の気温(°C) RH_9 : 両親の部屋の湿度(%) T_out : 観測所(シエーヴル)での気温(°C) Press_mm_Hg : 観測所(シエーヴル)での気圧(mm Hg) RH_out : 観測所(シエーヴル)での湿度(%) Windspeed : 観測所(シエーヴル)での風速(m/s) Visibility : 観測所(シエーヴル)での視程(km) Tdewpoint : 観測所(シエーヴル)での露点温度(°C) これらを使って未来の消費電力(Appliances)を予測するという問題を考えます。 消費電力が増える要因を特定する事で、例えば 各世帯の蓄電池への電力供給を最適化する 外気温等の予測可能なデータが影響している場合は、夜間の電気代が安い時間帯にバッテリー充電をしておく 消費電力増大の予兆が見えたら、自動で空調を弱めてブレーカーが落ちないようにする などの施策ができます。 統計量とグラフ まずはデータをアップロードして、統計量やグラフを確認します。 データのアップロードの仕方やモデル作成手順については「 ノーコードAIツールNode-AIを使って簡単に需要予測をしてみた 」をご覧ください。 (今回のデータは日付が「日-月-年」のフォーマットに従っており、Node-AIでは適切に読み込めないため、「年-月-日」のフォーマットに変形してからアップロードしています。) Node-AIは自動で統計量などを計算し、以下のように表示してくれます。 テーブル(元データ) 統計量など グラフ ここで、どのようなデータであるのか概要を掴んだり、欠損値等の確認をしてどんな前処理をするか決めていきます。 この例では、グラフを見ると多くの時間帯で消費電力が40~100程度である一方で急激に消費電力の増える時間帯がある事などがわかります。 仮に家電の使用状況等から「もっとなだらかなグラフになるはず」という事実がわかっているなら、データの測定方法に問題があるのかもしれません。 今回用いているデータに欠損値はありませんでしたが、欠損値がある場合は「欠損値補間」カードを使って直前や直後の値で埋めたり、前後の値を使った線形補間もできます。 他に「文字列置換」「外れ値補間」、「移動平均」、「時間差分」、「正規化」、「時間窓切り出し」、「時間窓結合」、「リサンプリング(アップサンプリング、ダウンサンプリング)」といった前処理用のカードが用意されています。 因果分析 データ分析を現実の問題に適用する場合、データ間の因果関係は重要な要素となります。 たとえば、A, B, C3つの値があり、AがB, Cそれぞれに影響しているもののBとCの間には因果関係がないという場合を考えます。 このとき、BとCには相関関係があるかもしれませんが、Cの値を人為的に操作してもBの値は変わらないという事になります。 Node-AIにはVAR-LiNGAM(詳しくは こちら をご覧ください。)という手法を用いてこのような因果関係を推論する機能があります。 右側にはデータ間の因果関係が表示され、左側には因果の強さが表示されます。 t=0やt=-1は時刻を表しており、今回は10分刻みのデータを用いているため、tが1増えると時刻が10分進む事になります。 この例では、消費電力(Appliances)に10分前の子供部屋の湿度(RH_8)と両親の部屋の湿度(RH_9)が負の影響を与えていると推論されています。(中央付近の5つのノードが繋がっている箇所に注目しています。) 部屋の湿度が下がった際に、加湿器を使って消費電力が増えているのかもしれません。 このように因果分析をする事でデータ間の因果関係がイメージ通りであるか確認でき、時には新しい気づきを得られる事もあります。 重要度可視化 Node-AIには特徴量重要度を可視化する「重要度可視化」カードも用意されています。 重要度可視化ではHilbert-Schmidt Independence Criterion(HSIC)を発展させたNTT Comの独自技術を使って重要度を算出しています。(詳しくは こちらの論文 をご覧ください。) 線型な関係のみを使って算出される相関係数とは異なり、HSICでは非線型な関係も検出できるという特徴があります。 相関係数と重要度(HSIC)の違いについてもう少し具体的に説明します。 以下は各グラフの相関係数を表した図です。 (出典: Wikipedia ) たとえば3段目(赤枠内)のように、2つの(数値型)データを縦軸横軸にとってプロットしたグラフがランダムではなさそうな形になる場合、2つのデータにはある種の関係があると思われますが相関係数の絶対値は大きくなりません。 しかし、これらのグラフに対してHSICの値は大きくなります。 以下は今回のデータについてNode-AIで重要度を可視化した結果です。 Node-AIでは目的変数(予測したい値)に対して重要度が高い説明変数(予測に用いる値)から順番に表示され、「類似」をクリックする事で、その説明変数に対して重要度の高い別の説明変数が表示されます。 ここではT6(外気温)に対してT_out(観測所での気温)、T2(リビングの気温)、Tdewpoint(観測所での露点温度)の順番で重要度が高いと表示されています。 T6(外気温)とT_out(観測所での気温)は、地形の問題もありますが大きく変わらないと思うので重要度が高くなるのは自然かなと思います。 T2(リビングの気温)がT6(外気温)に対して重要度が高くなるのは、リビングに玄関があって頻繁に外気が入ってくる、といった事情があるのかもしれません。 この例では単純に相関の高いものが出てきていますが、データに依っては他の関係によって重要度が高くなる場合もあります。 データ量が多く処理に時間がかかる場合などに、重要度が低いデータを説明変数から外す事で性能を保ったまま処理を高速化させる事が期待できます。 学習済みモデルの性能評価及び要因分析 最後に学習済みモデルの性能評価と、性能に影響している要因の可視化について説明します。 Node-AIには大きく分けて「ニューラルネットワーク(MLP)」、「線形モデル」、「Random Forest」の3つのモデルが搭載されています。 今回は住宅の10分間における消費電力を直近2時間の各種データ(消費電力、湿度、気温、etc.)と線形モデルを使って予測してみます。 こちらも、データの前処理やモデルの学習については「 ノーコードAIツールNode-AIを使って簡単に需要予測をしてみた 」をご覧ください。 学習済みモデルと評価用のデータを使って性能評価した結果が以下になります。 モデルの予測値と実測値が重なって表示されており、左側にはモデルの性能を表す各種指標が表示されます。(青が予測値、水色が実測値を表しています。) MAE(Mean Absolute Error/平均絶対値誤差)が27.3なので、今回作成したモデルの予測値は実測値から平均的に27.3ずれているという事になります。 モデルの性能を表す各種指標が自動で計算されるため、モデルのパラメータを変えて学習し直した時など、性能をすぐに確認できて、とても便利です。 要因分析では、この結果にどのデータが強く影響しているか一目でわかるように表示してくれます。 因果分析と少し似ていますが、作成したモデルがどの値を見ているか(或いは見ていないか)がわかるため、精度向上のためのフィードバックが得られます。 ここで、赤はプラスの影響、青はマイナスの影響を表し、色の濃さで影響の大きさがわかります。 たとえば、目的変数の直前の値だけに大きく依存して他の値をほとんど使っていない場合は、表の右上が赤くなり、他は真っ白になるため一目でわかります。(グラフを右にスライドさせるだけのモデルなどです。) このような場合はRidge回帰のように一部の値に依存しにくいモデルを使う事で、精度向上の可能性があります。 (少なくとも異なる学習済みモデルができるはずです。) ある程度精度の高い学習済みモデルができた後は、要因分析とドメイン知識を組み合わせて様々な考察ができます。 例えば、洗濯室の湿度(RH_3)に着目してみると1~2時間前の値はプラスに影響しているものの、1時間以内の値はマイナスに影響しています。 ここから「この家では、洗濯室の近くでシャワーを浴びて湿度が上がった1~2時間後に洗濯機を動かして消費電力が増えるのかもしれない。その間は換気をして湿度が下がっているのかもしれない。」といった考察ができます。(全然違うかもしれません。) このように、現実の問題を考える場合は、データからはわからないドメイン知識とデータ分析からわかる定量的な事実を組み合わせる事が大切かなと思います。 モデルでニューラルネットワーク(MLP)を選択した場合はXAI(説明可能なAI)の技術を使って要因分析を行なっています。(詳しくは こちらの論文 をご覧ください。) このように、時間ごとに要因分析が行われ動画で表示されます。目的変数の値が大きく変わったときに、どのデータが影響しているかなど、コマ送りで確認できます。 まとめ Node-AIではデータが持つ様々な情報を簡単に可視化できる! Node-AIで因果分析・重要度可視化・要因分析ができる! 重要度可視化やニューラルネットワーク(MLP)の要因分析ではNTT Comの独自技術が使われている! 終わりに いかがだったでしょうか。この記事を読んで、少しでもNode-AIに興味を持ってくれた方がいれば幸いです。2023年1月現在、Node-AIはフリートライアルキャンペーンを行っているので、興味を持ってくれた方は是非ご自身でNode-AIを使ってみてください!(リンクは こちら )
はじめに こんにちは。 Smart Data Platform (SDPF) クラウド/サーバー SDNチームの田島( @UdonYuya )です。 普段はSDPFクラウド/サーバーのSDN(Software Defined Network)基盤の開発をしています。 この記事では、2022年12月9日に開催されたTech-Nightと、2022年12月28日に行われたTech-Midnightいうイベントをご紹介します。 Tech-Nightとは Tech-NightはNTT Com内の有志で開催している発表会です。 業務や趣味で技術的に挑戦したことやサービスの裏側について部署の垣根を越えて共有することや、アウトプットの場、対外発表の練習などを目的として開催しています。 定期開催しており、最近は3ヶ月に1度の頻度で開催しています。 第1回目の開催は こちら で紹介されている通り、 2018年12月の開催で、今回の開催で4年間続くイベントとなりました。 Tech-Nightの発表内容 今回のTech-Nightでは次の6つのテーマの発表がありました。 とう道見学&チーム定例の議事録を工夫した話 JenkinsからGitHub Actionsに移行してCIの実行時間と安定性を改善した話 プロジェクトX ~データセンターYから撤退せよ~ 【新入社員が】Firecracker論文【読んでみた】 OCNにRPKI入れた話 GitHubの社内レポジトリ探検してみた それぞれの発表の簡単な紹介をします。 とう道見学&チーム定例の議事録を工夫した話 1つ目は SDPFクラウド/サーバー の仮想サーバーチームの宮岸さん( @daiking1756 )からの発表でした。 この発表では、「とう道見学紹介」と「チーム定例の議事録を工夫した話」の2つのトピックが話されました。 とう道見学 とう道は通信ケーブルを通す地下トンネルのことで、NTTでは一部地域でこのとう道の維持管理を行っています。 参考: このとう道の見学会がNTT Comでは定期的に行われており、担当者さんが丁寧に各設備の説明などを行ってくれるそうで、 ケーブルが束ねられ鉄の管の中に通されている様子も実際に見て確かめることができるそうです。 このような通信の超低レイヤをこうして体験できるのもNTTならではのことではないかと思います。 地下の大きなトンネルなので、なんとなく寒そうなイメージを私は持ったのですが、意外とそんなこともないらしく10月の朝でも中は暖かったそうです。 実際に行ってみないとわからない意外な発見ですね。 次回の開催時は私も応募して参加したいなと思っています。 チーム定例の議事録を工夫した話 次にチーム定例の議事録を工夫した話で、宮岸さんが定例会議に持った課題感とその改善策について話していただきました。 定例会議で特定のスコープの話にフォーカスしすぎて他のタスクの議論が疎かになってしまうなど、 定例会議の課題は多くの人が多かれ少なかれ抱えていてると思います。 このテーマはNTT Comの開発者ブログにも書かれているのでぜひチェックしてみてください。 JenkinsからGitHub Actionsに移行してCIの実行時間と安定性を改善した話 2つ目は飯國( @guni1192 )さんからの発表でした。 飯國さんはSDPFクラウド/サーバーにおけるネットワークコントローラ ESI (Elastic Service Infrastructure)の開発をされています。 このテーマもNTT Comの開発者ブログにも書かれているのでぜひチェックしてみてください。 飯國さんは1年目社員の方だったのですが、新しくチームに入ったばかりにも関わらず、 現行CI基盤の課題を正しく汲み取って要件定義し、問題を推測ではなく計測によって発見・改善されています。 CI基盤の改善は社内の他チームにとっても重要な課題であり、知見の共有としてもかなり意味のある発表でした。 プロジェクトX ~データセンターYから撤退せよ~ 3つ目はSDPFクラウド/サーバー開発環境の保守運用チームの方からの発表でした。 この発表では、SDPFクラウド/サーバーの開発環境のサーバーやネットワーク機器を含むデータセンターの移転についてお話をしていただきました。 SDPFクラウド/サーバー開発組織にはデータセンターの配線やラック管理など物理作業の専門チームがいて、 開発チームはそれより上のレイヤに専念できるような体制となっております。 今回のデータセンター移転に際しても、非常に困難な課題であるにも関わらず私達開発チームへの依頼はほとんどなく、普段の開発業務に集中できました。 その内部では大規模なサーバーやネットワーク機器の再設計や再配線などの物理的な工程を始め、 タスクの切り分け、チーム・部署・会社を越えたマネジメントなど、開発とは別次元のエンジニアリングが行われていることを知ることができました。 【新入社員が】Firecracker論文【読んでみた】 4つ目は一人目の宮岸さんと同じSDPFクラウド/サーバーの仮想サーバーチームの松下さん( @bean_public )からの発表でした。 チームで実施しているジャーナルクラブという勉強会で共有した内容をTech-Nightでも発表していただきました。 Firecrackerとは、AWS Lambdaというサーバーレスのコンピューティングサービスで使われている仮想化基盤です。 発表では論文を読んでわかったFirecrackerの目的やアーキテクチャを、 SDPFクラウド/サーバーの仮想化基盤の開発者視点で説明していただきました。 個人的にはジャーナルクラブという取り組みが素晴らしいなと感じていて、 仕事以外で何かを学び、さらにそれをチームに共有できる場所と時間を設けていることを真似したいと思いました。 とりあえずFirecracker論文は読もうと思います。 あと、SDPFクラウド/サーバーにも実装されることを期待します(笑) OCNにRPKI入れた話 5つ目はインターネットプロバイダーであるOCNのバックボーン開発チームの中森さん( @to_nakamori )からの発表でした。 RPKI(Resource Public Key Infrastructure)とは、 IPアドレスやAS番号などのアドレス資源の割り振り・割り当てを証明するための公開鍵基盤のことで、 経路ハイジャックの防止などインターネットの経路制御をセキュアに保つための仕組みです。 (参考: https://www.nic.ad.jp/ja/rpki/ ) RPKIではROA(Route Origin Authorizations)と呼ばれるIPとAS番号のペアをリソース証明書から生成し、 それを実際に受信した経路情報と比較して正しい経路なのかを判別します。 今回の発表では、ROAキャッシュサーバーをOCNに導入した経緯や導入途中で見つかったバグ、行った試験などを話していただきました。 OCNへの導入は(OCN顧客向けは除き)完全に完了されたそうですが、RPKIの性質上OCNだけが導入してもあまり効果がでないため、 今後は他のISP事業者などにRPKIの導入、ROAの登録を促していくことが必要になってくるそうです。 GitHubの社内レポジトリ探検してみた 最後はイノベーションセンターでセキュリティ製品の研究開発をしているMetemcyberチームの西野さん( @nitky )からの発表でした。 セキュリティ強化ツール Threatconnectome の検証で得た知見から、NTT Com社内リポジトリの特徴を紹介していただきました。 NTT ComではGitHub Enterprise Cloudを利用しているのですが、 エンタープライズ配下にOrganizationだけでも13個、リポジトリはinternal/publicだけでも640というかなりの数となっていてまさに探検といった感じでした。 発表の中では各Orgの特徴やよく使われている言語、見どころなどが紹介され、 例えば私が所属しているSDPFクラウド/サーバーのOrgはリポジトリ数が302(社内公開になっているもの)もあり、 1週間に約150ものリポジトリを更新する巨大Orgであることが紹介されました。 またエンタープライズ全体での拡張子別の集計の紹介もあり、プログラミング言語ではPython、Golang、JS、PHPの次にCUE言語のファイルが多いこともわかりました。 CUE言語が全体の5位に来るのはかなり特徴的なんじゃないかと思います。 ほかにもpemファイルが1133あり、一見セキュリティ上まずいんじゃないかとなるんですが、これは性能検査などのテスト用に使われているファイルで大丈夫とのことでした。 発表の最後ではGitHub運用やコードが参考になるおすすめOrgの紹介もあり、 私は特にCI/CDの手法なんかをこのおすすめOrgのリポジトリから真似しようかなと聞きながら考えておりました。 Tech-Midnightとは Tech-Midnightは2020年から行われている年末に開催しているLT大会です。 Techという名前を冠していますが、こちらではトークテーマに制限なく何でも5分間話していい会となっています。 Tech-Midnightは年末に開催されることもあって、某国民的歌合戦になぞらえて紅白に分かれたLT合戦という形式で行われています。 本家の紅白の組分けは男女で分けられますが、こちらの組分けは完全ランダムとなっています。 2020年と2021年はどちらも紅組の勝利となっており、今年は白組の初勝利となるか、紅組の三連覇となるか、という視点でも盛り上がりました。 このLT大会が終わるといよいよその年が終わったなという実感が湧きます。 Tech-Midnightの発表内容 またTech-Midnightでは次の24個(多い!)テーマの発表が紅白に分かれて戦いました。 ちなみに私もTech-Midnightでは発表者として参加して、紅組の「Build an Orchestrator in Goの紹介」という発表をしました。 そして気になる結果は、なんと初の白組の勝利でした! 今年感動したアルゴリズム1・2や、危ないアプリHackの類型(スマホアプリのハッキング・グリッチ事例紹介)などを中心に 聞き手の驚きを誘う発表が多く納得の勝利となりました。 Tech-Midnightは比較的内輪向けのイベントのため発表の詳細は割愛しますが、 Techに限らずバラエティ豊かなテーマと5分の発表のテンポ感が相まり、Tech-Nightに負けず劣らず盛り上がりました。 おわりに 本記事ではNTT ComのエンジニアコミュニティのイベントであるTech-NightとTech-Midnightを紹介しました。 これまで紹介したように、ネットワークからとう道、フォロワーの増やし方や留学のお話など本当にいろんなテーマの話を聞くことができ、非常に好評なイベントとなっています。 さらにNTT Comではお昼の勉強会の TechLunch や、 一般向けの NTT Com Open TechLunch も開催しています。 このようなイベントの開催は、知識・情報の共有だけでなく、さらにアウトプットを通した発表者個人の知識・技術の向上やエンジニア組織としての一体感の醸成にも繋がっています。 今後もこの取り組みを続けるとともに、輪を広げ、より活力のある組織へ成長させていきたいと考えていますので、共感できる方はぜひ! NTT Comではメンバーを募集しています 新卒採用 NTTドコモのサイトに移動します(NTT ComはNTTドコモグループの一員として新卒採用をしています) 経験者採用 障がい者採用
はじめに 初めまして!イノベーションセンターテクノロジー部門 データ分析コンサルタントPJの松岡和志です。普段はお客様の経営課題に対して、データ分析を通して解決策を提示する仕事をしています。 この記事では内製開発サービスである ノーコードAI開発ツール Node-AI を用いた需要予測について紹介していきます。 読んでほしい人 AIについてこれから勉強しようと思っている人 AIを使ったデータ分析をやりたい人 AIを活用した需要予測を業務に導入したいと思っている人 効率的にデータ分析したい人 ノーコードツールに興味がある人 伝えたいこと Node-AIで簡単に需要予測をするやり方 Node-AIはAIを作る工程がわかりやすく分かれていること Node-AIとは Node-AIは、ブラウザ上からノーコードでAIモデルを作成できるサービスです。NTT Comが独自に開発し、 2021年10月11日にリリース しました。現在は製造業のお客様を中心に、異常検知やプラント運転支援などの様々な領域で活用されています。 以前 こちらのブログ記事 でも紹介しているので、お時間がある方はぜひこちらもお読み下さい! また最近 このような賞 も受賞させていただきました。 何を予測するのか 今回取り扱うデータは、2011年~2012年のワシントンD.Cで使われた自転車シェアサイクル 1 です。 こちら からダウンロードできます(要ユーザー登録)。 データのカラムとしては以下のようなものがあります。 dteday : 日付 season : 季節 (1:春, 2:夏, 3:秋, 4:冬) yr : 年 (0:2011、1:2012) mnth : 月(1〜12) hr : 時間(0〜23) holiday : 休日の判定 weekday : 曜日 workingday : 平日は1、土日祝日は0 weathersit : 1 : 晴れ~少しの雲 2 : くもり 3 : 小雨 4 : 大雨 temp : 気温 atemp: 体感温度 hum:湿度 windspeed:風速 casual:このシェアサイクルの非会員の自転車利用数 registered:このシェアサイクルの会員の自転車利用数 cnt: 自転車利用の総台数 (casualとregisteredの合計) 今回は自転車利用の総台数(cnt)を予測するために、会員の利用数(registered)と非会員の利用数(casual)を分けて予測するモデルを作成していきたいと思います。※流れは同じなのでcasualのみ対象として記載します。 自転車利用の総台数を予測することによって 利用希望者が全員満足に利用できる台数の必要最小限数での設置 利用数の少ない時間帯に合わせた計画的なメンテナンス実施 等ビジネスに有効な施策を講じることができます。 予測モデル作成の流れ 予測モデル作成は データの統計やグラフを見ることで全体の概要を把握 データの前処理(AIモデルを当てはめるためにデータを加工したり抜けているデータを補完したり、モデルを作るデータとそのモデルを評価するデータに分けたりすること) モデル作成、学習 評価 (評価で納得できなければ)前処理に戻ってパラメーター変更 といった流れになります(より詳細な内容やNTT Com独自のノウハウについては こちら )。 Node-AIでは予測モデル作成に必要な工程がカードで分かれているため、どうやってAIモデルを作るのかを理解したい人にもおすすめです。 予測したいデータを設定する まずはNode-AIに予測したいデータをアップロードします。上記のデータをダウンロードしてから、こちらからデータをNode-AIにアップロードします。 その後できたデータカードを、キャンバス(Node-AI上にてデータを配置したりデータを処理するカードを設置するエリア)に出してからクリックして開いてみると、データのテーブルや各カラムごとの統計、時系列での推移が可視化されているグラフが見られます。 各カラムの統計 統計について、予測したいcasualの『75%』と『最大値』を見てみます。 『75%』は48.000で『最大値』は367.000となっていて、これはcasualの全データ中75%は48以下であり、最大値は367ということを示しています。 また『平均』が35.676であることから、1時間での非会員の利用数は大体30台〜50台であるが、何かしらの出来事があった際に10倍近くの自転車が使われたということがイメージできます。 この10倍近く使われる台数と時間を予測できれば、利用者と会社双方に理想的な自転車の設置ができそうだと思いますね。 予測したいデータ(casual)の時系列推移 時系列推移の期間選択を見ると、後半にある山が高く、かつ山になる頻度が増えているように見えます。 これはざっくり2012年の方が2011年と比較して利用台数、利用頻度が増えている事を示します。 情報が無いのであくまで想像の域を出ませんが、このサービスの認知度上昇や利用可能場所の増加によってより多くの利用者が増えたのではないかといったことも考えられます。 ここで今回予測する非登録者の利用数(casual)を目的変数、そして予測に関係していそうなパラメーターとして holiday : 休日かどうかの判定 weekday : 曜日 workingday : 土日祝日でない場合は1、そうでない場合は0。 weathersit : 1 : 晴れ~少しの雲 2 : くもり 3 : 小雨 4 : 大雨 temp : 気温 atemp: 体感温度 hum:湿度 windspeed:風速 を説明変数に選択して保存を押します。 これでデータの設定は完了しました。 データの前処理~モデル作成~学習~評価 ここからがさらに簡単です。 本来データ分析をする際には、様々な工程をRやPythonといったプログラミング言語を用いて実装していく必要があります。Node-AIはこの工程をカードを繋げるだけで実装できます。(様々な工程について説明した内容は こちら ) そしてさらにNode-AIには『データの前処理~モデル作成~学習~評価』といった一連の流れをできるようカードが設計されている レシピ があります。 レシピとは、処理したい様に繋げたカード群等を保存呼び出しできる機能です。 クイックスタートレシピをダウンロードしてインポートすることで、データの前処理からAIモデルの評価までつながっている状態のフローが出てきます。 基本的に上のカードから順にクリックして実行を押すだけで、AIモデルができて評価まで見ることができます! このレシピの中で少し設定が必要なデータ分割のカードと時間窓切り出しについてお話しします。 データ分割 これは元々のデータカードから、どこまでをAIモデルを作るためのデータ(学習データ)とそのAIモデルがどの程度あっているかを確認するためのデータ(テストデータ)に分けるものです。 今回はシンプルに、2011年のデータは学習データに、2012年はテストデータにするように設定します。 時間窓切り出し これはモデル作成の際に時系列データを学習可能な形式に変換するカードです。 今回の様に多変量での時系列データを予測するモデルを作成する際には、予測先の1つの時点を予測をするために、一定の時間幅で切り取ったデータを用いる事が多く、このカードはその設定をするものです。 詳しい説明はこちら 。 今回は1週間後の需要予測をするために、過去1週間のデータを説明変数とするよう設定します。 このデータは1時間刻みのデータなので、1週間は24(時間)×7(日)=168をN(予測先)とM(窓幅)に設定します。 他のL(丸め幅)とS(ストライド幅)は、推奨されている1に設定します。 評価 MLPカードや学習カード、正規化カードについてもクリックしてすぐに実行を押します。以下のような予測モデルができました。 作成したモデルは既知のデータを元に作られたものなので、未知のデータをどの程度予測してくれるのかを評価する必要があります。 しかし、手元にない未知のデータに対して予測精度の評価はしようがありません。 そこで学習データとテストデータに分けて、学習データで作成したAIモデルの予測値とテストデータの値を比較することでAIモデルの予測精度を評価します。 今回は2011年の情報を学習データとして予測モデルを作成し、2012年の情報をテストデータとすることで予測モデルの評価をします。 今回はRMSE、R 2 の2つを評価指標として考えます。 RMSEとは二乗平均平方根誤差のことで、予測値と実測値の誤差を2乗して平均したものの平方根を取ったものです。 RMSEは0に近いほど予測精度が高いということを示しています。 R 2 とは決定係数のことで、モデルと実測値を比較してのモデルの当てはまりの良さを示しています。1に近いほどモデルが実測値に当てはまっていることになります。(ただし、これがどのくらいの値が良いかの目安は諸説あります) R 2 =0.57ということでそこそこ当てはまっているんだなということが分かります。 今回取り扱わなかった評価指標や今回取り扱った2つの詳細については こちら をご覧ください。 パラメーターの再設定 このようにレシピを使えばすぐにモデルを作成できますし、より精度を上げたいなと思ったらAIについて調べて勉強すればよりNode-AIを使いこなせるようになります! たとえば多重共線性と呼ばれる、説明変数間で相関係数が高いものを用いて分析するという問題を回避するために、説明変数を減らしてみるなどが考えられます。 実例として先程の分析の説明変数を見てみると holidayとworkingday tempとatemp はそれぞれ似たようなものを説明していると思いませんか? ということで多重共線性を回避するために、holidayとatempを説明変数から除外して分析した結果がこちらになります。 評価指標はこのように変化しました。 RMSE 39.0→36.5 R 2   0.57→0.62 RMSEは0に、R 2 は1に近づくことで予測精度とモデルの当てはまりの良さが向上しました。 これ以外にも様々な手法があるので、ぜひとも自分の手で動かしてみてください! ちなみに、Node-AIを起動してから最初のモデル評価を確認するまで1時間程度でできました。この工程を直感的なカード配置と簡単な数値入力でできるのは個人的には非常に楽だなと思います。 もう1つのやさしい機能として NTT Com独自技術 でもあるAIの可視化機能の重要度可視化や要因分析、因果分析については別の記事で話させていただきたいと思います。 まとめ Node-AIを使うことによって簡単に需要予測のAIが作れる カード毎に分かれているのでAI作成の工程が理解できる レシピを使うことによってデータをつなげるだけでAIモデル作成評価ができる 現在Node-AIは メールアドレスを登録するだけで30日間無料で使えます!  こちらの記事を読んでデータ分析に興味を持った方はぜひ登録して使ってみてください。分析対象となるデータから、データをつなげるだけですぐAIモデル開発までできるレシピもあります。まずは触ってみてご自身の職場で使えそうだなと思ったら、ぜひとも こちらのフォーム からお問い合わせをお願いします。 Fanaee-T, Hadi, and Gama, Joao, "Event labeling combining ensemble detectors and background knowledge", Progress in Artificial Intelligence (2013): pp. 1-15, Springer Berlin Heidelberg, doi:10.1007/s13748-013-0040-3. ↩
この記事はSDPFクラウド/サーバー 仮想サーバーチームの宮岸( @daiking1756 )とCOTOHA Call Center開発チームの立木の共同執筆です。 二人共エンジニアではあるのですが、普段は全く違うチームで開発をしています。 この記事では、普通に働いていたら交わることのない私たちが、一緒にハッカソンに参加したことで得た学びと知見を共有します。 はじめに 私たちが今回参加したのは Twilioハッカソン2022 です。 その名の通り、Twilioを使った作品を作るハッカソンです。 今回のテーマは - Twilioを使って、ちょっと仕事を楽にしよう - でした。 当日はエンジニアを中心に30名ほどが参加しておりました。 宮岸は学生時代からハッカソンが好きで、 このTwilioハッカソンも以前から参加してみたかったものの1つでした。 今回2人でTwilioハッカソンに参加したきっかけは後述します。 まずは「ハッカソン」や「Twilio」について、用語の説明と2人の経験を載せておきます。 ハッカソンについて そもそもハッカソンって何?という方向けに、説明を載せておきます。 ハッカソンは、ハック(hack)とマラソン(marathon)を組み合わせた造語とされ、 プログラマーや設計者などのソフトウェア開発の関係者が、 短期間に集中的に開発作業を行うイベントを指します。 https://www.nic.ad.jp/ja/basics/terms/hackathon.html エンジニア界隈ではある程度知名度があると思いますが、語源は意外と知られていないかもしれないですね。 そして宮岸と立木のハッカソン歴は下記のとおりです。 宮岸: 学生時代からハッカソンに参加するのが好きだった 立木: 学生時代に1度だけハッカソンに参加して以来(人生では2回目) Twilioについて Twilioは電話やSMS・ビデオ・チャット・SNSなど世の中にある様々なコミュニケーションチャネルをWeb・モバイルアプリケーションとつなぐ「クラウドコミュニケーションAPI」です。 https://cloudapi.kddi-web.com/availability 一言でいうと、APIから電話を掛けたりSMSを送ったりできるサービスです。 また、それ以外にもビデオチャットやグループ通話など、コミュニケーションに関する様々な機能が提供されています。 気になる宮岸と立木のTwilio歴は下記のとおりです。 宮岸: できることは何となく理解していたけど、使ったことは無かった 立木: 業務で数ヶ月使っているけど、本格的に学んだことはなかった Twilioハッカソンに参加したきっかけ 1年目研修の中で グループリフレクション(ぐるり) という、3、4人組での振り返り会があります。 ぐるりに立木は参加者として、宮岸は3年目社員ファシリテーター役として参加していました。 立木が「業務でTwilioを触っている」と話していたため、 宮岸が「Twilioハッカソンってのがあるけど、よかったら一緒に出てみない?」と声を掛け、 今回2人でTwilioハッカソンに参加するきっかけとなりました。 また、各々の参加のモチベーションとしては下記のとおりです。 宮岸: ハッカソンに参加するのは好きで、前からTwilioハッカソンにも出てみたかった 宮岸自身がハッカソンに参加して良いカルチャーショックをたくさん受けたので、立木さんにも体験してみて欲しかった 立木: 業務でTwilio使っていて、知識を深めたい状態だった ハッカソンに出て外部のエンジニアと交流してみたかった ハッカソン当日の流れ 当日の細かい流れは割愛しますがざっくりと書いておくと下記の通りです。 サポート技術インプット(Twilio / kintone / obniz / LINE) アイデア発散とチームアップ ハッカソンタイム 成果発表 サポート技術インプットの時間で各サービスが実現可能なことの説明を聞いた後は、さっそく開発する作品のアイデアを練る「アイデア発散」の時間です。 1つのスプレッドシートを参加者全員で一斉にワイワイ編集するスタイルです。 30人でワイワイやるのはお祭り感があって楽しかったです。 具体的な流れは下記の通りです。 ステップ1: 最近感じた課題を一言で書く(10分間で150個埋まった) 例: 「チャットに気づかない時がある」 ステップ2: 他の人が書いた課題に対して一言でコメントする(共感/発散/解決策) 例: 「一定時間経過したら電話で通知」(10分間でステップ1の150個の課題に対してコメントが付いた) ステップ3: ステップ1とステップ2を見て何か思いつくアイデアを各自が記入する(10分間で約200個のアイデアが生まれた) 例: 「リアクションが一定時間無いユーザにチャットの内容を自動音声で連絡するサービス」 結果、30分で約200個のアイデアが生まれました。 その中から宮岸のアイデアが上位に選出され、そのアイデアに共感してくれたメンバーも立木と他に2名集まりました。 こうして計4名の「チームtwelve」が誕生しました。 ※ ぐるりのチーム番号が12だったことと、Twilioとスペルが似ていることがチーム名の由来です。 裏話ですが、今回は2人で申し込みしたため、「事前にこういうもの開発しようねー」というアイデアを持って参加しました。 しかし、アイデア発散をしている間に楽しくなってしまい、結局事前に練っていたアイデアとは全然違う作品を開発しました。 続いて、実際に開発に取り組む「ハッカソンタイム」です。私たちのチームではまず、メンバーで作業分担を決めました。 今回は、メンバーの経験や希望を踏まえて、 リーダー: 1人(宮岸) 開発: 2人(立木) 発表資料作成: 1人 という形にしました。 開発と同時に発表資料作成をすることで、4人の認識を合わせながら開発を進めることができる、はずでした。。。 詳細は後述します。 開発の流れについては、最初に各機能を実装するパーツ(関数)を作り、その後一気につなぎ合わせる方法を取りました。 機能の結合を始めるタイミングが遅れたため、全てのパーツ(関数)をつなぎ合わせることはできませんでしたが、最低限の機能+αが動く作品を作ることはできました。 こちらも詳しくは後述します。 作った作品について(やさしい呼び出しくん)の概要 私たちは「やさしい呼び出しくん」という作品を開発しました。 作品の概要は下記の通りです。 障害対応などの急ぎの要件で複数人をメンションした際に、反応が無い人には自動で電話を掛けてくれるアプリケーション。 これで人の呼び出しではなく、急ぎの用件に集中できます。 今回のハッカソンで開発された作品はProtopediaというサービスに登録することになっています。 詳細はそちらに情報をまとめておりますので、リンク情報を載せておきます。 protopedia.net 作品の構成と処理の流れ 制限時間の関係で最後までは完成しませんでしたが、今回開発した作品のシステム構成図は以下の通りです。 AWSのLambda上でServerless Frameworkを使い、Expressを動かしています。 今回参加したハッカソンではスポンサーにTwilio・kintoneが参加しているため、電話の発信とSMSの送信にはTwilioを、データベースはkintoneを使用しました。 また、Slackからのメンションとリアクションの情報を取得するためにSlack APIを、遅延処理を行うためにAWSのSQSを使用しています。 システムの処理の流れは以下のようになっています。 Slackで特定のワードが先頭に付いたメンションを含むメッセージを投稿する(例:「!やさしい呼び出しくん @A-san @B-san 〇〇のシステムがダウンしているようです。急ぎで対応お願いします。」) SlackのEvents APIを使用し、特定のチャンネルのメッセージ投稿を検知し、Lambdaにリクエストを投げる メンション付きの投稿である場合は、メンション元・メンション先の情報や日時などの投稿の情報をkintoneに保存する 投稿にリアクションがあった場合はSlackのEvents APIを使用し、Lambdaにリクエストを投げ、kintoneのステータス情報を更新する SQSでn分後、リアクションをしていない方全員に対してTwilioから発信する処理を実行 電話に応答できなかった方には、TwilioからSMSを送信する 今回はSQSを使った遅延処理まではできず、投稿後すぐにTwilioから発信する仕様になりました。 最終的には期限までに完成させることができ、ローカル環境ではありますが発表会でデモを行うことができました。 審査の結果・・・ 審査の結果、やさしい呼び出しくんが 最優秀賞 を頂くことができました! リアルタイムデモが成功したこと、テーマに沿った作品だったことと、Twilioの様々な機能を活用していたことが「Twilioハッカソン」としては評価されたようです。 またチームとしては、諦める機能と諦めない機能を合意して、途中から発表を意識した開発できたことが良かったと思います。 参加して気づいたこと、思ったこと、学び 時間の制約のある中での開発の難しさ 今回ハッカソンに参加してみて、時間の制約のある中での開発は難しいと感じました。 具体的には、メンバー間で実装箇所の認識に齟齬があり、2人が同じ部分を実装してしまうということが起こりました。 この問題を解決するために、リーダーと開発メンバー2人で話し合い、同じ機能を2人で分担して実装していたところを、それぞれが別の機能を実装するように変更しました。 ハッカソンという時間の短い中で早く作業を進めようとするあまり、このような役割分担やお互いのコミュニケーションが疎かになりがちだと感じました。 役割分担の明確化やお互いの進捗の共有などの意思疎通の重要性を改めて感じました。 また、開発手法についても、パーツ(関数)を後で一気に繋ぎ合わせるのではなく、できた機能から結合させていく方が良かったのではないかと思いました。 そうすれば、機能自体は完成したにも関わらず、作品には組み込めないということが起こらないためです。 実際に、今回パーツが完成していたのにも関わらず、作品に組み込めなかった機能があり、もったいなかったです。 作品のゴールを共有することの大切さ 今回は作品の目指すべき方向性の議論は重要視せずに、開発に着手しました。 ハッカソンの限られた開発時間では、早く手を動かしてどんどん開発を進めたくなってしまうものです。 1人で開発しているのであればそれでもいいのですが、今回はほぼ初対面の4名という即席チームだったので、結果的にこれが裏目に出ました。 必要のない機能を開発しそうになったり、想定していないユースケースに対応しようとしてしまっていたのです。 まだアイデアも生煮えの状態で開発に着手して、作りながら作品の価値を模索していくような状況では、MVP(Minimum Viable Product、顧客のニーズを満たす最小限のプロダクトのこと)を最速で作ることを意識するべきでした。 今になって振り返ると「最初にラフな資料を作って認識を合わせ、MVPができるまではなるべくモブプロ・ペアプロを多めでやっていく方が良かったなー」と思います。 ※ 頭の中で 移動手段のMVPのメタファー が何度もよぎりました。 この経験は今後ハッカソンに参加するときは勿論、業務での開発やその他のチーム開発など、あらゆるところで活きるものとなりそうです。 知識として理解はしていましたが、百聞は一見にしかず、百見は一体験にしかずという具合に、ハッカソンというある意味本番ではない場で一度体験できたのは非常に有り難いです。 メンバー間でコミュニケーションを取りながら本当に価値があることに時間を使うことが重要 と強く感じました。 個別の感想 宮岸の感想 自分がアイデアの発起人ということもあり、ハッカソン中は開発者というよりもユーザ目線で作品のことを考えることを意識していました。 今まで参加したハッカソンで、もしかすると自分が書いたコードは少ないかもしれませんが、 「どういう課題を解決する作品にしたいか」 「ユーザ目線だとどういう機能があると便利か」 「実装コストを考えると何を諦めるべきか」 といったことを2日間で考えることができ、非常に貴重な体験となりました。 たまたま研修で出会った立木さんと一緒にハッカソンに参加して、チームメンバーで足りないところを補いながら高め合い、最優秀賞を受賞できたことは素直に嬉しかったです。 ハッカソンやプロトタイピングが好きな仲間が社内外にもっと増えれば、盛り上がって嬉しいですし、この記事を読んで興味を持つ方がいれば幸いです。 立木の感想 私は社会人として参加するハッカソンでは初めて(人生では2回目)の参加となりましたが、非常に学びのあるハッカソンだったと感じています。 今回他社のハッカソン常連者の方と同じチームで参加し、実装面や使用する技術という点でも新たな学びを得ることができました。 他社のエンジニアの方と交流する機会はあまりなかったため、刺激になりモチベーションを高めることができました。 また、ハッカソンという場を通じて、Twilioやkintone、Slackなど様々なサービスのAPIに触れることができ、勉強になりました。 期間中はドキュメントを見ながら試行錯誤して実装し、結果としてサービスに詳しくなり技術力を高めることができたと感じています。 加えて、限られた時間内にチームで議論し、協力しながら1つのものを完成させるハッカソンは楽しいと改めて思いました。 また機会があればハッカソンに参加したいと考えています。 おわりに 今回はTwilioハッカソン2022に参加して得た学び・知見について紹介しました。 初めて会う方もいる中でのチームマネジメントの難しさ、時間の制約のある中での開発など困難もありましたが、ハッカソンで作品を完成させるまでに数多くのことを学べました。 結果的に、最優秀賞も受賞でき、良い経験になりました。 今後もこの経験を活かし、さらにエンジニアとしてパワーアップしていきたいと考えています! 最後にお知らせですが、NTT Comは一緒に働く仲間を募集中です。詳しくは下にある採用情報を確認していただけると嬉しいです!
この記事は NTTコミュニケーションズ Advent Calendar 2022 18日目です…が、少々遅れてお届けします。 はじめに PS本 5G&IoTサービス部 増田です。Advent Calendar参加も(たぶん)3年目となりました。 「テキスト指示をもとに、AIがお好みの画像を生成する(Text-to-Image)」「今ある画像へ、テキスト指示で編集を加える(Image-to-Image)」 -- そんな画像生成AIが注目を集めています。2022年の上半期、Open AIによるDALL-E 2の公開、Midjourneyの登場と盛り上がりを見せました。2022年8月23日のStable Diffusion一般公開からは、使ってみた報告、従来研究との融合、商用プロダクト応用と、研究者、アーティスト、プログラマなど様々な人の参加により、界隈はさらに活気づいています。 画像生成AIの技術解説は、たくさんの素晴らしい記事に譲ります。技術の全体像説明 1 や、図解による日本語 2 や英語 3 の解説があります。今年のアドベントカレンダーでも、テーマとして複数取り上げられました。そのものズバリ 画像生成AI Advent Calendar 2022 に様々な考察を読むことができます。また、2022年8月〜11月の目まぐるしい変化は、やまかず氏のnote 『 日刊 画像生成AI 』に詳しくまとまっています。 ジェネラティブAI全般にも、上記の画像生成のコアとして使われる「拡散生成モデル」ブームが到来しました。テキストからの画像生成とその発展に加え、サウンド生成、動画生成、モーション生成、3Dモデル生成と、ここ数ヶ月で様々な論文が発表されました。 次に興味が湧くのは、こうした技術が今後どのように社会に受容され、影響を及ぼすかという点です。本記事では、画像生成を中心としたジェネラティブAIを取り巻くビジネス、技術応用、法律その他を以下のステップで概観します。 ジェネラティブAIのビジネス機会と投資 差異化要素を生み出す人材、プロダクトやその素材 考慮すべき制約(法解釈と規制、コミュニティの倫理観) これから数年スパンで、ジェネラティブAIどう浸透し、社会を変化させるかという流れを読み解く、または予測する一助となれば幸いです。 1. ジェネラティブAIのビジネス機会と投資 ジェネラティブAI、中でも画像生成AIの技術的ブレークスルーは、ビジネス機会や投資目線ではどのように捉えられているのでしょうか。 IT分野を中心とした調査会社 Gartnerは、2022年の戦略的テクノロジートレンドの先頭に「ジェネラティブAI」を取り上げました。2025年には全データの10% (現在は1%未満) をジェネラティブAIが生み出すと予測しています。次に「来る」技術を予測するGartnerハイプサイクルでは、ジェネラティブAIが盛り上がりのほぼ頂点にプロット 4 されました。 イギリスの経済誌 Financial Timesは、ジェネラティブAIへの投資が2020年比で425%増加し、21億米ドル (約2800億円) に達する 5 と報じました。Web3の減速とAIへの資金還流が伸びの原因とされています。事実、大型調達の発表が相次いでいます。2022年10月には、Stable Diffusionモデルの発表元 Stability.aiが1.1億米ドル (約150億円) の資金調達 6 をし、成長戦略を発表しました。12月には、同じくStable Diffusionに関わったRunway MLが、5000万米ドル (約68億円) の調達を発表 7 しました。以前よりジェネラティブAIで名の通っていた会社だけではありません。Stable Diffusionモデル公開後に生まれた会社もあります。例えば Sharif Shameem氏 によるLexica.artは、Stable Diffusionの公開直後に生成コンテンツ検索エンジンとして開始 8 、すぐに500万米ドル (約6.8億円) を調達 9 しました。モデルのオープン化がもたらした効果といえるでしょう。 さて、これらの調達資金は何に投じられ、その会社とその顧客にどんなリターンを生むと考えられるでしょうか。 2. 差異化要素を生み出す人材、プロダクトやその素材 一般に、どこにリソースを投下することが最も効率よく事業を成長させるか、「てこ」となる場所は事業種別により異なります。そのため、調達資金の重点投下先も異なります。例えば、企業向け業務系SaaSの場合は営業やカスタマーサクセスの人員、個人向けゲームやコンテンツであればその制作費や広告宣伝費に多くを投じるでしょう。AIスタートアップの場合、それらに加えて独自のデータセット、計算資源を投下した学習、抱える研究者の技術によりもたらされる独自のモデル、それらを利用シーンと結合させるアプリケーション開発、プロフェッショナルサービスによる課題ごとにカスタマイズをした対応などが競争力と成長の源泉となります。 ジェネラティブAI、特に画像生成AIの付加価値や差異化要素は、どう生み出されるのでしょうか。ここでは 「人材やステークホルダ」 が 「プロダクトを生み出す素材や道具」 に作用し、 「法規制と倫理観」 の制約下で 「プロダクト」 を生み出すとモデル化します。各要素を詳しく見ていきましょう。 2.1. 人材やステークホルダ 主要な人材やステークホルダには、 「クリエイター」「アプリケーション開発者」「研究者」 が挙げられるでしょう。また、領域間の越境人材も見られます。 クリエイター 「絵を描く」「CGを制作する」といった活動をするクリエイターは、アマチュアかプロかを問わず、既に自身の制作プロセスに画像生成AIを取り入れ始めています。日本での一部事例を挙げます。 深津貴之氏 は、Stable Diffusion前夜の記事 10 で耳目を集め、SFマガジン 23年2月号表紙の制作 11 などいちはやく制作現場に取り入れています。 852話氏 は、Midjourney、Stable Diffusionを活用した美麗な画像を日々発表し、画像生成AI初の紙刷り画集を出版しました。 横原大和氏 や 齋藤彰氏 は、元々3D CGに強みを持ちながら、画像生成AIを制作プロセスに取り入れた習作例を日々発信されています。 アプリケーション開発者 機械学習モデル全般に言えることですが、モデルがあるだけでは「試す」ことはできても「継続して使う」ことは困難です。利用シーンに合わせたツールやアプリケーションに埋め込まれて初めて真価を発揮します。アプリケーションを開発し、継続的に改善できるエンジニアが必要です。 また、アプリケーションには二種類あります。既にあるアプリケーションやWebサービスに機能要素を足すケースと、スタンドアロンで新規アプリケーションを開発するケースです。Lexica.artの Sharif Shameem氏 や、LINEボット お絵描きばりぐっどくん の生みの親である 西野颯真氏 は後者の例と言えるでしょう。後段の「プロダクト」の項目でも取り上げます。 研究者 ジェネラティブAI領域にもともと関心があった研究者が、今回のブームを受け一歩早く動き出しています。一例に、Google Brainの著名な研究者であった David Ha (hardmaru) 氏 は、Stability.aiにHead of Strategyとして移籍しました。Stable Diffusion以前に静かな盛り上がりを見せたDisco Diffusion界隈のオープンソース活動をしていた研究者は、複数がMidjourneyへ立上げメンバ等として参画しました。 2.2. プロダクト 上に挙げるような人材やステークホルダにより生み出されるプロダクトには、どんなものがあるでしょうか。 アーリーステージ、テック企業向け投資を主に手がけるベンチャーキャピタル Andreessen Horowitz (a16z) は、画像生成に限らず、ジェネラティブAIの「今」を捉える記事を発表しています。2022年11月には、「Art Isn’t Dead, It’s Just Machine-Generated (アートは死なない。ただ機械が生成する) 12 」「The Generative AI Revolution in Games (ゲーム業界における生成AI革命) 13 」の2本が掲載されました。 「Art Isn’t Dead, It’s Just Machine-Generated」では、コード自動生成 (Copilot等) と画像生成を比較して取り上げています。前者に求められる厳密さに対して画像生成は既に十分実用に耐える出力ができる点と、画像生成AIのハイプは (関連リポジトリのGitHubスター数ベースでは) ブロックチェーンブーム等を遥かに凌駕する点に触れ、画像生成などのジェネラティブAIが一気に普及すると論じています。「2022年末のインターネットアーカイブが、人間が多くを生成した最後のリポジトリとして大切にされる日が来るかもね」という締めが印象的です。 「The Generative AI Revolution in Games」では、コスト・品質・スピードのうち2つしか取れないトレードオフ問題の終焉、産業の中では複雑性・リアルタイム性が高いゲーム業界が最も大きな影響を受けるだろう、と論じています。 ここでは、活用が期待される画像生成AIプロダクトについて、「四階建て」の構造でモデル化して議論を進めます。プロトタイプフェーズと、製品フェーズでも構造が多少異なると言えますが、本稿では詳細を省きます。 下階から上階に積み上げる形で、 「基礎となる画像生成モデル」「追加学習等によるカスタマイズ」「アプリケーション」「活用プロセス」 と、各階の様子を見てみましょう。 一階:基礎となる画像生成モデル 一階は「基礎となる画像生成モデル」です。画像生成には、Imagen、DALL-E2、Midjourney、Stable Diffusionなど著名なモデルがあります。 一部企業を除き、「一からの学習」に必要な計算資源へ安定してアクセスすることは困難です。基礎となる画像生成モデルの一つであるStable Diffusionの公開は、一階部分をGoogle、OpenAIなどの従来からマシンパワーとキャッシュに余裕のある企業に独占された状態とさせず、二階より上で起こるイノベーションに張ってみたものと言えます。様々な議論を呼びつつも、爆発的に「追加学習」「アプリケーション」「活用プロセス」例が出て、イノベーションが加速されたことは確かです。 二階:追加学習等によるカスタマイズ 二階は「追加学習等によるカスタマイズ」です。カスタマイズのためには、まず基礎となるモデルを手元に持つ必要があります。加えて、ここには研究知見やそれを実装する能力、学習に使うデータセットと計算資源が必要となります。具体例としては、拡散生成モデル部分の再学習に加えて、Textual Inversion、DreamBooth、Hypernetworks、LoRAなど、学習の箇所や方法に一定の制約を加える方法があります。「ガチャに頼らず、想定した表現を一発で生成するにはどうしたら良いか」は、この秋冬の大きな研究テーマとなっています。 また、 追加学習されたモデルは、「公開されないケース」「公開されるケース」 があります。さらに「公開されないケース」には、料金を取り利用できるケースと、活用プロセスに隠蔽され使われる場合があります。 公開されないケース: AIピカソが、先日12月20日に発表した「AIいらすとや」 14 は、この二階部分の技術と、フリーのイラストサイト「いらすとや」との提携によりデータセットを使い実現した、「無限にいらすとや風クリップアートを生成できる」機能です。 公開されるケース: Hugging Faceの Stable Diffusion Dreambooth Concepts Library には、DreamBoothにより追加学習した様々なモデルが170以上公開されています。 三階:アプリケーション 三階は「アプリケーション」です。一階や二階部分を活用しながら、コーディングを前提として、アプリケーション部分の実装を差異化領域とできます。先ほどアプリケーションには 「既存アプリやWebサービスに機能を足すケース」 と 「新規アプリを開発するケース」 があると述べました。 「既存アプリやWebサービスに機能を足すケース」 の既存アプリケーションには、Photoshop、Figmaなどが挙げられます。これらは、既にクリエイターの制作プロセスに深く浸透しています。以下のようなサードパーティプラグインが発表されていますが、今後半年から一年で公式機能としての実装が進むことでしょう。 Adobe Photoshopは高機能な画像編集ソフトウェアです。 Nicolay Mausz氏 による flying dog for Stable Diffusion は、Adobe Exchange上で89米ドルにて販売され、Stability.ai側のサーバへ描画リクエストを送ることによるクラウドでの動作、両方をサポートしています。 Figmaは共同編集をしながらインタフェースデザインを行えるツールです。 Antonio Cao氏 により、 Ando - Your design copilot という名前で、Stable Diffusionのプラグインが公開されました。生成枚数が42枚/月に制限されたFree版、月額18米ドルのPro版の料金プランがあります。 営利企業による製品だけではありません。 GIMPはオープンソースの画像編集ソフトウェアですが、 BlueTurtleAI氏 により、GIMPプラグインがMITライセンスで公開されています。 「新規アプリを開発するケース」 はどうでしょうか。 従来Webアプリケーション開発を行なっていた企業やエンジニアが、画像生成AIを素材として選び、他に先駆けサービスとしてリリースする例があります。 既存アプリケーションが同様の機能を実装してきても差異化要素を持ち続けられるかは、「一発芸」で終わらず、継続した利用シーンの探索と新機能のリリースが大切となるでしょう。 日本ではお絵描きばりぐっどくんのようなLINEボット、AIピカソのようなスマートフォンアプリがリリースされています。 なお、一階や二階部分のリリースと共に簡易アプリケーションとして公開される場合に、できるだけ三階部分の実装を軽くするため、DiscordやHugging Face上のGradioアプリケーションなどをフロントエンドとして活用するケースも見られます。 四階:活用プロセス 四階は「活用プロセス」です。コーディングを前提とせず、クリエイターやアーティストにより、生成におけるコツや他制作ツールとの組み合わせ発見など 「制作プロセスの効率化や独自色の付加」 や、 「生成コンテンツのキュレーション」 などが行われます。 ジェネラティブAIを人間が活用する際、「サンドイッチワークフロー」が普及する 15 と言われます。 サンドイッチワークフロー: 人間がAIに指示を与える(例:画像生成AIへのプロンプト提示) AIが生成オプションを提示する(例:複数種類の画像生成) それを人間が選択し、仕上げる(例:画像に対するレタッチ、コラージュ、別ツールへの取込み・編集などの仕上げ) 発明された活用プロセスは、クリエイターやその集団の「秘伝のタレ」として非公開とするケースもあれば、一般に公開するケースもあります。公開され、かつ利用頻度が高いものは、三階のアプリケーションレベルで実装され、コモディティ化します。 2.3. プロダクトを生み出す素材や道具 プロダクトを生み出す、またそれを改善し続けるためには、人材に加えて 「研究知見」「計算資源」「データセット」 などの素材や道具が必要となります。 研究知見 論文の形で様々な研究知見の公開が続きます。機械学習系の国際カンファレンスが開催されるごとに、ジェネラティブAI系の知見が更新されています。この秋は画像生成AIのカスタマイズ、及び画像の次としての映像、音楽、3Dモデルなどの生成についての論文が多数公開され、耳目を集めました。 この分野の論文は、Arxivにプレプリントとして公開され、すぐに個別のDiscordでそれらが論じられたり、Twitterでの拡散が進みます。同時に、またはその後、GitHubやHuggingFaceへの著者による公式実装やコミュニティによる再実装公開や、同様に著者またはコミュニティによるGradio等のプロトタイプアプリ、デモが公開され、それを試した人々によりアプリケーションなどへの取り込みが進むというのがよく見られる流れです。ただし、論文化される前に特許が出願されているケースがあり、ソースコードが公開されている場合もライセンスに気をつけて活用する必要があります。 計算資源 2018年のOpenAIの記事に、「How AI Training Scales (AIの学習はどのようにスケールするか) 16 」があります。その後数年で、大量のデータで学習させ、様々なタスクにカスタマイズを行える基盤モデルの活用が増え、そのサイズは増加の一途を辿っています 17 。大量のデータセット収集、及びその権利関係の整理とともに、モデルの学習に必要となる膨大なマシンパワーを持つことが、差異化に必要となりました。 学習用の計算資源と一口に言っても、前述の通り 「一からの学習」「追加学習(重め)」「追加学習(軽め)」 と程度が異なります。(ここは、2.2. プロダクトの「一階」「二階」に対応) 一からの学習例: 画像生成などのジェネラティブAIを一から学習するには、膨大な計算資源が必要です。Stable Diffusionの当初リリースモデルの学習において、60万米ドル (約8200万円) を投じました 18 。NVIDIA A100を256枚、15万GPU時間を投じたとされています。 追加学習(重め)例: 継続する企業運営のための資金調達ではなく、単発の学習に必要な資金をクラウドファンディングで集める例もあります。Stable DiffusionのフォークであるUnstable Diffusionは、Kickstarterプロジェクトを立ち上げ、25千米ドル (約350万円) のゴールを設定しました(ただし、その後Kickstarterによりプロジェクトは停止) 19 。クローズ後6週間をかけてデータセット準備、学習を進め、モデルを配布する予定とされていました。これは、公開されたStable Diffusionモデルをベースとした追加学習であり、1億円弱よりは大幅にコストが抑えられます。 追加学習(軽め)例: 特定のスタイル、キャラクター、人物に特化した制御可能な画像生成AIを学習により作る場合、より小さなスケールで学習を行い、カスタムの学習モデルを提供できます。手法が確立されていれば、学習に1時間とかからず、計算資源のコストは一件数千円以下の世界です。 データセット Stable Diffusionの学習において、 LAION というオープンなデータセットが重要な役割を果たしました。画像生成AIにおいては、以下のデータセットが活用されています。 インターネット等に公開されたデータを、スクレイピング等で収集したもの 企業所有など非公開でストックされているもの 前者の公開されたデータであっても、公開経緯が著作権などに配慮をしないものであると、それらを使って良いのかという法的、倫理的問題をはらみます。 言語や画像のデータはインターネットに莫大な量があり、日々生み出されていますが、学習で使い果たすことが来るかもしれません。 現状、言語は2040年に枯渇、高品質に限定すると2024年に枯渇、画像は2038年に枯渇するのではと、過去トレンドと計算機の制約をもとに推定した例 20 があります。 ジェネラティブAIにより生成されたコンテンツが指数関数的に増え始めると、やがて学習対象に無視できない量での混入も始まることでしょう。 3. 考慮すべき制約 ジェネラティブAI、特に画像生成AIにおける付加価値や差異化要素は、 「プロダクトを生み出す素材や道具」 に 「人材やステークホルダ」 が作用し、 「法規制と倫理観」 の制約下で 「プロダクト」 が生み出されているとモデル化して話を進めてきました。制約として意識すべき 「各国の法解釈と規制」 や 「対象コミュニティの倫理観」 について見ていきましょう。 3.1. 各国の法解釈と規制 STORIA 柿沼太一弁護士が、AI界隈の事情について以前より情報発信 21 をされています。2022年11月には画像生成AIの日本国内法についてのセミナーが開催され、録画と資料が無料公開 22 されました。 また、画像生成AIの著作権については各国各様の対応が行われています。Skyland Ventures 中村公哉弁護士 23 によると、英国はAIの生成物に著作権を認める方向であるのに対し、米国や日本は積極的な人間の関与があるかどうかにより認められるかどうかが変わる 24 と解釈されているようです。中国は、国内で流通させるコンテンツを生成するAIに対して新たな規制が発表されました。ジェネラティブAIの提供者は、ユーザの身元を確認し、コンテンツ管理をすること、そして人間の顔やリアルなシーンの生成時はAIによって生成されたことを明示すること、としています 25 。 3.2. 対象コミュニティの倫理観 ジェネラティブAIは、まず画像生成を中心にクリエイターの間で大きな議論を巻き起こしています。主なものは、 「AI制作物」「学習データセット」 の扱いです。前者は、制作コストの低い画像生成AI作品が増え、人手による作品の存在感・重要度低下と、中長期での産業自体の衰退に繋がるのではという視点、後者は学習に使われたデータセットの作者の権利はどこまで守られるべきかという点です。各プレーヤは、自身の関わりの深いステークホルダからの反響を注意深く観察しながら、それぞれの立ち位置を模索しているようです。法的に正しいかだけでなく、心情として受け入れられるかも大きな課題です。 画像素材などのコンテンツを扱うサービスやユーザ投稿型のイラストや写真ギャラリーでは、画像生成AIを使った制作物への対応方針が分かれています。画像素材提供サービス Adobe Stockは、AI作品投稿を条件付きで認めるとしました。ユーザ投稿型のイラストサイトであるpixivも同様の方針です。画像素材提供サービス Shutterstockは、OpenAIのDALL-E2を自社サイトに統合、学習に使われた画像の作者への分配の仕組みを作る 26 としました。一方で、画像素材提供サービス Getty Imagesは法的リスクを理由に投稿を受け付けないとしています。クリエイターが所属するプラットフォーム上で画像生成AIを展開することには、法規制だけでなく、様々な倫理観をファシリテートする難しさがあります。 今後、この倫理観と技術発展を見ながら、法規制についても更新されていくものと思われます。 まとめ 画像を中心としたジェネラティブAIを取り巻くビジネス、技術応用、法律その他を概観することを試みました。 画像生成AIの盛り上がり ジェネラティブAIのビジネス機会と投資 差異化要素を生み出す人材、プロダクトやその素材 考慮すべき制約(法解釈と規制、コミュニティの倫理観) さらに、画像生成AIやそれを使ったプロダクトがどう生み出されるかを、 「プロダクトを生み出す素材や道具」 に 「人材やステークホルダ」 が作用し、 「法規制と倫理観」 の制約下で、 「プロダクト」 とモデル化し、関わる要素をさらに概観しました。 人材やステークホルダ クリエイター アプリケーション開発者 研究者 プロダクト 基礎となる画像生成モデル 追加学習等によるカスタマイズ アプリケーション 活用プロセス プロダクトを生み出す素材や道具 公開された知見 計算資源 データセット 考慮すべき制約 各国の法解釈と規制 対象コミュニティの倫理観 これからの数ヶ月・数年スパンで、画像生成AIやジェネラティブAI全般が上に挙げた要素の動的な相互依存関係の中でどう社会に浸透していくか、目撃できることが楽しみですね。また、本記事がそれらの流れを読み解く、または予測するための一助となれば幸いです。 Stable Diffusion を基礎から理解したい人向け論文攻略ガイド (ステート・オブ・AIガイド) ↩ 世界に衝撃を与えた画像生成AI「Stable Diffusion」を徹底解説! - Qiita ↩ "The Illustrated Stable Diffusion" by Jay Alammar ↩ What’s New in Artificial Intelligence from the 2022 Gartner Hype Cycle™ | Gartner ↩ Investors seek to profit from groundbreaking ‘generative AI’ start-ups | Financial Times ↩ Stability AI, the startup behind Stable Diffusion, raises $101M | TechCrunch ↩ Runway Raises $50 Million At $500 Million Valuation As Generative AI Craze Continues | Forbes ↩ https://twitter.com/sharifshameem/status/1562455690714775552 ↩ https://twitter.com/danielgross/status/1575149080124313600 ↩ 世界変革の前夜は思ったより静か|深津 貴之 (fladdict)|note ↩ 史上初、SFマガジンの表紙がAIイラストに 特集は「AIとの距離感」:NEWS Weekly Top10 - ITmedia NEWS ↩ Art Isn't Dead, It's Just Machine-Generated | Andreessen Horowitz ↩ The Generative AI Revolution in Games | Andreessen Horowitz ↩ あの「いらすとや」が画像生成AIに! モバイルアプリ「AIピカソ」が画風を習得 - 窓の杜 ↩ Generative AI: autocomplete for everything | Noahpinion ↩ How AI Training Scales | OpenAI ↩ https://twitter.com/emollick/status/1584743837637160960 ↩ https://twitter.com/EMostaque/status/1563870674111832066 ↩ Unstable Diffusion: Unrestricted AI Art Powered by the Crowd (Suspended) by Unstable Diffusion — Kickstarter ↩ https://twitter.com/bioshok3/status/1598144094068359168 ↩ AI開発を円滑に進めるための契約・法務・知財 | slideshare ↩ https://twitter.com/tka0120/status/1598238927403372544 ↩ https://twitter.com/kimiya_nakamura ↩ 画像生成AIをめぐる倫理的問題の最新事情。各国で分かれる対応とは | モリカトロンAIラボ ↩ 中国が画像生成AIの画像に「AI生成マークの表示」を義務化&AIユーザーも実名登録制へ - GIGAZINE ↩ Shutterstock will start selling AI-generated stock imagery with help from OpenAI - The Verge ↩
この記事は、 NTT Communications Advent Calendar 2022 24日目の記事です。 はじめに イノベーションセンターの木村と申します。初めてのアドベントカレンダー&Engineers’blog投稿です。普段の業務は、機械学習をもちいた時系列データ分析の研究開発やお客様データ分析案件支援を主として行っています。プライベートでは自転車にお熱でZwiftでバーチャルライドをしたり、最近ではテクニック向上のためバニーホップの練習に励んでいます(なかなか上達しません…)。 今日はクリスマスイブということで、 時系列データ分析コンテンツ「ごちきか」 をプレゼント(?)します!年末休みのお供にぜひご照覧ください。 サマリー 時系列データ分析コンテンツ「ごちきか」を公開しました (余談として)基盤やデプロイ方法を紹介します What is 「ごちきか」? 私たちのチームでは、社会・産業DXのためのSmart World の一貫として、 時系列データ分析手法の研究開発、お客様のデータ分析支援や社内データ分析人材育成 を行っています。 【最近の研究開発成果】 NTT Comの開発した要因分析手法がAISTATS2022にて採択 www.ntt.com 2022年度人工知能学会全国大会 (JSAI2022) で発表してきた話 〜因果探索編〜 engineers.ntt.com また、これらの研究開発成果は、同じくイノベーションセンターで開発している ノーコードAI開発ツールNode-AI に搭載されていきますので、こちらもぜひご覧ください。詳しくは、以下の公式サイトとEngineers’Blogをご参照ください。 sdpf.ntt.com engineers.ntt.com この ごちきか(gochikika)プロジェクト は、これら研究開発成果や社内向けデータ分析人材育成コンテンツをまとめたナレッジベースです。主に製造業の時系列データを対象として、前処理からモデリングまで基本的な分析手法をPythonのソースコード付きで解説しています。 Why ごちきか 世の中にはありがたいことにたくさんのデータ分析に関するドキュメントがあります(いつも参考にさせていただいています)。しかし、私たちの興味のある時系列データ分析(特にプラント向けのようなドメイン知識に紐づくもの)については多くはなく、例えば新入社員の教育の際に困ることがありました。 さらに、学会発表資料やコードが個人管理のPCやGitHubに分散しており、チームの研究開発成果や検証結果が属人化していまっていました。社内向けライブラリを作ることも試しましたが、ユーザー不在で維持管理コストが高く普及しませんでした。そこで、ライブラリ化の前段として、ドキュメント化第一で考え、一元管理することとしました。研究者のアウトプットとしてもドキュメント化は重要であると考えました。 本記事の投稿は、私たちの取り組み内容や研究開発、興味がある分野について知ってもらうことが目的の1つです。 How to ごちきか それぞれの記事は、なるべくそのページ内でコードが完結するようにしています。したがって、一部数式が多く難しく見えるかもしれませんが、基本的なPythonの使い方がわかればコピー&ペーストで試すことができます。 いくつかコンテンツが含まれていますが、現在は2つの項目に大別されています。 分析 主に製造業の時系列データを対象として、基本的な分析手法をPythonコード付きで解説しています。 内部で開発した酢酸ビニルプラントシミュレーターから生成したデータを使用 可視化、前処理、モデリング、学習の実行まで一連の分析が可能。例えば以下のようなコンテンツがあります。 可視化: matplotlibを使った 時系列データの可視化 , スペクトル解析 前処理: 次元削減 , 次元圧縮 モデリング: PLSモデル , ガウス過程回帰モデル 学習: クロスバリデーション , ハイパーパラメータ最適化(ベイズ最適化) 特集記事 比較的新しめであったり難易度の高い手法や、私たちの取り組みを知ってもらうための学会発表資料が掲載されます。また一部未分類なコンテンツが格納されています。 例えば、変数間の依存関係をはかる Hilbert-Schmidt独立性基準 や、Trace LASSO/Graphical LASSOといった 発展的なスパースモデリング手法  があります(個人的な推しコンテンツです)。 基盤について 私たちの主な業務は研究開発やデータ分析なので、その片手間でサーバーやセキュリティ対策を完全には運用しきることは難しいです。そこで、以下を目的としてごちきか基盤を作成しました。 【モチベーション】 ドキュメント執筆に注力したい 実験ノート(=Jupyter Notebook)をそのまま使いまわしたい ⇒ MyST-NB インフラにとても詳しいわけではない。でもやるからには便利なシステムにしたい サーバーレス(セキュリティ対策、運用コストの低減) 記事投稿から自動で配信 ⇒ GitHub Actions, AWS MyST-NB をベースとした静的サイトをGitHub Actionsでビルドし、AWSで配信することとしました。概略図は以下の通りです。 MyST (MyST-NB) MyST は、Jupyterのエコシステム上で計算科学のドキュメント化を行う Executable Book Project の中核をなすOSSで、Markdownを拡張し柔軟な記述を可能にしたものです。Pythonにはドキュメンテーションビルダー Sphinx がありますが、 recommonmark というファイルフォーマットを使用しており、Markdownになれたユーザーからすると少々記述に癖がありました。なおrecommonmarkの開発は終了しており、MySTへの移行がすすめられています(MySTはrecommonmarkの文法も使用可能)。 このSphinx+MySTベースで、Jupyter Notebookをhtmlやpdfのドキュメントに変換するものが MyST-NB です。なお以後の説明ではMySTとMyST-NBをまとめて、MySTと記載します。 前述の通り、MySTは標準のMarkdownをJupyter Notebookで扱うだけではなく、リッチな機能を有しています。数式のレンダリングはもちろんのこと、注意書きを示すAdmonition、長すぎるコードをトグル形式で隠す機能、Plotlyやipywidgetsを使ったインタラクティブな描画が可能です。さらに、コンパイル時にJupyter Notebookを実行するテスト機能もあります(機械学習では計算時間がかかるためあまり向きませんが)。 実際にごちきかのコンテンツ、 データセット集, Electricity Transformer Temperature では、admonition、セルの非表示、Plotlyを使ったプロットをサンプルとして示しています。 GitHub Actions ソースコードの管理は会社契約のGitHub Enterpriseで行っています。契約して整備してくださった方々に感謝。 記事のクオリティを担保し、執筆者以外にも最低一人は知識を展開する(バス係数を上げる)ため、 GitHub Flow に従った編集フローを採用しています。 執筆記事に対するレビューが完了すると、公開用のブランチにマージされ、これをトリガーとしてGitHub Actionsが起動します。ActionsはMySTをもちいてJupyter Notebookをhtmlにビルドし、AWS S3にアップロードします。これにより、手動ビルドの必要なく自動で更新作業が済みます。また、逐次ビルドするため通常のGitHub Pagesのようにビルド後のソースを管理する必要もありません(最近だと ベータ版 としてPagesでもActionsが使えるようになったようです)。 AWS AWSでは、ビルドされたコンテンツをS3に格納し、Route53とCloudFrontで配信します。サーバーレスな構成になっているので、運用コストを下げることができました(社内向けだったこともあり、月額利用料金換算でも1ドル以下)。 基本的な設定は以下の公式ドキュメントに従っています。 docs.aws.amazon.com まとめ 時系列データ分析コンテンツ「ごちきか」を公開しました。ごちきかは、時系列データ分析手法や研究開発成果をPythonコード+その解説記事としてまとめ、広く公開するものです。みなさまのデータ分析の一助となれたら幸いです。 私たちの取り組みに興味がございましたら、時系列データ解析/予測/異常検知/最適化を対象としたPoC、各種究機関との共同研究案件、Node-AIのご契約を募集中ですので、ご興味があればこちらまでご連絡ください!(メール:ai-deep-ic[at]ntt.com) また、 中途 /新卒採用も実施しておりますので是非エントリーください。 今後は、まだまだ載せきれていない学会発表資料や、デザイン的につたないところがあるので改善していきたいです。面白い研究成果が出ましたらEngineers’Blogに寄稿&宣伝させてください🙇 明日はいよいよ最終日!トリの記事もお楽しみに!!
この記事は、 NTT Communications Advent Calendar 2022 23 日目の記事です。 はじめに こんにちは、デジタル改革推進部の組橋です。普段は社内データの整備や分析をしています。 この記事では、社内ツールなどの自作ツールを管理する方法や関連するサービスを紹介します。 パッケージリポジトリとは パッケージ ソフトウェアにおけるパッケージとはいくつかの機能を1つにまとめて、管理しやすくしたものを指します。 例えば、Pythonのパッケージは pip コマンドでインストールできます。 pip install $PACKAGE_NAME リポジトリ リポジトリは、保管場所という意味があります。 パッケージリポジトリはパッケージの保管場所です。単にリポジトリというと最近はGitリポジトリを指すことが多いですが、これはソースコードの保管場所ですね。 例えば、Pythonの公式パッケージリポジトリは Python Package Index (PyPI) であり、 pip でインストールする際のデフォルトの参照先に指定されています。 自分たち専用のパッケージリポジトリ Pythonに限らず他の言語にも公式のパッケージリポジトリがあり、公開されているパッケージを利用して開発することは一般的です。 公開されているパッケージに自分たちのほしいものがないとき、自作することはよくあることかと思います。 しかし、プロジェクトごとにツールを作って utils や tools みたいなディレクトリに置いていくと、似たようなツールが散乱してしまいます。 そこで、自分たち専用のパッケージリポジトリを用意すると、ツールの配布や管理が便利になります。 リポジトリがあることで再利用が促進され、開発効率が上がるかもしれません。 Pythonのプライベートパッケージリポジトリ Pythonで独自のパッケージリポジトリを用意するには、 pypiserver を用いる方法が簡単です。 pypiserver自身もPython製なので pip でインストールできます。 pip install pypiserver 本番運用はリポジトリ用のVMなどで実行するかと思いますが、ここではローカルで実行する方法を紹介します。 はじめに、 htpasswd コマンドで htpasswd.txt ファイルを作成します。デフォルトではMD5で生成されます。 $ htpasswd -c htpasswd.txt $USERNAME New password: Re-type new password: Adding password for user USERNAME pypi-server run コマンドを実行することでサーバが起動します。引数に指定している ./packages はパッケージを格納するディレクトリです。 pypi-server run -p 8080 -P htpasswd.txt ./packages パッケージをアップロードする方法は公式のPyPIと同様です。 例えば、 setuptools を用いてパッケージをアップロードするには、 ~/.pypirc にリポジトリのサーバ情報を書きます。 [distutils] index-servers = local [local] repository: http://localhost:8080 username: $USERNAME password: $PASSWORD --repository または -r オプションを使用すると、 ~/.pypirc に記載した設定を使用してアップロードできます。 python setup.py sdist upload -r local 標準ライブラリである setuptools を用いた方法を紹介しましたが、Pythonでパッケージを作成する場合、 Poetry もおすすめです。 今回のテーマから逸れるので説明は割愛しますが、興味がある方はぜひ触ってみてください! インストールするには -index-url または --extra-index-url のオプションでリポジトリのURLを指定します。 オプションではなく、環境変数に設定する方法や pip.conf に記載する方法もありますが、ここでは割愛します。 pip install --extra-index-url http://localhost:8080 $PACKAGE_NAME 専用リポジトリを導入するメリットの1つとして、上記のように公式のパッケージと同じ形式(例えば pip install )でインストールできることがあります。 プライベートパッケージリポジトリサービス 前節では独自にサーバを立ててリポジトリを運用する紹介しましたが、 Gemfury や AWS CodeArtifact などパッケージリポジトリのサービスが存在します。 Gemfury Gemfury は古くからあるサービスで、パッケージリポジトリに特化しています。また、対応している言語も豊富です。 主にユーザ数で課金される Personal プランと、アップロードできるプライベートパッケージ数で課金される Team プランの2種類があります 1 。 Gemfuryのリポジトリにパッケージをアップロードする方法はいくつかあります。 以下の方法を用いることで言語を問わず、同じようにアップロードできます。 curl コマンド Gemfury CLI GemfuryのWebページ(GUI) ここでは Gemfury CLI を利用する方法を紹介します。 Homebrew を使用してインストールできます。 Homebrew以外のインストール方法については、 こちらのドキュメント を参照してください。 brew tap gemfury/tap brew install fury-cli login コマンドでログインします。 $ fury login Please enter your Gemfury credentials. Email: : youremail@domain.com Password: : ******** You are logged in as " USERNAME " push コマンドでパッケージをアップロードできます。 fury push $PACKAGE_FILE Pythonパッケージの場合は、前述した ~/.pypirc を利用することもできます。 [fury] repository: https://pypi.fury.io/$USERNAME/ username: $TOKEN password: アップロードしたPythonパッケージをインストールするには、自作リポジトリと同様にリポジトリのURLを指定します。 pip install --extra-index-url https://pypi.fury.io/ $ACCOUNT / $PACKAGE_NAME プライベートなパッケージの場合はトークンを使用します。 pip install --extra-index-url https:// $TOKEN :@pypi.fury.io/ $ACCOUNT / $PACKAGE_NAME AWS CodeArtifact CodeArtifact は、AWSのサービス群の1つです。 基本的な使用方法はGemfuryと大きく変わらないため詳細は割愛しますが、furyのように専用のCLIやGUIからのアップロードはできません。 指定されたリポジトリのURLとトークンを用いてアップロードします。 トークンは、AWS CLIで発行できます 2 。 また、トークンの有効期限は最大12時間といった制限があります。 対応言語の比較 紹介したサービス以外にも類似サービスはいくつかあります。 ここでは、各サービスで対応しているプログラム言語の対応表を紹介したいと思います。 なお、対応表にはプログラム言語に限定して記載しています 3 。 Gemfury AWS CodeArtifact GCP Artifact Registry Azure Artifacts GitHub Packages PyPI (Python) ○ ○ ○ ○ - RubyGems (Ruby) ○ - - - ○ Composer (PHP) ○ - - - - Go Modules (Go) ○ - - - - Maven (Java) ○ ○ ○ ○ ○ npm (JavaScript) ○ ○ ○ ○ ○ NuGet (.NET) ○ ○ - ○ ○ 使用感が大きく異なることはないと思われるので、対応している言語や普段使用している環境などに応じて選択すると良いでしょう。 おわりに 社内ツールを配布や管理を便利にするプライベートパッケージリポジトリの導入や利用について紹介しました。 チーム内や部門内などで共通のパッケージリポジトリを用意しておくと便利なので皆さんもお試しください。 https://fury.co/pricing ↩ https://docs.aws.amazon.com/ja_jp/codeartifact/latest/ug/tokens-authentication.html ↩ サービスによってはaptなどLinuxパッケージを管理できるものもあります。 ↩
この記事は、 NTT Communications Advent Calendar 2022 22日目の記事です。 はじめに こんにちは、イノベーションセンターの鈴ヶ嶺( @suzu_3_14159265 )です。普段は、クラウド・ハイブリッドクラウド・エッジデバイスなどを利用したAI/MLシステムに関する業務に従事しています。 本日は、Rustでベクトル化された乱数生成器を実装する方法を紹介します。乱数生成器には Permuted congruential generator(PCG) という高速でシンプルな実装を取り扱います。ベクトル化には1つの命令で複数のデータを適用するSingle Instruction, Multiple Data(SIMD)を活用します。 また、以下のように毎年Rustネタのアドベントカレンダーを書いているのでぜひ見ていただけると嬉しいです! NTTコミュニケーションズ Advent Calendar 2021 Rustで実装するmalloc NTTコミュニケーションズ Advent Calendar 2020 Rustで実装するNetflow Collector PCGとは Permuted congruential generator(PCG) 1 は、シンプルな実装でメモリ消費も低く高速な乱数生成アルゴリズムです。次式のような線形合同法の出力に対してXorshift 2 のような排他的論理和とビットシフト操作 ( x ^= x >> N) を加えることで、線形合同法で見られる偶数と奇数が交互にでるような下位ビットの低いランダム性を改善しています。 また、PCGは TestU01 3 と呼ばれる乱数生成器をテストするツールのBig Crushと呼ばれる最も大きいテストを突破しています。 PCGの活用事例をみると、例えば Numpy の乱数生成器はデフォルトでPCGが採用されています。 The default BitGenerator used by Generator is PCG64. https://numpy.org/doc/stable/reference/random/generator.html ちなみに、他の乱数生成器との比較は次のようにPCGの公式ページに表としてまとめられており分かりやすいので気になる方は参照してください。 https://www.pcg-random.org/ Rustでは、乱数生成ライブラリの rand_pcg クレートから利用が可能です。次に利用方法のサンプルコードを示します。 use rand :: prelude :: * ; use rand_pcg :: Pcg32; fn main () { let mut rng = Pcg32 :: from_entropy (); let ru32: u32 = rng. gen (); println! ( "{}" , ru32); } PCGの実装方法は、Rustのrand 0.8.5のソースコードの一部を抜粋してコメントアウトを用いて次にインラインで説明します。 https://github.com/rust-random/rand/blob/0.8.5/rand_pcg/src/pcg64.rs const MULTIPLIER: u64 = 6364136223846793005 ; // 乗数は固定値 pub struct Lcg64Xsh32 { state: u64 , // 出力の2倍の状態をもつ increment: u64 , // 任意の奇数 } pub type Pcg32 = Lcg64Xsh32; // LCG(線形合同法)64bitにXSH(xorshift操作)をするという意味 impl Lcg64Xsh32 { // 線形合同法の1ステップ fn step ( &mut self ) { self .state = self .state . wrapping_mul (MULTIPLIER) // 積 . wrapping_add ( self .increment); // 和 } } impl RngCore for Lcg64Xsh32 { fn next_u32 ( &mut self ) -> u32 { let state = self .state; self . step (); // 線形合同法で現在の状態から次の状態を計算 // xorshift操作のbit数パラメータ const ROTATE: u32 = 59 ; // 64 - 5 const XSHIFT: u32 = 18 ; // (5 + 32) / 2 const SPARE: u32 = 27 ; // 64 - 32 - 5 let rot = (state >> ROTATE) as u32 ; let xsh = (((state >> XSHIFT) ^ state) >> SPARE) as u32 ; // xorshift操作 xsh. rotate_right (rot) // ビット回転により出力は状態のビット数の半分(32bit) } } ベクトル化とは ベクトル化はfor文などで繰り返し1つずつ計算している処理を高速に処理する手法です。今回はその中のSingle Instruction, Multiple Data(SIMD)という技術を活用します。SIMDは1つの命令で複数のデータを処理する方法です。例えば256bitのSIMD命令がある場合は64bit x 4個=256bitのように64bitのデータを同時に4個処理可能です。 Rustでは次のように core::arch::x86_64 ( https://doc.rust-lang.org/core/arch/x86_64/index.html ) 以下の _mm128_** , _mm256_** などのunsafeな関数を利用することでSIMDを利用することが可能になります。 例えば64bitごとに計4個の値を同時に加算するコード例を以下に示します。 今回はIntel AVX2環境で実装します。 #[cfg(any(target_arch = "x86_64" ))] use core :: arch :: x86_64 :: * ; fn main () { unsafe { sample (); } } #[cfg(any(target_arch = "x86" , target_arch = "x86_64" ))] #[target_feature(enable = "avx2" )] unsafe fn sample () { let a = _mm256_set_epi64x ( 1 , 2 , 3 , 4 ); let b = _mm256_set_epi64x ( 5 , 6 , 7 , 8 ); let c = _mm256_add_epi64 (a, b); println! ( " a : {:?}" , a); println! ( " b : {:?}" , b); println! ( "a+b: {:?}" , c); } 以下は、出力結果です。 a : __m256i(4, 3, 2, 1) b : __m256i(8, 7, 6, 5) a+b: __m256i(12, 10, 8, 6) このように2つの配列 [1, 2, 3, 4] , [5, 6, 7, 8] 各要素の加算された結果 [6, 8, 10, 12] が返ってきたことが分かると思います。このように1つの命令で複数のデータを処理します。これをPCGの実装の中の線形合同法のステップ、出力のxorshift操作とビット回転に適用していきます。 その他にも応用的なSIMDの活用方法を知りたい場合は simdjson などの高速JSON Parserの作者で著名なDaniel Lemire先生の githubのrepo を覗いてみるのをお勧めします。次に説明する実装も、C言語で実装された simdpcg や SIMDxorshift を参考にして作成しました。 実装 ここでは、SIMDを用いてベクトル化したPCG実装を示します。基本方針としてユーザが直接利用する関数に関してはsafeな関数として実装していきます。 64bitごとの積を計算する _mm256_mullo_epi64 はavx2にはないため別途実装していることなどに注意してください。 また、 portable_simd を利用するためnightlyを利用します。 #![feature(portable_simd)] #[cfg(target_arch = "x86_64" )] use std :: arch :: x86_64 :: * ; use std :: simd :: {u32x4}; #[cfg(any(target_arch = "x86" , target_arch = "x86_64" ))] pub struct Avx2Pcg { state: __m256i, inc: __m256i, mul_l: __m256i, mul_h: __m256i, } const MULTIPLIER: i64 = 6364136223846793005 ; // 乗数は固定 #[cfg(any(target_arch = "x86" , target_arch = "x86_64" ))] #[target_feature(enable = "avx2" )] #[inline] // 64bitごとの積 unsafe fn _mm256_mullo_epi64 (x: __m256i, ml: __m256i, mh: __m256i) -> __m256i { let xl = _mm256_and_si256 (x, _mm256_set1_epi64x ( 0x00000000ffffffff )); let xh = _mm256_srli_epi64 (x, 32 ); let hl = _mm256_slli_epi64 ( _mm256_mul_epu32 (xh, ml), 32 ); let lh = _mm256_slli_epi64 ( _mm256_mul_epu32 (xl, mh), 32 ); let ll = _mm256_mul_epu32 (xl, ml); let ret = _mm256_add_epi64 (ll, _mm256_add_epi64 (hl, lh)); return ret; } #[cfg(any(target_arch = "x86" , target_arch = "x86_64" ))] #[target_feature(enable = "avx2" )] #[inline] unsafe fn _mm256_rorv_epi32 (x: __m256i, r: __m256i) -> __m256i { let ret = _mm256_or_si256 ( _mm256_sllv_epi32 (x, _mm256_sub_epi32 ( _mm256_set1_epi32 ( 32 ), r)), _mm256_srlv_epi32 (x, r), ); return ret; } impl Avx2Pcg { #[inline] fn next ( &mut self ) -> __m128i { unsafe { self . next_ () } } #[cfg(any(target_arch = "x86" , target_arch = "x86_64" ))] #[target_feature(enable = "avx2" )] #[inline] unsafe fn next_ ( &mut self ) -> __m128i { let old_state = self .state; // 積和計算 self .state = _mm256_add_epi64 ( _mm256_mullo_epi64 ( self .state, self .mul_l, self .mul_h), self .inc, ); // xorshift let xorshifted = _mm256_srli_epi64 ( _mm256_xor_si256 ( _mm256_srli_epi64 (old_state, 18 ), old_state), 27 , ); let rot = _mm256_srli_epi64 (old_state, 59 ); // ビット回転 let ret = _mm256_castsi256_si128 ( _mm256_permutevar8x32_epi32 ( _mm256_rorv_epi32 (xorshifted, rot), _mm256_set_epi32 ( 7 , 7 , 7 , 7 , 6 , 4 , 2 , 0 ), )); return ret; } #[inline] pub fn next_u32x4 ( &mut self ) -> [ u32 ; 4 ] { let m128: u32x4 = self . next (). into (); return * m128. as_array (); } #[inline] pub fn from_state_inc (state: [ i64 ; 4 ], inc: [ i64 ; 4 ]) -> Avx2Pcg { unsafe { Avx2Pcg { state: _mm256_set_epi64x (state[ 0 ], state[ 1 ], state[ 2 ], state[ 3 ]), inc: _mm256_set_epi64x (inc[ 0 ] | 1 , inc[ 1 ] | 1 , inc[ 2 ] | 1 , inc[ 3 ] | 1 ), // 奇数のため "| 1" を追加 mul_l: _mm256_set1_epi64x (MULTIPLIER & 0x00000000ffffffff ), // 乗数は固定 mul_h: _mm256_set1_epi64x (MULTIPLIER >> 32 ), // 乗数は固定 } } } #[inline] pub fn from_entropy () -> Avx2Pcg { let mut state_buf: [ u8 ; 32 ] = [ 0u8 ; 32 ]; let mut inc_buf: [ u8 ; 32 ] = [ 0u8 ; 32 ]; let _ = getrandom :: getrandom ( &mut state_buf); let _ = getrandom :: getrandom ( &mut inc_buf); let state_buf64: [ i64 ; 4 ] = unsafe { std :: mem :: transmute (state_buf) }; let inc_buf64: [ i64 ; 4 ] = unsafe { std :: mem :: transmute (inc_buf) }; Avx2Pcg :: from_state_inc (state_buf64, inc_buf64) } } 実験 実際に、32bit x 10000000個の合計40Mbの乱数生成時間でRustのPCG実装のベースラインと今回のベクトル化されたPCG実装の比較します。 実験環境はGoogle Cloudのインスタンスサイズn2-standard-2, Ubuntu20.04LTSです。 Rust versionはrustc 1.68.0-nightly (d0dc9efff 2022-12-18)を利用します。 また、ループアンローリングでループ内に複数の命令数(1, 2, 4)を展開したケースもわけて計測します。 ちなみに、計測ツールには Criterion.rs を利用して試行回数100回で計測しました。 use criterion :: {criterion_group, criterion_main, Criterion}; use rand :: prelude :: * ; use rand_pcg :: Pcg32; use simd_pcg :: Avx2Pcg; const N: usize = 10000000 ; pub fn avx_one (c: &mut Criterion) { c. bench_function ( "avx one" , | b | { b. iter ( || { let mut arr = vec! [ 0u32 ; N]; let mut rng1 = Avx2Pcg :: from_entropy (); for i in ( 0 ..N). step_by ( 4 ) { let r1_arr = rng1. next_u32x4 (); arr[i..(i + 4 )]. copy_from_slice ( & r1_arr); } }) }); } pub fn avx_two (c: &mut Criterion) { c. bench_function ( "avx two" , | b | { b. iter ( || { let mut arr = vec! [ 0u32 ; N]; let mut rng1 = Avx2Pcg :: from_entropy (); let mut rng2 = Avx2Pcg :: from_entropy (); for i in ( 0 ..N). step_by ( 8 ) { let r1_arr = rng1. next_u32x4 (); let r2_arr = rng2. next_u32x4 (); arr[i..(i + 4 )]. copy_from_slice ( & r1_arr); arr[(i + 4 )..(i + 8 )]. copy_from_slice ( & r2_arr); } }) }); } pub fn avx_four (c: &mut Criterion) { c. bench_function ( "avx four" , | b | { b. iter ( || { let mut arr = vec! [ 0u32 ; N]; let mut rng1 = Avx2Pcg :: from_entropy (); let mut rng2 = Avx2Pcg :: from_entropy (); let mut rng3 = Avx2Pcg :: from_entropy (); let mut rng4 = Avx2Pcg :: from_entropy (); for i in ( 0 ..N). step_by ( 16 ) { let r1_arr = rng1. next_u32x4 (); let r2_arr = rng2. next_u32x4 (); let r3_arr = rng3. next_u32x4 (); let r4_arr = rng4. next_u32x4 (); arr[i..(i + 4 )]. copy_from_slice ( & r1_arr); arr[(i + 4 )..(i + 8 )]. copy_from_slice ( & r2_arr); arr[(i + 8 )..(i + 12 )]. copy_from_slice ( & r3_arr); arr[(i + 12 )..(i + 16 )]. copy_from_slice ( & r4_arr); } }) }); } pub fn baseline_one (c: &mut Criterion) { c. bench_function ( "baseline one" , | b | { b. iter ( || { let mut arr = vec! [ 0u32 ; N]; let mut rng1 = Pcg32 :: from_entropy (); for i in ( 0 ..N). step_by ( 1 ) { arr[i] = rng1. gen (); } }) }); } pub fn baseline_two (c: &mut Criterion) { c. bench_function ( "baseline two" , | b | { b. iter ( || { let mut arr = vec! [ 0u32 ; N]; let mut rng1 = Pcg32 :: from_entropy (); let mut rng2 = Pcg32 :: from_entropy (); for i in ( 0 ..N). step_by ( 2 ) { arr[i] = rng1. gen (); arr[i + 1 ] = rng2. gen (); } }) }); } pub fn baseline_four (c: &mut Criterion) { c. bench_function ( "baseline four" , | b | { b. iter ( || { let mut arr = vec! [ 0u32 ; N]; let mut rng1 = Pcg32 :: from_entropy (); let mut rng2 = Pcg32 :: from_entropy (); let mut rng3 = Pcg32 :: from_entropy (); let mut rng4 = Pcg32 :: from_entropy (); for i in ( 0 ..N). step_by ( 4 ) { arr[i] = rng1. gen (); arr[i + 1 ] = rng2. gen (); arr[i + 2 ] = rng3. gen (); arr[i + 3 ] = rng4. gen (); } }) }); } ループアンローリング 命令数 baseline avx2(今回の実装) 1 27.601 ms 24.447 ms 2 23.357 ms 19.803 ms 4 22.839 ms 19.526 ms 上の表が試行回数100回の計測時間の平均結果、図が計測時間の分布を示しています。 この結果からベクトル化された今回の実装のavx2は特にループアンローリングの命令数が多い場合baselineよりも有意に高速であることが分かります。 また、こちらの実験コードは以下に置いておきます。 https://github.com/suzusuzu/simd-pcg 次のコマンドで実行可能です。 git clone git@github.com:suzusuzu/simd-pcg.git cd simd-pcg rustup run nightly cargo bench まとめ 本記事では、PCGを対象にSIMDによるベクトル化をRustで実装する方法を紹介しました。また、比較実験の結果からもSIMD化による高速化が有効であることを示しました。 それでは、明日の記事もお楽しみに! 参考 Intel® Intrinsics Guide PCG, A Family of Better Random Number Generators xoshiro / xoroshiro generators and the PRNG shootout simdpcg SIMDxorshift O’Neill, Melissa E. "PCG: A family of simple fast space-efficient statistically good algorithms for random number generation." ACM Transactions on Mathematical Software (2014). ↩ Marsaglia, George. "Xorshift rngs." Journal of Statistical Software 8 (2003): 1-6. ↩ L'ecuyer, Pierre, and Richard Simard. "TestU01: AC library for empirical testing of random number generators." ACM Transactions on Mathematical Software (TOMS) 33.4 (2007): 1-40. ↩