SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

サーバーレスでAIシステム開発スタートダッシュ

AWSのServerless Inferenceを活用して、サーバーレスで学習から推論までを実装しよう

サーバーレスでAIシステム開発スタートダッシュ 第2回

  • X ポスト
  • このエントリーをはてなブックマークに追加

推論の実行

 次は、モデルを使って推論を行うコードを実装します。これには、最終的に推論コンテナ内で動作するコードを解説します。

1. モデルの読み込み

 まず、学習済みモデルはPyTorchライブラリを使用して読み込みます。

model = torch.load(model_path + "/best.pt")

 torch.load()はモデルを読み込むための関数です。学習結果の重みはbest.ptとして保存されているため、これを読み込みます。その際に、YOLOv5モデルの学習時にはmodelフォルダとutilフォルダも必要ですので、best.ptファイルと同じ階層に用意しておきます。この構造を保持しないと、モデルの読み込み時にエラーが発生しますので注意が必要です。

2. データの前処理

 次に、Pillowというライブラリを使用して、画像をモデルに入力する前の前処理を行います。画像はLINE Botからbase64形式でエンコードされて送られてくるため、それをデコードします。

# nparrayに変換
image = base64.b64decode(flask.request.data)
image = np.frombuffer(image, dtype="uint8")
image = cv2.imdecode(image, cv2.IMREAD_COLOR)
image = Image.fromarray(image)

 YOLOv5モデルは640サイズの画像を入力とするため、このサイズに変更し、元画像の縦横比を保つために余白を追加します。

# リサイズ、余白追加
image_padding = Image.new('RGB', [max(image.size)] * 2, (0, 0, 0))
image_padding.paste(image, (0, 0, image.width, image.height))
image_resized = image_padding.resize((640, 640), Image.ANTIALIAS)

 numpy配列に変換してからPyTorchのtensor型に変換します。

image = np.array(image_resized)
image = torch.from_numpy(image)

 数値を0~1の範囲に正規化します。

image = image.float()
image /= 255

 次の処理が特徴的で、モデルに入力するtensorのサイズを(1, 3, 640, 640)にリサイズします。通常、Pillowなどで読み込んだ際は(640, 640, 3)となっているので、これをモデルに入力できるよう整えていきます。

if len(image.shape) == 3:
    image = image[None]
image = torch.permute(image, (0, 3, 1, 2))

 これで前処理が完了しましたので、推論を実行してみましょう!

3. 推論の実行

 PyTorchで読み込んだモデルはディクショナリー型になっているため、以下のように使います。

pred = model['model'](image)

4. モデルの出力

 次に、推論結果がどのようになっているか確認しましょう。まず、得られた結果のサイズは以下のようになっています。

([[1, 25200, 6], [[1, 3, 80, 80, 6], [1, 3, 40, 40, 6], [1, 3, 20, 20, 6]]])

 このデータの中身は次のようになります。

[ 3.99102e-01,  5.78214e-01,  1.90415e+00, -5.36558e-01, -8.57918e+00,  1.00173e+01], …

 各6つの要素は次を表しています。

[center_x, center_y, width, height, 確度, 識別クラス係数]

 数値の並びから、xとy座標が画像の左上から右下に向かって少しずつずれていくのが分かります。これは画像内の25,200個のバウンディングボックスに対して、推論の確度が示されていることを意味しています。また、今回のモデルはナンバーだけを検知するもので、識別クラスは1つしかありませんが、複数の物体を検知するモデルだとそれに応じて要素数が増加します。つまり、これらのデータを適切に処理して、推論結果を導き出していく必要があります。

5. 推論結果の導出

 推論結果の導出にはNon-Maximum Suppression(NMS)という手法を使います。NMSの詳細な説明は省略しますが、複数のバウンディングボックスが重複している場合に、それを適切に処理して一つのバウンディングボックスとしてまとめる処理を行っています。このNMSの実装に関しては、YOLOv5のGitHubに掲載されているコードを参考にしました。

pred = non_max_suppression(pred)
print("処理後: ", pred)

処理後:  [tensor([[292.75226, 326.84778, 355.07587, 358.43054,   0.93183,   0.00000],
        [561.17792, 160.74695, 582.67120, 173.13055,   0.88415,   0.00000]])]

 NMSを適用した結果はこのような形になっています。これらの要素は以下の情報を表します。

[top_left_x, top_left_y, bottom_right_x, bottom_right_y, 確度, クラス]

 今回の例では、2つのナンバープレートが検知されました。これらを元に、検知したナンバープレートを黒で塗りつぶす処理を行います。

# ナンバー黒塗り
for det in pred[0]:
  det = det * scale_ratio
  image_original = np.array(image_original)
  cv2.rectangle(image_original, pt1=(int(det[0]), int(det[1])), pt2=(int(det[2]), int(det[3])), color=(0, 0, 0), thickness=-1)

 モデルへの入力画像は640x640でしたが、元画像のサイズに合わせてスケーリングを行っています。これでPythonコード上から推論を行う準備が整いました。次に、このモデルと処理をAWS環境にデプロイしていくことになります。

次のページ
推論コンテナの用意

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
サーバーレスでAIシステム開発スタートダッシュ連載記事一覧

もっと読む

この記事の著者

株式会社ブリューアス AI-TEAM(カブシキガイシャブリューアス エーアイチーム)

 モバイルのアプリを中心にUI/UXデザインから開発保守まで、幅広い実績を持つ会社です。専門的な知識と豊富な開発経験を活かし、AIとサービスの統合を推進しています。 Brewus.inc

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/18893 2024/01/25 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング