著者は、 Write forDOnationsプログラムの一環として寄付を受け取るためにCode2040を選択しました。

序章

機械学習(ML)の分野が成長するにつれて、このテクノロジーを使用するための環境のリストも成長します。 これらの環境の1つはWebブラウザーであり、近年、Webベースの機械学習モデルを対象としたデータ関連のフレームワークが急増しています。 これらのフレームワークの例は、 TensorFlow.js です。これは、ブラウザーで機械学習モデルをトレーニング、実行、デプロイするためのTensorFlowのJavaScript対応ライブラリです。 MLの経験が限られている、またはまったくない開発者がTensorFlow.jsにアクセスできるようにするために、ライブラリには、すぐに使用できる事前トレーニング済みのモデルがいくつか付属しています。

事前にトレーニングされた機械学習モデルは、トレーニングする必要のないすぐに使用できる機械学習です。 TensorFlow.jsには、さまざまなユースケースに適した14が含まれています。 たとえば、一般的なオブジェクトを識別するための画像分類モデルと、体の部分を識別するための体のセグメンテーションモデルがあります。 これらのモデルの主な便利さは、名前が示すように、それらをトレーニングする必要がないことです。 代わりに、それらをアプリケーションにロードします。 使いやすさと事前にトレーニングされた性質に加えて、これらは厳選されたモデルです。これらは正確で高速であり、アルゴリズムの作成者によってトレーニングされ、Webブラウザ用に最適化されている場合があります。

このチュートリアルでは、TensorFlow.jsを使用して、 Question and Answer (QnA)の事前トレーニング済みモデルを提供するWebアプリケーションを作成します。 デプロイするモデルは、トランスフォーマーからの双方向エンコーダー表現(BERT)モデルであり、パッセージと質問を入力として使用し、パッセージからの質問に答えようとします。

GitHubなどのソースから数回クリックするだけでアプリケーションを構築、デプロイ、スケーリングするためのマネージドソリューションであるDigitalOceanのAppPlatformにアプリをデプロイします。 作成するアプリは、2つの入力フィールドを持つ静的ページで構成されています。1つはパッセージ用、もう1つは質問用です。 最終的には、GitHubから、TensorFlow.jsの事前トレーニング済みモデルの1つとDigitalOceanのアプリプラットフォームを使用して、質問と回答のアプリケーションを作成してデプロイします。

前提条件

このチュートリアルを完了するには、次のものが必要です。

ステップ1—アプリのインターフェースを作成し、必要なライブラリをインポートする

このステップでは、アプリのHTMLコードを記述します。これにより、インターフェースが定義され、アプリのライブラリがインポートされます。 これらのライブラリの最初のものはTensorFlow.jsであり、パッケージをローカルにインストールする代わりに、コンテンツ配信ネットワークまたはCDNからロードします。 CDNは、インターネットに提供するコンテンツを格納する複数の場所にまたがるサーバーのネットワークです。 このコンテンツには、TensorFlow.jsライブラリなどのJavaScriptファイルが含まれており、CDNからロードすることで、アプリケーションにそれらをパックする必要がなくなります。 同様に、QuestionandAnswerモデルを含むライブラリをインポートします。 次のステップでは、モデルを使用して特定の質問に答えるアプリのJavaScriptを記述します。

このチュートリアルでは、次のようなアプリを構築します。

アプリには5つの主要な要素があります。

  • アプリのテストに使用できる事前定義されたパッセージをロードするボタン。
  • パッセージの入力テキストフィールド(自分で作成またはコピーすることを選択した場合)。
  • 質問の入力テキストフィールド。
  • 質問に答える予測をトリガーするボタン。
  • Answer!ボタンの下にモデルの出力を表示する領域(現在は空白の空白)。

名前の付いた新しいディレクトリを作成することから始めます tfjs-qna-do ご希望の場所で。 このディレクトリで、選択したテキストエディタを使用して、という名前の新しいHTMLファイルを作成します。 index.html 次のコードを貼り付けます。

index.html
<!DOCTYPE html>
<html lang="en-US">

<head>
    <meta charset="utf-8" />
    <!-- Load TensorFlow.js -->
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
    <!-- Load the QnA model -->
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/qna"></script>
    <link href="./style.css" rel="stylesheet">
</head>

