使用TensorFlow v2.0構建卷積神經網絡

使用TensorFlow v2.0構建卷積神經網絡。

這個例子使用低級方法來更好地理解構建卷積神經網絡和訓練過程背後的所有機制。

CNN 概述

使用TensorFlow v2.0構建卷積神經網絡

MNIST 數據集概述

此示例使用手寫數字的MNIST數據集。該數據集包含60,000個用於訓練的示例和10,000個用於測試的示例。這些數字已經過尺寸標準化並位於圖像中心,圖像是固定大小(28x28像素),值為0到255。

在此示例中,每個圖像將轉換為float32並歸一化為[0,1]。

使用TensorFlow v2.0構建卷積神經網絡

更多信息請查看鏈接: http://yann.lecun.com/exdb/mnist/

from __future__ import absolute_import, division, print_function
import tensorflow as tf
import numpy as np
# MNIST 數據集參數
num_classes = 10 # 所有類別(數字 0-9)
# 訓練參數
learning_rate = 0.001
training_steps = 200
batch_size = 128
display_step = 10
# 網絡參數
conv1_filters = 32 # 第一層卷積層卷積核的數目
conv2_filters = 64 # 第二層卷積層卷積核的數目
fc1_units = 1024 # 第一層全連接層神經元的數目
# 準備MNIST數據
from tensorflow.keras.datasets import mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# 轉化為float32
x_train, x_test = np.array(x_train, np.float32), np.array(x_test, np.float32)
# 將圖像值從[0,255]歸一化到[0,1]
x_train, x_test = x_train / 255., x_test / 255.
# 使用tf.data API對數據進行隨機排序和批處理
train_data = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_data = train_data.repeat().shuffle(5000).batch(batch_size).prefetch(1)
# 為簡單起見創建一些包裝器
def conv2d(x, W, b, strides=1):
# Conv2D包裝器, 帶有偏置和relu激活
x = tf.nn.conv2d(x, W, strides=[1, strides, strides, 1], padding='SAME')
x = tf.nn.bias_add(x, b)
return tf.nn.relu(x)
def maxpool2d(x, k=2):
# MaxPool2D包裝器
return tf.nn.max_pool(x, ksize=[1, k, k, 1], strides=[1, k, k, 1], padding='SAME')
# 存儲層的權重和偏置

# 隨機值生成器初始化權重
random_normal = tf.initializers.RandomNormal()
weights = {
# 第一層卷積層: 5 * 5卷積,1個輸入, 32個卷積核(MNIST只有一個顏色通道)
'wc1': tf.Variable(random_normal([5, 5, 1, conv1_filters])),
# 第二層卷積層: 5 * 5卷積,32個輸入, 64個卷積核
'wc2': tf.Variable(random_normal([5, 5, conv1_filters, conv2_filters])),
# 全連接層: 7*7*64 個輸入, 1024個神經元
'wd1': tf.Variable(random_normal([7*7*64, fc1_units])),
# 全連接層輸出層: 1024個輸入, 10個神經元(所有類別數目)
'out': tf.Variable(random_normal([fc1_units, num_classes]))
}
biases = {
'bc1': tf.Variable(tf.zeros([conv1_filters])),
'bc2': tf.Variable(tf.zeros([conv2_filters])),
'bd1': tf.Variable(tf.zeros([fc1_units])),
'out': tf.Variable(tf.zeros([num_classes]))
}
# 創建模型
def conv_net(x):

# 輸入形狀:[-1, 28, 28, 1]。一批28*28*1(灰度)圖像
x = tf.reshape(x, [-1, 28, 28, 1])
# 卷積層, 輸出形狀:[ -1, 28, 28 ,32]
conv1 = conv2d(x, weights['wc1'], biases['bc1'])

# 最大池化層(下采樣) 輸出形狀:[ -1, 14, 14, 32]
conv1 = maxpool2d(conv1, k=2)
# 卷積層, 輸出形狀:[ -1, 14, 14, 64]
conv2 = conv2d(conv1, weights['wc2'], biases['bc2'])

# 最大池化層(下采樣) 輸出形狀:[ -1, 7, 7, 64]
conv2 = maxpool2d(conv2, k=2)
# 修改conv2的輸出以適應完全連接層的輸入, 輸出形狀:[-1, 7*7*64]

fc1 = tf.reshape(conv2, [-1, weights['wd1'].get_shape().as_list()[0]])

