Tensorflow2.x.x全卷積神經網絡(CNN)

Tensorflow2.x.x全卷積神經網絡(CNN)

本章節主要使用Tensorflow2.x.x來搭建CNN神經網絡。

全卷積神經網絡原理

引用小夥伴的原理,作者個人理解爲卷積層提取特徵而已,每一層提取的特徵不一樣。所以如果需要對模型進行改進的話就可以從對高級特徵和低級特徵的提取進行優化。

實現1

使用CNN實現對MNIST數據集的分類,最後一層不使用Dense嘗試。

import tensorflow as tf
# mnist數據集
from tensorflow.keras.datasets import mnist
# Adam優化器
from tensorflow.keras.optimizers import Adam
# 交叉熵損失函數,一般用於多分類
from tensorflow.keras.losses import CategoricalCrossentropy
# 模型和網絡層
from tensorflow.keras import Model, layers

# 批次大小
BATCH_SIZE = 128
# 迭代次數
EPOCHS = 10
# 加載mnist的訓練、測試數據集
train, test = mnist.load_data()
# 數據集的預處理
@tf.function
def preprocess(x, y):
    # 將x一維數據轉爲3維灰度圖
    x = tf.reshape(x, [28, 28, 1])
    # 將x的範圍由[0, 255]爲[0, 1]
    x = tf.image.convert_image_dtype(x, tf.float32)
    # 將y數字標籤進行獨熱編碼
    y = tf.one_hot(y, 10)
    # 返回處理後的x和y
    return x, y

# 使用Dataset來減少內存的使用
train = tf.data.Dataset.from_tensor_slices(train)
# 對數據進行預處理並且給定BATCH_SIZE
train = train.map(preprocess).batch(BATCH_SIZE)

# test數據集同理
test = tf.data.Dataset.from_tensor_slices(test)
test = test.map(preprocess).batch(BATCH_SIZE)

x = layers.Input(shape=(28, 28, 1))                                                               # 輸入爲x, 大小爲 28*28*1
y = layers.Conv2D(filters=64, kernel_size=3, strides=1, padding='same', activation='relu')(x)    # 64核的卷積層
# 在conv2d和maxpool之間可以使用BatchNormalization來提升訓練速度, 可自行百度BatchNormalization的用途
# y = layers.BatchNormalization(axis=3)(y, training=True)  training爲True則是訓練模式,否則是推理模式
y = layers.MaxPooling2D(pool_size=(2, 2))(y)                                                     # 池化層
y = layers.Conv2D(filters=128, kernel_size=3, strides=1, padding='same', activation='relu')(y)  # 128核的卷積層
y = layers.MaxPooling2D(pool_size=(2, 2))(y)
y = layers.Conv2D(filters=256, kernel_size=3, strides=1, padding='same', activation='relu')(y)  # 256核的卷積層
y = layers.MaxPooling2D(pool_size=(2, 2))(y)
y = layers.Conv2D(filters=512, kernel_size=3, strides=1, padding='same', activation='relu')(y)  # 512核的卷積層
y = layers.MaxPooling2D(pool_size=(2, 2))(y)
y = layers.Conv2D(filters=10, kernel_size=3, strides=1, padding='same', activation='softmax')(y)  # 10分類, 使用sotfmax激活
y = layers.Flatten()(y)                                                                            # 由於是多維, 於是進行扁平化

# 創建模型
cnn = Model(x, y)
# 打印模型
print(cnn.summary())
# 編譯模型,選擇優化器、評估標準、損失函數
cnn.compile(optimizer=Adam(learning_rate=1e-4), metrics=['acc'], loss=CategoricalCrossentropy())   # 這裏使用初始學習率爲1e-4的adam優化器
# 進行模型訓練
history = cnn.fit(train, epochs=EPOCHS)
# 測試集的評估
score = cnn.evaluate(test)
# 打印評估成績
print('loss: {0}, acc: {1}'.format(score[0], score[1]))   # loss: 0.04622650425310123, acc: 0.9848999977111816

# 繪製訓練過程中每個epoch的loss和acc的折線圖
import matplotlib.pyplot as plt
# history對象中有history字典, 字典中存儲着“損失”和“評估標準”
epochs = range(EPOCHS)
fig = plt.figure(figsize=(15, 5), dpi=100)

ax1 = fig.add_subplot(1, 2, 1)
ax1.plot(epochs, history.history['loss'])
ax1.set_title('loss graph')
ax1.set_xlabel('epochs')
ax1.set_ylabel('loss val')

ax2 = fig.add_subplot(1, 2, 2)
ax2.plot(epochs, history.history['acc'])
ax2.set_title('acc graph')
ax2.set_xlabel('epochs')
ax2.set_ylabel('acc val')

