【機械学習】MNISTデータをCNNで分類【画像分類】

# 1.KaggleのDigit Recognizer Competitionのデータを借りて画像認識に挑戦。

https://www.kaggle.com/code/ngbolin/mnist-dataset-digit-recognizer/data

## 1.1.MNISTデータの取得
```python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns


#ファイルの読み込み
dftrain = pd.read_csv("train.csv")
dftest = pd.read_csv("test.csv")
print(dftrain.head())
dftrain.info()



########################      結果      ########################
   label  pixel0  pixel1  pixel2  pixel3  pixel4  pixel5  pixel6  pixel7  pixel8  pixel9  pixel10  ...  pixel772  pixel773  pixel774  pixel775  pixel776  pixel777  pixel778  pixel779  pixel780  pixel781  pixel782  pixel783
0      1       0       0       0       0       0       0       0       0       0       0        0  ...         0         0         0         0         0         0         0         0         0         0         0         0   
1      0       0       0       0       0       0       0       0       0       0       0        0  ...         0         0         0         0         0         0         0         0         0         0         0         0   
2      1       0       0       0       0       0       0       0       0       0       0        0  ...         0         0         0         0         0         0         0         0         0         0         0         0   
3      4       0       0       0       0       0       0       0       0       0       0        0  ...         0         0         0         0         0         0         0         0         0         0         0         0   
4      0       0       0       0       0       0       0       0       0       0       0        0  ...         0         0         0         0         0         0         0         0         0         0         0         0   

[5 rows x 785 columns]

RangeIndex: 42000 entries, 0 to 41999
Columns: 785 entries, label to pixel783
dtypes: int64(785)
```

## 1.2.トレーニングデータをY（ラベル、目的変数）とX（ピクセル、説明変数）に分ける
```python
ytrain = dftrain["label"]
xtrain = dftrain.drop(labels = ["label"],axis = 1) 
```

## 1.3.各数字の出現数を可視化
```python
sns.countplot(ytrain)
plt.title('Class Distribution')
plt.show()
```
![classdistribution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/c7847dc2-3b5b-654a-74ae-d18eae9c4764.png)


## 1.4.各数字の平均画像を可視化
平均画像：数字ごとにピクセルを全て合計して出現数で割った画像
```python
#数字の0、1、2、3、4、5、6、7、8、9の平均を計算して出力する
plt.figure(figsize=(4, 9))
for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:
    ytrain_i = dftrain[dftrain['label'] == i]
    xtrain_i = ytrain_i.drop(labels = ["label"],axis = 1) 

    #数字iの画像の平均を求める
    mxtrain_i = xtrain_i.mean()
    mxtrain_i = np.array(mxtrain_i)
    plt.subplot(5, 2, i+1)
    plt.xticks([])
    plt.yticks([])
    sns.despine(top=True, right=True, left=True, bottom=True)
    plt.imshow(mxtrain_i.reshape(28,28), cmap=plt.cm.binary)

plt.show()
```
![mean kind of numbers.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/8d44be59-937b-8a00-d753-ebd22950c420.png)

## 1.5.全部の画像の平均を可視化
```python
mxtrain = xtrain.mean()
mxtrain = np.array(mxtrain)
plt.xticks([])
plt.yticks([])
plt.imshow(mxtrain.reshape(28,28), cmap=plt.cm.binary)
plt.show()
```
![mean all numbers.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/ac335408-6ba7-3280-24a4-3d6a0711c159.png)

## 1.6."各数字の画像"と"全部の画像の平均"の差
```python
fig = plt.figure(figsize=(5, 10))
k=1
for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:
    ytrain_i = dftrain[dftrain['label'] == i]
    xtrain_i = ytrain_i.drop(labels = ["label"],axis = 1) 

    #5つのiの画像と全画像の平均の差を求める
    xtrain_i = xtrain_i.to_numpy()
    for j in range(5):
        diff_j = mxtrain - xtrain_i[j]
        fig.add_subplot(10, 5, k)
        plt.xticks([])
        plt.yticks([])
        sns.despine(top=True, right=True, left=True, bottom=True)
        plt.imshow(diff_j.reshape(28,28), cmap=plt.cm.binary)
        k += 1
plt.show()
```
![diff mean all number and kind of numbers.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/eee9463a-3ba4-34a4-2d3b-99ea42bab504.png)
<B>・明るいところほどピクセルが大きい。</B>
<B>・どこに強い特徴が存在するかの予想に使われる。</B>


