iT邦幫忙

2021 iThome 鐵人賽

DAY 6
0
AI & Data

AI Facial Expression Recognition: Data, Model, Application系列 第 6

[Day 06] 特徵圖想讓人分群 ~模型們的遷移學習戰~ 第一季 (遷移學習)

前言

「指月錄」卷二十八有道:

「見山是山,見水是水;見山不是山,見水不是水;見山仍是山,見水仍是水。」

這乃是學習深度學習時三種不同的境界,
從只看表面、看細節處再到綜觀全局,
就是「是山、非山、仍是山」的過程。

今天我們要使用預訓練模型EfficientNet去提取圖片特徵,
看看這些特徵就會體悟到剛剛的境界轉換


載入套件

from tensorflow.keras.applications.efficientnet import EfficientNetB0
from scipy.spatial.distance import cdist
from sklearn.cluster import KMeans
from tensorflow.keras.utils import to_categorical
import tensorflow as tf
import pandas as pd
import numpy as np
import os
import matplotlib.pyplot as plt
import cv2

自定義函數

def prepare_data(data):

    image_array = np.zeros(shape=(len(data), 48, 48, 1))
    image_label = np.array(list(map(int, data['emotion'])))

    for i, row in enumerate(data.index):
        image = np.fromstring(data.loc[row, 'pixels'], dtype=int, sep=' ')
        image = np.reshape(image, (48, 48, 1))
        image_array[i] = image

    return image_array, image_label


def plot_one_emotion(data, img_arrays, img_labels, label=0):
    fig, axs = plt.subplots(1, 5, figsize=(25, 12))
    fig.subplots_adjust(hspace=.2, wspace=.2)
    axs = axs.ravel()
    for i in range(5):
        idx = data[data['emotion'] == label].index[i]
        axs[i].imshow(img_arrays[idx][:, :, 0], cmap='gray')
        axs[i].set_title(emotions[img_labels[idx]])
        axs[i].set_xticklabels([])
        axs[i].set_yticklabels([])


def plot_conv_feature(data, img_arrays, img_labels, label = 0):
    fig, axs = plt.subplots(4, 4, figsize=(16, 16))
    fig.subplots_adjust(hspace=.2, wspace=.2)
    axs = axs.flatten()
    for i in range(16):
        idx = data[data['cluster'] == label].index[i]
        axs[i].imshow(img_arrays[idx], cmap='gray')
        axs[i].set_title(f"feature {i}, cluster {label}", size = 20)
        axs[i].set_xticklabels([])
        axs[i].set_yticklabels([])


def convert_to_3_channels(img_arrays):
    sample_size, nrows, ncols, c = img_arrays.shape
    img_stack_arrays = np.zeros((sample_size, nrows, ncols, 3))
    for _ in range(sample_size):
        img_stack = np.stack(
            [img_arrays[_][:, :, 0], img_arrays[_][:, :, 0], img_arrays[_][:, :, 0]], axis=-1)
        img_stack_arrays[_] = img_stack/255
    return img_stack_arrays

讀取資料

由於待會要下載的EfficientNet的輸入層需要RGB彩色圖片,
但我們只有灰階圖(單通道),
所以用convert_to_3_channels將圖片轉成3通道,
注意!這裡不是將圖片變成彩色,只是單純將第1通道複製貼到第2和第3通道

df_raw = pd.read_csv("D:/mycodes/AIFER/data/fer2013.csv")
df_train = df_raw[df_raw['Usage'] == 'Training']
X_train, y_train = prepare_data(df_train)
X_train = convert_to_3_channels(X_train)  
y_train_oh = to_categorical(y_train)
emotions = {0: 'Angry', 1: 'Disgust', 2: 'Fear',
            3: 'Happy', 4: 'Sad', 5: 'Surprise', 6: 'Neutral'}

範例圖片

先選定一張我們要拿來萃取特徵的表情圖片,
就決定是第一張了!

plt.imshow(X_train[0],cmap='gray')

範例圖片


讀取EFN預訓練模型

  1. include_top: 是否需要原始模型的最上層(分類層),因為我們不需要分類,所以選False。
  2. weights: 選擇哪種預訓練權重,選擇imagenet。
  3. input_shape: 可以指定模型輸入大小,預設是(224,224,3)。
  4. pooling: 池化層方法選擇,有avg和max可選,基本上都可以用。
efn = EfficientNetB0(include_top=False, weights='imagenet', 
                        input_shape=(48, 48, 3), pooling='max')

獲得卷積層輸出(低階特徵)

在這裡我們選擇一個位於模型很前面的卷積層,獲得低階特徵(low-level)。
b1_result的shape為(1, 24, 24, 96),
含意是1張圖片透過卷積後,
原圖縮小成(24,24)的特徵圖,並且每張原圖可對應到96個特徵圖。

block1_conv_model = tf.keras.Model(efn.inputs, efn.get_layer(name='block2a_expand_conv').output)
b1_result = block1_conv_model(X_train[0]).numpy()
print(b1_result.shape)
# output: (1, 24, 24, 96)

低階特徵圖範例

我們可以看出某些特徵圖很有效地抓到了人臉的輪廓(例如: featrue 3, cluster 0)
02

獲得卷積層輸出(高階特徵)

在這裡我們選擇模型最後一個卷積層,獲得高階特徵(high-level)。
top_result的shape為(1, 2, 2, 1280),
含意是1張圖片透過卷積後,
獲得(2,2)的特徵圖,並且每張原圖可對應到1280個特徵圖(feature map)。

top_conv_model = tf.keras.Model(efn.inputs, efn.get_layer(name='top_conv').output)
top_result = top_conv_model(X_train[0]).numpy()
print(top_result.shape)
# output: (1, 2, 2, 1280)

高階特徵圖範例

我們可以看出畢卡索再世,畫出了原圖的精神象徵(?) XD
03

筆記時間

  1. 淺層網路解析度高,學到的是圖片細節特徵(低階),像是邊緣、稜角。
  2. 深層網路解析度低,學到的是圖片語義特徵(高階),是縱觀全局的、抽象的。

結語

OK,今天學會了如何讀取預訓練模型,
並將自己的圖片透過模型萃取出低階與高階的特徵。
這在業界是很常使用的技巧,
網路上也有許多大神提供的預訓練模型。
明天就讓我們來將這1280張高階特徵圖進行分群,
看看可以分成幾群吧!


上一篇
[Day 05] 當我~們同在一起在17在17 (k-means 理論篇)
下一篇
[Day 07] 特徵圖想讓人分群 ~模型們的遷移學習戰~ 第二季 (k-means 實作篇)
系列文
AI Facial Expression Recognition: Data, Model, Application30

尚未有邦友留言

立即登入留言