統計的機械学習

乳癌の腫瘍に関する調査データセットを用いて、機械学習を行う例を示す。このデータセットは悪性腫瘍(malignant)と良性腫瘍(benign)の細胞の特徴についての調査データである。それぞれの腫瘍部分の半径、テクスチャ、面積、凹みなどの 30 個の特徴が数値化されて記録されている。この 30 個の特徴量を使って、その細胞が悪性腫瘍なのか、それとも良性腫瘍なのかを予測するモデルを作成する。

In [0]:
from sklearn import datasets
from sklearn import model_selection
from sklearn import preprocessing
from sklearn import svm

# 腫瘍データの取得
# 本来は CSV ファイルから読み取るが、ここでは Python / scikit-learn パッケージに保存されているデータを取り出して使用する。
cancer = datasets.load_breast_cancer()


# 特徴量の構造を出力
X = cancer.data
print('X shape is:')
print(X.shape)
print('----------------------')


# 教師ラベル(悪性か良性かの情報)を出力
y = cancer.target
print('y shape is: ')
print(y.shape)
print('----------------------')


# このデータセットには 569 サンプルが含まれている
# これらのサンプルからランダムに 40% 取り出してテストデータ(モデル検証用)として取っておく
# 残りの 60% を使って学習データとして使用する
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size=0.4, stratify=y)


# 各特徴量に対して、平均 0 および分散 1 となるように標準化する
sc = preprocessing.StandardScaler() 
sc.fit(X_train)
X_train_std = sc.transform(X_train) 
X_test_std = sc.transform(X_test)


# 30 個の特徴量があるが、すべての特徴量が良性腫瘍・悪性腫瘍を分類するのに適しているとは限らない
# そのため、本来は、モデルの複雑度を下げるために、ここでは特徴量選択したり、PCA などで次元削減したりする
# 今日は、このステップを省略する


# SVM アルゴリズムに学習データを与えて学習させる
svm = svm.SVC(kernel='rbf', C=0.1, gamma=0.001)
svm.fit(X_train_std, y_train)


# テストデータの特徴量を与えて、学習済みモデルを使って予測させてみる
predicted_label = svm.predict(X_test_std)


# 予測されたラベルとテストデータの(真の)ラベル比べて、正しく予測できたサンプルの割合(精度)を計算する
n_true_positive = (y_test == predicted_label)
acc = sum(n_true_positive == True) / len(n_true_positive)
print(acc)
X shape is:
(569, 30)
----------------------
y shape is: 
(569,)
----------------------
0.6842105263157895

畳み込みニューラルネットワークによる物体認識

Google Colab のバックグラウンドは Linux である。この Linux 上で畳み込みニューラルネットワークを使って物体認識(画像分類)を行う例を示す。物体認識を行うための手順として、

  1. 環境構築;Linux 上に解析環境を構築する。Linux のディストリビューションおよびバージョンによって、インストールされているライブラリーの種類やバージョンが異なる。同じ時期に導入したコンピュータでも、アップデートの有無で異なる構成になったりする。また、使用するプログラミング言語のバージョンやライブラリーも様々に存在する。ライブラリーについては、インストールする時間によってバージョンが少し変化する場合もある。そのため、環境構築は非常に煩雑な作業である。一回覚えれば十分というような標準手法がなく、何回か環境構築を経験して慣れる必要がある。
  2. データ準備;データを整理し、機械が扱いやすいように命名したり、あるいは特定のフォルダに保存したりする。
  3. 画像解析;実際の畳み込みニューラルネットワークを構築して学習を行ってみる。この際に、様々なハイパーパラメーターを調整して、予測精度を高める。

環境設定

深層学習に使ういくつかのパッケージをインストールする。パッケージのインストールは、Python コードで行うのではなく、Linux コマンドで行うので、ここでコードの前に「!」を付けて、コマンドを実行する。