# 2.CNNのモデルを作る
### ◎トレーニングデータ、テストデータの作成
```python
#トレーニングデータ、テストデータの作成
from sklearn.model_selection import train_test_split
from keras.utils.np_utils import to_categorical

ytrain = to_categorical(ytrain, num_classes = 10)
xtrain = xtrain.values.reshape(-1,28,28,1)

X_train, X_val, Y_train, Y_val = train_test_split(xtrain, ytrain, test_size = 0.15, random_state=2)
```

## 2.1.Seqentialモデルを作ってみるパート1！！！！！！
```python
# Seqentialモデルを作ってみる
import tensorflow as tf
import keras
from keras.models import Sequential
from keras.layers import Dense, Activation, Conv2D, MaxPooling2D, Flatten


model = Sequential()

model.add(Conv2D(filters = 32, kernel_size = (5,5),padding = 'Same', activation ='relu', input_shape = (28,28,1)))
model.add(Conv2D(filters = 32, kernel_size = (5,5),padding = 'Same', activation ='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))

model.add(Conv2D(filters = 64, kernel_size = (3,3),padding = 'Same', activation ='relu'))
model.add(Conv2D(filters = 64, kernel_size = (3,3),padding = 'Same', activation ='relu'))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))

model.add(Flatten())
model.add(Dense(256, activation = "relu"))
model.add(Dense(10, activation = "softmax"))
```

### 2.1.1RMSpropで最適化
```python
#RMSpropで最適化
from tensorflow import keras
from keras import optimizers

opt = keras.optimizers.RMSprop(lr=0.001, rho=0.9, epsilon=1e-08, decay=0.0)
model.compile(optimizer = opt, loss = "categorical_crossentropy", metrics=["accuracy"])
history = model.fit(X_train, Y_train, validation_split=0.25, epochs=30, batch_size=32, verbose=1)
```


### 2.1.2.元画像と2層目(Conv5×5×32)の出力結果を3個を可視化
```python
#学習済みモデルの1層目だけ取得してモデルを作成する
model_2 = Sequential()
model_2.add(model.layers[0])

fig = plt.figure(figsize=(4,8))
for i in range(10):
    ax = fig.add_subplot(10, 4, 4*i+1)
    ax.set_xticklabels([])
    ax.set_yticklabels([])
    ax.axis('off')
    ax.imshow(X_val[i][:, :, 0], cmap='gray')
    ax = fig.add_subplot(10, 4, 4*i+2)
    ax.set_xticklabels([])
    ax.set_yticklabels([])
    ax.axis('off')
    ax.imshow(model_2.predict(X_val[i:i+1])[0][:, :, 0], cmap='gray')
    ax = fig.add_subplot(10, 4, 4*i+3)
    ax.set_xticklabels([])
    ax.set_yticklabels([])
    ax.axis('off')
    ax.imshow(model_2.predict(X_val[i:i+1])[0][:, :, 1], cmap='gray')
    sns.despine(top=True, right=True, left=True, bottom=True)    
    ax = fig.add_subplot(10, 4, 4*i+4)
    ax.set_xticklabels([])
    ax.set_yticklabels([])
    ax.axis('off')
    ax.imshow(model_2.predict(X_val[i:i+1])[0][:, :, 2], cmap='gray')
    sns.despine(top=True, right=True, left=True, bottom=True)
plt.show()

#一層目で使われたカーネルフィルタも3つ抽出する
fig = plt.figure(figsize = (5,2))
for i in range(3):
    w = model_2.get_weights()[0][:, :, 0, i].reshape(5, 5)
    ax = fig.add_subplot(1, 3, i+1)
    ax.set_xticklabels([])
    ax.set_yticklabels([])
    ax.axis('off')
    ax.imshow(w, cmap='gray_r')
plt.show()
```
#### ◎二層目に通した後の出力
![first layor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/602f2a00-59b8-f553-7d84-fc035fdd18f9.png)
#### ◎一層目で使われたカーネルフィルタ(5×5)
![kernel of first layor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/db86752f-984c-1460-794a-fec049759410.png)

