版权为吴恩达老师所有,参考Koala_Tree的博客,部分根据自己实践添加
使用google翻译,部分手工翻译
你可能需要的参考资料https://pan.baidu.com/s/1VCkeolXINRYuWt7XnXU_JQ
2 - 在tensorflow中构建您的第一个神经网络
在这部分任务中,您将使用tensorflow构建神经网络。请记住,实现张量流模型有两个部分:
- 创建计算图
- 运行图表
让我们深入研究您想要解决的问题!
2.0 - 问题陈述:SIGNS数据集
一天下午,我和一些朋友决定教我们的电脑破译手语。我们花了几个小时在白墙前拍照,想出了以下数据集。现在,您的工作是构建一种算法,以促进从语言障碍者到不懂手语的人的通信。
- 训练集:1080个图像(64乘64像素)的符号表示从0到5的数字(每个数字180个图像)。
- 测试集:120张图片(64乘64像素)的符号,表示从0到5的数字(每个数字20张图片)。
请注意,这是SIGNS数据集的子集。完整的数据集包含更多符号。
以下是每个数字的示例,以及如何解释我们如何表示标签。在我们将图像重新降低到64 x 64像素之前,这些是原始图片。
图1:SIGNS数据集
然后运行以下代码以加载数据集。
X_train_orig, Y_train_orig, X_test_orig, Y_test_orig, classes = load_dataset()
更改下面的索引并运行单元格以显示数据集中的一些示例。
index=0
plt.imshow(X_train_orig[index])
plt.show()
print("y = "+str(np.squeeze(Y_train_orig[:,index])))
像往常一样,您展平图像数据集,然后将其除以255进行标准化。最重要的是,您将每个标签转换为one hot矢量,如图1所示。运行下面的单元格来执行此操作。
X_train_flatten=X_train_orig.reshape(X_train_orig.shape[0],-1).T
X_test_flatten=X_test_orig.reshape(X_test_orig.shape[0],-1).T
X_train=X_train_flatten/255.0
X_test=X_test_flatten/255.0
Y_train=convert_to_one_hot(Y_train_orig,6)
Y_test=convert_to_one_hot(Y_test_orig,6)
print ("number of training examples = " + str(X_train.shape[1]))
print ("number of test examples = " + str(X_test.shape[1]))
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))
请注意,12288来自64×64×364×64×3。每个图像是正方形,64乘64像素,3是RGB颜色。在继续之前,请确保所有这些形状对您有意义。
您的目标是构建一种能够高精度识别符号的算法。为此,您将构建一个张量流模型,该模型与您之前在numpy中为cat识别构建的模型几乎相同(但现在使用softmax输出)。这是一个很好的机会,可以将你的numpy实现与tensorflow实现进行比较。
该模型是LINEAR - > RELU - > LINEAR - > RELU - > LINEAR - > SOFTMAX。SIGMOID输出层已转换为SOFTMAX。当有两个以上的类时,SOFTMAX层是SIGMOID的推广。
2.1 - 创建占位符
您的第一个任务是为X
和创建占位符Y
。这将允许您稍后在运行会话时传递您的训练数据。
练习:实现以下函数以在tensorflow中创建占位符。
def create_placeholders(n_x,n_y):
X=tf.placeholder(tf.float32,shape=[n_x,None])
Y=tf.placeholder(tf.float32,shape=[n_y,None])
return X,Y
X, Y = create_placeholders(12288, 6)
print ("X = " + str(X))
print ("Y = " + str(Y))
2.2 - 初始化参数
您的第二个任务是初始化张量流中的参数。
练习:实现以下函数初始化张量流中的参数。您将使用Xavier Initialization进行权重和零偏置初始化。形状如下。例如,为了帮助您,对于W1和b1,您可以使用:
W1 = tf.get_variable("W1", [25,12288], initializer = tf.contrib.layers.xavier_initializer(seed = 1))
b1 = tf.get_variable("b1", [25,1], initializer = tf.zeros_initializer())
请使用seed = 1
以确保您的结果符合我们的要求。
def initialize_parameters():
tf.set_random_seed(1)
W1=tf.get_variable("W1",[25,12288],initializer=tf.contrib.layers.xavier_initializer(seed=1))
b1=tf.get_variable("b1",[25,1],initializer=tf.zeros_initializer())
W2=tf.get_variable("W2",[12,25],initializer=tf.contrib.layers.xavier_initializer(seed=1))
b2=tf.get_variable("b2",[12,1],initializer=tf.zeros_initializer())
W3=tf.get_variable("W3",[6,12],initializer=tf.contrib.layers.xavier_initializer(seed=1))
b3=tf.get_variable("b3",[6,1],initializer=tf.zeros_initializer())
parameters={"W1":W1,
"b1":b1,
"W2":W2,
"b2":b2,
"W3":W3,
"b3":b3,
}
return parameters
tf.reset_default_graph()
with tf.Session() as sess:
parameters = initialize_parameters()
print("W1 = " + str(parameters["W1"]))
print("b1 = " + str(parameters["b1"]))
print("W2 = " + str(parameters["W2"]))
print("b2 = " + str(parameters["b2"]))
tips:
1.可能非常慢
正如所料,尚未评估参数。
2.3 - tensorflow中的前向传播
您现在将在tensorflow中实现前向传播模块。该函数将接收参数字典,它将完成正向传递。您将使用的功能是:
tf.add(...,...)
做一个补充tf.matmul(...,...)
进行矩阵乘法tf.nn.relu(...)
应用ReLU激活
问题:实现神经网络的正向传递。我们为您评估了numpy等价物,以便您可以将tensorflow实现与numpy进行比较。重要的是要注意前向传播停止在z3
。原因在于,在tensorflow中,最后的线性层输出被给出作为计算损失的函数的输入。因此,你不需要a3
!
def forward_propagation(X,parameters):
W1 = parameters['W1']
b1 = parameters['b1']
W2 = parameters['W2']
b2 = parameters['b2']
W3 = parameters['W3']
b3 = parameters['b3']
Z1=tf.add(tf.matmul(W1,X),b1)
A1=tf.nn.relu(Z1)
Z2=tf.add(tf.matmul(W2,A1),b2)
A2=tf.nn.relu(Z2)
Z3=tf.add(tf.matmul(W3,A2),b3)
return Z3
tf.reset_default_graph()
with tf.Session() as sess:
X, Y = create_placeholders(12288, 6)
parameters = initialize_parameters()
Z3 = forward_propagation(X, parameters)
print("Z3 = " + str(Z3))
您可能已经注意到前向传播不会输出任何缓存。当我们进行向后传播时,在下面你会明白为什么。
2.4计算成本
如前所述,使用以下方法计算成本非常容易:
tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits = ..., labels = ...))
问题:执行以下成本函数。
- 重要的是要知道预期的“ logits
”和“ labels
”输入tf.nn.softmax_cross_entropy_with_logits
是形状的(例子数,num_classes)。因此,我们为您转换了Z3和Y.
- 此外,tf.reduce_mean
基本上是对例子的总结。
def compute_cost(Z3,Y):
logits=tf.transpose(Z3)
labels=tf.transpose(Y)
cost=tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits,labels=labels))
return cost
tf.reset_default_graph()
with tf.Session() as sess:
X, Y = create_placeholders(12288, 6)
parameters = initialize_parameters()
Z3 = forward_propagation(X, parameters)
cost = compute_cost(Z3, Y)
print("cost = " + str(cost))
2.5 - 向后传播和参数更新
这是您对编程框架感激不尽的地方。所有的反向传播和参数更新都在一行代码中处理。将该线合并到模型中非常容易。
计算成本函数后。您将创建一个“ optimizer
”对象。运行tf.session时,必须将此对象与成本一起调用。调用时,它将使用所选方法和学习速率对给定成本执行优化。
例如,对于梯度下降,优化器将是:
optimizer = tf.train.GradientDescentOptimizer(learning_rate = learning_rate).minimize(cost)
要进行优化,您需要:
_ , c = sess.run([optimizer, cost], feed_dict={X: minibatch_X, Y: minibatch_Y})
这通过以相反的顺序通过张量流图来计算反向传播。从成本到输入。
注意编码时,我们经常使用_
“一次性”变量来存储我们以后不需要使用的值。这里,_
采用optimizer
我们不需要的评估值(并c
获取cost
变量的值)。
2.6 - 构建模型
现在,你将把它们全部结合在一起!
练习:实施模型。您将调用之前实现的功能。
def model(X_train,Y_train,X_test,Y_test,learning_rate=0.0001,num_epochs=1500,minibatch_size=32,print_cost=True):
ops.reset_default_graph()
tf.set_random_seed(1)
seed=3
(n_x,m)=X_train.shape
n_y=Y_train.shape[0]
costs=[]
X,Y=create_placeholders(n_x,n_y)
parameters=initialize_parameters()
Z3=forward_propagation(X,parameters)
cost=compute_cost(Z3,Y)
optimizer=tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
init=tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
for epoch in range(num_epochs):
epoch_cost=0
num_minibatches=int(m/minibatch_size)
seed=seed+1
minibatches=random_mini_batches(X_train,Y_train,minibatch_size,seed)
for minibatch in minibatches:
(minibatch_X,minibatch_Y)=minibatch
_,minibatch_cost=sess.run([optimizer,cost],feed_dict={X:minibatch_X,Y:minibatch_Y})
epoch_cost+=minibatch_cost/num_minibatches
if print_cost and epoch%100==0 :
print("Cost after epoch %i: %f" %(epoch,epoch_cost))
if print_cost and epoch%10==0 :
costs.append(epoch_cost)
plt.close()
plt.plot(np.squeeze(costs))
plt.ylabel("cost")
plt.xlabel("iterations (per tens)")
plt.title("Learning rate = "+str(learning_rate))
plt.show()
parameters=sess.run(parameters)
print("Parameters have been trained!")
correct_prediction=tf.equal(tf.argmax(Z3),tf.argmax(Y))
accuracy=tf.reduce_mean(tf.case(correct_prediction,"float"))
print("Train Accuracy:",accuracy.eval({X:X_train,Y:Y_train}))
print("Test Accuracy:",accuracy.eval({X:X_test,Y:Y_test}))
return parameters
运行以下代码来训练您的模型!在我们的机器上大约需要5分钟。你的“Cost after epoch 100”应该是1.016458。如果不是,不要浪费时间; 中断训练,并尝试更正您的代码。如果是正确的费用,请休息一下,然后在5分钟后回来!
parameters = model(X_train, Y_train, X_test, Y_test)
令人惊讶的是,您的算法可以识别表示0到5之间的数字的符号,准确率为71.7%。
见解:
- 您的模型似乎足以适应训练集。但是,考虑到训练和测试精度之间的差异,您可以尝试添加L2或dropout正则化以减少过度拟合。
- 将会话视为训练模型的代码块。每次在mini-batch上运行会话时,它都会训练参数。总共运行会话很多次(1500个世代),直到你获得训练有素的参数。
2.7 - 使用您自己的图像进行测试(可选/未评分的练习)
恭喜你完成了这项任务。您现在可以拍摄手的图片并查看模型的输出。
import scipy
from PIL import Image
from scipy import ndimage
my_image = "thumbs_up.jpg"
fname = "images/" + my_image
image = np.array(ndimage.imread(fname, flatten=False))
my_image = scipy.misc.imresize(image, size=(64,64)).reshape((1, 64*64*3)).T
my_image_prediction = predict(my_image, parameters)
plt.imshow(image)
print("Your algorithm predicts: y = " + str(np.squeeze(my_image_prediction)))
你确实应该得到一个“竖起大拇指”,虽然你可以看到算法似乎错误地将其分类。原因是训练集不包含任何“竖起大拇指”,因此模型不知道如何处理它!我们称之为“不匹配的数据分布”,它是“构建机器学习项目”下一门课程的各种课程之一。
你应该记住的:
- Tensorflow是深度学习中使用的编程框架
- tensorflow中的两个主要对象类是Tensors和运算符。
- 当您在tensorflow中编码时,您必须执行以下步骤:
- 创建包含Tensors(变量,占位符...)和操作(tf.matmul,tf.add,...)的图形
- 创建会话
- 初始化会话
- 运行执行图形的会话
- 您可以像在模型()中看到的那样多次执行图形-
在“优化器”对象上运行会话时自动完成反向传播和优化。