Amazon Web Services ブログ

Amazon SageMaker Ground Truth を使用してジョブにラベルを付けるためのカスタム Angular アプリケーション構築



データサイエンティストが教師あり学習で問題を解決しようとする場合、通常、モデル構築の開始前に高い品質のラベル付きデータセットを準備する必要があります。Amazon SageMaker Ground Truth を使用することで、デキストの分類やオブ​​ジェクトの検出などさまざまなタスクのデータセットを簡単に作成し、誰でもアクセスできるようになります。

Ground Truth はカスタムのユーザー定義タスクのデータセットを構築し、どんなものにも注釈を付ける際にも役立ちます。この機能により、以下のことを実現できます。

  • ラベル付けの手順の間にトリガーできるカスタム AWS Lambda 関数。これにより、フィルタリングの例または Amazon TranslateAmazon Rekognition などの他のサービスを使用してメタデータを追加するなどの事前ラベル付けのカスタムロジック、さらにラベルの統合または品質管理のためのラベル付け後のロジックを使用できるようになります。
  • Ground Truth ワークフローと完全統合する HTML および JavaScript を使用した独自のユーザーインターフェイスを構築できるカスタムウェブテンプレート。これらのテンプレートは Crowd HTML 要素で簡単に構築できます。Crowd HTML 要素とは、カスタムテンプレートのブロックのように配置できるテキスト、動画、音声のラベル付けジョブに使用される一般的な UI 要素のセットです。
  • 対象分野のエキスパートがそろうプライベートチームを増強する必要がある場合は、AWS Marketplace および Amazon Mechanical Turk のスキルと専門知識を持つ人材の大規模なセット。厳しい審査を通過した AWS Marketplace のパートナーは、さまざまな業界のニーズ(医療向けのラベル付けなど)に適合する動画や画像注釈の特定のスキルだけでなく、多数の言語にも対応しています。

分類学に従った複雑な分類、非常に大きなマルチクラス分類、自動運転でのラベル付けタスクのような込み入ったラベル付けタスクの場合、ラベル付けを行う担当者のためにより複雑なフロントエンドアプリケーションを構築する必要がある場合があります。Angular のようなフロントエンドフレームワークはモデルビューコントローラ (MVC) といった有用な設計パターンを作成するので、こうした場合に役立ちます。このため、コードベースがより堅牢となり、UX/UI デザイナーやソフトウェアデベロッパーからなる大規模なチームによるメンテナンスが容易になります。

この投稿では、Angular と Angular 要素を使用して、Ground Truth にうまく連携する完全にカスタマイズ可能なソリューションを作成する方法について解説します。このチュートリアルでは、Ground Truth と Crowd HTML 要素を使用したカスタムラベル付けジョブの実行について理解があることを前提としています。詳細については、Build a custom data labeling workflow with Amazon SageMaker Ground Truth をご参照ください。

この投稿で説明するアプローチは Amazon Augmented AI (Amazon A2I) でも機能するため、機械学習予測での人によるレビューに必要なワークフローを簡単に構築できます。これが可能な理由は、Amazon A2I が Crowd HTML 要素を使用してカスタムワーカーテンプレートを作成するためです。詳細については、カスタムワーカーテンプレートを作成するをご参照ください。

分類法による複雑な分類のためのカスタム UI の構築

大規模なサプライチェーンの管理や、グローバル規模でのレストランや自動車メーカーなどいろんなサプライヤーとのやり取りには、さまざまな形式や言語で請求書を受け取ることがあります。オペレーションを追跡したり、財務効率を改善させたりするには、チームが裏で請求書や領収書を大きな製品カテゴリーにマッピングし、それらを階層分類法で編成する必要があります。

次の図は、コンピュータコンポーネントの階層分類法を示しています。

次の図は、食品の種類の階層分類法を示しています。