### 2.1.3.損失と正確さの可視化
```python
fig = plt.figure(figsize=(8, 8))
#制度
fig.add_subplot(1, 2, 1) 
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
plt.plot(acc, color='b', label="Training accuracy")
plt.plot(val_acc, color='r',label="Validation accuracy")
plt.title('Model accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='best')

#損失
fig.add_subplot(1, 2, 2) 
loss = history.history["loss"]
val_loss = history.history["val_loss"]
plt.plot(loss, color='b', label="Training loss")
plt.plot(val_loss, color='r', label="validation loss")
plt.title('Model loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='best')
plt.show()
print(history)
```
#### ◎学習率=0.001の時
![loss and accurancy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/f19e849f-f096-d088-aa31-b3fc7f27f737.png)
テストデータの推移がおかしい
#### ◎学習率=1e-5の時
![loss and accurancy lr1e-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/1333af95-caa6-7a1f-c2ff-7580e5c13944.png)
#### ◎学習率=1e-7の時
![loss and accurancy lr1e-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/6fb1c808-49fe-9c27-d84a-0565a85816eb.png)


## ◎学習率=0.001の時の結果
### 正誤状況をヒートマップで確認
```python
from sklearn.metrics import confusion_matrix
from decimal import Decimal
Y_pred = model.predict(X_val)
Y_pred_classes = np.argmax(Y_pred, axis = 1) 
Y_true = np.argmax(Y_val, axis = 1) 
cm = confusion_matrix(Y_true, Y_pred_classes)
sns.heatmap(cm, square=True, cbar=True, annot=True, cmap='Blues', fmt='.0f')
plt.title('Confusion matrix')
plt.xlabel("Predicted")
plt.ylabel("True")
plt.show()
```
![Confusion matrix weird number.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/86d2a875-73d7-c5f9-aea9-fc936e959c31.png)

### 各数字30個取り出して正誤を見てみる
```python
X_val2 = X_val.reshape(X_val.shape[0], 28, 28)
print(Y_pred_classes)
print(Y_true)
print(Y_pred_classes.shape)
print(Y_true.shape)

for t in  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:
    fig = plt.figure(figsize=(5, 2))
    h = 0
    k = 0
    while h < 30:
        if Y_pred_classes[k] == t:
            fig.add_subplot(3, 10, h+1) 
            plt.title(f"True {Y_true[k]} \n Pred {Y_pred_classes[k]}", fontsize = 8)
            plt.xticks([])
            plt.yticks([])
            sns.despine(top=True, right=True, left=True, bottom=True)
            plt.imshow(X_val2[k], cmap='binary')
            k += 1
            h += 1
        else:
            k += 1
    plt.show()
```
![n0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/96684ba7-9a2d-fe8e-dd1b-7196b7a99b03.png)
![n1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/d1a00ce6-1898-537e-430f-0424868799f4.png)
![n2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/9f9fe50f-230e-742e-0107-2d7775408347.png)
![n3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/feb9852b-ef84-f845-e921-9b13d20bbe0b.png)
![n4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/afc4aa95-f7b2-c3e2-06e0-b282dcb1df41.png)
![n5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/c1e655eb-2e07-019b-c76e-8eb1344ec2c5.png)
![n6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/317306b5-58b6-68c4-e7c8-ccf99b53b4d0.png)
![n7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/c1003ab8-3810-c55d-3123-7b59e82d258b.png)
![n8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/07ff6cc6-6bb3-52e7-a5f4-e8488f4130a8.png)
![n9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/38705e5e-b941-676d-9603-e0f31323af50.png)


### 間違った数字を30個取り出してみる
```python
fig = plt.figure(figsize=(5, 2))
h = 0
k = 0
while h < 30:
    if Y_pred_classes[k] != Y_true[k]:
        fig.add_subplot(3, 10, h+1) 
        plt.title(f"True {Y_true[k]} \n Pred {Y_pred_classes[k]}", fontsize = 8)
        plt.xticks([])
        plt.yticks([])
        sns.despine(top=True, right=True, left=True, bottom=True)
        plt.imshow(X_val2[k], cmap='binary')
        k += 1
        h += 1
    else:
        k += 1
plt.show()
```
![n miss.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/9d0abc25-9813-d30b-8b5f-5a69c4c10d1d.png)

## ◎学習率=1e-5の時の結果
### 正誤状況をヒートマップで確認
![Confusion matrix weird numberlr1e-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/84e54aac-22e9-4313-cfa0-c67c2e33f213.png)


## ◎学習率=1e-7の時の結果
### 正誤状況をヒートマップで確認
![Confusion matrix weird numberlr1e-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/ec8be987-8d15-f307-9213-c397463a1acc.png)

