機械知能のための TensorFlow 実践: 製品環境へのモデルの導入

機械知能のための TensorFlow 実践: 製品環境へのモデルの導入

TesnsorFlow を使用して、基本的な機械学習モデルから複雑なディープラーニング ネットワークまで、さまざまなモデルを構築およびトレーニングする方法を理解した後は、トレーニングしたモデルを製品に組み込んで他のアプリケーションで使用できるようにする方法を検討する必要があります。この記事では、これについて詳しく紹介します。この記事は、「TensorFlow Practice for Machine Intelligence」の第 7 章から抜粋したものです。

この記事では、ユーザーが画像をアップロードし、その画像に対して Inception モデルを実行して画像を自動的に分類できるシンプルな Web アプリを作成します。

TensorFlowサービス開発環境を構築する

Docker イメージ

TensorFlow Serving は、製品で提供されるモデルをユーザーが使用できるようにするサーバーを構築するためのツールです。開発中にこのツールを使用するには、すべての依存関係とツールを手動でインストールしてソースからビルドする方法と、Docker イメージを使用する方法の 2 つがあります。後者の方がより簡単かつクリーンであり、Linux 以外の環境での開発も可能なので、後者を使用します。

Docker イメージに詳しくない場合は、完全なオペレーティング システムを内部で実行する必要のない軽量の仮想マシン イメージと考えてください。 Docker がまだインストールされていない場合は、開発マシンにインストールしてください。詳細なインストール手順を確認するには、ここをクリックしてください (https://docs.docker.com/engine/installation/)。

Docker イメージを使用するには、ローカルでイメージを作成するための設定ファイルである、作者が提供しているファイル (https://github.com/tensorflow/serving/blob/master/tensorflow_serving/tools/docker/Dockerfile.devel) を使用することもできます。このファイルを使用するには、次のコマンドを使用します。

  1. docker build --pull -t $USER/tensorflow-serving-devel  
  2.  
  3. https://raw.githubusercontent.com/tensorflow/serving/master/
  4.  
  5. tensorflow_serving/tools/docker/Dockerfile.devel

上記のコマンドを実行した後、すべての依存関係をダウンロードするのに長い時間がかかる場合があることに注意してください。

上記のコマンドを実行した後、このイメージを使用してコンテナを実行するには、次のコマンドを入力します。

  1. docker run -v $HOME:/mnt/home -p 9999:9999 -it $ USER /
  2.  
  3. テンソルフローサービング開発

このコマンドは、ホーム ディレクトリをコンテナーの /mnt/home パスに読み込み、その内部のターミナルで作業できるようにします。これは、ビルド ツールを実行するときにのみコンテナーを使用しながら、お気に入りの IDE またはエディターを使用してコードを直接編集できるため、非常に便利です。また、ポート 9999 も開かれるので、独自のホストからアクセスでき、後で構築するサーバーで使用できるようになります。

exit コマンドを入力してコンテナ ターミナルを終了し、実行を停止します。必要に応じて上記のコマンドを使用して起動することもできます。

Bazel ワークスペース

TensorFlow サービング プログラムは C++ で記述されているため、Google の Bazel ビルド ツールを使用してビルドする必要があります。最近作成したコンテナ内から Bazel を実行します。

Bazel はコード レベルでサードパーティの依存関係を管理し、それらも Bazel でビルドする必要がある場合は自動的にダウンロードしてビルドします。プロジェクトがサポートするサードパーティの依存関係を定義するには、プロジェクト リポジトリのルート ディレクトリに WORKSPACE ファイルを定義する必要があります。

必要な依存関係は TensorFlow Serving ライブラリです。私たちの場合、TensorFlow モデル リポジトリには Inception モデルのコードが含まれています。

残念ながら、この記事の執筆時点では、TensorFlow Serving は Bazel が直接参照する Git リポジトリとしてはまだサポートされていないため、プロジェクトに Git サブモジュールとして含める必要があります。

  1. # ローカルマシン上
  2.  
  3. mkdir ~/serving_example
  4.  
  5. cd ~/serving_example
  6.  
  7. git 初期化
  8.  
  9. git サブモジュールを追加https://github.com/tensorflow/serving.git
  10.  
  11. tf_serving
  12.  
  13. git.submodule更新- -init - -recursive

次に、WORKSPACE ファイルの local_repository ルールを使用して、サードパーティの依存関係をローカルに保存されたファイルとして定義します。さらに、プロジェクトからインポートされた tf_workspace ルールを使用して、TensorFlow の依存関係を初期化する必要があります。

  1. Bazel WORKSPACE ファイル
  2.  
  3. ワークスペース(名前= "serving" )
  4.  
  5. ローカルリポジトリ(
  6.  
  7. 名前= "tf_serving"
  8.  
  9. パス = _workspace_dir__ + "/tf_serving"
  10.  
  11. ローカルリポジトリ(
  12.  
  13. 名前= "org_tensorflow"
  14.  
  15. パス = _workspace_dir__ + "/tf_serving/tensorflow"
  16.  
  17.  
  18. ロード( '//tf_serving/tensorflow/tensorflow:workspace.bzl'
  19.  
  20. 'tf_workspace' )
  21.  
  22. tf_workspace( "tf_serving/tensorflow/" "@org_tensorflow" )
  23.  
  24. バインド(
  25.  
  26. 名前= "libssl"
  27.  
  28. 実際 = "@boringssl_git//:ssl"
  29.  
  30.  
  31. バインド(
  32.  
  33. 名前= "zlib"
  34.  
  35. 実際 = "@zlib_archive//:zlib"  
  36.  
  37.  
  38. # インセプションモデルをインポートする場合にのみ必要
  39.  
  40. ローカルリポジトリ(
  41.  
  42. 名前= "inception_model"
  43.  
  44. パス = __workspace_dir__ + "/tf_serving/tf_models/
  45.  
  46. 「インセプション」、
  47.  
  48.  
  49. 最後に、コンテナ内から Tensorflow の ./configure を実行する必要があります。
  50.  
  51. # Dockerコンテナ内
  52.  
  53. cd /mnt/home/serving_example/tf_serving/tensorflow
  54.  
  55. ./configure

トレーニング済みモデルをエクスポートする

モデルのトレーニングが完了し、評価の準備ができたら、データフロー グラフとその変数値をエクスポートして、本番環境で使用できるようにする必要があります。

モデルのデータ フロー グラフは、プレースホルダーから入力を受け取り、それらに対して単一の推論ステップを実行して出力を計算する必要があるため、トレーニング バージョンとは異なる必要があります。 Inception モデルの例や一般的な画像認識モデルでは、入力を JPEG エンコードされた画像を表す文字列にして、それを消費アプリに簡単に渡せるようにする必要があります。これは、TFRecord ファイルからトレーニング入力を読み取ることとはまったく異なります。

入力を定義する一般的な形式は次のとおりです。

  1. def convert_external_inputs(external_x):
  2.  
  3. #外部入力を推論に必要な入力形式に変換する
  4.  
  5. 定義推論(x):
  6.  
  7. #オリジナルモデルより…
  8.  
  9. external_x = tf.placeholder(tf.string)
  10.  
  11. x = convert_external_inputs(外部x)
  12.  
  13. y = 推論(x)

上記のコードでは、入力に対してプレースホルダーが定義され、プレースホルダーによって表される外部入力を元の推論モデルに必要な入力形式に変換する関数が呼び出されます。たとえば、JPEG 文字列を Inception モデルに必要な画像形式に変換する必要があります。最後に、元のモデル推論メソッドが呼び出され、変換された入力に基づいて推論結果が取得されます。

たとえば、Inception モデルの場合、次のメソッドが必要です。

  1. テンソルフローをtfとしてインポートする
  2.  
  3. tensorflow_serving.session_bundleインポート エクスポーター
  4.  
  5. inception_modelからインポート
  6.  
  7. デフconvert_external_inputs(external_x)
  8.  
  9. # 外部入力を推論に必要な入力形式に変換する
  10.  
  11. # 画像文字列を [0,1] の成分を持つピクセルテンソルに変換します
  12.  
  13. 画像 =
  14.  
  15. tf.image.convert_image_dtype(tf.image.decode_jpeg(external_x,
  16.  
  17. チャンネル=3)、tf.float32)
  18.  
  19. # モデルが想定する幅と高さに合わせて画像サイズを拡大縮小します
  20.  
  21. 画像 = tf.image.resize_bilinear(tf.expand_dims(画像,
  22.  
  23. 0),[299,299])
  24.  
  25. # ピクセル値をモデルに必要な区間[-1,1]に変換する
  26.  
  27. 画像 = tf.mul(tf.sub(画像,0.5),2)
  28.  
  29. 画像を返す
  30.  
  31.  
  32. def推論(画像):
  33.  
  34. ロジット、_ = inception_model.inference(画像、1001)
  35.  
  36. リターンロジット

この推論方法では、すべてのパラメータに値を割り当てる必要があります。これらのパラメータ値をトレーニングチェックポイントから復元します。前の章では、モデルのトレーニング チェックポイント ファイルを定期的に保存したことを覚えているかもしれません。これらのファイルには、その時点で学習したパラメータが含まれているため、異常が発生してもトレーニングの進行には影響しません。

トレーニングの終了時に、最後に保存されたトレーニング チェックポイント ファイルには、最後に更新されたモデル パラメータが含まれます。これが本番環境で使用するバージョンです。

チェックポイント ファイルを復元するには、次のコードを使用します。

  1. セーバー = tf.train.Saver()
  2.  
  3. tf.Session()を sessとして使用:
  4.  
  5. # トレーニングチェックポイントファイルからトランザクションを復元する
  6.  
  7. ckpt = tf.train.get_checkpoint_state(sys.argv[1])
  8.  
  9. ckptおよびckpt.model_checkpoint_path の場合:
  10.  
  11. saver.restore(sess, sys.argv[1])+”/”+
  12.  
  13. ckpt.model_checkpoint_path)
  14.  
  15. それ以外
  16.  
  17. print("チェックポイントファイルが見つかりません")
  18.  
  19. SystemExit を起動する

Inception モデルの場合、事前トレーニング済みのチェックポイント ファイルを次のリンクからダウンロードできます: http://download.tensorflow.org/models/image/imagenet/inception-v3-2016-03-01.tar.gz。

  1. # Dockerコンテナ内
  2.  
  3. cd/tmp
  4.  
  5. curl -O http://download.tensorflow.org/models/image/imagenet/
  6.  
  7. インセプション-v3-2016-03-01.tar.gz
  8.  
  9. tar –xzf インセプション-v3-2016-03-01.tar.gz

最後に、tensorflow_serving.session_bundle.exporter.Exporter クラスを使用してモデルをエクスポートします。セーバーインスタンスを渡すことでそのインスタンスを作成します。次に、exporter.classification_signature メソッドを使用してモデルの署名を作成する必要があります。このシグネチャは、input_tensor が何で、出力テンソルが何であるかを指定します。出力は、出力クラス名のリストを含む classes_tensor と、モデルが各クラスに割り当てたスコア (または確率) を含む socres_tensor で構成されます。通常、カテゴリの数がかなり多いモデルでは、tf.nn.top_k によって選択されたカテゴリのみ、つまりモデルによって割り当てられたスコアの降順で上位 K 個のカテゴリのみが返されるように構成で指定する必要があります。

最後のステップは、exporter.Exporter.init メソッドを呼び出し、出力パス、モデル バージョン番号、およびセッション オブジェクトを受け取る export メソッドを介してモデルをエクスポートするこのシグネチャを適用することです。

  1. スコア、class_ids=tf.nn.top_k(y,NUM_CLASS_TO_RETURN)
  2.  
  3. #簡単にするために、カテゴリIDのみを返します。カテゴリIDは別々に名前を付ける必要があります。
  4.  
  5. クラス =
  6.  
  7. tf.contrib.lookup.index_to_string(tf.to_int64(クラスID)
  8.  
  9. マッピング = tf.constant([str(i) for i in range(1001)]))
  10.  
  11.  
  12. model_exporter = exporter.Exporter(saver)
  13.  
  14. 署名 = exporter.classification_signature(
  15.  
  16. input_tensor=external_x、classes_tensor=クラス、
  17.  
  18. scores_tensor=スコア)
  19.  
  20. model_exporter.init(default_graph_signature=署名、
  21.  
  22. init_op = tf.initialize_all_tables())
  23.  
  24. model_exporter.export(sys.argv[1]+ "/export"  
  25.  
  26. tf.constant(時間.時間()), sess)

Exporter クラス コードには自動生成されたコードへの依存関係があるため、Docker コンテナー内で bazel を使用してエクスポーターを実行する必要があります。

これを行うには、先ほど起動した bazel ワークスペースの exporter.py にコードを保存する必要があります。さらに、次のようなビルド ルールを含む BUILD ファイルが必要になります。

  1. # ビルドファイル
  2.  
  3. py_binary(
  4.  
  5. 名前= "エクスポート"
  6.  
  7. ソース =[
  8.  
  9. 「エクスポート.py」、
  10.  
  11. ]、
  12.  
  13. 依存関係 = [
  14.  
  15. "//tensorflow_serving/session_bundle:エクスポーター",
  16.  
  17. "@org_tensorflow//tensorflow:tensorflow_py",
  18.  
  19. #インセプションモデルをエクスポートする場合にのみ必要
  20.  
  21. 「@inception_model//インセプション」、
  22.  
  23. ]、
  24.  

次のコマンドを使用して、コンテナ内でエクスポーターを実行できます。

  1. # Dockerコンテナ内
  2.  
  3. cd /mnt/home/serving_example

/tmp/inception-v3 から抽出できるチェックポイント ファイルに基づいて、/tmp/inception-v3/{current_timestamp}/ にエクスポーターを作成します。

初めて実行するときには TensorFlow をコンパイルする必要があるため、時間がかかることに注意してください。

サーバーインターフェースの定義

次に、エクスポートされたモデル用のサーバーを作成する必要があります。

TensorFlow Serving は gRPC プロトコルを使用します (gRPC は HTTP/2 に基づくバイナリ プロトコルです)。サーバーを作成するためのさまざまな言語をサポートし、クライアントスタブを自動的に生成します。 TensorFlow は C++ に基づいているため、独自のサーバーを定義する必要があります。幸いなことに、サーバー側のコードは比較的短いです。

gRPS を使用するには、gRPC の IDL (インターフェイス定義言語) およびバイナリ エンコーディングであるプロトコル バッファーでサービス コントラクトを定義する必要があります。私たちのサービスを定義しましょう。前のエクスポート セクションで説明したように、JPEG エンコードされた画像文字列を入力として受け取り、分類してスコア順にランク付けされた推定カテゴリのリストを返すサービスが必要です。

このようなサービスは、次のように、classification_service.proto ファイルで定義する必要があります。

  1. 構文 = "proto3" ;
  2.  
  3. メッセージ分類要求 {
  4.  
  5. //JPEG エンコードされた画像文字列
  6.  
  7. バイト入力 = 1;
  8.  
  9. };
  10.  
  11. メッセージ分類応答{
  12.  
  13. 繰り返される ClassificationClass クラス = 1;
  14.  
  15. };
  16.  
  17. メッセージ分類クラス {
  18.  
  19. 文字列= 1;
  20.  
  21. フロートスコア = 2;
  22.  
  23. }

画像、オーディオ クリップ、またはテキストを受信できるあらゆる種類のサービスに同じインターフェイスを使用できます。

データベース レコードのような構造化された入力を使用するには、ClassificationRequest メッセージを変更する必要があります。たとえば、Iris データセットの分類サービスを構築しようとする場合は、次のようなコードを記述します。

  1. メッセージ分類要求 {
  2.  
  3. フロート花びらの幅 = 1;
  4.  
  5. フロートペタの高さ = 2;
  6.  
  7. フロート花びらの幅 = 3;
  8.  
  9. フロートペタの高さ = 4;
  10.  
  11. }

この proto ファイルは、proto コンパイラによってクライアントとサーバーの対応するクラス定義に変換されます。 protobuf コンパイラを使用するには、次のような新しいルールを BUILD ファイルに追加する必要があります。

  1. ロード( "@protobuf//:protobuf.bzl" "cc_proto_library" )
  2.  
  3. cc_proto_library(
  4.  
  5. 名前= "classification_service_proto"
  6.  
  7. srcs = [ "classification_service.proto" ],
  8.  
  9. cc_libs = [ "@protobuf//:protobuf" ],
  10.  
  11. protoc = "@protobuf//:protoc"
  12.  
  13. default_runtime = "@protobuf//:protobuf"
  14.  
  15. 使用_grpc_plugin=1
  16.  

上記のコード スニペットの上部にある負荷に注意してください。外部からインポートされた protobuf ライブラリから cc_proto_library ルール定義をインポートします。次に、それを使用して proto ファイルのビルド ルールを定義します。 bazel build :classification_service_proto を使用してビルドを実行し、bazel-genfiles/classification_service.grpc.pb.h を通じて結果を検査します。

  1.  
  2. クラス分類サービス {
  3.  
  4. ...
  5.  
  6. クラスService: public ::grpc::Service{
  7.  
  8. 公共
  9.  
  10. サービス();
  11.  
  12. 仮想 ~Service();
  13.  
  14. 仮想 ::grpc::Status 分類(::grpc::ServerContext*
  15.  
  16. コンテキスト、const ::ClassificationRequest*
  17.  
  18. リクエスト、::ClassificationResponse* レスポンス);
  19.  
  20. };

推論ロジックによれば、ClassificationService::Service は実装する必要があるインターフェースです。 bazel-genfiles/classification_service.pb.h をチェックすることで、リクエスト メッセージとレスポンス メッセージの定義を確認することもできます。

  1.  
  2. クラス ClassificationRequest:
  3.  
  4. パブリック::google::protobuf::Message {
  5.  
  6. ...
  7.  
  8. const ::std::string& input() const;
  9.  
  10. void set_input(const ::std::string& 値);
  11.  
  12. ...
  13.  
  14. }
  15.  
  16. クラス ClassificationResponse:
  17.  
  18. パブリック::google::protobuf::Message {
  19.  
  20. ...
  21.  
  22. const ::ClassificationClass& classes() const;
  23.  
  24. void set_allocated_classes(::ClassificationClass*
  25.  
  26. クラス);
  27.  
  28. ...
  29.  
  30. }
  31.  
  32. クラス分類クラス:
  33.  
  34. パブリック::google::protobuf::Message {
  35.  
  36. ...
  37.  
  38. const ::std::string&名前()const;
  39.  
  40. void set_name(const ::std::string& 値);
  41.  
  42. 浮動小数点スコア() 定数;
  43.  
  44. void set_score(浮動小数点値);
  45.  
  46. ...
  47.  
  48. }

ご覧のとおり、proto 定義は各型の C++ クラス インターフェイスになりました。それらの実装も自動的に生成されるため、直接使用できます。

推論サーバーの実装

ClassificationService::Service を実装するには、エクスポートされたモデルをロードし、その上で推論メソッドを呼び出す必要があります。これは、エクスポートされたモデルから作成され、完全にロードされたデータフロー グラフを含む TF Session オブジェクトと、エクスポーターで定義された分類シグネチャを含むメタデータを含む SessionBundle オブジェクトを通じて実現されます。

エクスポートされたファイル パスから SessionBundle オブジェクトを作成するには、この定型句を処理する便利な関数を定義します。

  1. #include <iostream>
  2.  
  3. #include <メモリ>
  4.  
  5. #include <文字列>
  6.  
  7.  
  8. #include <grpc++/grpc++.h>
  9.  
  10. #include "classification_service.grpc.pb.h"  
  11.  
  12.  
  13. #include "tensorflow_serving/servables/tensorflow/
  14.  
  15. セッションバンドルファクトリー.h"
  16.  
  17.  
  18. 名前空間 std を使用します。
  19.  
  20. 名前空間 tensorflow::serving を使用します。
  21.  
  22. 名前空間 grpc を使用します。
  23.  
  24.  
  25. unique_ptr<SessionBundle> createSessionBundle(const string&
  26.  
  27. エクスポートファイルのパス) {
  28.  
  29. セッションバンドル構成 session_bundle_config =
  30.  
  31. セッションバンドル構成();
  32.  
  33. unique_ptr<SessionBundleFactory> バンドルファクトリ;
  34.  
  35. SessionBundleFactory::作成(session_bundle_config、
  36.  
  37. &バンドルファクトリー);
  38.  
  39.  
  40. unique_ptr<セッションバンドル> セッションバンドル;
  41.  
  42. バンドルファクトリー -
  43.  
  44. >CreateSessionBundle(pathToExportFiles, &sessionBundle);
  45.  
  46.  
  47. sessionBundleを返します
  48.  
  49. }

このコードでは、SessionBundleFactory クラスを使用して SessionBundle オブジェクトを作成し、pathToExportFiles で指定されたパスからエクスポートされたモデルを読み込むように構成します。最後に、作成された SessionBundle インスタンスへの一意のポインターが返されます。

次に、推論で使用するパラメータとして SessionBundle インスタンスを受け取るサービスである ClassificationServiceImpl の実装を定義する必要があります。

  1. クラス ClassificationServiceImpl 最終:パブリック 
  2.  
  3. 分類サービス::サービス {
  4.  
  5. プライベート:
  6.  
  7. unique_ptr<セッションバンドル> セッションバンドル;
  8.  
  9. 公共
  10.  
  11. 分類サービス実装(unique_ptr<セッションバンドル>
  12.  
  13. セッションバンドル):
  14.  
  15. sificationServiceImpl(unique_ptr<SessionImpl
  16.  
  17. ステータス分類(ServerContext* context, const
  18.  
  19. ClassificationRequest* リクエスト、
  20.  
  21. 分類応答* 応答)
  22.  
  23. オーバーライド {
  24.  
  25. // カテゴリシグネチャをロードする
  26.  
  27. 分類署名署名;
  28.  
  29. const tensorflow::Status シグネチャStatus =
  30.  
  31. GetClassificationSignature(セッションバンドル-
  32.  
  33. >meta_graph_def、&署名);
  34.  
  35. 署名ステータスがok()の場合{
  36.  
  37. ステータスを返す(StatusCode::INTERNAL,
  38.  
  39. 署名ステータス.error_message());
  40.  
  41. }
  42.  
  43. // protobuf 入力を推論入力テンソルに変換する
  44.  
  45. テンソルフロー::テンソル
  46.  
  47. 入力(tensorflow::DT_STRING、tensorflow::TensorShape());
  48.  
  49. input.scalar<文字列>()() = request->input();
  50.  
  51. vector<tensorflow::Tensor> 出力;
  52.  
  53. //推論を実行する
  54.  
  55. const tensorflow::Status 推論Status =
  56.  
  57. sessionBundle->session->実行(
  58.  
  59. {{signature.input().tensor_name(),
  60.  
  61. 入力}}、
  62.  
  63. {署名.クラス().テンソル名(),
  64.  
  65. signature.scores().tensor_name()},
  66.  
  67. {},
  68.  
  69. &出力);
  70.  
  71. 推論ステータスがokの場合
  72.  
  73. ステータスを返す(StatusCode::INTERNAL,
  74.  
  75. 推論ステータス.error_message());
  76.  
  77. }
  78.  
  79. //推論出力テンソルをprotobuf出力に変換する
  80.  
  81. ( int i = 0 ; i <
  82.  
  83. 出力[0].vec<文字列>(). size (); ++i) {
  84.  
  85. 分類クラス
  86.  
  87. *classificationClass = レスポンス->add_classes();
  88.  
  89. 分類クラス-
  90.  
  91. >set_name(outputs[0].flat<文字列>()(i));
  92.  
  93. 分類クラス-
  94.  
  95. >set_score(outputs[1].flat< float >()(i));
  96.  
  97. }
  98.  
  99. Status::OKを返します
  100.  
  101. }
  102.  
  103. };

分類メソッドの実装には、次の 4 つのステップが含まれます。

  • GetClassificationSignature 関数を使用して、モデルのエクスポート メタデータに保存されている分類署名を読み込みます。このシグネチャは、入力テンソルの (論理) 名から受信した画像の実際の名前へのマッピングと、データフロー グラフ内の出力テンソルの (論理) 名からそれらに対して取得された推論結果へのマッピングを指定します。
  • JPEG でエンコードされた画像文字列を、リクエスト パラメータから推論に使用されるテンソルにコピーします。
  • 推論を実行します。 sessionBundle から TF セッション オブジェクトを取得し、入力テンソルと出力テンソルの両方を渡して推論を 1 回実行します。
  • 出力テンソルの結果を、ClassificationResponse メッセージで指定された形状で応答出力パラメータにコピーし、フォーマットします。

最後のコードは、gRPC サーバーをセットアップし、ClassificationServiceImpl (Session-Bundle オブジェクトで構成される) のインスタンスを作成する定型コードです。

  1. int main( int argc, char ** argv) {
  2.  
  3. (引数<3)の場合{
  4.  
  5. cerr << "使用法: server <port> /path/to/export/files" <<
  6.  
  7. 終わり;
  8.  
  9. 1 を返します
  10.  
  11. }
  12.  
  13. 定数文字列サーバアドレス(文字列( "0.0.0.0:" ) +
  14.  
  15. argv[1]);
  16.  
  17. 定数文字列pathToExportFile(argv[2]);
  18.  
  19.  
  20. unique_ptr<セッションバンドル> セッションバンドル =
  21.  
  22. セッションバンドルを作成します(エクスポートファイルのパス)。
  23.  
  24.  
  25. 定数文字列 serverAddress
  26.  
  27. 分類サービス実装((セッションバンドル)を移動します);
  28.  
  29.  
  30. ServerBuilder ビルダー;
  31.  
  32. ビルダー.AddListeningPort(サーバーアドレス、
  33.  
  34. grpc::InsecureServerCredentials(); のようになります。
  35.  
  36. ビルダー。RegisterService(&classificationServiceImpl);
  37.  
  38.  
  39. unique_ptr<Server> server = builder.BuildAndStart();
  40.  
  41. cout << "サーバーは " << serverAddress << endl;
  42.  
  43.  
  44. サーバー->Wait();
  45.  
  46. 0を返します
  47.  
  48. }

このコードをコンパイルするには、BUILD ファイルでルールを定義する必要があります。

  1. cc_binary(
  2.  
  3. 名前= "サーバー"
  4.  
  5. ソース = [
  6.  
  7. 「server.cc」
  8.  
  9. ]、
  10.  
  11. 依存関係 = [
  12.  
  13. ":classification_service_proto"
  14.  
  15. "@tf_serving//tensorflow_serving/servables/
  16.  
  17. テンソルフロー:セッションバンドルファクトリー",
  18.  
  19. "@grpc//:grpc++"
  20.  
  21. ]、
  22.  

このコードを使用すると、コマンド bazel run :server 9999 /tmp/inception-v3/export/{timestamp} を使用して、コンテナーから推論サーバーを実行できます。

クライアントアプリケーション

gRPC は HTTP/2 をベースとしているため、将来的にはブラウザから直接 gRPC ベースのサービスを呼び出すことが可能になる可能性がありますが、主流のブラウザが必要な HTTP/2 機能をサポートし、Google がブラウザ側の JavaScript gRPC クライアント プログラムをリリースしない限り、Web アプリからの推論サービスへのアクセスはサーバー側のコンポーネントを介して行う必要があります。

次に、BaseHTTPServer をベースにしたシンプルな Python Web サーバーを構築します。このサーバーは、アップロードされた画像ファイルを処理し、処理のために推論サービスに送信し、推論結果をプレーンテキストで返します。

分類のために推論サーバーに画像を送信する場合、サーバーは簡単なフォームで GET リクエストに応答します。使用されるコードは次のとおりです。

  1. BaseHTTPServerからHTTPServer、BaseHTTPRequestHandler をインポートします。
  2.  
  3. cgiをインポートする
  4.  
  5. インポート分類サービスpb2
  6.  
  7. grpc.beta インポート実装から
  8.  
  9.  
  10. クラス ClientApp (BaseHTTPRequestHandler);
  11.  
  12. def do_GET(self):
  13.  
  14. 自己応答フォーム()
  15.  
  16.  
  17. def respond_form(self, レスポンス = "" ):
  18.  
  19.  
  20. フォーム = "" "
  21.  
  22. <html><本文>
  23.  
  24. <h1>画像分類サービス</h1>
  25.  
  26. <form enctype= "multipart/form-data" method= "post" >
  27.  
  28. <div>画像: <input type= "file"  名前= "ファイル"  
  29.  
  30. accept= "画像/jpeg" </div>
  31.  
  32. <div><input type= "submit" value= "アップロード" ></div>
  33.  
  34. </フォーム>
  35.  
  36. %s
  37.  
  38. </body></html>
  39.  
  40. 「」 「
  41.  
  42.  
  43. レスポンス = フォーム % レスポンス
  44.  
  45.  
  46. 自己応答を送信(200)
  47.  
  48. self.send_header( "コンテンツタイプ" , "text/html" )
  49.  
  50. self.send_header( "コンテンツの長さ" , len(応答))
  51.  
  52. 自己終了ヘッダー()
  53.  
  54. self.wfile.write(レスポンス)

Web アプリ サーバーから推論機能を呼び出すには、ClassificationService の対応する Python プロトコル バッファー クライアントが必要です。これを生成するには、Python プロトコル バッファ コンパイラを実行します。

  1. pip で grpcio cython grpcio-tools をインストールします
  2.  
  3. python -m grpc.tools.protoc -I. --python_out=. --  
  4.  
  5. grpc_python_out=. 分類サービス.proto

サービスを呼び出すために使用されるスタブを含む classified_service_pb2.py ファイルが生成されます。

POST リクエストを受信すると、サーバーは送信されたフォームを解析し、それを使用して Classification-Request オブジェクトを作成します。次に、この分類サーバーのチャネルを設定し、そのチャネルにリクエストを送信します。最後に、分類された応答を HTML としてレンダリングし、ユーザーに返します。

  1. def do_POST(self):
  2.  
  3. フォーム = cgi.FieldStorage(
  4.  
  5. fp=self.rファイル、
  6.  
  7. ヘッダー=self.headers、
  8.  
  9. 環境={
  10.  
  11. 'REQUEST_METHOD' : 'POST'
  12.  
  13. 'CONTENT_TYPE' : self.headers[ 'コンテンツタイプ' ],
  14.  
  15. })
  16.  
  17. リクエスト =
  18.  
  19. 分類サービスpb2.分類リクエスト()
  20.  
  21. request.input = フォーム[ 'file' ].file.read ( )
  22.  
  23.  
  24. チャンネル =
  25.  
  26. 実装.安全でないチャネル( "127.0.0.1" , 9999)
  27.  
  28. スタブ =
  29.  
  30. 分類サービス_pb2.beta_create_ClassificationService_stub(チャネル)
  31.  
  32. response = stub.classify(request, 10) # 10秒
  33.  
  34. タイムアウト
  35.  
  36. self.respond_form( "<div>レスポンス: %s</div>" %
  37.  
  38. 応答)

サーバーを実行するには、コンテナの外部から python client.py コマンドを使用します。次に、ブラウザで http://localhost:8080 に移動して UI にアクセスします。画像をアップロードして推論がどのように機能するかを確認してください。

製品の準備

この記事を締めくくる前に、分類サーバーを本番環境に適用する方法についても学習します。

まず、コンパイルされたサーバー ファイルをコンテナー内の永続的な場所にコピーし、一時的なビルド ファイルをすべてクリーンアップします。

  1. #コンテナ内
  2.  
  3. mkdir /opt/classification_server
  4.  
  5. cd /mnt/home/serving_example
  6.  
  7. cp -R bazel-bin/. /opt/classification_server
  8.  
  9. バゼルクリーン

ここで、コンテナの外部で、その状態を新しい Docker イメージにコミットする必要があります。これは基本的に、仮想ファイル システムへの変更を記録するスナップショットを作成することを意味します。

  1. #コンテナ外
  2.  
  3. ドッカーps
  4.  
  5. #コンテナIDを取得する
  6.  
  7. docker commit <コンテナID>

この方法では、イメージを好みの Docker サービス クラウドにプッシュして提供することができます。

結論

この記事では、トレーニング済みのモデルを提供する方法、それらをエクスポートする方法、そしてこれらのモデルを実行できる高速で軽量なサーバーを構築する方法について学びました。また、他のアプリから TensorFlow モデルを使用するための完全なツールセットを使用して、これらのモデルを使用するシンプルな Web アプリを作成する方法も学びました。

<<:  中国のAI研究は米国を上回る?専門家:例えば、ディープラーニングに関する論文の発表数

>>:  敵対的サンプルとディープニューラルネットワークの学習

ブログ    
ブログ    
ブログ    
ブログ    

推薦する

WSLはAIトレーニングタスクとLinux GUIアプリケーションの実行をサポートします

WSL は Windows 上で GPU を使用してアプリケーションを実行することをサポートするよう...

5分間の技術講演 | GPU仮想化に関する簡単な講演

パート01 背景1.1 GPU アプリケーションのシナリオGPU (グラフィックス プロセッシング ...

...

...

「自由に眠る」にはヘッドバンドを着けるだけ | Nature サブ出版物

この記事はAI新メディアQuantum Bit(公開アカウントID:QbitAI)より許可を得て転載...

MOEA Framework 1.9は、MOEAアルゴリズムを開発するためのJavaクラスライブラリをリリースしました。

MOEA フレームワークは、多目的進化アルゴリズム (MOEA) を開発するための Java ライ...

中国情報通信研究院が2021年最初の「信頼できるAI成果」を発表、百度が5つの賞を受賞

[[416150]]グローバルな AI ガバナンスのコンセンサスを実装し、信頼できる AI テクノロ...

デジタルヒューマンとは何か、そしてその将来性はどのようなものでしょうか?

今日の技術的に進歩した世界では、生きているようなデジタルヒューマンが大きな関心を集める新たな分野とな...

...

人工知能がヘルスケア業界にもたらす変化

AIヘルスケア企業のCEOが、医療におけるAIの応用、AIソリューションの購入方法、ヘルスケア分野に...

インダストリー 5.0: スマート シティの未来を形作るテクノロジーのメガトレンドの融合

この新しいフェーズは、ディープ テクノロジーの開発と採用のかつてない増加、世界の人口動態の大きな変化...

...

ホットトピックのクイックレビュー:ドイツはシステムと技術の複数回の並行開発でAI戦略を強化

世界を見渡すと、各国の社会進歩、産業グレードアップ、国防建設などにおける科学技術の価値がますます明ら...