<body>
    <div class="main-centered-container">
        <h1>TensorFlow.js Pre-trained "QnA" BERT model</h1>
        <h3 class="header-border">Introduction</h3>
        <p>This application hosts TensorFlow.js' pre-trained Question and Answer model, and it attempts to answer the question
        using a given passage. To use it, write a passage (any!) in the input area below and a question. Then, click the
        "answer!" button to answer the question using the given passage as a reference. You could also click the test
        button to load a pre-defined input text.</p>
        
        <h4>Try the test passage!</h4>
        <div id='test-buttons'></div>

        <div>
            <h4>Enter the model's input passage here</h4>
            <textarea id='input-text' rows="20" cols="100" placeholder="Write the input text..."></textarea>
        </div>
        
        <div>
            <h4>Enter the question to ask</h4>
            <textarea id='question' rows="5" cols="100" placeholder="Write the input text..."></textarea>
        </div>
        <h4>Click to answer the question</h4>
        <div id="answer-button"></div>
        <h4>The model's answers</h4>
        <div id='answer'></div>
        
        <script src="./index.js"></script>

        
    </div>
</body>

</html>

そのHTMLの内訳は次のとおりです。

  • 初期 <html> タグには <head> メタデータ、スタイルの定義、およびスクリプトのロードに使用されるタグ。 その最初の要素は <meta>、ここでページを設定します charset にエンコードする utf-8. その後、2つあります <script> CDNからTensorFlow.jsとQuestionandAnswerモデルの両方をロードするためのタグ。
  • 2つに続いて <script> タグ、あります <link> CSSファイル(次に作成するファイル)をロードするタグ。
  • 次に、HTMLがあります <body>-ドキュメントのコンテンツ。 その中には、 <div> クラスのタグ main-centered-container ページの要素を含みます。 最初は <h1> アプリケーションタイトルと小さいヘッダー <h3> ヘッダーの後に、それがどのように機能するかを説明する簡単な紹介が続きます。
  • イントロダクションの下に、 <h4> ヘッダーと <div> ここで、パッセージ入力テキストフィールドにサンプルテキストを入力するボタンを追加します。
  • 次に、アプリの入力フィールドがあります。1つはパッセージ(モデルに読み取らせたいもの)用、もう1つは質問(モデルに答えてもらいたいもの)用です。 サイズを変更したい場合は、 rowscols 属性。
  • テキストフィールドの後に、 <div> ID付き button ここで、後でクリックするとテキストフィールドのテキストを読み取り、モデルへの入力として使用するボタンを追加します。
  • 最後に、 <div> ID付き answer これは、モデルの出力と <script> 次のセクションで作成するJavaScriptコードを含めるタグ。

次に、CSSをプロジェクトに追加します。 追加したのと同じディレクトリ内 index.html ファイル、という名前の新しいファイルを作成します style.css 次のコードを追加します。

style.css
body {
  margin: 50px 0;
  padding: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial;
}

button {
  margin: 10px 10px;
  font-size: 100%;
}

p {
  line-height: 1.8;
}

.main-centered-container {
  padding: 60px;
  display: flex;
  flex-direction: column;
  margin: 0 auto;
  max-width: 960px;
}

.header-border {
  border: solid #d0d0d0;
  border-width: 0 0 1px;
  padding: 0 0 5px;
}

このCSSは、本文、ボタン、段落の3つのHTML要素にスタイルを追加します(<p>). に body、マージンとパディングを追加し、デフォルトのフォントを変更します。 に button、マージンを追加し、フォントサイズを大きくします。 段落へ p、それは変更します line-height 属性。 CSSにはクラスがあります main-centered-container コンテンツと別のコンテンツを中央に配置し、 header-border、要素に実線を追加します。

このステップでは、アプリのHTMLファイルを作成しました。 TensorFlow.jsライブラリとQnAモデルをインポートし、後で回答するパッセージと質問を追加するために使用する要素を定義しました。 次の手順では、要素を読み取り、予測をトリガーするJavaScriptコードを記述します。

ステップ2—事前トレーニング済みモデルを使用した予測

このセクションでは、アプリの入力フィールドを読み取り、予測を行い、予測された回答をHTMLで書き込むWebアプリのJavaScriptコードを実装します。 「回答」ボタンをクリックするとトリガーされる1つの機能でそれを行います。 クリックすると、両方の入力フィールドを参照して値を取得し、モデルへの入力として使用して、その出力を <div> ID付き output 手順1で定義しました。 次に、アプリをローカルで実行してテストしてから、GitHubに追加します。

プロジェクトのディレクトリ内 tfjs-qna-do/、という名前の新しいファイルを作成します index.js、および次の変数を宣言します。

index.js
let model;

// The text field containing the input text
let inputText;

// The text field containing the question
let questionText;

// The div where we will write the model's answer
let answersOutput;

