原文链接
欢迎来到第四课的第二个练习,在这里你将:
完成练习之后,你将能够
完成本作业必须熟悉Tensorflow。
如果你还不会,请参考2020-8-23 吴恩达-改善深层NN-w3 超参调整/批量正则化/编程框架(课后编程-TensorFlow Tutorial-手势辨认)
在上一个编程作业中,你利用numpy来构筑辅助函数,以此来了解ConvNet背后的原理。但是今天大多数的深度学习实践应用都是利用程序框架来实现的,这些程序框架有很多内置函数方便你调用。
和往常一下,我们先导入库
import math
import numpy as np
import h5py
import matplotlib.pyplot as plt
import scipy
from PIL import Image
from scipy import ndimage
import tensorflow as tf
from tensorflow.python.framework import ops
from cnn_utils import *
#%matplotlib inline #Jupyter Notebook中使用
np.random.seed(1)
然后导入"SIGNS"数据集
# Loading the data (signs)
X_train_orig, Y_train_orig, X_test_orig, Y_test_orig, classes = load_dataset()
提醒一下,"SIGNS"数据集中收集了6个手势来代表数字0到5。
你可以看一下数据集中带标签的图像样本。修改下面代码中的index,可以查看不同图像。
# Example of a picture
index = 16
plt.imshow(X_train_orig[index])
plt.show()
print ("y = " + str(np.squeeze(Y_train_orig[:, index])))
运行结果
y = 2
其实这个数据集在前面的编程作业《2020-8-23 吴恩达-改善深层NN-w3 超参调整/批量正则化/编程框架(课后编程-TensorFlow Tutorial-手势辨认)》中已经用过一次了,你利用它实现了一个全连接网络。但是因为这是一个图像数据集,所以更自然的选择是利用ConvNet来实现分类。ConvNet最重要的应用就是在图像识别领域。
开始之前,先看一下你的数据的形状。
X_train = X_train_orig/255.
X_test = X_test_orig/255.
Y_train = convert_to_one_hot(Y_train_orig, 6).T
Y_test = convert_to_one_hot(Y_test_orig, 6).T
print ("number of training examples = " + str(X_train.shape[0]))
print ("number of test examples = " + str(X_test.shape[0]))
print ("X_train shape: " + str(X_train.shape))
print ("Y_train shape: " + str(Y_train.shape))
print ("X_test shape: " + str(X_test.shape))
print ("Y_test shape: " + str(Y_test.shape))
conv_layers = {
}
运行结果
number of training examples = 1080
number of test examples = 120
X_train shape: (1080, 64, 64, 3)
Y_train shape: (1080, 6)
X_test shape: (120, 64, 64, 3)
Y_test shape: (120, 6)
TensorFlow要求你为运行会话session时将送入模型中的输入数据创建占位符。
练习:实现下面的函数,为图像输入 X 和输出 Y 创建占位符。现在你还不需要定义训练样本的数量。为了做到这点,你将使用"None"作为批量数据的大小,它可以让你更加灵活的在后面再赋值。因此,现在 X 的维度是 [None, n_H0, n_W0, n_C0] ,Y的维度是[None, n_y]。
实现代码
def create_placeholders(n_H0, n_W0, n_C0, n_y):
"""
Creates the placeholders for the tensorflow session.
为session创建占位符
Arguments:
n_H0 -- scalar, height of an input image 实数,输入图像的高度
n_W0 -- scalar, width of an input image 宽度
n_C0 -- scalar, number of channels of the input 通道数量
n_y -- scalar, number of classes 分类数量
Returns:
输入数据的占位符,维度为[None, n_H0, n_W0, n_C0],类型为"float"
X -- placeholder for the data input, of shape [None, n_H0, n_W0, n_C0] and dtype "float"
输入数据的标签的占位符,维度为[None, n_y],维度为"float"
Y -- placeholder for the input labels, of shape [None, n_y] and dtype "float"
"""
### START CODE HERE ### (≈2 lines)
X = tf.placeholder(tf.float32, [None, n_H0, n_W0, n_C0])
Y = tf.placeholder(tf.float32, [None, n_y])
### END CODE HERE ###
return X, Y
测试一下
X, Y = create_placeholders(64, 64, 3, 6)
print ("X = " + str(X))
print ("Y = " + str(Y))
运行结果
X = Tensor("Placeholder:0", shape=(?, 64, 64, 3), dtype=float32)
Y = Tensor("Placeholder_1:0", shape=(?, 6), dtype=float32)
你将使用tf.contrib.layers.xavier_initializer(seed = 0)
来初始化过滤器/权重 W 1 W1 W1 和 W 2 W2 W2 。你不需要考虑偏置,因为你很快会发现TensorFlow会考虑到的。需要注意的是你只需要初始化为2D卷积函数,全连接层TensorFlow会自动初始化的。
练习:实现函数initialize_parameters()。每组过滤器的维度按照以下方式提供。
W = tf.get_variable("W", [1,2,3,4], initializer = ...)
实现代码
def initialize_parameters():
"""
初始化权值矩阵,这里我们把权值矩阵硬编码:
Initializes weight parameters to build a neural network with tensorflow. The shapes are:
W1 : [4, 4, 3, 8]
W2 : [2, 2, 8, 16]
Returns:
parameters -- a dictionary of tensors containing W1, W2 包含了tensor类型的W1、W2的字典
"""
tf.set_random_seed(1) # so that your "random" numbers match ours
### START CODE HERE ### (approx. 2 lines of code)
W1 = tf.get_variable("W1", [4, 4, 3, 8], initializer=tf.contrib.layers.xavier_initializer(seed=0))
W2 = tf.get_variable("W2", [2, 2, 8, 16], initializer=tf.contrib.layers.xavier_initializer(seed=0))
### END CODE HERE ###
parameters = {
"W1": W1,
"W2": W2}
return parameters
测试一下
tf.reset_default_graph()
with tf.Session() as sess_test:
parameters = initialize_parameters()
init = tf.global_variables_initializer()
sess_test.run(init)
print("W1 = " + str(parameters["W1"].eval()[1,1,1]))
print("W2 = " + str(parameters["W2"].eval()[1,1,1]))
结果如下
W1 = [ 0.00131723 0.1417614 -0.04434952 0.09197326 0.14984085 -0.03514394
-0.06847463 0.05245192]
W2 = [-0.08566415 0.17750949 0.11974221 0.16773748 -0.0830943 -0.08058
-0.00577033 -0.14643836 0.24162132 -0.05857408 -0.19055021 0.1345228
-0.22779644 -0.1601823 -0.16117483 -0.10286498]
在TensorFlow里面有一些可内置函数可以提供你构建卷积神经网络:
使用tf.contrib.layers.fully_connected(F, num_outputs)的时候,全连接层会自动初始化权值,同时在你训练模型的时候它也会一直参与。因此当你初始化参数的时候,你不需要专门去初始化它的权值。
练习:构筑函数forward_propagation,实现以下模型:CONV2D -> RELU -> MAXPOOL -> CONV2D -> RELU -> MAXPOOL -> FLATTEN -> FULLYCONNECTED。
具体实现的时候,我们需要使用以下的步骤和参数:
实现代码
# GRADED FUNCTION: forward_propagation
def forward_propagation(X, parameters):
"""
实现前向传播
Implements the forward propagation for the model:
CONV2D -> RELU -> MAXPOOL -> CONV2D -> RELU -> MAXPOOL -> FLATTEN -> FULLYCONNECTED
Arguments:
输入数据的placeholder,维度为(输入节点数量,样本数量)
X -- input dataset placeholder, of shape (input size, number of examples)
包含了“W1”和“W2”的字典。
parameters -- python dictionary containing your parameters "W1", "W2"
the shapes are given in initialize_parameters
Returns:
Z3 -- the output of the last LINEAR unit 最后一个LINEAR节点的输出
"""
# Retrieve the parameters from the dictionary "parameters"
W1 = parameters['W1']
W2 = parameters['W2']
### START CODE HERE ###
# CONV2D: stride of 1, padding 'SAME'
#CONV2D : 步伐:1,填充方式:“SAME”
Z1 = tf.nn.conv2d(X, W1, strides=[1, 1, 1, 1], padding='SAME')
# RELU
A1 = tf.nn.relu(Z1)
# MAXPOOL: window 8x8, stride 8, padding 'SAME'
# 窗口大小:8x8,步伐:8x8,填充方式:“SAME”
P1 = tf.nn.max_pool(A1, ksize = [1, 8, 8, 1], strides = [1, 8, 8, 1], padding='SAME')
# CONV2D: filters W2, stride 1, padding 'SAME'
# CONV2D: 步伐:1,填充方式:“SAME”
Z2 = tf.nn.conv2d(P1, W2, strides=[1, 1, 1, 1], padding='SAME')
# RELU
A2 = tf.nn.relu(Z2)
# MAXPOOL: window 4x4, stride 4, padding 'SAME'
# 过滤器大小:4x4,步伐:4x4,填充方式:“SAME”
P2 = tf.nn.max_pool(A2, ksize = [1, 4, 4, 1], strides = [1, 4, 4, 1], padding='SAME')
# FLATTEN #一维化上一层的输出
P = tf.contrib.layers.flatten(P2)
# FULLY-CONNECTED without non-linear activation function (not not call softmax).
#全连接层(FC):使用没有非线性激活函数的全连接层
# 6 neurons in output layer. Hint: one of the arguments should be "activation_fn=None"
Z3 = tf.contrib.layers.fully_connected(P, 6, activation_fn=None)
### END CODE HERE ###
return Z3
测试一下
tf.reset_default_graph()
with tf.Session() as sess_test:
np.random.seed(1)
X, Y = create_placeholders(64, 64, 3, 6)
parameters = initialize_parameters()
Z3 = forward_propagation(X, parameters)
init = tf.global_variables_initializer()
sess_test.run(init)
a = sess_test.run(Z3, {
X: np.random.randn(2,64,64,3), Y: np.random.randn(2,6)})
print("Z3 = " + str(a))
运行结果
Z3 = [[ 1.4416984 -0.24909666 5.450499 -0.2618962 -0.20669907 1.3654671 ]
[ 1.4070846 -0.02573211 5.08928 -0.48669922 -0.40940708 1.2624859 ]]
这个结果和原文中不一致。我的环境是py3.6+tensorflow 1.4。检查了代码,没有问题。
不得已,换了一个环境,使用Anaconda3,先安装tensorflow
C:\Users\toddc>conda install tensorflow
Fetching package metadata .............
Solving package specifications: .
Package plan for installation in environment C:\Users\toddc\Anaconda3:
The following NEW packages will be INSTALLED:
backports.weakref: 1.0rc1-py36_0
blas: 1.0-mkl
bleach: 1.5.0-py36_0
html5lib: 0.9999999-py36_0
libprotobuf: 3.2.0-vc14_0
markdown: 2.6.9-py36_0
protobuf: 3.2.0-py36_0
tensorflow: 1.2.1-py36_0
vc: 14-0
The following packages will be UPDATED:
conda: 4.3.8-py36_0 --> 4.3.30-py36h7e176b0_0
vs2015_runtime: 14.0.25123-0 --> 14.0.25420-0
Proceed ([y]/n)? y
blas-1.0-mkl.t 100% |###############################| Time: 0:00:00 2.44 MB/s
libprotobuf-3. 100% |###############################| Time: 0:00:03 2.79 MB/s
markdown-2.6.9 100% |###############################| Time: 0:00:00 6.35 MB/s
backports.weak 100% |###############################| Time: 0:00:00 3.35 MB/s
html5lib-0.999 100% |###############################| Time: 0:00:00 8.44 MB/s
protobuf-3.2.0 100% |###############################| Time: 0:00:00 8.22 MB/s
bleach-1.5.0-p 100% |###############################| Time: 0:00:00 4.48 MB/s
tensorflow-1.2 100% |###############################| Time: 0:00:06 3.39 MB/s
conda-4.3.30-p 100% |###############################| Time: 0:00:00 1.38 MB/s
tensorflow版本低了,不过不影响执行代码。
使用IPython,执行结果
Z3 = [[-0.44670227 -1.57208765 -1.53049231 -2.31013036 -1.29104376 0.46852064]
[-0.17601591 -1.57972014 -1.4737016 -2.61672091 -1.00810647 0.5747785 ]]
太神奇了,正确了,等空了再找原因把。
你可以利用以下2个函数来完成成本计算
代码如下
# GRADED FUNCTION: compute_cost
def compute_cost(Z3, Y):
"""
Computes the cost
Arguments:
Z3 -- output of forward propagation (output of the last LINEAR unit), of shape (6, number of examples) 正向传播最后一个LINEAR节点的输出,维度为(6,样本数)。
Y -- "true" labels vector placeholder, same shape as Z3
Returns:
cost - Tensor of the cost function
"""
### START CODE HERE ### (1 line of code)
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=Z3, labels=Y))
### END CODE HERE ###
return cost
测试一下
tf.reset_default_graph()
with tf.Session() as sess:
np.random.seed(1)
X, Y = create_placeholders(64, 64, 3, 6)
parameters = initialize_parameters()
Z3 = forward_propagation(X, parameters)
cost = compute_cost(Z3, Y)
init = tf.global_variables_initializer()
sess.run(init)
a = sess.run(cost, {
X: np.random.randn(4,64,64,3), Y: np.random.randn(4,6)})
print("cost = " + str(a))
结果
cost = 2.91034
最终你需要把上面完成的函数合并构建模型。然后使用它训练SIGNS数据集。
你已经在《2020-8-15 吴恩达-改善深层NN-w2 优化算法(课后编程-Optimization Methods-3种算法:Mini-batch下降/带动量/Adam)》中实现了random_mini_batches()函数,它会返回mini-batches列表
练习:实现模型,包含
最终你创建一个session执行num_epochs次for循环,获得mini-batches,对于每个mini-batches执行优化
# GRADED FUNCTION: model
def model(X_train, Y_train, X_test, Y_test, learning_rate=0.009,
num_epochs=100, minibatch_size=64, print_cost=True):
"""
Implements a three-layer ConvNet in Tensorflow:
使用TensorFlow实现三层的卷积神经网络
CONV2D -> RELU -> MAXPOOL -> CONV2D -> RELU -> MAXPOOL -> FLATTEN -> FULLYCONNECTED
Arguments:
X_train -- training set, of shape (None, 64, 64, 3) 训练数据,维度为(None, 64, 64, 3)
Y_train -- test set, of shape (None, n_y = 6) 训练数据的标签,维度为(None, n_y = 6)
X_test -- training set, of shape (None, 64, 64, 3) 测试数据,维度为(None, 64, 64, 3)
Y_test -- test set, of shape (None, n_y = 6) 训练数据的标签,维度为(None, n_y = 6)
learning_rate -- learning rate of the optimization 学习率
num_epochs -- number of epochs of the optimization loop 遍历整个数据集的次数
minibatch_size -- size of a minibatch 每个小批量数据块的大小
print_cost -- True to print the cost every 100 epochs 是否打印成本值,每遍历100次整个数据集打印一次
Returns:
实数,训练集的准确度
train_accuracy -- real number, accuracy on the train set (X_train)
实数,测试集的准确度
test_accuracy -- real number, testing accuracy on the test set (X_test)
学习后的参数
parameters -- parameters learnt by the model. They can then be used to predict.
"""
#能够重新运行模型而不覆盖tf变量
ops.reset_default_graph() # to be able to rerun the model without overwriting tf variables
#确保你的数据和我一样
tf.set_random_seed(1) # to keep results consistent (tensorflow seed)
#指定numpy的随机种子
seed = 3 # to keep results consistent (numpy seed)
print(X_train.shape)
(m, n_H0, n_W0, n_C0) = X_train.shape
n_y = Y_train.shape[1]
costs = [] # To keep track of the cost
# Create Placeholders of the correct shape #为当前维度创建占位符
### START CODE HERE ### (1 line)
X, Y = create_placeholders(n_H0, n_W0, n_C0, n_y)
### END CODE HERE ###
# Initialize parameters #初始化参数
### START CODE HERE ### (1 line)
parameters = initialize_parameters()
### END CODE HERE ###
# Forward propagation: Build the forward propagation in the tensorflow graph
# 前向传播
### START CODE HERE ### (1 line)
Z3 = forward_propagation(X, parameters)
### END CODE HERE ###
# Cost function: Add cost function to tensorflow graph 计算成本
### START CODE HERE ### (1 line)
cost = compute_cost(Z3, Y)
### END CODE HERE ###
# Backpropagation: Define the tensorflow optimizer. Use an AdamOptimizer that minimizes the cost.
#反向传播,由于框架已经实现了反向传播,我们只需要选择一个优化器就行了
### START CODE HERE ### (1 line)
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
### END CODE HERE ###
# Initialize all the variables globally #全局初始化所有变量
init = tf.global_variables_initializer()
# Start the session to compute the tensorflow graph #开始运行
with tf.Session() as sess:
# Run the initialization #初始化参数
sess.run(init)
# Do the training loop #开始遍历数据集
for epoch in range(num_epochs):
minibatch_cost = 0.
num_minibatches = int(m / minibatch_size) # number of minibatches of size minibatch_size in the train set
seed = seed + 1
minibatches = random_mini_batches(X_train, Y_train, minibatch_size, seed)
for minibatch in minibatches: #对每个数据块进行处理
# Select a minibatch 选择一个数据块
(minibatch_X, minibatch_Y) = minibatch
# IMPORTANT: The line that runs the graph on a minibatch.
# Run the session to execute the optimizer and the cost, the feedict should contain a minibatch for (X,Y).
### START CODE HERE ### (1 line) 最小化这个数据块的成本
_ , temp_cost = sess.run([optimizer, cost], feed_dict={
X:minibatch_X, Y:minibatch_Y})
### END CODE HERE ###
minibatch_cost += temp_cost / num_minibatches #累加数据块的成本值
# Print the cost every epoch
if print_cost == True and epoch % 5 == 0:
print ("Cost after epoch %i: %f" % (epoch, minibatch_cost))
if print_cost == True and epoch % 1 == 0:
costs.append(minibatch_cost)
# plot the cost
plt.plot(np.squeeze(costs))
plt.ylabel('cost')
plt.xlabel('iterations (per tens)')
plt.title("Learning rate =" + str(learning_rate))
plt.show()
plt.savefig('3.png')
#开始预测数据
# Calculate the correct predictions # 计算当前的预测情况
predict_op = tf.argmax(Z3, 1)
correct_prediction = tf.equal(predict_op, tf.argmax(Y, 1))
# Calculate accuracy on the test set ##计算准确度
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
print(accuracy)
train_accuracy = accuracy.eval({
X: X_train, Y: Y_train})
test_accuracy = accuracy.eval({
X: X_test, Y: Y_test})
print("Train Accuracy:", train_accuracy)
print("Test Accuracy:", test_accuracy)
return train_accuracy, test_accuracy, parameters
迭代100次
_, _, parameters = model(X_train, Y_train, X_test, Y_test)
运行结果
Cost after epoch 0: 1.917920
Cost after epoch 5: 1.532475
Cost after epoch 10: 1.014804
Cost after epoch 15: 0.885137
Cost after epoch 20: 0.766963
Cost after epoch 25: 0.651208
Cost after epoch 30: 0.613356
Cost after epoch 35: 0.605931
Cost after epoch 40: 0.534713
Cost after epoch 45: 0.551402
Cost after epoch 50: 0.496976
Cost after epoch 55: 0.454438
Cost after epoch 60: 0.455496
Cost after epoch 65: 0.458359
Cost after epoch 70: 0.450040
Cost after epoch 75: 0.410687
Cost after epoch 80: 0.469005
Cost after epoch 85: 0.389253
Cost after epoch 90: 0.363808
Cost after epoch 95: 0.376132
Tensor("Mean_1:0", shape=(), dtype=float32)
Train Accuracy: 0.868519
Test Accuracy: 0.733333