クイック スタート: Custom Vision クライアント ライブラリを使用して物体検出プロジェクトを作成する

.NET用の Custom Vision クライアント ライブラリの使用を開始します。 次の手順に従ってパッケージをインストールし、オブジェクト検出モデルを構築するためのコード例を試してください。 プロジェクトを作成し、タグを追加し、サンプル画像でプロジェクトをトレーニングし、プロジェクトの予測エンドポイント URL を使用してプログラムでテストします。 この例は、独自の画像認識アプリを構築するためのテンプレートとして使用します。

メモ

コードを記述 せずに オブジェクト検出モデルを構築してトレーニングする場合は、代わりに ブラウザーベースのガイダンス を参照してください。

リファレンスドキュメント |ライブラリ ソース コード (トレーニング)(予測) |パッケージ (NuGet) (トレーニング)(予測) | サンプル

前提 条件

環境変数を作成する

この例では、アプリケーションを実行しているローカル コンピューター上の環境変数に資格情報を書き込みます。

Azure ポータルに移動します。 [前提条件] セクションで作成した Custom Vision リソースが正常にデプロイされた場合は、[次の手順] の [リソースに移動] ボタンを選択します。 キーとエンドポイントは、リソースの [ キー] ページと [エンドポイント] ページの [ リソース管理] にあります。 API エンドポイントと共に、トレーニング リソースと予測リソースの両方のキーを取得する必要があります。

予測リソースの Properties タブには、Azure ポータルで Resource ID として一覧表示されています。

ヒント

また、 https://www.customvision.ai を使用してこれらの値を取得します。 サインインしたら、右上にある [設定] アイコンを選択します。 [設定] ページでは、すべてのキー、リソース ID、エンドポイントを表示できます。

環境変数を設定するには、コンソール ウィンドウを開き、オペレーティング システムと開発環境の指示に従います。

  • VISION_TRAINING KEY環境変数を設定するには、<your-training-key>をトレーニング リソースのキーのいずれかに置き換えます。
  • VISION_TRAINING_ENDPOINT環境変数を設定するには、<your-training-endpoint>をトレーニング リソースのエンドポイントに置き換えます。
  • VISION_PREDICTION_KEY環境変数を設定するには、<your-prediction-key>を予測リソースのキーのいずれかに置き換えます。
  • VISION_PREDICTION_ENDPOINT環境変数を設定するには、<your-prediction-endpoint>を予測リソースのエンドポイントに置き換えます。
  • VISION_PREDICTION_RESOURCE_ID環境変数を設定するには、<your-resource-id>を予測リソースのリソース ID に置き換えます。

重要

クラウドで実行されるアプリケーションに資格情報を格納しないように、 Azure リソースの管理された ID を使用して認証をMicrosoft Entra IDすることをお勧めします。

API キーは慎重に使用してください。 API キーをコードに直接含めず、パブリックに投稿しないでください。 API キーを使用する場合は、Azure Key Vaultに安全に格納し、キーを定期的にローテーションし、ロールベースのアクセス制御とネットワーク アクセス制限を使用してAzure Key Vaultへのアクセスを制限します。 アプリで API キーを安全に使用する方法の詳細については、「Azure Key Vault を使用した API キー」を参照してください。

AI サービスのセキュリティの詳細については、「Authenticate requests to Azure AI サービス」を参照してください。

setx VISION_TRAINING_KEY <your-training-key>
setx VISION_TRAINING_ENDPOINT <your-training-endpoint>
setx VISION_PREDICTION_KEY <your-prediction-key>
setx VISION_PREDICTION_ENDPOINT <your-prediction-endpoint>
setx VISION_PREDICTION_RESOURCE_ID <your-resource-id>

環境変数を追加した後、コンソール ウィンドウを含め、環境変数を読み取る実行中のプログラムを再起動することが必要になる場合があります。

セットアップ

新しい C# アプリケーションを作成する

Visual Studioを使用して、新しい .NET Core アプリケーションを作成します。

クライアント ライブラリをインストールする

新しいプロジェクトを作成したら、ソリューション エクスプローラー Manage NuGet Packages を選択して、クライアント ライブラリをインストールします。 開いたパッケージ マネージャーで Browse を選択し、プレリリースを含むチェック ボックスをオンにして、Microsoft.Azure.CognitiveServices.Vision.CustomVision.TrainingMicrosoft.Azure.CognitiveServices.Vision.CustomVision.Prediction を検索します。 最新バージョンを選択し、[ インストール] を選択します。

ヒント

クイック スタート コード ファイル全体を一度に表示しますか? このクイック スタートのコード例を含む GitHub で確認できます。

プロジェクト ディレクトリから 、program.cs ファイルを開き、次の using ディレクティブを追加します。

using Microsoft.Azure.CognitiveServices.Vision.CustomVision.Prediction;
using Microsoft.Azure.CognitiveServices.Vision.CustomVision.Training;
using Microsoft.Azure.CognitiveServices.Vision.CustomVision.Training.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;

アプリケーションの Main メソッドで、環境変数からリソースのキーとエンドポイントを取得する変数を作成します。 また、後で使用する基本的なオブジェクトも宣言します。

    string trainingEndpoint = Environment.GetEnvironmentVariable("VISION_TRAINING_ENDPOINT");

    string trainingKey = Environment.GetEnvironmentVariable("VISION_TRAINING_KEY");
    string predictionEndpoint = Environment.GetEnvironmentVariable("VISION_PREDICTION_ENDPOINT");
    string predictionKey = Environment.GetEnvironmentVariable("VISION_PREDICTION_KEY");

    private static Iteration iteration;
    private static string publishedModelName = "CustomODModel";

アプリケーションの Main メソッドで、このクイック スタートで使用するメソッドの呼び出しを追加します。 これらは後で実装します。

CustomVisionTrainingClient trainingApi = AuthenticateTraining(trainingEndpoint, trainingKey);
CustomVisionPredictionClient predictionApi = AuthenticatePrediction(predictionEndpoint, predictionKey);

Project project = CreateProject(trainingApi);
AddTags(trainingApi, project);
UploadImages(trainingApi, project);
TrainProject(trainingApi, project);
PublishIteration(trainingApi, project);
TestIteration(predictionApi, project);

クライアントを認証する

新しいメソッドでは、エンドポイントとキーを使用してトレーニング クライアントと予測クライアントをインスタンス化します。

private CustomVisionTrainingClient AuthenticateTraining(string endpoint, string trainingKey, string predictionKey)
{
    // Create the Api, passing in the training key
    CustomVisionTrainingClient trainingApi = new CustomVisionTrainingClient(new Microsoft.Azure.CognitiveServices.Vision.CustomVision.Training.ApiKeyServiceClientCredentials(trainingKey))
    {
        Endpoint = endpoint
    };
    return trainingApi;
}
private CustomVisionPredictionClient AuthenticatePrediction(string endpoint, string predictionKey)
{
    // Create a prediction endpoint, passing in the obtained prediction key
    CustomVisionPredictionClient predictionApi = new CustomVisionPredictionClient(new Microsoft.Azure.CognitiveServices.Vision.CustomVision.Prediction.ApiKeyServiceClientCredentials(predictionKey))
    {
        Endpoint = endpoint
    };
    return predictionApi;
}

新しい Custom Vision プロジェクトを作成する

次のメソッドは、物体検出プロジェクトを作成します。 作成されたプロジェクトが Custom Vision Web サイトに表示されます。 プロジェクトの作成時に他のオプションを指定するには、 CreateProject メソッドを参照してください ( 「検出器の構築 」Web ポータル ガイドで説明)。

private Project CreateProject(CustomVisionTrainingClient trainingApi)
{
    // Find the object detection domain
    var domains = trainingApi.GetDomains();
    var objDetectionDomain = domains.FirstOrDefault(d => d.Type == "ObjectDetection");

    // Create a new project
    Console.WriteLine("Creating new project:");
    project = trainingApi.CreateProject("My New Project", null, objDetectionDomain.Id);

    return project;
}

プロジェクトにタグを追加する

このメソッドは、モデルをトレーニングするタグを定義します。

private void AddTags(CustomVisionTrainingClient trainingApi, Project project)
{
    // Make two tags in the new project
    var forkTag = trainingApi.CreateTag(project.Id, "fork");
    var scissorsTag = trainingApi.CreateTag(project.Id, "scissors");
}

画像をアップロードしてタグ付けする

まず、このプロジェクトのサンプル イメージをダウンロードします。 サンプル イメージ フォルダーの内容をローカル デバイスに保存します。

物体検出プロジェクトで画像にタグを付ける場合は、正規化された座標を使用して、タグ付けされた各オブジェクトの領域を指定する必要があります。 次のコードは、各サンプル イメージをタグ付けされた領域に関連付けます。