最初の変数、 model、QnAモデルを保存する場所です。 inputTextquestionText 入力および質問テキストフィールドへの参照です。 answersOutput 出力への参照です <div>.

これらの変数に加えて、アプリのテストに使用するサンプルテキストを格納するための定数が必要になります。 サンプルパッセージとして、DigitalOceanに関するウィキペディアの記事を使用します。 この一節に基づいて、「DigitalOceanの本社はどこにありますか?」などのモデルの質問をすることができます。 そしてうまくいけば、それは「ニューヨーク」を出力します。

このブロックをあなたの index.js ファイル:

index.js
// Sample passage from Wikipedia.
const doText = `DigitalOcean, Inc. is an American cloud infrastructure provider[2] headquartered in New York City with data centers worldwide.[3] 
DigitalOcean provides developers cloud services that help to deploy and scale applications that run simultaneously on multiple computers.
DigitalOcean also runs Hacktoberfest which is a month-long celebration (October 1-31) of open source software run in partnership with GitHub and Twilio.
`;

次に、アプリの機能を定義します。 createButton(). この関数はボタンを作成し、それをHTML要素に追加します。

index.js
function createButton(innerText, id, listener, selector, disabled = false) {
  const btn = document.createElement('BUTTON');
  btn.innerText = innerText;
  btn.id = id;
  btn.disabled = disabled;

  btn.addEventListener('click', listener);
  document.querySelector(selector).appendChild(btn);
}

createButton() アプリの2つのボタンを作成する関数です。 すべてのボタンが同じように機能するため、この関数はコードの繰り返しを回避します。 この関数には5つのパラメーターがあります。

  • innerText:ボタンのテキスト。
  • id:ボタンのID。
  • listener:ユーザーがボタンをクリックしたときに実行されるコールバック関数。
  • selector<div> ボタンを追加する要素。
  • disabled:ボタンを無効または有効にするブール値。 このパラメータのデフォルト値は false.

createButton() ボタンのインスタンスを作成し、それを変数に割り当てることから始めます btn. 次に、ボタンを設定します innerText, id、 と disabled 属性。 ボタンは、クリックするたびにコールバック関数を実行するクリックイベントリスナーを使用します。 関数の最後の行は、ボタンをに追加します <div> で指定された要素 selector パラメータ。

次に、という名前の新しい関数を作成します setupButtons() それは createButton() アプリのボタンを作成するために2回。 アプリのAnswer!ボタンを作成することから始めます。

index.js
function setupButtons() {
  // Button to predict
  createButton('Answer!', 'answer-btn',
    () => {
      model.findAnswers(questionText.value, inputText.value).then((answers) => {
        // Write the answers to the output div as an unordered list.
        // It uses map create a new list of the answers while adding the list tags.
        // Then, we use join to concatenate the answers as an array with a line break
        // between answers.
        const answersList = answers.map((answer) => `<li>${answer.text} (confidence: ${answer.score})</li>`)
          .join('<br>');

        answersOutput.innerHTML = `<ul>${answersList}</ul>`;
      }).catch((e) => console.log(e));
    }, '#answer-button', true);
}

関数が作成する最初のボタンは、予測をトリガーするボタンです。 その最初の2つの引数、 innerTextid、はボタンのテキストとボタンに割り当てる識別子です。 3番目の引数は、リスナーのコールバックです(以下で説明します)。 4番目の引数、 selector、はのIDです