階層分類法は、リーフレベルで数千個のカテゴリーを持つことができますこのような例には、 ウェブディレクトリ(Yahoo! ディレクトリまたはオープンディレクトリプロジェクト)、ライブラリ分類スキーム(デューイ十進分類法や米国議会図書館)、自然科学、法律、医療向けアプリケーションで使用される分類スキームが含まれます。

自然言語処理 (NLP) モデルがあらゆる請求書を適切なカテゴリに自動的にタグ付けできるとしたら、どれほど便利でしょう。 あるいは、テキストラベリングツールが請求書からカテゴリを抽出できるとしたら?

密接に関連するクラスの大規模なセットを正確に分類することが本質的に難しい場合でも、最もコスト効率の高い方法で高い品質のデータセットを構築することから始めます。

Angular 要素による分類のラベル付け

次のユースケースでは、最大規模のファーストフードチェーンを運営し、世界中から材料を調達しています。NLP モデルのデータセットを構築するために、UX 調査に基づいて、作業者が請求書の説明を読み、分類法で対応するカテゴリを選択するのに参考となる単一ページのウェブアプリを考え出しました。次のスクリーンショットをご覧ください。

この実装では、[Angular 素材] タブと、カテゴリの移動を容易にするフィルターボックスを使用します。作業者が世界中から送られる請求書にラベルを付けることができるように、請求書の説明の英語訳も表示されます。さらに、Angular などのフレームワークに基づいて構築されているため、より高いレベルでの分類法によるドロップダウンや、サードパーティの API に基づいた画像や動画などの動的コンテンツなど、より多くの要素を使用して即座に実装を改善することも可能です。

このアプリケーションの詳細については、GitHub リポジトリをご参照ください。

このアプリケーションは Angular 要素を使って構築されています。このため、フレームワークに依存せずに新しい HTML 要素を定義するウェブ標準であるカスタム要素(ウェブコンポーネントとも呼ばれます)としてパッケージ化した Angular コンポーネントを作成します。これにより、後からでも Crowd HTML 要素とスムーズに統合できます。

Angular 要素の入力と出力

このユースケースでの Angular コンポーネントとは、2 つの入力(請求書の説明と請求書の翻訳)を想定しています。これらは、<ng-home> (アプリケーションのルート要素を指定するディレクティブ)のタグ属性を使用して渡されます。次に、値は src/app/home.ts の Angular コントローラで定義した @Input() 注釈によって取得されます。次のコードをご参照ください。

<ng-home source='10牛ステーキ-20パッケージ-ブランドX' translation='10 beef steak - 20 packages - brand X' id="home">loading</ng-home> 

export class Home implements OnInit {

  @Input() invoice = '';
  @Input() translation = '';
  