private void UploadImages(CustomVisionTrainingClient trainingApi, Project project)
{
    Dictionary<string, double[]> fileToRegionMap = new Dictionary<string, double[]>()
    {
        // FileName, Left, Top, Width, Height
        {"scissors_1", new double[] { 0.4007353, 0.194068655, 0.259803921, 0.6617647 } },
        {"scissors_2", new double[] { 0.426470578, 0.185898721, 0.172794119, 0.5539216 } },
        {"scissors_3", new double[] { 0.289215684, 0.259428144, 0.403186262, 0.421568632 } },
        {"scissors_4", new double[] { 0.343137264, 0.105833367, 0.332107842, 0.8055556 } },
        {"scissors_5", new double[] { 0.3125, 0.09766343, 0.435049027, 0.71405226 } },
        {"scissors_6", new double[] { 0.379901975, 0.24308826, 0.32107842, 0.5718954 } },
        {"scissors_7", new double[] { 0.341911763, 0.20714055, 0.3137255, 0.6356209 } },
        {"scissors_8", new double[] { 0.231617644, 0.08459154, 0.504901946, 0.8480392 } },
        {"scissors_9", new double[] { 0.170343131, 0.332957536, 0.767156839, 0.403594762 } },
        {"scissors_10", new double[] { 0.204656869, 0.120539248, 0.5245098, 0.743464053 } },
        {"scissors_11", new double[] { 0.05514706, 0.159754932, 0.799019635, 0.730392158 } },
        {"scissors_12", new double[] { 0.265931368, 0.169558853, 0.5061275, 0.606209159 } },
        {"scissors_13", new double[] { 0.241421565, 0.184264734, 0.448529422, 0.6830065 } },
        {"scissors_14", new double[] { 0.05759804, 0.05027781, 0.75, 0.882352948 } },
        {"scissors_15", new double[] { 0.191176474, 0.169558853, 0.6936275, 0.6748366 } },
        {"scissors_16", new double[] { 0.1004902, 0.279036, 0.6911765, 0.477124184 } },
        {"scissors_17", new double[] { 0.2720588, 0.131977156, 0.4987745, 0.6911765 } },
        {"scissors_18", new double[] { 0.180147052, 0.112369314, 0.6262255, 0.6666667 } },
        {"scissors_19", new double[] { 0.333333343, 0.0274019931, 0.443627447, 0.852941155 } },
        {"scissors_20", new double[] { 0.158088237, 0.04047389, 0.6691176, 0.843137264 } },
        {"fork_1", new double[] { 0.145833328, 0.3509314, 0.5894608, 0.238562092 } },
        {"fork_2", new double[] { 0.294117659, 0.216944471, 0.534313738, 0.5980392 } },
        {"fork_3", new double[] { 0.09191177, 0.0682516545, 0.757352948, 0.6143791 } },
        {"fork_4", new double[] { 0.254901975, 0.185898721, 0.5232843, 0.594771266 } },
        {"fork_5", new double[] { 0.2365196, 0.128709182, 0.5845588, 0.71405226 } },
        {"fork_6", new double[] { 0.115196079, 0.133611143, 0.676470637, 0.6993464 } },
        {"fork_7", new double[] { 0.164215669, 0.31008172, 0.767156839, 0.410130739 } },
        {"fork_8", new double[] { 0.118872553, 0.318251669, 0.817401946, 0.225490168 } },
        {"fork_9", new double[] { 0.18259804, 0.2136765, 0.6335784, 0.643790841 } },
        {"fork_10", new double[] { 0.05269608, 0.282303959, 0.8088235, 0.452614367 } },
        {"fork_11", new double[] { 0.05759804, 0.0894935, 0.9007353, 0.3251634 } },
        {"fork_12", new double[] { 0.3345588, 0.07315363, 0.375, 0.9150327 } },
        {"fork_13", new double[] { 0.269607842, 0.194068655, 0.4093137, 0.6732026 } },
        {"fork_14", new double[] { 0.143382356, 0.218578458, 0.7977941, 0.295751631 } },
        {"fork_15", new double[] { 0.19240196, 0.0633497, 0.5710784, 0.8398692 } },
        {"fork_16", new double[] { 0.140931368, 0.480016381, 0.6838235, 0.240196079 } },
        {"fork_17", new double[] { 0.305147052, 0.2512582, 0.4791667, 0.5408496 } },
        {"fork_18", new double[] { 0.234068632, 0.445702642, 0.6127451, 0.344771236 } },
        {"fork_19", new double[] { 0.219362751, 0.141781077, 0.5919118, 0.6683006 } },
        {"fork_20", new double[] { 0.180147052, 0.239820287, 0.6887255, 0.235294119 } }
    };

メモ

独自のプロジェクトでは、領域の座標をマークするクリック アンド ドラッグ ユーティリティがない場合は、 Custom Vision Web サイトで Web UI を使用できます。 この例では、座標は既に指定されています。

次に、この関連付けのマップを使用して、各サンプル イメージとその領域座標をアップロードします。 1 回のバッチで最大 64 個の画像をアップロードできます。 imagePathの値を変更して、正しいフォルダーの場所を指す必要がある場合があります。

    // Add all images for fork
    var imagePath = Path.Combine("Images", "fork");
    var imageFileEntries = new List<ImageFileCreateEntry>();
    foreach (var fileName in Directory.EnumerateFiles(imagePath))
    {
        var region = fileToRegionMap[Path.GetFileNameWithoutExtension(fileName)];
        imageFileEntries.Add(new ImageFileCreateEntry(fileName, File.ReadAllBytes(fileName), null, new List<Region>(new Region[] { new Region(forkTag.Id, region[0], region[1], region[2], region[3]) })));
    }
    trainingApi.CreateImagesFromFiles(project.Id, new ImageFileCreateBatch(imageFileEntries));

    // Add all images for scissors
    imagePath = Path.Combine("Images", "scissors");
    imageFileEntries = new List<ImageFileCreateEntry>();
    foreach (var fileName in Directory.EnumerateFiles(imagePath))
    {
        var region = fileToRegionMap[Path.GetFileNameWithoutExtension(fileName)];
        imageFileEntries.Add(new ImageFileCreateEntry(fileName, File.ReadAllBytes(fileName), null, new List<Region>(new Region[] { new Region(scissorsTag.Id, region[0], region[1], region[2], region[3]) })));
    }
    trainingApi.CreateImagesFromFiles(project.Id, new ImageFileCreateBatch(imageFileEntries));
}

この時点で、すべてのサンプル画像をアップロードし、それぞれ (フォーク または ハサミ) に関連付けられたピクセル四角形でタグ付けしました。

プロジェクトをトレーニングする

このメソッドは、プロジェクトで最初のトレーニング イテレーションを作成します。 トレーニングが完了するまでサービスに対してクエリを実行します。

private void TrainProject(CustomVisionTrainingClient trainingApi, Project project)
{

    // Now there are images with tags start training the project
    Console.WriteLine("\tTraining");
    iteration = trainingApi.TrainProject(project.Id);

    // The returned iteration will be in progress, and can be queried periodically to see when it has completed
    while (iteration.Status == "Training")
    {
        Thread.Sleep(1000);

        // Re-query the iteration to get its updated status
        iteration = trainingApi.GetIteration(project.Id, iteration.Id);
    }
}

ヒント

選択したタグを使用してトレーニングする

必要に応じて、適用されたタグのサブセットのみをトレーニングできます。 特定のタグをまだ十分に適用していないが、他のタグが十分にある場合は、これを行うことができます。 TrainProject 呼び出しで、trainingParameters パラメーターを使用します。 TrainingParameters を構築し、その SelectedTags プロパティを、タグとして使用したい ID の一覧に設定します。 モデルは、そのリストのタグのみを認識するようにトレーニングします。

現在のイテレーションを発行する

このメソッドを使用すると、モデルの現在のイテレーションをクエリに使用できるようになります。 モデル名を参照として使用して、予測要求を送信できます。 predictionResourceIdには独自の値を入力する必要があります。 予測リソース ID は、Azure ポータルのリソースの Properties タブで、Resource ID として表示されます。

private void PublishIteration(CustomVisionTrainingClient trainingApi, Project project)
{

    // The iteration is now trained. Publish it to the prediction end point.
    var predictionResourceId = Environment.GetEnvironmentVariable("VISION_PREDICTION_RESOURCE_ID");
    trainingApi.PublishIteration(project.Id, iteration.Id, publishedModelName, predictionResourceId);
    Console.WriteLine("Done!\n");
}

予測エンドポイントをテストする

このメソッドは、テスト イメージを読み込み、モデル エンドポイントに対してクエリを実行し、予測データをコンソールに出力します。

private void TestIteration(CustomVisionPredictionClient predictionApi, Project project)
{

    // Make a prediction against the new project
    Console.WriteLine("Making a prediction:");
    var imageFile = Path.Combine("Images", "test", "test_image.jpg");
    using (var stream = File.OpenRead(imageFile))
    {
        var result = predictionApi.DetectImage(project.Id, publishedModelName, stream);

        // Loop over each prediction and write out the results
        foreach (var c in result.Predictions)
        {
            Console.WriteLine($"\t{c.TagName}: {c.Probability:P1} [ {c.BoundingBox.Left}, {c.BoundingBox.Top}, {c.BoundingBox.Width}, {c.BoundingBox.Height} ]");
        }
    }
    Console.ReadKey();
}

アプリケーションを実行する

IDE ウィンドウの上部にある [デバッグ ] ボタンをクリックして、アプリケーションを実行します。

アプリケーションを実行すると、コンソール ウィンドウが開き、次の出力が書き込まれます。

Creating new project:
        Training
Done!

Making a prediction:
        fork: 98.2% [ 0.111609578, 0.184719115, 0.6607002, 0.6637112 ]
        scissors: 1.2% [ 0.112389535, 0.119195729, 0.658031344, 0.7023591 ]

その後、( 画像/テスト/で見つかった) テスト イメージが適切にタグ付けされていること、および検出の領域が正しいことを確認できます。 この時点で、任意のキーを押してアプリケーションを終了できます。

リソースのクリーンアップ

独自の物体検出プロジェクトを実装する (または 画像分類 プロジェクトを試す) 場合は、この例からフォーク/ハサミ検出プロジェクトを削除できます。 無料サブスクリプションでは、2 つの Custom Vision プロジェクトを利用できます。

Custom Vision Web サイトで、Projects に移動し、[マイ ニュー Project] の下にあるごみ箱を選択します。

ごみ箱アイコンが付いた [新しいProject] というラベルのパネルのスクリーンショット。

次の手順

これで、オブジェクト検出プロセスのすべての手順をコードで行いました。 このサンプルでは 1 回のトレーニング イテレーションを実行しますが、多くの場合、モデルをより正確にするために、モデルを複数回トレーニングしてテストする必要があります。 次のガイドでは画像分類について説明しますが、その原則は物体検出に似ています。

このガイドでは、Go 用 Custom Vision クライアント ライブラリを使用して物体検出モデルを構築する際に役立つ手順とサンプル コードについて説明します。 プロジェクトを作成し、タグを追加し、プロジェクトをトレーニングし、プロジェクトの予測エンドポイント URL を使用してプログラムでテストします。 この例は、独自の画像認識アプリを構築するためのテンプレートとして使用します。

メモ

コードを記述 せずに オブジェクト検出モデルを構築してトレーニングする場合は、代わりに ブラウザーベースのガイダンス を参照してください。

リファレンス ドキュメント (training)(prediction)

前提 条件

  • Azure サブスクリプション - 無料で作成します
  • Go 1.8+
  • Azure サブスクリプションを取得したら、Azure ポータルで Custom Vision リソースを作成し、トレーニングと予測のリソースを作成します。
    • Free 価格レベル (F0) を使用してサービスを試し、後で運用環境用の有料レベルにアップグレードできます。

環境変数を作成する

この例では、アプリケーションを実行しているローカル コンピューター上の環境変数に資格情報を書き込みます。

Azure ポータルに移動します。 [前提条件] セクションで作成した Custom Vision リソースが正常にデプロイされた場合は、[次の手順] の [リソースに移動] ボタンを選択します。 キーとエンドポイントは、リソースの [ キー] ページと [エンドポイント] ページの [ リソース管理] にあります。 API エンドポイントと共に、トレーニング リソースと予測リソースの両方のキーを取得する必要があります。

予測リソースの Properties タブには、Azure ポータルで Resource ID として一覧表示されています。

ヒント

また、 https://www.customvision.ai を使用してこれらの値を取得します。 サインインしたら、右上にある [設定] アイコンを選択します。 [設定] ページでは、すべてのキー、リソース ID、エンドポイントを表示できます。

環境変数を設定するには、コンソール ウィンドウを開き、オペレーティング システムと開発環境の指示に従います。

  • VISION_TRAINING KEY環境変数を設定するには、<your-training-key>をトレーニング リソースのキーのいずれかに置き換えます。
  • VISION_TRAINING_ENDPOINT環境変数を設定するには、<your-training-endpoint>をトレーニング リソースのエンドポイントに置き換えます。
  • VISION_PREDICTION_KEY環境変数を設定するには、<your-prediction-key>を予測リソースのキーのいずれかに置き換えます。
  • VISION_PREDICTION_ENDPOINT環境変数を設定するには、<your-prediction-endpoint>を予測リソースのエンドポイントに置き換えます。
  • VISION_PREDICTION_RESOURCE_ID環境変数を設定するには、<your-resource-id>を予測リソースのリソース ID に置き換えます。

重要

クラウドで実行されるアプリケーションに資格情報を格納しないように、 Azure リソースの管理された ID を使用して認証をMicrosoft Entra IDすることをお勧めします。

API キーは慎重に使用してください。 API キーをコードに直接含めず、パブリックに投稿しないでください。 API キーを使用する場合は、Azure Key Vaultに安全に格納し、キーを定期的にローテーションし、ロールベースのアクセス制御とネットワーク アクセス制限を使用してAzure Key Vaultへのアクセスを制限します。 アプリで API キーを安全に使用する方法の詳細については、「Azure Key Vault を使用した API キー」を参照してください。

AI サービスのセキュリティの詳細については、「Authenticate requests to Azure AI サービス」を参照してください。

setx VISION_TRAINING_KEY <your-training-key>
setx VISION_TRAINING_ENDPOINT <your-training-endpoint>
setx VISION_PREDICTION_KEY <your-prediction-key>
setx VISION_PREDICTION_ENDPOINT <your-prediction-endpoint>
setx VISION_PREDICTION_RESOURCE_ID <your-resource-id>

環境変数を追加した後、コンソール ウィンドウを含め、環境変数を読み取る実行中のプログラムを再起動することが必要になる場合があります。

セットアップ

Custom Vision クライアント ライブラリをインストールする

Custom Vision for Go を使用して画像分析アプリを作成するには、Custom Vision サービス クライアント ライブラリが必要です。 PowerShell で次のコマンドを実行します。

go get -u github.com/Azure/azure-sdk-for-go/...