ボタンを追加したい場所(#answer-button)、および5番目の引数、 disabled、 に設定されています true、ボタンを無効にします(アプリがモデルをロードする前に予測しないようにするため)。

リスナーのコールバックは、 Answer!ボタンをクリックすると実行される関数です。 クリックすると、コールバック関数は最初に事前トレーニングされたモデルの関数を呼び出します findAnswers(). (詳細については findAnswers() 機能については、製品ドキュメントを参照してください)。 findAnswers() 入力パッセージを引数として使用します( questionText)と質問(から読む inputText). モデルの出力を次のような配列で返します。

Model's output
[ { "text": "New York City", "score": 19.08431625366211, "startIndex": 84, "endIndex": 97 }, { "text": "in New York City", "score": 8.737937569618225, "startIndex": 81, "endIndex": 97 }, { "text": "New York", "score": 7.998648166656494, "startIndex": 84, "endIndex": 92 }, { "text": "York City", "score": 7.5290607213974, "startIndex": 88, "endIndex": 97 }, { "text": "headquartered in New York City", "score": 6.888534069061279, "startIndex": 67, "endIndex": 97 } ]

配列の各要素は、次の4つの属性のオブジェクトです。

  • text: 答え。
  • score:モデルの信頼水準。
  • startIndex:質問に答えるパッセージの最初の文字のインデックス。
  • endIndex:回答の最後の文字のインデックス。

モデルが出力を返すときに出力を表示する代わりに、コールバックは map() リストを追加しながら、モデルの回答とスコアを含む新しい配列を作成する関数 <li> HTMLタグ。 次に、配列の要素を <br> (改行)回答の間に結果を割り当てます answer <div> それらをリストとして表示します。

次に、2番目の呼び出しを追加します createButton(). 強調表示された部分をに追加します setupButtons 最初の下で機能する createButton:

index.js
function setupButtons() {
  // Button to predict
  createButton('Answer!', 'answer-btn',
    () => {
      model.findAnswers(questionText.value, inputText.value).then((answers) => {
        // Write the answers to the output div as an unordered list.
        // It uses map create a new list of the answers while adding the list tags.
        // Then, we use join to concatenate the answers as an array with a line break
        // between answers.
        const answersList = answers.map((answer) => `<li>${answer.text} (confidence: ${answer.score})</li>`)
          .join('<br>');

        answersOutput.innerHTML = `<ul>${answersList}</ul>`;
      }).catch((e) => console.log(e));
    }, '#answer-button', true);

  createButton('DigitalOcean', 'test-case-do-btn',
    () => {
     document.getElementById('input-text').value = doText;
    }, '#test-buttons', false);
}

この新しい呼び出しはに追加されます test-buttons <div> 変数で前に定義したDigitalOceanサンプルテキストをロードするボタン doText. 関数の最初の引数はボタンのラベル( DigitalOcean )であり、2番目の引数は id、3番目は、パッセージ入力テキスト領域に値を書き込むリスナーのコールバックです。 doText 変数、4番目は selector、そして最後は false 値(ボタンの無効化を回避するため)。

次に、という名前の関数を作成します init()、他の関数を呼び出します:

index.js
async function init() {
  setupButtons();
  answersOutput = document.getElementById('answer');
  inputText = document.getElementById('input-text');
  questionText = document.getElementById('question');

  model = await qna.load();
  document.getElementById('answer-btn').disabled = false;
}

init() 呼び出すことから始まります setupButtons(). 次に、スクリプトの上部で定義した変数にアプリのHTML要素の一部を割り当てます。 次に、QnAモデルをロードし、次のように変更します。 false 回答の無効な属性(answer-btn) ボタン。

ラスト・オーダー init():

index.js
init();

アプリが完成しました。 テストするには、Webブラウザを開き、プロジェクトのディレクトリ絶対パスを次のように記述します。 /index.html アドレスバーに追加されます。 ファイルマネージャアプリケーション(MacのFinderなど)を開き、「index.html」をクリックしてWebアプリケーションを開くこともできます。 この場合、アドレスは次のようになります。 your_filepath/tfjs-qna-do/index.html.

絶対パスを見つけるには、ターミナルに移動し、プロジェクトのディレクトリから次のコマンドを実行します。

  1. pwd

その出力は次のようになります。

Output
/Users/your_filepath/tfjs-qna-do

アプリを起動した後、モデルをダウンロードしてロードするまで数秒待つ必要があります。 アプリがAnswer!ボタンを有効にすると、準備ができたことがわかります。 次に、テスト通過ボタンを使用することができます(DigitalOcean)または独自の文章を書いて、質問を入力します。

アプリをテストするには、「DigitalOcean」ボタンをクリックします。 パッセージ入力エリアには、DigitalOceanに関するサンプルテキストが表示されます。 質問入力領域に、「DigitalOceanの本社はどこにありますか?」と記入します。 パッセージから、答えは「ニューヨーク」であることがわかります。 しかし、モデルは同じことを言うでしょうか? Answer!をクリックして確認してください。

出力は次のようになります。

正しい! わずかな違いはありますが、5つの回答のうち4つは、DigitalOceanの本社がニューヨーク市にあると述べています。

このステップでは、Webアプリケーションを完成させてテストしました。 作成したJavaScriptコードは、入力パッセージと質問を読み取り、それをQnAモデルへの入力として使用して質問に回答します。 次に、コードをGitHubに追加します。

ステップ3—アプリをGitHubにプッシュする

このセクションでは、WebアプリケーションをGitHubリポジトリに追加します。 後で、リポジトリをDigitalOceanのApp Platformに接続し、アプリをデプロイします。

GitHubにログインすることから始めます。 メインページから、名前の下にある緑色のボタンまたは画面の右上隅にあるプラス記号をクリックして、新しいリポジトリを作成します。

どちらを選択しても、新しいリポジトリの作成画面が表示されます。 リポジトリ名フィールド(ユーザー名の後)で、リポジトリにtfjs-qna-doという名前を付けます。 プライバシー設定を選択し、リポジトリの作成をクリックして作成します。

ターミナルを開き、プロジェクトのディレクトリに移動します tfjs-qna-do/. そこで、次のコマンドを実行して、新しいローカルGitリポジトリを作成します。

  1. git init

次に、追跡するファイルをGitでステージングします。この場合は、ディレクトリ内のすべてのものです。

  1. git add .

そしてそれらをコミットします:

  1. git commit -m "initial version of the app"

リポジトリの主分岐の名前を次のように変更します main:

  1. git branch -M main

次に、ローカルリポジトリをGitHub上のリモートリポジトリにリンクします。

  1. git remote add origin [email protected]:your-github-username/tfjs-qna-do.git

最後に、ローカルコードベースをリモートリポジトリにプッシュします。

  1. git push -u origin main

コードをGitHubにプッシュするのが初めての場合は、GitHubのクレデンシャルを入力するように求められます。

コードをプッシュしたら、GitHubリポジトリに戻り、ページを更新します。 コードが表示されます。

このステップでは、WebアプリのコードをリモートのGitHubリポジトリにプッシュしました。 次に、このリポジトリをDigitalOceanアカウントにリンクし、アプリをデプロイします。

ステップ4— DigitalOceanAppPlatformにWebアプリケーションをデプロイする

この最後のセクションでは、質問と回答のアプリを、手順3で作成したGitHubリポジトリからDigitalOceanの App Platform )にデプロイします。