  ...

値は src/app/home.html にある Angular ビュー のプレースホルダー {{source}}{{translation}} で、2 つのバインドを使用してレンダリングされます。次のコードをご参照ください。

<!-- Invoice Description -->
<div class="card" >
    <div class="card-header">
        <h3>Invoice Description</h3>
    </div>
    <div>
        <p id="step1">
        <span>Invoice Description: <br />
        <b>{{ invoice }}</b></span>
        </p>
        <p style='font-weight: small; color: gray;' id="step2">
        <span>English Translation: <br /> {{ translation }}</span>
        </p>
    </div>
</div>

次のスクリーンショットは、「フードカテゴリー」のページの [食肉] タブを示しています。

カテゴリを選択して [送信] をクリックする際には、Angular コンポーネントはカテゴリ ID を含む Javascript イベントもその親 DOM 要素にブロードキャストする必要があります。これは、src/app/home.ts の Angular コントローラ@Output() を使用して行います。次のコードをご参照ください。

<button mat-button color="primary" (click)="onSubmit()" id="submitButton">Submit</button>

<table>
    ...
    <tr mat-row *matRowDef="let row; columns: displayedColumns;"
        (click)="selectRow(row)" [ngClass]="{ 'highlight': row === selectedRow }">
    </tr>
</table>
@Output('rowselected') rowselected = new EventEmitter<any>();

#called when user click on a row in the table ("selecting" a category)
selectRow(row) {
      this.selectedRow = row;
}

#called when user click on Submit button
onSubmit(){
    this.rowselected.emit(this.selectedRow);
}

Crowd HTML 要素と Angular の統合

Angular 要素と Crowd HTML 要素間の通信は、前のセクションで説明したメカニズムを介して行われます。

Build a custom data labeling workflow with Amazon SageMaker Ground Truth で説明している手順に従って、注釈を付けるテキストを渡す方法と、Angular 要素からブロードキャストされたイベントを追加してカスタムテンプレートを作成する方法を適用できます。

次のコードは、ジョブの作成に使用する完全な Liquid HTML テンプレートを示しています。このファイルは src/ フォルダーの下にある Angular アプリの index.html ルートファイルでもある必要があります。(アプリをホストするための正しい Amazon Simple Storage Service (Amazon S3) パスを使用して縮小 .js ファイルが注入された dist フォルダーの下の index.html ファイルを必ず使用してください。)

<!doctype html>
<html lang="en">
<html>
  <head>
    <script src="https://assets.crowd.aws/crowd-html-elements.js"></script>
  </head>
  <body>

    <crowd-form style="display: none;">
        <input name="annotations" id="annotations" type="hidden">
        <input name="timeElapsed" id="timeElapsed" type="hidden">
         <!-- Prevent crowd-form from creating its own button -->
        <crowd-button form-action="submit" style="display: none;"></crowd-button>
    </crowd-form>

    <div class="mat-app-background basic-container">
      <!-- Dev Mode to test the Angular Element -->
      <!-- <ng-home source='10牛ステーキ-20パッケージ-ブランドX' translation='10 beef steak - 20 packages - brand X' id="home">loading</ng-home> -->
      <ng-home source='{{ task.input.source }}' translation='{{ task.input.translatedDesc }}'>loading</ng-home>
    </div>

    <script src="<your-s3-bucket-angular-app>/runtime-es2015.js" type="module"></script>
    <script src="<your-s3-bucket-angular-app>/runtime-es5.js" nomodule defer></script>
    <script src="<your-s3-bucket-angular-app>/polyfills-es5.js" nomodule defer></script>
    <script src="<your-s3-bucket-angular-app>/polyfills-es2015.js" type="module"></script>
    <script src="<your-s3-bucket-angular-app>/styles-es2015.js" type="module"></script>
    <script src="<your-s3-bucket-angular-app>/styles-es5.js" nomodule defer></script>
    <script src="<your-s3-bucket-angular-app>/vendor-es2015.js" type="module"></script>
    <script src="<your-s3-bucket-angular-app>/vendor-es5.js" nomodule defer></script>
    <script src="<your-s3-bucket-angular-app>/main-es2015.js" type="module"></script>
    <script src="<your-s3-bucket-angular-app>/main-es5.js" nomodule defer></script>
</body>
</html>

<script>

  document.addEventListener("DOMContentLoaded", function(event) {
    // Counter
    var enterDate = new Date();
    function secondsSinceEnter()
    {
      return (new Date() - enterDate) / 1000;
    }

    // GT Form Submitting
    const component = document.querySelector('ng-home').addEventListener('rowselected', (event) => {
      // alert(event.detail.CODE);
      document.getElementById('annotations').value = event.detail.CODE;
      document.getElementById('timeElapsed').value = secondsSinceEnter();
      document.querySelector('crowd-form').submit();
    });

  });

</script>
<style>
  .body {
    background-color: #fafafa;
  }

  .header {
    background: #673ab7;
      color: #fff;
      padding: 0 16px;
      margin: 20px 20px 0px 20px;
      padding: 20px;
  }