In [0]:
!pip install matplotlib
!pip install opencv-python
!pip install tensorflow-gpu
!pip install keras
Requirement already satisfied: matplotlib in /usr/local/lib/python3.6/dist-packages (3.0.3)
Requirement already satisfied: python-dateutil>=2.1 in /usr/local/lib/python3.6/dist-packages (from matplotlib) (2.5.3)
Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.6/dist-packages (from matplotlib) (1.1.0)
Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.6/dist-packages (from matplotlib) (0.10.0)
Requirement already satisfied: numpy>=1.10.0 in /usr/local/lib/python3.6/dist-packages (from matplotlib) (1.16.4)
Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/local/lib/python3.6/dist-packages (from matplotlib) (2.4.0)
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.6/dist-packages (from python-dateutil>=2.1->matplotlib) (1.12.0)
Requirement already satisfied: setuptools in /usr/local/lib/python3.6/dist-packages (from kiwisolver>=1.0.1->matplotlib) (41.0.1)
Requirement already satisfied: opencv-python in /usr/local/lib/python3.6/dist-packages (3.4.5.20)
Requirement already satisfied: numpy>=1.11.3 in /usr/local/lib/python3.6/dist-packages (from opencv-python) (1.16.4)
Collecting tensorflow-gpu
  Downloading https://files.pythonhosted.org/packages/76/04/43153bfdfcf6c9a4c38ecdb971ca9a75b9a791bb69a764d652c359aca504/tensorflow_gpu-1.14.0-cp36-cp36m-manylinux1_x86_64.whl (377.0MB)
     |████████████████████████████████| 377.0MB 84kB/s 
Requirement already satisfied: wrapt>=1.11.1 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu) (1.11.2)
Requirement already satisfied: astor>=0.6.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu) (0.8.0)
Requirement already satisfied: protobuf>=3.6.1 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu) (3.7.1)
Requirement already satisfied: google-pasta>=0.1.6 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu) (0.1.7)
Requirement already satisfied: keras-preprocessing>=1.0.5 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu) (1.1.0)
Requirement already satisfied: tensorflow-estimator<1.15.0rc0,>=1.14.0rc0 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu) (1.14.0)
Requirement already satisfied: absl-py>=0.7.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu) (0.7.1)
Requirement already satisfied: keras-applications>=1.0.6 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu) (1.0.8)
Requirement already satisfied: gast>=0.2.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu) (0.2.2)
Requirement already satisfied: six>=1.10.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu) (1.12.0)
Requirement already satisfied: termcolor>=1.1.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu) (1.1.0)
Requirement already satisfied: grpcio>=1.8.6 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu) (1.15.0)
Requirement already satisfied: wheel>=0.26 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu) (0.33.4)
Requirement already satisfied: numpy<2.0,>=1.14.5 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu) (1.16.4)
Requirement already satisfied: tensorboard<1.15.0,>=1.14.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu) (1.14.0)
Requirement already satisfied: setuptools in /usr/local/lib/python3.6/dist-packages (from protobuf>=3.6.1->tensorflow-gpu) (41.0.1)
Requirement already satisfied: h5py in /usr/local/lib/python3.6/dist-packages (from keras-applications>=1.0.6->tensorflow-gpu) (2.8.0)
Requirement already satisfied: markdown>=2.6.8 in /usr/local/lib/python3.6/dist-packages (from tensorboard<1.15.0,>=1.14.0->tensorflow-gpu) (3.1.1)
Requirement already satisfied: werkzeug>=0.11.15 in /usr/local/lib/python3.6/dist-packages (from tensorboard<1.15.0,>=1.14.0->tensorflow-gpu) (0.15.5)
Installing collected packages: tensorflow-gpu
Successfully installed tensorflow-gpu-1.14.0
Requirement already satisfied: keras in /usr/local/lib/python3.6/dist-packages (2.2.4)
Requirement already satisfied: h5py in /usr/local/lib/python3.6/dist-packages (from keras) (2.8.0)
Requirement already satisfied: keras-applications>=1.0.6 in /usr/local/lib/python3.6/dist-packages (from keras) (1.0.8)
Requirement already satisfied: scipy>=0.14 in /usr/local/lib/python3.6/dist-packages (from keras) (1.3.0)
Requirement already satisfied: six>=1.9.0 in /usr/local/lib/python3.6/dist-packages (from keras) (1.12.0)
Requirement already satisfied: keras-preprocessing>=1.0.5 in /usr/local/lib/python3.6/dist-packages (from keras) (1.1.0)
Requirement already satisfied: numpy>=1.9.1 in /usr/local/lib/python3.6/dist-packages (from keras) (1.16.4)
Requirement already satisfied: pyyaml in /usr/local/lib/python3.6/dist-packages (from keras) (3.13)

データ整理