まず、DigitalOceanアカウントにログインします。 ログインしたら、右上隅にある Create 緑色のボタンをクリックしてから、Appsをクリックします。 これにより、新しいアプリの作成画面が表示されます。

ここでは、プロジェクトが存在するソースとしてGitHubを選択します。

DigitalOceanアカウントをGitHubにリンクしていない場合は、DigitalOceanにGitHubへのアクセスを許可するように求められます。 その後、リンクするリポジトリtfjs-qna-doを選択します。

[アプリプラットフォーム]ウィンドウに戻り、アプリのリポジトリ( tfjs-qna-do )、アプリのデプロイ元のブランチ( main )を選択し、を確認します。自動デプロイコードの変更ボックス; このオプションにより、コードをmainブランチにプッシュするたびにアプリケーションが再デプロイされます。

次の画面で、アプリを構成します、デフォルトの構成値を使用します。 追加の手順として、WebアプリのHTTPリクエストルートを、たとえばデフォルトのhttps://example.ondigitalocean.app/tfjs-qna-doからに変更する場合https://example.ondigitalocean.app/ my-custom-route HTTPRoutesの下のEditをクリックし、 my- ROUTES入力のcustom-route

次に、サイトに名前を付けます。 ここでも、デフォルトの tfjs-qna-do 名をそのままにするか、別の名前に置き換えることができます。

次へをクリックすると、最後の画面確定して起動が表示され、アプリの料金階層が選択されます。 アプリは静的なウェブページであるため、AppPlatformは無料のスタータープランを自動的に選択します。 最後に、 Starter App ボタンをクリックして、アプリケーションをビルドおよびデプロイします。

アプリがデプロイされている間、次のような画面が表示されます。

デプロイすると、次のように表示されます。

アプリにアクセスするには、アプリのURLをクリックして、クラウドにデプロイされているアプリにアクセスします。

結論

機械学習の分野が拡大するにつれて、Webブラウザを含む到達する環境やプラットフォームとともにそのユースケースも拡大します。

このチュートリアルでは、TensorFlow.jsの事前トレーニング済みモデルを使用するWebアプリケーションを構築してデプロイしました。 Question and Answer Webアプリは、質問とともにパッセージを入力として受け取り、事前にトレーニングされたBERTモデルを使用して、パッセージに従って質問に回答します。 アプリを開発した後、GitHubアカウントをDigitalOceanにリンクし、追加のコードを必要とせずにアプリケーションをAppPlatformにデプロイしました。

今後の作業として、アプリに変更を追加してGitHubにプッシュすることで、アプリの自動デプロイをトリガーできます。 また、新しいテストパッセージを追加し、回答の出力を表としてフォーマットして、読みやすさを向上させることもできます。

TensorFlow.jsの詳細については、その公式ドキュメントを参照してください。