  .cards {
    display: grid;
    grid-template-columns: 30% auto;
    grid-auto-rows: auto;
    grid-gap: 1rem;
    margin: 20px 20px 0px 20px;
  }

  .card {
    box-shadow: 0 2px 1px -1px rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 1px 3px 0 rgba(0,0,0,.12);
    transition: box-shadow 280ms cubic-bezier(.4,0,.2,1);
    display: block;
    position: relative;
    padding: 16px;
    border-radius: 4px;
    /* margin: 20px 0px 0px 20px; */
    border: 2px solid #e7e7e7;
    border-radius: 4px;
  }

  .highlight-step {
    background-color: #2515424a;
    margin: 0px -15px 0px -15px;
    padding: 15px;
  }
</style>

テンプレートの作成

上記のテンプレートを作成するには、次の手順を実行します。

  1. Crowd HTML 要素を使用できるように、テンプレートの上部に crowd-html-element.js スクリプトを追加します。
    <script src="https://assets.crowd.aws/crowd-html-elements.js"></script>
  2. ルート要素 <ng-home> で直接 Liquid のテンプレート言語を使用し、注釈を付けるテキストと、前処理の Lambda 関数からユーザーインターフェイスに送信される関連メタデータを挿入します。
    <ng-home source='{{ task.input.source }}' translation='{{ task.input.translated }}' id="home">loading</ng-home>
  3. 注釈を Ground Truth に送信する <crowd-form /> 要素を使用します。送信はバックグラウンドで行われるため、要素は非表示になっています。次のコードをご参照ください。
    <crowd-form style="display: none;">
            <input name="annotations" id="annotations" type="hidden">
            <input name="timeElapsed" id="timeElapsed" type="hidden">
             <!-- Prevent crowd-form from creating its own button -->
            <crowd-button form-action="submit" style="display: none;"></crowd-button>
    </crowd-form>
    
  4. Crowd HTML 要素を使用して注釈を送信するのではなく、Angular Element を <crowd-form /> と統合する小さなスクリプトを含めます。
    ocument.addEventListener("DOMContentLoaded", function(event) {
    
        var enterDate = new Date();    
        function secondsSinceEnter()
        {
          return (new Date() - enterDate) / 1000;
        }
      
        const component = document.querySelector('ng-home').addEventListener('rowselected', (event) => 
          document.getElementById('annotations').value = event.detail.CODE;
          document.getElementById('timeElapsed').value = secondsSinceEnter();
          document.querySelector('crowd-form').submit();
        });
      
      });
    

このユースケースでは、作業者が注釈を完了するのにかかる時間をモニタリングするためのカウンターも保持しています。

次の図は、各要素間のデータフローを示しています。

まとめ

この投稿では、Angular および Ground Truthを使用してカスタムラベル UI を構築する方法をご紹介しました。このソリューションは、ラベル付けジョブの作成で提供されるカスタムテンプレートの異なるスコープ間の通信を処理できます。Angular のようなカスタムのフロントエンドフレームワークが使用できる機能により、パブリック、プライベート、またはベンダーのラベリング作業者を利用する際に、ニーズを正確に満たす最新のウェブアプリケーションを簡単に作成できます。

Ground Truth の階層分類法の詳細については、Creating hierarchical label taxonomies using Amazon SageMaker Ground Truth をご覧ください。

この投稿についてのご意見やご質問があれば、コメント欄をご利用ください。楽しくラベル付けしましょう。


著者について

Yassine Landa は AWS のデータサイエンティストです。数学と物理学の学士号を取得し、フランスの大学でコンピューターサイエンスとデータサイエンス、ウェブインテリジェンス、環境工学の修士号も取得しています。機械学習や人工知能を使ったお客様向け製品の構築に熱心に取り組んでいるだけでなく、テック系スタートアップ企業と協力して構築した機械学習製品や、スタートアップ企業の創設者として、多くの賞も受賞しています。