fig.show()

模型結構:
在這裏插入圖片描述
結果:
在這裏插入圖片描述

實現2

使用CNN實現對MNIST數據集的分類,最後一層使用Dense嘗試。

import tensorflow as tf
# mnist數據集
from tensorflow.keras.datasets import mnist
# Adam優化器
from tensorflow.keras.optimizers import Adam
# 交叉熵損失函數,一般用於多分類
from tensorflow.keras.losses import CategoricalCrossentropy
# 模型和網絡層
from tensorflow.keras import Model, layers

# 批次大小
BATCH_SIZE = 128
# 迭代次數
EPOCHS = 10
# 加載mnist的訓練、測試數據集
train, test = mnist.load_data()
# 數據集的預處理
@tf.function
def preprocess(x, y):
    # 將x一維數據轉爲3維灰度圖
    x = tf.reshape(x, [28, 28, 1])
    # 將x的範圍由[0, 255]爲[0, 1]
    x = tf.image.convert_image_dtype(x, tf.float32)
    # 將y數字標籤進行獨熱編碼
    y = tf.one_hot(y, 10)
    # 返回處理後的x和y
    return x, y

# 使用Dataset來減少內存的使用
train = tf.data.Dataset.from_tensor_slices(train)
# 對數據進行預處理並且給定BATCH_SIZE
train = train.map(preprocess).batch(BATCH_SIZE)

# test數據集同理
test = tf.data.Dataset.from_tensor_slices(test)
test = test.map(preprocess).batch(BATCH_SIZE)

x = layers.Input(shape=(28, 28, 1))                                                             # 輸入爲x, 大小爲 28*28*1
y = layers.Conv2D(filters=64, kernel_size=3, strides=1, padding='same', activation='relu')(x)   # 64核的卷積層
# 在conv2d和maxpool之間可以使用BatchNormalization來提升訓練速度, 可自行百度BatchNormalization的用途
# y = layers.BatchNormalization(axis=3)(y, training=True)  training爲True則是訓練模式,否則是推理模式
y = layers.MaxPooling2D(pool_size=(2, 2))(y)                                                    # 池化層
y = layers.Conv2D(filters=128, kernel_size=3, strides=1, padding='same', activation='relu')(y)  # 128核的卷積層
y = layers.MaxPooling2D(pool_size=(2, 2))(y)
y = layers.Conv2D(filters=256, kernel_size=3, strides=1, padding='same', activation='relu')(y)  # 256核的卷積層
y = layers.MaxPooling2D(pool_size=(2, 2))(y)
y = layers.Conv2D(filters=512, kernel_size=3, strides=1, padding='same', activation='relu')(y)  # 512核的卷積層
y = layers.MaxPooling2D(pool_size=(2, 2))(y)
y = layers.Flatten()(y)                                                                         # 由於是多維, 於是進行扁平化
y = layers.Dense(10, activation='softmax')(y)  # 10分類, 使用sotfmax激活

# 創建模型
cnn = Model(x, y)
# 打印模型
print(cnn.summary())
# 編譯模型,選擇優化器、評估標準、損失函數
cnn.compile(optimizer=Adam(learning_rate=1e-4), metrics=['acc'], loss=CategoricalCrossentropy())   # 這裏使用初始學習率爲1e-4的adam優化器
# 進行模型訓練
history = cnn.fit(train, epochs=EPOCHS)
# 測試集的評估
score = cnn.evaluate(test)
# 打印評估成績
print('loss: {0}, acc: {1}'.format(score[0], score[1]))   # loss: 0.035550699669444456, acc: 0.9883999824523926

# 繪製訓練過程中每個epoch的loss和acc的折線圖
import matplotlib.pyplot as plt
# history對象中有history字典, 字典中存儲着“損失”和“評估標準”
epochs = range(EPOCHS)
fig = plt.figure(figsize=(15, 5), dpi=100)

ax1 = fig.add_subplot(1, 2, 1)
ax1.plot(epochs, history.history['loss'])
ax1.set_title('loss graph')
ax1.set_xlabel('epochs')
ax1.set_ylabel('loss val')

ax2 = fig.add_subplot(1, 2, 2)
ax2.plot(epochs, history.history['acc'])
ax2.set_title('acc graph')
ax2.set_xlabel('epochs')
ax2.set_ylabel('acc val')

fig.show()

模型結構:
在這裏插入圖片描述
結果如下:
在這裏插入圖片描述

使用Dense對比

可以看出使用Dense的準確率將高一些,並且從折線圖可以看出使用Dense訓練下降會比較快。

