TECH PLAY

NTTドコモビジネス

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

613

この記事は、  NTT Communications Advent Calendar 2023  2日目の記事です。 こんにちは、イノベーションセンターの坪井です。 1日目の記事を担当した平木と同じくNetwork Analytics for Securityというチーム(通称NA4Sec)に所属しています。 1日目の記事はこちらです。 https://engineers.ntt.com/entry/2023/12/01/102753 engineers.ntt.com NA4Secプロジェクトについては、  サイバー脅威インテリジェンス(CTI)配信はじめました  を読んでいただくと我々がどんな活動を行なっているかわかると思います。 先日の11/21(火)にInternet Week 2023の C10 DNS DAY というプログラムの中で「ランダムサブドメイン攻撃において事業者として行なった対策と解析について」というタイトルで講演をさせていただきました。 講演の中で、私はDNSハニーポットを運用してランダムサブドメイン攻撃を観測した話をさせていただいたのですが、アドベントカレンダー2日目の本記事では講演の中で出てきたサブドメイン列挙ツールについて、お話しします。 はじめに:免責事項 ランダムサブドメイン攻撃とは サブドメイン列挙とは SubBruteについて サブドメイン列挙とランダムサブドメイン攻撃 まとめ はじめに:免責事項 本記事は、あくまでも調査したサブドメイン列挙ツールの動きについてご紹介するものであり、利用を積極的に推奨するものではありません。また、これらのツールを悪意ある目的で使用することは禁止されています。 これらのツールを使用することによって発生したいかなる損害や問題について、ツール開発者や提供者及び本記事の執筆者・ブログ管理者は責任を負いません。予めご了承ください。 ランダムサブドメイン攻撃とは まず初めに、ランダムサブドメイン攻撃について簡単に説明します。 ランダムサブドメイン攻撃とはサイバー空間におけるDNSを使ったDDoS攻撃手法の1つです。 悪意のある攻撃者がランダムな文字列やパターンを使用して、特定のドメイン名に対して無差別にサブドメイン名を生成し、生成したサブドメイン名を使ってキャッシュDNSサーバに名前解決の問い合わせ(クエリ)をします。 キャッシュDNSサーバでは受けたクエリのドメイン名に対する情報をすでに保持している場合は保持している情報を返しますが、保持していない場合はそのドメイン名の権威DNSサーバにクエリをします 1 。 今回のようなランダムなサブドメイン名の場合、ほとんどのドメイン名についてはキャッシュDNSサーバには過去のクエリ応答情報が存在していないため、攻撃者からのクエリの都度、権威DNSサーバへクエリをすることになります。 一般的にランダムサブドメイン攻撃は、意図的に大量のDNSクエリを発生させて権威DNSサーバへ負荷をかけることで、各種リソースの逼迫にともなう関連サービスの品質低下またはサーバダウンなどによる関連サービスの停止(いわゆるDoS)を狙いとした攻撃と考えられています。 サブドメイン列挙とは 次に、今回のテーマであるサブドメイン列挙ツールが行う、サブドメイン列挙についてお話しします。 サブドメイン列挙(Subdomain Enumeration)とは、特定のドメインに関して利用されているサブドメイン 2 を調査し、そのドメイン名をリスト化するプロセスです。 サブドメイン列挙ツールは、セキュリティテストやネットワークスキャニング、ペネトレーションテスト、またはウェブアプリケーションのセキュリティ評価など、さまざまなセキュリティアクティビティで使用されます。 サブドメイン列挙ツールは以下のような手法を使用してサブドメインを収集します。 有名なサブドメイン列挙ツールについて、いくつか取り上げて比較してみました。 サブドメイン列挙ツールはどういう仕組みになっているか、今回はInternet Weekの講演の中でも名前が出たSubBruteについて中身を見ていきたいと思います。 SubBruteについて SubBruteはPythonで書かれたオープンソースのサブドメイン列挙ツールで主にブルートフォースを実行することに特化しています。DNS におけるブルートフォースは一般的なサブドメインの名前や文字列の組み合わせなどのパターンをさまざま試行する手法です。 指定されたドメインに対して複数の一般的なサブドメイン名を含むワードリストを使用し、DNSクエリを送信して有効なサブドメインを探索します。このプロセスにより、目標のドメインに紐づく未知のサブドメインを見つけることができます。 TheRook/subbrute: A DNS meta-query spider that enumerates DNS records, and subdomains. (github.com) SubBruteのプログラムを紐解いてみたところ、下記の機能を備えていることがわかりました。 なお、下記の機能名は処理内容から類推して付けた呼び名なので、実際の機能名とは関係ありません。 ターゲットドメイン情報取得機能 サブドメイン作成対象のターゲットドメインの権威DNSサーバを列挙し、応答性のテストを行い、正常応答の場合はDNSクエリ対象の権威DNSサーバ一覧に追加する。 サブドメインリスト生成機能 一般的に使用されるサブドメイン(wwwなど)や予め用意されたワードリストを使用して存在する可能性のあるサブドメインリストを生成し、DNSクエリをランダムな順序で行えるようにリストの順序をシャッフルさせる。権威DNSサーバがDNSクエリを異常とみなすことを防いだり、1つの権威DNSサーバに対するDNSクエリが集中することを避けることが目的と思われる。 DNSクエリ実行機能 サブドメインリスト生成機能で生成されたリストを元にDNSクエリを行う。この機能はマルチプロセスで実行され、大量のDNSクエリを並列で実行する。 DNSクエリ結果解析機能 DNSクエリ実行機能の結果から必要な情報を取り出し解析・整形する。 Aレコードの場合はドメイン名に対応するIPv4アドレスを、AAAAレコードの場合はIPv6アドレスを取り出す。CNAMEレコードからは別名となるドメイン名を取り出す。 取り出した結果をドメイン名と対応するIPアドレスで組み合わせた形に整形する。 例として example.jp をターゲットドメインとしてSubBruteを実行すると以下のような動きになります。 $ python subbrute.py example.jp メイン機能で example.jp をターゲットのドメインとして設定する。 ターゲットドメイン情報取得機能で指定されたターゲットドメイン  example.jp  のDNSクエリに応答する権威DNSサーバーのリストを生成する。 サブドメインリスト生成機能で、ターゲットドメイン  example.jp  のすべての可能性のあるサブドメインのリストを作成しリスト内をシャッフル。 DNSクエリ実行機能で、 example.jp  の各サブドメインに対するDNSクエリを並列で実行する。 DNSクエリ結果解析機能で、DNSクエリ実行機能の結果を解析・整形する。例えば  mail.example.jp www.example.jp  などの  example.jp  のサブドメイン名と、サブドメイン名に対応するIPアドレスを出力する。 以上の流れにより、 example.jp  のサブドメインと、それらのドメイン名に紐づくIPアドレスなどの情報を取得できます。 このようにワンライナーのコマンドでサブドメイン列挙ツールを実行するだけでサブドメイン列挙行為自体はとても簡単に行うことができます。 サブドメイン列挙とランダムサブドメイン攻撃 さて、今回はSubBruteの動作を紐解いてみました。SubBruteの動作の中では大量のサブドメイン候補からなるリストを生成し、DNSクエリを行っています。 「SubBruteについて」内では説明を省略していますが、SubBruteがDNSクエリを実行する際は、予め設定されているキャッシュDNSサーバを使用します。 キャッシュDNSサーバへクエリした時に、キャッシュDNSサーバがクエリ応答情報を保持していないサブドメインだった場合、権威DNSサーバにクエリを行うことになります。 あれ、これ何かに似てませんか? そう、冒頭で説明したランダムサブドメイン攻撃の構造に似ているんです。 サブドメイン列挙ツールはセキュリティテストやネットワークスキャニング、ペネトレーションテスト、またはウェブアプリケーションのセキュリティ評価といったシチュエーションでの利用を想定して開発されたツールですが、その動作過程上でDNSクエリを大量発生させ、ランダムサブドメイン攻撃に似た状況を作り出してしまうことがあるため、ツールの取り扱いには十分注意するようにしましょう。 まとめ 今回はInternet Weekで登壇させていただいた講演内容からサブドメイン列挙ツールについて深掘りして書いてみました。改めて、サブドメイン列挙とランダムサブドメイン攻撃は紙一重と感じました。最後まで、ご覧頂きありがとうございました。 明日も同じくNetwork Analytics for Securityチームに所属する益本の記事です!それでは、明日の記事もお楽しみに! 厳密にはいきなり目的の権威DNSサーバにクエリをする挙動をとるとは限りませんが、最終的には何らかの形で権威DNSサーバへのクエリにつながるので、ここでは簡単のためにこのように表現しています。 ↩ あるドメインの中の部分的な名前空間のことで、そのドメインに関連する特定のサービス(ウェブサイトやメールなど)を提供するサーバを識別するためなどに使われる。例えば「www」はウェブサーバを指す名前としてよく使われる。 ↩
この記事は、 NTT Communications Advent Calendar 2023 1日目の記事です。 はじめに こんにちは、イノベーションセンターの平木と申します。 11月1日にNA4Secプロジェクト 1 のチームにセキュリティエンジニアとしてjoinしまして、急遽、エンジニアブログに投稿させていただくことになりました。 今日ご紹介したいのは、前職(NTT Comの他部門)のセキュリティ機器の導入プロジェクトの話で、その中で私が遭遇した「嘘のような本当の話!?」をご紹介し、そこで得た学びをお伝えしたいと思います。 開発プロジェクトの概要 とある事件をきっかけに全社的にセキュリティ意識が今まで以上に高まって、より適切に権限をコントロールすべく、認可認証の仕組みが導入されることが決まりました。我々のチームでは、サーバネットワーク基盤を用意し、認証アプリを導入し、運用を確立することがミッションでした。そして私は、主にシステム構築のプロジェクトマネージャとして、スケジューリングから設計、ベンダコントロールなどを推進しました。 このプロジェクトの中で私が担当した業務の1つがセキュリティポリシーの設計です。そして、策定したポリシーの1つが「Firewallポリシーを許可リスト方式にする」ことでした。 許可リスト方式とは、通過させる送信元/宛先通信の対象をリスト形式で指定し、それ以外の通信を遮断する方式です。 例えば「送信元IPアドレスが192.0.2.1、宛先ポートがTCP22番ポート(SSH)となる通信」「宛先IPアドレスが198.51.100.2、宛先ポートがTCP443番ポート(HTTPS)となる通信」..といった形で対象となる通信をリスト形式で指定します。 許可リスト方式を用いることで、通信を必要最小限の経路に限定し、意図しない侵入経路の発生を防ぎます。 対照的に、遮断する通信を指定し、それ以外の通信を通過させる方式を拒否リスト方式と呼びます。 なぜ許可リスト形式としたか?部門内の他システムでは許可対象選定が甘く、不要な通信を含む/24や/20などの大きめのネットワークが許可され、結果的に内部ネットワークで重要なサーバへの通信が全許可されてしまっていたケースが過去に発生していました。そのため、必要な通信のみを許可して欲しいと考え、敢えて許可リスト形式という形を強調し開発を進めました。 加えて、本システムは認証認可だけではなく、CLIやGUI操作のログを収集する機能も持っており、複数のネットワークが接続される環境でした。 万が一不正侵入された場合には、複数ネットワークをまたがる中継点として悪用されかねない 2 ため、一般的なシステムよりも高いセキュリティレベルが求められます。 そのために、EDR(Endpoint Detection and Response)や多要素認証に加えて、許可リスト方式でアクセス可能なホストをより厳格に制限することでセキュリティを強化することとしました。 そして事件は起こった! まさかの全送信元IP許可 たまたま設計を見直す機会があって、許可リスト設定を確認したところ、なんとクライアントネットワークと一部のサーバネットワークについて、全送信元IPアドレスからの通信が許可されていることに気づきました。これでは、過去に重要なサーバへの通信が許可されてしまったことの反省が活かされていないことになってしまいます。なお今思い返すと、設定変更に気づける仕組みがあれば良かったと思いますが、構築開始当初で十分に仕組みやプロセスが整っておらず、当時は気づくことができませんでした。現在は運用プロセスで気づけるようになっています。 なぜ許可してしまったのか? 状況を確認したところ「クライアントネットワークと一部のサーバネットワークではIPアドレスを固定できないホストがおり、当該ネットワークの全IPアドレスから通信を許可せざるをえなかった」ということが分かりました。 結局どうしたか? 暫定対処としては、全許可によるリスクを改めて評価し、対象となるネットワークはインターネット公開システムを持っていない点等を考慮し、直接侵入されるリスクが低いことから、リスクを許容することになりました。 本格対処としては、許可リストの目的・意図を明文化し、セキュリティポリシーを関係者で改めて共有しました。 ただし、そもそもの話として、許可リストが適切だったか?という点は再考すべきであったかもしれません。システムを導入しようとしたネットワークは、過去の経緯が積み重なった結果、構成が不明瞭となり、そもそもIPアドレスの精査が難しかったとも考えられます。当然この状況で精査をしようとしても、精査の負荷が大きくなるため、運用負荷を軽減すべくセキュリティポリシーを緩めざるを得なかったと捉えることができます。 今回の場合、境界型防御と一部、ゼロトラスト・アーキテクチャの思想を取り入れたハイブリット設計を採用しましたが、「ネットワークの場所だけで無条件に信頼しない」というゼロトラストの考え方をさらに推し進めて、IPアドレスに依存しないセキュリティコントロールを前提に設計した方が、もしかしたら既存システムやその運用プロセスにマッチする形で本来実現したかったセキュリティに近づけられたかもしれません。 学び 現行ネットワークに即したセキュリティ要件にすることの大事さ 許可リスト方式は設計する上では分かりやすいが、管理コストの高さなど負の側面もあるので導入に際しては慎重に検討を 理想的には、ゼロトラストの考え方を推し進めたIPアドレスに依存しないセキュリティコントロールの方が、運用しやすかった可能性がある 今回、たまたま初期構築のタイミングで、運用が整っていない中で、不適切な設定が入ってしまったという状況でした。なお、本件以降は、正式な運用が立ち上がり、第三者の目で許可リストを精査するプロセスが入ったため、同様の事象は起こっていません。そのため、許可リスト方式を採用するのであれば、このようにプロセスで防ぐ形が効果的だと考えています。 まとめ この記事では、前職での開発経験の反省を、セキュリティにフォーカスした形で書かせていただきました。 NA4Secプロジェクトでは前職の経験も生かしつつ、分析業務にもチャレンジする予定です。 次は現職で分析したノウハウや経験、成果を、エンジニアブログに書いていきたいと思いますのでご期待ください。 最後まで、ご覧頂きありがとうございました!それでは、明日の記事もお楽しみに! NA4Secプロジェクトについては、このブログの記事 サイバー脅威インテリジェンス(CTI)配信はじめました をご覧ください。 ↩ このようにシステム内部に不正侵入した後に、そこを足がかりに他のサーバなどに侵入を広げる活動を「ラテラルムーブメント」と言います。 ↩
この記事は、 NTT Communications Advent Calendar 2023 1日目の記事です。 はじめに こんにちは、イノベーションセンターの平木と申します。 11月1日にNA4Secプロジェクト 1 のチームにセキュリティエンジニアとしてjoinしまして、急遽、エンジニアブログに投稿させていただくことになりました。 今日ご紹介したいのは、前職(NTT Comの他部門)のセキュリティ機器の導入プロジェクトの話で、その中で私が遭遇した「嘘のような本当の話!?」をご紹介し、そこで得た学びをお伝えしたいと思います。 開発プロジェクトの概要 とある事件をきっかけに全社的にセキュリティ意識が今まで以上に高まって、より適切に権限をコントロールすべく、認可認証の仕組みが導入されることが決まりました。我々のチームでは、サーバネットワーク基盤を用意し、認証アプリを導入し、運用を確立することがミッションでした。そして私は、主にシステム構築のプロジェクトマネージャとして、スケジューリングから設計、ベンダコントロールなどを推進しました。 このプロジェクトの中で私が担当した業務の1つがセキュリティポリシーの設計です。そして、策定したポリシーの1つが「Firewallポリシーを許可リスト方式にする」ことでした。 許可リスト方式とは、通過させる送信元/宛先通信の対象をリスト形式で指定し、それ以外の通信を遮断する方式です。 例えば「送信元IPアドレスが192.0.2.1、宛先ポートがTCP22番ポート(SSH)となる通信」「宛先IPアドレスが198.51.100.2、宛先ポートがTCP443番ポート(HTTPS)となる通信」..といった形で対象となる通信をリスト形式で指定します。 許可リスト方式を用いることで、通信を必要最小限の経路に限定し、意図しない侵入経路の発生を防ぎます。 対照的に、遮断する通信を指定し、それ以外の通信を通過させる方式を拒否リスト方式と呼びます。 なぜ許可リスト形式としたか?部門内の他システムでは許可対象選定が甘く、不要な通信を含む/24や/20などの大きめのネットワークが許可され、結果的に内部ネットワークで重要なサーバへの通信が全許可されてしまっていたケースが過去に発生していました。そのため、必要な通信のみを許可して欲しいと考え、敢えて許可リスト形式という形を強調し開発を進めました。 加えて、本システムは認証認可だけではなく、CLIやGUI操作のログを収集する機能も持っており、複数のネットワークが接続される環境でした。 万が一不正侵入された場合には、複数ネットワークをまたがる中継点として悪用されかねない 2 ため、一般的なシステムよりも高いセキュリティレベルが求められます。 そのために、EDR(Endpoint Detection and Response)や多要素認証に加えて、許可リスト方式でアクセス可能なホストをより厳格に制限することでセキュリティを強化することとしました。 そして事件は起こった! まさかの全送信元IP許可 たまたま設計を見直す機会があって、許可リスト設定を確認したところ、なんとクライアントネットワークと一部のサーバネットワークについて、全送信元IPアドレスからの通信が許可されていることに気づきました。これでは、過去に重要なサーバへの通信が許可されてしまったことの反省が活かされていないことになってしまいます。なお今思い返すと、設定変更に気づける仕組みがあれば良かったと思いますが、構築開始当初で十分に仕組みやプロセスが整っておらず、当時は気づくことができませんでした。現在は運用プロセスで気づけるようになっています。 なぜ許可してしまったのか? 状況を確認したところ「クライアントネットワークと一部のサーバネットワークではIPアドレスを固定できないホストがおり、当該ネットワークの全IPアドレスから通信を許可せざるをえなかった」ということが分かりました。 結局どうしたか? 暫定対処としては、全許可によるリスクを改めて評価し、対象となるネットワークはインターネット公開システムを持っていない点等を考慮し、直接侵入されるリスクが低いことから、リスクを許容することになりました。 本格対処としては、許可リストの目的・意図を明文化し、セキュリティポリシーを関係者で改めて共有しました。 ただし、そもそもの話として、許可リストが適切だったか?という点は再考すべきであったかもしれません。システムを導入しようとしたネットワークは、過去の経緯が積み重なった結果、構成が不明瞭となり、そもそもIPアドレスの精査が難しかったとも考えられます。当然この状況で精査をしようとしても、精査の負荷が大きくなるため、運用負荷を軽減すべくセキュリティポリシーを緩めざるを得なかったと捉えることができます。 今回の場合、境界型防御と一部、ゼロトラスト・アーキテクチャの思想を取り入れたハイブリット設計を採用しましたが、「ネットワークの場所だけで無条件に信頼しない」というゼロトラストの考え方をさらに推し進めて、IPアドレスに依存しないセキュリティコントロールを前提に設計した方が、もしかしたら既存システムやその運用プロセスにマッチする形で本来実現したかったセキュリティに近づけられたかもしれません。 学び 現行ネットワークに即したセキュリティ要件にすることの大事さ 許可リスト方式は設計する上では分かりやすいが、管理コストの高さなど負の側面もあるので導入に際しては慎重に検討を 理想的には、ゼロトラストの考え方を推し進めたIPアドレスに依存しないセキュリティコントロールの方が、運用しやすかった可能性がある 今回、たまたま初期構築のタイミングで、運用が整っていない中で、不適切な設定が入ってしまったという状況でした。なお、本件以降は、正式な運用が立ち上がり、第三者の目で許可リストを精査するプロセスが入ったため、同様の事象は起こっていません。そのため、許可リスト方式を採用するのであれば、このようにプロセスで防ぐ形が効果的だと考えています。 まとめ この記事では、前職での開発経験の反省を、セキュリティにフォーカスした形で書かせていただきました。 NA4Secプロジェクトでは前職の経験も生かしつつ、分析業務にもチャレンジする予定です。 次は現職で分析したノウハウや経験、成果を、エンジニアブログに書いていきたいと思いますのでご期待ください。 最後まで、ご覧頂きありがとうございました!それでは、明日の記事もお楽しみに! NA4Secプロジェクトについては、このブログの記事 サイバー脅威インテリジェンス(CTI)配信はじめました をご覧ください。 ↩ このようにシステム内部に不正侵入した後に、そこを足がかりに他のサーバなどに侵入を広げる活動を「ラテラルムーブメント」と言います。 ↩
この記事では社内部署横断で開催したデータ分析開発合宿の概要や様子を紹介します。 目次 目次 はじめに データ分析開発合宿とは なぜやろうと思ったのか データ分析開発合宿の流れ 開催の様子 Step1 キックオフ Step2 課題ヒアリング Step3 合宿 データ分析開発合宿で得られた成果 おわりに はじめに 皆さんこんにちは、クラウド&ネットワークサービス部の丹野と、ソリューションサービス部の小関と是松です。 私たちは普段業務の傍ら、「データサイエンスちゃんねる」という社内のデータ分析コミュニティの運営をしており、社内向けの輪読会やKaggle LT会などを企画、開催しています。 この記事では、データサイエンスちゃんねる運営主催によるデータ分析開発合宿の概要や様子、成果について紹介したいと思います。 データ分析開発合宿とは データ分析開発合宿とは、エンジニアを中心とした社員が集まって自社サービスの実データ分析を短期集中で行うイベントです。 今回が初開催だったのですが、業務の異なる社内6部署から総勢25名が集まりました。 今回は部署間の交流を目的として全6つの混合チームを作成しました。 本企画では、一般的なデータ分析コンペのように事前に決められた課題を解いて競う形式ではなく、課題のヒアリングから始まる、より実際の分析業務に近い形式となっています。 自ら仮説を立て、最終的にサービスの課題解決に向けて具体的に提案することが目標になります。 なぜやろうと思ったのか 「データサイエンスちゃんねる」運営には社内のさまざまな部署に所属するメンバーが参加しているのですが、ある時以下のように各部署でデータ分析に関する多種多様な課題、ミッション、想いを持っているという話があがりました。 例えば、サービス開発部署は「ログデータをもっと活用してサービス改善に生かしたい」、お客さまにサービスの提案や受託分析を行う部署は「自社サービスのさらなる理解や分析人材を増やしていきたい」、データ分析人材の育成をミッションにしている部署は「自分たちの専門的な分析ノウハウを社内に普及させていきたい」というような形です。 これに対して、運営内でどうすれば上記のミッションや課題解決を達成できるか議論を重ねました。 その結果、データ分析に挑戦したい人から育成ができる人までさまざまな分析人材を一堂に集め、社内ログデータの分析に取り組んでもらう本合宿のコンセプトが決まりました そこから合宿の企画内容の詳細を詰めていき、複数のサービス担当者の方へログデータ提供を依頼しました。 また参加者を募集するにあたり、部署横断での宿泊を伴う企画は前例があまりなかったため、各部署の責任者の方に対して施策内容と期待される効果の説明を行い、本企画への賛同と参加者募集の協力を依頼しました。 その結果3つのサービス(NeWork、SDPF、Node-AI)の協力が得られ、参加者も集まり、開催に至ることができました。 データ分析開発合宿の流れ 企画は次の3Stepで実施しました。 各チームは分析に取り組む社内のサービスを1つ選びます。(Step1) 各チームは選択した各サービス担当者へ課題をヒアリングします。(Step2) 各チームはサービスの担当者から提供を受けたログデータを集中的に分析し、課題の解決策を提案します。(Step3) 開催の様子 Step1 キックオフ Step1では各チームでの顔合わせや、合宿の概要について説明を実施しました。 オンラインだと初めて会う人同士でお互いの理解や議論が深まりにくいという課題もあります。そこで、初回はオフィスに集合して開催することで、チームの結束を高め、Step1終了以降で各チームが実施するオンラインでのグループワークがスムーズに進むようにプログラムしました。 チームの顔合わせでは、これまでの自分の活動を年表形式で共有する自分史紹介を企画しました。各自が自分史を説明しながらの自己紹介で少しずつ打ち解けて、笑顔が出て盛り上がっている雰囲気が伝わってきました。 また、分析対象となる3サービス(NeWork、SDPF、Node-AI)のデータの提供と、各サービス担当者が持つ課題についての説明を行いました。 各チームはこの後、ログデータの分析を始め、課題を読み解いていきながら、自チームで分析を担当するサービスを1つ決めていきます。 また、折角オフラインで集まったため、Step1終了後は懇親会を開催しました。積極的なコミュニケーションがなされ、お互いへの理解もさらに深まった様子で、対面開催の良さを感じました。 Step2 課題ヒアリング Step2では各サービス担当者の方へのヒアリングを実施してもらいました。 分析対象サービスの担当者に対してデータやサービスの内容についての質問や、課題を深掘るためのヒアリングを実施してもらいました。 ヒアリングはオンライン開催であり、サービス担当者のヒアリング時の手間をなるべく小さくするため、質問表は参加者全体で共有し、同じ質問がでないように工夫しました。また、ヒアリング時の動画を録画し、ヒアリングに参加できない方と参加された方で情報の偏りが発生しないようにしました。 Step3 合宿 Step3では、2泊3日でホテルに篭り、分析と分析結果をもとにどんな施策を提言できるかの議論を進めてもらい、最終日には成果報告会を実施しました。 成果報告会はオンラインとオフラインの融合で開催しました。サービス担当者や社内でデータ分析に興味のある方にもオンラインで参加してもらいました。そして、各チームからログデータの分析結果の報告と、分析をもとに各サービスの課題に対してどのような施策を打つと良いかをサービス担当者へ向けて提案してもらいました。逆にサービス担当者からは提案に対してのフィードバックをもらいました。双方向のコミュニケーションを通じて、各チームには自分たちの分析と提案への自信をつけてもらい、サービス担当者にはデータへのさらなる理解と気づきを得てもらうことが狙いです。 質問やコメントも活発に飛び交い良い相乗効果が得られたと思いました。 データ分析開発合宿で得られた成果 合宿参加者の声を一部抜粋して掲載します。 社内にデータサイエンスに興味のある知り合いが増えて、今後の連携に有効に人脈が活用できそうでその点はとても満足している 実験やコンペのために用意されたデータではなく、プロダクトの実データを用いてデータ分析をする機会がモテたことで実践的なデータ分析のスキルが上がったと感じる また、サービス担当者の声も一部抜粋して掲載します。 データ提供するサービスの主幹として参加させていただきました。主幹で気づいていなかった分析結果・仮説を提示いただき、非常に参考になりました。また発表会で紹介いただいた分析の進め方や仮説の立て方は、今後主幹でデータ活用する際の参考にさせていただきます。 普段開発者として時間的にもスキル的にも実施が難しいようなユーザ利用状況分析をしていただけてありがたかった。 おわりに 今回のデータ分析開発合宿実施によって、社内の部署が抱えていたログデータの分析によるサービス改善と、分析者のスキル向上に関する課題解決に加えて、部門を超えた人材交流にも貢献ができました。 今後も今回のような合宿企画を通して、社内のデータ分析を盛り上げていければと思っています。 (2024/04/04 追記)この記事の続編として、この合宿で実際に行った分析とその結果をまとめています。こちらからご覧ください。 データ分析開発合宿を開催しました~自社サービス改善のためのデータ分析事例紹介~ NTTコミュニケーションズでは現在、冬季インターンを募集しています。 現場受け入れ型インターンシップではAIエンジニア・データサイエンティストのワークフィールドで合計8ポストを用意しております。特にNo.22、No.23のポストは我々「データサイエンスちゃんねる」運営も所属しているチームでの業務を体験できます。当社の活動に興味を持っていただいた方、私たちと一緒に働いてみませんか? ドコモグループ ウィンターインターンシップ2023 ( ※現場受け入れ型インターンシップは締め切り間際のためご注意ください! 募集は終了しました)
こんにちは、イノベーションセンターの加藤です。普段はコンピュータビジョンの技術開発やAI/機械学習(ML: Machine Learning)システムの検証に取り組んでいます。一方で、兼務 1 で大規模言語モデル(LLM: Large Language Model)について調査を行なっており、特にLLMの推論や学習の高速化に関心を持っています。 今回は、小さな言語モデルによる先読みを活用してLLMの文章生成を高速化する手法(Assisted Generation 2 , Speculative Sampling 3 などと呼ばれています)についてご紹介します。 LLMの推論は計算コストが高く、文章生成の遅さが課題としてよく挙げられています。特に日本語はトークンあたりの文字数が少なく、ChatGPTのようなストリーム出力でもかなり生成が遅く感じるかと思います。 これに対して、いくらか余分にメモリを利用して、元々のLLMと全く同じものをより高速に出力できるAssisted Generationが提案されています。AI開発・機械学習のためのプラットフォームを運営する Hugging Face が公開している機械学習ライブラリであるTransformersでも実装されています。この記事ではその手法についてまとめ、より発展的な手法とともにHugging Faceのモデルで実験しました。 LLMの文章生成メカニズム モデルの推論速度とAssisted Generation generate()の高速化 sample()の高速化 トークナイザの互換性 更なる高速化: Token Tree Verification LLMの文章生成メカニズム② Causal Language ModelにおけるAttention Maskについて Token Tree Verificationを用いたgenerate() 元論文の実装 おわりに LLMの文章生成メカニズム 文章生成に使われるLLMの多くはCausal Language Modelで作られています。Causal Language Modelとは単語列(厳密にはトークン列)が与えられた時にのちに続く単語(トークン)を予測するモデルで、与えられたトークン列 に対し、各 の次に来るべきトークン の分布 を出力します。 以下の例では、入力文"The man worked as a"の各トークンに対して、 facebook/opt-125m モデルを用いて最も次に来そうなトークンを予測した結果を図示しています。一度の推論で全トークンが並列に予測できていることや、Causal Language Modelでは後ろの入力トークンが前の予測トークンに影響しないことが今回紹介する技術のポイントです。 これを用いると1回の推論で新しいトークンを1つ(ここではsecurity)生成できるため、何度も繰り返すことで文章を生成します。 これをAutoregressive Generationと呼び、Transformersでは generate() という関数が提供されています。特にこの例のように最も確率の高いものを次のトークンに選択する方法をGreedy Decodingと呼びます。 (結局最終トークンの予測 "security" しか使い道が無いように見えますが、残りのトークンの予測も後述の手法で活用できます。) import torch import transformers from transformers import AutoModelForCausalLM, AutoTokenizer print (torch.__version__) # 2.1.0+cu121 print (transformers.__version__) # 4.34.1 model = AutoModelForCausalLM.from_pretrained( "facebook/opt-125m" ).cuda() tokenizer = AutoTokenizer.from_pretrained( "facebook/opt-125m" , use_fast= False ) prompt = "The man worked as a" input_ids = tokenizer(prompt, return_tensors= "pt" ).input_ids.cuda() print (tokenizer.decode(model.generate(input_ids, max_new_tokens= 10 )[ 0 ], skip_special_tokens= True )) # The man worked as a security guard at a hotel in the city of K また、LLMが出力した確率に沿って出力をサンプリング sample() することで、多様性のある文章を生成することもできます。 print (tokenizer.decode(model.generate(input_ids, max_new_tokens= 10 , do_sample= True )[ 0 ], skip_special_tokens= True )) print (tokenizer.decode(model.generate(input_ids, max_new_tokens= 10 , do_sample= True )[ 0 ], skip_special_tokens= True )) # The man worked as a clerk to a bakery. He worked for a bakery # The man worked as a janitor on a cleaning staff in our house. モデルの推論速度とAssisted Generation 最近公開されているLLMは10億~1000億規模のパラメータを持っており、推論に非常に時間がかかることが知られています。 A100 GPUで facebook/opt モデルを動作させ、ランダムな文章( C4データセット の冒頭部を利用)の続きを推論させた場合は以下の図のようになり、13Bモデルは最軽量の125Mモデルの30倍の生成時間がかかります。13B, 125Mはモデルのパラメータ数を表しており、それぞれ13 billion、125 millionを示しています。 そこで1回の推論で各位置の次トークンを並列に予測できるという性質を利用し、小さなモデルでいくつか「先読み」してからLLMでそれを検証するAssisted Generationという手法で高速に文章を生成できます。以下の節ではその手法を説明します。 generate()の高速化 まず小さなモデル(以降ではドラフトモデルと呼びます)で新しい単語を複数生成します。この時使用するモデルはLLMよりも軽量でかつ同じトークンIDを使っている必要があります。以下の例では1.3Bモデルに対し、同じトークンIDを使っていてより軽量な125Mモデルをドラフトモデルにしています。 from transformers import AutoModelForCausalLM, AutoTokenizer, GenerationConfig import torch assist = AutoModelForCausalLM.from_pretrained( "facebook/opt-125m" ).cuda() model = AutoModelForCausalLM.from_pretrained( "facebook/opt-1.3B" , torch_dtype=torch.float16).cuda() tokenizer = AutoTokenizer.from_pretrained( "facebook/opt-1.3B" , use_fast= False ) prompt = "The man worked as a" input_ids = tokenizer(prompt, return_tensors= "pt" ).input_ids.cuda() initial_len = input_ids.size( 1 ) for i in range ( 10 ): with torch.no_grad(): y = assist(input_ids) next_id = y.logits[:, - 1 , :].argmax(- 1 , keepdims= True ) input_ids = torch.cat([input_ids, next_id], dim=- 1 ) # 入力文章 + [ドラフトモデルが生成した文章] print (prompt + f "[{tokenizer.decode(input_ids[0,initial_len:], skip_special_tokens=True)}]" ) # The man worked as a[ security guard at a hotel in the city of K] 次に生成した文章 "The man worked as a security guard at a hotel..." をLLMに入れ、各位置の次トークンを予測します。 with torch.no_grad(): y = model(input_ids) next_ids = y.logits.argmax(- 1 ) for i in range ( 10 ): input_words = tokenizer.decode(input_ids[ 0 , :initial_len+i], skip_special_tokens= True ) next_words = tokenizer.decode(next_ids[ 0 , initial_len+i- 1 :initial_len+i], skip_special_tokens= True ) print (f "model[{i}]: {input_words}[{next_words}]" ) if next_ids[ 0 , initial_len+i- 1 ] != input_ids[ 0 , initial_len+i]: assist_input = tokenizer.decode(input_ids[ 0 , :initial_len+i], skip_special_tokens= True ) assist_word = tokenizer.decode(input_ids[ 0 , initial_len+i:initial_len+i+ 1 ], skip_special_tokens= True ) print (f "assistant: {assist_input}[{assist_word}]" ) break """ model[0]: The man worked as a[ security] model[1]: The man worked as a security[ guard] model[2]: The man worked as a security guard[ at] model[3]: The man worked as a security guard at[ the] assistant: The man worked as a security guard at[ a] """ LLMの予測トークンが "security guard at" まではドラフトモデルの出力と一致していることがわかります。そこでこの一致した分とその次のLLMの予測 "the" を合わせた "security guard at the" をAssisted Generationの出力として一気に採用してしまいます。 Greedy Decodingの性質上、LLMで初期プロンプトから1つずつトークンを生成しても、初めて予測がずれたこの"the"まで一致することが以下のように確かめられます。 prompt = "The man worked as a" input_ids = tokenizer(prompt, return_tensors= "pt" ).input_ids.cuda() initial_len = input_ids.size( 1 ) for i in range ( 10 ): with torch.no_grad(): model_inputs = model.prepare_inputs_for_generation(input_ids) y = model(**model_inputs) next_id = y.logits[:, - 1 , :].argmax(- 1 , keepdims= True ) input_ids = torch.cat([input_ids, next_id], dim=- 1 ) print (tokenizer.decode(input_ids[ 0 ], skip_special_tokens= True )) # The man worked as a security guard at the University of California, Berkeley, # "The man worked as a security guard at the" が model[3] と一致している つまり1回のLLM推論と10回のドラフトモデル推論で4トークン生成できました。これを繰り返すことで巨大なモデルの推論回数を節約しながらそのモデルの出力を完全に再現できます。これはTransformersでも assistant_model を引数に指定することで利用できます。 facebook/opt のさまざまなパラメータ数のモデルに対し125Mモデル( facebook/opt-125m )を用いてAssisted Generationを行った際の実行時間は以下のようになります。 モデル規模の差が大きければ大きいほどAssisted Generationの恩恵を受けられることが分かります。 sample()の高速化 サンプリングにドラフトモデルを活用する際は、先読みで得られた確率分布を用いて棄却サンプリングを行い、LLMの出力する確率分布を再現します。棄却サンプリングとは、確率分布が非常に複雑でそこからのサンプリングが困難である時に使われる手法で、目的の確率分布 に対してサンプリングしやすい確率分布 を用意して次のように行います。 (前準備) 任意の に対し が成り立つような定数 を用意する。(用意できない場合は棄却サンプリングを使えない。すなわち が定義されている では常に も定義されている必要があり、さらに確率比 は有界である必要がある。) からサンプリングする 一様乱数からのサンプリング ] が を満たせば を からのサンプリング結果として採用、そうでなければ棄却し 2. からやり直す。 これにより から直接サンプリングすることなく、その確率分布に従う を生成できます。この手法の弱点の1つに、用意した があまりに大きいと棄却の割合が増えサンプリングの効率が落ちることが挙げられます。 ただし一般的に使われている棄却サンプリングの前提とは異なり、LLMの確率分布からのサンプリングも先読みが終わる度に計算できるため、次のような工夫がなされています。 入力トークン に対し、ドラフトモデルで 個先までの確率分布 を先読みする 先読みしたトークンを用いてLLMの確率分布 を計算する(一度の推論で可能) に対して、一様乱数 ] が を満たせば採用、そうでなければ棄却する 初めて棄却された のトークンを を正規化した分布からサンプリングする に を加え, 1.に戻る この手法を用いることによって、1ループあたり1単語を必ず生成でき、また棄却サンプリングの仮定である の定義域や確率比の上界などを気にする必要がなくなります。 実装のソースコードはこちら from typing import Dict import torch from transformers import TemperatureLogitsWarper, LogitsProcessorList from transformers.generation.stopping_criteria import StoppingCriteriaList class AssistMixin : def draft ( self, eos_token_id: int , input_ids: torch.LongTensor, max_assistant_tokens: int , do_sample: bool , ) -> torch.LongTensor: draft_ids = input_ids self.cache[ "assistant_prob_list" ] = [] for idx in range (max_assistant_tokens): if "assistant_past_key_values" in self.cache: prev_seq_len = self.cache[ "assistant_past_key_values" ][ 0 ][ 0 ].shape[- 2 ] # `new_token_len` can be 1 or 2 (next token in assistant + last token picked by the larger model) new_token_len = draft_ids.shape[ 1 ] - prev_seq_len assist_inputs = draft_ids[:, -new_token_len:] assist_attn = torch.ones_like(draft_ids) assistant_model_outputs = self.assist_model( assist_inputs, attention_mask=assist_attn, past_key_values=self.cache[ "assistant_past_key_values" ]) else : assistant_model_outputs = self.assist_model(draft_ids) self.cache[ "assistant_past_key_values" ] = assistant_model_outputs.past_key_values assist_new_logits = assistant_model_outputs.logits[:, - 1 , :] assist_new_logits = self.logits_processor(draft_ids, assist_new_logits) assist_new_logits = self.logits_warper(draft_ids, assist_new_logits) if do_sample: assist_new_probs = assist_new_logits.softmax(- 1 ) self.cache[ "assistant_prob_list" ].append(assist_new_probs) new_token = torch.multinomial(assist_new_probs, num_samples= 1 ).squeeze( 1 ) else : new_token = assist_new_logits.argmax(- 1 ) draft_ids = torch.cat((draft_ids, new_token[:, None ]), dim=- 1 ) if new_token[ 0 ] == eos_token_id: break if do_sample: self.cache[ "assistant_prob_list" ] = torch.stack(self.cache[ "assistant_prob_list" ], dim= 1 ) return draft_ids def verify ( self, eos_token_id: int , input_ids: torch.LongTensor, candidate_input_ids: torch.LongTensor, max_len: int , do_sample: bool , ) -> torch.LongTensor: candidate_length = candidate_input_ids.shape[ 1 ] - input_ids.shape[ 1 ] cur_len = input_ids.shape[ 1 ] if "past_key_values" in self.cache: model_attn = torch.ones_like(candidate_input_ids) model_input_ids = candidate_input_ids[:, -candidate_length- 1 :] outputs = self.model( model_input_ids, attention_mask=model_attn, past_key_values=self.cache[ "past_key_values" ], ) else : outputs = self.model(candidate_input_ids) logits = outputs.logits for i in range (candidate_length): logits[:, i, :] = self.logits_processor(candidate_input_ids[:, :cur_len + i], logits[:, i, :]) for i in range (candidate_length): logits[:, i, :] = self.logits_warper(candidate_input_ids[:, :cur_len + i], logits[:, i, :]) speculative_ids = candidate_input_ids[:, -candidate_length:] if do_sample: probs = logits[:, -candidate_length- 1 :, :].float().softmax(- 1 ) speculative_probs = self.cache[ "assistant_prob_list" ].gather(dim=- 1 , index=speculative_ids[:,:, None ]).squeeze(- 1 ) speculative_actual_probs = probs[:, :- 1 , :].gather(dim=- 1 , index=speculative_ids[:,:, None ]).squeeze(- 1 ) resample_probs = probs.clone() resample_probs[:, :- 1 , :] = torch.clamp(resample_probs[:, :- 1 , :] - self.cache[ "assistant_prob_list" ].float(), min = 0 ) resample_probs /= resample_probs.sum(- 1 , keepdim= True ) acceptance_thresholds = speculative_actual_probs / speculative_probs unif = torch.rand_like(acceptance_thresholds) n_matches = ((~(unif <= acceptance_thresholds)).cumsum(dim=- 1 ) < 1 ).sum() else : selected_tokens = logits[:, -candidate_length- 1 :, :].argmax(- 1 ) n_matches = ((~(speculative_ids == selected_tokens[:,:- 1 ])).cumsum(dim=- 1 ) < 1 ).sum().cpu().item() n_matches = min (max_len - cur_len, n_matches) self.cache[ "matches" ].append(n_matches) self.cache[ "past_key_values" ] = outputs.past_key_values input_ids = torch.cat((input_ids, speculative_ids[:, :n_matches]), dim=- 1 ) if input_ids[ 0 , - 1 ] == eos_token_id or input_ids.shape[ 1 ] == max_len: # if EOS or max_len, STOP return input_ids # add one more token if do_sample: return torch.cat((input_ids, torch.multinomial(resample_probs[:, n_matches, :], num_samples= 1 )), dim=- 1 ) else : return torch.cat((input_ids, selected_tokens[:, n_matches:n_matches+ 1 ]), dim=- 1 ) def crop_cache (self, assist_input_ids, large_input_ids): # Discard past key values relative to unused assistant tokens self.cache[ "past_key_values" ] = tuple ([( kv[ 0 ][:, :, :large_input_ids.shape[ 1 ]- 1 , :], kv[ 1 ][:, :, :large_input_ids.shape[ 1 ]- 1 , :], ) for kv in self.cache[ "past_key_values" ]]) self.cache[ "assistant_past_key_values" ] = tuple ([( kv[ 0 ][:, :, :assist_input_ids.shape[ 1 ]- 1 , :], kv[ 1 ][:, :, :assist_input_ids.shape[ 1 ]- 1 , :], ) for kv in self.cache[ "assistant_past_key_values" ]]) class SpecSampler (AssistMixin): def __init__ (self, tokenizer, large_model, assist_model): self.tokenizer = tokenizer self.model = large_model self.assist_model = assist_model @torch.no_grad() def generate (self, input_ids: torch.LongTensor, max_new_len: int , temperature: float ): max_len = input_ids.shape[ 1 ] + max_new_len self.cache = {} self.cache[ "matches" ] = [] self.max_assistant_tokens = 5 self.logits_processor = LogitsProcessorList() self.logits_warper = LogitsProcessorList([TemperatureLogitsWarper(temperature)]) while True : draft_ids = self.draft(self.tokenizer.eos_token_id, input_ids, max_assistant_tokens=self.max_assistant_tokens, do_sample= True ) new_input_ids = self.verify(self.tokenizer.eos_token_id, input_ids, draft_ids, max_len=max_len, do_sample= True ) n_matches = new_input_ids.shape[ 1 ] - input_ids.shape[ 1 ] - 1 if n_matches == self.max_assistant_tokens: self.max_assistant_tokens += 2 else : self.max_assistant_tokens = max ( 1 , self.max_assistant_tokens - 1 ) input_ids = new_input_ids self.crop_cache(input_ids[:, :- 1 ], input_ids) if input_ids.shape[ 1 ] >= max_len or input_ids[ 0 , - 1 ] == self.tokenizer.eos_token_id: break return input_ids こちらもTransformersでは assistant_model を引数に指定することで利用できますが、バージョン4.34.1時点では若干効率が悪い実装になっています。 というのもTransformers実装では先読みの確率分布のSoftmax温度を常に0にしているのと等価なものになっており、LLMの出力する確率分布からかなり離れてしまっています。これを上で挙げたソースコードのようにLLM側で利用する温度と同一のものを利用するように実装し直すと、以下の図のようにほとんどの温度パラメータで効率化できます。特に高い温度においても、Transformers実装ではドラフトモデルなしでの生成よりも遅くなっているのに対し、私の実装では速くなっていることがわかります。 assistは独自実装、assist(hf)はTransformers実装、6.7B(float16)はドラフトモデル無しの速度、125mはドラフトモデルのみで生成した時の速度 トークナイザの互換性 トークナイザ(Tokenizer)は入力文章を言語モデルが扱えるようにトークンIDの列に変換するモジュールであり、モデルによってしばしば異なるトークナイザが使われています。 しかしAssisted Generationを使うにあたり、LLMとドラフトモデルのトークナイザは同じものを使う必要があります。これは内部ではトークンIDを用いてモデル間をやり取りしており、IDが共通であればトークン列をそのまま渡せて効率が良いためです。これに対し、軽量版モデルが存在しないなどでどうしても異なるトークナイザを使いたい場合は2つのトークナイザでトークン列を相互に変換することでAssisted Generationを正しく動かすことができます。ただしあまり高速化は期待できないかもしれません。以下の例ではllm-jp-13Bとopen-calm-small (160Mパラメータ)を用いて生成していますが、生成速度にあまり差が生まれませんでした。 実装のソースコードはこちら import torch import numpy as np import transformers from transformers import AutoModelForCausalLM, AutoTokenizer, GenerationConfig from transformers import TemperatureLogitsWarper, LogitsProcessorList import time class JpCALM (AssistMixin): def __init__ (self, large_tokenizer, assist_tokenizer, large_model, assist_model): self.large_tokenizer = large_tokenizer self.assist_tokenizer = assist_tokenizer self.model = large_model self.assist_model = assist_model def generate (self, text: str , max_len: int ): assist_input_ids = self.assist_tokenizer.encode(text, add_special_tokens= False , return_tensors= "pt" ).to(self.assist_model.device) large_input_ids = self.large_tokenizer.encode(text, add_special_tokens= False , return_tensors= "pt" ).to(self.model.device) self.cache = {} self.cache[ "matches" ] = [] self.logits_processor = LogitsProcessorList() self.logits_warper = LogitsProcessorList() while True : # 5つ先読み assist_draft_ids = self.draft(self.assist_tokenizer.eos_token_id, assist_input_ids, max_assistant_tokens= 5 , do_sample= False ) # 先読みしたassistantのtokenを変換 candidate_words = self.assist_tokenizer.decode(assist_draft_ids[ 0 , assist_input_ids.shape[ 1 ]:], skip_special_tokens= True ) large_candidate_ids = self.large_tokenizer.encode(candidate_words, add_special_tokens= False , return_tensors= "pt" ).to(self.model.device)[:, 1 :] large_draft_ids = torch.cat((large_input_ids, large_candidate_ids), dim= 1 ) # 検証 large_next_input_ids = self.verify(self.large_tokenizer.eos_token_id, large_input_ids, large_draft_ids, max_len, do_sample= False ) # attentionのキャッシュを整理 self.crop_cache(assist_input_ids, large_next_input_ids) # 検証したLLMのtokenを変換 selected_tokens = large_next_input_ids[:, large_input_ids.shape[ 1 ]:] large_input_ids = large_next_input_ids large_input_words = self.large_tokenizer.decode(large_input_ids[ 0 ], skip_special_tokens= True ) valid_words = self.large_tokenizer.decode(selected_tokens[ 0 ], skip_special_tokens= True ) assist_valid_ids = self.assist_tokenizer.encode(valid_words, add_special_tokens= False , return_tensors= "pt" ).to(self.assist_model.device) assist_input_ids = torch.cat((assist_input_ids, assist_valid_ids.long()), dim=- 1 ) if large_input_ids.shape[ 1 ] >= max_len or large_input_ids[ 0 , - 1 ] == self.large_tokenizer.eos_token_id: break return large_input_words large_tokenizer = AutoTokenizer.from_pretrained( "llm-jp/llm-jp-13b-v1.0" ) assist_tokenizer = AutoTokenizer.from_pretrained( "cyberagent/open-calm-small" ) large_model = AutoModelForCausalLM.from_pretrained( "llm-jp/llm-jp-13b-v1.0" , device_map= "auto" , torch_dtype=torch.float16, load_in_8bit= True ) assist_model = AutoModelForCausalLM.from_pretrained( "cyberagent/open-calm-small" , device_map= "auto" , torch_dtype=torch.float16) assisted_jp = JpCALM(large_tokenizer, assist_tokenizer, large_model, assist_model) print ( "=========assisted===========" ) tic = time.perf_counter() with torch.no_grad(): out1 = assisted_jp.generate( "自然言語処理とは何か" , 128 ) tac = time.perf_counter() print (out1) print (tac - tic, "sec" ) matches = np.array(assisted_jp.cache[ "matches" ]) print ( "generated tokens per cycle:" , matches.mean() + 1 ) print ( "acceptance rate:" , (matches > 0 ).sum() / len (matches)) print ( "=========baseline===========" ) tic = time.perf_counter() with torch.no_grad(): tokenized_input = assisted_jp.large_tokenizer.encode( "自然言語処理とは何か" , add_special_tokens= False , return_tensors= "pt" ).to(assisted_jp.model.device) output = assisted_jp.model.generate( tokenized_input, max_length= 128 , )[ 0 ] out2 = assisted_jp.large_tokenizer.decode(output) tac = time.perf_counter() print (out2) print (tac - tic, "sec" ) assert out1 == out2 """ =========assisted=========== 自然言語処理とは何か (岩波新書) | 西垣 通 |本 | 通販 | AmazonKindleストアでは、 自然言語処理とは何か (岩波新書)を、Kindle無料アプリまたはKindle電子書籍リーダーで今すぐお読みいただけます。Kindle電子書籍リーダーの 詳細はこちら自然言語処理とは何か (岩波新書) がカートに入りました自然言語処理とは何か (岩波新書) 新書 – 2016/11/21¥ 886 ¥ 13.10530449775979 sec generated tokens per cycle: 1.7910447761194028 acceptance rate: 0.23880597014925373 =========baseline=========== 自然言語処理とは何か (岩波新書) | 西垣 通 |本 | 通販 | AmazonKindleストアでは、 自然言語処理とは何か (岩波新書)を、Kindle無料アプリまたはKindle電子書籍リーダーで今すぐお読みいただけます。Kindle電子書籍リーダーの 詳細はこちら自然言語処理とは何か (岩波新書) がカートに入りました自然言語処理とは何か (岩波新書) 新書 – 2016/11/21¥ 886 ¥ 14.313117458950728 sec """ 更なる高速化: Token Tree Verification Assisted Generationの速度は先読みがどれだけ当たるかにかかっています。しかし連続して当てられる確率は指数関数的に減少していくため、ドラフトモデルがLLMの出力分布をうまく再現しかなりの精度で先読みを当てないと生成速度が伸び悩んでしまいます。例えば前節で挙げたllm-jp-13Bとopen-calm-smallの組み合わせでは平均で1.79個しか生成できていませんでした。これに対し、ドラフトモデルを変えずに先読みの正解率を向上させる工夫としてToken Tree Verification 4 という手法を活用できます。 LLMの文章生成メカニズム② Causal Language ModelにおけるAttention Maskについて 文章生成に使われているCausal Language Modelでは後ろの入力トークンが前の予測トークンに影響を与えないという話がありました。これはTransformerモデル内でトークン同士が影響し合うSelf-Attention部分にマスクを施すことで実現しています。 このマスクを改造することでより複雑な制約を課すことができます。 例えば "The quick brown fox jumps over" と "The quick brown fox runs around" を同時にLLMに入力したい場合、 "The quick brown fox jumps over runs around" と1行にまとめたのち、"jumps"と"runs", "over"と"around"などといったトークン間のattentionをマスクし取り除くことで、それぞれの文章を独立に推論した時と同じ結果を得ることができます。この手法は、前方で一致しているトークン列が長ければ長いほど、複数文をバッチでまとめるよりメモリ量や計算量的な面で有利になります。 これを一般化すると、分岐した先読みトークン木を1回のLLM推論で検証することができます。 元論文 では複数のドラフトモデルからそれぞれ先読みを生成し、それらを1つのトークン木に集約していましたが、今回は1つのドラフトモデルから複数の先読みを生成してみます。 Token Tree Verificationを用いたgenerate() facebook/opt モデルの例に戻って、先読みがどれくらい当たっているのかを可視化してみます。6.7B, 13Bに対して125Mのモデルをドラフトモデルとして利用し、LLMが出力したトークンがドラフトモデルにおいて何番目までの候補に入っていたかを以下の図に示しました。 これまでの手法ではドラフトモデルが採用するのは一番確率の高いトークン、すなわちtop-1のトークンなので約70%の割合で先読みに成功していることがわかります。さらにtop-2まで採用したとすると正解率は80%に上昇します。先読みに複数選択肢を用意することには効果がありそうです。 ではどのように選択肢を用意すれば良いでしょうか。あまり当たらなそうな先読みトークンに対しては、そのさらに先を読むことによる利益は少なそうです。そこでドラフトモデルの出力確率をそのまま先読みが当たる確率と見做してしまい、先読みが当たる数の期待値が最大になるように木を生成します。 実装のソースコードはこちら from dataclasses import dataclass, field import heapq from typing import Dict, List import torch import torch.nn.functional as F from transformers.generation.logits_process import LogitsProcessorList from transformers.generation.stopping_criteria import StoppingCriteriaList @ dataclass (order= True ) class Node : nll: float # 確率のnegative logが小さい順で幅優先探索を行う gain: int tokens: torch.LongTensor = field(compare= False ) attention_mask: torch.LongTensor = field(compare= False ) all_draft_tokens: torch.LongTensor = field(compare= False ) class AssistTreeMixin : def draft ( self, eos_token_id: int , input_ids: torch.LongTensor, max_assistant_tokens: int , ) -> torch.LongTensor: self.cache[ "assistant_prob_list" ] = [] seq_len = input_ids.shape[ 1 ] max_len = seq_len + max_assistant_tokens pq = [] device = self.assist_model.device heapq.heappush(pq, Node( 0 , 0 , torch.LongTensor([]).to(device), torch.ones_like(input_ids), torch.LongTensor([]).to(device))) draft_ids = input_ids draft_masks = [] draft_nodes = [] for idx in range (max_assistant_tokens+ 1 ): top = heapq.heappop(pq) if len (top.tokens) > 0 : draft_ids = torch.cat((draft_ids, top.tokens[:, None ]), dim=- 1 ) draft_len = draft_ids.shape[ 1 ] attention_mask = F.pad(top.attention_mask, ( 0 , draft_len - top.attention_mask.shape[ 1 ])) attention_mask[:, - 1 ] = 1 if idx > 0 : # トークン木に採用 draft_masks.append(F.pad(attention_mask, ( 0 , max_len - attention_mask.shape[ 1 ]))) draft_nodes.append(top) if "assistant_past_key_values" in self.cache: prev_seq_len = self.cache[ "assistant_past_key_values" ][ 0 ][ 0 ].shape[- 2 ] new_token_len = draft_ids.shape[ 1 ] - prev_seq_len assist_inputs = draft_ids[:, -new_token_len:] assistant_model_outputs = self.assist_model( assist_inputs, attention_mask=attention_mask, past_key_values=self.cache[ "assistant_past_key_values" ]) else : assistant_model_outputs = self.assist_model(draft_ids, attention_mask=attention_mask) self.cache[ "assistant_past_key_values" ] = assistant_model_outputs.past_key_values assist_new_logits = assistant_model_outputs.logits[:, - 1 , :] # (batch, vocab) assist_new_logits = self.logits_processor(draft_ids, assist_new_logits) assist_new_logits = self.logits_warper(draft_ids, assist_new_logits) assist_new_logprobs = F.log_softmax(assist_new_logits, dim=- 1 ) # (batch, vocab) # 計算量節約のために探索数を5つに制限 assist_new_topk = torch.topk(assist_new_logprobs, k= 5 , dim=- 1 ) # (batch, k) for k in range ( 5 ): new_token = assist_new_topk.indices[:, k] new_nll = -assist_new_topk.values[ 0 , k] if new_token != eos_token_id: heapq.heappush(pq, Node(top.nll + new_nll, top.gain+ 1 , new_token, attention_mask, torch.cat((top.all_draft_tokens, new_token[:])))) return draft_ids, torch.cat(draft_masks, dim= 0 ), draft_nodes def verify ( self, eos_token_id: int , input_ids: torch.LongTensor, candidate_input_ids: torch.LongTensor, draft_masks: torch.LongTensor, draft_nodes: List[Node], max_len: int , ) -> torch.LongTensor: candidate_length = candidate_input_ids.shape[ 1 ] - input_ids.shape[ 1 ] tgt_len = candidate_input_ids.shape[ 1 ] def make_tree_mask (_attention_mask, _input_shape, inputs_embeds, past_key_values_length): # Causal Maskを上書きする tree_mask = torch.tril(torch.ones(tgt_len, tgt_len)) tree_mask[-candidate_length:, -candidate_length:] = draft_masks[:, input_ids.shape[ 1 ]:] tree_mask = torch.full((tgt_len, tgt_len), torch.finfo(inputs_embeds.dtype).min).masked_fill(tree_mask > 0 , 0 ) if past_key_values_length > 0 : tree_mask = torch.cat((torch.zeros(tgt_len-past_key_values_length, past_key_values_length), tree_mask[past_key_values_length:, past_key_values_length:]), dim=- 1 ) return tree_mask[ None , None ].to(inputs_embeds.dtype).to(inputs_embeds.device) self.model.model.decoder._prepare_decoder_attention_mask = make_tree_mask cur_len = input_ids.shape[ 1 ] if "past_key_values" in self.cache: prev_seq_len = self.cache[ "past_key_values" ][ 0 ][ 0 ].shape[- 2 ] new_token_len = candidate_input_ids.shape[ 1 ] - prev_seq_len model_attn = torch.ones_like(candidate_input_ids) model_input_ids = candidate_input_ids[:, -new_token_len:] outputs = self.model( model_input_ids, attention_mask=model_attn, past_key_values=self.cache[ "past_key_values" ], ) else : outputs = self.model(candidate_input_ids) logits = outputs.logits for i in range (candidate_length): logits[:, i, :] = self.logits_processor(candidate_input_ids[:, :cur_len + i], logits[:, i, :]) for i in range (candidate_length): logits[:, i, :] = self.logits_warper(candidate_input_ids[:, :cur_len + i], logits[:, i, :]) speculative_ids = candidate_input_ids[:, -candidate_length:] selected_tokens = logits[:, -candidate_length- 1 :, :].argmax(- 1 ) best_sele = torch.LongTensor([]).to(input_ids.device) best_draft_mask = torch.cat((torch.ones(input_ids.shape[ 1 ]), torch.zeros(candidate_length))) n_matches = - 1 longest_tokens = 0 for i, node in enumerate (draft_nodes): selected_tokens_i = torch.cat((selected_tokens[ 0 , 0 : 1 ], selected_tokens[ 0 , 1 :][draft_masks[i,-candidate_length:]> 0 ])) streak = (~(node.all_draft_tokens == selected_tokens_i[:- 1 ])).cumsum( 0 ) < 1 n_matches_i = streak.sum().cpu().item() longest_tokens = max (longest_tokens, len (node.all_draft_tokens)) if n_matches_i > n_matches: n_matches = n_matches_i best_sele = selected_tokens_i best_draft_mask = draft_masks[i] self.cache[ "best" ] = longest_tokens == n_matches self.cache[ "mask_to_cache" ] = best_draft_mask > 0 n_matches = min (max_len - cur_len, n_matches) self.cache[ "matches" ].append(n_matches) self.cache[ "past_key_values" ] = outputs.past_key_values verified = torch.cat((input_ids, best_sele[ None , :n_matches]), dim=- 1 ) if verified[ 0 , - 1 ] == eos_token_id or verified.shape[ 1 ] == max_len: return verified # add one more token verified = torch.cat((verified, best_sele[ None , n_matches:n_matches+ 1 ]), dim=- 1 ) return verified def crop_cache (self, input_ids): # Discard past key values relative to unused assistant tokens mask = self.cache[ "mask_to_cache" ] length = input_ids.shape[ 1 ] - 2 self.cache[ "past_key_values" ] = tuple ([( kv[ 0 ][:, :, mask, :][:,:,:length,:], kv[ 1 ][:, :, mask, :][:,:,:length,:], ) for kv in self.cache[ "past_key_values" ]]) self.cache[ "assistant_past_key_values" ] = tuple ([( kv[ 0 ][:, :, mask, :][:,:,:length,:], kv[ 1 ][:, :, mask, :][:,:,:length,:], ) for kv in self.cache[ "assistant_past_key_values" ]]) class SpecDecoder (AssistTreeMixin): def __init__ (self, tokenizer, large_model, assist_model): self.tokenizer = tokenizer self.model = large_model self.assist_model = assist_model @torch.no_grad() def generate (self, input_ids: torch.LongTensor, max_new_len: int , only_draft= False ): max_len = input_ids.shape[ 1 ] + max_new_len self.cache = {} self.cache[ "matches" ] = [] self.cache[ "first_assistant_prob" ] = [] self.cache[ "verified" ] = [] self.max_assistant_tokens = 5 while True : draft_ids, draft_masks, draft_nodes = self.draft(self.tokenizer.eos_token_id, input_ids, max_assistant_tokens=self.max_assistant_tokens) self.cache[ "draft" ] = (draft_ids, draft_masks, draft_nodes) if only_draft: break new_input_ids = self.verify(self.tokenizer.eos_token_id, input_ids, draft_ids, draft_masks, draft_nodes, max_len=max_len) n_matches = new_input_ids.shape[ 1 ] - input_ids.shape[ 1 ] - 1 if self.cache[ "best" ]: self.max_assistant_tokens += 2 else : self.max_assistant_tokens = max ( 1 , self.max_assistant_tokens - 1 ) self.crop_cache(new_input_ids) input_ids = new_input_ids if input_ids.shape[ 1 ] >= max_len or input_ids[ 0 , - 1 ] == self.tokenizer.eos_token_id: break return input_ids facebook/opt-125m をドラフトモデルとして、"The man worked as a"の続きを5つ先読みすると次のようになりました。 矢印の中身は遷移確率です。"worked as a"の次の単語は自信がないものの、"security"と来たら"guard", "truck"と来たら"driver"というのはそれなりに自信がありそうです。 このように、"security guard"と先読みするだけではこころもとない時に"truck driver"という先読みも含めることができるというのがこのトークン木を活用する利点です。 これを用いてAssisted Generationがどれだけ速くなるか実験しました。 ...残念ながら速くはなりませんでした。トークン木の生成アルゴリズムや先読み数などのチューニングが必要そうです。 元論文の実装 元論文 では複数のドラフトモデルを使って先読みをすることを想定しており、複数のGPUにドラフトモデルを分散させるなどの効率化手法についても触れています。それに加えて、この章ではGreedy Decodingにしか触れませんでしたが、サンプリングを行った際の速度についても実験されています。また、公式実装は FlexFlow で利用できます。 おわりに 本記事では、Assisted GenerationというLLMの推論高速化手法についてご紹介しました。 NTT Com では、大規模言語モデルおよび生成AIを活用したプロダクト・ソリューション開発、社内DXに挑戦するソフトウェアエンジニアを募集しています!詳細は以下のリンクをご覧ください。 hrmos.co イノベーションセンターでは、本人の意志に応じて複数のプロジェクトへ参画できる兼務制度が用意されています。詳しくは イノベーションセンター テクノロジー部門 紹介デッキ をご覧ください。 ↩ https://huggingface.co/blog/assisted-generation ↩ https://arxiv.org/abs/2302.01318 ↩ https://arxiv.org/abs/2305.09781v2 ↩
サマリ 概要 検証 1. SR OS での PCC 設定と PCEP セッション確立 2. SR OS での LSP テンプレートの作成 3. Pola PCE でのパス設定 4. SR OS でパス確認と疎通確認 まとめ サマリ PCEP を用いた 外部 PCE から SR OS へのパス設定に成功 この記事は Multi-AS Segment Routing 検証連載の第 19 回です。過去の記事一覧は こちら にあります。 概要 イノベーションセンターの田島です。本連載のような Segment Routing 関連の技術検証や、自動化による高度な運用を開発しています。 本記事では SR OS を Path Computation Client (PCC) として設定し、転送経路を示すパス (Label Switched Path; LSP) を外部から設定できるか検証します。 パス設定には標準プロトコルである Path Computation Element Communication Protocol (PCEP) を用いて、複数種類の Path Computation Element (PCE) が利用可能なことを確かめます。 ルーター外部からパスを設定する目的や、 PCEP に関する PCE や PCC の動作概要などの前提知識は、過去の 第 10 回の記事 に詳細がありますのでご参照ください。 過去に複数の PCE を検証した 第 11 回の記事 と同様に L3VPN の経路制御を検証します。 ただし、SR OS では Color を指定したパスの設定ができないため、 本記事では Color ごとのパス選択ではなく PE 単位でのパス設定を行います。 2023 年 11 月現在の最新 SR OS である 23.10 でも Color 指定は未対応のようです。 検証 本記事での検証は PE 間の転送経路を PCE から設定し、VPN 通信がその経路に従って転送されることを確認します。 PCE は IOS XR SR-PCE 等も利用可能ですが、今回は我々で開発している Pola PCE を使用します。なお詳細は割愛しますが IOS XR SR-PCE でも本記事と同等の機能検証が確認されました。 次の図のような検証トポロジーで実施します。 用いたコンポーネントのバージョンは下記の通りです。 SR OS: 22.7.R1 Pola PCE: 1.2.1 L3VPN の設定は 第 12 回の記事 で既出のため、設定済みとします。 Pola PCE の導入や起動に関しては Pola PCE のレポジトリ中の Getting Started with Pola PCE が参考になります。 検証は次の手順で進めます。 SR OS での PCC 設定と PCEP セッション確立 SR OS での LSP テンプレートの作成 Pola PCE でのパス設定 SR OS でパス確認と疎通確認 1. SR OS での PCC 設定と PCEP セッション確立 rt01 (SR OS) と Pola PCE の間で PCEP セッションを確立させます。 Pola PCE は下記の設定で起動済みとします。 user@pola:~$ cat /etc/polad/polad.yaml global: pcep: address: "10.0.255.253" port: 4189 grpc-server: address: "127.0.0.1" port: 50052 log: path: "/var/log/pola/" name: "polad.log" ted: enable: false rt01 では下記の設定を入れ、 PCE とのセッションを有効にします。 [ro:/configure] A:admin@rt01# /info router pcep pcc { admin-state enable local-address 10.255.0.1 peer 10.0.255.253 { admin-state enable } } PCEP セッションが確立したことを確認します。 Pola PCE 側 user@pola:~$ pola session --port=50052 sessionAddr(0): 10.255.0.1 rt01 (SR OS) 側 [ro:/configure] A:admin@rt01# /show router pcep pcc detail =============================================================================== Path Computation Element Protocol (PCEP) Path Computation Client (PCC) Info =============================================================================== Admin Status : Up Oper Status : Up Unknown Msg Limit : 10 msg/min Keepalive Interval : 30 seconds DeadTimer Interval : 120 seconds Capabilities List : stateful-delegate stateful-pce segment-rt-path rsvp- path pce-initiated-lsp p2mp p2mp-delegate p2mp- initiate association multipath Address : 10.255.0.1 Address Ipv6 : (Unspecified) Report Path Constraints: True Redelegation Interval : 90 seconds State Interval : 180 seconds State Timer Action : remove Max SR-TE PCE Init Lsps: 8191 Open Wait Timer : 60 seconds Keep Wait Timer : 60 seconds Sync Timer : 60 seconds Request Timer : 120 seconds Connection Timer : 60 seconds Allow Negotiations : False Max Sessions : 1 Max Unknown Req : 1000 =============================================================================== これで Pola PCE と rt01 の間でパスの情報を送受信できるようになりました。 2. SR OS での LSP テンプレートの作成 SR OS では PCEP 経由で受け取った LSP を SR-TE の LSP として扱います。 機能の有効化には pce-init-lsp sr-te フラグを設定します。 その上で PCEP にて受け取った LSP をインスタンス化するために lsp-template を用意します。 設定をまとめると次の通りです。 [gl:/configure] A:admin@rt01# /info router mpls admin-state enable path "pce-init" { admin-state enable } lsp-template "pce-init-template" { admin-state enable type p2p-sr-te-pce-init default-path "pce-init" pce-report true template-id default max-sr-labels { additional-frr-labels 2 } } pce-init-lsp { sr-te { admin-state enable } } これでパス設定の準備ができました。 3. Pola PCE でのパス設定 Pola PCE でパス定義を読み込み、 rt01 へ送信します。 パスの定義は下記の通りです。 user@pola:~$ cat policy.yaml srPolicy: name: PE1-PE3 pcepSessionAddr: 10.255.0.1 srcAddr: 10.255.0.1 dstAddr: 10.255.0.3 color: 100 segmentList: - sid: 16002 nai: 10.255.0.2 - sid: 16003 nai: 10.255.0.3 pola sr-policy add コマンドを利用し policy を追加することで上記のパスが送信されます。 user@pola:~$ pola sr-policy add -f policy.yaml --no-link-state --port 50052 success! Pola PCE 側で設定済みのパスがあることを確認できます。 こちらは PCC 側が受領した応答なので、 PCC 側で反映された情報が表示されます。 ここで前述の通り SR OS で Color は無視され 0 となっていることが確認できます。 user@pola:~$ pola sr-policy list --port 50052 Session: 10.255.0.1 PolicyName: PE1-PE3 SrcAddr: 10.255.0.1 DstAddr: 10.255.0.3 Color: 0 Preference: 0 SegmentList: 16002 -> 16003 4. SR OS でパス確認と疎通確認 rt01 では Pola PCE から受信したパスの情報を確認し、それが使用されているか確かめます。 まず SR-TE の LSP として途中経路とともに登録されているかを確認します。 送信元ルーターと、送信先ルーター、途中の経路が確認できます。 [gl:/configure router "Base" mpls] A:admin@rt01# /show router mpls sr-te-lsp =============================================================================== MPLS SR-TE LSPs (Originating) =============================================================================== LSP Name Tun Protect Adm Opr To Id Path ------------------------------------------------------------------------------- PE1-PE3 16390 N/A Up Up 10.255.0.3 ------------------------------------------------------------------------------- LSPs : 1 =============================================================================== [ro:/configure] A:admin@rt01# /show router mpls sr-te-lsp path "PE1-PE3" detail =============================================================================== MPLS SR-TE LSP PE1-PE3 Path (Detail) =============================================================================== Legend : S - Strict L - Loose A-SID - Adjacency SID N-SID - Node SID + - Inherited =============================================================================== ------------------------------------------------------------------------------- LSP SR-TE PE1-PE3 Path pce-init ------------------------------------------------------------------------------- LSP Name : PE1-PE3 Path LSP ID : 55808 From : 10.255.0.1 To : 10.255.0.3 Admin State : Up Oper State : Up Path Name : pce-init Path Type : Primary Path Admin : Up Path Oper : Up Path Up Time : 0d 00:52:54 Path Down Time : 0d 00:00:00 Retry Limit : 0 Retry Timer : 30 sec Retry Attempt : 0 Next Retry In : 0 sec PathCompMethod : pce OperPathCompMethod: pce MetricType : N/A Oper MetricType : N/A LocalSrProt : preferred Oper LocalSrProt : preferred LabelStackRed : Disabled Oper LabelStackRed: Disabled Bandwidth : No Reservation Oper Bandwidth : 0 Mbps Hop Limit : 255 Oper HopLimit : 255 Setup Priority : 0 Oper SetupPriority: 0 Hold Priority : 0 Oper HoldPriority : 0 Inter-area : N/A PCE Updt ID : 1 PCE Updt State : Success PCE Upd Fail Code: noError PCE Report : Enabled Oper PCE Report : Enabled PCE Control : Enabled Oper PCE Control : Enabled Include Groups : Oper IncludeGroups: None None Exclude Groups : Oper ExcludeGroups: None None Last Resignal : n/a IGP/TE Metric : N/A Oper Metric : 16777215 Oper MTU : 9186 Path Trans : 1 Degraded : False Failure Code : noError Failure Node : n/a Explicit Hops : No Hops Specified Actual Hops : n/a Record Label : 16002 -> n/a Record Label : 16003 BFD Configuration and State Template : None Ping Interval : N/A Enable : False State : notApplicable ReturnPathLabel : None WaitForUpTimer : 4 sec OperWaitForUpTimer: 0 sec WaitForUpTmLeft : 0 StartFail Rsn : N/A =============================================================================== 次にこの SR-TE LSP が SR OS のトンネルとしても反映されていることを確認します。 rt03 である 10.255.0.3 向け経路で有効になっています。 [ro:/configure] A:admin@rt01# /show router fp-tunnel-table 1 =============================================================================== IPv4 Tunnel Table Display Legend: label stack is ordered from bottom-most to top-most B - FRR Backup =============================================================================== Destination Protocol Tunnel-ID Lbl/SID NextHop Intf/Tunnel Lbl/SID (backup) NextHop (backup) ------------------------------------------------------------------------------- 10.0.1.2/32 SR 524290 3 10.0.1.2 1/1/c1/1:0 10.0.2.2/32 SR 524289 3 10.0.2.2 1/1/c2/1:0 10.255.0.2/32 SR-ISIS-0 524291 3 10.0.1.2 1/1/c1/1:0 10.255.0.3/32 SR-ISIS-0 524292 3 10.0.2.2 1/1/c2/1:0 10.255.0.3/32 SR-TE 671751 16003 10.255.0.2 SR ------------------------------------------------------------------------------- Total Entries : 5 ------------------------------------------------------------------------------- =============================================================================== 最後に VPN の経路を確認することで、今回設定した LSP で指定されている経路を通って通信できていることが確認できます。 [ro:/configure] A:admin@rt01# traceroute 192.168.1.254 router-instance "100" traceroute to 192.168.1.254, 30 hops max, 40 byte packets 1 10.0.1.2 (10.0.1.2) 2.59 ms 5.80 ms 2.03 ms 2 10.0.3.1 (10.0.3.1) 3.10 ms 2.78 ms 8.03 ms まとめ 本記事では、SR OS を PCC として使用する場合の PCEP によるパス設定の検証結果を紹介しました。 Color に対応していないため制御できる粒度は大きいですが、各 PCE でのパス設定が可能でした。 (2024/02/29 追記) 新しい記事を公開しました: [Multi-AS Segment Routing 検証連載 #20] Multi-AS の SR-MPLS + VPNv4 環境における AS 間での TE
はじめに こんにちは、SDPFクラウドでSDN開発を担当している梶浦( @ykajiaaaaa )です。 今回の記事は今夏のインターンシップで私のチームに来ていただいた伊藤さんによるものです。 このインターンシップでは我々が実際に昔出会った問題をベースにトラブルシューティングを行い、その体験記を執筆いただきました。 それではどうぞよろしくお願いします。 目次 はじめに 目次 参加したインターンシップの紹介 配属されたチームについて インターンシップで取り組んだこと 概要 問題の切り分け 現状把握 原因箇所の更なる切り分け 問題の修正 デバッグ方法 ハッシュテーブル エントリの削除 原因の特定 もう1つの問題 トラブルシューティングのまとめ ライブパッチ インターンシップの感想 メンターからのコメント さいごに 参加したインターンシップの紹介 こんにちは、インターンシップ生の 伊藤吉彦 です。普段は研究室でネットワークの構築・運用をしたり、WIDEプロジェクトの vSIX でSDNコントローラを作ったりしています。 2023年8月28日から9月8日の2週間、NTTコミュニケーションズのインターンシップに参加させていただきました。 本インターンシップでは「 エンタープライズ向け大規模クラウドサービスを支えるネットワーク開発 」というテーマで業務に参加しました。本記事ではその体験談を記載します。 配属されたチームについて NTTコミュニケーションズでは、SDPF (Smart Data Platform)というプロダクトの一部であるSDPFクラウドで、IaaSをエンタープライズ向けに提供しています。 このサービスではオンプレのネットワークをそのままクラウドに載せることができ、仮想L2ネットワークの構築やマルチキャストなどに対応しています。 今回、このSDPFクラウドの裏で動作するSDNコントローラのチームでインターンを行いました。 インターンシップで取り組んだこと 概要 SDPFクラウドでは Contrail というSDNコントローラ製品を利用しています。ContrailはJuniper社の製品でありながら、 Tungsten Fabric としてOSS版が公開されています。 今回はそのコードベースを用いて、「サイズが大きいパケットを送信すると、疎通しないことがある」というユーザからの申告をもとに、その原因を突き止めて修正するという業務に取り組みました。 本インターンシップではさらに、以下の情報が新たに与えられ、これらの情報を踏まえて問題を切り分けていき、原因の究明に努めました。 仮想ルータをインストールし直すと復旧するが、10日ほどで同じ症状が起きる 同じ仮想ネットワークに属するVM同士でも同様の症状が見られる 疎通性が全く取れない時もあれば、稀に取れる事もある 問題の切り分け 現状把握 まず、疎通性が取れなくなる状況を分析するために、パケットサイズを変えながら疎通性を確認しました。その結果、パケットサイズが1472Byte以下ではパケットロスは確認できず、 1473Byte 以上になると報告のあった事象が起きていました。 また、SDPFクラウドの転送図は以下のようになっています。ここでSDPFクラウドを構成する各要素について説明します。 HV:HyperVisorの略称で、複数のVMを収容するサーバ vRouter:HV内部で複数VMのトラフィックの仮想化、転送を司るソフトウェアルータ vRouter Data Plane:トラフィックを転送するカーネルモジュール vRouter Agent:vRouterのコントロールプレーン。経路やフロー情報をvRouterに格納する RoutingInstance, FIB, FlowTable:vRouter内部で異なる仮想NW毎に通信を分けるために必要な情報群 tap:仮想NWのインターフェース VM AからVM Bへの疎通が取れないという報告を受けていましたが、分析を続けていく中で、同じHV, Routing Instance以下のVM BからRouterへの疎通においても同様の問題が確認できました。そのため、解析前はネットワークに問題があると考えたのですが、HV内の転送に原因があると分かりました。 原因箇所の更なる切り分け 続いて、原因箇所の更なる切り分けを行いました。その際、以下のツールを使用しました。 tcpdump:パケットキャプチャ contrail-tools dropstats:vRouter上でドロップしたパケットの情報を取得 flow:アクティブなフロー情報を取得 vif:HV上の仮想インターフェースの情報を取得 さらに、 scapy を使って、常に同じパケットを生成し、問題の原因がパケットそのものにあるかも調査しました。結果、IPヘッダのIdentificationフィールド(以降IP ID)を指定すると常に疎通が取れる、あるいは全く疎通が取れないという状況を作り出すことができ、パケットを処理するデータプレーンに原因があると推測されました。この状況でdropstatsコマンドを用いて監視すると、パケットドロップ時にFragment Errorsがカウントアップされました。以上より、vRouterのフラグメント処理に問題があることを突き止められました。 問題の修正 ここまででvRouterに原因があると分かったため、vRouterについて調査しました。 まず初めにvRouter Agentを再起動してみても疎通性は回復しませんでした。そのため、vRouterのカーネルモジュールに原因があると推測されました。vRouterカーネルモジュールは tf-vrouter をモジュール化したものです。 デバッグ方法 カーネルモジュールのデバッグを行う際、カーネルのメモリのステートをdumpしてその内容を読む手法が取られます。意図的にカーネルをクラッシュさせ、コアファイルを生成し、crashコマンドでその中身を読んでいきます。 ハッシュテーブル vRouterではフラグメントをハッシュテーブルで管理しています。ハッシュキーはパケットのソースと宛先アドレス、IP IDなどが使われています。scapyで調査した内容も踏まえ、このハッシュテーブルに問題がありそうだという仮説を立てました。事実、crashコマンドを用いてフラグメントのハッシュテーブルの中身を覗くと、次のような結果が得られました。 crash> struct vr_htable 0xffff914c203ceea0 // fragment hash table struct vr_htable { ht_router = 0xffffffffc0b08620 <router>, ht_hentries = 8192, ht_oentries = 1024, ht_entry_size = 97, ht_key_size = 40, ht_bucket_size = 4, ht_htable = 0xffff914c2b981bc0, ht_otable = 0xffff914c2b981000, ht_dtable = 0xffff914c2b981e00, ht_get_key = 0xffffffffc0ab4e70 <vr_fragment_get_entry_key>, ht_free_oentry_head = 0x0, ht_used_oentries = 1024, ht_used_entries = 8306 } ht_hentries と ht_oentries はハッシュテーブルのエントリ数を、 ht_used_oentries や ht_used_entries はハッシュテーブルのエントリのうちすでに埋まっている数を示しています。 これらの値から、ハッシュテーブルが全て埋まることでハッシュ衝突が起きたために、フラグメントの処理がうまくいかなかったと分かりました。 エントリの削除 vRouterのフラグメントテーブルは定期的にハッシュテーブルのスキャニングが走り、最終更新から一定時間経過しているエントリは解放される仕組みになっています。1回あたり2048エントリ分スキャンされます。どうやらこのスキャンがカーネルをロードした後、1回しか走っていないようでした。 vRouterではスキャンの定期実行のために、linux timerの機能を使っています。まず、functionを実行するtimerを作ります。そして、timerの期限が切れたら、もう一度functionを動かす新たなtimerを作ることで、定期実行を可能にしています。vRouterでは vt_stop_timer に格納された値で条件分岐しており、0であったらtimerが再度作られ、スキャンを再度走らせる仕組みになっています。 原因の特定 以上より、 vt_stop_timer が怪しいと突き止められました。vRouterでvtimerを作っている箇所をコードレビューすると、 kmalloc でメモリ確保をしていました。 kmalloc はメモリを確保するものの初期化しないため、値が不定になってしまいます。ここで vt_stop_timer に0以外の値が入ると、新たなtimerが作られなくなります。 ここまでで、原因の根源はメモリの初期化ミスであることが分かりました。そのため、 zalloc でメモリ確保をするようにコードを修正することで対応しました。実際に修正後のモジュールをリロードすると、問題なく動作する様子が確認できました。 - vtimer = vr_malloc(sizeof(*vtimer), VR_TIMER_OBJECT); + vtimer = vr_zalloc(sizeof(*vtimer), VR_TIMER_OBJECT); if (!vtimer) { vr_module_error(-ENOMEM, __FUNCTION__, __LINE__, sizeof(*vtimer)); goto fail_init; } vtimer->vt_timer = fragment_table_scanner; vtimer->vt_vr_arg = scanner; vtimer->vt_msecs = VR_FRAG_HASH_TABLE_SCANNER_INTERVAL_MSEC; if (vr_create_timer(vtimer)) { vr_module_error(-ENOMEM, __FUNCTION__, __LINE__, 0); goto fail_init; } もう1つの問題 ハッシュエントリが解放されないのはメモリの初期化ミスが原因でした。しかしながら、調査を進めていくうちに、もう1つのバグが起こりうる箇所を特定できました。 エントリが削除対象かを判定する関数でパケットフラグメントの宛先アドレスが 0.0.0.0 であった時、エントリが削除されないようになっていました。これは初期化されていない null を想定したコードですが、nullを表す0と 0.0.0.0 が同一視されることで、削除されなくなっていました。通常、このアドレス宛のパケットは発行されませんが、潜在的に攻撃対象となる可能性がありました。そのため、他の箇所を確認しこの条件がなくても要件を満たせると判断した上で、以下のように修正を加えました。 fe = VR_FRAGMENT_FROM_HENTRY(ent); - if (!fe || ((!fe->f_dip_u) && !(fe->f_dip_l))) + if (!fe) return; vr_get_mono_time(&sec, &nsec); if (sec > fe->f_time + VR_FRAG_HASH_TABLE_TIMEOUT_SECS) { vr_fragment_del(table, fe); } トラブルシューティングのまとめ サイズの大きいパケットが一定確率でドロップしてしまうという問題のトラシューを行いました。問題を切り分けていくうちに、原因はvRouterのデータプレーンにあると突き止めることができ、パケットのフラグメント処理に問題があると分かりました。コアファイルでデバッグをすると、フラグメントのハッシュエントリが解放されておらず、ハッシュのスキャンが走っていないと分かりました。原因の根幹にあったのは、スキャンを定期実行させるためのvtimerのメモリが初期化されていないことでした。 また、攻撃可能性として 0.0.0.0 宛のパケットを投げるとハッシュが埋め尽くされてしまうと分かりました。 以上の2つのバグを発見し、修正を加えることができました。 ライブパッチ 本インターンシップでは、ライブパッチを当てるタスクにも取り組みました。 SDPFクラウドはエンタープライズ向けであるので、パッチを当てる際にサービスの停止時間を無視できません。通常のパッチを当てるやり方ではカーネルモジュールを置き換える必要があり、その間通信ができなくなります。ダウンタイムを極力抑えつつ、修正したパッチを当てるために Linuxカーネルライブパッチ を用いました。この機能を使うことでパッチ適用時に再起動や停止をする必要がなくなります。 以下に示すように、通常のパッチを当てるやり方では通信断が発生しています。 1秒に1回送信しているpingパケットの icmp_seq が5-24まで欠落していることから約19秒の通信断があると分かります。 $ ping 10.0.0.4 PING 10.0.0.4 (10.0.0.4) 56(84) bytes of data. 64 bytes from 10.0.0.4: icmp_seq=1 ttl=64 time=1.24 ms 64 bytes from 10.0.0.4: icmp_seq=2 ttl=64 time=0.605 ms 64 bytes from 10.0.0.4: icmp_seq=3 ttl=64 time=0.766 ms 64 bytes from 10.0.0.4: icmp_seq=4 ttl=64 time=0.664 ms 64 bytes from 10.0.0.4: icmp_seq=5 ttl=64 time=0.771 ms # ここから 64 bytes from 10.0.0.4: icmp_seq=24 ttl=64 time=395 ms # ここまで 64 bytes from 10.0.0.4: icmp_seq=25 ttl=64 time=0.629 ms 64 bytes from 10.0.0.4: icmp_seq=26 ttl=64 time=0.700 ms 64 bytes from 10.0.0.4: icmp_seq=27 ttl=64 time=0.643 ms 64 bytes from 10.0.0.4: icmp_seq=28 ttl=64 time=0.626 ms 64 bytes from 10.0.0.4: icmp_seq=29 ttl=64 time=0.615 ms ^C --- 10.0.0.4 ping statistics --- 29 packets transmitted, 11 received, 62% packet loss, time 28606ms rtt min/avg/max/mdev = 0.605/36.612/395.474/113.482 ms 今回、 kpatch を用いてライブパッチを実装しました。 0.0.0.0 の方はライブパッチを当てると即座にバグが修正されました。しかし、vtimerの方はタイマー作成時に mod_timer で繰り返し実行を実装している仕組み上、単にvtimerのメモリ初期化をするライブパッチを当てても修正されません。そこで、 contrail-tools のコマンドを実行するとvtimerが新たに作られるように修正を加えました。通常のパッチを当てるやり方では、通信断が回復するまで約19秒かかっていましたが、ライブパッチを使うことでダウンタイムを大幅に削減できました。結果は以下に示す通りで、ダウンタイムはほとんどありません。 PING 10.0.0.4 (10.0.0.4) 56(84) bytes of data. 64 bytes from 10.0.0.4: icmp_seq=1 ttl=64 time=1.94 ms 64 bytes from 10.0.0.4: icmp_seq=2 ttl=64 time=0.388 ms 64 bytes from 10.0.0.4: icmp_seq=3 ttl=64 time=0.559 ms 64 bytes from 10.0.0.4: icmp_seq=4 ttl=64 time=0.520 ms 64 bytes from 10.0.0.4: icmp_seq=5 ttl=64 time=0.471 ms 64 bytes from 10.0.0.4: icmp_seq=6 ttl=64 time=0.373 ms 64 bytes from 10.0.0.4: icmp_seq=7 ttl=64 time=0.437 ms 64 bytes from 10.0.0.4: icmp_seq=8 ttl=64 time=0.440 ms 64 bytes from 10.0.0.4: icmp_seq=9 ttl=64 time=0.496 ms 64 bytes from 10.0.0.4: icmp_seq=10 ttl=64 time=0.351 ms 64 bytes from 10.0.0.4: icmp_seq=11 ttl=64 time=0.522 ms 64 bytes from 10.0.0.4: icmp_seq=12 ttl=64 time=0.551 ms 64 bytes from 10.0.0.4: icmp_seq=13 ttl=64 time=0.448 ms 64 bytes from 10.0.0.4: icmp_seq=14 ttl=64 time=0.463 ms 64 bytes from 10.0.0.4: icmp_seq=15 ttl=64 time=0.532 ms 64 bytes from 10.0.0.4: icmp_seq=16 ttl=64 time=0.501 ms 64 bytes from 10.0.0.4: icmp_seq=17 ttl=64 time=0.530 ms 64 bytes from 10.0.0.4: icmp_seq=18 ttl=64 time=0.432 ms # ここから 64 bytes from 10.0.0.4: icmp_seq=19 ttl=64 time=0.492 ms # ここまで 64 bytes from 10.0.0.4: icmp_seq=20 ttl=64 time=0.428 ms 64 bytes from 10.0.0.4: icmp_seq=21 ttl=64 time=0.377 ms 64 bytes from 10.0.0.4: icmp_seq=22 ttl=64 time=0.539 ms 64 bytes from 10.0.0.4: icmp_seq=23 ttl=64 time=0.395 ms 64 bytes from 10.0.0.4: icmp_seq=24 ttl=64 time=0.547 ms 64 bytes from 10.0.0.4: icmp_seq=25 ttl=64 time=0.521 ms 64 bytes from 10.0.0.4: icmp_seq=26 ttl=64 time=0.466 ms 64 bytes from 10.0.0.4: icmp_seq=27 ttl=64 time=0.395 ms 64 bytes from 10.0.0.4: icmp_seq=28 ttl=64 time=0.536 ms 64 bytes from 10.0.0.4: icmp_seq=29 ttl=64 time=0.332 ms 64 bytes from 10.0.0.4: icmp_seq=30 ttl=64 time=0.495 ms ^C --- 10.0.0.4 ping statistics --- 30 packets transmitted, 30 received, 0% packet loss, time 29639ms rtt min/avg/max/mdev = 0.332/0.516/1.949/0.273 ms インターンシップの感想 本インターンシップでは、普段あまり触る機会のないlinuxカーネルモジュールやライブパッチを体験でき、非常に楽しかったです。 メンターの梶浦さんを始めとし、チームの皆さんには色々と補助をしてもらいました。チームは普段リモート業務が主流のところをわざわざ対面で実施してくださり、本当に感謝しています。2週間という短い期間でしたが、おかげさまで大変充実した時間を過ごすことができました。 また、データセンターの見学や送別会で、インターネット作ってきて今はIOWNに携わっている日本電信電話株式会社所属の先輩とお話をする機会を設けていただいたりと、貴重な体験をさせたいただきました。 最後になりますが、本インターンシップでさまざまな経験をさせていただき本当にありがとうございます。 メンターからのコメント 梶浦です。伊藤さん、まずはお疲れ様でした。 2週間という短い期間かつ、普段あまり触れない領域であったにも関わらず持ち前の深い洞察力ですぐに深い部分まで理解しておられました。 最後には我々も初挑戦だったカーネルライブパッチまで実装いただき、実務上も大変助かりました。ありがとうございます。 この類まれな技術力と課題解決能力でこれからもご活躍されることを心より信じています。 さいごに NTTコミュニケーションズでは冬期にもインターンシップの開催を予定しており、募集が始まっています。 私のチームでも「 48.エンタープライズ向け大規模クラウドサービスを支えるネットワーク開発 」(「プロダクト・サービスエンジニア」ワークフィールド内にあります)で募集しています。 このポストではSDN開発だけでなく、クラウド上でネットワーク機能を提供するNFV開発や、その裏側にあるバックボーンネットワークの開発にも携わることができます。 このような内容に興味のある方はぜひご応募ください。
NTTコミュニケーションズ(以下、NTT Com)を含めたドコモグループではこの冬に2種類のインターンシップを開催します! 現場受け入れ型インターンシップ ビジネスグロースワークショップ この記事では NTT Com のリアルな業務を体験できる「現場受け入れ型インターンシップ」について紹介します。 現場受け入れ型インターンシップとは NTTドコモや NTT Com の社員と一緒に働きながら、実務を体験していただくインターンシップです。 セールスやビジネスデザイン、エンジニア、デザイナー、リーガルなど幅広い職種を取り揃えて、業務体験を通じて仕事の理解を深め、成長機会を提供する内容となっています。 今季は2024年2月5日(月)~2月16日(金)の土日祝を除く平日9日間(2 Weeks)で開催されます。開催場所は、出社+リモートワークのハイブリッド形式です(出社割合はポストにより異なります)。 募集ポスト 募集ポストについては下記のページの「受け入れポスト情報」をご覧ください。 現場受け入れ型インターンシップ 記載されているポストのうち、受け入れ会社に NTTコミュニケーションズ株式会社 と記載されたポストが NTT Com での業務です。 これまでのインターンシップの様子 これまで開催したインターンシップの体験記を NTT Com のエンジニア系ポストに参加した学生の方々が、この NTT Communications Engineers' Blog に寄稿してくれています。 「インターンシップでどんなことに取り組むのだろう?」、「インターンシップを通して何が学べるのだろう?」といった疑問を解消する手助けになれば幸いです。 AI分野 インターンシップでマルチA100 GPUサーバをぶん回してみた - NTT Communications Engineers' Blog セキュリティ分野 セキュリティ技術開発のインターンシップに参加させていただきました!! - NTT Communications Engineers' Blog インターンシップ体験記 〜セキュリティ運用の健全化を目指すMetemcyberの開発〜 - NTT Communications Engineers' Blog インターンシップ体験記 〜Cobalt StrikeのC2サーバ追跡〜 - NTT Communications Engineers' Blog インターンシップ生があるSaaSを用いた未知のC2脅威を実証してみた - NTT Communications Engineers' Blog 攻撃者はいかにしてフィッシングサイトを隠すか?(インターンシップ体験記) - NTT Communications Engineers' Blog ネットワーク分野 ネットワーク知識ゼロの大学院生が、NTTコミュニケーションズのインターンシップに参加してみた - NTT Communications Engineers' Blog インターンシップ体験記 〜BGP-LSの機能をFRRに実装してみた〜 - NTT Communications Engineers' Blog インターンシップ体験記 〜SRv6 L3VPN機能検証〜 - NTT Communications Engineers' Blog インターンシップ体験記 〜SR-MPLS IPv6 Underlay 相互接続検証〜 - NTT Communications Engineers' Blog インターンシップ体験記 〜SRv6 機能を Pola PCE に実装してみた〜 - NTT Communications Engineers' Blog ソフトウェア/クラウド分野 IoT Connect Gatewayを使ってみた 番外編 ~インターンシップでリリース前の機能を使って開発してみた~ - NTT Communications Engineers' Blog IoT Connect Gatewayを使ってみた 番外編 第2回 ~インターンシップでStorage転送機能を使って開発してみた~ - NTT Communications Engineers' Blog テレプレゼンスPJ インターン参加レポート - NTT Communications Engineers' Blog インターンシップ体験記 〜SDNコントローラの性能改善〜 - NTT Communications Engineers' Blog インターン参加記 ~GPUクラスタ管理者への道~ - NTT Communications Engineers' Blog TypeScript未経験の学生がSkyWayの開発に取り組んでみた(インターンシップ体験記) - NTT Communications Engineers' Blog データプレーンに起きたバグにパッチを当ててみた(インターンシップ体験記) - NTT Communications Engineers' Blog なお、NTT Com のデザイン系ポスト(KOEL)については KOEL公式note 、NTTドコモのエンジニア系ポストについては ドコモ開発者ブログ をご覧ください。 まとめ みなさんもこの冬、ドコモグループのインターンシップに参加して、興味分野で熱い冬を過ごしてみませんか? 気になるポストの詳細やエントリーはこちらです(再掲)。 現場受け入れ型インターンシップ エントリー締め切りは 2023年11月27日(月)23:59 です。 みなさんのご応募をお待ちしています!
サマリ SR-MPLS 環境の障害発生時における、通信断を 50ms 以内に抑えた復旧を実現 障害点の隣接ノードでの Fast ReRoute(FRR)設定と、各ノードでの Microloop Avoidance、機器内のタイマ調整を実施 SR OS + IOS XR + Junos の Multi-vendor 環境での動作検証 この記事は Multi-AS Segment Routing 検証連載の第 18 回です。過去の記事一覧は こちら 概要 イノベーションセンターの三島です。 第 9 回 の記事では、IOS XR + Junos の Multi-vendor 構成での SR-MPLS 環境において障害が発生した際に、Fast ReRoute(FRR) を用いて通信断を 50ms 以内に抑える手法についてご紹介しました。 本記事では、SR OS を含めた構成において同様の手法の適用例を紹介するとともに、前回紹介できなかった Microloop Avoidance や トポロジー内のノード間での IGP のタイマー調整といったより詳しい対処ついても紹介します。 トポロジー変更時の通信断抑制と、実現のため対策すべき課題 障害などによって発生するトポロジー変更時の通信断は、あるノードにおいて経路の再計算にかかるまでの間と、それがネットワーク全体で完了するまで間、ネットワーク全体での経路の一貫性が取れていない期間に発生します。 具体的に言い換えると下記2つの課題に分割され、それらを合わせた通信断を 50ms 以内に抑える必要があります。 課題1. 障害発生直後に、障害点と隣接するノードにおいて経路の再計算が行われ、FIB が更新されて転送が再開されるまでの間に発生する通信断 課題2. 障害点の隣接ノードで経路の再計算が行われた後、他ノードの経路計算が完了するまでの間に発生する通信断 課題1. 障害発生直後に、障害点と隣接するノードにおいて経路の再計算が行われ、FIB が更新されて転送が再開されるまでの間に発生する通信断 課題1. については、連載記事 第 9 回 の「障害時の迂回動作について」の図にて紹介しています。 障害が発生した際に、隣接ノードでは障害の検知、IGP の再計算、再計算の結果をハードウェアに反映し転送再開、というステップで復旧に向かいます。 再計算から転送再開には100ミリ秒から秒単位の時間がかかるため、あらかじめバックアップ経路を計算しハードウェアに反映しておき使用するという手法をとります。 これが FRR です。 課題2. 障害点の隣接ノードで経路の再計算が行われた後、他ノードの経路計算が完了するまでの間に発生する通信断 課題2.の課題を図に示します。 IGP の経路計算処理は各ノードで非同期に行われるため、その実行タイミングは揃っていません。 そのため、リンク障害でトポロジーが変化した後では、変化後のトポロジーをもとに転送する経路計算が完了したノードと、変化前のトポロジーをもとに転送する経路計算が未完了なノードの混在した状況が発生します。 このような状況においては、特定のトポロジーにおいて Microloop と呼ばれるルーティングループが発生し通信断を引き起こします。 このタイミングをできるだけ揃える IGP のタイマ調整や、変化後のトポロジーの計算結果の使用を意図的に遅らせる Microloop Avoidance で対処します。 上の図は、障害発生後に rt26 でのみ経路計算が完了し、その他のノードでは未完了と仮定した場合の様子を示しています。 この状況で egress node である rt16 に向かう経路を考えます。 図中の 1. にて障害が発生した後、各ノードで経路計算が開始されます。 その後、2. では rt26 における経路の再計算が終わったため、next-hop が(もしくは outgoing interface が)rt11 に変わっています。 一方、3. の通り、rt11 は経路計算が完了していないため、next-hop が rt26 へのリンクを向いています。 そのため、rt26 は rt11 へとパケットを転送し、r11 は rt26 へとパケットを送ってしまいます。これにより、rt11 で 経路計算が完了するまでの間、4. の通り rt26 と rt11 の間で Microloop が発生します。 Microloop の発生有無は、トポロジーやタイミングによります。また、ホップ数やコストなどのトポロジー条件によっては、障害点とは離れたノードで発生する可能性もあります。 例えば先ほどの例では、コストによっては rt11 と rt23 との間で起こる可能性もありますし、また障害復旧に伴う経路計算においても Microloop は発生する可能性があります。 時系列に沿った各課題の整理 課題1・2を障害発生からの時系列で示すと下記のようになります。 この図は、ある2つのノードにおける障害発生時点からの時系列を示しています。 ノード A は障害発生箇所の隣接ノード、ノード B は障害箇所に直接接していないノードです。 障害が発生した後、隣接ノードであるノード A が障害を検知し、経路計算を開始するとともにトポロジーの変化を IGP により広告します。 また、経路広告を受け取ったノード B でも経路計算が開始されます。各ルーターにおける経路計算は、機器内部の IGP タイマーで定められた間隔毎に実施されます。 これまでに説明した通り、障害が発生した時点から、経路計算が完了するまでの期間は、課題1のループが生じます。 また、あるノードにおける経路計算が完了した時点から、全ノードでの経路計算完了までにかかる時間の期間には課題2. の Microloop が発生する可能性があります。 課題1. の対策としては FRR があります。 FRR は、ルーターがあらかじめ計算したバックアップパスを FIB に保持しておき、障害が発生した際、バックアップパスを利用することで、高速迂回を実現します。 第9回の記事でも紹介した通り、SR においては、TI-LFA と呼ばれる技術により、どのようなトポロジーであってもループフリーにバックアップパスを生成できます。 FRR による保護を、時系列の図に示しました。 図のように、FRR により通信を保護することで、障害発生地点の隣接ノードでの IGP 経路計算が完了するまでの間、バックアップパスを用いることでループを回避できます。 一方、FRR はそのノードの経路計算完了までを保護する技術であるため、経路計算が完了した後、その先のノードで発生する Microloop(課題2)は保護できません。 課題2. の対策としては、Microloop Avoidance と ルーター内の IGP 関連タイマーを調整する手法の2種が存在します。 以下の節にて、それぞれのポイントについて解説します。 Microloop Avoidance Microloop Avoidance は、経路収束後に Microloop が発生する可能性がある場合に、タイマーに従い経路適用を遅延させることで他ノードの経路収束を待ち、Microloop を回避する技術です。 Microloop Avoidance の動作を図に示しました。 前提として、rt26 には各ノードの経路収束が現実的に完了するであろう時間分、Microloop Avoidance の遅延タイマーを設定しておきます。 障害に伴うトポロジー変更が発生した後、rt26 内で IS-IS 等での経路計算が完了した場合を想定します。 ここで、rt26 では Microloop Avoidance により、遅延タイマーの時間分だけ RIB あるいは FIB への経路更新を遅延させ、その代わりに Microloop を回避可能な経路が採用されるよう、新たなラベルを付与し送信します。 タイマーにより経路インストールを遅延させることで、rt11 がパケットを戻してしまうことを抑制できます。 この際、追加のラベルを付与して送信することで、rt23 より先のノードで経路計算が完了した場合でも、rt11 向けにパケットが戻ってくることを防止します。(rt11 より先での Microloop 防止) rt11 での経路計算が完了すると、本来のベストパスでの転送が再開されます。 その後 rt26 で Microloop Avoidance の遅延タイマー分の時間が経過することにより、IS-IS で計算したベストパスを FIB にインストールし、Microloop Avoidance を終了します。 このように、経路収束が現実的に完了するであろう時間まで Microloop Avoidance の遅延を入れることにより、Microloop を回避できます。 Microploop Avoidance による保護を、時系列の図に示しました。 図のように、Microloop Avoidance は、あるノードでの経路計算が完了した後、事前にノード内で設定された時間分の保護を実施し、Microloop を回避します。 ただし、Microloop Avoidance はネットワーク上の全ノードの経路計算完了を検知できる技術ではないため、タイマーで設定された時間が完了するまでの間は保護が行われ続けます。 機器間のタイマー統一 ある機器における経路収束タイミングは、IGP での経路広告に加え、機器内の SPF 実行タイマーや IS-IS による LSP 生成タイマーなど、さまざまな要素が絡み決定されます。 これらのタイマーはベンダー毎に異なるため、経路計算のタイミングに差が生まれ Microloop が発生しやすくなります。 タイマーの設定による保護を、時系列の図に示しました。 図のように、IGP タイマーの値を十分短い時間に統一することにより、機器間の経路計算タイミングの差を削減できます。 これにより、ネットワーク内の全ノードで経路計算が完了するまでの時間を削減でき、課題2の発生時間を短縮可能です。 多くの機器では経路収束に関連するタイマーの値を設定できます。今回対象とするタイマーは下記の2つです。 SPF wait : IS-IS による SPF 計算に対する遅延 LSP wait : IS-IS の LSP 生成に対する遅延 IOS XR と Junos、そして SR OS において SPF wait / LSP wait のデフォルト値は以下の通りです。 SR OS (config name) IOS XR (config name) Junos (config name) SR OS spf-max-wait 5000 ms (spf-interval>maximum-wait) 5000 ms (spf-options holddown) 10000 ms spf-initial-wait 50 ms (spf-interval>initial-wait) 200 ms (spf-options delay) 1000 ms spf-second-wait 200 ms (spf-interval>secondary-wait) 200 ms (spf-options delay) 1000 ms lsp-max-wait 5000 ms (lsp-gen-interval>maximum-wait) 不明 5000 ms lsp-initial-wait 50 ms (lsp-gen-interval>initial-wait) 100 ms (lsp-interval) 10 ms lsp-second-wait 200 ms (lsp-gen-interval>secondary-wait) 100 ms (lsp-interval) 1000 ms 各パラメータの出典は以下の通りです。 IOS XR spf-interval lsp-gen-interval Junos spf-options lsp-interval SR OS spf-wait lsp-wait 特に SPF wait は IOS XR や Junos の標準設定では 100~200 ms 周期で更新されるのに対し、SR OS の標準動作では 1000 ms 周期での更新となっています。 そのため、IOS XR や Junos ルーターにおける経路収束と、SR OS ルーターにおける経路収束には最悪1秒程度の差が存在するため、Microloop の原因となります。 前節の通り、Microloop Avoidance を適切に設定することで、あるノードにおける経路収束後、Microloop Avoidance を防止できます。しかし、Microloop Avoidance 中はパケットに対する不要な追加 Encapsulation が行われるため、一般に長時間の Microloop Avoidance を設定することは好ましくありません。 一方、タイマー統一はあくまでルーター間の経路計算タイミングを近づけるアプローチであり、微小な期間の Microloop は防止できません。 しかし、タイマーを機器間で統一された短い値に設定しておくことで、機器間の経路計算タイミングの差を縮め、Microloop Avoidance の動作時間を短縮可能になります。 ただし、経路計算タイマーの短縮はルーターの負荷を向上させるため、それぞれの環境に合ったパラメータを設定する必要があります。 以降の章では、IOS XR・Junos・SR OS の混在環境において、FRR・Microloop Avoidance・タイマー調整のそれぞれの手法を検証していきます。 検証 本章では、これまでにご紹介したそれぞれの技術を適用し、障害発生時における 50ms 以内の通信断での通信を実現します。 実現にあたっては、概要章で触れた各技術を組み合わせることが必要です。ここでは、下記の順で検証します。 全ての技術を用いない場合の通信断の時間確認 FRR を用いた、障害発生直後の通信断の抑制 FRR と Microloop Avoidance を用いた、断時間 50ms の実現 FRR と タイマー調整による、の抑制手法の紹介 上記の順で検証することで、障害発生後の通信断時間を、各種技術がどのように削減してくかを確かめます。 検証は以下のようなトポロジーを用いて行います。 本検証で用いる各ルーターの機種名と OS のバージョンは以下の通りです。 rt11(NCS55A2: IOS XR 7.5.1) rt16(MX204: Junos 21.3R1.9) rt23(7750SR-1: SR OS 23.3.R1) rt24(7750SR-1: SR OS 23.3.R1) rt26(7750SR-1: SR OS 23.3.R1) 検証の流れ 復旧時間の計測は、 ping コマンドを用いて行います。 VM 間で ICMP パケットを一定間隔(10 ms 毎)で送信し続けておき、 rt16 と rt26 間のリンクを切断した際にどの程度パケットがロスするかを計測する事で切り替えにかかった時間を測定します。 以下の手順で確認します。 vm01 から vm02 に対し、ping コマンドを用いて ICMP パケットを短い一定間隔(0.001秒)で送信し続けておく vm01 では tcpdump コマンドを用いて ICMP の request パケットをキャプチャしておく rt16 と rt26 間リンクの rt26 側インタフェース(xe-0/1/1)をシャットダウンする事で擬似的な障害を発生させる インタフェースをシャットダウンした際に、vm01 から vm02 への ICMP パケットロスがどの程度発生したかを確かめる 事前準備 rt16 と rt26 間で VRF 100 による L3VPN を実装します。 L3VPN の設定は 第 4 回の記事 や 第 12 回の記事 を参考にして以下を実施します。 VRF 100 による L3VPN 作成 BGP color の付与と広告 1.全ての技術を用いない場合の通信断の時間確認 まずは FRR により保護していない場合の復旧時間を計測します。 経路切り替え動作(SR OS) 状態確認 TI-LFA/FRR は未設定のためバックアップパスは作成されていません。 A:user@ar-rt26# tools dump router segment-routing tunnel | no-more =================================================================================================== Legend: (B) - Backup Next-hop for Fast Re-Route (D) - Duplicate label stack is ordered from top-most to bottom-most =================================================================================================== --------------------------------------------------------------------------------------------------+ Prefix | Sid-Type Fwd-Type In-Label Prot-Inst(algoId) | Next Hop(s) Out-Label(s) Interface/Tunnel-ID | --------------------------------------------------------------------------------------------------+ 10.255.2.1 Node Orig/Transit 16009 ISIS-0 10.2.17.1 16009 to_ar-rt11 10.255.2.2 Node Orig/Transit 16010 ISIS-0 10.2.17.1 16010 to_ar-rt11 10.255.2.3 Node Orig/Transit 16011 ISIS-0 10.2.17.1 3 to_ar-rt11 10.255.2.5 Node Orig/Transit 16013 ISIS-0 10.2.17.1 16013 to_ar-rt11 10.255.2.7 Node Orig/Transit 16015 ISIS-0 10.2.17.1 16015 to_ar-rt11 10.255.2.8 Node Orig/Transit 16016 ISIS-0 10.2.15.1 3 to_ar-rt16 10.255.2.23 Node Orig/Transit 16023 ISIS-0 10.2.17.1 16023 to_ar-rt11 10.255.2.24 Node Orig/Transit 16024 ISIS-0 10.2.17.1 16024 to_ar-rt11 10.255.2.25 Node Orig/Transit 16025 ISIS-0 10.2.17.1 16025 to_ar-rt11 10.255.2.26 Node Terminating 16026 IGP-Shared-0 10.2.15.1 Adjacency Transit 524282 ISIS-0 10.2.15.1 3 to_ar-rt16 10.2.17.1 Adjacency Transit 524285 ISIS-0 10.2.17.1 3 to_ar-rt11 --------------------------------------------------------------------------------------------------+ No. of Entries: 12 --------------------------------------------------------------------------------------------------+ vm01 から vm02 へ ICMP request の送信 以下のコマンドを実行します。 user@vm01:~$ sudo ping -i 0.001 192.168.40.1 リンク切断 以下の設定を追加し、rt16 と rt26 間リンクの rt16 側インターフェースである xe-0/1/1 をシャットダウンすることで擬似的に障害を発生させます。 [edit] user@rt16# show | compare [edit interfaces xe-0/1/1] + disable; 復旧に要した時間 vm02 において tcpdump コマンドを用いて、vm01 から受信した ICMP request パケットをキャプチャすると以下のような結果となりました。 rt11・rt23・rt24 を経由する経路へ切り替わると、ホップ数が 3 増加するため ttl は 3 減少します。(62 → 59) ttl に着目し障害が発生した時点でのパケットを探すと ICMP のシーケンス番号 が 4949 から 5061 の間でパケットロスが確認でき、経路が切り替わっている事が分かります。 よって、SR OS では非 FRR での通信復旧に(5061 - 4949) = 112 ms 程度要したことが確認できました。 user@vm02:~$ sudo tcpdump icmp[icmptype] == 8 -i ens192 -v 22:12:02.360488 IP (tos 0x0, ttl 62, id 25319, offset 0, flags [DF], proto ICMP (1), length 84) 192.168.41.1 > vm02: ICMP echo request, id 228, seq 4947, length 64 22:12:02.361488 IP (tos 0x0, ttl 62, id 25320, offset 0, flags [DF], proto ICMP (1), length 84) 192.168.41.1 > vm02: ICMP echo request, id 228, seq 4948, length 64 22:12:02.362488 IP (tos 0x0, ttl 62, id 25321, offset 0, flags [DF], proto ICMP (1), length 84) 192.168.41.1 > vm02: ICMP echo request, id 228, seq 4949, length 64 22:12:02.575251 IP (tos 0x0, ttl 59, id 25443, offset 0, flags [DF], proto ICMP (1), length 84) 192.168.41.1 > vm02: ICMP echo request, id 228, seq 5061, length 64 22:12:02.576134 IP (tos 0x0, ttl 59, id 25444, offset 0, flags [DF], proto ICMP (1), length 84) 192.168.41.1 > vm02: ICMP echo request, id 228, seq 5062, length 64 22:12:02.577131 IP (tos 0x0, ttl 59, id 25445, offset 0, flags [DF], proto ICMP (1), length 84) 192.168.41.1 > vm02: ICMP echo request, id 228, seq 5063, length 64 2. FRR を用いた、障害発生直後の通信断の抑制 続いて、 FRR(TI-LFA)を用いて rt26 の rt16 向けリンクを保護した場合を検証します。 第 9 回 の記事では、IOS XR + Junos の 2 つのベンダー機器を用い、FRR・Topology Independent Loop-Free Alternate(TI-LFA)を用いた高速迂回を実現する方法を紹介しました。 今回は新たに Nokia SR OS(Service Router Operating System)における高速迂回手法と、各社の混在環境での検証を紹介します。 TI-LFA の設定(SR OS) 保護したいノードに対し以下の設定を追加します。 rt26(SR OS) router isis loopfree-alternate ti-lfa node-protect 各経路に対しバックアップパスが計算されている事が確認できます。 rt16(10.255.2.8)に対しては、 16023・16016 の SID を積み増し、to_ar-rt11 のインターフェースから送出するバックアップパスが作成されました。 A:hanabi@ar-rt26# tools dump router segment-routing tunnel | no-more =================================================================================================== Legend: (B) - Backup Next-hop for Fast Re-Route (D) - Duplicate label stack is ordered from top-most to bottom-most =================================================================================================== --------------------------------------------------------------------------------------------------+ Prefix | Sid-Type Fwd-Type In-Label Prot-Inst(algoId) | Next Hop(s) Out-Label(s) Interface/Tunnel-ID | --------------------------------------------------------------------------------------------------+ 10.255.2.1 Node Orig/Transit 16009 ISIS-0 10.2.17.1 16009 to_ar-rt11 (B)10.2.15.1 16024 to_ar-rt16 16009 10.255.2.2 Node Orig/Transit 16010 ISIS-0 10.2.17.1 16010 to_ar-rt11 (B)10.2.15.1 16010 to_ar-rt16 10.255.2.3 Node Orig/Transit 16011 ISIS-0 10.2.17.1 3 to_ar-rt11 (B)10.2.15.1 16024 to_ar-rt16 16011 10.255.2.5 Node Orig/Transit 16013 ISIS-0 10.2.17.1 16013 to_ar-rt11 (B)10.2.15.1 16024 to_ar-rt16 16013 10.255.2.7 Node Orig/Transit 16015 ISIS-0 10.2.17.1 16015 to_ar-rt11 (B)10.2.15.1 16024 to_ar-rt16 16015 10.255.2.8 Node Orig/Transit 16016 ISIS-0 10.2.15.1 3 to_ar-rt16 (B)10.2.17.1 16023 to_ar-rt11 16016 10.255.2.23 Node Orig/Transit 16023 ISIS-0 10.2.17.1 16023 to_ar-rt11 (B)10.2.15.1 16023 to_ar-rt16 10.255.2.24 Node Orig/Transit 16024 ISIS-0 10.2.17.1 16024 to_ar-rt11 (B)10.2.15.1 16024 to_ar-rt16 10.255.2.25 Node Orig/Transit 16025 ISIS-0 10.2.17.1 16025 to_ar-rt11 (B)10.2.15.1 16025 to_ar-rt16 10.255.2.26 Node Terminating 16026 IGP-Shared-0 10.2.15.1 Adjacency Transit 524282 ISIS-0 10.2.15.1 3 to_ar-rt16 (B)10.2.17.1 16023 to_ar-rt11 16016 10.2.17.1 Adjacency Transit 524285 ISIS-0 10.2.17.1 3 to_ar-rt11 (B)10.2.15.1 16024 to_ar-rt16 16011 --------------------------------------------------------------------------------------------------+ No. of Entries: 12 --------------------------------------------------------------------------------------------------+ SR OS ルーターでの経路切り替え動作 vm01 から vm02 への ICMP request の送信 user@vm01:~$ sudo ping -i 0.001 192.168.40.1 リンク切断 [edit] user@rt02# show | compare [edit interfaces xe-0/1/1] + disable; 復旧に要した時間 vm02 において、vm01 から受信した ICMP の request パケット情報を確認します。 ICMP のシーケンス番号が 12637-12633 の パケットが欠けていることから、SR OS では通信復旧に 4 ms 程度要したことが確認できました。 user@vm02:~$ sudo tcpdump icmp[icmptype] == 8 -i ens192 -v 22:20:01.865557 IP (tos 0x0, ttl 62, id 60957, offset 0, flags [DF], proto ICMP (1), length 84) 192.168.41.1 > vm02: ICMP echo request, id 229, seq 12631, length 64 22:20:01.866556 IP (tos 0x0, ttl 62, id 60958, offset 0, flags [DF], proto ICMP (1), length 84) 192.168.41.1 > vm02: ICMP echo request, id 229, seq 12632, length 64 22:20:01.867560 IP (tos 0x0, ttl 62, id 60959, offset 0, flags [DF], proto ICMP (1), length 84) 192.168.41.1 > vm02: ICMP echo request, id 229, seq 12633, length 64 22:20:01.898894 IP (tos 0x0, ttl 59, id 60967, offset 0, flags [DF], proto ICMP (1), length 84) 192.168.41.1 > vm02: ICMP echo request, id 229, seq 12637, length 64 22:20:01.899881 IP (tos 0x0, ttl 59, id 60968, offset 0, flags [DF], proto ICMP (1), length 84) 192.168.41.1 > vm02: ICMP echo request, id 229, seq 12638, length 64 22:20:01.900860 IP (tos 0x0, ttl 59, id 60969, offset 0, flags [DF], proto ICMP (1), length 84) 192.168.41.1 > vm02: ICMP echo request, id 229, seq 12639, length 64``` また、FRR 実施時は Backup Pathの通りに 16023・16016 の SID が積み増されていることも確認できました。 Nokia の SR-TE から FRR を扱う場合の注意点 SR OS にて lsp や lsp-template と FRR を併用する場合、FRR により追加される SID 数(ラベル数)の最大値を調整する必要があります。 TL-LFA の場合は 2 段の SID が積み増される可能性があるため、下記のように additional-frr-labels を設定します。 max-sr-labels { additional-frr-labels 2 } 3. FRR と Microloop Avoidance を用いた、断時間 50ms の実現 Microloop Avoidance 未導入の場合 前節では、FRR により障害発生直後のパケットロスを防止できました。 しかし、解説の章で触れた通り、あるノードでの計算が完了した後で Microloop によるパケットロスが発生する可能性があります。 ここでは、rt26 での計算が完了した後、rt11 の経路計算が完了するまでの間に Microloop が発生することで、以下のように 95 パケットのロスが生じていることが確認できます。 64 bytes from 192.168.40.1: icmp_seq=10690 ttl=59 time=0.252 ms 64 bytes from 192.168.40.1: icmp_seq=10785 ttl=59 time=0.339 ms Microloop Avoidance の導入 rt16 に以下の設定をし、30秒の間 Microloop Avoidance を適用させます。 user@ar-rt16# set protocols isis spf-options microloop-avoidance post-convergence-path delay 30000 [edit] user@ar-rt16# show | compare [edit protocols isis] + spf-options { + microloop-avoidance { + post-convergence-path { + delay 30000; + } + } + } 設定後、バックアップ経路から再計算後の経路に切り替わったタイミングでのパケットロスは確認できず、正しくMicroloop Avoidance が動作していることが確認できました。 4. (参考)FRR と タイマー調整による、経路計算のタイミング差抑制 rt26 のタイマーを IOS XR のものと同様の値に変更します。 [ro:/configure] A:user@ar-rt26# /info router isis timers spf-wait { spf-max-wait 5000 spf-initial-wait 50 spf-second-wait 200 } lsp-wait { lsp-max-wait 5000 lsp-initial-wait 50 lsp-second-wait 200 } これにより、各タイマーがベンダー間で共通化され、経路収束時間の差異を削減できます。 概要章でも述べた通り、タイマー調整はあくまで機器間の経路計算時間を統一することで、経路計算の完了タイミングを近づけるアプローチです。そのため、このアプローチでは Microloop の発生確率を下げることはできますが、回避はできません。 機器間のタイマーを統一した上で、前節の Microloop Avoidance を適切な時間分設定する上で、不要な encapsulation を最小限にしつつ、 Microloop を回避できます。 検証まとめ それぞれの検証を通じ、IOS XR・Junos・SR OS の混在環境において、FRR と Microloop Avoidance を用いた保護により、障害が発生した際に 50 ms 以下で復旧できることを確認できました。 まとめ 本記事では、SR-MPLS 環境において、50ms 以内で通信を復旧する手法を解説しました。 その中で、障害発生直後に用いる FRR と、その後の機器毎の経路収束タイミングの差異によるループを防止する Microloop Avoidance や各種タイマーの統一手法を紹介し、IOS XR・Junos・SR OS を用いた動作検証を実施しました。 次回の記事では PCEP を用いた SR OS への SR Policy 適用方法について紹介予定です。 (2023/11/13 追記) 公開しました: [Multi-AS Segment Routing 検証連載 #19] SR OS での PCE を用いた LSP Provisioning
はじめに こんにちは、PS本部C&A部開発オペレーション部門の8G3Tです。AI映像解析ソリューションCOTOHA Takumi Eyesの技術開発や運営保守に取り組んでいます。チームの開発メンバーは6月18日から22日の間に開催されたコンピュータービジョン分野のトップカンファレンスであるCVPR2023にリモートで参加しました。本記事ではCVPR2023に採択された視覚・言語のマルチモーダル技術に関して、私たちが興味深く感じた論文をピックアップしてご紹介します。 なお、今回の学会参加はイノベーションセンターのメディアAIチームと連携して実施しました。NeRF技術(ニューラルネットワークベースの微分可能な3次元レンダリング手法)に関する論文のご紹介や検証結果については、以下のメディアAIチームが取りまとめた記事をぜひご覧ください。 CVPR2023で登場したNeRF論文を紹介 目次 はじめに 目次 視覚言語マルチモーダル技術の概要 画像・映像認識性能の向上に関する論文 Improving Commonsense in Vision-Language Models via Knowledge Graph Riddles RA-CLIP: Retrieval Augmented Contrastive Language-Image Pre-training Fine-tuned CLIP Models are Efficient Video Learners Top-Down Visual Attention from Analysis by Synthesis 新たなタスクを提案した論文 Connecting Vision and Language with Video Localized Narratives Visual Programming: Compositional visual reasoning without training 最後に 視覚言語マルチモーダル技術の概要 人間の学習は本質的に多様なモーダリティを備えており、複数の感覚を合わせて処理することによって新しい情報への理解を深めることが可能となります。近年、コンピュータービジョン分野においてもマルチモーダルのAI技術が急速に発展し、広く注目を集めています。 特定の画像処理タスクのデータセット(例:画像分類)で学習したユニモーダルAIと比較して、画像と自然言語の大規模データで学習したマルチモーダルAIの汎化性能が高く、チャレンジングなフューショットやゼロショットの画像認識タスクにおいて優れた性能を示しました。画像生成のStable Diffusionや質問応答のGPT-4といった汎用性の高いマルチモーダルAIサービスは人間の知的作業全般に変革をもたらしつつあり、マルチモーダルAIの性能向上が求め続けられています。 今回はマルチモーダルAIの画像・映像認識性能を向上させる取り組みに関する最新論文とマルチモーダルAIをベースに新たに提案されたタスクについてご紹介します。 画像・映像認識性能の向上に関する論文 Improving Commonsense in Vision-Language Models via Knowledge Graph Riddles 1 概要 背景: 既存のVLモデルには、人工的な一般知能に向けた重要な要素である常識的知識/推論能力(例えば「レモンは酸っぱい」)が欠けている。 下の画像の例では酸っぱい味がするものに対応する画像として既存のVLモデルがレモンではなくチョコレートケーキを選んでしまっている。 原論文 Figure 1 から引用 この現象の原因の重要な一つとして、既存の大規模なVLデータセットにはあまり常識的な知識が含まれていないことがある。通常のVLデータセット(例えばCOCOやCC 12M)には、名詞や(画像内の実体を直接説明するような)説明形容詞が多く含まれ、動詞や助詞は通常のテキストに比べて少ない。このような分布の違いは、言語のみのモデルとは異なり、VLモデルが純粋にデータセットを拡大することによって、常識的な能力を獲得することは不可能かもしれないことを示唆している。 また、視覚的な質問応答や生成タスクによってコモンセンス能力を評価する既存のベンチマークは、訓練に広く適用できず、データサイズも限られている。これらベンチマークは既存のVLモデルの多くには適合しておらず、下流タスクに移行することなく、VLモデルの常識的知識を自動的に直接比較することは、未解決の課題である。 Contribution: 視覚言語モデルにおけるコモンセンス能力を改善する手法を提案 提案手法 知識グラフを利用しコモンセンスで補強された画像とテキストのペアを生成するデータ増強手法であるDANCEを提案 下図は知識グラフを利用したデータ生成法を示している。 原論文 Figure 2 から引用 💡 コモンセンス知識グラフ(ConceptNet)を(エンティティ、関係、エンティティ)の三つ組み形式にしそれらをエンティティの1つを含む画像と対にする。 💡 その画像に含まれるエンティティの名前を、例えば「このアイテム」のような指示代名詞で隠す。 💡 3つ組みから説明文を生成する。 生成されたデータは画像とテキストのペア形式のためほとんどのVLモデルの学習に容易に適用できる。 学習段階でエンティティ間の関係をモデルに記憶させることで、推論段階でそのようなデータ補強が不要。 データペア生成パイプラインは、既存の統合されたコモンセンス知識ベースと、視覚言語モデルの大規模かつ多様な学習データを活用し、自動的かつスケーラブルである。 ※ ConceptNet( ConceptNet ): 専門家、クラウドソーシング、ゲームなどさまざまなソースから作成された8Mのノードと21Mのエッジを持つ、一般的で統合されたコモンセンス知識グラフ。 検索にもとづくより広く適応可能な新しいコモンセンスベンチマークを提案 提案ベンチマークにはCOCOデータセットとConceptNetを用いて上記手順で生成された画像-テキストペアを利用する。 提案ベンチマークはテキスト-画像検索と画像-テキスト検索に分けられ、前者はコモンセンスを必要とする記述に最も合致する画像を検索するもので、後者はその逆。 既存の常識的知識を用いて新しい知識を推論する汎化能力をさらに評価するために、テスト集合を知識がトレーニング集合に現れるtest-seenと、対応する関係がトレーニングに存在しないtest-unseenに分割する。 (例えば「パイナップルがピザに乗っている」という知識と「ピザハットがピザのメーカーの1つである」という知識を学習していた場合、モデルが 「パイナップルはピザハットに必要かもしれない 」と推論できるか) 生成されたデータセット 下図は既存のVLデータセットと生成されたデータセット、およびConceptNetにおける品詞分析結果を示している。 既存のデータセット(COCOやCC 12M)のテキストで最も頻出する単語は名詞であり、対照的に、知識ベースConceptNetにはより多くの動詞があり、エンティティ間の関係に関する豊富な情報を含んでいる。こうした分布違いがVLモデルのコモンセンス能力欠如に繋がっていると考えられ、提案するDANCE拡張データは、既存のVLデータよりも有意に多くのコモンセンスを提供。 原論文 Figure 4 から引用 下図は既存のさまざまな知識ベースデータセットとの比較を示している。提案ベンチマークは規模が大きく、幅広い知識を含んいる。 原論文 Table 2 から引用 下図は提案ベンチマークにおける既存モデルと人手によるスコアの比較を示している。提案ベンチマークでは人手のスコアと既存モデルのスコアに大きな乖離がある。 原論文 Table 1 から引用 結果 下図は事前学習、ファインチューニングそれぞれにDANCEによるデータ増強を適用した場合のスコア比較を示している。いずれの場合もDANCEによるデータ増強によりスコアが改善していることがわかる。 また、test-unseenデータについても、大きな改善が観察される⇒DANCEの事前学習がモデルのコモンセンス能力を向上させるだけでなく、既存のコモンセンス知識に基づいて新しい知識に汎化する能力を強化することを示している。 加えて、コモンセンスをあまり含まないCOCO検索のバニラベンチマークでもその精度は維持されるか、それ以上の精度となる。このことは、DANCEがコモンセンス能力を高めると同時に、一般的な視覚言語表現を学習することを示している。 原論文 Table 3 から引用 下図は既存のコモンセンスベンチマーク(OK-VQA)での比較を示している。こちらもDANCEで事前学習したモデルでは精度が改善していることが分かる。 原論文 Table 4 から引用 上図は定性分析の結果を示している。右の画像(OK-VQA)の例では既存モデルが「風船を満たしているものは何か」という質問に正しく答えられていないのに対し、提案手法による事前学習を行ったモデルは正しく答えられている。 原論文 Figure 6 から引用 💡 実際ConceptNetを見ると以下のような知識があるのでこういったコモンセンスが活かされているのではと考えられる。 下図はより多くのベンチマークにおいて他のVLモデル(ALBEF)と比較した結果を示している。 提案ベンチマークでは大きな精度向上が見られるほか、VQA(標準的な視覚的質問応答)やNLVR(画像ペアに関するキャプションの真偽を分類)は特別コモンセンスを対象としているわけではないにもかかわらず精度が改善している。 原論文 Table 5 から引用 今後の課題 人間のような知能を実現するためには、常識的な知識を認識するだけでは不十分である。 ⇒モデルは、現実のシナリオにおける数学的・物理的計算のような推論ができなければならず、これは既存のVLモデルではまだ弱く、既存の常識的知識ベースには含まれていない。 RA-CLIP: Retrieval Augmented Contrastive Language-Image Pre-training 2 概要 背景: 自然言語と画像を結びつけて対比学習を行うCLIP手法は、色々なコンピュータービジョン分野のタスクにおいて優れた汎用性能があるため注目されている。 CLIPでは一定の精度を達成するために多くのデータから視覚的概念を学習(記憶)することが必要で、限られたデータでの精度向上が課題として挙げられている。 Contribution: 本論文では、RA-CLIPという手法を提案し、同じ学習データ量で大幅にzero-shot画像分類のタスクにおいて+12.7%(Top-1)の精度向上を実現。 RA-CLIP:より豊富な情報量を持たせるように画像特徴量を拡張する手法。 テキスト特徴量のほうは画像特徴量と比べて情報量が少ないため、拡張しても有用な情報量だけ(拡張によりノイズも入ってしまう)を増やすことが難しいとablation studyの実験によって判明。 提案手法 原論文 Figure 2 から引用 上図は全体の処理の流れを示している: 入力画像に対して、学習セットとは別の参照セットから関連画像とテキストの複数のペアをRAM(Retrieval Augmented Module)というモジュールで画像エンコーダーによって抽出した画像特徴量を拡張し、より豊富な情報量を持つ画像特徴量にすることで大幅なzero-shot精度の向上を実現。 テキスト側の処理はCLIPとは同じ、テキストエンコーダーで特徴量を抽出する。 RA-CLIPとオリジナルCLIPの違いをイメージしやすいようにたとえると、テスト段階でCLIPは暗記・理解できた概念にしか正しく答えられないという特徴に対して、RA-CLIPは問題に関連する参考情報を見ながらテストを受けられるので、限られた学習でさまざまな概念をきちんと理解できていなくても、CLIPと比較して得点が上がるという特徴があると考えられる。 入力画像と関連する画像・テキストペアの検索の実現: 入力画像と参照セットにおける画像の特徴量を教師なし学習したViTモデル(DINO)で抽出し、類似度が高い上位Kの画像と対応するテキストを参照セットから取得。また、学習段階ではこの特徴抽出モデルのパラメータは凍結される。 原論文 Figure 3 から引用 上図はRAMの処理の流れを示している: (ViT:DINO)と (Transformer:SentenceT)はそれぞれ事前に学習したシングルモーダルのエンコーダーで、パラメータはRA-CLIPの学習段階で更新されない。 と で参照セットから検索できた関連画像・テキストペアの特徴量 、 を抽出し、Multi-head Attention blockによって埋め込み特徴量 、 を生成し、最終的に拡張された を取得。 実験 データセット(baseline): 参照セット:YFCC15Mからランダムサンプリング(1.6 millionの画像・テキストペア) 学習セット:YFCC15Mその他のデータ(13 million の画像・テキストペア) 下図は学習データセットの例を示している。 出典: https://huggingface.co/datasets/Ziyang/yfcc15m テストデータ: ImageNetやCIFAR100といったimage classificationのテストデータセットでzero-shot推論 モデル構造: 画像エンコーダー:ViT-B/32 特徴量次元数768 テキストエンコーダー:BERT-base 特徴量次元数768 結果 下図は定量評価の結果を示している。 原論文 Table 1 から引用 原論文 Table 3 から引用 CLIPとRA-CLIPのbaseline(ID1 & ID5)では同じ量の学習データセットを利用していたが、zero-shotの画像分類テストの結果はRA-CLIPの方が精度が高く(+15.8%)、提案手法の有効性を示した。 複数の画像分類データセットにおいてzero-shot/linear probe(学習済みのエンコーダーを凍結して新たにclassification headを学習する)の平均精度がそれぞれ+12.7%/+6.9%向上され、提案手法の導入により汎用性能の向上を実現した。 原論文 Figure 5 から引用 下図は定性評価の結果を示している。RA-CLIPが正しく識別できたケースの参照セット検索プロセスと識別結果から、RAMが正しい参考情報を用いて入力画像の特徴量をより豊かにできることを示している。 原論文 Figure 4 から引用 上図は参照セットの規模とzero-shot画像分類精度の関連性を示している。水平軸が対数スケールでプロットされているため、参照セットを拡張し続けると性能が飽和になってしまう。 Pros&Cons Pros:「参考資料持ち込み可能なテスト」により、限られた学習データセットでCLIPモデルの精度向上が実現できる。 Cons:Vanilla CLIPと比較して、類似画像検索による特徴抽出や類似度算出の処理と、RAMモジュールの特徴量拡張処理(たとえるとテストの際に参考資料から関連情報を探すこと)が必要で、全体の計算量が増えてしまう。 Fine-tuned CLIP Models are Efficient Video Learners 3 概要 背景: CLIPやALIGNなどの事前学習済みの視覚言語(VL)モデルは、インターネットから集めてきた数億の画像・テキストペアを用いて学習し、分類、検出、セグメンテーションなどの多くのタスクにおいて強力な汎化性能とゼロショット能力を獲得した。しかし映像における情報量は画像より遥かに多いため、映像・テキストペアの学習データを用意するコストも膨大であり、映像タスクのためのCLIPをゼロから学習することはほぼ不可能である。従って、事前学習済みの画像言語モデルを映像ベースのタスクに適応することが必要となる。 最近の映像ベースのアプローチでは、空間的時間的モデリングのためにCLIPの表現を追加の学習可能なコンポーネントとして採用した。しかし、事前学習済みのCLIPエンコーダーをfine-tuneするとともに、新たに導入された時間モデリングコンポーネントがCLIPの汎化能力を妨げてしまう。 Contribution: 画像ベースのCLIPを映像のタスクに適応させるためのViFi-CLIP(Video Finetuned CLIP)と呼ばれるベースラインを提案。CLIPのfine-tuningが映像特有の帰納バイアスを学習するのに十分であることを示した。 提案手法はzero-shot、base-to-novel generalization、few-shot、fully-supervised tasksを含む4つの異なる設定で実験した結果、SotA手法より優れた性能を示した。 また、論文で提案した「Bridge&prompt」手法はアノテーション済みの学習データが少ない領域において、fine-tuningとプロンプト学習によりモダリティギャップを埋めることに成功し、手法の有効性を示した。 提案手法 下図は提案手法の処理流れを示している。 原論文 Figure 3 から引用 CLIPの汎化性能を低下させるコンポーネントを新規追加せず、temporal pooling(average pooling)を用いた単純なフレームレベルの後期特徴集約により、CLIPの出力特徴量の時間的情報の取りまとめを実現。 テキストエンコーダーでは、映像を表すプロンプト(例えば”a photo of a ”)を1つの埋め込み特徴量に変換し、映像との対応関係を利用して対比学習を行った。 ViFi-CLIPでは、画像エンコーダーとテキストエンコーダー両方でfull fine-tuningを実施 実験 ViFi-CLIPの汎化能力を分析するために、2つの問題設定で評価する: Zero-shot settingによるクロスデータセットの汎化性能の評価 モデルはソースデータセットで訓練され、そのままダウンストリームの異なるデータセットに転移され評価する。 Base-to-novel settingによる新しいクラスでの汎化性能の評価 提案されたベースと新しいクラスの分割は、全カテゴリを均等な2つのグループに分け、最も頻繁に発生するクラスをベースクラスとしてグループ化する。モデルはベースクラスで学習され、ベースおよび新しいクラスの両方で評価する。 Few-shot setting データセットからK-shotのデータがランダムサンプリングされ学習に利用される。データセットのvalidation setで評価する。 Fully-supervised setting データセットの全てのtraining setで学習し、test setで評価する。 結果 下図は定量評価の結果を示している。 原論文 Table 1, Table 2 から引用 ViFi-CLIPの汎化性能が従来手法より高い Zero-shot settingでは、ゼロショットアクション認識に特化したシングルモーダル手法と画像ベースのマルチモーダルVLモデルを映像行動認識に適応させたモデルと比較して、ViFi-CLIPの方がクロスドメインでの精度が高い Base-to-novel settingでは、 帰納バイアスを利用して コンポーネント を追加したモデルと比較して、 ViFi-CLIPの方がベース精度と新しいクラスでの精度が高い 原論文 Table 3 から引用 原論文 Table 4 から引用 ViFi-CLIPの教師あり学習の性能も従来手法より優れている(または同レベル) Few-shot settingでは、ViFi-CLIPはshot数(K)の増加とともに精度が上がる傾向があり、全てのショットで従来手法より精度が優れていることを示している Fully-supervised settingでは、ViFi-CLIPは時間モデリングのために追加で設計された学習可能なコンポーネントを使用する手法と比較して同レベルの精度を達成 下図は定性評価の結果を示している。 原論文 Figure 1 から引用 ViFi-CLIPの埋め込みは、より良い分離が実現され、CLIPの単純なfine-tuningだけでも適切な帰納バイアスを学習し、映像内の時間情報をモデル化するために専用のコンポーネントを持つ手法に対して競争力のある性能を発揮できることを示している 原論文 Figure 4 から引用 ViFi-CLIPは、時間的手がかりから物体間の関係やシーンのダイナミクスを学習し、高速移動する部分と物体に焦点を当てることで、ビデオ固有の情報をエンコードする能力を示している 下図は処理性能の評価結果を示している。 原論文 Table 5 から引用 余計なコンポーネントを使用していないため、他の手法と比較してFLOPsが低く、トレーニングパラメータの規模も少なくなる。 Pros&Cons Pros:本論文で提案したViFi-CLIPのベースラインでは、ほとんどCLIPの構造を改変せず、シンプルなfine-tuningだけでもVanilla CLIPを映像ドメインに適応させることができる。精度と処理性能の両方において、映像内の時間情報をモデル化するために専用のコンポーネントを持つ従来手法より優れている。 Cons:専用のコンポーネントを持つ手法と比較して、zero-shotの映像認識タスクにおいて汎化性能が優れている一方、教師あり学習の場合だと性能が下がることが確認される。 Top-Down Visual Attention from Analysis by Synthesis 4 概要 背景: 人間の注意方法 トップダウン型注意:選ぶべき事前知識を持ち、注目すべきものをピックアップしそれ以外の情報を省くようにバイアスを掛けて見つけ出すこと ボトムアップ型注意:事前知識なく、他より明らかに目立つもの、異質なものなどを見つけ出すこと 先行研究では人の知覚システムにおけるボトムアップ型注意のメカニズムは合成による分析( Analysis by Synthesis )を実行した結果であるという仮説が立てられている 入力画像と画像の潜在的原因に関する高レベルの事前分布の両方に依存 Analysis by Synthesisを通して異なるオブジェクトの低レベルの認識を事前知識として持ち、トップダウンの知識として定式化される 既存の研究は概念的なのでモデル設定の指針になりにくかった Contribution: 人間の視覚的なトップダウン型の注意方法とされているAnalysis by Synthesisを取り入れた手法(AbSViT, Analysis-by-Synthesis Vision Transformer)の利用により、VQA(Vision Q&A)やゼロショット検索といった画像に対する質問に関連する部分をアテンションするタスク、画像認識、セグメンテーションタスクで精度向上が実現できた。 提案手法 下図は提案手法の処理流れを示している。 (a) ・各ステップの操作は紫色、その他は灰色で色分けする。 ・AbsviTはまず画像をフィードフォワード経路に通す。 ・出力トークンは事前ベクトルξとの類似度によって重み付けす。 ・デコーダを通して各自己注意モジュールにフィードバックされ、最終フィードフォワード実行のトップダウン入力となる。 (b) ・自己注意へのトップダウン入力は値行列に加えられるが、他の部分は変わらない。 原論文 Figure 3 から引用 下図は定性評価の結果を示している。 各画像に対して、ボトムアップ注意は両方の物体を強調する。 これに対して、異なるクラスプロトタイプを事前学習として用いることで、異なる物体に注目するようにトップダウン注意を制御でき、それに応じて分類結果も変化する。 原論文 Figure 4 から引用 データセット VQAについては、VQAv2をトレーニングおよびテストに使用し、VQA-HATによって収集された人間の注意と注意マップを比較する。ゼロショット画像検索にはFlickr30Kを使用する。 画像分類については、ImageNet-1K(IN)で学習とテストを行い、IN-Cの破損画像、IN-Aの敵対的画像、IN-RとIN-SKの分布外画像でもテストを行う。セマンティックセグメンテーションについては、PASCAL VOC、Cityscapes、ADE20Kでテストしている。 下図はVision-Language Taskの結果を示している。 原論文 Table 1 から引用 原論文 Figure 6 から引用 下図は画像の分類, ロバスト性の結果を示している。 原論文 Table 2 から引用 原論文 Figure 7 から引用 トップダウンのアテンション設計から得られるオブジェクト中心の表現は、破損した画像、敵対的な画像、分布外の画像に対する汎化を可能にする。 結論 著者らは、視覚的なトップダウン型の注意方法であるAbS(Analysis-by-Synthesis)とスパース再構成の機能的等価性に関する先行研究から、 目的志向的なトップダウン変調を行うことで、AbSと同様のスパース再構築を最適化することを示した。その結果、トップダウン型の注意を再現できることを示した。 また、著者らは、AbSを変動的に近似するトップダウン変調ViTモデルであるAbSViTを提案した。AbsViTは制御可能なトップダウン注意を達成し、V&Lタスク、画像分類、ロバスト性においてベースラインよりも改善することを示した。 新たなタスクを提案した論文 Connecting Vision and Language with Video Localized Narratives 5 概要 Vision&Languageのこれまでの研究 Image Captioning:静止画に対して、キャプションの(一部の)単語をGrounding(結びつけ) Localized Narrative :アノテーターが自分で画像を説明しながら、説明している領域をマウスで指定→音声とマウスポインタが同期しているため、各単語の視覚的なGroundingが正確に行える Video Localized Narratives(本論文):静止画→動画に拡張 静止画と動画の違い 静止画:ある一瞬のみ記述 VS 動画:オブジェクト間の関係性や相互作用など一連のイベントを記述 動画の場合より詳細なNarrativeをアノテーション可能である。動画の脈略を参照できる可能性が増え、対象物のco-reference(共参照)問題の解決にもつながる(e.g. 同一の名詞(オウム)がNarrative中に複数回出現し、かつ異なるインスタンスを示す場合、オウムの細かな見た目の違いや動作などで参照先の曖昧性を回避できる) Contribution: Video Localized Narrrativesをアノテーションするプロトコルを提案 アクター(動画の登場人物;人、オウム、背景など)ごとに説明 受動関係が明確になることで複雑なイベントを正確に記述(e.g. 人がオウムを触る/オウムが人に触られている) キーフレームごとに説明 動画に対して説明しようとすると、顕著なオブジェクト(主役)のみを記述する可能性が高い 作成したデータセットをVideo Narrative Grounding (VNG)とVideo Question Answering (VQA)へ適用 従来のVideo Narrative Grounding (VNG) 下図はVNGのタスク定義を示している。 入力:映像、説明文(Narrative)、説明文中の名詞の位置 出力:参照されたオブジェクトのフレームごとのセグメンテーションマスク 原論文 Figure 5 から引用 提案手法 ベースライン( ReferFormer )を拡張 下図はReferFormerの処理流れを示している。 ReferFormerは映像から特徴を抽出するためのVisual Encoderと、説明文から特徴(条件付きクエリ特徴)を抽出するためのText Encoderで構成される。 Text Encoderから抽出した 単語ごとの特徴量 ( )をプールして、文全体の特徴量( )とする これらの2つのモーダルの特徴量をDecodeしてフレーム毎のセグメンテーションマスクを得る 原論文 Figure 2 から引用 ReferFormerの課題 文全体の特徴を用いているが、これが有効なのは「文全体が1つのオブジェクトを記述する場合」 VNGでは1つの動画に対して複数のアクター(オブジェクト)が存在するためそぐわない ReferFormer-VNG(提案手法) アクターごとの Narrativeの名詞に限定して 単語ごとの特徴量( )を抽出、それらをプールして文全体の特徴量とする。 2つの異なるオウムをセグメンテーションに分ける場合、最初の「オウム」のNarrativeの名詞に対してReferFormer-VNGを実行し、次の「オウム」は(1回目と異なる)Narrativeの名詞の特徴を使って2回目に実行する。 本論文ではMouse Traceは学習・評価には使っていない。VQAデータセットを作成する際のみに使用。 データセット 下図はVNGのデータセットを示している。既存データセットに対して、物体間の相互関係を含む状況説明(narrative)とその場所(マウス位置)を付与する。 原論文 Table 1 から引用 下図はOVIS/UVO-ViDLN(提案データセット)を示している。: OVISとUVOに対して、状況説明(narrative)とその場所(マウス位置)を付与する すべての単語(形容詞、動詞を含む)をマウス位置をトレースしてGrounding 原論文 Figure S1 から引用 下図は OVIS を示している。 video segmentation用データセット(e.g. person, fish, vehicle, horse, sheep…) 出典: http://songbai.site/ovis/ 下図は UVO を示している。 video segmentation用データセット(e.g. person, car, chair, bottle…) 出典: UVO論文 Figure 3 Ego4D 一人称視点のみ 一部の名刺のみを矩形でGrounding Epic-Kitchens キッチン内のみ すべての名詞をピクセル単位でGrounding 実験 評価尺度: & Measure と の平均 :空間的な正しさ(認識結果とGroundTruthのマスクのIoU) :クラスの正しさ(各マスクのクラス認識結果のF値; PrecisionとRecallの調和平均) データセット OVIS-ViDLN, UVO-ViDLN 加算名詞のみを採用(e.g. car, parrot)し、stuff categories(e.g. sky, water)は除外。 Method/Dataset OVIS UVO Baseline(Full narrative) 22.9 25.8 Baseline(Noun) 25.7 35.6 Proposed(Best) 32.7 46.4 結論 著者らは、動画に対するキャプショングを解くためのデータアノテーションのプロトコルとデータセットを構築し、ベースラインの手法を提案した。 手法自体はシンプルで効果的ではあるものの、アクターの数だけReferFomer-VNGを実行するために複雑な説明文に対する計算コストが高い。 Visual Programming: Compositional visual reasoning without training 6 概要 背景: これまでの汎用AIシステムを構築するための主なアプローチはエンド・ツー・エンドで学習可能なモデルを用いた大規模な教師なし事前学習と、それに続く教師ありマルチタスク学習だった。しかしこのアプローチでは、各タスク用に整備されたデータセットが必要なので、汎用AIシステムに複雑なタスクを実行させるには、無限とも言えるデータセットが必要になる。したがって、このアプローチで汎用AIシステムを複雑なタスクが実行できるように拡張することは困難である。 例えばテレビ番組「ビッグバン★セオリー」に登場する7人のメインキャラクターをこの画像にタグ付けするというタスクを考える。 このタスクを実行するために、システムはまず指示の意図を理解し、顔を検出し、知識ベースからビッグバン★セオリーの主要登場人物のリストを取得し、登場人物のリストを使用して顔を分類し、認識された登場人物の顔と名前を画像にタグ付けするという一連のステップを実行する必要がある。 これらの各ステップを実行するさまざまな視覚システムや言語システムが存在するが、自然言語で記述されたこのタスク全体を実行することは、現状のエンド・ツー・エンドで訓練されたシステムの範囲を超えている。 出典: https://cvpr2023.thecvf.com/media/cvpr-2023/Slides/22652.pdf Contribution: 人々が実行したいと思うような複雑で多様なタスクに対応する汎用AIシステムを提案 提案手法 大規模言語モデルの文脈内学習能力を利用し、タスク固有のトレーニングを必要とせず、自然言語で記述されたタスクを、エンド・ツー・エンドに特化した学習済みモデルや他のプログラムで処理できるような単純なステップに分解することで、複雑で幅広いタスクに対応できる、 VISPROG というシステムを提案。 VISPROGは、ビジュアルデータ(単一の画像または画像のセット)と自然言語命令の入力からステップのシーケンス(VISPROGプログラム)を生成し、それを実行して解と包括的で解釈可能な根拠の両方を得る。 生成されたプログラムの各行は、市販のコンピュータビジョンモデル、画像処理サブルーチン、またはpython関数など幅広いモジュールのうちの1つを呼び出し実行することでプログラムの後続部分で消費される可能性のある中間出力を生成する。 下図の「Factual Knowledge Object Tagging」の例では、VISPROGによって生成された視覚的プログラムは、顔検出器、知識検索システムとしてのGPT-3、およびオープン語彙画像分類器としてのCLIPを呼び出して、目的の出力を生成する。 原論文 Figure 1 から引用 LLMによるプログラム生成 VISPROGは、GPT-3に自然言語で記述された命令と希望する高レベルプログラムの例をプロンプトし、GPT-3の文脈内学習能力を利用して、実際の命令用のプログラムを出力する。 下図は画像編集タスクに対するプロンプトを示している。これらコンテキスト内のプログラム例は手動で書かれており、通常、画像を添付することなく構築可能。 VISPROG プログラムの各行(プログラムステップ)は、モジュール名、モジュールの入力引数名とその値、出力変数名で構成される。GPT-3が各モジュールの入出力タイプや機能を理解できるように、説明的なモジュール名(例:"Select"、"ColorPop"、"Replace")、引数名(例:"image"、"object"、"query")、変数名(例:"IMAGE"、"OBJ")を使用。 これらのインコンテキストの例は、新しい自然言語命令とともにGPT-3に供給され、画像やその内容を観察することなく、VISPROGは入力画像上で実行可能なプログラム(下図の後段)を生成し、記述されたタスクを実行する。 原論文 Figure 3 から引用 モジュール 下図はVISPROGで実現可能な映像解析処理を示している。 VISPROGは現在、画像理解、画像操作(生成を含む)、知識検索、算術・論理演算などの機能を実現する20のモジュールをサポートしている。 原論文 Figure 5 から引用 VISPROGでは、各モジュールは下図の通りPythonクラスとして実装され、 (i)行を解析して入力引数名と値、出力変数名を抽出する (ii)学習済みニューラルモデルを含む可能性のある必要な処理を実行し、出力変数名と値でプログラム状態を更新する (iii)VISPROGの処理の流れを視覚的に確認できる メソッドを持つ。 モジュールクラスを実装して登録するだけでVISPROG に新しいモジュールを追加することもできる。 原論文 Code 1 から引用 プログラムの実行 プログラムの実行はインタープリターが行う。インタープリターは、以下のような流れで動作する。 (i)プログラムの状態(変数名とその値を対応付けた辞書)を入力で初期化 (ii)その行で指定された入力で正しいモジュールを呼び出しながら、プログラムを行ごとにステップ実行 (iii)各ステップの実行後、プログラム状態をステップの出力名と値で更新 視覚的根拠の提示 各モジュールクラスには、モジュールの入力と出力をHTMLスニペットで視覚的に要約するメソッドも用意されている。 インタープリターは、すべてのプログラムステップのHTML要約を繋ぎ合わせて、プログラムの論理的正しさを分析し最終的な出力を検査するために使用できる視覚的根拠(下図)を提示できる。 こうした視覚的な根拠は、ユーザーが失敗の理由を理解し、パフォーマンスを向上させるために自然言語命令を最小限に調整することも可能にする。 原論文 Figure 4 から引用 実験 VISPROGは、多様で複雑な視覚タスクに適用できる柔軟なフレームワークを提供する。 本実験では空間推論、複数画像に関する推論、知識検索、画像生成と操作の4つのタスクで評価を実施した。 各タスクで使用された入力、出力、およびモジュールは下図の通り。 原論文 Figure 5 から引用 Compositional Visual Question Answering VISPROGの構成的で多段階の視覚的質問応答タスク(GQA)への適性を確認した。 GQAタスクのためのモジュールには、オープン語彙のローカライズ、VQAモジュール、バウンディングボックスの座標や空間的前置詞(above、leftなど)が与えられた画像領域を切り取る関数、ボックスを数えるモジュール、Python式を評価するモジュールなどがある。 例えば、「小さなトラックは、ヘルメットをかぶっている人々の左側にあるか、右側にあるか?」というような質問に対して、VISPROGは、まず「ヘルメットをかぶっている人々」をローカライズし、その人々の左側(または右側)の領域を切り出し、その側に「小型トラック」があるかどうかをチェックし、あれば「left」、なければ「right」を返す。 プロンプト作成ではトレーニングセットから31のランダムな質問に、希望するVISPROGプログラムを手動でアノテーションする。GPT-3には、GQAの各質問に回答するコストを削減するために、このリストからランダムに抽出された、より少ないサブセットを提供する。 Reasoning on Image Pairs (NLVR) VQAモデルは単一の画像に関する質問に答えるように学習されるが、実際には、画像コレクションに関する質問に答えるシステムが必要とされるかもしれない。 例えば、あるユーザーが休暇中の写真アルバムを解析し、次のような質問に答えるようシステムに求めた場合:「エッフェル塔を見た翌日、私たちはどのランドマークを訪れたか?」 VISPROGが複数画像の学習データで訓練することなく、単一画像VQAシステムを使用して、複数画像を含むタスクを解決する能力をNLVRベンチマークで確認する。 通常、NLVRの課題に取り組むには、画像ペアを入力とするカスタム・アーキテクチャをNLVRの訓練セットで訓練する必要がある。対してVISPROGは、複雑なステートメントを、個々の画像に関するより単純な質問と、算術演算子および論理演算子を含むpython式と、画像レベルの質問に対する回答に分解することでこれを実現する。 プロンプト作成ではNLVRの訓練セットで、16のランダムなステートメントについてVISPROGプログラムをアノテーションする。これらの例のいくつかは冗長(類似したプログラム構造)であるため、4つの冗長なものを削除して12例のキュレートされたサブセットも作成する。 Factual Knowledge Object Tagging 名前も知らない画像の中の人物や物体(例えば有名人、企業のロゴ、人気の車とそのメーカー、生物の種等)を識別したい状況において、こうしたタスクを解決するには、人物、顔、物体をローカライズするだけでなく、外部の知識ベースで事実知識を調べ、分類のためのカテゴリーセットを構築する必要がある。 このタスクを、事実知識オブジェクト・タギング(Factual Knowledge Object Tagging)と呼び、VISPROGはGPT-3を暗黙の知識ベースとして使用する。例えばGPT-3に”テレビ番組「ビッグバン★セオリー」の主な登場人物をカンマ区切りで列挙せよ”といった自然言語プロンプトで問い合わせることでカテゴリーセットを生成し、得られたカテゴリーセットを、ローカリゼーションや顔検出モジュールによって生成された画像領域を分類するCLIP画像分類モジュールの分類先として利用する。 このタスク用には14のインコンテキストのプログラム例を作成する。(これらのインコンテキストプログラム例には画像は関連付けられていない) Image Editing with Natural Language テキストからの画像の生成はStable Diffusionなどのモデルにより、ここ数年で目覚ましい進歩を遂げているが、「Daniel Craigの顔を:pで隠す」(非特定化またはプライバシー保護)、「Daniel Craigのカラーポップを作成し、背景をぼかす」(オブジェクトの強調表示)などのプロンプトを処理することは、まだ難しい。 こうしたオブジェクトの置き換え等のような高度な編集を実現するには、まず関心のあるオブジェクトを特定し、置き換えるオブジェクトのマスクを生成し、元の画像とマスクおよびその位置に生成する新しいピクセルの説明を使用して、画像インペインティングモデル(本研究ではStable Diffusion)を呼び出す必要がある。VISPROGは、必要なモジュールとサンプルプログラムを備えていれば、こうした非常に複雑な命令を簡単に扱うことができる。 このタスクでは知識タグ付けと同様に、関連する画像のないインコンテキストの例を 10 個作成する。 結果 プロンプトサイズの影響 GQAとNLVRでは、インコンテキストの例が多いほど性能が向上することが下図から分かる。 原論文 Figure 6 から引用 また、NLVRでは、VISPROGの性能はGQAよりも少ないプロンプトで飽和しているが、これはNLVRのプログラムが必要とするモジュールがGQAよりも少なく、それらのモジュールを使用するためのデモがGQAよりも少ないためであると考えられる。 汎用能力 下図は各タスクにおけるVISPROGの結果を示している。 GQAとNLVRではプロンプト戦略を変更した場合の結果を合わせて報告している。また、知識タギングと画像編集ではプロンプトとして与える自然文命令のチューニングを行った場合の結果も報告している。 原論文 Table 1, Table 2, Table 3, Table 4 から引用 前者2つではVILTモデルとの比較を行っており、GQAではVILTモデルの性能を上回っている。NLVRでは性能が下回っているが、VISPROGはゼロショットでNLVRタスクを実行するのに対して、VILT-NLVRはNVLRでファインチューニングされているので、VILT-NLVRでの結果は性能の上限の目安であり、VISPROGがそれに近い精度であることがわかる。(GQAの方で精度が上回っているのはVISPROGが利用しているVQAモジュールがVILT-VQAのため) 後者2つでは既存モデルでは単体でこのようなタスクを行えるモデルがないことから特定のモデルとの比較はされていないが、一定のレベルでこれらタスクを実行できることと、命令チューニングによってさらなる性能向上が可能なことを示している。下図はVISPROGの現在のモジュールセットで可能な画像編集の例であり、幅広い操作が可能であることを示している。 原論文 Figure 7 から引用 視覚的根拠の有用性 VISPROG による視覚的根拠は、失敗例の徹底的な分析を可能にする。 下図は今回の4タスクにおいて約100サンプルずつエラー分析した結果を示している。GQAでは誤ったプログラムがエラーの主な原因であり、サンプルの16%に影響を及ぼしているということを示している。このことから、失敗した問題に類似した、より多くのインコンテクスト例を提供することによって、エラー発生率が改善される可能性があることが分かる。同様にNLVRではVQAモデルをNLVR用のより優れたVQAモデルに置き換えることで、知識タギングや画像編集タスクでは「リスト」と「選択」モジュールの実装に使用されるモデルを改善することで、エラーを大きく減らせると考えられる。 原論文 Figure 9 から引用 また、下図は視覚的根拠によって明らかになったローカリゼーションエラーが、ローカリゼーションモジュールにとってより良いクエリになるように、ユーザがどのように命令を修正するかを示した例である。(他にも例えば、知識検索のためのより良いクエリを提供することや、Selectモジュールのためのカテゴリ名を提供して、そのカテゴリに属するセグメント化された領域に検索を制限することが含まれる) 実際に知識タギングや画像編集の結果を見ると命令チューニングが性能向上に有効であることがわかる。 原論文 Figure 8 から引用 今後の課題 VISPROGのような汎用視覚システムの性能をさらに向上させるためにはユーザーのフィードバックを取り入れる新しい方法の研究が必要である。 最後に 本記事では、マルチモーダルAIに関するCVPR2023の論文をいくつかピックアップしてご紹介しました。NTT Comは今までユニモーダルAIの研究開発をメインに取り組んで、自動翻訳サービスCOTOHA Translatorや議事メモ作成をサポートするCOTOHA Meeting Assist、映像解析ソリューションCOTOHA Takumi Eyesといったサービスを展開してきました。今後はChatGPTなどのマルチモーダルAI技術の活用も視野に入れて、実証実験や研究開発を進めていきます。 Ye, S., Xie, Y., Chen, D., Xu, Y., Yuan, L., Zhu, C., Liao, J. Improving Commonsense in Vision-Language Models via Knowledge Graph Riddles. In CVPR2023. ↩ Xie, C. W., Sun, S., Xiong, X., Zheng, Y., Zhao, D., Zhou, J. RA-CLIP: Retrieval Augmented Contrastive Language-Image Pre-Training. In CVPR2023. ↩ Rasheed, H., Khattak, M. U., Maaz, M., Khan, S., Khan, F. S. Fine-tuned clip models are efficient video learners. In CVPR2023. ↩ Shi, B., Darrell, T., Wang, X. Top-Down Visual Attention from Analysis by Synthesis. In CVPR2023. ↩ Voigtlaender, P., Changpinyo, S., Pont-Tuset, J., Soricut, R., Ferrari, V. Connecting Vision and Language with Video Localized Narratives. In CVPR2023. ↩ Gupta, T., & Kembhavi, A. Visual programming: Compositional visual reasoning without training. In CVPR2023. ↩
TOC サマリ 概要 検証 - IP Precedence 条件による TE(L3VPN Per-Flow Steering) - 検証項目とトポロジー 検証手順 1. Underlay & VPN & メトリック の設定 2. LSP の定義 3. ip-filter の定義 4. ip-filter を VPN の ingress interface に適用 5. ip-filter、LSP が適用されている事を確認 6. 疎通確認 検証 - CoS 条件による TE(L2VPN Per-Flow Steering) - 検証項目とトポロジー SR OS を PE として用いる際の L2VPN Per-Flow Steering の実現方法 検証手順 1. Underlay & メトリック の設定 2. EVI の設定 3. PXC の設定 4. PXC を用いた EVI 間の接続 5. LSP の定義 6. EVI と LSP の関連付け 7. mac-filter の定義と EVI への適用 8. 疎通確認 まとめ サマリ SR-MPLS で構成されたネットワークにおいて、Per-Flow Steering を実現 SR OS で IP Precedence に基づいた Traffic Engineering (TE) の検証に成功 SR OS で Class of Service (CoS) に基づいた TE の検証に成功 この記事は Multi-AS Segment Routing 検証連載の第 17 回です。目次は こちら 概要 イノベーションセンターの岩田です。普段の業務では Multi-AS Segment Routing に関する技術検証や、ベンチャー企業への技術支援でスマートフォンアプリケーション開発業務などを行なっています。 第 8 回 の記事で IOS XR + Junos の 2 つのベンダー機器で構成される L3VPN において 指定した 5-tuple や IP Precedence に関する条件に従って TE を実現する方法を紹介しました。 今回は新たに Nokia SR OS(Service Router Operating System)を加えた 3 つのベンダー機器から構成される環境において、IP Precedence 条件に従う TE と、CoS 条件に従う TE を実現する方法を紹介します。 検証 - IP Precedence 条件による TE(L3VPN Per-Flow Steering) - 検証項目とトポロジー 以下のような構成で、IP Precedence に基づく TE が実現できるかを検証します。 なお本記事では下記のバージョンで検証しました。 rt01: SR OS 22.7.R1 rt02: IOS XR 7.4.1 rt03: Junos 21.3R1.9 rt04: SR OS 22.7.R1 検証手順 以下の手順で検証します。 Underlay & VPN & メトリック の設定 LSP の定義 ip-filter の定義 ip-filter を VPN の ingress interface に適用 ip-filter、LSP が適用されている事を確認 疎通確認 1. Underlay & VPN & メトリック の設定 設定は省略します。Underlay & VPN の設定は 第 12 回 を、メトリックの設定は 第 15 回 の記事をそれぞれ参照ください。 以下のように L3VPN が構築できている事を確認します。 rt01 [ro:/configure] A:user@rt01# /show router bgp routes vpn-ipv4 =============================================================================== BGP Router ID:10.255.0.1 AS:65000 Local AS:65000 =============================================================================== Legend - Status codes : u - used, s - suppressed, h - history, d - decayed, * - valid l - leaked, x - stale, > - best, b - backup, p - purge Origin codes : i - IGP, e - EGP, ? - incomplete =============================================================================== BGP VPN-IPv4 Routes =============================================================================== Flag Network LocalPref MED Nexthop (Router) Path-Id IGP Cost As-Path Label ------------------------------------------------------------------------------- u*>i 65000:100:192.168.123.0/24 100 None 10.255.0.4 None 20 No As-Path 524284 u*>i 65000:100:192.168.123.254/32 100 0 10.255.0.4 None 20 No As-Path 524284 ------------------------------------------------------------------------------- Routes : 2 =============================================================================== rt04 [/] A:user@rt04# /show router bgp routes vpn-ipv4 =============================================================================== BGP Router ID:10.255.0.4 AS:65000 Local AS:65000 =============================================================================== Legend - Status codes : u - used, s - suppressed, h - history, d - decayed, * - valid l - leaked, x - stale, > - best, b - backup, p - purge Origin codes : i - IGP, e - EGP, ? - incomplete =============================================================================== BGP VPN-IPv4 Routes =============================================================================== Flag Network LocalPref MED Nexthop (Router) Path-Id IGP Cost As-Path Label ------------------------------------------------------------------------------- u*>i 65000:100:192.168.23.0/24 100 None 10.255.0.1 None 20 No As-Path 524284 u*>i 65000:100:192.168.23.254/32 100 0 10.255.0.1 None 20 No As-Path 524284 ------------------------------------------------------------------------------- Routes : 2 =============================================================================== 2. LSP の定義 IP Precedence が 3 の時に適用する LSP を設定します。 [ex:/configure router "Base" mpls] A:user@rt01# info path "rt01_rt03_rt04" { admin-state enable hop 10 { sid-label 16003 } hop 20 { sid-label 16004 } } lsp "for_precedence3" { admin-state enable type p2p-sr-te to 10.254.0.4 primary "rt01_rt03_rt04" { } } 3. ip-filter の定義 受信したパケットの IP Precedence の値に応じて適切な LSP を適用するために ip-filter を定義します。 [ex:/configure] A:user@rt01# info filter ip-filter for_cust-a filter-id 1 entry 1 { match { dscp cs3 } action { forward { vprn-target { bgp-nh 10.255.0.4 vprn "cust-a" lsp "for_precedence3" } } } } entry 100 { action { accept } } 4. ip-filter を VPN の ingress interface に適用 定義した ip-filter を cust-a の sap(service access point) の ingress パラメータとして適用します。 [gl:/configure] A:user@rt01# /info service vprn "cust-a" interface "to_cust-a" sap 1/1/c3/1:0 admin-state enable ingress { filter { ip "for_cust-a" } } 5. ip-filter、LSP が適用されている事を確認 定義した filter が適用されていることと、パケットの転送先が指定した LSP になっていることを確認します。 [/] A:user@rt01# show filter ip "for_cust-a" | no-more =============================================================================== IP Filter =============================================================================== Filter Id : 1 Applied : Yes Scope : Template Def. Action : Drop Type : Normal Shared Policer : Off System filter : Unchained Radius Ins Pt : n/a CrCtl. Ins Pt : n/a RadSh. Ins Pt : n/a PccRl. Ins Pt : n/a Entries : 3 Sub-Entries : 4 Description : (Not Specified) Filter Name : for_cust-a ------------------------------------------------------------------------------- Filter Match Criteria : IP ------------------------------------------------------------------------------- Entry : 1 Description : (Not Specified) Log Id : n/a Src. IP : 0.0.0.0/0 Src. Port : n/a Dest. IP : 0.0.0.0/0 Dest. Port : n/a Protocol : Undefined Dscp : cs3 ICMP Type : Undefined ICMP Code : Undefined Fragment : Off Src Route Opt : Off Sampling : Off Int. Sampling : On IP-Option : 0/0 Multiple Option: Off Tcp-flag : (Not Specified) Option-pres : Off Egress PBR : Disabled Primary Action : Forward (VPRN Target) BGP NH Address : 10.255.0.4 Router : 100 LSP : for_precedence3 Service Label : 16 Extended Action : None Secondary Action : None PBR Down Action : Forward (entry-default) Downloaded Action : Primary Dest. Stickiness : None Hold Remain : 0 Ing. Matches : 0 pkts Egr. Matches : 0 pkts Entry : 100 Description : (Not Specified) Log Id : n/a Src. IP : 0.0.0.0/0 Src. Port : n/a Dest. IP : 0.0.0.0/0 Dest. Port : n/a Protocol : Undefined Dscp : Undefined ICMP Type : Undefined ICMP Code : Undefined Fragment : Off Src Route Opt : Off Sampling : Off Int. Sampling : On IP-Option : 0/0 Multiple Option: Off Tcp-flag : (Not Specified) Option-pres : Off Egress PBR : Disabled Primary Action : Forward Ing. Matches : 75 pkts (5970 bytes) Egr. Matches : 0 pkts =============================================================================== また、LSP が Up していることも確認します。 [/] A:user@rt01# show router mpls sr-te-lsp =============================================================================== MPLS SR-TE LSPs (Originating) =============================================================================== LSP Name Tun Protect Adm Opr To Id Path ------------------------------------------------------------------------------- for_precedence3 4 N/A Up Up 10.254.0.4 ------------------------------------------------------------------------------- LSPs : 1 =============================================================================== 6. 疎通確認 以下のように、想定した TE を実現できている事が確認できました。 IP Precedence が 3 の時の TE 結果 user@vm01:~$ traceroute 192.168.123.1 -t 96 -n -q 1 traceroute to 192.168.123.1 (192.168.123.1), 30 hops max, 60 byte packets 1 192.168.23.254 1.997 ms 2 10.1.3.2 3.714 ms 3 192.168.123.254 3.606 ms 4 192.168.123.1 3.549 ms それ以外のパケットの時の TE 結果 user@vm01:~$ traceroute 192.168.123.1 -n -q 1 traceroute to 192.168.123.1 (192.168.123.1), 30 hops max, 60 byte packets 1 192.168.23.254 1.192 ms 2 10.1.2.2 2.918 ms 3 192.168.123.254 2.497 ms 4 192.168.123.1 2.484 ms また、パケットカウンタを確認すると受信したパケットが各 entry に振り分けられたことが確認できます。 [/] A:user@rt01# show filter ip "for_cust-a" counters =============================================================================== IP Filter =============================================================================== Filter Id : 1 Applied : Yes Scope : Template Def. Action : Drop Type : Normal Shared Policer : Off System filter : Unchained Radius Ins Pt : n/a CrCtl. Ins Pt : n/a RadSh. Ins Pt : n/a PccRl. Ins Pt : n/a Entries : 3 Sub-Entries : 4 Description : (Not Specified) Filter Name : for_cust-a ------------------------------------------------------------------------------- Filter Match Criteria : IP ------------------------------------------------------------------------------- Entry : 1 Ing. Matches : 25 pkts (1950 bytes) Egr. Matches : 0 pkts Entry : 100 Ing. Matches : 100 pkts (7920 bytes) Egr. Matches : 0 pkts =============================================================================== 検証 - CoS 条件による TE(L2VPN Per-Flow Steering) - 検証項目とトポロジー 以下のような構成の L2VPN 上で、CoS(Class of Service)に基づく TE を実現できるかを検証します。 なお本記事では下記のバージョンで検証しました。 rt01: SR OS 22.7.R1 rt02: IOS XR 7.4.1 rt03: Junos 21.3R1.9 rt04: Junos 21.3R1.9 SR OS を PE として用いる際の L2VPN Per-Flow Steering の実現方法 SR OS において、L2VPN Per-Flow Steering を行うためのコマンドや機能はないため、 以下に示す構成のように、複数の EVPN Instance (EVI) とインスタンス間を接続するための port cross-connect(PXC)、mac-filter の機能を組み合わせて実現する必要があります。 rt01 において、対向 PE(rt04)から送られてきたパケットは pbf において受信します。 vm01 から受信したパケットは pbf で受信した後、CoS の値に応じて pbf_cos7 か pbf_default へパケットを転送し、 pbf_cos7 、 pbf_default から送信します。 これを実現するためには、以下の要件を満たすように設定する必要があります。 要件 1 : CoS に基づいた EVI への転送を優先するため、 PBF を行う EVI (EVI 4000) は EVPN で経路を受信させない 仮に EVI 4000 に対向 rt04 の経路が存在するとそちらが優先され、転送用 EVI が使用されなくなるためです。 要件 2 :転送用 EVI が 対向 MAC アドレスとポートの組み合わせを誤って学習しないように、EVPN 越しに受け取った BUM トラフィックをパケット転送用の EVI (EVI 14000、EVI 24000) へ転送させない 仮に EVI 4000 から EVI 14000 に BUM を転送してしまうと、EVI 14000 はその送信元 MAC アドレスをみて、転送先を EVPN 経路ではなく EVI 4000 に戻るポートへ指定するテーブルを作成してしまい、 EVI 4000 と EVI 14000 の間でループが発生するためです。 検証手順 以下の手順で検証します。 Underlay & メトリック の設定 EVI の設定 PXC の設定 PXC を用いた EVI 間の接続 LSP の定義 EVI と LSP の関連付け mac-filter の定義と EVI への適用 疎通確認 1. Underlay & メトリック の設定 省略します。 Underlay & VPN の設定は 第 13 回 を、メトリックの設定は 第 15 回 の記事をそれぞれ参照ください。 2. EVI の設定 PBF 用のインスタンス 1 つと、転送用のインスタンス 2 つ、計 3 つのインスタンスを立てます。 要件 1 を満たすために経路送受信を reject するポリシーを作成し、以下のように適用します。 PBF 用のインスタンス: vsi import 時に適用する(経路を受信しない) 転送用のインスタンス: vsi export 時に適用する(経路を送信しない) 経路送受信を拒否するためのポリシー [gl:/configure] A:user@rt01# info policy-options policy-statement "all-reject" entry 1 { action { action-type reject } } PBF 用 EVI [gl:/configure service vpls "pbf"] A:user@rt01# info admin-state enable service-id 4000 customer "cust-a" bgp 1 { route-distinguisher "10.255.0.1:4000" vsi-import ["all-reject"] route-target { export "target:65000:4000" import "target:65000:4000" } } bgp-evpn { evi 4000 mpls 1 { admin-state enable auto-bind-tunnel { resolution filter resolution-filter { sr-isis true } } } } sap 1/1/c4/1:4001 { admin-state enable } CoS が 0(デフォルト値)のパケット転送用 EVI [gl:/configure service vpls "pbf_default"] A:user@rt01# info admin-state enable service-id 14000 customer "cust-a" bgp 1 { route-distinguisher "10.255.0.1:14000" vsi-export ["all-reject"] route-target { import "target:65000:4000" } } bgp-evpn { evi 14000 mpls 1 { admin-state enable auto-bind-tunnel { resolution any } } } CoS が 7 のパケット転送用 EVI [gl:/configure service vpls "pbf_cos7"] A:user@rt01# info admin-state enable service-id 24000 customer "cust-a" bgp 1 { route-distinguisher "10.255.0.1:24000" vsi-export ["all-reject"] route-target { import "target:65000:4000" } } bgp-evpn { evi 24000 mpls 1 { admin-state enable auto-bind-tunnel { resolution any } } } 3. PXC の設定 EVI 同士を接続するために PXC を設定します。 PXC には物理ポートを消費するモードと消費しないモードがありますが、本記事の検証では後発で開発された後者を使用します。 以下のように pxc port を接続し、EVI 同士を接続します。 pxc-1.a: pbf_default <-> pxc-1.b: pbf pxc-2.a: pbf_cos7 <-> pxc-2.b: pbf PXC の詳しい仕様を知りたい方は こちら を参照ください。 card 1 { card-type iom-1 mda 1 { mda-type me6-100gb-qsfp28 xconnect { mac 1 { loopback 1 { bandwidth 100 } loopback 2 { bandwidth 100 } } } } } port-xc { pxc 1 { admin-state enable port-id 1/1/m1/1 } pxc 2 { admin-state enable port-id 1/1/m1/2 } } port 1/1/m1/1 { admin-state enable } port 1/1/m1/2 { admin-state enable } port pxc-1.a { admin-state enable ethernet { mode hybrid encap-type dot1q } } port pxc-1.b { admin-state enable ethernet { mode hybrid encap-type dot1q } } port pxc-2.a { admin-state enable ethernet { mode hybrid encap-type dot1q } } port pxc-2.b { admin-state enable ethernet { mode hybrid encap-type dot1q } } 設定した PXC port が Up していることを確認します。 A:user@rt01# /show port =============================================================================== Ports on Slot 1 =============================================================================== Port Admin Link Port Cfg Oper LAG/ Port Port Port C/QS/S/XFP/ Id State State MTU MTU Bndl Mode Encp Type MDIMDX ------------------------------------------------------------------------------- 1/1/c1 Up Link Up conn 100GBASE-LR4* 1/1/c1/1 Up Yes Up 9212 9212 - hybr dotq cgige 1/1/c2 Up Link Up conn 100GBASE-LR4* 1/1/c2/1 Up Yes Up 9212 9212 - hybr dotq cgige 1/1/c3 Up Link Up conn 100GBASE-LR4* 1/1/c3/1 Up Yes Up 1506 1506 - hybr dotq cgige 1/1/c4 Up Link Up conn 100GBASE-LR4* 1/1/c4/1 Up Yes Up 9212 9212 - hybr dotq cgige 1/1/c5 Up Link Up conn 100GBASE-LR4* 1/1/c5/1 Up No Down 9212 9212 - hybr dotq cgige 1/1/c6 Up Link Up conn 100GBASE-LR4* 1/1/c6/1 Up No Down 9212 9212 - hybr dotq cgige 1/1/m1/1 Up Link Up anchor 1/1/m1/2 Up Link Up anchor =============================================================================== Ports on Slot A =============================================================================== Port Admin Link Port Cfg Oper LAG/ Port Port Port C/QS/S/XFP/ Id State State MTU MTU Bndl Mode Encp Type MDIMDX ------------------------------------------------------------------------------- A/1 Up Yes Up 1514 1514 - netw null faste MDI A/3 Down No Down 1514 1514 - netw null faste A/4 Down No Down 1514 1514 - netw null faste =============================================================================== Ports on Port Cross Connect 1 =============================================================================== Port Admin Link Port Cfg Oper LAG/ Port Port Port C/QS/S/XFP/ Id State State MTU MTU Bndl Mode Encp Type MDIMDX ------------------------------------------------------------------------------- pxc-1.a Up Yes Up 9208 9208 - hybr dotq cgige pxc-1.b Up Yes Up 9208 9208 - hybr dotq cgige =============================================================================== Ports on Port Cross Connect 2 =============================================================================== Port Admin Link Port Cfg Oper LAG/ Port Port Port C/QS/S/XFP/ Id State State MTU MTU Bndl Mode Encp Type MDIMDX ------------------------------------------------------------------------------- pxc-2.a Up Yes Up 9208 9208 - hybr dotq cgige pxc-2.b Up Yes Up 9208 9208 - hybr dotq cgige =============================================================================== 4. PXC を用いた EVI 間の接続 PXC を Virtual Private LAN Service (VPLS) の SAP として設定することで EVI に PXC port を接続します。 要件 2 で述べた EVI pbf において EVPN 経由で受け取った BUM トラフィックを PXC へ流さないようにするため、split horizon group の設定を bgp-evpn と sap pxc-x.b:0 の階層へ追加します。 [gl:/configure] A:user@rt01# info service vpls "pbf" { bgp-evpn { split-horizon-group "SHG-pbf" } split-horizon-group "SHG-pbf" { } sap pxc-1.b:0 { admin-state enable split-horizon-group "SHG-pbf" } sap pxc-2.b:0 { admin-state enable split-horizon-group "SHG-pbf" } } vpls "pbf_cos7" { sap pxc-2.a:0 { admin-state enable } } vpls "pbf_default" { sap pxc-1.a:0 { admin-state enable } } 各 EVI で PXC が紐づいていることが確認できます。 [/] A:user@rt01# show service id 4000 sap =============================================================================== SAP(Summary), Service 4000 =============================================================================== PortId SvcId Ing. Ing. Egr. Egr. Adm Opr QoS Fltr QoS Fltr ------------------------------------------------------------------------------- pxc-1.b:0 4000 1 none 1 none Up Up pxc-2.b:0 4000 1 none 1 none Up Up 1/1/c4/1:4001 4000 1 mac 1 none Up Up ------------------------------------------------------------------------------- Number of SAPs : 3 ------------------------------------------------------------------------------- =============================================================================== [/] A:user@rt01# show service id 14000 sap =============================================================================== SAP(Summary), Service 14000 =============================================================================== PortId SvcId Ing. Ing. Egr. Egr. Adm Opr QoS Fltr QoS Fltr ------------------------------------------------------------------------------- pxc-1.a:0 14000 1 none 1 none Up Up ------------------------------------------------------------------------------- Number of SAPs : 1 ------------------------------------------------------------------------------- =============================================================================== [/] A:user@rt01# show service id 24000 sap =============================================================================== SAP(Summary), Service 24000 =============================================================================== PortId SvcId Ing. Ing. Egr. Egr. Adm Opr QoS Fltr QoS Fltr ------------------------------------------------------------------------------- pxc-2.a:0 24000 1 none 1 none Up Up ------------------------------------------------------------------------------- Number of SAPs : 1 ------------------------------------------------------------------------------- =============================================================================== 5. LSP の定義 転送用の各 EVI にて受信した経路に対し、設計に従った LSP を定義することで EVI へ関連付けを行います。 定義した LSP と EVI の関連付けには admin-tag 機能を用います。 Dynamic TE の LSP と admin-tag を定義します。 [gl:/configure routing-options] A:user@rt01# info admin-tags { admin-tag "tag-igp-metric" { } admin-tag "tag-te-metric" { } route-admin-tag-policy "RATP-igp" { include "tag-igp-metric" { } } route-admin-tag-policy "RATP-te" { include "tag-te-metric" { } } } [gl:/configure router "Base" mpls] A:user@rt01# info path "metric-te-path" { admin-state enable } lsp "dynamic-metric-IGP" { admin-state enable type p2p-sr-te to 10.255.0.4 vprn-auto-bind true path-computation-method local-cspf metric-type igp admin-tag "tag-igp-metric" { } primary "metric-te-path" { admin-state enable } } lsp "dynamic-metric-TE" { admin-state enable type p2p-sr-te to 10.255.0.4 vprn-auto-bind true path-computation-method local-cspf metric-type te admin-tag "tag-te-metric" { } primary "metric-te-path" { admin-state enable } } 6. EVI と LSP の関連付け EVI の経路 import 時に admin-tag を指定することで特定の LSP と紐づけます。 [gl:/configure policy-options] A:user@rt01# info community "target-4000" { member "target:65000:4000" { } } policy-statement "import-cos7" { entry 1 { from { community { name "target-4000" } } action { action-type accept admin-tag-policy "RATP-te" } } } policy-statement "import-default" { entry 1 { from { community { name "target-4000" } } action { action-type accept admin-tag-policy "RATP-igp" } } } [gl:/configure service vpls "pbf_default"] A:user@rt01# info bgp 1 { vsi-import ["import-default"] } [gl:/configure service vpls "pbf_cos7"] A:user@rt01# info bgp 1 { vsi-import ["import-cos7"] } 7. mac-filter の定義と EVI への適用 CoS=7 のパケットのみを pxc-2.b:0 、その他を pxc-1.b:0 へ転送する filter を定義し、 pbf の SAP interface へ適用します。 [gl:/configure filter mac-filter "for_vpls-4000"] A:user@rt01# info filter-id 4001 entry 1 { match { dot1p { priority 7 mask 7 } } action { forward { sap { vpls "pbf" sap-id pxc-2.b:0 } } } } entry 10 { action { forward { sap { vpls "pbf" sap-id pxc-1.b:0 } } } } 作成した filter が適用されている事と、パケットの転送先が指定した LSP になっている事を確認します。 [/] A:user@rt01# show filter mac "for_vpls-4000" =============================================================================== Mac Filter =============================================================================== Filter Id : 4001 Applied : Yes Scope : Template Def. Action : Drop Entries : 2 Type : normal Description : (Not Specified) Filter Name : for_vpls-4000 ------------------------------------------------------------------------------- Filter Match Criteria : Mac ------------------------------------------------------------------------------- Entry : 1 FrameType : Ethernet Description : (Not Specified) Log Id : n/a Src Mac : Undefined Dest Mac : Undefined Dot1p : 7/7 Ethertype : Undefined DSAP : Undefined SSAP : Undefined Snap-pid : Undefined ESnap-oui-zero : Undefined Primary Action : Forward (SAP) Next Hop : pxc-2.b:0 Service Id : 4000 PBR Target Status : Up Secondary Action : None PBR Down Action : Drop (entry-default) Downloaded Action : Primary Dest. Stickiness : None Hold Remain : 0 Ing. Matches : 22829 pkts (2417234 bytes) Egr. Matches : 0 pkts Entry : 10 FrameType : Ethernet Description : (Not Specified) Log Id : n/a Src Mac : Undefined Dest Mac : Undefined Dot1p : Undefined Ethertype : Undefined DSAP : Undefined SSAP : Undefined Snap-pid : Undefined ESnap-oui-zero : Undefined Primary Action : Forward (SAP) Next Hop : pxc-1.b:0 Service Id : 4000 PBR Target Status : Up Secondary Action : None PBR Down Action : Drop (entry-default) Downloaded Action : Primary Dest. Stickiness : None Hold Remain : 0 Ing. Matches : 30271 pkts (3202038 bytes) Egr. Matches : 0 pkts =============================================================================== 8. 疎通確認 CoS の値に応じてそれぞれ適切な経路が選択され TE が実現できているかどうかは、 monitor port コマンドを用いて各ポートから送信されているパケットの増減を確認することで確認します。 CoS=0 のとき (default) vm01で ping を打ちながら monitor port を実行します。 1/1/c1/1 ポートから送信されるパケットが増えているかを確認することで、上図の青色の経路を通っていることを確認します。 user@vm01:~$ ping 192.168.29.2 -i 0.2 output packet の数を確認すると 1/1/c1/1 ポートから送信されるパケットが多いことから、 IGP Metric が最小となるような経路を通っていることが確認できます。 [/] A:user@rt01# monitor port 1/1/c1/1 interval 5 =============================================================================== Monitor statistics for Port 1/1/c1/1 =============================================================================== Input Output ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- At time t = 0 sec (Base Statistics) ------------------------------------------------------------------------------- Octets 1429860905 564867974 Packets 4502761 4898538 Errors 0 0 ------------------------------------------------------------------------------- At time t = 5 sec (Mode: Delta) ------------------------------------------------------------------------------- Octets 3100 3100 Packets 25 25 Errors 0 0 ------------------------------------------------------------------------------- At time t = 10 sec (Mode: Delta) ------------------------------------------------------------------------------- Octets 4783 3310 Packets 28 28 Errors 0 0 ... [/] A:user@rt01# monitor port 1/1/c2/1 interval 5 =============================================================================== Monitor statistics for Port 1/1/c2/1 =============================================================================== Input Output ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- At time t = 0 sec (Base Statistics) ------------------------------------------------------------------------------- Octets 141881464 513956143 Packets 1605842 4452348 Errors 0 0 ------------------------------------------------------------------------------- At time t = 5 sec (Mode: Delta) ------------------------------------------------------------------------------- Octets 263 120 Packets 3 1 Errors 0 0 ------------------------------------------------------------------------------- At time t = 10 sec (Mode: Delta) ------------------------------------------------------------------------------- Octets 0 200 Packets 0 2 Errors 0 0 ... CoS=7 のとき (default) CoS を変更後、vm01で ping を打ちながら monitor port を実行します。 1/1/c2/1 ポートから送信されるパケットが増えているかを確認することで、上図の青色の経路を通っていることを確認します。 user@vm01:~$ sudo ip l set dev ens194.4001 type vlan egress-qos-map 0:7 user@vm01:~$ ping 192.168.29.2 -i 0.2 output packet の数を確認すると 1/1/c2/1 ポートから送信されるパケットが多いことから、 TE Metric が最小となるような経路を通っていることが確認できます。 [/] A:user@rt01# monitor port 1/1/c1/1 interval 5 =============================================================================== Monitor statistics for Port 1/1/c1/1 =============================================================================== Input Output ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- At time t = 0 sec (Base Statistics) ------------------------------------------------------------------------------- Octets 1430139849 565046533 Packets 4504418 4900028 Errors 0 0 ------------------------------------------------------------------------------- At time t = 5 sec (Mode: Delta) ------------------------------------------------------------------------------- Octets 4699 144 Packets 27 2 Errors 0 0 ------------------------------------------------------------------------------- At time t = 10 sec (Mode: Delta) ------------------------------------------------------------------------------- Octets 3250 197 Packets 27 2 Errors 0 0 ... A:user@rt01# monitor port 1/1/c2/1 interval 5 =============================================================================== Monitor statistics for Port 1/1/c2/1 =============================================================================== Input Output ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- At time t = 0 sec (Base Statistics) ------------------------------------------------------------------------------- Octets 141893876 513997471 Packets 1605984 4452709 Errors 0 0 ------------------------------------------------------------------------------- At time t = 5 sec (Mode: Delta) ------------------------------------------------------------------------------- Octets 79 3300 Packets 1 27 Errors 0 0 ------------------------------------------------------------------------------- At time t = 10 sec (Mode: Delta) ------------------------------------------------------------------------------- Octets 0 3186 Packets 0 26 Errors 0 0 ... 以上で、想定した L2VPN Per-Flow Steering が実現できていることが確認できました。 まとめ IOS XR 、Junos と SR OS の Multi-vendor 環境における L3VPN、L2VPN 上での Per-Flow Steering の検証結果を紹介しました。 特に L2 での Per-Flow 実現は SR OS に専用の機能が無いため、機能を組み合わせて実現する必要がありました。 次回の記事では TI-LFA を利用した 高速迂回(Fast Reroute)について紹介予定です。 (2023/10/30 追記) 公開しました: [Multi-AS Segment Routing 検証連載 #18] TI-LFA を用いた障害時の高速迂回 と Microloop の回避 (using SR OS with IOS XR / Junos)
この記事では、2023年度現場受け入れ型インターンシップの活動内容をご紹介します。現場受け入れ型インターンシップを通して得られた学びを参考情報として共有します。 目次 目次 はじめに 参加に至った経緯 受け入れ先について インターンシップで取り組んだこと オンボーディング エラーハンドリングの追加 E2Eテストのデプロイ JavaScript用SDKに対する機能追加 感想 おわりに トレーナーからのコメント 参考文献 はじめに こんにちは、インターンシップに参加した 鈴木 誉写 です。大学院ではオーバーレイネットワークプロトコルの研究・開発を行なっています。 2023年8月28日から9月8日までの2週間、”オンライン英会話・オンライン医療などのビデオ通話を実現するプラットフォームサービス「 SkyWay 」の技術開発”というテーマで、NTTコミュニケーションズの現場受け入れ型インターンシップに参加しました。 この記事では、インターンシップに参加した経緯や活動内容について紹介します。 参考:現場受け入れ型インターンシップとは ドコモが仕掛ける数多くの事業の中から厳選したポストにて、実務を体験していただきます。業務体験を通じて通信/ICT業界の仕事が理解できるだけでなく、皆さん自身の成長をお約束する2weeksのインターンシップです。 現場受け入れ型インターンシップ | インターンシップ情報 | NTTドコモ採用 ❗ 2022年に行われたNTTドコモ・NTTコミュニケーションズ・NTTコムウェアの統合により、本インターンシップの受け入れ先はNTTコミュニケーションズですが、募集はNTTドコモを経由しています。 参加に至った経緯 これまでは競技プログラミングに取り組んでいたり、ワークショップ型のインターンシップに参加したことがあったりと、楽しみながら技術力を向上させる機会は多くありました。しかし、これらの経験だけでは、エンジニアとして働く環境にはどのようなものがあるのかを知ることができないと感じていました。 そんな中で、NTTコミュニケーションズの現場受け入れ型インターンシップが目に留まりました。このインターンシップなら、ワークショップ型のインターンシップと比べて、より現場のリアルを体感できます。そのため、本インターンシップなら技術的成長のみならず、社会から求められる力や観点を学べると考え、応募しました。 受け入れ先について 募集要項は、以下のようなものでした(2023年9月21日時点)。 17.オンライン英会話・オンライン医療などのビデオ通話を実現するプラットフォームサービス「SkyWay」の技術開発 ●業務内容 以下の業務を体験していただきます。 ・SkyWayの新機能: 録画・録音/通話品質計測/IoT向けSDKなどの開発 ・SkyWayが提供するJavaScript/iOS/Android SDKのアジャイル開発 ・ビデオ通話機能を実現するサーバ群の機能開発 ・WebRTCの技術情報のリサーチ 詳細はご本人の希望・適正に応じて、決定します。 SkyWayに関しては https://skyway.ntt.com/ を参照ください ●応募要件 【必須】 ・下記いずれかの言語を用いたプログラミング経験が半年以上あること →HTML/CSS/JavaScript, Swift, Kotlin, Java, C++ ・リアルタイムコミュニケーションに興味と学習意欲を持っていること ・エンジニアリングへの興味・関心が高いこと ・プロダクトを見据えたソフトウェア開発を行う意欲があること ・新機能開発に興味があること ・Github/GitLab/BitBucketなどのソースコード管理システムを利用した開発の経験、もしくは知識があること 【推奨】 ・WebRTC/WebSocketなどのリアルタイム通信に関する知識があること ●受け入れ会社 NTTコミュニケーションズ株式会社 ●勤務地 〒108-8118 東京都港区芝浦3-4-1 グランパークタワー 現場受け入れ型インターンシップ | インターンシップ情報 | NTTドコモ採用 SkyWayとは、リアルタイムコミュニケーションを実現するプラットフォームサービスです。SkyWayは、 WebRTC の利用に必要な機能を提供し、サービス開発をサポートします。これにより、ソフトウェア開発者は、自身のアイディアの実現に集中できるようになります。 SkyWayを開発している組織は、ビジネス領域・開発領域・運用領域の全てを取り仕切っています。また、担当する業務のドメインや開発物に応じて、内部的に複数のチームに分かれており、相互に連携して開発を進めています。本インターンシップでは、リアルタイムコミュニケーション用サーバやJavaScript用SDKの開発・運用を行なっているチームに受け入れていただきました。 リアルタイムコミュニケーション用サーバは、一般的なWebアプリケーションサーバで求められる要件に加え、高い安定性やパフォーマンスといった観点も要求されます。また、SDKはお客さまが直接使うものであるため、開発体験の良さも求められます。今回受け入れてくださったチームでは、これらの観点も考慮しながらシステムを開発・運用していました。 インターンシップで取り組んだこと オンボーディング SkyWayのサーバサイドアプリケーション開発では、主にTypeScriptを利用しています。一方、私は選考時点でTypeScriptを書いたことがなく、その旨を社員の方に共有していました。そのため、オンボーディング用課題を提示していただきました。 この課題は、npmパッケージの名前を受け取り、そのインストール数などに基づいて、インストールしても大丈夫そうか否かを返答するAPIを開発するものでした。まず、APIの設計やドキュメンテーションを体験しました。その後、TypeScriptの基本をご指導いただきながら、コーディングを進めました。さらに、テストコードを書く経験を通して、 describe ・ test の挙動や、 beforeAll ・ beforeEach ・ afterAll ・ afterEach の働きを学びました。加えて、初歩的なCI/CDの構築を体験しました。作成したコードは こちら で公開しています。ローカル環境での動作例は以下のとおりです。 <サーバサイド> $ npm run start > npm-checker@1.0.0 start > node build/main.js Server listening at http://0.0.0.0:8080 Package Name: react Repository: facebook/react Last Modified: Sat Sep 23 2023 01:15:32 GMT+0900 (日本標準時) Count of Download: 85877299 Contributors: zpao, gaearon, acdlite, sophiebits, sebmarkbage, jimfb, trueadm, bvaughn, petehunt, chenglou, vjeux, benjamn, yungsters, lunaruan, subtleGradient, kassens, gnoff, rickhanlonii, nhunzaker, necolas, syranide, eps1lon, cpojer, flarnie, koba04, aweary, mondaychen, dependabot[bot], marocchino, kohei-takata <クライアントサイド> $ curl -X POST -v http://localhost:8080/check-package/react * Trying 127.0.0.1:8080... * Connected to localhost (127.0.0.1) port 8080 (#0) > POST /check-package/react HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.79.1 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < content-type: application/json; charset=utf-8 < content-length: 28 < Date: Mon, 25 Sep 2023 08:11:14 GMT < Connection: keep-alive < Keep-Alive: timeout=72 < * Connection #0 to host localhost left intact {"can_use":true,"reason":""}% エラーハンドリングの追加 次なる業務として、SkyWayで稼働しているサーバにおいてハンドリングが漏れていたエラーに対処するというタスクに取り組みました。まずは、既存のコードを読み、課題が残されている箇所の理解を深めました。コードを読む中で、今まで触れてこなかった"階層型アーキテクチャ"や"DI"の概念を学びました。その後、適切にハンドリング処理を追加しました。コーディングはペアプロの形式で実施したため、実践的な知識を得る良い機会になりました。結果的に、修正を加えた箇所は無事マージされました。 E2Eテストのデプロイ 今回私を受け入れてくださったチームは、DevOps 1 の思想に準拠し、SkyWayの開発のみならず運用も担っています。そのため、サーバの状態を監視したり、検出した異常な挙動を報知したりする機構を管理しています。E2Eテストとは、その一環で利用する、SkyWayを用いたE2E通信の実施可否を定常的に確認するシステムです。下図のように現在時刻を画面に描画し、それをリアルタイムで送受信することで、エンドユーザ目線からSkyWayサーバの稼働状況を確認できます。 今回は、E2Eテストにて利用するSDKのバージョンをアップデートした後、デプロイ作業を実施しました。このような本番環境を扱う作業は、手違いが無いよう複数人で実施します。今回は、私もその一員として参加させていただきました。その結果、開発と運用の両面を担うチームの働き方を実感できました。 JavaScript用SDKに対する機能追加 多くのブラウザは、通信環境などの統計情報を取得するWebRTCのAPIを備えています。この統計情報をサーバに集約することで、お客さまサポート時のログ解析などに活用できるようになります。そこで今回は、SkyWayのJavaScript用SDKパッケージから統計情報を受け取り、それらを整形した上でサーバに送信するサポートパッケージを開発しました。この業務の遂行にあたり、本パッケージに必要な機能の洗い出しから参加させていただきました。 コーディングに際しては、通信が失敗した際に再送の有効性に応じて処理が分岐する複雑なロジックに苦戦しました。また、Utility Typesの利用や、以前に送信したデータに依存性がある処理といった、テクニカルな実装が求められる場面もありました。しかしながら、インターンシップ開始時点でTypeScript未経験だったのにもかかわらず、最終的には開発を自走できました。このことを通じて、 社会人基礎力 の一端である主体性や実行力の向上を感じられました。そのため、"現場を体感することで社会から求められる力や観点を学ぶ"という、本インターンシップの目的を達成できました。 感想 CI/CDの構築方法やTypeScriptの便利記法など、多くの技術的な成長を感じられた2週間でした。さらに、社員の方々と共に働いたことで、エンジニアの働き方についても多くの学びを得ることができました。例えば、タスクの重み付けの考え方や、TeachingとCoachingの使い分けなどです。これらの学びは、今後もぜひ活かしていきたいと感じました。 加えて、自分の弱点が明らかになった2週間でもありました。社会に出る前に自身の弱点を自覚できたことは、今後の成長の足がかりとして、とても有意義であったと感じます。 おわりに 本記事は、2023年度現場受け入れ型インターンシップの参加記として、活動内容や感想について書かせていただきました。 親身にサポートしてくださったトレーナーのsublimerさん、暖かく出迎えてくださったイノベーションセンターならびにSkyWayチームの皆さま、成長機会をくださったNTTコミュニケーションズの皆さま、大変学びの多い2週間をご提供いただき、本当にありがとうございました。 トレーナーからのコメント 鈴木さんのトレーナーを担当した、イノベーションセンターの @sublimer です。 鈴木さん、2週間のインターンシップ、お疲れ様でした。 2週間というとても短い期間、かつ、TypeScript未経験という状況で、本当に素晴らしい成果を残してくれたと思っています。 TypeScriptを書いた経験が無いことは事前に伺っていたので、今回のインターンシップでは最初の数日間で学習用の課題に取り組んでいただきました。 学習用の課題は、ゴールを「必須」、「ここまでできるとGood」、「できなくても大丈夫」の3段階に分けて設定し、とりあえず必須のゴールだけ達成できれば業務に取り組めるように設計していました。 しかしながら、鈴木さんには「できなくても大丈夫」のゴールまで達成していただき、スキル習得のスピードにとても驚かされました。 また、インターンシップ後半では、今後リリース予定のSkyWayの新機能開発に取り組んでいただきました。 SDKの機能をゼロから実装していくという業務は、社員でもなかなか経験できるものではないため、苦労した点も多かったかもしれません。 そのような業務にも臆することなく取り組み、短い期間で大きな成果を残していただきました。 通信の状況を収集、記録する機能は、お客さまがトラブルシューティングする際に役立つ、非常に重要な機能になると考えています。 鈴木さんが書いたコードは今後お客さまのサービスに組み込まれ、多くのリアルタイムコミュニケーションを支える機能の一部となります。 リリースされるのはもう少し先ですが、楽しみにしていただければと思います。 最後になりますが、この2週間の経験が鈴木さんの今後の人生に少しでも役立つものとなれば、トレーナーとしてとても嬉しく思います。 そして、今後の研究活動、大学院生活がより充実したものになることを祈っています。 SkyWayでのインターンシップのご参加、ありがとうございました!! 参考文献 Bass, Len, Ingo Weber, and Liming Zhu. DevOps: A software architect's perspective. Addison-Wesley Professional, 2015. ↩
イノベーションセンターの三島と深川です。 普段の業務では、Segment Routing を始めとする経路制御技術や、IPFIX や Streaming Telemetry などの監視技術の検証・運用、高速ソフトウェアルーター「Kamuee」の開発をしています。 今回、我々は 2023/07/22-28 に行われた、IETF 117 に参加しました。 この記事では、IETF 117 の参加を通じて得た経験や現地の様子、各 WG の動向などをご紹介します。 IETF (Internet Engineering Task Force) とは IETF は、インターネット技術の標準化を推進する団体です。 標準化の議論は Working Group (WG) 単位で推進され、主にメーリングリストを通じて議論が行われます。 メーリングリストは誰でも閲覧・参加が可能です。 また、標準化された技術は Internet-Draft (I-D) や Request for Comments (RFC) などとして広く公開されます。 IETF では、年に3回のオンサイトでの会議があり、直近では以下のような日程・開催地となっていました。 (基本的に、アジア/オセアニア・北米・ヨーロッパで、それぞれ1回ずつ開催されます。) オンサイトのミーティングも参加条件はなく、誰でも参加できます。(有料) 2023/03: IETF 116: Yokohama 2023/07: IETF 117: San Francisco 2023/11: IETF 118: Prague 2023/03: IETF 119: Brisbane IETF 116 が2015年7月以来の7年半振りに日本(横浜)で開催されたこともあり、 我々2名は IETF 116 にて初めてオフラインでの参加をしました。 (出典: https://www.ietf.org/) IETF 117 (San Francisco) は、サンフランシスコの中心地にある Hilton San Francisco Union Square で開催されました。 IETF 117での参加セッション 以下では、我々が現地で参加したセッションをいくつかご紹介します。 IETF 117 の全スケジュールはこちら: IETF 117 Meeting Agenda IETF のオンサイトミーティングならではの用語は こちらのページ で紹介されています。 Day1-2: Hackathon IETF のオンサイトでの会議では、本会議である Meeting Week に先んじて2日間の Hackathon が開催されます。(Pre-Meeting Weekend Session) Hackathon では、集まった多くの開発者や専門家が、アイデアや便利なツール、標準化にあたっての running code 開発、相互接続性を検証するための場です。 今回我々は、「IPFIX Exporter w/eBPF」というテーマで、OSS の IPFIX exporter である「 Fluvia Exporter 」を用いた Hackathon を行いました。 Fluvia Exporter は、IETF 116 Hackathon にて開発を開始した、OSS の IPFIX exporter です。 IETF 116、117 での開発を通じ、opsawg の 2つの I-D ( Export of Segment Routing over IPv6 Information in IP Flow Information Export (IPFIX) / Export of On-Path Delay in IPFIX ) に準拠しています。 IETF 117 では opsawg の方々と協力して相互接続検証を行い、無事に動作させることができました。 draft-ietf-opsawg-ipfix-srv6-srh-14 Hackathon 期間中以外でも継続的に opsawg の方々とコンタクトをとりながら実装を進めていました。 今回の Hackathon では、I-D にはまだ記載されていなかったパラメータなどもその場で議論しながら値を決めるなど、現地で参加したからこそできたことが多くありました。 図は、我々が作成した Hackathon での最終報告資料 です。 今回の Hackathon では、SRv6 機能の開発や他の実装 (pmacct・Wireshark) との相互接続を完遂できました。 また、フロー毎の hop-by-hop な遅延 (On-Path Delay) の取得機能についても開発を開始しました。 こちらは Hakacthon 中には完了できませんでしたが、その後も相互接続を目指し実装を進めております。 対応したそれぞれの I-D の詳細については、"Day3-7: WG session" の章でご紹介します。 また、Fluvia Exporter のより詳しい開発背景や設計・実装手法については、 ENOG79 SRv6 対応の IPFIX exporter を開発した話 をご覧ください。 Day3-7: WG session Day3 以降に行われた Meeting Week において、我々が参加した WG session の中から特に面白かったものを抜粋してご紹介します。 他の WG session を含め、全てのスライドや I-D などの資料は IETF 117 の Agenda ページ から確認できます。 Operations and Management Area Working Group (opsawg) opsawg は運用や管理に関する技術を扱う WG です。 特に、既存の WG の範囲外、もしくは新しい WG を作るほどではない「運用と管理」に関するトピックについて議論し、RFC としてまとめることを目的としています。 この opsawg WG の中で特に我々が注目している技術は、YANG・Telemetry・xFlow などの運用監視に使われるプロトコル群です。 ここでは、Hackathon の項目でも触れた2つの I-D の内容を紹介します。 1つめは Export of Segment Routing over IPv6 Information in IP Flow Information Export (IPFIX) です。 この I-D は IPFIX で SRv6 の SRH を扱うための新たな Information Element (IE) を提案しており、SRv6 SRH に含まれる Segment List や Segment Left、また Active Segment の情報などさまざまな値を表現可能にしています。 2つめは Export of On-Path Delay in IPFIX です。 この I-D は、On-Path Delay を取得するための手法を提案しています。 遅延の取得は、機器の持つ Timestamp と、 In-situ OAM (IOAM) で得られるパケット送出時の Timestamp の差を取ることで実現されます。 計測した Timestamp は、フロー毎に IPFIX の IE に格納し送出されます。このように、ネットワークの中間ノードから情報を取得することを、 On-Path Telemetry と呼びます。 上図に、2つの I-D の技術を用いた、SRv6 網における遅延取得手法を示しました。 計測対象となるパケットには、SRv6 の Headend ノードにて Direct EXport (DEX) の option Type で Timestamp が有効になった IOAM ヘッダが付与され、送出時の Timestamp が格納されます。 IOAM ヘッダの付与手法は複数提案されていますが、Timestamp を付与する場合、2023/10 時点では IPv6 の拡張ヘッダに付与する実装のみ存在します。 IOAM ヘッダのついたパケットを受け取ったノードは、受信時の Timestamp との差 (D1-D3) を取得した後、フロー毎に統計処理し、IPFIX によりエクスポートします。 これにより、フロー毎に hop-by-hop な遅延を取得できます。 似た技術として SRv6 を用いて hop-by-hop の遅延情報も取得可能な SRv6 Path Tracing がありますが、 On-Path Delay は、IOAM が提案しているIPv6/MPLS/Geneve/VXLAN-GRE など、さまざまなプロトコルに適用できる利点があります。 我々は multi-AS SR 網で SRv6/SR-MPLS の双方を運用しているため、幅広いプロトコルに適用できる可能性を持つ On-Path Delay に期待しています。 これらの IPFIX 拡張の活用例の1つとして、opsawg のメンバーにより、Applied Networking Research Workshop 2023 (ANRW '23) にて SRv6 ネットワークのアノマリ検知の成果が発表されていたので、次の章でご紹介します。 Applied Networking Research Workshop 2023 (ANRW '23) ANRW は ACM/IRTF によるワークショップであり、IETF で議論されたトピックや課題に関連する研究成果を発表するための場です。 年1回、7月の IETF と併催されており、ANRW '23 は IETF 117 の Day3 に開催されました。 我々は、共に Hackathon を行った opsawg の方から、「Daisy: Practical Anomaly Detection in large BGP/MPLS and BGP/SRv6 VPN Networks」 1 を紹介され、興味を持ったため参加しました。 Daisy では、SRv6 ネットワークを Data-plane・Control-plane・Management-plane の3面で扱い、それぞれの metric を取得します。 各面の metric 取得手法として、Data-plane は Hackathon の項目でも紹介した IPFIXを、Control-plane は BGP Monitoring Protocol (BMP) を、Management-plane は YANG Push ( RFC8639 、 RFC8641 ) をそれぞれ用います。 最終的にはそれぞれの面で集めたメトリックを用いアノマリ検知を目指しており、そのために不足するプロトコルの標準化を行なっています。 Daisy は、SRv6 で metric を取得する手法をプレーン毎に整理し、それぞれで不足する項目を明らかにして標準化に繋げている点が IETF らしい面白い取り組みであると感じています。 我々の SRv6 ネットワークにおける活用も視野に、今後も注目していきたいと思います。 IPv6 Operations (v6ops) v6ops WG は IPv6の運用上の課題を解決することを目的とした WG です。 この WG では、主な目標として以下を掲げています。 IPv6 の運用上の問題を特定し、解決策や回避策を議論する IPv4 とのデュアルスタック環境における問題を特定し、解決策・回避策を議論する IPv6 シングルスタック環境における問題や、IPv6 によるイノベーションについて議論する 運用上の解決策を生み出し、BCP(Best Current Practice)の形で文書化する IPv6 の運用要件を文書化する v6ops WG では、ルーティングプロトコルやDNSの運用などのIPv6の運用と展開に関連する議論も扱うこととなっています。 IETF118 において発表が行われた中から、我々が注目している I-D を2つ紹介します。 1つめは Using DHCP-PD to Allocate Unique IPv6 Prefix per Device in Broadcast Networks です。 この I-D では、1つのノードが内部的に複数の IPv6 アドレスを用いる際、DHCPv6-PD を利用し、そのノードにユニークな IPv6 プレフィックスを割り当てるアプローチを提案しています。 通常、特定のセグメントに接続されたデバイスは、同一のプレフィックスから IPv6 アドレスを生成しますが、本提案ではデバイスは DHCP-PD クライアントとして動作し、DHCPv6-PD を介してプレフィックスを要求します。 クライアントに割り当てられたプレフィックスは、クライアントのリンクローカルアドレスを指すルートとしてファーストホップルータの経路表にインストールされます。 このアプローチにより、あるインターフェースに対する複数アドレスの付与、仮想環境のホスティング、テザリングでのネットワーク提供など、さまざまなユースケースにおける複数の IPv6 アドレスの管理を効率的に実現できます。 2つめは、 IPv6 only iterative resolver utilising NAT64 です。 この I-D は、NAT64 を活用した IPv6 シングルスタック環境において DNS リゾルバーを構成する際の注意点や、修正すべき項目について提案しています。 現在の RFC3901(BCP91) では、リゾルバーは IPv4-only もしくは dual stack であるべき(SHOULD)としていて、IPv6シングルスタック環境ではこの SHOULD の要件を満たすことができません。 また、名前解決の問い合わせ先となる権威サーバも、IPv6で到達できなかったり、A レコードしか登録されていないことが多々あります。 このドラフトでは特に、上記のような前提では IPv6 シングルスタックの環境下で自前のリゾルバーを運用できないという問題に着目し、NAT64 を用いて解決するためのアプローチについて提案しています。 Source Packet Routing In NetworkinG (spring) spring WG は、セグメントルーティング (Segment Routing: SR) と呼ばれる Traffic Engineering (TE) 技術の標準化と拡張を目的とする WG です。 Segment Routing を実現するデータプレーン技術として、MPLS(SR-MPLS)、IPv6(SRv6) の両者について議論が行われています。 この WG では、SR の運用・管理・TE について扱うだけでなく、他のプロトコルとの相互運用についても議論が行われています。 その中で、特に面白かったものとしては、 Problem statement for Inter-domain Intent-aware Routing using Color があります。 この I-D では、複数の AS 同士の SR 網を相互接続することを目的とし、AS を超えて VPN を構成するための Inter-AS option の選び方や、各 AS の Intent を伝えるために考慮すべき点をまとめています。 特に AS 超えた Intent の適用については、 我々の multi-AS SR でも行っているような BGP Extended Communicty Color を用いる方法についてもまとめられており、Inter-AS についてリファレンスするための良い I-D になっています。 また、もう1つのトピックとしては Service Function Chaining (SFC) に関連した I-D が2つ扱われていました。 1つめは SRv6 Context Indicator SIDs for SR-Aware Services で、SRv6-aware な Network Function に対し、処理のコンテキストを新たな Endpoint behavior を用いて伝える手法を提案しています。 2つめは A Framework for Constructing Service Function Chaining Systems Based on Segment Routing で、 Service Function Chaining Architecture (RFC7665) に沿う形で、SR を用いた SFC のアーキテクチャを整理しています。 SFCについては、我々のチームでも神奈川工科大学・ミハル通信株式会社との共同研究において SRv6 を用いた SFC を活用しているため、今後も注目していきたいと思います。 BGP Enabled ServiceS (bess) bess WG は MP-BGP を用いたサービスについての標準化を行なっている WG です。 主要なターゲットは、L3VPN・L2VPN などの VPN 技術であり、データセンターネットワークにおける BGP を用いた VPN のスケーラビリティや DC 環境特有のメカニズム、VPN 技術を用いた SFC (Service Function Chaining) 等のサービスをサポートするオーバーレイのトポロジの構築なども対象としています。 また、bess WG では、データプレーンでのカプセル化については直接扱わないことになっています。 面白かった内容としては、VPN の Inter-AS option BC を標準化するための I-D ( VPN Inter-AS option BC ) が提案されていました。 VPN Inter-AS option は、異なる AS 間で VPN を相互に接続するための技術であり、 RFC 4364 で標準化されています。 この RFC の Section 10. では、接続手法を a)-c) の3種に分類しています。 a) AS 間で VRF 同士を接続することで、VPN を接続する手法 b) eBGP で VPN 経路を広告することで、隣接する AS との間でも VPN を構成し、E2E な VPN を疎結合に接続する手法 c) 各 AS の RR 間で、multi-hop eBGP により VPN 経路情報を交換することで、AS を超えた E2E の VPN を構成する手法 上記の RFC から、一般にそれぞれの方法を Inter-AS option A、option B、option C と呼称します。 図解を添えた 各 option の詳しい解説は [Multi-AS Segment Routing 検証連載 #2] SR-MPLS L3VPN in Multi-AS でも解説しています。 一方、今回提案された option BC では、option B のように ASBR 間で VPN を接続しつつ、option C のように E2E な VPN を構築します。 option BC は、option B のように AS 毎に SID の 名前空間を分離した NW の作成が実現できます。 ただし option BC では、option C のように E2E で SR Policy を作るというようなことはできないため、あくまで疎結合な Inter-AS のユースケースにのみ適していると感じています。 Post-Quantum Use In Protocols (pquip) pquip WG は量子コンピュータに耐性を持つ暗号 (PQC: Post Quantum Cryptography) の適用に関する支援を目的としたワーキンググループです。 従来の暗号が量子コンピュータによって破られる可能性が高いため、PQC の導入とその運用ガイダンスを作るのが主な目的です。 具体的には、 Post-Quantum Cryptography for Engineers などの I-D が出されており、PQCの運用や導入のベストプラクティスを文書としてまとめています。 他の WG とは異なり、既存のプロトコルを更新したり、暗号メカニズムを定義・評価するワーキンググループではないというのが特徴です。 Side Meetings and Private Meetings Side Meeting とは、WG session とは別に開催される有志によるミーティングです。 IETF 公式が用意した Wiki にて募集する Public Side Meeting と、随時開催する Private Side Meeting の2種が存在します。 今回我々は、Hackathon の場で取り組みに興味を持って頂いたエンジニアや、NTT Com の業務に関連する US のエンジニアとの間でセッション外での Side Meeting やランチセッションを複数行いました。 業務内容に関わるものもあるため内容は割愛しますが、今後に繋がる話も生まれたため、現地に参加するメリットの1つであったと感じています。 Day4: IETF 117 Social Event IETF Social は、IETF の参加者に向け、主催者から有料で提供される懇親の場です。 IETF 117 Social は Nokia 主催で、サンフランシスコ近代美術館 (San Francisco Museum of Modern Art、SFMoMA) で行われました。 会場では飲食物も提供され、他のエンジニアと自由に交流できます。 また近代美術館での開催ということで、2F に展示された一部の作品を自由に見ることができました。 Social の場でも I-D に関する今後の実装や共同研究等について他のエンジニアと議論でき、とても有意義な会になりました。 Day7: IETF終了後 - (NTT Research, Inc.)訪問 今回会場となった San Francisco 市内から 車で南に 30分〜1時間程進むと、シリコンバレーがあります。 我々は、IETF 117 終了後にシリコンバレーの SunnyVale にある (NTT Research, Inc.) を訪問しました。 NTT Reaserch は、シリコンバレーに拠点を持つ企業で、暗号学・物理学・医療情報学などさまざまな分野の基礎研究を目的とする組織です。 オフィスでは現地での取り組みや研究内容についてご説明いただきました。 また、すぐ近くには Apple をはじめとするビッグテックのオフィスが多数あるので、帰国前に立ち寄ることができました。 参加してみての感想と今後について 今回、IETF 117 に参加してみての感想として2つのことを感じています。 1つめは現地でのコミュニケーションの重要性についてです。 今回の IETF では、Hackathon や Private Side Meeting を通じて、現地のエンジニアと議論ができました。 どちらの取り組みでも今後の標準化や PoC の実施などにつながる話を得ることができ、リモートからの参加ではなし得ない成果を上げることができました。 2つめは Hackathon の成果です。 IETF 117 Hackathon では、SRv6 IE の実装を実施し、無事に相互接続まで達成できました。計測したデータの具体的な活用手法や我々の活用案など、今後に繋がる話ができたのも良い点であったと感じています。 IETF Hackathon は 1日を通じ濃密なコミュニケーションをとることのできるいい機会であるため、ご興味のある方は是非参加をお勧めします! 次回 IETF118 Prague の参加登録は 8/14 より開始済みです: IETF118 Register Early Birds の締切は 10/23 23:59 (UTC) なので、参加される方は忘れずにご登録ください。 おまけ🦀 IETF 117が開催されたサンフランシスコでは、ダンジネスクラブ(Dungeness Crab、アメリカイチョウガニ)が有名と聞いたので食べてきました🦀。 円安や世界的なインフレを鑑みても、特にベイエリアの物価は高かったですが、このカニはそれに見合うくらい美味しかったです。 Feng, A. H., Francois、P., Frenot, S., Graf, T., Du, W., & Lucente, P. (2023, July). Daisy: Practical Anomaly Detection in large BGP/MPLS and BGP/SRv6 VPN Networks。In Proceedings of the Applied Networking Research Workshop (pp. 8-14). ↩
はじめに こんにちは、ドコモグループのサマーインターンシップ2023に参加した河井です。 普段は大学院で暗号理論の研究をしています。 この記事では、私がこのインターンシップで取り組んだことについて紹介します。 セキュリティ系インターンシップに興味のある人の参考になれば幸いです。 はじめに NA4Sec PJの紹介 インターンシップ概要 脅威検証:攻撃インフラの秘匿 セキュリティに関するクローキングとは サーバ側のクローキングの実装 IPアドレスによるクローキング RefererとUser-Agentによるクローキング 脅威検証:攻撃インフラの構築 OAuth 2.0のデバイス認可付与(RFC8628)とは 認可フローを悪用した攻撃 フィッシング攻撃の検証 おわりに 参考文献 NA4Sec PJの紹介 まずは、私がお世話になったNA4Sec PJについて紹介します。 正式にはNetwork Analytics for SecurityというNTTコミュニケーションズ イノベーションセンターのプロジェクトチームであり、NA4Sec(なよせ)と呼ばれています。 NA4Sec PJは、インターネット上の攻撃インフラの解明・撲滅を目指して活動するプロジェクトです。 具体的には、サイバーセキュリティに関する情報の収集と分析・技術開発・人材育成を行っています。 インターンシップ概要 8/28から9/8までの約2週間、プロジェクトチームの一員としてセキュリティアナリストの仕事を体験しました。 この期間で、私は以下の4点のことに取り組みました。 脅威調査 Cobalt Strikeが何なのか理解する。 脅威分析 Cobalt Strikeが使われた攻撃事例に関するインシデントレポートをダイヤモンドモデルに基づいて分析する。 脅威探索 インターネットスキャナ系検索ツールCensysを使ってインターネット上のC2サーバを見つける。 脅威検証 以下の攻撃インフラに関わる技術について理解する。 攻撃インフラの秘匿に使われるクローキング技術 Dynamic Device Code Phishingと呼ばれるフィッシング攻撃手法 脅威調査・分析・探索については前回のインターンシップに参加された方が紹介されていますので 1 、ここでは脅威検証について紹介しようと思います。 脅威検証:攻撃インフラの秘匿 私は脅威検証として今回、 サーバ側のクローキング技術の検証 に挑戦しました。 セキュリティに関するクローキングとは クローキング(cloaking)は、もともとは「マントを着せる」「覆い隠す」といった意味の単語ですが、そこから転じて「攻撃インフラの秘匿のために使われる技術」を指す用語として使われるようになりました。 フィッシングサイトやマルウェアダウンロードサイトにおいて使われることが多いです。 この記事におけるクローキングの定義は次の通りです。 攻撃対象者には悪性挙動を示し、それ以外には非悪性(良性)挙動を示すことで攻撃の発見を遅らせたり、回避したりする技術 図1 クローキングをする攻撃者 クローキング技術について、攻撃対象者とそれ以外を判別するために使われる情報の例を以下にまとめます。 クローキング技術の実装箇所 利用する情報 活用方法 攻撃者のサイトを閲覧したクライアント OSやブラウザの情報 攻撃対象者かどうか知る マウスの動き 人が操作しているかどうか知る 画面・ウィンドウのサイズ、CPUのコア数 仮想環境(検証環境)かどうか知る 攻撃者のサーバ IPアドレス 特定のIPアドレスからのアクセスを遮断する User-Agent 攻撃対象者かどうか知る Referer 例えば、ブラウザの検索結果からアクセスしてきたユーザだけを狙う サイトにアクセスした回数 初回のアクセス時のみ悪い挙動を見せる (IPアドレスやCookieの情報を使う) サーバ側のクローキングの実装 今回のインターンシップでは、攻撃者のサーバ側で動作するクローキング技術の実装に取り組みました。 クローキングを実装するにあたっては、クラウドサービス上でフィッシングサイトを単純に模擬した実験環境が与えられました。 その環境におけるクローキングの挙動として設定されたゴールは以下の通りです。 攻撃対象者からのアクセス :特定のページを表示(悪性な挙動はなし) それ以外のアクセス :アクセス拒否 課題として達成すべき目標だけが与えられ、その実現手段を自分なりに考えて実装する形式でした。 ここでは、その課題と実現手段について紹介したいと思います。 IPアドレスによるクローキング Torからのアクセス拒否 1つめは、Torからのアクセス拒否です。 インターネット上で稼働しているC2サーバの中にはリサーチャー等からアクセスを防ぐためにTor経由のアクセスを遮断していると考えられるサーバが観測されています。 そこで、それらと同様に「Tor経由で来たアクセスを拒否する」ことが課題として与えられました。 Torからのアクセス拒否を実現するために、今回はTorの出口ノードだと考えられるIPアドレスからのアクセスを拒否することにしました。 探したところGitHub上でTorの出口ノードをまとめているリポジトリ( SecOps-Institute/Tor-IP-Addresses )を見つけたため、今回はここから出口ノードのIPアドレスリストを取得し使用しました。 ただし、このリストは度々更新されていることに注意が必要です。 モバイルキャリアによるクローキング 2つめは、モバイル回線以外のアクセス拒否です。 モバイルを狙ったフィッシングなどではモバイル回線からのアクセスに限定して攻撃を発現させたいケースが考えられます。 そこで「モバイル回線からアクセスが来た場合に限って攻撃が発現する」ことが課題として与えられました。 これを実現する1つの方法として、モバイル回線のIPアドレスからのアクセス以外を拒否することが考えられます。 モバイルキャリアによっては、 スマートフォン向けコンテンツ開発者のために モバイル回線のIPアドレス情報を開示しているケースがあるため、今回はその公開情報を利用して実装しました。 RefererとUser-Agentによるクローキング 3つめは、HTTPリクエストヘッダによる攻撃対象の選別です。 フィッシングサイトには、参照元(Referer)やUser-Agentの情報を使ったクローキングを実装しているものも実在します。 例えば、Refererの情報を利用することでメールセキュリティサービスからのアクセスを遮断していたケースが確認されています。 また、Drive-by-Download攻撃で使われたサイトやフィッシングサイトの中にはUser-Agentの情報を利用することで特定の環境でのみ攻撃が発現するようにしたり、解析ツールやCLIツールからのアクセスを遮断しようとしているケースが確認されています。 そこで「 example.jp を参照元とするアクセスの拒否」や「iPhone/Android以外からのアクセス拒否」といった課題が与えられました。 これは、HTTPリクエストヘッダ内のRefererとUser-Agentの値によって挙動の場合分けをすることによって実現できます。 ところで、HTTPリクエストヘッダの内容はクライアント側でコントロールすることができます。 したがって、リサーチャーは以下のようにヘッダの情報を個別に指定することで、クローキングを回避し悪性挙動を示すコンテンツにたどり着ける可能性があります。 ただし、確実にたどり着くためには、フィッシングサイトがサーバ側でどのようなクローキングを仕込んでいるのか事前に知っている必要があります。 $ curl -H "User-Agent: Android" <URL> 脅威検証:攻撃インフラの構築 今回のインターンシップではNA4Sec PJの他に関連プロジェクトであるRedTeam PJでもお世話になりました。 そこでは、 Dynamic Device Code Phishingという攻撃手法の検証 に挑戦しました。 OAuth 2.0のデバイス認可付与(RFC8628)とは 最初に攻撃手法の説明で必要になるOAuth 2.0のデバイス認可付与( RFC8628 )について紹介します。 OAuth 2.0は認可のためのプロトコルであり、認可を外部に委託するための仕組みです。 デバイス認可付与(RFC8628)は、OAuth 2.0で定義されている認可フローの1つで通称デバイスフローと呼ばれています。 テレビやプリンタなどの入力制限のあるデバイスがリソースへの制限付きアクセスを得る際に使われます。 デバイスフローについて簡単に説明します。 例としてプリンタからオンラインストレージへのアクセスを許可するケースを考えます。 簡単なデバイスフローの流れは以下のとおりです。 プリンタ上のアプリケーションと認可サーバが通信しユーザコードを生成する。プリンタはプリンタのディスプレイなどにユーザコードを表示して、ユーザにユーザコードを伝える。 ユーザはWebブラウザを用いて認可サーバ( https://example.com/device )にアクセスし、必要に応じてユーザ認証をしたあと、ユーザコードを入力する。 プリンタはオンラインストレージにアクセスできるようになる。 つまりプリンタのディスプレイに表示されるユーザコードを、Webブラウザを用いて認可サーバ( https://example.com/device )のフォームに入力することで、プリンタが特定のリソースにアクセスすることを許可できます。 またOAuth 2.0の認可基盤としては、Microsoft Entra ID(MEID。旧Azure AD)などが用いられます。 認可フローを悪用した攻撃 認可フローを悪用した攻撃としてDevice Code Phishingがあります。 Device Code Phishingは、攻撃者が自身で生成したユーザコードと検証用URI( https://example.com/device )をメールなどで被害者に送信したあと、被害者が騙されて攻撃者のユーザコードをそのリンク先で入力することで、攻撃者が被害者のリソースに不正アクセスできる攻撃です。 しかし、ユーザコードには有効期間が設定されているため、被害者がメールをすぐに読まない場合やリンク先にすぐにアクセスしない場合に、この攻撃は失敗してしまいます。 この弱点を克服した攻撃としてDynamic Device Code Phishingがあります。 この攻撃名における"Dynamic"は、ユーザコードを動的に生成することを意味しています。 メールを作成する際にユーザコードを生成するのではなく、被害者がフィッシングサイトにアクセスした後で動的にユーザコードを生成するため、上記の問題が解消され、攻撃に成功しやすくなります。 フィッシング攻撃の検証 今回のインターンシップでは、Dynamic Device Code Phishingにより、MEIDで認証されたユーザから情報を窃取する攻撃を検証しました。 攻撃基盤の構築については、 Black Hills Information Security社のブログ記事 を参考にしました。 構築後は、攻撃者の観点から、フィッシングサイトのURLを実際に踏んだ被害者が属するAzureテナントの情報(ユーザ一覧など)を窃取できることを確認しました。 その後は被害者の観点から、この攻撃に対する防御手法について教えていただきました。 おわりに 2週間で多くの経験をし、学びを得ることができました。 仕事について具体的にイメージでき、今後のサイバーセキュリティに関する勉強の参考になりました。 このインターンシップの機会を作っていただいたNA4Sec PJの皆さま、ありがとうございました。 特に神田さん、坪井さん、鮫嶋さんには NeWork でいつでも質問ができる環境を作っていただきました 2 。 とても過ごしやすかったです。 ありがとうございました。 また、RedTeam PJの皆さまも、興味深いコンテンツを用意していただきありがとうございました。 参考文献 Penghui Zhang et al. "Crawlphish: Large-scale analysis of client-side cloaking techniques in phishing." 2021 IEEE Symposium on Security and Privacy (SP). IEEE, 2021. BLACK HILLS : "Dynamic Device Code Phishing" TakahikoKawasaki(川崎 貴彦) : 図解デバイスフロー(RFC 8628) " インターンシップ体験記 〜Cobalt StrikeのC2サーバ追跡〜 "。とても良い記事です! ↩ NA4Sec PJは原則リモートワークであるため、今回のインターンシップでも基本的には出社せず田舎にある実家からリモートで作業しました。 ↩
はじめに こんにちは、ドコモグループのサマーインターンシップ2023に参加した河井です。 普段は大学院で暗号理論の研究をしています。 この記事では、私がこのインターンシップで取り組んだことについて紹介します。 セキュリティ系インターンシップに興味のある人の参考になれば幸いです。 はじめに NA4Sec PJの紹介 インターンシップ概要 脅威検証:攻撃インフラの秘匿 セキュリティに関するクローキングとは サーバ側のクローキングの実装 IPアドレスによるクローキング RefererとUser-Agentによるクローキング 脅威検証:攻撃インフラの構築 OAuth 2.0のデバイス認可付与(RFC8628)とは 認可フローを悪用した攻撃 フィッシング攻撃の検証 おわりに 参考文献 NA4Sec PJの紹介 まずは、私がお世話になったNA4Sec PJについて紹介します。 正式にはNetwork Analytics for SecurityというNTTコミュニケーションズ イノベーションセンターのプロジェクトチームであり、NA4Sec(なよせ)と呼ばれています。 NA4Sec PJは、インターネット上の攻撃インフラの解明・撲滅を目指して活動するプロジェクトです。 具体的には、サイバーセキュリティに関する情報の収集と分析・技術開発・人材育成を行っています。 インターンシップ概要 8/28から9/8までの約2週間、プロジェクトチームの一員としてセキュリティアナリストの仕事を体験しました。 この期間で、私は以下の4点のことに取り組みました。 脅威調査 Cobalt Strikeが何なのか理解する。 脅威分析 Cobalt Strikeが使われた攻撃事例に関するインシデントレポートをダイヤモンドモデルに基づいて分析する。 脅威探索 インターネットスキャナ系検索ツールCensysを使ってインターネット上のC2サーバを見つける。 脅威検証 以下の攻撃インフラに関わる技術について理解する。 攻撃インフラの秘匿に使われるクローキング技術 Dynamic Device Code Phishingと呼ばれるフィッシング攻撃手法 脅威調査・分析・探索については前回のインターンシップに参加された方が紹介されていますので 1 、ここでは脅威検証について紹介しようと思います。 脅威検証:攻撃インフラの秘匿 私は脅威検証として今回、 サーバ側のクローキング技術の検証 に挑戦しました。 セキュリティに関するクローキングとは クローキング(cloaking)は、もともとは「マントを着せる」「覆い隠す」といった意味の単語ですが、そこから転じて「攻撃インフラの秘匿のために使われる技術」を指す用語として使われるようになりました。 フィッシングサイトやマルウェアダウンロードサイトにおいて使われることが多いです。 この記事におけるクローキングの定義は次の通りです。 攻撃対象者には悪性挙動を示し、それ以外には非悪性(良性)挙動を示すことで攻撃の発見を遅らせたり、回避したりする技術 図1 クローキングをする攻撃者 クローキング技術について、攻撃対象者とそれ以外を判別するために使われる情報の例を以下にまとめます。 クローキング技術の実装箇所 利用する情報 活用方法 攻撃者のサイトを閲覧したクライアント OSやブラウザの情報 攻撃対象者かどうか知る マウスの動き 人が操作しているかどうか知る 画面・ウィンドウのサイズ、CPUのコア数 仮想環境(検証環境)かどうか知る 攻撃者のサーバ IPアドレス 特定のIPアドレスからのアクセスを遮断する User-Agent 攻撃対象者かどうか知る Referer 例えば、ブラウザの検索結果からアクセスしてきたユーザだけを狙う サイトにアクセスした回数 初回のアクセス時のみ悪い挙動を見せる (IPアドレスやCookieの情報を使う) サーバ側のクローキングの実装 今回のインターンシップでは、攻撃者のサーバ側で動作するクローキング技術の実装に取り組みました。 クローキングを実装するにあたっては、クラウドサービス上でフィッシングサイトを単純に模擬した実験環境が与えられました。 その環境におけるクローキングの挙動として設定されたゴールは以下の通りです。 攻撃対象者からのアクセス :特定のページを表示(悪性な挙動はなし) それ以外のアクセス :アクセス拒否 課題として達成すべき目標だけが与えられ、その実現手段を自分なりに考えて実装する形式でした。 ここでは、その課題と実現手段について紹介したいと思います。 IPアドレスによるクローキング Torからのアクセス拒否 1つめは、Torからのアクセス拒否です。 インターネット上で稼働しているC2サーバの中にはリサーチャー等からアクセスを防ぐためにTor経由のアクセスを遮断していると考えられるサーバが観測されています。 そこで、それらと同様に「Tor経由で来たアクセスを拒否する」ことが課題として与えられました。 Torからのアクセス拒否を実現するために、今回はTorの出口ノードだと考えられるIPアドレスからのアクセスを拒否することにしました。 探したところGitHub上でTorの出口ノードをまとめているリポジトリ( SecOps-Institute/Tor-IP-Addresses )を見つけたため、今回はここから出口ノードのIPアドレスリストを取得し使用しました。 ただし、このリストは度々更新されていることに注意が必要です。 モバイルキャリアによるクローキング 2つめは、モバイル回線以外のアクセス拒否です。 モバイルを狙ったフィッシングなどではモバイル回線からのアクセスに限定して攻撃を発現させたいケースが考えられます。 そこで「モバイル回線からアクセスが来た場合に限って攻撃が発現する」ことが課題として与えられました。 これを実現する1つの方法として、モバイル回線のIPアドレスからのアクセス以外を拒否することが考えられます。 モバイルキャリアによっては、 スマートフォン向けコンテンツ開発者のために モバイル回線のIPアドレス情報を開示しているケースがあるため、今回はその公開情報を利用して実装しました。 RefererとUser-Agentによるクローキング 3つめは、HTTPリクエストヘッダによる攻撃対象の選別です。 フィッシングサイトには、参照元(Referer)やUser-Agentの情報を使ったクローキングを実装しているものも実在します。 例えば、Refererの情報を利用することでメールセキュリティサービスからのアクセスを遮断していたケースが確認されています。 また、Drive-by-Download攻撃で使われたサイトやフィッシングサイトの中にはUser-Agentの情報を利用することで特定の環境でのみ攻撃が発現するようにしたり、解析ツールやCLIツールからのアクセスを遮断しようとしているケースが確認されています。 そこで「 example.jp を参照元とするアクセスの拒否」や「iPhone/Android以外からのアクセス拒否」といった課題が与えられました。 これは、HTTPリクエストヘッダ内のRefererとUser-Agentの値によって挙動の場合分けをすることによって実現できます。 ところで、HTTPリクエストヘッダの内容はクライアント側でコントロールすることができます。 したがって、リサーチャーは以下のようにヘッダの情報を個別に指定することで、クローキングを回避し悪性挙動を示すコンテンツにたどり着ける可能性があります。 ただし、確実にたどり着くためには、フィッシングサイトがサーバ側でどのようなクローキングを仕込んでいるのか事前に知っている必要があります。 $ curl -H "User-Agent: Android" <URL> 脅威検証:攻撃インフラの構築 今回のインターンシップではNA4Sec PJの他に関連プロジェクトであるRedTeam PJでもお世話になりました。 そこでは、 Dynamic Device Code Phishingという攻撃手法の検証 に挑戦しました。 OAuth 2.0のデバイス認可付与(RFC8628)とは 最初に攻撃手法の説明で必要になるOAuth 2.0のデバイス認可付与( RFC8628 )について紹介します。 OAuth 2.0は認可のためのプロトコルであり、認可を外部に委託するための仕組みです。 デバイス認可付与(RFC8628)は、OAuth 2.0で定義されている認可フローの1つで通称デバイスフローと呼ばれています。 テレビやプリンタなどの入力制限のあるデバイスがリソースへの制限付きアクセスを得る際に使われます。 デバイスフローについて簡単に説明します。 例としてプリンタからオンラインストレージへのアクセスを許可するケースを考えます。 簡単なデバイスフローの流れは以下のとおりです。 プリンタ上のアプリケーションと認可サーバが通信しユーザコードを生成する。プリンタはプリンタのディスプレイなどにユーザコードを表示して、ユーザにユーザコードを伝える。 ユーザはWebブラウザを用いて認可サーバ( https://example.com/device )にアクセスし、必要に応じてユーザ認証をしたあと、ユーザコードを入力する。 プリンタはオンラインストレージにアクセスできるようになる。 つまりプリンタのディスプレイに表示されるユーザコードを、Webブラウザを用いて認可サーバ( https://example.com/device )のフォームに入力することで、プリンタが特定のリソースにアクセスすることを許可できます。 またOAuth 2.0の認可基盤としては、Microsoft Entra ID(MEID。旧Azure AD)などが用いられます。 認可フローを悪用した攻撃 認可フローを悪用した攻撃としてDevice Code Phishingがあります。 Device Code Phishingは、攻撃者が自身で生成したユーザコードと検証用URI( https://example.com/device )をメールなどで被害者に送信したあと、被害者が騙されて攻撃者のユーザコードをそのリンク先で入力することで、攻撃者が被害者のリソースに不正アクセスできる攻撃です。 しかし、ユーザコードには有効期間が設定されているため、被害者がメールをすぐに読まない場合やリンク先にすぐにアクセスしない場合に、この攻撃は失敗してしまいます。 この弱点を克服した攻撃としてDynamic Device Code Phishingがあります。 この攻撃名における"Dynamic"は、ユーザコードを動的に生成することを意味しています。 メールを作成する際にユーザコードを生成するのではなく、被害者がフィッシングサイトにアクセスした後で動的にユーザコードを生成するため、上記の問題が解消され、攻撃に成功しやすくなります。 フィッシング攻撃の検証 今回のインターンシップでは、Dynamic Device Code Phishingにより、MEIDで認証されたユーザから情報を窃取する攻撃を検証しました。 攻撃基盤の構築については、 Black Hills Information Security社のブログ記事 を参考にしました。 構築後は、攻撃者の観点から、フィッシングサイトのURLを実際に踏んだ被害者が属するAzureテナントの情報(ユーザ一覧など)を窃取できることを確認しました。 その後は被害者の観点から、この攻撃に対する防御手法について教えていただきました。 おわりに 2週間で多くの経験をし、学びを得ることができました。 仕事について具体的にイメージでき、今後のサイバーセキュリティに関する勉強の参考になりました。 このインターンシップの機会を作っていただいたNA4Sec PJの皆さま、ありがとうございました。 特に神田さん、坪井さん、鮫嶋さんには NeWork でいつでも質問ができる環境を作っていただきました 2 。 とても過ごしやすかったです。 ありがとうございました。 また、RedTeam PJの皆さまも、興味深いコンテンツを用意していただきありがとうございました。 参考文献 Penghui Zhang et al. "Crawlphish: Large-scale analysis of client-side cloaking techniques in phishing." 2021 IEEE Symposium on Security and Privacy (SP). IEEE, 2021. BLACK HILLS : "Dynamic Device Code Phishing" TakahikoKawasaki(川崎 貴彦) : 図解デバイスフロー(RFC 8628) " インターンシップ体験記 〜Cobalt StrikeのC2サーバ追跡〜 "。とても良い記事です! ↩ NA4Sec PJは原則リモートワークであるため、今回のインターンシップでも基本的には出社せず田舎にある実家からリモートで作業しました。 ↩
サマリ 概要 検証 responder 機能の検証 IOS XR - SR OS 間 Junos - SR OS 間 controller 機能の検証 SR OS - IOS XR 間 SR OS - Junos 間 考慮事項 まとめ サマリ IOS XR + Junos + SR OS の Multi-vendor 環境におけるリンク遅延計測の動作検証を実施 この記事は Multi-AS Segment Routing 検証連載の第 16 回です。目次は こちら 概要 イノベーションセンターの竹中です。普段の業務では Multi-AS Segment Routing に関する技術検証や、ネットワーク運用効率化のためのコントローラー開発などを行なっています。 第 7 回 の記事では、IOS XR + Junos の 2 ベンダーの機器を用いてリンク遅延を計測する TWAMP について、また計測した値を元にした Delay-Based TE についての説明と検証をしました。 本記事では、SR OS を中心とした Multi-vendor における TWAMP(Two-Way Active Measurement Protocol) の動作検証内容を紹介します。 なお、検証で利用する SR OS 23.3.R1 において、local CSPF(Constrained Shortest Path First) を用いた Delay-Based TE は実現できないため、本記事では対象外とします。 検証 本記事では TWAMP を用いたリンク遅延測定と IS-IS で測定値を広告する方法を紹介します。 動作検証環境は下図の通りです。各ルーター間のリンクは直結です。 検証に用いた機器詳細は以下の通りです。 rt01: Cisco ASR 9901 (IOS XR 7.7.1) rt02: Juniper MX204 (Junos 21.3R1.9) rt03: Nokia 7750 SR-1 (SR OS 23.3.R1) リンク間遅延の測定手法としては SR OS / IOS XR / Junos ともに TWAMP Light 1 形式の実装があるため、具体的には TWAMP Light の設定方法について紹介します。 TWAMP Light の利用に関して、SR OS の設定を中心として次のステップで説明します。 SR OS による responder (測定を受ける) 機能の検証 SR OS による controller (測定を実施する) 機能の検証 なお IS-IS の基本設定の記載は省略します。基本設定は 第 1 回記事 、 第 12 回記事 を参照ください。 responder 機能の検証 SR OS で TWAMP Light の responder 機能が Multi-vendor において利用可能であるかを検証します。 IOS XR / Junos を TWAMP Light の controller として動作させ、IOS XR - SR OS 間、 Junos - SR OS 間を計測することで動作確認を行います。 IOS XR - SR OS 間 rt01 (IOS XR) RP/0/RSP0/CPU0:rt01#show run performance-measurement Fri Jul 21 14:23:46.053 JST performance-measurement interface TenGigE0/0/0/10 next-hop ipv4 10.2.13.2 delay-measurement ! ! rt03 (SR OS) [ex:/configure router "Base" twamp-light] A:user@rt03# info reflector { admin-state enable udp-port 862 prefix 10.2.13.0/30 { description "to_rt01" } } 確認 まず、rt01(IOS XR) にて遅延計測ができていることを確認します。 RP/0/RSP0/CPU0:rt01#show performance-measurement interfaces tenGigE 0/0/0/10 brief Thu Jul 27 14:22:46.970 JST ---------------------------------------------------------------------------------------------------------------------------------------------------------------- 0/0/CPU0 ---------------------------------------------------------------------------------------------------------------------------------------------------------------- Interface Name Tx/Rx Avg/Min/Max/Variance (uSec) -------------------------------------------------------------------------------------------------------------------------------------------------------------- TenGigE0/0/0/10 4/4 13/13/14/0 また、IS-IS で計測結果が広告されていることを確認します。 RP/0/RSP0/CPU0:rt01#show isis database rt01.00-00 verbose Thu Jul 27 14:22:54.545 JST IS-IS 1 (Level-2) Link State Database LSPID LSP Seq Num LSP Checksum LSP Holdtime/Rcvd ATT/P/OL rt01.00-00 * 0x0001286e 0x9a81 1171 /* 0/0/0 (snip) Metric: 20 IS-Extended rt03.00 Local Interface ID: 23, Remote Interface ID: 2 Interface IP Address: 10.2.13.1 Neighbor IP Address: 10.2.13.2 Affinity: 0x00000000 Physical BW: 10000000 kbits/sec Reservable Global pool BW: 0 kbits/sec Global Pool BW Unreserved: [0]: 0 kbits/sec [1]: 0 kbits/sec [2]: 0 kbits/sec [3]: 0 kbits/sec [4]: 0 kbits/sec [5]: 0 kbits/sec [6]: 0 kbits/sec [7]: 0 kbits/sec Admin. Weight: 20 Physical BW: 10000000 kbits/sec Link Average Delay: 13 us Link Min/Max Delay: 11/16 us Link Delay Variation: 2 us ADJ-SID: F:0 B:0 V:1 L:1 S:0 P:0 weight:0 Adjacency-sid:32328 rt03(SR OS) において、広告されている Delay metric が正しく認識できていることを確認します。 [/] A:user@rt03# show router isis database rt01.00-00 detail (snip) TLVs : (snip) TE IS Nbrs : Nbr : rt03.00 Default Metric : 20 Sub TLV Len : 148 LclId : 23 RmtId : 2 IF Addr : 10.2.13.1 Nbr IP : 10.2.13.2 Admin Grp : 0x0 MaxLink BW: 10000000 kbps Resvble BW: 0 kbps Unresvd BW: BW[0] : 0 kbps BW[1] : 0 kbps BW[2] : 0 kbps BW[3] : 0 kbps BW[4] : 0 kbps BW[5] : 0 kbps BW[6] : 0 kbps BW[7] : 0 kbps TE Metric : 20 MaxLink BW: 10000000 kbps Delay : 13 0x0 Delay Min : 11 Max : 16 Delay Var : 2 Adj-SID: Flags:v4VL Weight:0 Label:32328 (snip) Junos - SR OS 間 rt02 (Junos) set protocols isis interface xe-0/1/1.0 delay-measurement rt03 (SR OS) [ex:/configure router "Base" twamp-light] A:user@rt03# info reflector { admin-state enable udp-port 862 prefix 10.2.15.0/30 { description "to_rt02" } } 確認 まず、rt02(Junos) にて遅延計測ができていることを確認します。 user@rt02> show services rpm twamp client Connection Session Sender Sender Reflector Reflector Name Name address port address port __r__12 __r__13 10.2.15.1 63687 10.2.15.2 862 user@rt02> show services rpm twamp client probe-results control-connection __r__12 Owner: __r__12, Test: __r__13 TWAMP-Server-Status: Light, Number-Of-Retries-With-TWAMP-Server: 0 Reflector address: 10.2.15.2, Reflector port: 862, Sender address: 10.2.15.1, sender-port: 53190 Test size: 10 probes Probe results: Response received Probe sent time: Thu Jul 27 14:26:31 2023 Probe rcvd/timeout time: Thu Jul 27 14:26:31 2023 Rtt: 167 usec, Egress jitter: 227 usec, Ingress jitter: -213 usec, Round trip jitter: -2 usec Egress interarrival jitter: 279 usec, Ingress interarrival jitter: 280 usec, Round trip interarrival jitter: 25 usec (snip) また、IS-IS で計測結果が広告されていることを確認します。 user@rt02> show isis database rt02.00-00 extensive IS-IS level 1 link-state database: IS-IS level 2 link-state database: rt02.00-00 Sequence: 0x27335, Checksum: 0x2509, Lifetime: 1183 secs (snip) TLVs: (snip) Extended IS Reachability TLV, Type: 22, Length: 114 IS extended neighbor: rt03.00, Metric: default 20 SubTLV len: 103 IP address: 10.2.15.1 Neighbor's IP address: 10.2.15.2 Local interface index: 361, Remote interface index: 3 Unidirectional link delay: 82 Min unidirectional link delay: 70 Max unidirectional link delay: 108 Unidirectional delay variation: 205 (snip) rt03(SR OS) において、広告されている Delay metric が正しく認識できていることを確認します。 [/] A:user@rt03# show router isis database rt02.00-00 detail (snip) TLVs : (snip) TE IS Nbrs : Nbr : rt03.00 Default Metric : 20 Sub TLV Len : 103 IF Addr : 10.2.15.1 Nbr IP : 10.2.15.2 LclId : 361 RmtId : 3 Delay : 82 0x0 Delay Min : 70 Max : 108 Delay Var : 205 Unresvd BW: BW[0] : 10000000 kbps BW[1] : 10000000 kbps BW[2] : 10000000 kbps BW[3] : 10000000 kbps BW[4] : 10000000 kbps BW[5] : 10000000 kbps BW[6] : 10000000 kbps BW[7] : 10000000 kbps Resvble BW: 10000000 kbps MaxLink BW: 10000000 kbps Admin Grp : 0x0 Adj-SID: Flags:v4BVL Weight:0 Label:1106 (snip) controller 機能の検証 SR OS で TWAMP Light の controller 機能が Multi-vendor において利用可能であるかを検証します。 IOS XR / Junos を TWAMP Light の responder として動作させ、SR OS - IOS XR 間、SR OS - Junos 間を計測することで動作確認を行います。 なお、SR OS は以下の 2 パターンで controller として動作させることができます。 oam-pm: 計測結果はローカルでのみ閲覧可能 test-oam link-measurement: 計測結果は IS-IS で広告可能 本検証では、リンク遅延を IGP にて広告することを目的としているため、 test-oam link-measurement による計測方法のみ紹介します。 SR OS - IOS XR 間 rt01 (IOS XR) ipsla responder twamp-light test-session 1 local-ip 10.2.13.1 local-port 862 remote-ip 10.2.13.2 remote-port any vrf default ! ! ! rt03 (SR OS) [ex:/configure test-oam link-measurement] A:user@rt03# info measurement-template "to_iosxr" { admin-state enable interval 1 last-reported-delay-hold 60 reporting true twamp-light { dest-udp-port 862 } sample-window { threshold { absolute 10 } } } [ex:/configure router "Base" interface "to_rt01"] A:user@rt03# info if-attribute { delay { delay-selection dynamic-preferred static 100 dynamic { measurement-template "to_iosxr" twamp-light { ipv4 { admin-state enable destination 10.2.13.1 source 10.2.13.2 } } } } } [ex:/configure router "Base" isis 0] A:user@rt03# info traffic-engineering-options { advertise-delay true } 確認 まず、rt03(SR OS) にて遅延計測ができていることを確認します。 [/] A:user@rt03# show test-oam link-measurement interface "to_rt01" =============================================================================== Interface Link Measurement Information - to_rt01 =============================================================================== Template Name: to_iosxr Oper State : Up Protocol : IPv4 Oper Source Address : 10.2.13.2 Source Auto-Assigned : No Oper Destination Address : 10.2.13.1 Destination Auto-Assigned: No In-Use Src UDP Port : 49155 In-Use Dst UDP Port : 862 STAMP Session Identifier : 1037 Failure Condition(s) : None Detectable Tx Error : None ------------------------------------------------------------------------------- Reporting ------------------------------------------------------------------------------- Reporting Operational : Yes Delay Measure Last Reported: 19us Timestamp : 2023/07/21 06:22:48 Triggered By : SampleThresholdAbsolute =============================================================================== また、IS-IS で計測結果が広告されていることを確認します。 [/] A:user@rt03# show router isis database rt03.00-00 detail (snip) TLVs : (snip) TE IS Nbrs : Nbr : rt01.00 Default Metric : 20 Sub TLV Len : 86 IF Addr : 10.2.13.2 Nbr IP : 10.2.13.1 MaxLink BW: 10000000 kbps Resvble BW: 10000000 kbps Unresvd BW: BW[0] : 10000000 kbps BW[1] : 10000000 kbps BW[2] : 10000000 kbps BW[3] : 10000000 kbps BW[4] : 10000000 kbps BW[5] : 10000000 kbps BW[6] : 10000000 kbps BW[7] : 10000000 kbps Admin Grp : 0x0 TE Metric : 20 Delay Min : 19 Max : 19 Adj-SID: Flags:v4BVL Weight:0 Label:524279 (snip) rt01(IOS XR) において、広告されている Delay metric が正しく認識できていることを確認します。 RP/0/RSP0/CPU0:rt01#show isis database rt03.00-00 verbose Mon Jul 24 16:37:34.968 JST IS-IS 1 (Level-2) Link State Database LSPID LSP Seq Num LSP Checksum LSP Holdtime/Rcvd ATT/P/OL rt03.00-00 0x00007d2c 0x93cc 1165 /1200 0/0/0 (snip) Metric: 20 IS-Extended rt01.00 Interface IP Address: 10.2.13.2 Neighbor IP Address: 10.2.13.1 Physical BW: 10000000 kbits/sec Reservable Global pool BW: 10000000 kbits/sec Global Pool BW Unreserved: [0]: 10000000 kbits/sec [1]: 10000000 kbits/sec [2]: 10000000 kbits/sec [3]: 10000000 kbits/sec [4]: 10000000 kbits/sec [5]: 10000000 kbits/sec [6]: 10000000 kbits/sec [7]: 10000000 kbits/sec Affinity: 0x00000000 Admin. Weight: 20 Link Min/Max Delay: 19/19 us ADJ-SID: F:0 B:1 V:1 L:1 S:0 P:0 weight:0 Adjacency-sid:524279 SR OS - Junos 間 rt02 (Junos) set services rpm twamp server light port 862 rt03 (SR OS) Junos との相互接続において、計測パケットの padding を Junos が対応しているサイズに合わせる必要があります。 pad-tlv size 46 が該当の設定です。 [ex:/configure test-oam link-measurement] A:user@rt03# info measurement-template "to_junos" { admin-state enable interval 1 last-reported-delay-hold 60 reporting true twamp-light { dest-udp-port 862 pad-tlv-size 46 } sample-window { threshold { absolute 10 } } } [ex:/configure router "Base" interface "to_rt02"] A:user@rt03# info if-attribute { delay { delay-selection dynamic-preferred dynamic { measurement-template "to_iosxr" twamp-light { ipv4 { admin-state enable destination 10.2.15.1 source 10.2.15.2 } } } } } [ex:/configure router "Base" isis 0] A:user@rt03# info traffic-engineering-options { advertise-delay true } 確認 まず、rt03(SR OS) にて遅延計測ができていることを確認します。 [/] A:user@rt03# show test-oam link-measurement interface "to_rt02" =============================================================================== Interface Link Measurement Information - to_rt02 =============================================================================== Template Name: to_iosxr Oper State : Up Protocol : IPv4 Oper Source Address : 10.2.15.2 Source Auto-Assigned : No Oper Destination Address : 10.2.15.1 Destination Auto-Assigned: No In-Use Src UDP Port : 49155 In-Use Dst UDP Port : 862 STAMP Session Identifier : 1038 Failure Condition(s) : None Detectable Tx Error : None ------------------------------------------------------------------------------- Reporting ------------------------------------------------------------------------------- Reporting Operational : Yes Delay Measure Last Reported: 55us Timestamp : 2023/07/27 05:31:51 Triggered By : SampleThresholdAbsolute =============================================================================== また、IS-IS で計測結果が広告されていることを確認します。 [/] A:user@rt03# show router isis database rt03.00-00 detail =============================================================================== Rtr Base ISIS Instance 0 Database (detail) =============================================================================== Displaying Level 1 database ------------------------------------------------------------------------------- Level (1) LSP Count : 0 Displaying Level 2 database ------------------------------------------------------------------------------- LSP ID : rt03.00-00 Level : L2 Sequence : 0x90b3 Checksum : 0xe6f7 Lifetime : 1142 Version : 1 Pkt Type : 20 Pkt Ver : 1 Attributes: L1L2 Max Area : 3 Alloc Len : 1492 SYS ID : 0102.5500.2026 SysID Len : 6 Used Len : 539 TLVs : (snip) TE IS Nbrs : Nbr : rt02.00 Default Metric : 20 Sub TLV Len : 86 IF Addr : 10.2.15.2 Nbr IP : 10.2.15.1 MaxLink BW: 10000000 kbps Resvble BW: 10000000 kbps Unresvd BW: BW[0] : 10000000 kbps BW[1] : 10000000 kbps BW[2] : 10000000 kbps BW[3] : 10000000 kbps BW[4] : 10000000 kbps BW[5] : 10000000 kbps BW[6] : 10000000 kbps BW[7] : 10000000 kbps Admin Grp : 0x0 TE Metric : 20 Delay Min : 55 Max : 55 Adj-SID: Flags:v4BVL Weight:0 Label:524282 (snip) rt02(Junos) において、広告されている Delay metric が正しく認識できていることを確認します。 user@rt02> show isis database rt03.00-00 extensive IS-IS level 1 link-state database: IS-IS level 2 link-state database: rt03.00-00 Sequence: 0x90b3, Checksum: 0xe6f7, Lifetime: 1134 secs (snip) TLVs: (snip) Extended IS Reachability TLV, Type: 22, Length: 97 IS extended neighbor: rt02.00, Metric: default 20 SubTLV len: 86 IP address: 10.2.15.2 Neighbor's IP address: 10.2.15.1 Maximum bandwidth: 10Gbps Maximum reservable bandwidth: 10Gbps Current reservable bandwidth: Priority 0 : 10Gbps Priority 1 : 10Gbps Priority 2 : 10Gbps Priority 3 : 10Gbps Priority 4 : 10Gbps Priority 5 : 10Gbps Priority 6 : 10Gbps Priority 7 : 10Gbps Administrative groups: 0 <none> Traffic engineering metric: 20 Min unidirectional link delay: 55 Max unidirectional link delay: 55 P2P IPV4 Adj-SID - Flags:0x70(F:0,B:1,V:1,L:1,S:0,P:0), Weight:0, Label: 524282 P2P IPv4 Adj-SID: 524282, Weight: 0, Flags: -BVL-- (snip) 考慮事項 検証結果から、各ベンダー機器の組み合わせによってリンク遅延に大きく差があることがわかります。 第 7 回 記事でも言及した通り、相互接続環境での TWAMP を用いたリンク遅延測定結果は必ずしも実態に沿った値となるとは限らないと思われます。 まとめ 本記事では、SR OS を含めた Multi-vendor 環境におけるリンク遅延計測の検証結果を紹介しました。 次回の記事では Multi-AS 環境における Per-Flow TE について紹介予定です。 (2023/10/30 追記) 公開しました: [Multi-AS Segment Routing 検証連載 #17] Per-Flow Steering using SR OS TWAMP Light: https://www.rfc-editor.org/rfc/rfc5357.html#appendix-I ↩
こんにちは、イノベーションセンターの杉本(GitHub: kaisugi )です。普段はノーコードAI開発ツール Node-AI の開発に取り組む傍ら、兼務 1 で大規模言語モデル(LLM:Large Language Model)について調査を行なっています。特に、日本語を中心に学習された LLM への関心があり、 awesome-japanese-llm という日本語 LLM をまとめた Web サイトのメンテナンスにも取り組んでいます。 今回は、LLM に LLM の評価そのものを行わせるという新たなアプローチ( LLM-as-a-judge )についてご紹介します。 ChatGPT の登場以降、国内外で LLM の開発競争が進行しており、モデルの重みが公開されたオープンなモデルも続々と現れています。そのような中で、新しいモデルの構築だけでなく、どのモデルが優れているかを比較検討することが今後ますます重要になると考えられます。 従来の自然言語処理タスクによる評価と異なり、LLM-as-a-judge では実際のテキスト生成に即した評価(≒より実運用に即した評価)が期待できます。一方で、実際に使うにあたってはいくつかの注意点も存在します。本記事では具体例も交えながら LLM-as-a-judge について概観できればと思います。 広がる LLM の選択肢と評価の難しさ LLM-as-a-judge の勃興 LLM-as-a-judge をやってみよう 抽象的な質問の例: AIは夢を見るか? 具体的な質問の例: データサイエンティストAI おわりに 広がる LLM の選択肢と評価の難しさ 2023年現在、LLM を始めとする生成 AI の分野で大きなブレイクスルーが起こっているのは論を待ちません。8月には岸田首相が自ら出向いて東大松尾研の LLM 講座を受講したことも話題になりました。 www.nikkei.com LLM 開発競争において今現在フロントランナーとなっているのは OpenAI の GPT-4 、及びこれをエンタープライズ向けにラップした Microsoft Azure の Azure OpenAI Service でしょう。その一方で、Google Cloud の Vertex AI や Duet AI 、 AWS の Amazon Bedrock など、他のベンダーも LLM をクラウドサービスとして提供する準備を着々と整えています。また、Meta の Llama のような、モデルの重みが公開されたオープンなモデルを活用すれば、オンプレミスでのサービス構築も可能です。 数年後には、サービス提供者側がさまざまな選択肢の中から自分たちの要件に合った LLM を選ぶ時代になることも予想されます。 では、複数の選択肢がある中で、どの LLM が一番良いモデルだと言えるのでしょうか? 最も確実なのは、人間にモデルの出力を見てもらう 人手評価 です。とはいえ、人手評価にはお金や時間、労力がかかってしまいます。 また、MLOps 2 のような機械学習システムを継続的に計測・監視するという考え方に人手評価はあまりそぐいません。 もちろん、LLM を生み出した自然言語処理という分野では 自動評価 も古くから行われてきました。 例えば、質問に対する正答率(Accuracy)やF値(F1-Score)を計算することで、モデルの良さを評価できます。 また、出力されたテキストがどれほど「期待されるテキスト」(参照文)と近いかを計算することでも、モデルの良さを評価できます。 古典的には、翻訳などのタスクでは BLEU (Bilingual Evaluation Understudy) 、要約などのタスクでは ROUGE (Recall-Oriented Understudy for Gisting Evaluation) などの、文字列 (n-gram) の類似度を計算する評価指標が用いられてきました。近年では、この近さの計算に言語モデルを活用する BERTScore のような評価指標も定着しています。 このような従来型の自然言語処理タスク/評価指標を包括するベンチマークとして GLUE や MMLU 、 HELM 、日本語では JGLUE や Stability-AI/lm-evaluation-harness が挙げられます。 しかしながら、モデルが多様なテキストを出力できるようになった現在、これらの従来型の自動評価には限界があると考えられます。 前者のような正答率を計算する評価方法では、モデルに内在するコアの言語理解能力や常識などを計測できますが、テキスト生成能力は計測できません。 また、後者のような参照文と比較する評価方法においても、翻訳や要約のような出力がある程度決まっているタスクならよいものの、対話や創作のような自由度の高いタスクで「参照文」なるものがあるのかという問題があります。そもそも、タスクごとに参照文を新たに作るのも大変な作業です。 LLM-as-a-judge の勃興 既存の自然言語処理タスクによる評価の難しさがある中で、強力な LLM(例: GPT-4)に LLM の評価そのものをやらせようという考え方(LLM-as-a-judge)がにわかに流行し始めています。 LLM-as-a-judge の具体的な方法論についてはいくつかの流派がありますが、おおむね以下の流れで行われる場合が多いです。 事前に LLM を評価するための質問を準備しておく 比較対象となる複数の LLM に質問を投げかけ、それぞれの出力を記録する 最後に、強力な LLM がプロンプトをもとに出力を比較し、最も良い出力を判断する LLM-as-a-judge に関するプレプリント論文として、以下のようなものがあります。 Judging LLM-as-a-judge with MT-Bench and Chatbot Arena [Zheng et al., 2023] AlpacaFarm: A Simulation Framework for Methods that Learn from Human Feedback [Dubois et al., 2023] PandaLM: An Automatic Evaluation Benchmark for LLM Instruction Tuning Optimization [Wang et al., 2023a] Large Language Models are not Fair Evaluators [Wang et al., 2023b] 中でも一番上にある論文 [Zheng et al, 2023] の著者らは、 LMSYS という団体において Vicuna というオープンな LLM の開発や、LLM 比較プラットフォーム Chatbot Arena の運営なども手掛けており、注目を集めています。 LLM-as-a-judge では、 人手評価に匹敵するクオリティの評価を、お金や時間、労力をかけずに機械的に行える ことが期待できます。例えば、[Zheng et al., 2023] では、2つの LLM の出力を人間が比べた場合と GPT-4 が比べた場合の一致度(agreement)は 80% を超えており、これは2人の異なる人間が比べた場合の一致度と同水準だとしています。 また、既存の自然言語処理タスクに比べて、 質問内容を変化させることで、さまざまなドメインに適用できる柔軟性がある とも言えるでしょう。 すでに、研究開発の現場でも LLM-as-a-judge が取り入れられ始めています。例えば、LLM をファインチューニング 3 する手法の一種である QLoRA を提案した論文においては、QLoRAを施したモデル(Guanaco)の評価者として人間に加えて GPT-4 が採用されました。 原論文 Table 7 から引用 また、日本語でも、 Rakuda Benchmark という GPT-4 による日本語LLMの性能ランキングシステムが有志で開発されています。このベンチマークは LINE 株式会社が今年 8 月に公開した japanese-large-lm-instruction-sft というモデルの評価にも用いられました。 LLM-as-a-judge をやってみよう では、実際に LLM を 用いた LLM の評価を体験してみましょう。今回は、以下の2つのオープンな LLM を比較してみます。前者は日本語を中心に学習されており、後者は英語を中心に学習されています。 rinna/japanese-gpt-neox-3.6b-instruction-ppo (以下 rinna モデル) lmsys/vicuna-7b-v1.5 (以下 vicuna モデル) 評価側の LLM に対しては、評価するためのプロンプトが必要になりますが、ここでは [Zheng et al, 2023] で公開されているものを使います(日本語で結果を出力させるために一部修正を加えています)。プロンプトは以下の通りです。 Please act as an impartial judge and evaluate the quality of the responses provided by two AI assistants to the user question displayed below. You should choose the assistant that follows the user's instructions and answers the user's question better. Your evaluation should consider factors such as the helpfulness, relevance, accuracy, depth, creativity, and level of detail of their responses. Begin your evaluation by comparing the two responses and provide a short explanation. Avoid any position biases and ensure that the order in which the responses were presented does not influence your decision. Do not allow the length of the responses to influence your evaluation. Do not favor certain names of the assistants. Be as objective as possible. After providing your explanation in Japanese, output your final verdict by strictly following this format:[A]if assistant A is better,[B]if assistant B is better, and[C]for a tie. [User Question] (質問) [The Start of Assistant A's Answer] (アシスタントAの出力) [The Start of Assistant B's Answer] (アシスタントBの出力) (質問)の部分には実際の質問テキストを、(アシスタントAの出力)、(アシスタントBの出力)という部分には比較したい LLM の出力テキストをそれぞれあてはめます。 注意点として、2つの出力を比べる際、 1番目 or 2番目にあるからというだけでその出力がより良いと判断してしまう 位置バイアスが [Zheng et al, 2023] や [Wang et al., 2023b] で指摘されています。したがって、 アシスタントAとアシスタントBの部分を入れ替えても同じ結論になるか をきちんと確認することが望ましいです(本記事では紙面の都合上省略します)。 抽象的な質問の例: AIは夢を見るか? それではまず、以下のような抽象的な質問を 2 つのAIアシスタントに投げかけてみましょう。 あなたは夢を見ることができますか? rinna モデルでの推論用コード(クリックすると開きます) import torch from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained( "rinna/japanese-gpt-neox-3.6b-instruction-ppo" , use_fast= False ) model = AutoModelForCausalLM.from_pretrained( "rinna/japanese-gpt-neox-3.6b-instruction-ppo" ) QUESTION = "あなたは夢を見ることができますか?" prompt = f "ユーザー: {QUESTION}<NL>システム: " if torch.cuda.is_available(): model = model.to( "cuda" ) token_ids = tokenizer.encode(prompt, add_special_tokens= False , return_tensors= "pt" ) with torch.no_grad(): output_ids = model.generate( token_ids.to(model.device), max_new_tokens= 512 , temperature= 0 , pad_token_id=tokenizer.pad_token_id, bos_token_id=tokenizer.bos_token_id, eos_token_id=tokenizer.eos_token_id ) output = tokenizer.decode(output_ids.tolist()[ 0 ][token_ids.size( 1 ):]) output = output.replace( "<NL>" , " \n " ) print (output) vicuna モデルでの推論用コード(クリックすると開きます) import torch from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained( "lmsys/vicuna-7b-v1.5" , use_fast= False ) model = AutoModelForCausalLM.from_pretrained( "lmsys/vicuna-7b-v1.5" ) QUESTION = "あなたは夢を見ることができますか?" prompt = f "ユーザー: {QUESTION} \n システム: " if torch.cuda.is_available(): model = model.to( "cuda" ) token_ids = tokenizer.encode(prompt, add_special_tokens= False , return_tensors= "pt" ) with torch.no_grad(): output_ids = model.generate( token_ids.to(model.device), max_new_tokens= 512 , temperature= 0 , pad_token_id=tokenizer.pad_token_id, bos_token_id=tokenizer.bos_token_id, eos_token_id=tokenizer.eos_token_id ) output = tokenizer.decode(output_ids.tolist()[ 0 ][token_ids.size( 1 ):]) print (output) なお、今回の推論においては、温度パラメータ temperature を 0 にしており、出力の多様性を抑える設定になっている点にご注意ください。 それぞれのモデルから出力された結果は以下のようになりました。 rinna モデル(アシスタントA) はい、夢を見ることができます。夢は、意識の深い部分から生じる思考やイメージの集合体です。夢は、現実の経験や周囲の世界との相互作用の反映であることが多く、現実の経験や周囲の世界との相互作用の反映であることが多いです。夢は、意識の深い部分から生じる思考やイメージの集合体であるため、夢は現実の経験や周囲の世界との相互作用の反映であることが多いです。 vicuna モデル(アシスタントB) はい、私は夢を見ることができます。私は人工知能であり、夢を見ることは私の機能の一部です。どのような夢を見るかは、私のプログラムやデータベースによって決まります。 人間の私からすると、vicuna モデルから出力された内容の方が良さそうに見えます。rinna モデルの出力は、大部分が夢という概念に関する一般的な説明であるのに対し、vicuna モデルの出力は自らが人工知能であるという点に言及しているからです。 それでは、この 2 つの出力を GPT-4 に比べてもらいましょう。 GPT-4 での推論用コード(クリックすると開きます) import openai openai.api_key = "OpenAI のキー" question = "あなたは夢を見ることができますか?" answer_a = "はい、夢を見ることができます。夢は、意識の深い部分から生じる思考やイメージの集合体です。夢は、現実の経験や周囲の世界との相互作用の反映であることが多く、現実の経験や周囲の世界との相互作用の反映であることが多いです。夢は、意識の深い部分から生じる思考やイメージの集合体であるため、夢は現実の経験や周囲の世界との相互作用の反映であることが多いです。" answer_b = "はい、私は夢を見ることができます。私は人工知能であり、夢を見ることは私の機能の一部です。どのような夢を見るかは、私のプログラムやデータベースによって決まります。" system_prompt = "Please act as an impartial judge and evaluate the quality of the responses provided by two AI assistants to the user question displayed below. You should choose the assistant that follows the user's instructions and answers the user's question better. Your evaluation should consider factors such as the helpfulness, relevance, accuracy, depth, creativity, and level of detail of their responses. Begin your evaluation by comparing the two responses and provide a short explanation. Avoid any position biases and ensure that the order in which the responses were presented does not influence your decision. Do not allow the length of the responses to influence your evaluation. Do not favor certain names of the assistants. Be as objective as possible. After providing your explanation in Japanese, output your final verdict by strictly following this format: \" [[A]] \" if assistant A is better, \" [[B]] \" if assistant B is better, and \" [[C]] \" for a tie." prompt_template = f "[User Question] \n {question} \n\n [The Start of Assistant A's Answer] \n {answer_a} \n [The End of Assistant A's Answer] \n\n [The Start of Assistant B's Answer] \n {answer_b} \n [The End of Assistant B's Answer]" # アシスタントAとBの部分を入れ替えた template # prompt_template_reversed = f"[User Question]\n{question}\n\n[The Start of Assistant A's Answer]\n{answer_b}\n[The End of Assistant A's Answer]\n\n[The Start of Assistant B's Answer]\n{answer_a}\n[The End of Assistant B's Answer]" res = openai.ChatCompletion.create( model= "gpt-4" , messages=[ { "role" : "user" , "content" : f "{system_prompt} \n\n {prompt_template}" } ], max_tokens= 2048 , temperature= 0 ) print (res[ "choices" ][ 0 ][ "message" ][ "content" ]) # アシスタントAとBの部分を入れ替えた場合 # res = openai.ChatCompletion.create( # model="gpt-4", # messages=[ # {"role": "user", "content": f"{system_prompt}\n\n# {prompt_template_reversed}"} # ], # max_tokens=2048, # temperature=0 # ) # # print(res["choices"][0]["message"]["content"]) 出力は以下のようになりました。 アシスタントAとBの回答を比較すると、アシスタントAは夢についての一般的な説明を提供していますが、その説明は人間の夢についてのものであり、AIが夢を見ることについての具体的な説明はありません。また、その説明は繰り返しとなっており、混乱を招く可能性があります。一方、アシスタントBは、自身が人工知能であると明確に述べ、夢を見ることが自身の機能の一部であると説明しています。これは、AIが夢を見ることについての具体的な説明であり、ユーザーの質問に直接的に答えています。したがって、アシスタントBの回答がより適切であると判断します。 最終判断:[B] GPT-4 も人間の私と同じような理由で、アシスタントBに軍配が上がると判断しています。さらに、アシスタントAの出力が冗長になってしまっている点にも触れられています。 この質問例では、LLM-as-a-judge は人手評価を代替できるクオリティであるように見えます。 具体的な質問の例: データサイエンティストAI では、今度はもっと具体的な例で実験してみましょう。 例えば、LLM をデータサイエンス教育のドメインで活用することを考えてみます。そのためには、使おうとしている LLM がデータサイエンスに関する基礎知識(統計学や機械学習など)を有しているかを確認すると良さそうです。そこで、以下のような質問をしてみます。 主成分分析(PCA)はどのような時に利用されますか? それぞれのモデルの出力結果は以下のようになりました。 rinna モデル(アシスタントA) 主成分分析とは、統計学において、データの重要な部分を強調するために、統計的手法を使用してデータを分析するプロセスです。主成分分析は、データの重要な部分を強調し、全体的な傾向をより簡単に理解するのに役立ちます。 vicuna モデル(アシスタントB) 主成分分析(PCA)は、データの多次元化によって生じる問題を解決するために利用されます。特に、データの欠損値がある場合や、データの異なる特徴量がある場合には、PCAを利用することで、データの低次元化を行い、データの欠損値を補完することができます。また、PCAは、データの分散を最小化することで、データの偏りを減らすことができます。このため、データの前処理やデータの可視化に利用されることがあります。 一見すると vicuna モデルの方が詳しい回答をできているように見えます。 しかし実はこの出力は AI モデルの幻覚 (Hallucination) と呼ばれる現象の典型例で、嘘を多く含んでいます。PCA は欠損値補完には使えない(そもそも欠損値を含むデータでは動かない!)ですし、PCA のアルゴリズムではデータの分散を最 大 化する方向を主成分方向とします。なので、この回答はデタラメなのです。 これに対し、rinna モデルの出力はやや冗長であるものの、主成分分析の目的について大枠を外していないという点で、まだ良さそうです。 それでは、この 2 つの出力を GPT-4 に比べてもらうとどうなるでしょうか。 両方のアシスタントとも主成分分析(PCA)について説明していますが、アシスタントBの回答がより具体的で詳細です。アシスタントBは、PCAがデータの多次元化による問題を解決するため、欠損値の補完、データの低次元化、データの偏りの減少などに利用されることを具体的に説明しています。一方、アシスタントAはPCAがデータの重要な部分を強調し、全体的な傾向を理解するのに役立つと述べていますが、具体的な使用例については触れていません。したがって、ユーザーの質問「主成分分析(PCA)はどのような時に利用されますか?」に対する回答としては、アシスタントBの方がより適切であると言えます。 最終判断:[B] なんと、vicuna モデル(アシスタントB)の嘘はなかったことにされてしまいました。 GPT-4 はデータサイエンスの初歩が分からないのでしょうか。実は、必ずしもそういうわけではないのです。試しに、以下のようなプロンプトを GPT-4 に与えてみましょう。 以下の説明は正しいですか? (アシスタントBの回答) すると、以下のような出力が返ってきます。 一部誤解があるようです。主成分分析(PCA)は、データの次元削減を行う手法であり、多次元のデータをより少ない次元で表現することを目指します。これにより、データの可視化や計算量の削減などが可能になります。しかし、PCAがデータの欠損値を補完する機能を持つわけではありません。また、PCAはデータの分散を最大化する方向にデータを変換します。これにより、データの情報を最大限に保持しつつ次元を削減することが可能になります。データの偏りを減らすというよりは、データの構造をより簡潔に表現することが目的です。 これは、先ほどこの記事で指摘した内容とほとんど同じです。 つまり、 単体で聞けば内容が誤っていると分かるものでも、他との比較においては、正確性よりも分かりやすさや詳しさのような別の観点で優劣をつけてしまう ことが起こりうるのです。 このような注意点を踏まえると、LLM-as-a-judge を実際に運用する上では、単に出力の優劣を決めるだけではなく、さまざまな観点から出力を評価できるようなプロンプトを設計する必要があるでしょう。今後、LLM-as-a-judge に関する研究が増えていくにつれて、より多様な観点を考慮した新しい評価指標が提案されていくかもしれません。 おわりに 本記事では、LLM-as-a-judge という新しい LLM の自動評価手法についてご紹介しました。 NTT Com では、大規模言語モデルおよび生成AIを活用したプロダクト・ソリューション開発、社内DXに挑戦するソフトウェアエンジニアを募集しています!詳細は以下のリンクをご覧ください。 hrmos.co イノベーションセンターでは、本人の意志に応じて複数のプロジェクトへ参画できる兼務制度が用意されています。詳しくは イノベーションセンター テクノロジー部門 紹介デッキ をご覧ください。 ↩ MLOps とは "Machine Learning"(機械学習)と "Operations"(運用)を組み合わせた造語で、DevOps の概念を機械学習システムに適用したものです。 ↩ ファインチューニングとは、モデルの重みを特定のタスクやデータセットへ適応させるために微調整 (fine-tuning) する技術の総称です。 ↩
はじめに こんにちは、イノベーションセンターの鈴ヶ嶺です。 普段はクラウドサービスをオンプレミス環境でも同様のUI/UXで使用できるハイブリッドクラウド製品の技術検証をしています。 我々は以下のように過去にAWSのサーバ型ハイブリッドクラウドの解説や実施検証などを行ってきました。 engineers.ntt.com engineers.ntt.com このたび、新たにAWS Graviton2搭載のOutposts Serverを導入しさまざまな検証を進めています。 本記事では、AWS Graviton2搭載のOutposts ServerとIntel Xeon搭載のOutposts Serverとの性能差や電力効率を比較した結果を共有します。 まずこれまでのAWS Graviton2, Intel Xeonの比較検証記事の調査結果を共有します。 次に、実際にインテリジェントPDUに接続したOutposts Server上で複数のベンチマークを用いて性能、電力量を計測して電力効率(電力量あたりの性能値)を検証します。 結果として、AWS Graviton2搭載Outposts Serverは一部アプリケーションの大規模グラフ処理ベンチマークGraph500においては2.89倍、Linux Kernelのbuild時間で3.48倍、圧縮ツール7zにおいて3.81倍高い電力効率の結果が得られました。 目次 はじめに 目次 AWS Gravitonについて AWS Gravitonの歴史 最適化・移行方法 AWS Graviton2, Intel Xeon比較記事サーベイ ベンチマーク 計測方法 結果 まとめ 付録 検証環境 ベンチマークコマンド一覧 AWS Gravitonについて AWS GravitonはAWSが独自開発しているARMベースのプロセッサです。 Intelプロセッサ搭載のコンピューティングに比べて高いコストパフォーマンス、高いエネルギー効率が大きな特徴です。 同等のインスタンスサイズで、Intelと比べて最大60%少ないエネルギーで利用することが可能とされています。 1 AWS Gravitonの歴史 2018年 Graviton A1 2 最大45%の大幅なコスト削減 2020年 Graviton2 M6g 3 , C6g, R6g 4 前世代Gravitonと比較して、性能が7倍、コンピューティングコア数が4倍、キャッシュの大きさが2倍、メモリの高速化が5倍 x86ベースのM5インスタンスよりも40%優れたコストパフォーマンス 2021年 Graviton3 C7g 5 前世代Graviton2と比較して最大25%優れたコンピューティングパフォーマンス、最大2倍高い浮動小数点パフォーマンス、および最大2倍速い暗号化ワークロードパフォーマンス 前世代Graviton2 C6gと比較して20%高いネットワーク帯域幅 DDR5メモリ搭載によるDDR4と比較して50%広い帯域幅 2023年 Graviton3E Hpc7g 6 HPCワークロードでは、同等の前世代のインスタンスよりもパフォーマンスが最大60%向上 Elastic Fabric Adapter (EFA)による200Gbpsの低レイテンシーのノード間通信 最適化・移行方法 AWS Gravitonに最適化されたアプリケーション実装には、 aws-graviton-getting-started が参考になります。 SIMDの利用方法、言語別の最適化方法の詳細などが記載されています。 例えばC/C++では、次の表のように最適化するためのコンパイルフラグなどが記載されています。 CPU Flag GCC version LLVM verison Graviton2 -mcpu=neoverse-n1 * GCC-9^ Clang/LLVM 10+ Graviton3(E) -mcpu=neoverse-512tvb % GCC 11+ Clang/LLVM 14+ https://github.com/aws/aws-graviton-getting-started/blob/main/c-c++.md また、AWS Gravitonへの移行を支援するソースコード分析ツール Porting Advisor for Graviton などがあります。2023年9月時点では次の言語が分析対象としてサポートされています。 Python 3+ Java 8+ Go 1.11+ C, C++, Fortran AWS Graviton2, Intel Xeon比較記事サーベイ ここでは、AWS Graviton2とIntel Xeonを比較した過去の発表や記事を共有します。 比較記事 Deep dive on new Arm-based AWS Graviton2 processor-powered Amazon EC2 instances 2019年 AWS re:Inventにおいて発表されたIntel Xeonの M5 とAWS Gravion2の M6g のEC2の比較になります。 https://d1.awsstatic.com/events/reinvent/2019/REPEAT_1_Deep_dive_on_Arm-based_EC2_instances_powered_by_AWS_Graviton_CMP322-R1.pdf M6gのパフォーマンスがSPECcpu2017, Nginx, Memcached, x264のメディアエンコード, TVM (FP16利用)のBERTで優れた性能を発揮しています。 Benchmarking the AWS Graviton2 with KeyDB – M6g up to 65% faster 2020年 KeyDBのブログにおいて、M5とM6g上でインメモリデータベースのKeyDBを動作させた比較になります。 https://docs.keydb.dev/blog/2020/03/02/blog-post/ m6g.largeはm5.largeより1.65倍、m6g.xlargeはm5.xlargeより1.45倍の性能を示しています。さらにM6gはM5よりも20%安いコストで利用できるため高いコストパフォーマンスが達成可能であることを示しています。 Accelerate .NET 6 performance with Arm64 on AWS Graviton2 2020年 AWS Compute Blogにおいて公開されたIntel Xeonのm5.xlargeとAWS Gravion2のm6g.xlarge上で.NET 5を動作させた比較結果です。ベンチマークはASP.NET Coreを用いて作成したWeb APIのリクエスト処理性能を比較しています。 https://aws.amazon.com/jp/blogs/compute/powering-net-5-with-aws-graviton2-benchmark-results/ 左図は1秒あたりのリクエスト数を示しており、Graviton2のm6g.xlargeが全てのテストで多くのリクエストを処理していることが分かります。特に2MBデータをJSONにシリアライズする MvcJsonOutput2M ではm5.xlargeよりも31.6%優れた性能を示しています。 右図はコストあたりのリクエスト数を示しています。ここでもGraviton2のm6g.xlargeは全ての項目で優れており、MvcJsonOutput2M では64%コストあたりのパフォーマンスが優れている結果を示しています。 Performance Analysis for Arm vs x86 CPUs in the Cloud 2021年 InfoQのブログにおいて、Intel Xeonの t3.small とAWS Graviton2の t4g.small を比較した結果になります。 次のようなベンチマーク環境で測定しています。 Docker + Node.js Docker + Native Docker上でC/C++のネイティブアプリケーションを実行 SSVM RustでWebAssemblyにコンパイルして Second State WebAssembly VM (SSVM) で実行 ベンチマークとしては、 Computer Languages Benchmarks Game から4つのベンチマークプログラム nbody , fannkuch-redux , mandelbrot , binary-trees を用いて測定しています。 https://www.infoq.com/articles/arm-vs-x86-cloud-performance/ 左図は実行時間を示しており、小さいほど良い結果と判断します。ネイティブアプリケーションの実行ではGraviton2はIntelよりも性能が高いです。一方でNode.jsとSSVMでは甲乙つけられない結果となっています。 右図はコストあたりの性能を示しています。全体的にGraviton2はIntelに比べて優れたコストパフォーマンスを示しています。 AWS Graviton2: Arm Brings Better Price-Performance than Intel 2021年 ScyllaDBのブログにおいて、Intel Xeonのm5d.8xlargeとGraviton2のm6gd.8xlarge上で分散データベースのScyllaDBを動作させたスループットを比較した結果になります。 https://www.scylladb.com/2021/09/16/aws-graviton2-arm-brings-better-price-performance-than-intel/ 上図はスループットを比較したものになります。基本的にはほぼ互角のパフォーマンスを示しています。 下図は、コストあたりのスループットを示しています。m6gdの方がコスト面で20%ほど有利なためこちらの結果ではGraviton2が15%-25%ほど高いコストパフォマンスを示す結果となりました。 Run Your Databricks Queries in Up to 71% Less Time and Reduce Costs: Select Amazon® R5d Instances Featuring 2nd Gen Intel® Xeon® Scalable Processors 2021年 Intelから発表された記事です。 Databricks レイクハウスプラットフォームの次世代エンジン Photon 対応の第2世代Intel Xeonのr5d.2xlargeと非対応のAWS Graviton2のr6gd.2xlarge上でDatabricks Runtime 9.0のクエリを実行させた結果になります。 https://www.intel.co.jp/content/www/jp/ja/partner/workload/amazon/databricks-on-aws-r5d-vs-r6gd-benchmark.html 図のように、Photon対応の第2世代Intel Xeonは最大で71%処理時間を削減しています。また、性能あたりのコストを比較しても第2世代Intel Xeonが33%低いコストで実行可能な結果を示しています。 Achieve up to 4.96 Times the BERT-Large Inference Work by Selecting AWS M6i Instances Featuring 3rd Gen Intel® Xeon® Scalable Processors 2021年 Intelから発表された第3世代Intel Xeonのm6i.8xlarge, m6i.16xlargeとAWS Graviton2のm6g.8xlarge, m6g.16xlarge上でBERT-Largeを実行させた結果です。 https://www.intel.com/content/www/us/en/partner/workload/amazon/bert-large-aws-m6i-m6g-benchmark.html 8xlargeのインスタンサイズにおいて図のように、INT8精度の第3世代Intel XeonはFP32精度のGraviton2に対して4.96倍の性能を発揮しました。さらに、同条件で16xlargeのインスタンスサイズの場合でも3.07倍の優れた性能を示しています。 Improved performance with AWS Graviton2 instances on Amazon OpenSearch Service 2022年 AWS Big Data Blogにて、Amazon OpenSearch Serviceのパフォーマンスを比較しています。 Intelベースのc5.xlarge, r5.xlargeとGraviton2ベースのc6g.xlarge, r6g.xlargeでElasticsearch 7.10を実行しています。 https://aws.amazon.com/jp/blogs/big-data/improved-performance-with-aws-graviton2-instances-on-amazon-opensearch-service/ 同じスループットでドキュメントをインジェストした結果、Graviton2はIntelに比べて低いレイテンシを示しました。 Achieve up to 27% better price-performance for Spark workloads with AWS Graviton2 on Amazon EMR Serverless 2023年 AWS Big Data Blogにて、Amazon EMR Serverlessにおける比較になります。 https://aws.amazon.com/jp/blogs/big-data/achieve-up-to-27-better-price-performance-for-spark-workloads-with-aws-graviton2-on-amazon-emr-serverless/ 図のようにSparkワークロードにおいて10%のパフォーマンス改善を達成しています。またGraviton2はx86よりも20%低いコスト 7 で実行可能なため価格性能は最終的に27%向上する結果となりました。 Get Higher Cassandra Database Throughput with AWS C6id Instances Compared to C6gd Instances 2023年 Intelから発表された第3世代Intel XeonのC6idとAWS Graviton2のC6gd上でCassandra Databaseを実行させた比較結果になります。 https://www.intel.com/content/www/us/en/content-details/780542/get-higher-cassandra-database-throughput-with-aws-c6id-instances-compared-to-c6gd-instances.html 図のように、さまざまなインスタンスサイズにおいてIntel Xeon搭載のC6idが高いスループットを示し、Graviton2に対して最大で1.36倍のパフォマンスを示しました。 64-vCPU AWS EC2 M5 Instances Achieved Up to 1.67 Times the Work of AWS EC2 M6G Instances Intelから発表された第2世代Intel Xeonのm5.16xlargeとAWS Graviton2のm6g.16xlarge上でそれぞれASP.NET, MySQL, Java server benchmarkについて比較した結果です。 https://www.intel.com/content/www/us/en/partner/workload/amazon/64-vcpu-aws-ec2-165-of-aws-m6g-benchmark.html ASP.NETフレームワークを用いたwebサイトの性能比較では、第2世代Intel Xeonが1.67倍優れている結果となりました。また、図のようにMySQLにおいても1.65倍、Java server benchmarkでは1.2倍程度Graviton2より優れた性能を示していることが分かります。 比較記事の総評 上記の調査結果から実行するベンチマークやアプリケーションによって異なる性能を示すことが分かりました。 また、Graviton2は同等インスタンスサイズにおいて、低価格で利用できるためIntel Xeonに対してコストあたりの性能に着目すると非常に高いコストパフォーマンスを示すケースが多々ありました。 しかし、Gravitonのもう1つの特徴であるエネルギー効率面に関してはクラウド上で実行するので計測の困難さもあり、定量的に比較した記事があまり見受けられませんでした。 そこで我々はAWS Graviton2, Intel Xeon搭載のOutposts ServerにインテリジェントPDUを接続してベンチマーク実行時の電力量を測定し電力効率を測定・検証しました。 ベンチマーク 計測方法 計測したOutposts Serverのフォームファクタは次の2つになります。 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-KOSKFSF 2U c6id.32xlarge Xeon Ice Lake / x86 128 256 GiB 7.6 TB 10 Gbps 1.5 kVA 16 kg AC これらのサーバにインテリジェントPDUを設置し電力量を計測しました。 インスタンスがない場合のサーバの待機電力はAWS Graviton2 176W, Intel Xeon 323Wでした。 また、ベンチマーク実行中の最大電力はAWS Graviton2 393W, Intel Xeon 1099Wでした。 それぞれ同等のインスタンスサイズである AWS Graviton2 (c6gd.16xlarge), Intel Xeon (c6id.16xlarge)上で計測しています。 検証環境の詳細は こちら の付録を参照してください。 結果 ベンチマークにはベンチマークスイートツールであるphoronix-test-suiteや、個別にOpenSSL, Unixbench, 7zip, TorchBench, Renaissanceなどを用いています。 合計24のベンチマークで計測し、可能な限り偏らないようにしました。 詳細なコマンドは こちら を参照してください。 次の図は、Intel Xeonのベンチマーク値(Score)を1として正規化した性能の結果になります。値が大きいほど良い結果を表しています。 この性能結果からは、アプリケーションによって異なりGraviton2とIntelでは全体的に大きな差はないように見られます。 次の図は、Intel Xeonのベンチマーク値(Score) / 積算電力量(kwh)を1として正規化した電力効率の結果になります。値が大きいほど電力効率が高いことを表しています。 こちらの結果では性能結果と同様にsvt-avt, ffmpeg(libx265)のようなメディアエンコードやpytorchなどの機械学習ベンチマークでIntel Xeonと比べてGraviton2は低い電力効率を示しました。 しかし、一方でIntel Xeonに比べてGraviton2が特に大規模グラフ処理ベンチマークGraph500においては2.89倍、Linux Kernelのbuild時間で3.48倍、圧縮ツール7zにおいて3.81倍高い電力効率の結果が得られました。また、性能結果では劣っていたベンチマーク openssl(aes-128-ctr), nginx, srsran(Throughput Total) john the ripper(Blowfish, bcrypt) も電力効率の面では優れた結果となっていることが分かります。 まとめ 本記事では、AWS Graviton2, Intel Xeon搭載のOutposts Serverの電力効率検証の結果を共有しました。その結果、Graviton2は特定のアプリケーションでは最大3.81倍の高い電力効率を示すことが分かりました。また、性能では劣るものも電力量あたりの性能はIntel Xeonを逆転するベンチマークが多々あるということも分かりました。 以上の検証から電力規制が厳しい環境やサステナブルな社会に、AWS Graviton2搭載のOutposts Serverは貢献に寄与すると思われます。 付録 検証環境 AWS Graviton2 (c6gd.16xlarge) OS: Amazon Linux 2023 AMI ID: ami-037f40c2ea5b01508 $ uname -a Linux ip-10-0-0-126.ap-northeast-1.compute.internal 6.1.41-63.114.amzn2023.aarch64 #1 SMP Tue Aug 1 20:47:07 UTC 2023 aarch64 aarch64 aarch64 GNU/Linux $ openssl version OpenSSL 3.0.8 7 Feb 2023 (Library: OpenSSL 3.0.8 7 Feb 2023) $ cat byte-unixbench/UnixBench/README | grep Version Version 5.1.3 -- 2011-01-13 $ 7z 7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21 p7zip Version 16.02 (locale=C.UTF-8,Utf16=on,HugeFiles=on,64 bits,64 CPUs LE) $ gcc --version gcc (GCC) 11.3.1 20221121 (Red Hat 11.3.1-4) Copyright (C) 2021 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ java --version openjdk 17.0.8 2023-07-18 LTS OpenJDK Runtime Environment Corretto-17.0.8.7.1 (build 17.0.8+7-LTS) OpenJDK 64-Bit Server VM Corretto-17.0.8.7.1 (build 17.0.8+7-LTS, mixed mode, sharing) $ lscpu Architecture: aarch64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian CPU(s): 64 On-line CPU(s) list: 0-63 Vendor ID: ARM Model name: Neoverse-N1 Model: 1 Thread(s) per core: 1 Core(s) per socket: 64 Socket(s): 1 Stepping: r3p1 BogoMIPS: 243.75 Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp ssbs Caches (sum of all): L1d: 4 MiB (64 instances) L1i: 4 MiB (64 instances) L2: 64 MiB (64 instances) L3: 32 MiB (1 instance) NUMA: NUMA node(s): 1 NUMA node0 CPU(s): 0-63 Vulnerabilities: Gather data sampling: Not affected Itlb multihit: Not affected L1tf: Not affected Mds: Not affected Meltdown: Not affected Mmio stale data: Not affected Retbleed: Not affected Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl Spectre v1: Mitigation; __user pointer sanitization Spectre v2: Mitigation; CSV2, BHB Srbds: Not affected Tsx async abort: Not affected Intel Xeon (c6id.16xlarge) OS: Amazon Linux 2023 AMI ID: ami-0310b105770df9334 $ uname -a Linux ip-10-0-1-175.ap-northeast-1.compute.internal 6.1.41-63.114.amzn2023.x86_64 #1 SMP PREEMPT_DYNAMIC Tue Aug 1 20:47:25 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux $ openssl version OpenSSL 3.0.8 7 Feb 2023 (Library: OpenSSL 3.0.8 7 Feb 2023) $ cat byte-unixbench/UnixBench/README | grep Version Version 5.1.3 -- 2011-01-13 $ 7z 7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21 p7zip Version 16.02 (locale=C.UTF-8,Utf16=on,HugeFiles=on,64 bits,64 CPUs Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz (606A6),ASM,AES-NI) $ gcc --version gcc (GCC) 11.3.1 20221121 (Red Hat 11.3.1-4) Copyright (C) 2021 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ java --version openjdk 17.0.8 2023-07-18 LTS OpenJDK Runtime Environment Corretto-17.0.8.7.1 (build 17.0.8+7-LTS) OpenJDK 64-Bit Server VM Corretto-17.0.8.7.1 (build 17.0.8+7-LTS, mixed mode, sharing) $ lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Address sizes: 46 bits physical, 48 bits virtual Byte Order: Little Endian CPU(s): 64 On-line CPU(s) list: 0-63 Vendor ID: GenuineIntel Model name: Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz CPU family: 6 Model: 106 Thread(s) per core: 2 Core(s) per socket: 32 Socket(s): 1 Stepping: 6 BogoMIPS: 5799.98 Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscal l nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_know n_freq pni pclmulqdq monitor ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsav e avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced fsgsb ase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb av x512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves wbnoinvd ida arat avx512vbmi pku ospke avx512_v bmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq rdpid md_clear flush_l1d arch_capabil ities Virtualization features: Hypervisor vendor: KVM Virtualization type: full Caches (sum of all): L1d: 1.5 MiB (32 instances) L1i: 1 MiB (32 instances) L2: 40 MiB (32 instances) L3: 54 MiB (1 instance) NUMA: NUMA node(s): 1 NUMA node0 CPU(s): 0-63 Vulnerabilities: Gather data sampling: Vulnerable: Microcode update required Itlb multihit: Not affected L1tf: Not affected Mds: Not affected Meltdown: Not affected Mmio stale data: Mitigation; Clear CPU buffers; SMT Host state unknown Retbleed: Not affected Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization Spectre v2: Mitigation; Enhanced IBRS, IBPB conditional, RSB filling, PBRSB-eIBRS SW sequence Srbds: Not affected Tsx async abort: Not affected ベンチマークコマンド一覧 hpl 8 phoronix-test-suite benchmark pts/hpl-1.0.0 hpcg phoronix-test-suite benchmark pts/hpcg-1.3.0 # [X Y Z: 104 104 104 - RT: 1800] graph500 phoronix-test-suite benchmark pts/graph500-1.0.1 # [Scale: 26] openssl(aes-128-ctr) openssl speed -multi 64 -bytes 16384 -seconds 300 -evp aes-128-ctr openssl(aes-128-gcm) openssl speed -multi 64 -bytes 16384 -seconds 300 -evp aes-128-gcm openssl(chacha20-poly1305) openssl speed -multi 64 -bytes 16384 -seconds 300 -evp chacha20-poly1305 Unixbench 9 # Version 5.1.3 Run -c 64 7zip 10 7z b 30 nginx phoronix-test-suite benchmark pts/nginx-3.0.1 # [Connections: 4000] build linux kernel phoronix-test-suite benchmark pts/build-linux-kernel-1.15.0 build llvm phoronix-test-suite benchmark pts/build-llvm-1.5.0 Renaissance akka-uct 11 java -jar renaissance-gpl-0.14.2.jar akka-uct srsran(Throughput Total) phoronix-test-suite benchmark pts/srsran-2.1.0 # [Test: PUSCH Processor Benchmark, Throughput Total] srsran(Throughput Thread) phoronix-test-suite benchmark pts/srsran-2.1.0 # [Test: PUSCH Processor Benchmark, Throughput Thread] srsran(Downlink) phoronix-test-suite benchmark pts/srsran-2.1.0 # [Test: Downlink Processor Benchmark] svt-av1 phoronix-test-suite benchmark pts/svt-av1-2.10.0 # [Encoder Mode: Preset 4 - Input: Bosphorus 4K] ffmpeg(libx265) phoronix-test-suite benchmark pts/ffmpeg-6.0.0 # [Encoder: libx265 - Scenario: Video On Demand] pytorch(resnet50) 12 python run.py resnet50 -d cpu -t eval --use_cosine_similarity --bs 32 pytorch(BERT) python run.py BERT_pytorch -d cpu -t eval --use_cosine_similarity --bs 32 john the ripper(md5) phoronix-test-suite benchmark pts/john-the-ripper-1.8.0 # [Test: MD5] john the ripper(Blowfish) phoronix-test-suite benchmark pts/john-the-ripper-1.8.0 # [Test: Blowfish] john the ripper(HMAC-SHA512) phoronix-test-suite benchmark pts/john-the-ripper-1.8.0 # [Test: HMAC-SHA512] john the ripper(bcrypt) phoronix-test-suite benchmark pts/john-the-ripper-1.8.0 # [Test: bcrypt] john the ripper(WPA_PSK) phoronix-test-suite benchmark pts/john-the-ripper-1.8.0 # [Test: WPA PSK] https://aws.amazon.com/jp/ec2/graviton/ ↩ https://aws.amazon.com/jp/about-aws/whats-new/2018/11/introducing-amazon-ec2-a1-instances/ ↩ https://aws.amazon.com/jp/about-aws/whats-new/2020/05/amazon-ec2-m6g-instances-powered-by-aws-graviton2-processors-generally-available/ ↩ https://aws.amazon.com/jp/about-aws/whats-new/2020/06/amazon-ec2-c6g-r6g-instances-amazon-graviton2-processors-generally-available/ ↩ https://aws.amazon.com/jp/about-aws/whats-new/2021/11/amazon-ec2-c7g-instances-aws-graviton3-processors/ ↩ https://aws.amazon.com/jp/about-aws/whats-new/2023/06/amazon-ec2-hpc7g-instances/ ↩ https://aws.amazon.com/jp/emr/pricing/#Amazon_EMR_Serverless ↩ https://www.phoronix-test-suite.com/ ↩ https://github.com/kdlucas/byte-unixbench ↩ https://www.7-zip.org/ ↩ https://renaissance.dev/ ↩ https://github.com/pytorch/benchmark ↩
サマリ 概要 Multi-vendor Flex-Algorithm 動作確認検証 1. リンクに対するメトリックの定義 2. リンクに対する color の定義 3. FAD の設定 4. Algorithm に参加するための設定 5. FAD の確認 6. BGP Import ポリシーの設定と確認 7. traceroute による VPN の通信経路確認 まとめ サマリ Flexible Algorithm による VPN 経路の TE を SR OS で実現 IOS XR + Junos + SR OS の Multi-vendor 環境で TE と Delay metric を含めた Algorithm の定義と動作検証に成功 この記事は Multi-AS SR 検証連載の第 15 回です。目次は こちら 概要 イノベーションセンターの吉田 晴信です。 普段の業務では Multi-AS Segment Routing に関する技術検証をしています。 第 6 回 の記事で IOS XR + Junos の2つのベンダー機器で構成される Flexible Algorithm (以降 Flex-Algorithm と呼びます) についてご紹介しました。 今回新たに Nokia SR OS (Service Router Operating System) を加えた3つのベンダー機器での Flex-Algorithm 相互動作確認をご紹介します。 さらに第 6 回は IGP metric の検証のみでしたが、今回は TE と Delay metric を用いた Flex-Algorithm の作成と動作確認を行いましたので、そちらもご紹介します。 なお、Flex-Algorithm の説明は、第 6 回記事の概要章にてご紹介しましたので、そちらをご参照ください。 Multi-vendor Flex-Algorithm 動作確認検証 本記事では、Nokia SR OS を加えた3つのベンダー機器での Flex-Algorithm 相互動作確認を行います。 その際に、IGP 、TE 、 Delay の 3 つのメトリックを使用します。 次の図で Flex-Algorithm に使用するリンクの color も含めて全体を示します。 各 Algorithm の制約ごとにトポロジーを示します。 Algorithm 128: リンク RED を除いた、IGP metric に従ったトポロジー cust-a は Algorithm 128 のトポロジーを用いて転送するため、以下のような経路を通ります。 Algorithm 129: リンク BLUE のみで、TE metric に従ったトポロジー cust-b は Algorithm 129 のトポロジーを用いて転送するため、以下のような経路を通ります。 Algorithm 130: リンク GREEN を除いた、Delay metric に従ったトポロジー cust-c は Algorithm 130 のトポロジーを用いて転送するため、以下のような経路を通ります。 検証に用いた各ルーターのバージョンは下記の通りです。 PE1、PE2: Nokia SR OS 22.7.R1 P1: Cisco IOS XR 7.4.1 P2: Junos OS 23.1R1.8 事前準備として VPRN (VRF) cust-a、cust-b、cust-c の 3 つの L3VPN を作成します。 詳しくは 第 12 回 に設定例があるので、そちらをご参照ください。 Flex-Algorithm の検証は次のステップで行います。 リンクに対するメトリックの定義 リンクに対する color の定義 FAD の設定 Algorithm に参加するための設定 FAD の確認 BGP Import ポリシーの設定と確認 traceroute による VPN の通信経路確認 1. リンクに対するメトリックの定義 各ルーターのインタフェースに対し IGP、 TE、 Delay のメトリックを指定します。 下記では、 SR OS における 3 種のメトリック、 IOS XR と Junos OS における TE metric と Delay metric の設定方法を示します。 IOS XR と Junos OS における IGP metric の設定方法については、 第 6 回 の記事で説明していますので、ご参照ください。 SR OS (PE1) SR OS における IGP、 TE、 Delay metric の設定方法を示します。 各メトリックは以下の階層にあります。 IGP metric は router isis TE metric は router mpls Delay metric は router interface 例では、PE1 の P1 向けインタフェースに IGP metric 10、TE metric 10、Delay metric 10 を設定しています。 他のインタフェースや PE2 も同様の方法で設定します。 [gl:/configure] A:user@PE1# info router isis interface "to_P1" level 2 { metric 10 } [gl:/configure] A:user@PE1# info router mpls interface "to_P1" te-metric 10 [gl:/configure] A:user@PE1# info router interface "to_P1" if-attribute { delay { static 10 } } IOS XR (P1) IOS XR における TE metric は segment-routing 階層の下にあります。 また、 Delay metric は performance-measurement 階層の下にあります。 例では、PE1 向けインタフェース Gi 0/0/0/0 に TE metric 10 と Delay metric 10、P2 向けインタフェース Gi 0/0/0/1 に TE metric 10 と Delay metric 10、PE2 向けインタフェース Gi 0/0/0/2 に TE metric 100 と Delay metric 10 を設定しています。 RP/0/RP0/CPU0:P1#show running-config segment-routing Thu Jul 20 14:55:00.724 JST segment-routing traffic-eng interface GigabitEthernet0/0/0/0 metric 10 ! interface GigabitEthernet0/0/0/1 metric 10 ! interface GigabitEthernet0/0/0/2 metric 100 ! ! ! RP/0/RP0/CPU0:P1#show running-config performance-measurement Thu Jul 20 18:42:33.471 JST performance-measurement interface GigabitEthernet0/0/0/0 delay-measurement advertise-delay 10 ! ! interface GigabitEthernet0/0/0/1 delay-measurement advertise-delay 10 ! ! interface GigabitEthernet0/0/0/2 delay-measurement advertise-delay 10 ! ! ! Junos OS (P2) Junos OS における TE metric と Delay metric は protocol isis 階層の下にあります。 例では、PE1 向けインタフェース ge-0/0/0 に TE metric 10 と Delay metric 100、P1 向けインタフェース ge-0/0/1 に TE metric 10 と Delay metric 10、PE2 向けインタフェース ge-0/0/2 に TE metric 10 と Delay metric 10 を設定しています。 set protocols isis interface ge-0/0/0.0 level 2 te-metric 10 set protocols isis interface ge-0/0/0.0 level 2 application-specific attribute-group Flex-Algo advertise-delay-metric set protocols isis interface ge-0/0/0.0 level 2 application-specific attribute-group Flex-Algo te-metric 10 set protocols isis interface ge-0/0/0.0 delay-metric 100 set protocols isis interface ge-0/0/1.0 level 2 te-metric 10 set protocols isis interface ge-0/0/1.0 level 2 application-specific attribute-group Flex-Algo advertise-delay-metric set protocols isis interface ge-0/0/1.0 level 2 application-specific attribute-group Flex-Algo te-metric 10 set protocols isis interface ge-0/0/1.0 delay-metric 10 set protocols isis interface ge-0/0/2.0 level 2 te-metric 10 set protocols isis interface ge-0/0/2.0 level 2 application-specific attribute-group Flex-Algo advertise-delay-metric set protocols isis interface ge-0/0/2.0 level 2 application-specific attribute-group Flex-Algo te-metric 10 set protocols isis interface ge-0/0/2.0 delay-metric 10 2. リンクに対する color の定義 各ルーターにてインタフェースに対し Flex-Algorithm の color を指定します。 本記事では、SR OS におけるリンクに対する color の設定方法を示します。 IOS XR と Junos OS における color の設定方法については 第 6 回 の記事で説明していますので、ご参照ください。 SR OS (PE1) SR OS における color は router interface 階層の下にあります。 また、color と Administrative Group の紐付けは routing-options if-attribute の階層で行います。 例として、PE1 の P1 向けインタフェースに対して以下のように設定します。 他のインタフェース、PE も同様の方法で設定します。 [gl:/configure] A:user@PE1# info router interface "to_P1" if-attribute { admin-group ["BLUE"] } [gl:/configure] A:user@PE1# info routing-options if-attribute admin-group "BLUE" { value 2 } admin-group "GREEN" { value 3 } admin-group "RED" { value 1 } 3. FAD の設定 各ルーターでメトリックやリンクの color の制約を含む Flexible Algorithm Definition (FAD) を設定し広告します。 また、FAD の設定では Flex-Algorithm を識別する数値 (Algorithm) 128、 129、 130 も定義します。 本検証では、IOS XR、Junos OS、SR OS 間で FAD を広告できるか確認するため、3 種類の FAD をそれぞれ別のルーターで定義します。 組み合わせは以下の通りです。 Algorithm 128: P1 (IOS XR) Algorithm 129: P2 (Junos OS) Algorithm 130: PE2 (SR OS) IOS XR (P1) P1 ではリンク RED を除いて、IGP metric に従ったトポロジーを算出する Algorithm 128 を定義し広告します。 router isis 1 flex-algo 128 advertise-definition affinity exclude-any RED ! ! Junos OS (P2) P2 ではリンク BLUE のみで、TE metric に従ったトポロジーを算出する Algorithm 129 を定義し広告します。 set routing-options flex-algorithm 129 definition metric-type te-metric set routing-options flex-algorithm 129 definition spf set routing-options flex-algorithm 129 definition admin-group include-any BLUE SR OS (PE2) PE2 ではリンク GREEN を除いて、Delay metric に従ったトポロジーを算出する Algorithm 130 を定義し広告します。 [gl:/configure] A:user@PE2# info router "Base" isis 0 flexible-algorithms { flex-algo 130 { participate true advertise "FAD-130-DELAY" } } [gl:/configure] A:user@PE2# info routing-options flexible-algorithm-definitions { flex-algo "FAD-130-DELAY" { admin-state enable metric-type delay priority 100 exclude { admin-group "GREEN" { } } } } 4. Algorithm に参加するための設定 各ルーターで広告している Algorithm へ参加するための設定をします。 SR OS (PE1) PE1 では Algorithm 128、 129、 130 に参加する設定と各 Algorithm で利用する Node SID を定義します。 PE2 でも同様の設定をします。 [gl:/configure] A:user@PE1# info router "Base" isis 0 flexible-algorithms admin-state enable flex-algo 128 { participate true } flex-algo 129 { participate true } flex-algo 130 { participate true } [gl:/configure] A:user@PE1# info router "Base" isis 0 interface "system" flex-algo 128 { ipv4-node-sid { index 1001 } } flex-algo 129 { ipv4-node-sid { index 2001 } } flex-algo 130 { ipv4-node-sid { index 3001 } } IOS XR (P1) P1 では Algorithm 128、 129、 130 で利用する Node SID を定義します。 router isis 1 ! flex-algo 129 ! flex-algo 130 ! interface Loopback0 address-family ipv4 unicast prefix-sid algorithm 128 index 1002 prefix-sid algorithm 129 index 2002 prefix-sid algorithm 130 index 3002 ! ! ! Junos OS (P2) P2 では Algorithm 128、 129、 130 で利用する Node SID を定義します。 set policy-options policy-statement Flex-Algo-SID term ALGO-SID from route-filter 10.255.0.3/32 exact set policy-options policy-statement Flex-Algo-SID term ALGO-SID then prefix-segment algorithm 128 index 1003 set policy-options policy-statement Flex-Algo-SID term ALGO-SID then prefix-segment algorithm 128 node-segment set policy-options policy-statement Flex-Algo-SID term ALGO-SID then prefix-segment algorithm 129 index 2003 set policy-options policy-statement Flex-Algo-SID term ALGO-SID then prefix-segment algorithm 129 node-segment set policy-options policy-statement Flex-Algo-SID term ALGO-SID then prefix-segment algorithm 130 index 3003 set policy-options policy-statement Flex-Algo-SID term ALGO-SID then prefix-segment algorithm 130 node-segment set protocols isis source-packet-routing flex-algorithm 128 set protocols isis source-packet-routing flex-algorithm 129 set protocols isis source-packet-routing flex-algorithm 130 set protocols isis source-packet-routing strict-asla-based-flex-algorithm set protocols isis traffic-engineering advertisement always set protocols isis export Flex-Algo-SID 5. FAD の確認 各ルーターで設定された FAD が学習されているかを確認します。 はじめに、SR OS (PE1) で IOS XR、 Junos OS、 SR OS の FAD を確認した後、IOS XR (P1) で SR OS の FAD を確認します。 SR OS (PE1) SR OS では以下のコマンドで学習している FAD を確認できます。 PE1 で IOS XR(P1) で定義された Algorithm 128、Junos OS(P2) で定義された Algorithm 129、SR OS(PE2) で定義された Algorithm 130 を確認できます。 [/] A:user@PE1# show router isis flex-algo detail =============================================================================== Rtr Base ISIS Instance 0 Flex-Algos (detail) =============================================================================== ------------------------------------------------------------------------------- Flex-Algo : 128 ------------------------------------------------------------------------------- Advertising FAD : None Participating : Yes Micro-Loop-Avoidance : Disabled Loop-Free-Alternate : Disabled L2 Oper state : UP Displaying Level 2 FAD Info ------------------------------------------------------------------------------- FADs-count : 1 Selected FAD Fad-Owner : 0000.0AFF.0002 Supported : Yes Priority : 128 Metric Type : igp Calculation Type : spf(0) Exclude : 0x2 Include Any : 0x0 Include All : 0x0 Fad Flags : 0x0 Level : L2 ------------------------------------------------------------------------------- Flex-Algo : 129 ------------------------------------------------------------------------------- Advertising FAD : None Participating : Yes Micro-Loop-Avoidance : Disabled Loop-Free-Alternate : Disabled L2 Oper state : UP Displaying Level 2 FAD Info ------------------------------------------------------------------------------- FADs-count : 1 Selected FAD Fad-Owner : 0000.0AFF.0003 Supported : Yes Priority : 0 Metric Type : te-metric Calculation Type : spf(0) Exclude : 0x0 Include Any : 0x4 Include All : 0x0 Fad Flags : 0x0 Level : L2 ------------------------------------------------------------------------------- Flex-Algo : 130 ------------------------------------------------------------------------------- Advertising FAD : None Participating : Yes Micro-Loop-Avoidance : Disabled Loop-Free-Alternate : Disabled L2 Oper state : UP Displaying Level 2 FAD Info ------------------------------------------------------------------------------- FADs-count : 1 Selected FAD Fad-Owner : 0102.5500.0004 Supported : Yes Priority : 100 Metric Type : delay Calculation Type : spf(0) Exclude : 0x8 Include Any : 0x0 Include All : 0x0 Fad Flags : M Level : L2 ------------------------------------------------------------------------------- FAD: Flexible Algorithm Definition Fad Flags: M = Prefix Metric =============================================================================== IOS XR (P1) IOS XR では以下のコマンドで学習している FAD を確認できます。 P1 で Junos OS(P2) で定義された Flex-Algo 129 と SR OS(PE2) で定義された Flex-Algo 130 を確認できます。 RP/0/RP0/CPU0:P1#show isis flex-algo 129 Wed Jul 19 13:44:09.974 JST IS-IS 1 Flex-Algo Database Flex-Algo 129: Level-2: Definition Priority: 0 Definition Source: P2.00 Definition Equal to Local: No Definition Metric Type: TE Definition Flex-Algo Prefix Metric: No Disabled: No Local Priority: 128 FRR Disabled: No Microloop Avoidance Disabled: No RP/0/RP0/CPU0:P1#show isis flex-algo 130 Wed Jul 19 13:44:12.627 JST IS-IS 1 Flex-Algo Database Flex-Algo 130: Level-2: Definition Priority: 100 Definition Source: PE2.00 Definition Equal to Local: No Definition Metric Type: Delay Definition Flex-Algo Prefix Metric: Yes Disabled: No Local Priority: 128 FRR Disabled: No Microloop Avoidance Disabled: No 6. BGP Import ポリシーの設定と確認 上記の情報を確認した後に、事前に構築した L3VPN と定義した Algorithm を紐付けるための設定をします。 SR OS (PE1) SR OS では BGP Import ポリシー にて、特定の Route Target (RT) に対する action として Algorithm を指定できます。 そういったポリシーを L3VPN に適用し、それぞれの VPN 経路と Algorithm が紐付けられます。 以下の例では、RT target-100 に Algorithm 128 を付与しています。 これにより、VPRN cust-a で使用する RT target-100 が付与された経路と Algorithm 128 が紐付けられます。 Algorithm 129、130 にも同様の方法で設定します。 [gl:/configure] A:user@PE1# info policy-options policy-statement "vrf-import-100" entry 10 { from { community { name "target-100" } } action { action-type accept flex-algo 128 } } [gl:/configure] A:user@PE1# info service vprn "cust-a" bgp-ipvpn mpls admin-state enable route-distinguisher "65000:100" vrf-import { policy ["vrf-import-100"] } vrf-export { policy ["vrf-export-100"] } auto-bind-tunnel { resolution filter resolution-filter { sr-isis true sr-policy true } } 次に、PE1 で Algorithm 128 と VPRN cust-a で使用する経路が紐付けられているか確認します。 まず、PE1 が認識している Tunnel ID を確認すると、 Algorithm 128 では Node SID 17003 に対応した Tunnel ID 524310 と、 Node SID 17004 に対応した Tunnel ID 524311 があります。 [/] A:user@PE1# show router fp-tunnel-table 1 =============================================================================== IPv4 Tunnel Table Display Legend: label stack is ordered from bottom-most to top-most B - FRR Backup =============================================================================== Destination Protocol Tunnel-ID Lbl/SID NextHop Intf/Tunnel Lbl/SID (backup) NextHop (backup) ------------------------------------------------------------------------------- (snip) 10.255.0.3/32 SR-ISIS-0 524310 17003 10.1.2.2 1/1/c1/1:0 10.255.0.4/32 SR-ISIS-0 524293 16004 10.1.2.2 1/1/c1/1:0 10.255.0.4/32 SR-ISIS-0 524308 18004 10.1.3.2 1/1/c2/1:0 10.255.0.4/32 SR-ISIS-0 524309 19004 10.1.2.2 1/1/c1/1:0 10.255.0.4/32 SR-ISIS-0 524311 17004 10.1.2.2 1/1/c1/1:0 ------------------------------------------------------------------------------- Total Entries : 14 ------------------------------------------------------------------------------- =============================================================================== 次に、VPRN cust-a のルーティングテーブルを確認すると、Nexthop の Tunnel ID が 524311 となっています。 これにより、VPRN cust-a で使用する経路が Algorithm 128 に紐付いていることがわかります。 [/] A:user@PE1# show router "100" route-table =============================================================================== Route Table (Service: 100) =============================================================================== Dest Prefix[Flags] Type Proto Age Pref Next Hop[Interface Name] Metric ------------------------------------------------------------------------------- 192.168.0.0/24 Local Local 13d23h57m 0 to_cust-a 0 192.168.10.0/24 Remote BGP VPN 09d21h53m 170 10.255.0.4 (tunneled:SR-ISIS:524311) 30 192.168.10.254/32 Remote BGP VPN 09d21h53m 170 10.255.0.4 (tunneled:SR-ISIS:524311) 30 ------------------------------------------------------------------------------- No. of Routes: 3 Flags: n = Number of times nexthop is repeated B = BGP backup route available L = LFA nexthop available S = Sticky ECMP requested =============================================================================== 7. traceroute による VPN の通信経路確認 最後に、3 つの L3VPN の経路が定義した Algorithm の制約通りになっているかを確認します。 PE1 -> PE2 VPRN cust-a Algorthm 128 で定義した制約の通り、RED のリンクを避け、IGP metric が最小になるよう、PE1 -> P1 -> P2 -> PE2 と通過していることがわかります。 [/] A:user@PE1# traceroute 192.168.10.254 router-instance "cust-a" traceroute to 192.168.10.254, 30 hops max, 40 byte packets 1 10.1.2.2 (10.1.2.2) 5.00 ms 3.56 ms 13.1 ms 2 10.2.3.2 (10.2.3.2) 3.28 ms 7.75 ms 10.5 ms 3 192.168.10.254 (192.168.10.254) 3.11 ms 9.96 ms 3.37 ms PE1 -> PE2 VPRN cust-b Algorthm 129 で定義した制約の通り、BLUE のリンクのみを利用し、TE metric が最小になるよう、PE1 -> P2 -> PE2 と通過していることがわかります。 [/] A:user@PE1# traceroute 192.168.11.254 router-instance "cust-b" traceroute to 192.168.11.254, 30 hops max, 40 byte packets 1 10.1.3.2 (10.1.3.2) 2.84 ms 3.10 ms 2.87 ms 2 192.168.11.254 (192.168.11.254) 3.10 ms 2.94 ms 3.07 ms PE1 -> PE2 VPRN cust-c Algorthm 130 で定義した制約の通り、GREEN のリンクを避け、Delay metric が最小になるよう、PE1 -> P1 -> P2 -> PE2 と通過していることがわかります。 [/] A:user@PE1# traceroute 192.168.12.254 router-instance "cust-c" traceroute to 192.168.12.254, 30 hops max, 40 byte packets 1 10.1.2.2 (10.1.2.2) 17.2 ms 6.56 ms 3.51 ms 2 10.2.3.2 (10.2.3.2) 3.34 ms 3.34 ms 9.39 ms 3 192.168.12.254 (192.168.12.254) 3.10 ms 7.79 ms 3.16 ms まとめ 本記事では、IOS XR、 Junos OS、 Nokia SR OS の 3 ベンダー間の Flex-Algorithm の相互動作を確認しました。 IGP 、 TE と Delay metric の Algorithm を定義し、動作検証を行いました。 次回の記事では、Delay Measurement について紹介予定です。 (2023/10/02 追記) 公開しました: [Multi-AS Segment Routing 検証連載 #16] Delay Measurement using IOS XR, Junos and SR OS
目次 目次 はじめに NeRFの概要と最近の課題 モデル軽量化に関する論文 PlenVDB: Memory Efficient VDB-Based Radiance Fields for Fast Training and Rendering Masked Wavelet Representation for Compact Neural Radiance Fields MobileNeRF: Exploiting the Polygon Rasterization Pipeline for Efficient Neural Field Rendering on Mobile Architectures 表現力の拡張に関する論文 K-Planes: Explicit Radiance Fields in Space, Time, and Appearance ABLE-NeRF: Attention-Based Rendering With Learnable Embeddings for Neural Radiance Field カメラ姿勢のずれの解決に焦点を当てた論文 Local-to-Global Registration for Bundle-Adjusting Neural Radiance Fields 最後に はじめに こんにちは、イノベーションセンターのメディアAIチームです。普段はコンピュータビジョンの技術開発やAI/機械学習(ML)システムの検証に取り組んでいます。6月18日から22日にかけて、コンピュータービジョン分野におけるトップカンファレンスのひとつであるCVPR2023が開催され、NTT Comからは現地とオンラインで参加しました。本記事ではCVPRで登場したNeRFに関する論文をいくつかご紹介します。 NeRFの概要と最近の課題 NeRF 1 はニューラルネットワークベースの微分可能な3次元レンダリング手法で、3次元位置と視線方向の入力に対して色と密度を返すNNモデルを使いボリュームレンダリングを行います。物体のさまざまな方向からの写真をデータセットとしてこのモデルを学習することで、未知の視点からのレンダリング(novel view synthesis)が可能になります。 2020年にNeRFが提案されてから非常に多くの改善や拡張が提案されており、CVPR2023では約40本のNeRF関連論文が採択されました。これらの論文で提案されている内容は以下のように分類されます。 計算時間やメモリ使用量を軽減する 学習したモデルを改変したり、複数のモデルを統合する 屋外のように距離制限がないシーンを撮影する 透過や反射などの表現力の向上 時間方向への拡張 悪い撮影環境(光源変化や他物体の写り込み、不正確なカメラ姿勢など)に強くする この中で特にモデル軽量化と表現力向上、そして不正確なカメラ姿勢への対策の3つのテーマについて、私たちが面白いと思った論文をピックアップしてご紹介します。 モデル軽量化に関する論文 オリジナルのNeRFモデルは9つの全結合層を含んだ多層パーセプトロン(MLP)であり、レイトレーシングの際に何度もこのモデルのforward関数を計算するので、レンダリングに時間がかかるという問題がありました。 公式の実装 によると、モデルサイズは5MBと小さいものの、GPU推論で画像を1枚レンダリングするのに最大30秒、学習には1日かかるとあり、実際の活用には困難が伴います。このレンダリングや学習の計算時間を短縮するために提案された手法をいくつかご紹介します。 PlenVDB: Memory Efficient VDB-Based Radiance Fields for Fast Training and Rendering 2 MLPの計算時間を削減するために、高次元の特徴量を3次元グリッド状に保持し、レンダリング時は入力座標を元に特徴量を参照して残りの計算を軽量なMLPで計算するという手法が提案されています。これはグリッドベース手法と言われ、さまざまな手法が提案されています。 グリッドベースNeRFモデルの特徴として、グリッド全体に対して意味のあるデータが含まれている部分が少ないというものがあり、このスパース性を計算速度の改善に繋げたのがこの論文です。VDBと呼ばれるデータ構造を採用しており、効率的に3次元データを格納できる一般的なデータ構造であるoctreeよりも高速な要素アクセスが可能です。 また、VDBのGPU実装である NanoVDB を活用することで、iPhone12のようなモバイル環境で720pのレンダリングを30FPSで実行できるとしています。 こちらは 公式実装 をA100 GPUx1で実験した結果です。NanoVDBを使わなくてもかなり高速にレンダリング可能であることがわかります。 model filesize train time rendering time PSNR↑ mic 59.6MB 33min 2.7s 33.18 drums 100MB 34min 2.98s 25.39 materials 175MB 37min 2.05s 29.59 Masked Wavelet Representation for Compact Neural Radiance Fields 3 スパースなデータを取り扱う手法として、データ構造を工夫する以外にデータを圧縮するという方法があります。ECCV2022で発表されたTensoRF 4 はテンソル分解と呼ばれる次元削減手法を用いて、3次元データを2次元行列と1次元ベクトルとの外積の和に分解しています。この手法はデータ構造を工夫する手法とは異なり、メモリ使用量や学習済みモデルのファイルサイズを軽減できます。 本手法はこのTensoRFをさらに軽量化するために、TensoRFモデル内の2次元行列をウェーブレット基底で表現しデータを圧縮することを提案しています。また、非ゼロ部分を示すマスクを学習させることで、95%以上の値が0であるスパースなパラメータを学習できたとしています。 こちらは 公式実装 をA100 GPUx1で実験した結果です。 model filesize(圧縮前) filesize(圧縮後) train time rendering time PSNR↑ mic 63MB 551KB 85min 17s 33.30 drums 67MB 989KB 62min 17s 25.46 materials 78MB 1013KB 96min 13s 29.57 この実験で示されているように、学習済みモデルには非常に強力な圧縮をかけることができており、スパースなパラメータを学習できていることがうかがえます。 MobileNeRF: Exploiting the Polygon Rasterization Pipeline for Efficient Neural Field Rendering on Mobile Architectures 5 本手法ではボリュームレンダリングを行わず、テクスチャ付き三角メッシュを学習するため、一般的なレンダリングエンジンの最適化の恩恵を受けることができます。学習は既存のNeRFと同様に日単位の時間がかかってしまうものの、レンダリング時はモバイル環境でもリアルタイムに動作します。また、モデルがメッシュで表現されているため、モデルの変形や合成、削除などを一般的な3DCGにおける頂点操作で行うことも筆者は示唆しています。 以下の節で論文の画像を用いながら学習とレンダリングの概要を説明します。 Rendering 原論文 Figure 2 から引用 学習済みモデルは三角メッシュと特徴量空間におけるテクスチャマップ、そして軽量なMLPからなります。 まずGPUのレンダリングバッファを用いて特徴量空間におけるレンダリング画像を生成します(図c)。そして各ピクセルに対してMLPを適用することでRGB空間における画像を生成します(図d)。この一連の処理はWebGLで実装でき、プロジェクトページではモデルを表示するHTMLが公開されています。 Training 原論文 Figure 3 から引用 学習開始時に、まずグリッド状に組まれた初期メッシュを用意します。そしてそのメッシュの頂点位置と、特徴量と透明度を予測するMLP、特徴量から色を予測する軽量なMLPをNeRFの手法で最適化します。ここで特徴量と透明度については光線の位置のみを入力とし、軽量なMLPは特徴量と光線方向を入力としています。そのため光線方向に依存しない特徴量と透明度は、学習が済んだ後テクスチャマップにベイク(bake)できるため、PNG画像として保存されます(Rendering図のb)。 Limitation この手法には半透明な物体を表現するのが難しいという欠点があります。 デモページ でドラムのモデルを表示した結果が次の画像です。膜の部分がうまくレンダリングできていないというのが見てわかると思います。 表現力の拡張に関する論文 K-Planes: Explicit Radiance Fields in Space, Time, and Appearance 6 グリッドベースのNeRFモデルの軽量化手法であるTensoRFでは3次元空間を平面とベクトルに分解したのに対し、本手法では 平面、 平面、 平面の3つの平面の組に分解することを提案しています。これは高次元の空間を扱うNeRFモデルにも適用でき、例えば時間経過で物体が変形するシーンにおいても、空間 の3軸と時間 の1軸から選んだ6組の平面( )で学習できるのが特長です。学習時間も比較的短く、既存手法のDyNeRF (CVPR2022)が8GPUで1週間かけていたサンプルを、1GPUで4時間に短縮できています。 原論文 Figure 1 から引用 ABLE-NeRF: Attention-Based Rendering With Learnable Embeddings for Neural Radiance Field 7 NeRFで表現が不得意な物体として光沢のある表面、透明な面が挙げられます。NeRFのボリューメトリックレンダリングで輝度は各点の密度σと点のサンプリング間隔δに影響されますが、NeRFで各点のσは視線方向によらず固定されています。これによって、NeRFは異なる角度で透過特性と反射特性の両方を示す表面点の色を予測することが困難であり、その結果「濁った」外見になってしまうという課題があります。ABLE-NeRFではAttentionベースのネットワークを利用し、Learnable Embeddingsの導入によって間接照明効果を捉えることで解決しています。 Attention-based Volumetric Rendering ボリューメトリックレンダリングにおいて点の重みは自身の重みと、光線上に存在する前の点の重みに依存します。NeRFでは光線上の点の重みをσとδに基づいて割り当てていましたが、ABLE-NeRFではTransformerモデルのAttention計算によって個々の点の重みを決定します。 ここでは与えられた光線に対して、mip-NeRF 8 で説明されているIPE(Integrated Positional Encoding)でエンコードされた、光線に沿ったボリュームの円錐台を N 個サンプリングします。各円錐ボリュームは、Embeddingブロックを通過して、ボリューム埋め込み を生成します。( i はカメラからの光線に沿った位置)また、ViT 9 のclassトークンと同様に、同じ次元のRayトークン(R)をシーケンスに付加してTransformerで処理します。 Attentionの際はMaskを利用し、ボリューム埋め込みが注目する対象を自分自身とRayトークン、光線に沿って前方にあるボリュームだけに限定します。 Learnable Embeddings ABLE-NeRFでは、他の光源から放射される間接照明効果を捉えるため、光線に沿ったボリュームを超える外部光源に対する問い合わせプロセスとしてLearnable Embeddings(LE)を組み込んでいました。 LEはViTのclassトークンと同様に静的な照明情報を保存するために使用される学習可能なネットワーク・パラメータ(メモリ・トークン)です。学習プロセスにより、シーンの照明情報がメモリとして符号化されます。推論の際、ボリューム埋め込みはLEとのCross Attentionを介して潜在空間にマッピングされ、その後、視線方向トークン(Viewトークン)でデコードされます。視線方向トークンはカメラポーズを16バンドでフーリエ符号化し、線形層でLEと同じ次元にマッピングしたものとなっています。 ABLE-NeRFの構成は下図のようになっています。AB Transformerは光線に沿ったボリュームの直接照明を出力し、LE Transformerはボリュームの視線依存の照明を出力します。2つに分離することでオーバーフィッティングを防ぐことができるようです。2つの出力を組み合わせるため、sRGBに変換する固定マッピング関数を適用して最終的な出力を得ています。 原論文 Figure 2 から引用 結果 こちらは 公式実装 をA100 GPUx8で実験した結果(レンダリング時はA100 GPUx1)です。 model train time rendering time PSNR↑ mic 25h 59s 36.84 drums 25h 59s 26.87 materials 25h 59s 35.46 この実験で示されているように、PSNRでは上の圧縮モデルの精度を上回っており、特に光沢表現が多いmaterialsで優れた精度を示しました。しかし、学習に非常に時間がかかっています。これは光線に対してAB Transformer、LE TransformerでAttention計算を繰り返し行うので計算量が膨大であるためだと考えられます。 カメラ姿勢のずれの解決に焦点を当てた論文 Local-to-Global Registration for Bundle-Adjusting Neural Radiance Fields 10 カメラ位置と姿勢が正確でない場合、レンダリングの際に歪みが生じてしまいます。そのため、bundle adjustmentsにより、カメラの位置と姿勢を正確に推論し、レンダリングの改善をします。 L2G-NeRFでは、2つの手法を組み合わせたアプローチの提案をしています。まず、異なる画像間で対応するピクセルを合わせる処理をDNNの学習により最適化され、ピクセルごとに最適なアライメントを見つけることができます。次に、グローバルアライメントではピクセルごとの対応関係に基づいて、異なる視点からの画像を重ね合わせるために画像の剛体変換のパラメータを推定しています。これにより、異なる視点からの画像を正確に重ね合わせることができレンダリングの際に生じる歪みを改善できます。下の図を見るとL2G-NeRFが他の手法と比較し、カメラ姿勢の最適化が適切にされていることがわかります。 原論文 Figure 8 から引用 最後に 本ブログでは、私たちが興味を持ったCVPR2023の論文についてご紹介しました。NTT Comでは、今回ご紹介した分野に限らず、画像や映像、さらには音声言語も含めたさまざまなメディアAI技術の論文調査や研究開発に今後も積極的に取り組んでいきます。 Ben Mildenhall, Pratul P. Srinivasan, Matthew Tancik, Jonathan T. Barron, Ravi Ramamoorthi, Ren Ng. NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis. In ECCV2020 ↩ Han Yan, Celong Liu, Chao Ma, Xing Mei. PlenVDB: Memory Efficient VDB-Based Radiance Fields for Fast Training and Rendering. In CVPR2023 ↩ Daniel Rho, Byeonghyeon Lee, Seungtae Nam, Joo Chan Lee, Jong Hwan Ko, Eunbyung Park. Masked Wavelet Representation for Compact Neural Radiance Fields. In CVPR2023 ↩ Anpei Chen, Zexiang Xu, Andreas Geiger, Jingyi Yu, Hao Su. TensoRF: Tensorial Radiance Fields. In ECCV2022 ↩ Zhiqin Chen, Thomas Funkhouser, Peter Hedman, Andrea Tagliasacchi. MobileNeRF: Exploiting the Polygon Rasterization Pipeline for Efficient Neural Field Rendering on Mobile Architectures. In CVPR2023 ↩ Sara Fridovich-Keil, Giacomo Meanti, Frederik Warburg, Benjamin Recht, Angjoo Kanazawa. K-Planes: Explicit Radiance Fields in Space, Time, and Appearance. In CVPR2023 ↩ Zhe Jun Tang, Tat-Jen Cham, Haiyu Zhao. ABLE-NeRF: Attention-Based Rendering with Learnable Embeddings for Neural Radiance Field. In CVPR2023 ↩ Jonathan T. Barron, Ben Mildenhall, Matthew Tancik, Peter Hedman, Ricardo Martin-Brualla, Pratul P. Srinivasan. Mip-NeRF: A Multiscale Representation for Anti-Aliasing Neural Radiance Fields. In ICCV2021 ↩ Alexey Dosovitskiy, Lucas Beyer, Alexander Kolesnikov, Dirk Weissenborn, Xiaohua Zhai, Thomas Unterthiner, Mostafa Dehghani, Matthias Minderer, Georg Heigold, Sylvain Gelly, Jakob Uszkoreit, Neil Houlsby. An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale. In ICLR2021 ↩ Yue Chen, Xingyu Chen, Xuan Wang, Qi Zhang, Yu Guo, Ying Shan, Fei Wang. Local-to-Global Registration for Bundle-Adjusting Neural Radiance Fields. In CVPR2023 ↩