Google Drive 上のデータを使えるようにする。(USB メモリをパソコンに差し込んで、パソコンから USB にアクセスできるようにするほぼ同じイメージ。)次にデータセットは、アーカイブ化されているので、これを展開して使えるようにする。Google Colab を使わない方はこちらのリンクよりダウンロードしてください。

In [0]:
from google.colab import drive
drive.mount('/content/drive')
Enter your authorization code: ·········· Mounted at /content/drive
In [0]:
!mkdir drive/My\ Drive/lec3
!wget "https://drive.google.com/uc?export=download&id=" -O drive/My\ Drive/lec3/dataset.tar
!tar xvf drive/My\ Drive/lec3/dataset.tar -C drive/My\ Drive/lec3/
mkdir: cannot create directory ‘drive/My Drive/lec3’: File exists
--2019-07-31 02:43:42--  https://drive.google.com/uc?export=download&id=17_93Aw3_Ongl97NCubqn-sl1gahn9klL
Resolving drive.google.com (drive.google.com)... 74.125.201.100, 74.125.201.101, 74.125.201.113, ...
Connecting to drive.google.com (drive.google.com)|74.125.201.100|:443... connected.
HTTP request sent, awaiting response... ^C
In [0]:
dataset_path = 'drive/My Drive/lec3/dataset'
import glob
print(glob.glob(dataset_path + '/*'))
['drive/My Drive/lec3/dataset/test', 'drive/My Drive/lec3/dataset/train']

物体認識(自作 CNN)

畳み込み層、プーリング層、畳み込み層、プーリング層、全結合層、全結合層、全結合層(出力層)の 7 層のアーキテクチャーを構築して、馬・牛・パンダの画像を学習させて、3 クラス分類をやらせてみる。

In [0]:
import os
import sys
import glob
import numpy as np
import keras
import cv2



class BatchGenerator(keras.utils.Sequence):

    def __init__(self, image_path, label, image_shape=(299, 299, 3), batch_size=16):

        self.x = image_path
        self.y = label
        self.length = len(image_path)

        self.batch_size = batch_size
        self.image_shape = image_shape
        self.batches_per_epoch = int((self.length - 1) / batch_size) + 1


    def __getitem__(self, idx):

        batch_from = self.batch_size * idx
        batch_to   = batch_from + self.batch_size

        if batch_to > self.length:
            batch_to = self.length

        x_batch = []
        y_batch = []
        for i in range(batch_from, batch_to):
            img = cv2.imread(self.x[i], cv2.IMREAD_COLOR)
            img = cv2.resize(img, image_shape[:2])
            x_batch.append(img)
            y_batch.append(self.y[i])
        x_batch = np.asarray(x_batch).astype('float32') / 255
        y_batch = np.asarray(y_batch)

        return x_batch, y_batch



    def __len__(self):
        return self.batches_per_epoch


    def on_epoch_end(self):
        pass
      
      
      


      

image_shape = (200, 200, 3)
batch_size = 20

class_labels = {'horse': 0, 'ox': 1, 'panda': 2}


# prepare train and test data sets
x_train = []
y_train = []
for img_path in sorted(glob.glob(dataset_path + '/train/*/*.csv')):
  x_train.append(img_path)
  y_train.append(class_labels[os.path.basename(os.path.dirname(img_path))])
y_train = keras.utils.np_utils.to_categorical(y_train, num_classes=len(class_labels))
train_batch_generator = BatchGenerator(x_train, y_train, image_shape, batch_size)


# create an original model
model = keras.models.Sequential()
model.add(keras.layers.Conv2D(64, kernel_size=(7, 7), activation='relu',
                              input_shape = image_shape))
model.add(keras.layers.Conv2D(32, kernel_size=(5, 5), activation='relu'))
model.add(keras.layers.MaxPooling2D(pool_size=(2, 2)))
model.add(keras.layers.Conv2D(64, kernel_size=(3, 3), activation='relu'))
model.add(keras.layers.MaxPooling2D(pool_size=(2, 2)))  
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(128, activation='relu'))
model.add(keras.layers.Dropout(rate=0.5))
model.add(keras.layers.Dense(64, activation='relu'))
model.add(keras.layers.Dense(len(class_labels), activation='softmax'))

model.compile(loss='categorical_crossentropy',
              optimizer=keras.optimizers.RMSprop(lr=0.00001),
              metrics=['accuracy'])