與ANN對比

cnn的準確率比ANN高了一些。卷積可以很好的提取特徵並且相對ANN而言不容易過擬合。

使用BatchNormalization層優化卷積網絡的實現

使用BatchNormalization可以有效提高訓練速度和準確度。

import tensorflow as tf
# mnist數據集
from tensorflow.keras.datasets import mnist
# Adam優化器
from tensorflow.keras.optimizers import Adam
# 交叉熵損失函數,一般用於多分類
from tensorflow.keras.losses import CategoricalCrossentropy
# 模型和網絡層
from tensorflow.keras import Model, layers

# 批次大小
BATCH_SIZE = 128
# 迭代次數
EPOCHS = 10
# 加載mnist的訓練、測試數據集
train, test = mnist.load_data()
# 數據集的預處理
@tf.function
def preprocess(x, y):
    # 將x一維數據轉爲3維灰度圖
    x = tf.reshape(x, [28, 28, 1])
    # 將x的範圍由[0, 255][0, 1]
    x = tf.image.convert_image_dtype(x, tf.float32)
    # 將y數字標籤進行獨熱編碼
    y = tf.one_hot(y, 10)
    # 返回處理後的x和y
    return x, y

# 使用Dataset來減少內存的使用
train = tf.data.Dataset.from_tensor_slices(train)
# 對數據進行預處理並且給定BATCH_SIZE
train = train.map(preprocess).batch(BATCH_SIZE)

# test數據集同理
test = tf.data.Dataset.from_tensor_slices(test)
test = test.map(preprocess).batch(BATCH_SIZE)

x = layers.Input(shape=(28, 28, 1))                                                             # 輸入爲x, 大小爲 28*28*1
y = layers.Conv2D(filters=64, kernel_size=3, strides=1, padding='same', activation='relu')(x)   # 64核的卷積層
# 在conv2d和maxpool之間可以使用BatchNormalization來提升訓練速度, 可自行百度BatchNormalization的用途
y = layers.BatchNormalization(axis=3)(y, training=True)
y = layers.MaxPooling2D(pool_size=(2, 2))(y)                                                    # 池化層
y = layers.Conv2D(filters=128, kernel_size=3, strides=1, padding='same', activation='relu')(y)  # 128核的卷積層
y = layers.BatchNormalization(axis=3)(y, training=True)
y = layers.MaxPooling2D(pool_size=(2, 2))(y)
y = layers.Conv2D(filters=256, kernel_size=3, strides=1, padding='same', activation='relu')(y)  # 256核的卷積層
y = layers.BatchNormalization(axis=3)(y, training=True)
y = layers.MaxPooling2D(pool_size=(2, 2))(y)
y = layers.Conv2D(filters=512, kernel_size=3, strides=1, padding='same', activation='relu')(y)  # 512核的卷積層
y = layers.BatchNormalization(axis=3)(y, training=True)
y = layers.MaxPooling2D(pool_size=(2, 2))(y)
y = layers.Flatten()(y)                                                                         # 由於是多維, 於是進行扁平化
y = layers.Dense(10, activation='softmax')(y)  # 10分類, 使用sotfmax激活

# 創建模型
cnn = Model(x, y)
# 打印模型
print(cnn.summary())
# 編譯模型,選擇優化器、評估標準、損失函數
cnn.compile(optimizer=Adam(learning_rate=1e-4), metrics=['acc'], loss=CategoricalCrossentropy())   # 這裏使用初始學習率爲1e-4的adam優化器
# 進行模型訓練
history = cnn.fit(train, epochs=EPOCHS)
# 測試集的評估
score = cnn.evaluate(test)
# 打印評估成績
print('loss: {0}, acc: {1}'.format(score[0], score[1]))   # loss: 0.035550699669444456, acc: 0.9883999824523926

# 繪製訓練過程中每個epoch的loss和acc的折線圖
import matplotlib.pyplot as plt
# history對象中有history字典, 字典中存儲着“損失”和“評估標準”
epochs = range(EPOCHS)
fig = plt.figure(figsize=(15, 5), dpi=100)

ax1 = fig.add_subplot(1, 2, 1)
ax1.plot(epochs, history.history['loss'])
ax1.set_title('loss graph')
ax1.set_xlabel('epochs')
ax1.set_ylabel('loss val')

ax2 = fig.add_subplot(1, 2, 2)
ax2.plot(epochs, history.history['acc'])
ax2.set_title('acc graph')
ax2.set_xlabel('epochs')
ax2.set_ylabel('acc val')

fig.show()

模型結構:
在這裏插入圖片描述
結果:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章