### 各数字30個取り出して正誤を見てみる
![n0lr1e-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/c065daf5-27d8-988c-46bf-7f45f8f7cb3a.png)
![n1lr1e-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/10d0a491-e0b4-26f9-c2d3-9ccbe90eac06.png)
![n2lr1e-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/b23524e4-4abe-d44b-6363-1672fe88a722.png)
![n3lr1e-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/2ef1d9fb-3667-a620-19d5-2ab0fd88566b.png)
![n4lr1e-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/ecc60c2b-4143-4f87-e523-c7eb81343139.png)
![n5lr1e-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/71f692dc-b1da-25cb-b17f-572a57ff90e4.png)
![n6lr1e-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/426cb182-2317-faa0-4b58-450d3e0fcc77.png)
![n7lr1e-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/06b1f5a4-9189-0646-b2a0-daa5b0b314cd.png)
![n8lr1e-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/babf9676-2c0c-b002-5db1-90b640ae6890.png)
![n9lr1e-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/846d72f9-493b-d5fa-a8d6-26f923a9ceba.png)
エポック30だと学習が足りず、間違いが結構多くなる。


## 2.2.Seqentialモデルを作ってみるパート2！！！！！
```python
model2 = Sequential()

model2.add(Conv2D(filters = 20, kernel_size = (5, 5), padding = 'Same', activation ='relu', input_shape = (28,28,1)))
model2.add(MaxPooling2D(pool_size=(2, 2)))

model2.add(Conv2D(filters = 50, kernel_size = (5, 5), padding = 'Same', activation ='relu'))
model2.add(MaxPooling2D(pool_size=(2, 2)))

model2.add(Conv2D(500,kernel_size =  (4, 4),padding = 'Same', activation ='relu'))
model2.add(Conv2D(10,kernel_size =  (1, 1),padding = 'Same', activation ='relu'))
model2.add(Flatten())
model2.add(Dense(500, activation = "relu"))
model2.add(Dense(10, activation = "softmax"))
```

### 2.2.1.RMSpropで最適化
```python
#RMSpropで最適化
opt = keras.optimizers.RMSprop(lr=1e-3, rho=0.9, epsilon=1e-08, decay=0.0)
model2.compile(optimizer = opt, loss = "categorical_crossentropy", metrics=["accuracy"])
history = model2.fit(X_train, Y_train, validation_split=0.25, epochs=3, batch_size=32, verbose=1)
```

### 2.2.2.モデル2の損失と正確度、その時の正誤の様子を可視化
```python
fig = plt.figure(figsize=(8, 8))
#ヒストリーの可視化（正確）
fig.add_subplot(1, 2, 1) 
acc = history2.history['accuracy']
val_acc = history2.history['val_accuracy']
plt.plot(acc, label="Training accuracy")
plt.plot(val_acc,label="Validation accuracy")
plt.title('Model2 accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='best')

#ヒストリーの可視化（損失）
fig.add_subplot(1, 2, 2) 
loss = history2.history["loss"]
val_loss = history2.history["val_loss"]
plt.plot(loss, label="Training loss")
plt.plot(val_loss, label="validation loss")
plt.title('Model2 loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='best')
plt.show()

#ヒートマップで確認
from sklearn.metrics import confusion_matrix
from decimal import Decimal
Y_pred = model2.predict(X_val)
Y_pred_classes = np.argmax(Y_pred, axis = 1) 
Y_true = np.argmax(Y_val, axis = 1) 
cm = confusion_matrix(Y_true, Y_pred_classes)
sns.heatmap(cm, square=True, cbar=True, annot=True, cmap='Blues', fmt='.0f')
plt.title('Confusion matrix')
plt.xlabel("Predicted")
plt.ylabel("True")
plt.show()
```

#### ◎学習率=0.001の時
![loss and accurancy lr1e-3 model2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/5998102b-a22d-76c9-f08d-de96155223ef.png)
![Confusion matrix 1e-3 model2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/e6214a75-9c35-627c-6959-61d215b7e103.png)

#### ◎学習率=1e-5の時
![loss and accurancy lr1e-5 model2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/9b36da1b-72b6-6947-20e6-7ef240d98b7a.png)
![Confusion matrix 1e-5 model2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/eb40eaf3-a877-1ad2-c7e0-1222b6690594.png)

#### ◎学習率=1e-7の時
![loss and accurancy lr1e-7 model2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/0adffe26-266c-340d-9cfa-85ac4d706672.png)
![Confusion matrix 1e-7 model2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658998/c842d3bb-8722-61de-8f2f-0ef93f3ebad9.png)