【IBM Cloud】Watson Visual Recognition

はじめに

本稿は、こちらの最後で述べた「別の道」です。最終的には1〜9までの数字を学習させて、ナンプレの問題から切り出した数字の画像を与えて、テキスト値の数値を得ることが目標です。

そのために、今回はIBMのWatsonを使ってみたいと思います。

大きな流れは次の通りです。

  1. サービスの作成
  2. チュートリアルの実施(curl)
  3. 実践(Python)

IBM Cloudのアカウントが必要ですが、その作成手順の掲載は割愛します。それ以外については、完全に一から環境を作っていく過程を掲載します。

アカウントについては、クレジットカード登録はしているが無料での実施を前提にします。

1.サービスの作成

まずはVisual Recognitionのサービスを作成する手順からです。

ログインするとダッシュボードが表示されていると思います。リソース・リストを表示ため、アイコンをクリックしてください。

利用しているリソース(サービス等)は全くなしの状態です。

メニューのアイコンをクリックしてください。

一番下にあるWatsonをクリックします。

Watsonサービスをクリックし展開、サービスの参照をクリックすると、右側のペインにサービスが一覧されるのでVisual Recognitionをクリックしてください。

ライトプランを選択し、サービス名を入力後、作成をクリックしてください。

無事に作成されると以下の画面が表示されているはずです。

2.チュートリアルの実施(curl)

curlコマンドおよび各種言語でのチュートリアルの最後あたりにその次のステップとして、カスタム・モデルの作成に関するガイドへの案内があります。

カスタム・モデルの作成とは、Watsonに初めから教え込まれているものではなく、我々が学習データを準備してWatsonを教育し、実際に判定が必要な画像をWatsonに問うという流れにおける、教育の部分を指しています。

要するに、我々が動物の写真をWatsonに与えたときに「ネコ」という解をもらうために、ネコ1、ネコ2、ネコ3、ネコ4とWatsonが特徴を捕らえられる程度にネコの写真を学習させる部分を指しています。

クリックした先は、以下のリンクです。

https://cloud.ibm.com/docs/services/visual-recognition?topic=visual-recognition-tutorial-custom-classifier&locale=ja#tutorial-custom-classifier

もし、このURLが変わっていたとしても、このあとご紹介するやり方の基本的な部分はWatsonのAPI自身が変わらない(バージョンアップしない)限りは変わりません。

チュートリアルでは、4つのzipファイルにビーグル、ハスキー、ゴールデン・レトリバー、ネコの4つの画像をzipファイルに纏めたモノが準備されています。

以下のリンクからダウンロードしてください。また、curlコマンドのコマンドラインをコピーボタンを使ってコピーしてください。

curl -X POST -u "apikey:{apikey}" \
--form "beagle_positive_examples=@beagle.zip" \
--form "husky_positive_examples=@husky.zip" \
--form "goldenretriever_positive_examples=@golden-retriever.zip" \
--form "negative_examples=@cats.zip" \
--form "name=dogs" \
"https://gateway.watsonplatform.net/visual-recognition/api/v3/classifiers?version=2018-03-19"

コピーしたコマンドラインは上記の通りです。この中で{apikey}の部分はご自身の値に差し替える必要があります。

APIキーは以下の通り、管理をクリックして、コピーボタンをクリックして手に入れてください。

実行

curl -X POST -u "apikey:*******" \
--form "beagle_positive_examples=@beagle.zip" \
--form "husky_positive_examples=@husky.zip" \
--form "goldenretriever_positive_examples=@golden-retriever.zip" \
--form "negative_examples=@cats.zip" \
--form "name=dogs" \
"https://gateway.watsonplatform.net/visual-recognition/api/v3/classifiers?version=2018-03-19"

実行した結果がJSONで返ってきます。

結果を見るとhusky, goldenretriever, beagleというクラスが出来ているようです。この名前がどこから付いているかというと、

正例のファイル名には、サフィックス _positive_examples が必要です。この例では、ファイル名は beagle_positive_examples、goldenretriever_positive_examples、および husky_positive_examples です。プレフィックス (beagle、goldenretriever、および husky) は、クラスの名前として返されます。