# start training
fit_history = model.fit_generator(train_batch_generator, epochs=20,
                                  verbose=1, shuffle=True)



#final_model_path = 'drive/My Drive/lec3/my_cnn_final_model.h5'
#model.save(final_model_path)
Epoch 1/20
30/30 [==============================] - 4s 141ms/step - loss: 1.1591 - acc: 0.2534
Epoch 2/20
30/30 [==============================] - 4s 140ms/step - loss: 1.1146 - acc: 0.2803
Epoch 3/20
30/30 [==============================] - 4s 141ms/step - loss: 1.1096 - acc: 0.2756
Epoch 4/20
30/30 [==============================] - 4s 141ms/step - loss: 1.1059 - acc: 0.2850
Epoch 5/20
30/30 [==============================] - 4s 140ms/step - loss: 1.0916 - acc: 0.3798
Epoch 6/20
30/30 [==============================] - 4s 138ms/step - loss: 1.1135 - acc: 0.3507
Epoch 7/20
30/30 [==============================] - 4s 142ms/step - loss: 1.0981 - acc: 0.3462
Epoch 8/20
30/30 [==============================] - 4s 139ms/step - loss: 1.0894 - acc: 0.3851
Epoch 9/20
30/30 [==============================] - 4s 138ms/step - loss: 1.0803 - acc: 0.4232
Epoch 10/20
30/30 [==============================] - 4s 142ms/step - loss: 1.0851 - acc: 0.3960
Epoch 11/20
30/30 [==============================] - 4s 141ms/step - loss: 1.0748 - acc: 0.4268
Epoch 12/20
30/30 [==============================] - 4s 139ms/step - loss: 1.0596 - acc: 0.4691
Epoch 13/20
30/30 [==============================] - 4s 138ms/step - loss: 1.0582 - acc: 0.4354
Epoch 14/20
30/30 [==============================] - 4s 139ms/step - loss: 1.0285 - acc: 0.4996
Epoch 15/20
30/30 [==============================] - 4s 139ms/step - loss: 1.0336 - acc: 0.5004
Epoch 16/20
30/30 [==============================] - 4s 140ms/step - loss: 1.0186 - acc: 0.4985
Epoch 17/20
30/30 [==============================] - 4s 140ms/step - loss: 1.0060 - acc: 0.5374
Epoch 18/20
30/30 [==============================] - 4s 141ms/step - loss: 0.9780 - acc: 0.5621
Epoch 19/20
30/30 [==============================] - 4s 137ms/step - loss: 0.9974 - acc: 0.5182
Epoch 20/20
30/30 [==============================] - 4s 141ms/step - loss: 0.9905 - acc: 0.5379

学習に使われていない 5 枚の写真を使って、予測精度を確認する。

In [0]:
import matplotlib.pyplot as plt
%matplotlib inline 

test_image = dataset_path + '/test/001.jpg'
img = cv2.imread(test_image, cv2.IMREAD_COLOR)

plt.figure()
plt.imshow(img)
plt.show()


x = np.asarray([cv2.resize(img, (200, 200))])
x = x.astype('float32') / 255.0
print(np.round(model.predict(x), 2))
[[0.28 0.4  0.32]]
In [0]:
test_image = dataset_path + '/test/002.jpg'
img = cv2.imread(test_image, cv2.IMREAD_COLOR)
plt.figure()
plt.imshow(img)
plt.show()
x = np.asarray([cv2.resize(img, (200, 200))])
x = x.astype('float32') / 255.0
print(np.round(model.predict(x), 2))
[[0.29 0.28 0.43]]
In [0]:
test_image = dataset_path + '/test/003.jpg'
img = cv2.imread(test_image, cv2.IMREAD_COLOR)
plt.figure()
plt.imshow(img)
plt.show()
x = np.asarray([cv2.resize(img, (200, 200))])
x = x.astype('float32') / 255.0
print(np.round(model.predict(x), 2))
[[0.19 0.38 0.42]]
In [0]:
test_image = dataset_path + '/test/004.jpg'
img = cv2.imread(test_image, cv2.IMREAD_COLOR)
plt.figure()
plt.imshow(img)
plt.show()
x = np.asarray([cv2.resize(img, (200, 200))])
x = x.astype('float32') / 255.0
print(np.round(model.predict(x), 2))