または、 depを使用する場合は、リポジトリ内で次を実行します。

dep ensure -add github.com/Azure/azure-sdk-for-go

サンプル イメージを取得する

この例では、GitHub の Foundry Tools Python SDK Samples リポジトリのイメージを使用します。 このリポジトリを開発環境に複製またはダウンロードします。 後の手順では、フォルダーの場所を覚えておいてください。

Custom Vision プロジェクトを作成する

好みのプロジェクト ディレクトリに sample.go という名前の新しいファイルを作成し、任意のコード エディターで開きます。

スクリプトに次のコードを追加して、新しい Custom Vision サービス プロジェクトを作成します。

プロジェクトの作成時に他のオプションを指定するには、 CreateProject メソッドを参照してください ( 「検出器の構築 」Web ポータル ガイドで説明)。

import(
    "context"
    "bytes"
    "fmt"
    "io/ioutil"
    "path"
    "log"
    "time"
    "github.com/Azure/azure-sdk-for-go/services/cognitiveservices/v3.0/customvision/training"
    "github.com/Azure/azure-sdk-for-go/services/cognitiveservices/v3.0/customvision/prediction"
)

// retrieve environment variables:
var (
    training_key string = os.Getenv("VISION_TRAINING_KEY")
    prediction_key string = os.Getenv("VISION_PREDICTION_KEY")
    prediction_resource_id = os.Getenv("VISION_PREDICTION_RESOURCE_ID")
    endpoint string = os.Getenv("VISION_ENDPOINT")
   
    project_name string = "Go Sample OD Project"
    iteration_publish_name = "detectModel"
    sampleDataDirectory = "<path to sample images>"
)

func main() {
    fmt.Println("Creating project...")

    ctx = context.Background()

    trainer := training.New(training_key, endpoint)

    var objectDetectDomain training.Domain
    domains, _ := trainer.GetDomains(ctx)

    for _, domain := range *domains.Value {
        fmt.Println(domain, domain.Type)
        if domain.Type == "ObjectDetection" && *domain.Name == "General" {
            objectDetectDomain = domain
            break
        }
    }
    fmt.Println("Creating project...")
    project, _ := trainer.CreateProject(ctx, project_name, "", objectDetectDomain.ID, "")

プロジェクトでタグを作成する

プロジェクトに分類タグを作成するには、 sample.go の末尾に次のコードを追加します。

# Make two tags in the new project
forkTag, _ := trainer.CreateTag(ctx, *project.ID, "fork", "A fork", string(training.Regular))
scissorsTag, _ := trainer.CreateTag(ctx, *project.ID, "scissors", "Pair of scissors", string(training.Regular))

画像をアップロードしてタグ付けする

物体検出プロジェクトで画像にタグを付ける場合は、正規化された座標を使用して、タグ付けされた各オブジェクトの領域を指定する必要があります。

メモ

領域の座標をマークするクリック アンド ドラッグ ユーティリティがない場合は、 Customvision.ai で Web UI を使用できます。 この例では、座標は既に指定されています。

イメージ、タグ、および領域をプロジェクトに追加するには、タグの作成後に次のコードを挿入します。 このチュートリアルでは、リージョンはインラインでハードコーディングされていることに注意してください。 領域は正規化された座標で境界ボックスを指定し、座標は左、上、幅、高さの順に指定されます。

forkImageRegions := map[string][4]float64{
    "fork_1.jpg": [4]float64{ 0.145833328, 0.3509314, 0.5894608, 0.238562092 },
    "fork_2.jpg": [4]float64{ 0.294117659, 0.216944471, 0.534313738, 0.5980392 },
    "fork_3.jpg": [4]float64{ 0.09191177, 0.0682516545, 0.757352948, 0.6143791 },
    "fork_4.jpg": [4]float64{ 0.254901975, 0.185898721, 0.5232843, 0.594771266 },
    "fork_5.jpg": [4]float64{ 0.2365196, 0.128709182, 0.5845588, 0.71405226 },
    "fork_6.jpg": [4]float64{ 0.115196079, 0.133611143, 0.676470637, 0.6993464 },
    "fork_7.jpg": [4]float64{ 0.164215669, 0.31008172, 0.767156839, 0.410130739 },
    "fork_8.jpg": [4]float64{ 0.118872553, 0.318251669, 0.817401946, 0.225490168 },
    "fork_9.jpg": [4]float64{ 0.18259804, 0.2136765, 0.6335784, 0.643790841 },
    "fork_10.jpg": [4]float64{ 0.05269608, 0.282303959, 0.8088235, 0.452614367 },
    "fork_11.jpg": [4]float64{ 0.05759804, 0.0894935, 0.9007353, 0.3251634 },
    "fork_12.jpg": [4]float64{ 0.3345588, 0.07315363, 0.375, 0.9150327 },
    "fork_13.jpg": [4]float64{ 0.269607842, 0.194068655, 0.4093137, 0.6732026 },
    "fork_14.jpg": [4]float64{ 0.143382356, 0.218578458, 0.7977941, 0.295751631 },
    "fork_15.jpg": [4]float64{ 0.19240196, 0.0633497, 0.5710784, 0.8398692 },
    "fork_16.jpg": [4]float64{ 0.140931368, 0.480016381, 0.6838235, 0.240196079 },
    "fork_17.jpg": [4]float64{ 0.305147052, 0.2512582, 0.4791667, 0.5408496 },
    "fork_18.jpg": [4]float64{ 0.234068632, 0.445702642, 0.6127451, 0.344771236 },
    "fork_19.jpg": [4]float64{ 0.219362751, 0.141781077, 0.5919118, 0.6683006 },
    "fork_20.jpg": [4]float64{ 0.180147052, 0.239820287, 0.6887255, 0.235294119 },
}

scissorsImageRegions := map[string][4]float64{
    "scissors_1.jpg": [4]float64{ 0.4007353, 0.194068655, 0.259803921, 0.6617647 },
    "scissors_2.jpg": [4]float64{ 0.426470578, 0.185898721, 0.172794119, 0.5539216 },
    "scissors_3.jpg": [4]float64{ 0.289215684, 0.259428144, 0.403186262, 0.421568632 },
    "scissors_4.jpg": [4]float64{ 0.343137264, 0.105833367, 0.332107842, 0.8055556 },
    "scissors_5.jpg": [4]float64{ 0.3125, 0.09766343, 0.435049027, 0.71405226 },
    "scissors_6.jpg": [4]float64{ 0.379901975, 0.24308826, 0.32107842, 0.5718954 },
    "scissors_7.jpg": [4]float64{ 0.341911763, 0.20714055, 0.3137255, 0.6356209 },
    "scissors_8.jpg": [4]float64{ 0.231617644, 0.08459154, 0.504901946, 0.8480392 },
    "scissors_9.jpg": [4]float64{ 0.170343131, 0.332957536, 0.767156839, 0.403594762 },
    "scissors_10.jpg": [4]float64{ 0.204656869, 0.120539248, 0.5245098, 0.743464053 },
    "scissors_11.jpg": [4]float64{ 0.05514706, 0.159754932, 0.799019635, 0.730392158 },
    "scissors_12.jpg": [4]float64{ 0.265931368, 0.169558853, 0.5061275, 0.606209159 },
    "scissors_13.jpg": [4]float64{ 0.241421565, 0.184264734, 0.448529422, 0.6830065 },
    "scissors_14.jpg": [4]float64{ 0.05759804, 0.05027781, 0.75, 0.882352948 },
    "scissors_15.jpg": [4]float64{ 0.191176474, 0.169558853, 0.6936275, 0.6748366 },
    "scissors_16.jpg": [4]float64{ 0.1004902, 0.279036, 0.6911765, 0.477124184 },
    "scissors_17.jpg": [4]float64{ 0.2720588, 0.131977156, 0.4987745, 0.6911765 },
    "scissors_18.jpg": [4]float64{ 0.180147052, 0.112369314, 0.6262255, 0.6666667 },
    "scissors_19.jpg": [4]float64{ 0.333333343, 0.0274019931, 0.443627447, 0.852941155 },
    "scissors_20.jpg": [4]float64{ 0.158088237, 0.04047389, 0.6691176, 0.843137264 },
}

次に、この関連付けのマップを使用して、各サンプル 画像とその領域座標をアップロードします (1 回のバッチで最大 64 個の画像をアップロードできます)。 次のコードを追加します。

メモ

先ほど Foundry Tools Go SDK Samples プロジェクトをダウンロードした場所に基づいて、イメージへのパスを変更する必要があります。

// Go through the data table above and create the images
fmt.Println("Adding images...")
var fork_images []training.ImageFileCreateEntry
for file, region := range forkImageRegions {
    imageFile, _ := ioutil.ReadFile(path.Join(sampleDataDirectory, "fork", file))

    regiontest := forkImageRegions[file]
    imageRegion := training.Region{
        TagID:  forkTag.ID,
        Left:   &regiontest[0],
        Top:    &regiontest[1],
        Width:  &regiontest[2],
        Height: &regiontest[3],
    }
    var fileName string = file

    fork_images = append(fork_images, training.ImageFileCreateEntry{
        Name:     &fileName,
        Contents: &imageFile,
        Regions:  &[]training.Region{imageRegion}
    })
}
    
fork_batch, _ := trainer.CreateImagesFromFiles(ctx, *project.ID, training.ImageFileCreateBatch{ 
    Images: &fork_images,
})

if (!*fork_batch.IsBatchSuccessful) {
    fmt.Println("Batch upload failed.")
}

var scissor_images []training.ImageFileCreateEntry
for file, region := range scissorsImageRegions {
    imageFile, _ := ioutil.ReadFile(path.Join(sampleDataDirectory, "scissors", file))

    imageRegion := training.Region { 
        TagID:scissorsTag.ID,
        Left:&region[0],
        Top:&region[1],
        Width:&region[2],
        Height:&region[3],
    }

    scissor_images = append(scissor_images, training.ImageFileCreateEntry {
        Name: &file,
        Contents: &imageFile,
        Regions: &[]training.Region{ imageRegion },
    })
}
    
scissor_batch, _ := trainer.CreateImagesFromFiles(ctx, *project.ID, training.ImageFileCreateBatch{ 
    Images: &scissor_images,
})
    
if (!*scissor_batch.IsBatchSuccessful) {
    fmt.Println("Batch upload failed.")
}     

プロジェクトを学習させて公開する

このコードは、予測モデルの最初のイテレーションを作成し、そのイテレーションを予測エンドポイントに発行します。 発行されたイテレーションに指定された名前を使用して、予測要求を送信できます。 イテレーションは、公開されるまで予測エンドポイントでは使用できません。

iteration, _ := trainer.TrainProject(ctx, *project.ID)
fmt.Println("Training status:", *iteration.Status)
for {
    if *iteration.Status != "Training" {
        break
    }
    time.Sleep(5 * time.Second)
    iteration, _ = trainer.GetIteration(ctx, *project.ID, *iteration.ID)
    fmt.Println("Training status:", *iteration.Status)
}

trainer.PublishIteration(ctx, *project.ID, *iteration.ID, iteration_publish_name, prediction_resource_id))

予測エンドポイントを使用する

画像を予測エンドポイントに送信して予測を取得するには、ファイルの末尾に次のコードを追加します。

    fmt.Println("Predicting...")
    predictor := prediction.New(prediction_key, endpoint)

    testImageData, _ := ioutil.ReadFile(path.Join(sampleDataDirectory, "Test", "test_od_image.jpg"))
    results, _ := predictor.DetectImage(ctx, *project.ID, iteration_publish_name, ioutil.NopCloser(bytes.NewReader(testImageData)), "")

    for _, prediction := range *results.Predictions    {
        boundingBox := *prediction.BoundingBox

        fmt.Printf("\t%s: %.2f%% (%.2f, %.2f, %.2f, %.2f)", 
            *prediction.TagName,
            *prediction.Probability * 100,
            *boundingBox.Left,
            *boundingBox.Top,
            *boundingBox.Width,
            *boundingBox.Height)
        fmt.Println("")
    }
}