# 全連接層, 輸出形狀: [-1, 1024]
fc1 = tf.add(tf.matmul(fc1, weights['wd1']), biases['bd1'])
# 將ReLU應用於fc1輸出以獲得非線性
fc1 = tf.nn.relu(fc1)
# 全連接層,輸出形狀 [ -1, 10]
out = tf.add(tf.matmul(fc1, weights['out']), biases['out'])
# 應用softmax將輸出標準化為概率分佈
return tf.nn.softmax(out)
# 交叉熵損失函數
def cross_entropy(y_pred, y_true):
# 將標籤編碼為獨熱向量
y_true = tf.one_hot(y_true, depth=num_classes)
# 將預測值限制在一個範圍之內以避免log(0)錯誤
y_pred = tf.clip_by_value(y_pred, 1e-9, 1.)
# 計算交叉熵
return tf.reduce_mean(-tf.reduce_sum(y_true * tf.math.log(y_pred)))
# 準確率評估
def accuracy(y_pred, y_true):
# 預測類是預測向量中最高分的索引(即argmax)
correct_prediction = tf.equal(tf.argmax(y_pred, 1), tf.cast(y_true, tf.int64))
return tf.reduce_mean(tf.cast(correct_prediction, tf.float32), axis=-1)
# ADAM 優化器
optimizer = tf.optimizers.Adam(learning_rate)
# 優化過程
def run_optimization(x, y):
# 將計算封裝在GradientTape中以實現自動微分
with tf.GradientTape() as g:
pred = conv_net(x)
loss = cross_entropy(pred, y)

# 要更新的變量,即可訓練的變量
trainable_variables = weights.values() + biases.values()
# 計算梯度
gradients = g.gradient(loss, trainable_variables)


# 按gradients更新 W 和 b
optimizer.apply_gradients(zip(gradients, trainable_variables))
# 針對給定步驟數進行訓練
for step, (batch_x, batch_y) in enumerate(train_data.take(training_steps), 1):
# 運行優化以更新W和b值
run_optimization(batch_x, batch_y)

if step % display_step == 0:
pred = conv_net(batch_x)
loss = cross_entropy(pred, batch_y)
acc = accuracy(pred, batch_y)
print("step: %i, loss: %f, accuracy: %f" % (step, loss, acc))

output:

step: 10, loss: 72.370056, accuracy: 0.851562
step: 20, loss: 53.936745, accuracy: 0.882812
step: 30, loss: 29.929554, accuracy: 0.921875
step: 40, loss: 28.075102, accuracy: 0.953125
step: 50, loss: 19.366310, accuracy: 0.960938
step: 60, loss: 20.398090, accuracy: 0.945312
step: 70, loss: 29.320951, accuracy: 0.960938
step: 80, loss: 9.121045, accuracy: 0.984375
step: 90, loss: 11.680668, accuracy: 0.976562
step: 100, loss: 12.413654, accuracy: 0.976562
step: 110, loss: 6.675493, accuracy: 0.984375
step: 120, loss: 8.730624, accuracy: 0.984375
step: 130, loss: 13.608270, accuracy: 0.960938
step: 140, loss: 12.859011, accuracy: 0.968750
step: 150, loss: 9.110849, accuracy: 0.976562
step: 160, loss: 5.832032, accuracy: 0.984375
step: 170, loss: 6.996647, accuracy: 0.968750
step: 180, loss: 5.325038, accuracy: 0.992188
step: 190, loss: 8.866342, accuracy: 0.984375
step: 200, loss: 2.626245, accuracy: 1.000000
# 在驗證集上測試模型
pred = conv_net(x_test)
print("Test Accuracy: %f" % accuracy(pred, y_test))

output:

Test Accuracy: 0.980000
# 可視化預測
import matplotlib.pyplot as plt
# 從驗證集中預測5張圖像
n_images = 5
test_images = x_test[:n_images]
predictions = conv_net(test_images)
# 顯示圖片和模型預測結果
for i in range(n_images):
plt.imshow(np.reshape(test_images[i], [28, 28]), cmap='gray')
plt.show()
print("Model prediction: %i" % np.argmax(predictions.numpy()[i]))

output:

使用TensorFlow v2.0構建卷積神經網絡

Model prediction: 7

使用TensorFlow v2.0構建卷積神經網絡

Model prediction:2

使用TensorFlow v2.0構建卷積神經網絡

Model prediction: 1

使用TensorFlow v2.0構建卷積神經網絡

Model prediction: 0

使用TensorFlow v2.0構建卷積神經網絡

Model prediction: 4


分享到:


相關文章: