[WIP]Custom Vision Services を使ってSDKで学習させてみた 

# だれ？

Microsoft Student Partners の くぅです。
Xamarin とか、 C# とかをいじってます。

# 何をしようとしたの？

Custom Vision Services を使って、欅坂46 のメンバーを学習させようとしました。
飲み会とかで欅坂46 のメンバーを見分けれないとか言ってるおっさんより頭がいい存在を作ってみたい
欅坂46 と一口に言っても、漢字欅とひらがなけやきに分かれていて、どうせなら、、、ということで両方学習させてみました。

# Cognitive Services, Custom Vision Service とは？

## Cognitive Services ってなに？

Cognitive Service とは、画像処理やテキスト処理などの自分でプログラムを作ると面倒なことを SDK を通して呼び出すだけで利用できるサービスです。機械学習が使われているらしく、自分で機械学習なコードを書かなくても使えます。いえい！( ˘ω˘ )

GUIから画像を学習させることもできますが、私は怠惰なので、プログラムを使い自動化しました。
（自動化させると、それはそれでいろいろ大変でしたが(;´･ω･)）

Cognitive Services にどんな種類のがあるかは、以下のリンクをご覧になるといいかなと思います。

[https://blogs.msdn.microsoft.com/bluesky/2016/05/06/microsoft-cognitive-services-api-overview/](https://blogs.msdn.microsoft.com/bluesky/2016/05/06/microsoft-cognitive-services-api-overview/)

##Custom Vision Service ってなに？

Build 2017 でCognitive Services で紹介された Cognitive Services の新しいサービスです。具体的には、以前からあった、 Computer Vision (画像の中にあるものやOCRなどの機能を提供しているサービス) を個人がカスタムできるようにしたバージョンといった感じです。

さらに言うと、自前で持っている学習データにタグ付けして学習させ、学習させたデータを利用してあとから投げ入れた画像にタグ付けをしてくれるサービスです。

公式サイトへのリンク:
[https://azure.microsoft.com/ja-jp/services/cognitive-services/custom-vision-service/](https://azure.microsoft.com/ja-jp/services/cognitive-services/custom-vision-service/)

# 学習データには何を使ったの？

Custom Vision Service は、現在プレビューのため？ 1000 枚までしか学習データを保存させることはできません、そのため、学習データを選別するときに量で殴れないので一定以上の質を担保しつつある程度の学習データ量はないといけないという大変な感じでした。

同じく、 Cognitive Service で提供されている Bing Image Search API を使って学習データを用意しました。
みんなよく使っている Bing 検索結果をAPIから利用できるようにしたものです。

公式サイトからデータを取得することも考えたのですが、情報量が少なすぎると判断しました。
また、同じく公式ブログから学習データを取得することも考えたのですが、情報の質（ほかの人が映っていたり、そもそもブログの記事の投稿主が移っていないため大変かなと考えました。）

欅坂46 はメンバー数が 32 人（脱退したメンバー含む）なので、一人あたり 31 枚の学習データを用意すればいい感じです。

# プログラム解説

## 作成したプログラムは Gist に置いてあります。

<script src="https://gist.github.com/fumiya-kume/de6d0d6ef5d14c77325791ac66859d05.js"></script>

[https://gist.github.com/fumiya-kume/de6d0d6ef5d14c77325791ac66859d05](https://gist.github.com/fumiya-kume/de6d0d6ef5d14c77325791ac66859d05)

Console Application + C# で作成しました。 
開発環境は、 Visual Studio 2017 です。

## 要点解説

### Custom Vision API を使うために必要なSDKのインスタンスを取得する関数

```csharp
 static TrainingApi GetCustomVisionClient(string CustomVisionSbscriotionKey)
{
    var TraningCredinental = new TrainingApiCredentials(CustomVisionSbscriotionKey);
    return new TrainingApi(TraningCredinental);
}
```

### Bing Image Search API の検索結果を返す関数

ヘッダにsubscriptionkeyをくっつけて、指定のURLにリクエストを投げるだけの簡単なお仕事です。
長濱ねるちゃんは可愛いので 取得する学習データの量をすこし多めにしてあります。
あとは、普通に レスポンスを Json からパースして、詰め替えて返しているだけです。

```csharp
 public static async Task<List<Member>> GetMemberInfoFromBingImageSeatchAsync(string MemberName, string BingSubscriotionKey)
        {
            var client = new HttpClient();

            // Request headers
            client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", BingSubscriotionKey);

            // 長濱ねるちゃんの時は、学習素材をちょっと多めに取得する
            var count = MemberName == "長濱ねる" ? 39 : 32;
            var uri = $"https://api.cognitive.microsoft.com/bing/v5.0/images/search?q={MemberName}&count={count}";

            var response = await client.GetAsync(uri);

            var responseText = await response.Content.ReadAsStringAsync();

            var BingImageURLList = JsonConvert.DeserializeObject<BingImageSearchObject>(responseText);
            var BingMemberList = BingImageURLList.value
                .Select(value => value.contentUrl)
                .Select(image => new Member() { Name = MemberName, ImageURL = image })
                .ToList();
            return BingMemberList;

        }
```

### Custom Vision Service に学習させているところ

一度に複数の画像を学習させることができるそうなので、すごい楽ができてます。時間当たりのリクエスト制限の壁を少しだけ突破しやすくなってます。

```csharp
 var TraningAPI = GetCustomVisionClient(CustomVisionSubscriptionKey);

                var Batch = new ImageUrlCreateBatch
                {
                    TagIds = GetTag(TraningAPI, MemberList.Where(member => member.Name == memberName).Select(memberInfo => memberInfo.Name).First()),
                    Urls = MemberList.Where(member => member.Name == memberName).Select(memberInfo => memberInfo.ImageURL).ToList()
                };
                TraningAPI.CreateImagesFromUrls(GetKEYAKIProjectID(TraningAPI), Batch);
```

# Custon Vision に学習させた 実行結果

## Custom Vison Service にて、学習させたデータを見ている写真

![無題.png](https://qiita-image-store.s3.amazonaws.com/0/143354/13a54168-32a2-2439-2e7e-7a61b33c400a.png)

## 学習させたデータを使い、 大正義長濱ねるちゃんでテストしてみました

![DBVPvn6UMAE1yeV.jpg-large.jpg](https://qiita-image-store.s3.amazonaws.com/0/143354/c62f5db8-d6d0-b0d5-7b5b-0e080847457a.jpeg)

# バッドノウハウ

## Bing Image Search API のサンプルのコードをコピペすると日本語で検索するとダメ

Bing Image Search API の[APIドキュメント](https://dev.cognitive.microsoft.com/docs/services/56b43eeccf5ff8098cef3807/operations/56b4447dcf5ff8098cef380d)のページには、丁寧に Sample Code がついていますが、検索ワードに日本語(ex, 長濱ねる)が入っていると実行に失敗します。

問題個所は、検索クエリを組み立てたいる場所です。
かわりに、手作業で丁寧に組み立ててあげてください

### Before

```csharp
var queryString = HttpUtility.ParseQueryString(string.Empty);

            // Request headers
            client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "{subscription key}");

            // Request parameters
            queryString["q"] = "bill gates";
            queryString["count"] = "10";
            queryString["offset"] = "0";
            queryString["mkt"] = "en-us";
            queryString["safesearch"] = "Moderate";
            var uri = "https://api.cognitive.microsoft.com/bing/v5.0/search?" + queryString;
```

### After

```csharp
 var uri = $"https://api.cognitive.microsoft.com/bing/v5.0/images/search?q={MemberName}&count={count}";
```

## １分間に 20回ぐらい、学習させるためのリクエストを投げるとHTTPリクエストに失敗する

解決方法としては、Task.Delay()的なのをかけるか、同じタグに紐づけたい画像はまとめて投げるければ比較的回避できます。
ただ、この壁を乗り越えても、学習データ最大 1000 枚の壁が存在

## 欅坂46 のメンバー全員を学習させると、 Bing Image Search API の無料枠を超過する

欅坂46 のメンバー先ほど述べた通り32 人です。

Bing Image Search API の無料枠での１秒当たりの最大アクセス数は、 10回までです。
ということで、４秒にわたりアクセスを行うか、金で殴るかの選択肢をとる必要があります。

![無題.png](https://qiita-image-store.s3.amazonaws.com/0/143354/ecbf92c8-b52c-460f-4920-b44cf0acaad4.png)