アプリケーションを実行する

sample.go を実行します。

go run sample.go

アプリケーションの出力がコンソールに表示されます。 その後、( サンプル/ビジョン/画像/テストに含まれる) テスト 画像に適切なタグが付き、検出の領域が正しいことを確認できます。

リソースのクリーンアップ

独自の物体検出プロジェクトを実装する (または 画像分類 プロジェクトを試す) 場合は、この例からフォーク/ハサミ検出プロジェクトを削除できます。 無料サブスクリプションでは、2 つの Custom Vision プロジェクトを利用できます。

Custom Vision Web サイトで、Projects に移動し、[マイ ニュー Project] の下にあるごみ箱を選択します。

ごみ箱アイコンが付いた [新しいProject] というラベルのパネルのスクリーンショット。

次の手順

これで、オブジェクト検出プロセスのすべての手順をコードで行いました。 このサンプルでは 1 回のトレーニング イテレーションを実行しますが、多くの場合、モデルをより正確にするために、モデルを複数回トレーニングしてテストする必要があります。 次のガイドでは画像分類について説明しますが、その原則は物体検出に似ています。

Java用の Custom Vision クライアント ライブラリを使用して物体検出モデルを構築します。 パッケージをインストールし、基本的なタスクのコード例を試すには、次の手順に従います。 この例は、独自の画像認識アプリを構築するためのテンプレートとして使用します。

メモ

コードを記述 せずに オブジェクト検出モデルを構築してトレーニングする場合は、代わりに ブラウザーベースのガイダンス を参照してください。

リファレンスドキュメント | ライブラリ ソース コード (トレーニング)(予測) | アーティファクト (Maven) (トレーニング)(予測) | サンプル

前提 条件

  • Azure サブスクリプション - 無料で作成します
  • Java Development Kit(JDK)
  • Gradle ビルド ツール、または別の依存関係マネージャー。
  • Azure サブスクリプションを取得したら、Azure ポータルで Custom Vision リソース を作成して、トレーニングと予測のリソースを作成します。
    • Free 価格レベル (F0) を使用してサービスを試し、後で運用環境用の有料レベルにアップグレードできます。

環境変数を作成する

この例では、アプリケーションを実行しているローカル コンピューター上の環境変数に資格情報を書き込みます。

Azure ポータルに移動します。 [前提条件] セクションで作成した Custom Vision リソースが正常にデプロイされた場合は、[次の手順] の [リソースに移動] ボタンを選択します。 キーとエンドポイントは、リソースの [ キー] ページと [エンドポイント] ページの [ リソース管理] にあります。 API エンドポイントと共に、トレーニング リソースと予測リソースの両方のキーを取得する必要があります。

予測リソースの Properties タブには、Azure ポータルで Resource ID として一覧表示されています。

ヒント

また、 https://www.customvision.ai を使用してこれらの値を取得します。 サインインしたら、右上にある [設定] アイコンを選択します。 [設定] ページでは、すべてのキー、リソース ID、エンドポイントを表示できます。

環境変数を設定するには、コンソール ウィンドウを開き、オペレーティング システムと開発環境の指示に従います。

  • VISION_TRAINING KEY環境変数を設定するには、<your-training-key>をトレーニング リソースのキーのいずれかに置き換えます。
  • VISION_TRAINING_ENDPOINT環境変数を設定するには、<your-training-endpoint>をトレーニング リソースのエンドポイントに置き換えます。
  • VISION_PREDICTION_KEY環境変数を設定するには、<your-prediction-key>を予測リソースのキーのいずれかに置き換えます。
  • VISION_PREDICTION_ENDPOINT環境変数を設定するには、<your-prediction-endpoint>を予測リソースのエンドポイントに置き換えます。
  • VISION_PREDICTION_RESOURCE_ID環境変数を設定するには、<your-resource-id>を予測リソースのリソース ID に置き換えます。

重要

クラウドで実行されるアプリケーションに資格情報を格納しないように、 Azure リソースの管理された ID を使用して認証をMicrosoft Entra IDすることをお勧めします。

API キーは慎重に使用してください。 API キーをコードに直接含めず、パブリックに投稿しないでください。 API キーを使用する場合は、Azure Key Vaultに安全に格納し、キーを定期的にローテーションし、ロールベースのアクセス制御とネットワーク アクセス制限を使用してAzure Key Vaultへのアクセスを制限します。 アプリで API キーを安全に使用する方法の詳細については、「Azure Key Vault を使用した API キー」を参照してください。

AI サービスのセキュリティの詳細については、「Authenticate requests to Azure AI サービス」を参照してください。

setx VISION_TRAINING_KEY <your-training-key>
setx VISION_TRAINING_ENDPOINT <your-training-endpoint>
setx VISION_PREDICTION_KEY <your-prediction-key>
setx VISION_PREDICTION_ENDPOINT <your-prediction-endpoint>
setx VISION_PREDICTION_RESOURCE_ID <your-resource-id>

環境変数を追加した後、コンソール ウィンドウを含め、環境変数を読み取る実行中のプログラムを再起動することが必要になる場合があります。

セットアップ

新しい Gradle プロジェクトを作成する

コンソール ウィンドウ (cmd、PowerShell、Bash など) で、アプリ用の新しいディレクトリを作成し、そこに移動します。

mkdir myapp && cd myapp

作業ディレクトリから gradle init コマンドを実行します。 このコマンドは、実行時にアプリケーションの作成と構成に使用される build.gradle.kts など、Gradle の重要なビルド ファイルを作成します。

gradle init --type basic

DSL の選択を求められたら、[Kotlin] を選択します。

クライアント ライブラリをインストールする

build.gradle.kts を見つけて、任意の IDE またはテキスト エディターで開きます。 次に、次のビルド構成をコピーします。 この構成では、エントリ ポイントがクラス CustomVisionQuickstart を持つJava アプリケーションとしてプロジェクトを定義します。 Custom Vision ライブラリがインポートされます。

plugins {
    java
    application
}
application { 
    mainClassName = "CustomVisionQuickstart"
}
repositories {
    mavenCentral()
}
dependencies {
    compile(group = "com.azure", name = "azure-cognitiveservices-customvision-training", version = "1.1.0-preview.2")
    compile(group = "com.azure", name = "azure-cognitiveservices-customvision-prediction", version = "1.1.0-preview.2")
}

Java ファイルを作成する

作業ディレクトリから、次のコマンドを実行してプロジェクト ソース フォルダーを作成します。

mkdir -p src/main/java

新しいフォルダーに移動し、 CustomVisionQuickstart.javaという名前のファイルを作成します。 任意のエディターまたは IDE で開き、次の import ステートメントを追加します。

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;

import com.google.common.io.ByteStreams;

import com.microsoft.azure.cognitiveservices.vision.customvision.training.models.Classifier;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.models.Domain;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.models.DomainType;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.models.ImageFileCreateBatch;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.models.ImageFileCreateEntry;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.models.Iteration;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.models.Project;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.models.Region;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.models.TrainProjectOptionalParameter;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.CustomVisionTrainingClient;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.Trainings;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.CustomVisionTrainingManager;
import com.microsoft.azure.cognitiveservices.vision.customvision.prediction.models.ImagePrediction;
import com.microsoft.azure.cognitiveservices.vision.customvision.prediction.models.Prediction;
import com.microsoft.azure.cognitiveservices.vision.customvision.prediction.CustomVisionPredictionClient;
import com.microsoft.azure.cognitiveservices.vision.customvision.prediction.CustomVisionPredictionManager;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.models.Tag;

ヒント

クイック スタート コード ファイル全体を一度に表示しますか? このクイック スタートのコード例を含む GitHub で確認できます。

アプリケーションの CustomVisionQuickstart クラスで、環境変数からリソースのキーとエンドポイントを取得する変数を作成します。

// retrieve environment variables
final static String trainingApiKey = System.getenv("VISION_TRAINING_KEY");
final static String trainingEndpoint = System.getenv("VISION_TRAINING_ENDPOINT");
final static String predictionApiKey = System.getenv("VISION_PREDICTION_KEY");
final static String predictionEndpoint = System.getenv("VISION_PREDICTION_ENDPOINT");
final static String predictionResourceId = System.getenv("VISION_PREDICTION_RESOURCE_ID");

アプリケーションの メイン メソッドで、このクイック スタートで使用するメソッドの呼び出しを追加します。 これらは後で定義します。

Project projectOD = createProjectOD(trainClient);
addTagsOD(trainClient, projectOD);
uploadImagesOD(trainClient, projectOD);
trainProjectOD(trainClient, projectOD);
publishIterationOD(trainClient, project);
testProjectOD(predictor, projectOD);

オブジェクト モデル

次のクラスとインターフェイスは、Custom Vision Java クライアント ライブラリの主要な機能の一部を処理します。

名前 説明
CustomVisionTrainingClient このクラスは、モデルの作成、トレーニング、発行を処理します。
CustomVisionPredictionClient このクラスは、オブジェクト検出予測のモデルのクエリを処理します。
ImagePrediction このクラスは、1 つの画像に対して 1 つのオブジェクト予測を定義します。 これには、オブジェクト ID と名前のプロパティ、オブジェクトの境界ボックスの位置、信頼度スコアが含まれます。

コード例

これらのコード スニペットは、Java用 Custom Vision クライアント ライブラリを使用して次のタスクを実行する方法を示しています。

クライアントを認証する

メインメソッドで、エンドポイントとキーを使用してトレーニングクライアントと予測クライアントをインスタンス化します。

// Authenticate
CustomVisionTrainingClient trainClient = CustomVisionTrainingManager
        .authenticate(trainingEndpoint, trainingApiKey)
        .withEndpoint(trainingEndpoint);
CustomVisionPredictionClient predictor = CustomVisionPredictionManager
        .authenticate(predictionEndpoint, predictionApiKey)
        .withEndpoint(predictionEndpoint);

新しい Custom Vision プロジェクトを作成する

次のメソッドは、物体検出プロジェクトを作成します。 作成したプロジェクトは、先ほどアクセスした Custom Vision Web サイト に表示されます。 プロジェクトの作成時に他のオプションを指定するには、 CreateProject メソッドのオーバーロードを参照してください ( 「検出機能の構築 」Web ポータル ガイドで説明されています)。

public static Project createProjectOD(CustomVisionTrainingClient trainClient) {
    Trainings trainer = trainClient.trainings();

    // find the object detection domain to set the project type
    Domain objectDetectionDomain = null;
    List<Domain> domains = trainer.getDomains();
    for (final Domain domain : domains) {
        if (domain.type() == DomainType.OBJECT_DETECTION) {
            objectDetectionDomain = domain;
            break;
        }
    }

    if (objectDetectionDomain == null) {
        System.out.println("Unexpected result; no objects were detected.");
    }

    System.out.println("Creating project...");
    // create an object detection project
    Project project = trainer.createProject().withName("Sample Java OD Project")
            .withDescription("Sample OD Project").withDomainId(objectDetectionDomain.id())
            .withClassificationType(Classifier.MULTILABEL.toString()).execute();

    return project;
}

プロジェクトにタグを追加する

このメソッドは、モデルをトレーニングするタグを定義します。

public static void addTagsOD(CustomVisionTrainingClient trainClient, Project project) {
    Trainings trainer = trainClient.trainings();
    // create fork tag
    Tag forkTag = trainer.createTag().withProjectId(project.id()).withName("fork").execute();

    // create scissors tag
    Tag scissorsTag = trainer.createTag().withProjectId(project.id()).withName("scissor").execute();
}

画像をアップロードしてタグ付けする

まず、このプロジェクトのサンプル イメージをダウンロードします。 サンプル イメージ フォルダーの内容をローカル デバイスに保存します。

メモ

