畳み込みとプーリングの実行

1. 始める前に

この Codelab では、畳み込みと、コンピュータ ビジョンのシナリオにおける畳み込みが非常に強力な理由について学びます。

前の Codelab では、ファッション アイテムのためのコンピュータ ビジョン用のシンプルなディープ ニューラル ネットワーク(DNN)を作成しました。これは、衣類が写真内の唯一の要素であることと、中央に配置する必要があることから制限されていました。

もちろん、これは現実的なシナリオではありません。DNN は、他の物と一緒に、または正面と中央に配置されていない写真内の衣類を識別できるようにします。これを行うには、畳み込みを使用する必要があります。

前提条件

この Codelab は、「こんにちは、World of Machine Learning の紹介」「コンピュータ ビジョン モデルの構築」の 2 回にわたる作業に基づいています。続行するには、これらの Codelab を完了してください。

ラボの内容

  • 畳み込みとは
  • フィーチャー マップの作成方法
  • プーリングとは

作成するアプリの概要

  • 画像のフィーチャー マップ

必要なもの

Colab で実行する Codelab の残りの部分のコードを確認できます。

TensorFlow と前の Codelab でインストールしたライブラリも必要です。

2. 畳み込みとは

畳み込みとは、画像を通過して処理し、重要な特徴を抽出するフィルタのことです。

たとえば、スニーカーを身に着けている人物の画像があるとします。スニーカーが画像に含まれていることを検出するには、どうすればよいでしょうか。プログラムでスニーカーとして画像を表示するには、重要な特徴を抽出し、不要な特徴をぼかす必要があります。これを「特徴マッピング」と呼びます。

特徴マッピング プロセスは理論的には簡単です。画像内のすべてのピクセルをスキャンしてから、隣接するピクセルを確認します。それらのピクセルの値にフィルタ内の同等の重みを掛けます。

次に例を示します。

画像の畳み込み

この場合、3x3 畳み込み行列(画像カーネル)を指定します。

現在のピクセル値は 192 です。新しいピクセルの値を計算するには、隣の値のフィルタに指定された値を掛けて、新しいピクセル値を最終的な値にします。

次は、2D グレースケール画像の基本的な畳み込みを作成することにより、畳み込みの仕組みを見てみましょう。

それを SciPy の昇順画像で示します。さまざまな角度と線で彩られた美しい写真です。

3. コーディングを開始する

まず、いくつかの Python ライブラリと Ascent 画像をインポートします。

import cv2
import numpy as np
from scipy import misc
i = misc.ascent()

次に、Pyplot ライブラリ matplotlib を使用して、画像を描画します。

import matplotlib.pyplot as plt
plt.grid(False)
plt.gray()
plt.axis('off')
plt.imshow(i)
plt.show()

edb460dd5397f7f4.png

ご覧のとおり、これは階段の画像です。さまざまな機能を分離して試すことができます。たとえば、強い縦線などがあります。

画像は NumPy 配列として保存されるため、その配列をコピーするだけで変換後の画像を作成できます。size_x 変数と size_y 変数は、画像のサイズを保持するため、後でループさせることができます。

i_transformed = np.copy(i)
size_x = i_transformed.shape[0]
size_y = i_transformed.shape[1]

4. 畳み込み行列を作成する

まず、3x3 配列として畳み込み行列(またはカーネル)を作成します。

# This filter detects edges nicely
# It creates a filter that only passes through sharp edges and straight lines. 
# Experiment with different values for fun effects.
#filter = [ [0, 1, 0], [1, -4, 1], [0, 1, 0]] 
# A couple more filters to try for fun!
filter = [ [-1, -2, -1], [0, 0, 0], [1, 2, 1]]
#filter = [ [-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]
 # If all the digits in the filter don't add up to 0 or 1, you 
# should probably do a weight to get it to do so
# so, for example, if your weights are 1,1,1 1,2,1 1,1,1
# They add up to 10, so you would set a weight of .1 if you want to normalize them
weight  = 1

出力ピクセルを計算します。画像を反復処理して 1 ピクセルの余白を残し、現在のピクセルの各ネイバーにフィルタで定義された値を掛けます。