つまり以下の下線部分の通り、クラス名 + _positive_examples という形式を求められています。

結果の見るべき所としては、以下です。

使う時に必要となる分類器ID(classifier_id)と、そのステータス(status)です。ステータスがreadyとなるまで実際に判定させることが出来ません。

もしreadyとなっていないときに分類を指示すると、以下のように404エラーが返ってきます。

(numpre) MacBookPro:src $ sh curl_sample.sh
{
    "images": [
        {
            "image": "fruitbowl.jpg",
            "error": {
                "code": 404,
                "description": "No classifiers found"
            }
        }
    ],
    "images_processed": 1
}
(numpre) MacBookPro:src $

readyとなっているかどうかの確認は、以下のリクエストを送信します。

curl -X GET -u "apikey:{apikey}" \
"https://gateway.watsonplatform.net/visual-recognition/api/v3/classifiers/{classifier_id}?version=2018-03-19"

{classifier_id}をご自身の結果から差し替えて実行して下さい。

チュートリアルでは、このモデルを更新する(犬種を増やす)手順が解説されていますが、こちらでreadyになったことを確認したら判定を実行してみます。

判定させるのは以下の写真です。

写真は、以下からダウンロード可能です。

curl -X POST -u "apikey:{apikey}" \
--form "images_file=@dogs.jpg" \
--form "classifier_ids={classifier_id}" \
"https://gateway.watsonplatform.net/visual-recognition/api/v3/classify?version=2018-03-19"

{apikey}と{classifier_id}をご自身のモノに差し替えて実行してください。

ガイドにはclassifier_idsにdefaultも加わっていますが、説明がぼやけるので外しています。(defaultを指定するとこの手順で学習させたものではなく、あらかじめWatsonが学主旨ている内容に照らした結果も同時に返却してくれます)

今回の結果は、ビーグルであると判定したようです。(ちょっとどれがビーグルなのか疑問ですが…)

ということで、別のファイルを試して見ます。

明らかにゴールデン・レトリバーですね。

今度はゴールデン・レトリバーという結果を返してくれました。

さて、クラスの更新の仕方は、マニュアルを参照してください。基本的には作成同じで、重ねて実行すると更新になるというイメージです。

ここでは、モデルの削除方法へと進めたいと思います。

curl -X DELETE -u "apikey:{apikey}" \
"https://gateway.watsonplatform.net/visual-recognition/api/v3/classifiers/{classifier_id}?version=2018-03-19"

{apikey}と{classifier_id}をご自身のものに差し替えて実行してください。

無事に削除できたようです。

3.実践(Python)

さて、ここからが本稿のメインとなる部分です。

3.1 Pythonでサンプル実行

実践編といいながら、まずはチュートリアルに記載されているサンプルを動作させてみます。何事も順を追って実施していかないと、問題にぶち当たったときに、何が悪いのかが分からず迷子になりがちですからね。

Visual Recognitionのコンソールに戻ります。当サイトではPythonがテーマですのでPythonを選びます。

実施の前に必要なこととして、プロジェクト用の環境を用意した方が良いと思います。そのための手順としては、以下を参考にしてください。

本稿では「Macで環境構築」に従った環境において実施しています。

まずは、インストールします。

  pip install --upgrade watson-developer-cloud

判定する画像は以下です。

https://watson-developer-cloud.github.io/doc-tutorial-downloads/visual-recognition/640px-IBM_VGA_90X8941_on_PS55.jpg

ソースコードは以下です。

import json
from watson_developer_cloud import VisualRecognitionV3

visual_recognition = VisualRecognitionV3(
    '2018-03-19',
    iam_apikey='{apikey}')

url = 'https://watson-developer-cloud.github.io/doc-tutorial-downloads/visual-recognition/640px-IBM_VGA_90X8941_on_PS55.jpg'

classes_result = visual_recognition.classify(url=url).get_result()
print(json.dumps(classes_result, indent=2))

必要な修正箇所は{apikey}のみです。

実行します。