トレーニングを完了するには、より広範な画像セットが必要ですか? トローブは、Microsoft Garageによるプロジェクトで、トレーニング目的の画像セットを収集および購入することが可能です。 画像を収集したら、それらをダウンロードし、通常の方法で Custom Vision プロジェクトにインポートできます。 詳細については、 Trove のページ を参照してください。

物体検出プロジェクトで画像にタグを付ける場合は、正規化された座標を使用して、タグ付けされた各オブジェクトの領域を指定する必要があります。 次のコードは、各サンプル イメージをタグ付けされた領域に関連付けます。

メモ

領域の座標をマークするクリック アンド ドラッグ ユーティリティがない場合は、 Customvision.ai で Web UI を使用できます。 この例では、座標は既に指定されています。

public static void uploadImagesOD(CustomVisionTrainingClient trainClient, Project project) {
    // Mapping of filenames to their respective regions in the image. The
    // coordinates are specified
    // as left, top, width, height in normalized coordinates. I.e. (left is left in
    // pixels / width in pixels)

    // This is a hardcoded mapping of the files we'll upload along with the bounding
    // box of the object in the
    // image. The boudning box is specified as left, top, width, height in
    // normalized coordinates.
    // Normalized Left = Left / Width (in Pixels)
    // Normalized Top = Top / Height (in Pixels)
    // Normalized Bounding Box Width = (Right - Left) / Width (in Pixels)
    // Normalized Bounding Box Height = (Bottom - Top) / Height (in Pixels)
    HashMap<String, double[]> regionMap = new HashMap<String, double[]>();
    regionMap.put("scissors_1.jpg", new double[] { 0.4007353, 0.194068655, 0.259803921, 0.6617647 });
    regionMap.put("scissors_2.jpg", new double[] { 0.426470578, 0.185898721, 0.172794119, 0.5539216 });
    regionMap.put("scissors_3.jpg", new double[] { 0.289215684, 0.259428144, 0.403186262, 0.421568632 });
    regionMap.put("scissors_4.jpg", new double[] { 0.343137264, 0.105833367, 0.332107842, 0.8055556 });
    regionMap.put("scissors_5.jpg", new double[] { 0.3125, 0.09766343, 0.435049027, 0.71405226 });
    regionMap.put("scissors_6.jpg", new double[] { 0.379901975, 0.24308826, 0.32107842, 0.5718954 });
    regionMap.put("scissors_7.jpg", new double[] { 0.341911763, 0.20714055, 0.3137255, 0.6356209 });
    regionMap.put("scissors_8.jpg", new double[] { 0.231617644, 0.08459154, 0.504901946, 0.8480392 });
    regionMap.put("scissors_9.jpg", new double[] { 0.170343131, 0.332957536, 0.767156839, 0.403594762 });
    regionMap.put("scissors_10.jpg", new double[] { 0.204656869, 0.120539248, 0.5245098, 0.743464053 });
    regionMap.put("scissors_11.jpg", new double[] { 0.05514706, 0.159754932, 0.799019635, 0.730392158 });
    regionMap.put("scissors_12.jpg", new double[] { 0.265931368, 0.169558853, 0.5061275, 0.606209159 });
    regionMap.put("scissors_13.jpg", new double[] { 0.241421565, 0.184264734, 0.448529422, 0.6830065 });
    regionMap.put("scissors_14.jpg", new double[] { 0.05759804, 0.05027781, 0.75, 0.882352948 });
    regionMap.put("scissors_15.jpg", new double[] { 0.191176474, 0.169558853, 0.6936275, 0.6748366 });
    regionMap.put("scissors_16.jpg", new double[] { 0.1004902, 0.279036, 0.6911765, 0.477124184 });
    regionMap.put("scissors_17.jpg", new double[] { 0.2720588, 0.131977156, 0.4987745, 0.6911765 });
    regionMap.put("scissors_18.jpg", new double[] { 0.180147052, 0.112369314, 0.6262255, 0.6666667 });
    regionMap.put("scissors_19.jpg", new double[] { 0.333333343, 0.0274019931, 0.443627447, 0.852941155 });
    regionMap.put("scissors_20.jpg", new double[] { 0.158088237, 0.04047389, 0.6691176, 0.843137264 });
    regionMap.put("fork_1.jpg", new double[] { 0.145833328, 0.3509314, 0.5894608, 0.238562092 });
    regionMap.put("fork_2.jpg", new double[] { 0.294117659, 0.216944471, 0.534313738, 0.5980392 });
    regionMap.put("fork_3.jpg", new double[] { 0.09191177, 0.0682516545, 0.757352948, 0.6143791 });
    regionMap.put("fork_4.jpg", new double[] { 0.254901975, 0.185898721, 0.5232843, 0.594771266 });
    regionMap.put("fork_5.jpg", new double[] { 0.2365196, 0.128709182, 0.5845588, 0.71405226 });
    regionMap.put("fork_6.jpg", new double[] { 0.115196079, 0.133611143, 0.676470637, 0.6993464 });
    regionMap.put("fork_7.jpg", new double[] { 0.164215669, 0.31008172, 0.767156839, 0.410130739 });
    regionMap.put("fork_8.jpg", new double[] { 0.118872553, 0.318251669, 0.817401946, 0.225490168 });
    regionMap.put("fork_9.jpg", new double[] { 0.18259804, 0.2136765, 0.6335784, 0.643790841 });
    regionMap.put("fork_10.jpg", new double[] { 0.05269608, 0.282303959, 0.8088235, 0.452614367 });
    regionMap.put("fork_11.jpg", new double[] { 0.05759804, 0.0894935, 0.9007353, 0.3251634 });
    regionMap.put("fork_12.jpg", new double[] { 0.3345588, 0.07315363, 0.375, 0.9150327 });
    regionMap.put("fork_13.jpg", new double[] { 0.269607842, 0.194068655, 0.4093137, 0.6732026 });
    regionMap.put("fork_14.jpg", new double[] { 0.143382356, 0.218578458, 0.7977941, 0.295751631 });
    regionMap.put("fork_15.jpg", new double[] { 0.19240196, 0.0633497, 0.5710784, 0.8398692 });
    regionMap.put("fork_16.jpg", new double[] { 0.140931368, 0.480016381, 0.6838235, 0.240196079 });
    regionMap.put("fork_17.jpg", new double[] { 0.305147052, 0.2512582, 0.4791667, 0.5408496 });
    regionMap.put("fork_18.jpg", new double[] { 0.234068632, 0.445702642, 0.6127451, 0.344771236 });
    regionMap.put("fork_19.jpg", new double[] { 0.219362751, 0.141781077, 0.5919118, 0.6683006 });
    regionMap.put("fork_20.jpg", new double[] { 0.180147052, 0.239820287, 0.6887255, 0.235294119 });

次のコード ブロックは、プロジェクトにイメージを追加します。 ダウンロードしたGetImage フォルダーとハサミ フォルダーの場所を指す呼び出しの引数を変更する必要があります。

    Trainings trainer = trainClient.trainings();

    System.out.println("Adding images...");
    for (int i = 1; i <= 20; i++) {
        String fileName = "fork_" + i + ".jpg";
        byte[] contents = GetImage("/fork", fileName);
        AddImageToProject(trainer, project, fileName, contents, forkTag.id(), regionMap.get(fileName));
    }

    for (int i = 1; i <= 20; i++) {
        String fileName = "scissors_" + i + ".jpg";
        byte[] contents = GetImage("/scissors", fileName);
        AddImageToProject(trainer, project, fileName, contents, scissorsTag.id(), regionMap.get(fileName));
    }
}

前のコード スニペットでは、リソース ストリームとしてイメージを取得してサービスにアップロードする 2 つのヘルパー関数を使用しています (1 回のバッチで最大 64 個の画像をアップロードできます)。 これらのメソッドを定義します。

private static void AddImageToProject(Trainings trainer, Project project, String fileName, byte[] contents,
        UUID tag, double[] regionValues) {
    System.out.println("Adding image: " + fileName);
    ImageFileCreateEntry file = new ImageFileCreateEntry().withName(fileName).withContents(contents);

    ImageFileCreateBatch batch = new ImageFileCreateBatch().withImages(Collections.singletonList(file));

    // If Optional region is specified, tack it on and place the tag there,
    // otherwise
    // add it to the batch.
    if (regionValues != null) {
        Region region = new Region().withTagId(tag).withLeft(regionValues[0]).withTop(regionValues[1])
                .withWidth(regionValues[2]).withHeight(regionValues[3]);
        file = file.withRegions(Collections.singletonList(region));
    } else {
        batch = batch.withTagIds(Collections.singletonList(tag));
    }

    trainer.createImagesFromFiles(project.id(), batch);
}

private static byte[] GetImage(String folder, String fileName) {
    try {
        return ByteStreams.toByteArray(CustomVisionSamples.class.getResourceAsStream(folder + "/" + fileName));
    } catch (Exception e) {
        System.out.println(e.getMessage());
        e.printStackTrace();
    }
    return null;
}

プロジェクトをトレーニングする

このメソッドは、プロジェクトで最初のトレーニング イテレーションを作成します。 トレーニングが完了するまでサービスに対してクエリを実行します。

public static String trainProjectOD(CustomVisionTrainingClient trainClient, Project project) {
    Trainings trainer = trainClient.trainings();
    System.out.println("Training...");
    Iteration iteration = trainer.trainProject(project.id(), new TrainProjectOptionalParameter());

    while (iteration.status().equals("Training")) {
        System.out.println("Training Status: " + iteration.status());
        Thread.sleep(5000);
        iteration = trainer.getIteration(project.id(), iteration.id());
    }
    System.out.println("Training Status: " + iteration.status());
}

現在のイテレーションを発行する

このメソッドを使用すると、モデルの現在のイテレーションをクエリに使用できるようになります。 モデル名を参照として使用して、予測要求を送信できます。 predictionResourceIdには独自の値を入力する必要があります。 予測リソース ID は、Azure ポータルのリソースの Properties タブで、Resource ID として表示されます。

public static String publishIterationOD(CustomVisionTrainingClient trainClient, Project project) {
    Trainings trainer = trainClient.trainings();

    // The iteration is now trained. Publish it to the prediction endpoint.
    String publishedModelName = "myModel";
    String predictionID = "<your-prediction-resource-ID>";
    trainer.publishIteration(project.id(), iteration.id(), publishedModelName, predictionID);
    return publishedModelName;
}

予測エンドポイントをテストする

このメソッドは、テスト イメージを読み込み、モデル エンドポイントに対してクエリを実行し、予測データをコンソールに出力します。

public static void testProjectOD(CustomVisionPredictionClient predictor, Project project) {

    // load test image
    byte[] testImage = GetImage("/ObjectTest", "test_image.jpg");

    // predict
    ImagePrediction results = predictor.predictions().detectImage().withProjectId(project.id())
            .withPublishedName(publishedModelName).withImageData(testImage).execute();

    for (Prediction prediction : results.predictions()) {
        System.out.println(String.format("\t%s: %.2f%% at: %.2f, %.2f, %.2f, %.2f", prediction.tagName(),
                prediction.probability() * 100.0f, prediction.boundingBox().left(), prediction.boundingBox().top(),
                prediction.boundingBox().width(), prediction.boundingBox().height()));
    }
}

アプリケーションを実行する

次の方法でアプリをビルドできます。

gradle build

gradle run コマンドを使用してアプリケーションを実行します。

gradle run

リソースのクリーンアップ

Azure AI サービス サブスクリプションをクリーンアップして削除する場合は、リソースまたはリソース グループを削除できます。 リソース グループを削除すると、それに関連付けられている他のリソースも削除されます。

独自の物体検出プロジェクトを実装する (または 画像分類 プロジェクトを試す) 場合は、この例からフォーク/ハサミ検出プロジェクトを削除できます。 無料サブスクリプションでは、2 つの Custom Vision プロジェクトを利用できます。