つまり、すぐ上、その左にある現在のピクセルの隣に、フィルタの左上の項目が乗算されます。次に、結果に重みを掛けて、0 ~ 255 の範囲であることを確認します。

最後に、変換後の画像に新しい値を読み込みます。

for x in range(1,size_x-1):
  for y in range(1,size_y-1):
      output_pixel = 0.0
      output_pixel = output_pixel + (i[x - 1, y-1] * filter[0][0])
      output_pixel = output_pixel + (i[x, y-1] * filter[0][1])
      output_pixel = output_pixel + (i[x + 1, y-1] * filter[0][2])
      output_pixel = output_pixel + (i[x-1, y] * filter[1][0])
      output_pixel = output_pixel + (i[x, y] * filter[1][1])
      output_pixel = output_pixel + (i[x+1, y] * filter[1][2])
      output_pixel = output_pixel + (i[x-1, y+1] * filter[2][0])
      output_pixel = output_pixel + (i[x, y+1] * filter[2][1])
      output_pixel = output_pixel + (i[x+1, y+1] * filter[2][2])
      output_pixel = output_pixel * weight
      if(output_pixel<0):
        output_pixel=0
      if(output_pixel>255):
        output_pixel=255
      i_transformed[x, y] = output_pixel

5. 結果を確認する

次は、画像をプロットして、そのフィルタを通過した場合の影響を確認します。

# Plot the image. Note the size of the axes -- they are 512 by 512
plt.gray()
plt.grid(False)
plt.imshow(i_transformed)
#plt.axis('off')
plt.show()   

48ff667b2df812ad.png

次のフィルタの値と、画像への影響を考慮してください。

[-1,0,1,-2,0,2,-1,0,1] を使用すると、非常に強力な縦線のセットが得られます。

縦線フィルタの検出

[-1,-2,-1,0,0,0,1,2,1] を使用すると、次の水平方向の線になります。

横線の検出

さまざまな価値をご確認ください。また、5x5、7x7 などのサイズの異なるフィルタを使用します。

6. プーリングについて

画像の基本的な特徴を特定したら、次は何をすればよいでしょうか。作成された特徴マップを使用して画像を分類するにはどうすればよいですか?

畳み込みと同様に、プールは特徴の検出に大いに役立ちます。レイヤをプールすると、検出された特徴を維持しながら、画像内の情報の総量を減らすことができます。

プーリングにはさまざまな種類がありますが、最大(最大)プーリングというものを使用します。

画像を反復処理し、各ポイントで、右、下、右の周辺にあるピクセルとそのすぐ隣の領域を検討します。その中の最大サイズ(つまり max プーリング)を取得して、新しいイメージに読み込みます。新しい画像は元のサイズの 4 分の 1 のサイズになります。最大プーリング

7. プール用のコードを記述する

次のコードは、(2, 2)プーリングを示しています。実行して出力を確認します。

画像は元のサイズの 1/4 ですが、すべての特徴が保持されています。

new_x = int(size_x/2)
new_y = int(size_y/2)
newImage = np.zeros((new_x, new_y))
for x in range(0, size_x, 2):
  for y in range(0, size_y, 2):
    pixels = []
    pixels.append(i_transformed[x, y])
    pixels.append(i_transformed[x+1, y])
    pixels.append(i_transformed[x, y+1])
    pixels.append(i_transformed[x+1, y+1])
    pixels.sort(reverse=True)
    newImage[int(x/2),int(y/2)] = pixels[0]
 
# Plot the image. Note the size of the axes -- now 256 pixels instead of 512
plt.gray()
plt.grid(False)
plt.imshow(newImage)
#plt.axis('off')
plt.show()

1f5ebdafd1db2595.png

プロットの軸に注意してください。画像は元のサイズの 4 分の 1 の 256x256 となり、検出されたデータは画像内のデータ量が減少しましたが、補正されました。

8. 完了

初めてのコンピュータ ビジョン モデルの作成コンピュータ ビジョン モデルをさらに強化する方法については、畳み込みニューラル ネットワーク(CNN)を構築してコンピュータ ビジョンを強化するをご覧ください。