(numpre) MacBookPro:src $ python ibm_watson.py
ibm_watson.py:4: DeprecationWarning: watson-developer-cloud moved to ibm-watson. To get updates, use the new package.
  visual_recognition = VisualRecognitionV3(
{
  "images": [
    {
      "classifiers": [
        {
          "classifier_id": "default",
          "name": "default",
          "classes": [
            {
              "class": "circuit board",
              "score": 0.578,
              "type_hierarchy": "/electrical device/computer circuit/circuit board"
            },
            {
              "class": "computer circuit",
              "score": 0.755
            },
            {
              "class": "electrical device",
              "score": 0.757
            },
            {
              "class": "disk controller",
              "score": 0.553,
              "type_hierarchy": "/controller/disk controller"
            },
            {
              "class": "controller",
              "score": 0.558
            },
            {
              "class": "central processing unit",
              "score": 0.535
            },
            {
              "class": "PC board",
              "score": 0.501,
              "type_hierarchy": "/electrical device/computer circuit/PC board"
            },
            {
              "class": "CPU board",
              "score": 0.5,
              "type_hierarchy": "/electrical device/computer circuit/CPU board"
            },
            {
              "class": "electronic equipment",
              "score": 0.6
            },
            {
              "class": "memory device",
              "score": 0.599
            },
            {
              "class": "microchip",
              "score": 0.592
            },
            {
              "class": "jade green color",
              "score": 0.838
            },
            {
              "class": "emerald color",
              "score": 0.787
            }
          ]
        }
      ],
      "source_url": "https://watson-developer-cloud.github.io/doc-tutorial-downloads/visual-recognition/640px-IBM_VGA_90X8941_on_PS55.jpg",
      "resolved_url": "https://watson-developer-cloud.github.io/doc-tutorial-downloads/visual-recognition/640px-IBM_VGA_90X8941_on_PS55.jpg"
    }
  ],
  "images_processed": 1,
  "custom_classes": 0
}
(numpre) MacBookPro:src $

なにやらパッケージがDeprecationになっているとか警告が出ていますが、それはあとで対処するとして、ひとまず結果が返ってきたようなので一安心です。概ね画像を人が見て口にしそうなキーワードが返ってきていますね。

チュートリアルとしては、そのあと食品の例も出ていますが、ここでは割愛します。

3.2 実践編

いよいよホントの実践編です。参考にするのは以下のURLにるマニュアルの記載です。

https://cloud.ibm.com/apidocs/visual-recognition/visual-recognition-v3?locale=ja&code=python

右側のコードのペインでPythonを洗濯した状態です。

と、いいましたが、その前にDeprecationなのを解消しましょう。そうしないと、マニュアルにあるAPIの説明が活用できないからです。(全く困ったものです)

pipenv uninstall watson-developer-cloud
pipenv install "ibm-watson>=4.4.0"

そしてここからがホントのホントの実践です。

ここまでで、カスタム・モデルの作り方とPythonでのWatsonの呼び出し方を学んだ訳ですから、それを合体させたらやりたいことの完成のはずです。

新しいパッケージの使い方というか、必須のお膳立ては、マニュアルと見ると見えています。

このコードで必要な情報の{apikey}は、すでに承知の通りです。

次に{url}ですが、以下で手に入ります。

自分がどこでサービスを作ったか忘れてしまった人は、Watsonのコンソールで、詳細をクリックするとロケーションが確認できます。実際には管理である必要はなく他のメニューでも詳細はここにあると思います。

残った{version}ですが 2018-03-19 です。調べ方は以下の通りです。

使用するコードは、以下を元にします。コピーボタンを使ってコピーしてください。

ソースコードは以下のような感じです。

import json
from ibm_watson import VisualRecognitionV3
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator

APIKEY = "bjMFmTv229Fg3_C22Czdw8eLLfatA_T9gw6HoktJ52-M"
VERSION = "2018-03-19"
URL = "https://api.us-south.visual-recognition.watson.cloud.ibm.com"


authenticator = IAMAuthenticator(APIKEY)
visual_recognition = VisualRecognitionV3(
    version=VERSION,
    authenticator=authenticator
)

visual_recognition.set_service_url(URL)

with open('./watson/_1.zip', 'rb') as one, \
        open('./watson/_2.zip', 'rb') as two,  \
        open('./watson/_3.zip', 'rb') as three, \
        open('./watson/_4.zip', 'rb') as four, \
        open('./watson/_5.zip', 'rb') as five, \
        open('./watson/_6.zip', 'rb') as six, \
        open('./watson/_7.zip', 'rb') as seven, \
        open('./watson/_8.zip', 'rb') as eight, \
        open('./watson/_9.zip', 'rb') as nine, \
        open('./watson/_0.zip', 'rb') as zero:
    model = visual_recognition.create_classifier(
        'numbers',
        positive_examples={'one': one, 'two': two, 'three': three, 'four': four, 'five': five, 'six': six, 'seven': seven, 'eight': eight, 'nine': nine},
        negative_examples=zero
    ).get_result()

print(json.dumps(model, indent=2))

結果は以下の通りです。無事に作成できたようですね。ただし、statusはtrainingです。

さて、続いて作ったカスタム・クラスで分類させてみたいと思います。

マニュアルの以下からサンプルコードを手に入れます。

ソースコードです

import json
from ibm_watson import VisualRecognitionV3
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator

APIKEY = "bjMFmTv229Fg3_C22Czdw8eLLfatA_T9gw6HoktJ52-M"
VERSION = "2018-03-19"
URL = "https://api.us-south.visual-recognition.watson.cloud.ibm.com"


authenticator = IAMAuthenticator(APIKEY)
visual_recognition = VisualRecognitionV3(
    version=VERSION,
    authenticator=authenticator
)

visual_recognition.set_service_url(URL)


def test(filename):
    with open(filename, 'rb') as images_file:
        classes = visual_recognition.classify(
            images_file=images_file,
            threshold='0.6',
            classifier_ids=["numbers_1817165686"]).get_result()
        print(json.dumps(classes, indent=2))


test('./images/test/1out_sample.jpg')
test('./images/test/2out_sample.jpg')
test('./images/test/3out_sample.jpg')
test('./images/test/4out_sample.jpg')
test('./images/test/5out_sample.jpg')
test('./images/test/6out_sample.jpg')
test('./images/test/7out_sample.jpg')
test('./images/test/8out_sample.jpg')
test('./images/test/9out_sample.jpg')
test('./images/test/0out_sample.jpg')

実行してみます。

(numpre) MacBookPro:watson $ python ibm_watson_sample4.py
{
  "images": [
    {
      "classifiers": [
        {
          "classifier_id": "numbers_1817165686",
          "name": "numbers",
          "classes": [
            {
              "class": "one",
              "score": 0.93
            }
          ]
        }
      ],
      "image": "1out_sample.jpg"
    }
  ],
  "images_processed": 1,
  "custom_classes": 9
}
{
  "images": [
    {
      "classifiers": [
        {
          "classifier_id": "numbers_1817165686",
          "name": "numbers",
          "classes": [
            {
              "class": "two",
              "score": 0.914
            }
          ]
        }
      ],
      "image": "2out_sample.jpg"
    }
  ],
  "images_processed": 1,
  "custom_classes": 9
}
{
  "images": [
    {
      "classifiers": [
        {
          "classifier_id": "numbers_1817165686",
          "name": "numbers",
          "classes": [
            {
              "class": "three",
              "score": 0.926
            }
          ]
        }
      ],
      "image": "3out_sample.jpg"
    }
  ],
  "images_processed": 1,
  "custom_classes": 9
}
{
  "images": [
    {
      "classifiers": [
        {
          "classifier_id": "numbers_1817165686",
          "name": "numbers",
          "classes": [
            {
              "class": "four",
              "score": 0.93
            }
          ]
        }
      ],
      "image": "4out_sample.jpg"
    }
  ],
  "images_processed": 1,
  "custom_classes": 9
}
{
  "images": [
    {
      "classifiers": [
        {
          "classifier_id": "numbers_1817165686",
          "name": "numbers",
          "classes": [
            {
              "class": "five",
              "score": 0.909
            }
          ]
        }
      ],
      "image": "5out_sample.jpg"
    }
  ],
  "images_processed": 1,
  "custom_classes": 9
}
{
  "images": [
    {
      "classifiers": [
        {
          "classifier_id": "numbers_1817165686",
          "name": "numbers",
          "classes": [
            {
              "class": "six",
              "score": 0.927
            }
          ]
        }
      ],
      "image": "6out_sample.jpg"
    }
  ],
  "images_processed": 1,
  "custom_classes": 9
}
{
  "images": [
    {
      "classifiers": [
        {
          "classifier_id": "numbers_1817165686",
          "name": "numbers",
          "classes": [
            {
              "class": "seven",
              "score": 0.93
            }
          ]
        }
      ],
      "image": "7out_sample.jpg"
    }
  ],
  "images_processed": 1,
  "custom_classes": 9
}
{
  "images": [
    {
      "classifiers": [
        {
          "classifier_id": "numbers_1817165686",
          "name": "numbers",
          "classes": [
            {
              "class": "eight",
              "score": 0.925
            }
          ]
        }
      ],
      "image": "8out_sample.jpg"
    }
  ],
  "images_processed": 1,
  "custom_classes": 9
}
{
  "images": [
    {
      "classifiers": [
        {
          "classifier_id": "numbers_1817165686",
          "name": "numbers",
          "classes": [
            {
              "class": "nine",
              "score": 0.928
            }
          ]
        }
      ],
      "image": "9out_sample.jpg"
    }
  ],
  "images_processed": 1,
  "custom_classes": 9
}
{
  "images": [
    {
      "classifiers": [
        {
          "classifier_id": "numbers_1817165686",
          "name": "numbers",
          "classes": []
        }
      ],
      "image": "0out_sample.jpg"
    }
  ],
  "images_processed": 1,
  "custom_classes": 9
}
(numpre) MacBookPro:watson $

おっと、まさかの大成功じゃないですか。いったんこれ採用したいと思います。

もしも、ここで次のようなエラーに遭遇したら…

ERROR:root:Unknown error
Traceback (most recent call last):
  File "/Users/kazuto/git/numpre/lib/python3.8/site-packages/ibm_cloud_sdk_core/base_service.py", line 228, in send
    raise ApiException(
ibm_cloud_sdk_core.api_exception.ApiException: Error: Unknown error, Code: 404 , X-global-transaction-id: 93ac206c4f0eda4532b09186945ef193
Traceback (most recent call last):
  File "ibm_watson_sample3.py", line 37, in <module>
    classifiers = visual_recognition.list_classifiers(verbose=True).get_result()
  File "/Users/kazuto/git/numpre/lib/python3.8/site-packages/ibm_watson/visual_recognition_v3.py", line 313, in list_classifiers
    response = self.send(request)
  File "/Users/kazuto/git/numpre/lib/python3.8/site-packages/ibm_cloud_sdk_core/base_service.py", line 228, in send
    raise ApiException(
ibm_cloud_sdk_core.api_exception.ApiException: Error: Unknown error, Code: 404 , X-global-transaction-id: 93ac206c4f0eda4532b09186945ef193

それは、statusがreadyになっていない可能性が高いです。curlで実行した場合にはJSON内に“description”: “No classifiers found”と出ているのですぐに疑うべき所にたどり着けるのですが、Pythonで実行した場合には何故だかUnknow errorということで、余計な所を疑う危険性がありますのでお気を付け下さい。

statusの確認には、すでにご紹介しているcurlコマンドのほか、以下のPythonコードでも可能です。

classifiers = visual_recognition.list_classifiers(verbose=True).get_result()
print(json.dumps(classifiers, indent=2))

まとめ

IBM CloudのWatson Visual Recognitionを使ってみました。難しい事は考えずに、判定して欲しいものの画像を10以上用意してWatsonに学習させることで、新たに入手した画像が学習したものであるかどうかを判定してくれるというものでした。

Always Basics
ベテランコピペプログラマー。

コメントする

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です