Custom Vision Web サイトで、Projects に移動し、[マイ ニュー Project] の下にあるごみ箱を選択します。

ごみ箱アイコンが付いた [新しいProject] というラベルのパネルのスクリーンショット。

次の手順

これで、オブジェクト検出プロセスのすべての手順をコードで行いました。 このサンプルでは 1 回のトレーニング イテレーションを実行しますが、多くの場合、モデルをより正確にするために、モデルを複数回トレーニングしてテストする必要があります。 次のガイドでは画像分類について説明しますが、その原則は物体検出に似ています。

このガイドでは、Node.js 用 Custom Vision クライアント ライブラリを使用して物体検出モデルを構築する際に役立つ手順とサンプル コードについて説明します。 プロジェクトを作成し、タグを追加し、プロジェクトをトレーニングし、プロジェクトの予測エンドポイント URL を使用してプログラムでテストします。 この例は、独自の画像認識アプリを構築するためのテンプレートとして使用します。

メモ

コードを記述 せずに オブジェクト検出モデルを構築してトレーニングする場合は、代わりに ブラウザーベースのガイダンス を参照してください。

リファレンス ドキュメント (トレーニング)(予測) | Package (npm) (トレーニング)(予測) | サンプル

前提 条件

  • Azure サブスクリプション - 無料で作成します
  • Node.js の現在のバージョン
  • Azure サブスクリプションを取得したら、Azure ポータルで Custom Vision リソース を作成して、トレーニングと予測のリソースを作成します。
    • Free 価格レベル (F0) を使用してサービスを試し、後で運用環境用の有料レベルにアップグレードできます。

環境変数を作成する

この例では、アプリケーションを実行しているローカル コンピューター上の環境変数に資格情報を書き込みます。

Azure ポータルに移動します。 [前提条件] セクションで作成した Custom Vision リソースが正常にデプロイされた場合は、[次の手順] の [リソースに移動] ボタンを選択します。 キーとエンドポイントは、リソースの [ キー] ページと [エンドポイント] ページの [ リソース管理] にあります。 API エンドポイントと共に、トレーニング リソースと予測リソースの両方のキーを取得する必要があります。

予測リソースの Properties タブには、Azure ポータルで Resource ID として一覧表示されています。

ヒント

また、 https://www.customvision.ai を使用してこれらの値を取得します。 サインインしたら、右上にある [設定] アイコンを選択します。 [設定] ページでは、すべてのキー、リソース ID、エンドポイントを表示できます。

環境変数を設定するには、コンソール ウィンドウを開き、オペレーティング システムと開発環境の指示に従います。

  • VISION_TRAINING KEY環境変数を設定するには、<your-training-key>をトレーニング リソースのキーのいずれかに置き換えます。
  • VISION_TRAINING_ENDPOINT環境変数を設定するには、<your-training-endpoint>をトレーニング リソースのエンドポイントに置き換えます。
  • VISION_PREDICTION_KEY環境変数を設定するには、<your-prediction-key>を予測リソースのキーのいずれかに置き換えます。
  • VISION_PREDICTION_ENDPOINT環境変数を設定するには、<your-prediction-endpoint>を予測リソースのエンドポイントに置き換えます。
  • VISION_PREDICTION_RESOURCE_ID環境変数を設定するには、<your-resource-id>を予測リソースのリソース ID に置き換えます。

重要

クラウドで実行されるアプリケーションに資格情報を格納しないように、 Azure リソースの管理された ID を使用して認証をMicrosoft Entra IDすることをお勧めします。

API キーは慎重に使用してください。 API キーをコードに直接含めず、パブリックに投稿しないでください。 API キーを使用する場合は、Azure Key Vaultに安全に格納し、キーを定期的にローテーションし、ロールベースのアクセス制御とネットワーク アクセス制限を使用してAzure Key Vaultへのアクセスを制限します。 アプリで API キーを安全に使用する方法の詳細については、「Azure Key Vault を使用した API キー」を参照してください。

AI サービスのセキュリティの詳細については、「Authenticate requests to Azure AI サービス」を参照してください。

setx VISION_TRAINING_KEY <your-training-key>
setx VISION_TRAINING_ENDPOINT <your-training-endpoint>
setx VISION_PREDICTION_KEY <your-prediction-key>
setx VISION_PREDICTION_ENDPOINT <your-prediction-endpoint>
setx VISION_PREDICTION_RESOURCE_ID <your-resource-id>

環境変数を追加した後、コンソール ウィンドウを含め、環境変数を読み取る実行中のプログラムを再起動することが必要になる場合があります。

セットアップ

新しい Node.js アプリケーションを作成する

コンソール ウィンドウ (cmd、PowerShell、Bash など) で、アプリ用の新しいディレクトリを作成し、そこに移動します。

mkdir myapp && cd myapp

npm init コマンドを実行して、package.json ファイルを含むノード アプリケーションを作成します。

npm init

クライアント ライブラリをインストールする

Custom Vision for Node.jsを使用して画像分析アプリを作成するには、Custom Vision npm パッケージが必要です。 それらをインストールするには、PowerShell で次のコマンドを実行します。

npm install @azure/cognitiveservices-customvision-training
npm install @azure/cognitiveservices-customvision-prediction

アプリの package.json ファイルが依存関係で更新されます。

index.jsという名前のファイルを作成し、次のライブラリをインポートします。

const util = require('util');
const fs = require('fs');
const TrainingApi = require("@azure/cognitiveservices-customvision-training");
const PredictionApi = require("@azure/cognitiveservices-customvision-prediction");
const msRest = require("@azure/ms-rest-js");

ヒント

クイック スタート コード ファイル全体を一度に表示しますか? このクイック スタートのコード例を含む GitHub で確認できます。

リソースのAzure エンドポイントとキーの変数を作成します。

// retrieve environment variables
const trainingKey = process.env["VISION_TRAINING_KEY"];
const trainingEndpoint = process.env["VISION_TRAINING_ENDPOINT"];

const predictionKey = process.env["VISION_PREDICTION_KEY"];
const predictionResourceId = process.env["VISION_PREDICTION_RESOURCE_ID"];
const predictionEndpoint = process.env["VISION_PREDICTION_ENDPOINT"];

また、プロジェクト名のフィールドと非同期呼び出しのタイムアウト パラメーターも追加します。

const publishIterationName = "detectModel";
const setTimeoutPromise = util.promisify(setTimeout);

オブジェクト モデル

名前 説明
TrainingAPIClient このクラスは、モデルの作成、トレーニング、発行を処理します。
PredictionAPIClient このクラスは、オブジェクト検出予測のモデルのクエリを処理します。
予測 このインターフェイスは、1 つの画像に対して 1 つの予測を定義します。 これには、オブジェクト ID と名前のプロパティと信頼度スコアが含まれます。

コード例

これらのコード スニペットは、JavaScript 用 Custom Vision クライアント ライブラリを使用して次のタスクを実行する方法を示しています。

クライアントを認証する

エンドポイントとキーを使用してクライアント オブジェクトをインスタンス化します。 キーを使用 して ApiKeyCredentials オブジェクトを作成し、それをエンドポイントと共に使用して TrainingAPIClient オブジェクトと PredictionAPIClient オブジェクトを作成します。

const credentials = new msRest.ApiKeyCredentials({ inHeader: { "Training-key": trainingKey } });
const trainer = new TrainingApi.TrainingAPIClient(credentials, trainingEndpoint);
const predictor_credentials = new msRest.ApiKeyCredentials({ inHeader: { "Prediction-key": predictionKey } });
const predictor = new PredictionApi.PredictionAPIClient(predictor_credentials, predictionEndpoint);

ヘルパー関数を追加する

複数の非同期呼び出しを行うために役立つ次の関数を追加します。 後で使います。

const credentials = new msRest.ApiKeyCredentials({ inHeader: { "Training-key": trainingKey } });
const trainer = new TrainingApi.TrainingAPIClient(credentials, trainingEndpoint);
const predictor_credentials = new msRest.ApiKeyCredentials({ inHeader: { "Prediction-key": predictionKey } });
const predictor = new PredictionApi.PredictionAPIClient(predictor_credentials, predictionEndpoint);

新しい Custom Vision プロジェクトを作成する

すべての Custom Vision 関数呼び出しを含む新しい関数を開始します。 次のコードを追加して、新しい Custom Vision サービス プロジェクトを作成します。

(async () => {
    console.log("Creating project...");
    const domains = await trainer.getDomains()
    const objDetectDomain = domains.find(domain => domain.type === "ObjectDetection");
    const sampleProject = await trainer.createProject("Sample Obj Detection Project", { domainId: objDetectDomain.id });

プロジェクトにタグを追加する

プロジェクトに分類タグを作成するには、次のコードを関数に追加します。

const forkTag = await trainer.createTag(sampleProject.id, "Fork");
const scissorsTag = await trainer.createTag(sampleProject.id, "Scissors");

画像をアップロードしてタグ付けする

まず、このプロジェクトのサンプル イメージをダウンロードします。 サンプル イメージ フォルダーの内容をローカル デバイスに保存します。

サンプル イメージをプロジェクトに追加するには、タグの作成後に次のコードを挿入します。 このコードは、対応するタグを持つ各画像をアップロードします。 物体検出プロジェクトで画像にタグを付ける場合は、正規化された座標を使用して、タグ付けされた各オブジェクトの領域を指定する必要があります。 このチュートリアルでは、リージョンはコードと共にインラインでハードコーディングされます。 領域は正規化された座標で境界ボックスを指定し、座標は左、上、幅、高さの順に指定されます。 1 回のバッチで最大 64 個の画像をアップロードできます。

const sampleDataRoot = "Images";

const forkImageRegions = {
    "fork_1.jpg": [0.145833328, 0.3509314, 0.5894608, 0.238562092],
    "fork_2.jpg": [0.294117659, 0.216944471, 0.534313738, 0.5980392],
    "fork_3.jpg": [0.09191177, 0.0682516545, 0.757352948, 0.6143791],
    "fork_4.jpg": [0.254901975, 0.185898721, 0.5232843, 0.594771266],
    "fork_5.jpg": [0.2365196, 0.128709182, 0.5845588, 0.71405226],
    "fork_6.jpg": [0.115196079, 0.133611143, 0.676470637, 0.6993464],
    "fork_7.jpg": [0.164215669, 0.31008172, 0.767156839, 0.410130739],
    "fork_8.jpg": [0.118872553, 0.318251669, 0.817401946, 0.225490168],
    "fork_9.jpg": [0.18259804, 0.2136765, 0.6335784, 0.643790841],
    "fork_10.jpg": [0.05269608, 0.282303959, 0.8088235, 0.452614367],
    "fork_11.jpg": [0.05759804, 0.0894935, 0.9007353, 0.3251634],
    "fork_12.jpg": [0.3345588, 0.07315363, 0.375, 0.9150327],
    "fork_13.jpg": [0.269607842, 0.194068655, 0.4093137, 0.6732026],
    "fork_14.jpg": [0.143382356, 0.218578458, 0.7977941, 0.295751631],
    "fork_15.jpg": [0.19240196, 0.0633497, 0.5710784, 0.8398692],
    "fork_16.jpg": [0.140931368, 0.480016381, 0.6838235, 0.240196079],
    "fork_17.jpg": [0.305147052, 0.2512582, 0.4791667, 0.5408496],
    "fork_18.jpg": [0.234068632, 0.445702642, 0.6127451, 0.344771236],
    "fork_19.jpg": [0.219362751, 0.141781077, 0.5919118, 0.6683006],
    "fork_20.jpg": [0.180147052, 0.239820287, 0.6887255, 0.235294119]
};

const scissorsImageRegions = {
    "scissors_1.jpg": [0.4007353, 0.194068655, 0.259803921, 0.6617647],
    "scissors_2.jpg": [0.426470578, 0.185898721, 0.172794119, 0.5539216],
    "scissors_3.jpg": [0.289215684, 0.259428144, 0.403186262, 0.421568632],
    "scissors_4.jpg": [0.343137264, 0.105833367, 0.332107842, 0.8055556],
    "scissors_5.jpg": [0.3125, 0.09766343, 0.435049027, 0.71405226],
    "scissors_6.jpg": [0.379901975, 0.24308826, 0.32107842, 0.5718954],
    "scissors_7.jpg": [0.341911763, 0.20714055, 0.3137255, 0.6356209],
    "scissors_8.jpg": [0.231617644, 0.08459154, 0.504901946, 0.8480392],
    "scissors_9.jpg": [0.170343131, 0.332957536, 0.767156839, 0.403594762],
    "scissors_10.jpg": [0.204656869, 0.120539248, 0.5245098, 0.743464053],
    "scissors_11.jpg": [0.05514706, 0.159754932, 0.799019635, 0.730392158],
    "scissors_12.jpg": [0.265931368, 0.169558853, 0.5061275, 0.606209159],
    "scissors_13.jpg": [0.241421565, 0.184264734, 0.448529422, 0.6830065],
    "scissors_14.jpg": [0.05759804, 0.05027781, 0.75, 0.882352948],
    "scissors_15.jpg": [0.191176474, 0.169558853, 0.6936275, 0.6748366],
    "scissors_16.jpg": [0.1004902, 0.279036, 0.6911765, 0.477124184],
    "scissors_17.jpg": [0.2720588, 0.131977156, 0.4987745, 0.6911765],
    "scissors_18.jpg": [0.180147052, 0.112369314, 0.6262255, 0.6666667],
    "scissors_19.jpg": [0.333333343, 0.0274019931, 0.443627447, 0.852941155],
    "scissors_20.jpg": [0.158088237, 0.04047389, 0.6691176, 0.843137264]
};

console.log("Adding images...");
let fileUploadPromises = [];

const forkDir = `${sampleDataRoot}/fork`;
const forkFiles = fs.readdirSync(forkDir);

await asyncForEach(forkFiles, async (file) => {
    const region = { tagId: forkTag.id, left: forkImageRegions[file][0], top: forkImageRegions[file][1], width: forkImageRegions[file][2], height: forkImageRegions[file][3] };
    const entry = { name: file, contents: fs.readFileSync(`${forkDir}/${file}`), regions: [region] };
    const batch = { images: [entry] };
    // Wait one second to accommodate rate limit.
    await setTimeoutPromise(1000, null);
    fileUploadPromises.push(trainer.createImagesFromFiles(sampleProject.id, batch));
});

const scissorsDir = `${sampleDataRoot}/scissors`;
const scissorsFiles = fs.readdirSync(scissorsDir);

await asyncForEach(scissorsFiles, async (file) => {
    const region = { tagId: scissorsTag.id, left: scissorsImageRegions[file][0], top: scissorsImageRegions[file][1], width: scissorsImageRegions[file][2], height: scissorsImageRegions[file][3] };
    const entry = { name: file, contents: fs.readFileSync(`${scissorsDir}/${file}`), regions: [region] };
    const batch = { images: [entry] };
    // Wait one second to accommodate rate limit.
    await setTimeoutPromise(1000, null);
    fileUploadPromises.push(trainer.createImagesFromFiles(sampleProject.id, batch));
});

await Promise.all(fileUploadPromises);

重要

Foundry Tools Python SDK Samples リポジトリをダウンロードした場所に基づいて、イメージへのパス (sampleDataRoot) を変更する必要があります。

メモ

領域の座標をマークするクリック アンド ドラッグ ユーティリティがない場合は、 Customvision.ai で Web UI を使用できます。 この例では、座標は既に指定されています。

プロジェクトをトレーニングする

このコードは、予測モデルの最初のイテレーションを作成します。

console.log("Training...");
let trainingIteration = await trainer.trainProject(sampleProject.id);

// Wait for training to complete
console.log("Training started...");
while (trainingIteration.status == "Training") {
    console.log("Training status: " + trainingIteration.status);
    // wait for ten seconds
    await setTimeoutPromise(10000, null);
    trainingIteration = await trainer.getIteration(sampleProject.id, trainingIteration.id)
}
console.log("Training status: " + trainingIteration.status);

現在のイテレーションを発行する

このコードは、トレーニング済みのイテレーションを予測エンドポイントに発行します。 発行されたイテレーションに指定された名前を使用して、予測要求を送信できます。 イテレーションは、発行されるまで予測エンドポイントで利用できません。

// Publish the iteration to the end point
await trainer.publishIteration(sampleProject.id, trainingIteration.id, publishIterationName, predictionResourceId);    

予測エンドポイントをテストする

画像を予測エンドポイントに送信して予測を取得するには、次のコードを関数に追加します。

const testFile = fs.readFileSync(`${sampleDataRoot}/test/test_image.jpg`);
const results = await predictor.detectImage(sampleProject.id, publishIterationName, testFile)

// Show results
console.log("Results:");
results.predictions.forEach(predictedResult => {
    console.log(`\t ${predictedResult.tagName}: ${(predictedResult.probability * 100.0).toFixed(2)}% ${predictedResult.boundingBox.left},${predictedResult.boundingBox.top},${predictedResult.boundingBox.width},${predictedResult.boundingBox.height}`);
});

次に、Custom Vision 関数を閉じて呼び出します。

})()

アプリケーションを実行する

クイック スタート ファイルで node コマンドを使用してアプリケーションを実行します。

node index.js

アプリケーションの出力がコンソールに表示されます。 その後、テスト イメージ ( <sampleDataRoot>/Test/) が適切にタグ付けされていること、および検出の領域が正しいことを確認できます。 Custom Vision Web サイトに戻り、新しく作成したプロジェクトの現在の状態を確認することもできます。

リソースのクリーンアップ

独自の物体検出プロジェクトを実装する (または 画像分類 プロジェクトを試す) 場合は、この例からフォーク/ハサミ検出プロジェクトを削除できます。 無料サブスクリプションでは、2 つの Custom Vision プロジェクトを利用できます。

Custom Vision Web サイトで、Projects に移動し、[マイ ニュー Project] の下にあるごみ箱を選択します。

ごみ箱アイコンが付いた [新しいProject] というラベルのパネルのスクリーンショット。

次の手順

これで、オブジェクト検出プロセスのすべての手順をコードで行いました。 このサンプルでは、1 回のトレーニング イテレーションを実行しますが、多くの場合、モデルをより正確にするために、モデルを複数回トレーニングしてテストする必要があります。 次のガイドでは画像分類について説明しますが、その原則は物体検出に似ています。

Python用 Custom Vision クライアント ライブラリの使用を開始します。 次の手順に従ってパッケージをインストールし、オブジェクト検出モデルを構築するためのコード例を試してください。 プロジェクトを作成し、タグを追加し、プロジェクトをトレーニングし、プロジェクトの予測エンドポイント URL を使用してプログラムでテストします。 この例は、独自の画像認識アプリを構築するためのテンプレートとして使用します。

メモ

コードを記述 せずに オブジェクト検出モデルを構築してトレーニングする場合は、代わりに ブラウザーベースのガイダンス を参照してください。

リファレンス ドキュメント | ライブラリのソース コード | パッケージ (PyPI) | サンプル

前提 条件

  • Azure サブスクリプション - 無料で作成します
  • Python 3.x
    • Pythonインストールには、pipが含まれている必要があります。 コマンド ラインで pip --version を実行することで、pip がインストールされているかどうかを確認できます。 最新バージョンのPythonをインストールして pip を取得します。
  • Azure サブスクリプションを取得したら、Azure ポータルで Custom Vision リソースを作成して、トレーニングと予測リソースを作成します。
    • Free 価格レベル (F0) を使用してサービスを試し、後で運用環境用の有料レベルにアップグレードできます。

環境変数を作成する

この例では、アプリケーションを実行しているローカル コンピューター上の環境変数に資格情報を書き込みます。

Azure ポータルに移動します。 [前提条件] セクションで作成した Custom Vision リソースが正常にデプロイされた場合は、[次の手順] の [リソースに移動] ボタンを選択します。 キーとエンドポイントは、リソースの [ キー] ページと [エンドポイント] ページの [ リソース管理] にあります。 API エンドポイントと共に、トレーニング リソースと予測リソースの両方のキーを取得する必要があります。

予測リソースの Properties タブには、Azure ポータルで Resource ID として一覧表示されています。

ヒント

また、 https://www.customvision.ai を使用してこれらの値を取得します。 サインインしたら、右上にある [設定] アイコンを選択します。 [設定] ページでは、すべてのキー、リソース ID、エンドポイントを表示できます。

環境変数を設定するには、コンソール ウィンドウを開き、オペレーティング システムと開発環境の指示に従います。

  • VISION_TRAINING KEY環境変数を設定するには、<your-training-key>をトレーニング リソースのキーのいずれかに置き換えます。
  • VISION_TRAINING_ENDPOINT環境変数を設定するには、<your-training-endpoint>をトレーニング リソースのエンドポイントに置き換えます。
  • VISION_PREDICTION_KEY環境変数を設定するには、<your-prediction-key>を予測リソースのキーのいずれかに置き換えます。
  • VISION_PREDICTION_ENDPOINT環境変数を設定するには、<your-prediction-endpoint>を予測リソースのエンドポイントに置き換えます。
  • VISION_PREDICTION_RESOURCE_ID環境変数を設定するには、<your-resource-id>を予測リソースのリソース ID に置き換えます。

重要

クラウドで実行されるアプリケーションに資格情報を格納しないように、 Azure リソースの管理された ID を使用して認証をMicrosoft Entra IDすることをお勧めします。

API キーは慎重に使用してください。 API キーをコードに直接含めず、パブリックに投稿しないでください。 API キーを使用する場合は、Azure Key Vaultに安全に格納し、キーを定期的にローテーションし、ロールベースのアクセス制御とネットワーク アクセス制限を使用してAzure Key Vaultへのアクセスを制限します。 アプリで API キーを安全に使用する方法の詳細については、「Azure Key Vault を使用した API キー」を参照してください。

AI サービスのセキュリティの詳細については、「Authenticate requests to Azure AI サービス」を参照してください。

setx VISION_TRAINING_KEY <your-training-key>
setx VISION_TRAINING_ENDPOINT <your-training-endpoint>
setx VISION_PREDICTION_KEY <your-prediction-key>
setx VISION_PREDICTION_ENDPOINT <your-prediction-endpoint>
setx VISION_PREDICTION_RESOURCE_ID <your-resource-id>

環境変数を追加した後、コンソール ウィンドウを含め、環境変数を読み取る実行中のプログラムを再起動することが必要になる場合があります。

セットアップ

クライアント ライブラリをインストールする

Custom Vision for Python を使用して画像分析アプリを作成するには、Custom Vision クライアント ライブラリが必要です。 Pythonをインストールしたら、PowerShell またはコンソール ウィンドウで次のコマンドを実行します。

pip install azure-cognitiveservices-vision-customvision

新しいPython アプリケーションを作成する

新しいPython ファイルを作成し、次のライブラリをインポートします。

from azure.cognitiveservices.vision.customvision.training import CustomVisionTrainingClient
from azure.cognitiveservices.vision.customvision.prediction import CustomVisionPredictionClient
from azure.cognitiveservices.vision.customvision.training.models import ImageFileCreateBatch, ImageFileCreateEntry, Region
from msrest.authentication import ApiKeyCredentials
import os, time, uuid

ヒント

クイック スタート コード ファイル全体を一度に表示しますか? このクイック スタートのコード例を含む GitHub で確認できます。

リソースのAzure エンドポイントとキーの変数を作成します。

# Replace with vprediction_endpointalid values
ENDPOINT = os.environ["VISION_TRAINING_ENDPOINT"]
prediction_endpoint = os.environ["VISION_PREDICTION_ENDPOINT"]
training_key = os.environ["VISION_TRAINING_KEY"]
prediction_key = os.environ["VISION_PREDICTION_KEY"]
prediction_resource_id = os.environ["VISION_PREDICTION_RESOURCE_ID"]

オブジェクト モデル

名前 説明
CustomVisionTrainingClient このクラスは、モデルの作成、トレーニング、発行を処理します。
CustomVisionPredictionClient このクラスは、オブジェクト検出予測のモデルのクエリを処理します。
ImagePrediction このクラスは、1 つの画像に対して 1 つのオブジェクト予測を定義します。 これには、オブジェクト ID と名前のプロパティ、オブジェクトの境界ボックスの位置、信頼度スコアが含まれます。

コード例

これらのコード スニペットは、Python用 Custom Vision クライアント ライブラリを使用して次の操作を行う方法を示しています。

クライアントを認証する

エンドポイントとキーを使用してトレーニングおよび予測クライアントをインスタンス化します。 キーを使用して ApiKeyServiceClientCredentials オブジェクトを作成し、それらをエンドポイントと共に使用して CustomVisionTrainingClient オブジェクトと CustomVisionPredictionClient オブジェクトを作成します。

credentials = ApiKeyCredentials(in_headers={"Training-key": training_key})
trainer = CustomVisionTrainingClient(ENDPOINT, credentials)
prediction_credentials = ApiKeyCredentials(in_headers={"Prediction-key": prediction_key})
predictor = CustomVisionPredictionClient(prediction_endpoint, prediction_credentials)

新しい Custom Vision プロジェクトを作成する

スクリプトに次のコードを追加して、新しい Custom Vision サービス プロジェクトを作成します。

プロジェクトの作成時に他のオプションを指定するには、 create_project メソッドを参照してください ( 「検出機能の構築 」Web ポータル ガイドで説明)。

publish_iteration_name = "detectModel"

# Find the object detection domain
obj_detection_domain = next(domain for domain in trainer.get_domains() if domain.type == "ObjectDetection" and domain.name == "General")

# Create a new project
print ("Creating project...")
# Use uuid to avoid project name collisions.
project = trainer.create_project(str(uuid.uuid4()), domain_id=obj_detection_domain.id)

プロジェクトにタグを追加する

プロジェクトにオブジェクト タグを作成するには、次のコードを追加します。

# Make two tags in the new project
fork_tag = trainer.create_tag(project.id, "fork")
scissors_tag = trainer.create_tag(project.id, "scissors")

画像をアップロードしてタグ付けする

まず、このプロジェクトのサンプル イメージをダウンロードします。 サンプル イメージ フォルダーの内容をローカル デバイスに保存します。

物体検出プロジェクトで画像にタグを付ける場合は、正規化された座標を使用して、タグ付けされた各オブジェクトの領域を指定する必要があります。 次のコードは、各サンプル イメージをタグ付けされた領域に関連付けます。 領域は正規化された座標で境界ボックスを指定し、座標は左、上、幅、高さの順に指定されます。

fork_image_regions = {
    "fork_1": [ 0.145833328, 0.3509314, 0.5894608, 0.238562092 ],
    "fork_2": [ 0.294117659, 0.216944471, 0.534313738, 0.5980392 ],
    "fork_3": [ 0.09191177, 0.0682516545, 0.757352948, 0.6143791 ],
    "fork_4": [ 0.254901975, 0.185898721, 0.5232843, 0.594771266 ],
    "fork_5": [ 0.2365196, 0.128709182, 0.5845588, 0.71405226 ],
    "fork_6": [ 0.115196079, 0.133611143, 0.676470637, 0.6993464 ],
    "fork_7": [ 0.164215669, 0.31008172, 0.767156839, 0.410130739 ],
    "fork_8": [ 0.118872553, 0.318251669, 0.817401946, 0.225490168 ],
    "fork_9": [ 0.18259804, 0.2136765, 0.6335784, 0.643790841 ],
    "fork_10": [ 0.05269608, 0.282303959, 0.8088235, 0.452614367 ],
    "fork_11": [ 0.05759804, 0.0894935, 0.9007353, 0.3251634 ],
    "fork_12": [ 0.3345588, 0.07315363, 0.375, 0.9150327 ],
    "fork_13": [ 0.269607842, 0.194068655, 0.4093137, 0.6732026 ],
    "fork_14": [ 0.143382356, 0.218578458, 0.7977941, 0.295751631 ],
    "fork_15": [ 0.19240196, 0.0633497, 0.5710784, 0.8398692 ],
    "fork_16": [ 0.140931368, 0.480016381, 0.6838235, 0.240196079 ],
    "fork_17": [ 0.305147052, 0.2512582, 0.4791667, 0.5408496 ],
    "fork_18": [ 0.234068632, 0.445702642, 0.6127451, 0.344771236 ],
    "fork_19": [ 0.219362751, 0.141781077, 0.5919118, 0.6683006 ],
    "fork_20": [ 0.180147052, 0.239820287, 0.6887255, 0.235294119 ]
}

scissors_image_regions = {
    "scissors_1": [ 0.4007353, 0.194068655, 0.259803921, 0.6617647 ],
    "scissors_2": [ 0.426470578, 0.185898721, 0.172794119, 0.5539216 ],
    "scissors_3": [ 0.289215684, 0.259428144, 0.403186262, 0.421568632 ],
    "scissors_4": [ 0.343137264, 0.105833367, 0.332107842, 0.8055556 ],
    "scissors_5": [ 0.3125, 0.09766343, 0.435049027, 0.71405226 ],
    "scissors_6": [ 0.379901975, 0.24308826, 0.32107842, 0.5718954 ],
    "scissors_7": [ 0.341911763, 0.20714055, 0.3137255, 0.6356209 ],
    "scissors_8": [ 0.231617644, 0.08459154, 0.504901946, 0.8480392 ],
    "scissors_9": [ 0.170343131, 0.332957536, 0.767156839, 0.403594762 ],
    "scissors_10": [ 0.204656869, 0.120539248, 0.5245098, 0.743464053 ],
    "scissors_11": [ 0.05514706, 0.159754932, 0.799019635, 0.730392158 ],
    "scissors_12": [ 0.265931368, 0.169558853, 0.5061275, 0.606209159 ],
    "scissors_13": [ 0.241421565, 0.184264734, 0.448529422, 0.6830065 ],
    "scissors_14": [ 0.05759804, 0.05027781, 0.75, 0.882352948 ],
    "scissors_15": [ 0.191176474, 0.169558853, 0.6936275, 0.6748366 ],
    "scissors_16": [ 0.1004902, 0.279036, 0.6911765, 0.477124184 ],
    "scissors_17": [ 0.2720588, 0.131977156, 0.4987745, 0.6911765 ],
    "scissors_18": [ 0.180147052, 0.112369314, 0.6262255, 0.6666667 ],
    "scissors_19": [ 0.333333343, 0.0274019931, 0.443627447, 0.852941155 ],
    "scissors_20": [ 0.158088237, 0.04047389, 0.6691176, 0.843137264 ]
}

メモ

領域の座標をマークするクリック アンド ドラッグ ユーティリティがない場合は、 Customvision.ai で Web UI を使用できます。 この例では、座標は既に指定されています。

次に、この関連付けのマップを使用して、各サンプル 画像とその領域座標をアップロードします (1 回のバッチで最大 64 個の画像をアップロードできます)。 次のコードを追加します。

base_image_location = os.path.join (os.path.dirname(__file__), "Images")

# Go through the data table above and create the images
print ("Adding images...")
tagged_images_with_regions = []

for file_name in fork_image_regions.keys():
    x,y,w,h = fork_image_regions[file_name]
    regions = [ Region(tag_id=fork_tag.id, left=x,top=y,width=w,height=h) ]

    with open(os.path.join (base_image_location, "fork", file_name + ".jpg"), mode="rb") as image_contents:
        tagged_images_with_regions.append(ImageFileCreateEntry(name=file_name, contents=image_contents.read(), regions=regions))

for file_name in scissors_image_regions.keys():
    x,y,w,h = scissors_image_regions[file_name]
    regions = [ Region(tag_id=scissors_tag.id, left=x,top=y,width=w,height=h) ]

    with open(os.path.join (base_image_location, "scissors", file_name + ".jpg"), mode="rb") as image_contents:
        tagged_images_with_regions.append(ImageFileCreateEntry(name=file_name, contents=image_contents.read(), regions=regions))

upload_result = trainer.create_images_from_files(project.id, ImageFileCreateBatch(images=tagged_images_with_regions))
if not upload_result.is_batch_successful:
    print("Image batch upload failed.")
    for image in upload_result.images:
        print("Image status: ", image.status)
    exit(-1)

メモ

先ほど Foundry Tools Python SDK Samples リポジトリをダウンロードした場所に基づいて、イメージへのパスを変更する必要があります。

プロジェクトをトレーニングする

このコードは、予測モデルの最初のイテレーションを作成します。

print ("Training...")
iteration = trainer.train_project(project.id)
while (iteration.status != "Completed"):
    iteration = trainer.get_iteration(project.id, iteration.id)
    print ("Training status: " + iteration.status)
    time.sleep(1)

ヒント

選択したタグを使用してトレーニングする

必要に応じて、適用されたタグのサブセットのみをトレーニングできます。 特定のタグをまだ十分に適用していないが、他のタグが十分にある場合は、これを行うことができます。 train_project呼び出しで、省略可能なパラメーター selected_tagsを、使用するタグの ID 文字列の一覧に設定します。 モデルは、そのリストのタグのみを認識するようにトレーニングします。

現在のイテレーションを発行する

イテレーションは、発行されるまで予測エンドポイントで利用できません。 次のコードでは、モデルの現在のイテレーションをクエリに使用できるようにします。

# The iteration is now trained. Publish it to the project endpoint
trainer.publish_iteration(project.id, iteration.id, publish_iteration_name, prediction_resource_id)
print ("Done!")

予測エンドポイントをテストする

画像を予測エンドポイントに送信して予測を取得するには、ファイルの末尾に次のコードを追加します。

# Now there is a trained endpoint that can be used to make a prediction

# Open the sample image and get back the prediction results.
with open(os.path.join (base_image_location, "test", "test_image.jpg"), mode="rb") as test_data:
    results = predictor.detect_image(project.id, publish_iteration_name, test_data)

# Display the results.    
for prediction in results.predictions:
    print("\t" + prediction.tag_name + ": {0:.2f}% bbox.left = {1:.2f}, bbox.top = {2:.2f}, bbox.width = {3:.2f}, bbox.height = {4:.2f}".format(prediction.probability * 100, prediction.bounding_box.left, prediction.bounding_box.top, prediction.bounding_box.width, prediction.bounding_box.height))

アプリケーションを実行する

CustomVisionQuickstart.py を実行 します

python CustomVisionQuickstart.py

アプリケーションの出力がコンソールに表示されます。 その後、( <base_image_location>/images/Test で見つかった) テスト イメージが適切にタグ付けされていること、および検出の領域が正しいことを確認できます。 Custom Vision Web サイトに戻り、新しく作成したプロジェクトの現在の状態を確認することもできます。

リソースのクリーンアップ

独自の物体検出プロジェクトを実装する (または 画像分類 プロジェクトを試す) 場合は、この例からフォーク/ハサミ検出プロジェクトを削除できます。 無料サブスクリプションでは、2 つの Custom Vision プロジェクトを利用できます。

Custom Vision Web サイトで、Projects に移動し、[マイ ニュー Project] の下にあるごみ箱を選択します。

ごみ箱アイコンが付いた [新しいProject] というラベルのパネルのスクリーンショット。

次の手順

これで、オブジェクト検出プロセスのすべての手順をコードで行いました。 このサンプルでは 1 回のトレーニング イテレーションを実行しますが、多くの場合、モデルをより正確にするために、モデルを複数回トレーニングしてテストする必要があります。 次のガイドでは画像分類について説明しますが、その原則は物体検出に似ています。