吴恩达的 DeepLearning.ai 已经于 1 月 31 日发布了最后一门课程。近日,来自重庆大学的 Wan Zhen 制做了一份深度学习专项课程笔记,该笔记从神经网络与深度学习基础、提高深度神经网络性能和卷积神经网络三门课程出发详细解释了关键概念与做业代码。本文归纳性地介绍了这三课的主要内容,并选择每一个课程主题比较有意思的知识点进行介绍。node
在这份笔记中,Wan Zhen 不只介绍了每一个课程的关键知识点,同时还详细解释了各课程的编程做业。在第一门课程《神经网络与深度学习基础》中,该课程笔记不只提供了最基础的 Python 和 NumPy 操做笔记,同时还从最基础的 Logistic 回归推导到最通常的深度全链接网络。固然,还介绍了必要的损失函数与反向传播方法。而在第二门课程中,该笔记详细记录了提高深度网络性能所须要的技巧与基础,例如初始化、正则化和梯度检验等在实践上大大提高模型性能的方法,以及通常 SGD、动量法和适应性学习率方法等常见的最优化方法。最后,第二门课程重点介绍了 TensorFlow,包括该框架的经常使用函数和实际构建网络的过程等。最后一章节主要记录了卷积神经网络,包括基本的卷积运算、残差网络和目标检测框架等。python
如下是该课程笔记的简要框架与一些详细的知识点。算法
这一部分对应的是吴恩达深度学习课程的第一课,主要介绍必要的编程语言和编程工具,并逐步进阶介绍线性网络、非线性网络、隐藏层网络到深度网络的实现方法,细节详尽,附有完整的代码。经过这一部分的学习,你将理解神经网络的结构和数据流(前向传播和反向传播),非线性激活函数和隐藏层对学习复杂函数的做用,并知道如何一步步构建完整的(任意结构的、自定义的)神经网络,体会向量化和模块化编程思想的妙处。数据库
本章第一节介绍了如何使用 Python 的 Numpy 工具包、iPython Notebook 等基本的编程工具。而后介绍如何用这些工具构建神经网络,特别是理解神经网络计算的向量化思想和 Python 广播的使用。编程
第 2 节介绍如何构建一个准确率为 70% 的 logistic 回归神经网络分类器(图像识别网络)来识别猫,并介绍如何进一步将准确率提升的方法,以及损失函数的偏导数更新参数的过程。其中特别强调了尽可能用向量化结构而不要用循环结构,除非有必要(好比 epoch 的迭代就必须使用循环结构)。数组
1.2.1 介绍必要的 Python 工具包;1.2.2 介绍数据集的结构;1.2.3 介绍整个学习算法的宏观架构;1.2.4 介绍构建算法的基本步骤;1.2.5 和 1.2.6 总结前述内容进行代码实现,并进行了可视化分析;1.2.7 介绍如何用本身的数据集训练该神经网络;1.2.8 展现了 logistic 回归神经网络的完整代码。bash
其中 1.2.4 介绍的构建算法的基本步骤为:网络
定义模型结构;session
初始化模型参数;架构
循环迭代结构:
计算当前损失函数值(前向传播)
计算当前梯度值(反向传播)
更新参数(梯度降低)
一般 1—3 部分是分开构建的,而后整合到一个函数 model() 中。
1.2.5 对 model() 进行了代码实现,并画出了损失函数和梯度的图像。
第 3 节介绍如何在神经网络中添加隐藏层以对平面数据点进行分类,本节将教你理解反向传播的工做过程、隐藏层对捕捉非线性关系的做用,以及构建辅助函数的方法。
重点内容包括:用单个隐藏层实现二分类器;使用非线性激活函数;计算交叉熵损失;实现前向和反向传播。
1.3.1 介绍必要的工具包;1.3.2 介绍数据集的构成(平面上的红点和蓝点);1.3.3 介绍无隐藏层的 logistic 回归对该数据集的分类结果;1.3.4 介绍添加了隐藏层的完整模型的实现过程和对该数据集的分类;1.3.5 展现了完整代码。
其中 1.3.3 的分类结果以下图所示:
1.3.4 中使用的神经网络的架构:
1.3.4 构建神经网络的方法和 1.2.4 基本相同,重点强调了如何定义隐藏层结构和非线性激活函数的使用,实现代码后,获得的运行结果为:
其中,添加了隐藏层以后,必须使用非线性激活函数,由于不使用非线性激活函数的线性层堆叠是无心义的,没法增大模型的复杂度和容量。
第 4 节介绍深度神经网络的完整架构,以及如何构建自定义的模型。完成这部分后,你将学会:使用 ReLU 激活函数提高模型的性能、构建更深的模型(隐藏层数大于 1),以及实现易用的神经网络(模块化思想)。
1.4.1 介绍必要的工具包;1.4.2 介绍任务概述;1.4.3 介绍从 2 层网络到 L 层网络的初始化过程;1.4.4 介绍前向传播模块的构建,从线性前向传播、线性+非线性激活前向传播,再到 L 层网络的前向传播;1.4.5 介绍损失函数;1.4.6 介绍反向传播模块的构建,从线性反向传播、线性+非线性激活反向传播,再到 L 层网络的反向传播;1.4.7 展现了深度神经网络的完整代码。
经过前面四节的学习,你已学会如何一步一步构建完整的深度神经网络。第 5 节介绍如何用深度神经网络构建猫识别分类器。此前在 logistic 回归网络中,识别准确率只能达到 68%,而在完整的深度网络中,识别准确率能达到 80%!
完成本节后,你将学会:用前面介绍的全部辅助函数构建任意结构的神经网络;试验不一样结构的神经网络,并进行分析;理解构建辅助函数对构建网络的好处(对比从零开始)。
1.5.1 介绍必要的工具包;1.5.2 介绍数据集(猫 vs. 非猫);1.5.3 介绍模型架构,其中分别构建了 2 层和 L 层的神经网络;1.5.4 介绍 2 层神经网络的训练和测试结果;1.5.5 介绍 2 层神经网络的训练和测试结果;1.5.6 对结果进行分析;1.5.7 介绍如何用你本身的图像训练分类模型;1.5.8 展现了完整代码。
其中,2 层神经网络的运行结果:
运行结果:
运行结果:
经过比较可知,更深的网络有助于提升识别准确率(0.72 vs. 0.8;2 层 vs. 5 层)。
1.5.6 简单总结了影响识别错误的因素:
猫出如今很是规的位置;
猫的颜色和背景类似;
很是规的猫毛色和品种;
拍摄角度;
照片的亮度;
猫的占图比例过小或太大。
这些识别错误可能跟全链接网络自身的局限性有关,包括参数共享、过拟合倾向(参数数量)和层级特征方面,而这些问题将在卷积神经网络里获得改善。
这一部分对应吴恩达 deeplearning.ai 的第二门课程,重点从超参数调整、随机和 Xavier 等参数初始化方法、Dropout 和 L2 范数等正则化方法、以及 1 维和 N 维梯度检验方法来描述深度学习在实践上的性能提高方法。固然,这一部分不只包含课程知识点,还展现了课后问答与实现做业。
最优化在这一部分课程中也获得了重点讲解,Wan Zhen 的课程笔记从最基本的最速降低法到小批量随机梯度降低介绍了基本的一阶梯度法,而后再探讨动量法与适应性学习率方法来利用历史梯度得到更好的降低方向。值得注意的是,该笔记详细介绍了 Adam 最优化方法的更新过程与实现代码。
这门课程最后一部分主要展示了 TensorFlow 的基本函数与实际构建神经网络的过程。
在参数初始化、正则化和梯度检验中,比较有意思的是 He 初始化和 Dropout 的机制,下面咱们将详细探讨这两个组件。
He 初始化(He Initialization,He et al., 2015)是根据第一做者的名字而肯定的。若是读者了解 Xavier 初始化,那么其实它们是很是类似的,只不过 Xavier 初始化会为权重 W^l 使用标量元素 sqrt(1./layers_dim[l-1]),而 He 初始化会使用 sqrt(2./layers_dims[l-1])。如下展现了如何实现 He 初始化,这一部分是课程做业的答案:
# GRADED FUNCTION: initialize_parameters_he
def initialize_parameters_he(layers_dims):
""" Arguments: layer_dims -- python array (list) containing the size of each ,→ layer. Returns: parameters -- python dictionary containing your parameters "W1", ,→ "b1", ..., "WL", "bL": W1 -- weight matrix of shape (layers_dims[1], ,→ layers_dims[0]) b1 -- bias vector of shape (layers_dims[1], 1) ... WL -- weight matrix of shape (layers_dims[L], ,→ layers_dims[L-1]) bL -- bias vector of shape (layers_dims[L], 1) """
np.random.seed(3)
parameters = {}
L = len(layers_dims) - 1 # integer representing the number of
,→ layers
for l in range(1, L + 1):
### START CODE HERE ### (
2 lines of code)
parameters['W' + str(l)] = np.random.randn(layers_dims[l],
,→ layers_dims[l-1]) * np.sqrt(2./layers_dims[l-1])
parameters['b' + str(l)] = np.zeros((layers_dims[l], 1))
### END CODE HERE ###
return parameters
复制代码
最后,该文档还总结了三种初始化的效果。以下所示,它们都在相同迭代数、相同的超参数和相同网络架构下进行测试:
在正则化方法中,Dropout 是很是有用和成功的一种技术。虽然近来有研究者发现把它和批归一化(BN)一块儿使用会产生一些冲突,但仍然不影响它做为一种强大的技术来控制模型过拟合。通常来讲,Dropout 会随机删除一些神经元,以在不一样批量上训练不一样的神经网络架构。
Bagging 是经过结合多个模型下降泛化偏差的技术,主要的作法是分别训练几个不一样的模型,而后让全部模型表决测试样例的输出。而 Dropout 能够被认为是集成了大量深层神经网络的 Bagging 方法,所以它提供了一种廉价的 Bagging 集成近似方法,可以训练和评估值数据数量的神经网络。
在每个批量的前向传播与反向更新中,咱们关闭每一个神经元的几率为 1-keep_prob,且关闭的神经元不参与前向传播计算与参数更新。每当咱们关闭一些神经元,咱们实际上修改了原模型的结构,那么每次迭代都训练一个不一样的架构,参数更新也更加关注激活的神经元。这种正则化方法能够当作是一种集成方法,即集成每一个批量所训练的不一样网络架构。
在正则化方法中,该笔记也比较了 L2 正则化和 Dropout 的效果:
在后面的最优化方法中,咱们比较感兴趣的是 Adam 方法,所以下面咱们也将重点描述该方法。
Adam 算法和传统的随机梯度降低不一样。随机梯度降低保持单一的学习率(即 alpha)更新全部的权重,学习率在训练过程当中并不会改变。而 Adam 经过计算梯度的一阶矩估计和二阶矩估计,为不一样的参数设计独立的自适应性学习率。
Adam 算法的提出者描述其为两种随机梯度降低扩展式的优势集合,即:
适应性梯度算法(AdaGrad)为每个参数保留一个学习率,以提高在稀疏梯度(即天然语言和计算机视觉问题)上的性能。
均方根传播(RMSProp)基于权重梯度最近量级的均值为每个参数适应性地保留学习率。这意味着算法在非稳态和在线问题上有很优秀的性能。
Adam 算法同时具有 AdaGrad 和 RMSProp 算法的优势。Adam 不只如 RMSProp 算法那样基于一阶矩均值计算适应性参数学习率,它同时还充分利用了梯度的二阶矩均值(即有偏方差/uncentered variance)。具体来讲,算法计算了梯度的指数移动均值(exponential moving average),超参数 beta1 和 beta2 控制了这些移动均值的衰减率。
移动均值的初始值和 beta一、beta2 值接近于 1(推荐值),所以矩估计的误差接近于 0。该误差经过首先计算带误差的估计然后计算误差修正后的估计而获得提高。
正如该笔记所总结的,Adam 的计算更新过程可分为三部分:
1. 计算历史梯度的指数加权平均值,并将它储存在变量 v 中(有偏估计),而后再计算 v^corrected(修正后得出的无偏估计)。
2. 计算历史梯度平方的指数加权平均值,并将它储存为变量 s(有偏估计),而后计算 s^corrected(修正的无偏估计)。
3. 而后结合前两步的信息更新参数。
这一更新过程如笔记所述可表示为:
其中 t 会计算 Adam 所迭代更新的次数、L 为层级数、β_1 和β_1 为控制指数加权平均值得超参数、α 为学习率,而 ε 为避免分母为零的小常数。
Wan Zhen 一样给出了 Adam 的实现代码或做业解读:
# GRADED FUNCTION: initialize_adam
def initialize_adam(parameters) :
""" Initializes v and s as two python dictionaries with: - keys: "dW1", "db1", ..., "dWL", "dbL" - values: numpy arrays of zeros of the same shape as ,→ the corresponding gradients/parameters. Arguments: parameters -- python dictionary containing your parameters. parameters["W" + str(l)] = Wl parameters["b" + str(l)] = bl Returns: v -- python dictionary that will contain the exponentially weighted ,→ average of the gradient. v["dW" + str(l)] = ... v["db" + str(l)] = ... s -- python dictionary that will contain the exponentially weighted ,→ average of the squared gradient. s["dW" + str(l)] = ... s["db" + str(l)] = ... """
L = len(parameters) // 2 # number of layers in the neural networks
v = {}
s = {}
# Initialize v, s. Input: "parameters". Outputs: "v, s".
for l in range(L):
### START CODE HERE ### (approx. 4 lines)
v["dW" + str(l+1)] = np.zeros(parameters["W" + str(l+1)].shape)
v["db" + str(l+1)] = np.zeros(parameters["b" + str(l+1)].shape)
s["dW" + str(l+1)] = np.zeros(parameters["W" + str(l+1)].shape)
s["db" + str(l+1)] = np.zeros(parameters["b" + str(l+1)].shape)
### END CODE HERE ###
return v, s
复制代码
如下实现了上面描述的参数更新过程:
# GRADED FUNCTION: update_parameters_with_adam
def update_parameters_with_adam(parameters, grads, v, s, t, learning_rate = 0.01, beta1 = 0.9, beta2 = 0.999, epsilon = 1e-8):
L = len(parameters) // 2 # number of layers in the neural networks
v_corrected = {} # Initializing first moment estimate, python, dictionary
s_corrected = {} # Initializing second moment estimate, python
,→ dictionary
# Perform Adam update on all parameters
for l in range(L):
# Moving average of the gradients. Inputs: "v, grads, beta1".
,→ Output: "v".
v["dW" + str(l+1)] = beta1*v["dW" +
,→ str(l+1)]+(1-beta1)*grads['dW' + str(l+1)]
v["db" + str(l+1)] = beta1*v["db" + str(l+1)]+(1-beta1)*grads['db' + str(l+1)]
# Compute bias-corrected first moment estimate. Inputs: "v, beta1, t". Output: "v_corrected".
v_corrected["dW" + str(l+1)] = v["dW" + str(l+1)]/(1-math.pow(beta1,t))
v_corrected["db" + str(l+1)] = v["db" + str(l+1)]/(1-math.pow(beta1,t))
# Moving average of the squared gradients. Inputs: "s, grads, beta2". Output: "s".
s["dW" + str(l+1)] = beta2*s["dW" + str(l+1)]+(1-beta2)*(grads['dW' + str(l+1)]**2)
s["db" + str(l+1)] = beta2*s["db" + str(l+1)]+(1-beta2)*(grads['db' + str(l+1)]**2)
# Compute bias-corrected second raw moment estimate. Inputs: "s, beta2, t". Output: "s_corrected".
s_corrected["dW" + str(l+1)] = s["dW" + str(l+1)]/(1-math.pow(beta2,t))
s_corrected["db" + str(l+1)] = s["db" + str(l+1)]/(1-math.pow(beta2,t))
# Update parameters. Inputs: "parameters, learning_rate, v_corrected, s_corrected, epsilon". Output: "parameters".
parameters["W" + str(l+1)] = parameters["W" + str(l+1)]-learning_rate * v_corrected["dW" + str(l+1)]/(np.sqrt(s_corrected["dW" + str(l+1)])+epsilon)
parameters["b" + str(l+1)] = parameters["b" + str(l+1)]-learning_rate * v_corrected["db" + str(l+1)]/(np.sqrt(s_corrected["db" + str(l+1)])+epsilon)
return parameters, v, s
复制代码
该章节一样介绍和对比了这几个最优化方法的优点:
最后一部分重点介绍了 TensorFlow 的函数与实践。TensorFlow 是一种采用数据流图(data flow graphs),用于数值计算的开源软件库。其中 Tensor 表明传递的数据为张量(多维数组),Flow 表明使用计算图进行运算。数据流图用「结点」(nodes)和「边」(edges)组成的有向图来描述数学运算。「结点」通常用来表示施加的数学操做,但也能够表示数据输入的起点和输出的终点,或者是读取/写入持久变量(persistent variable)的终点。边表示结点之间的输入/输出关系。这些数据边能够传送维度可动态调整的多维数据数组,即张量(tensor)。
这一部分笔记重点介绍了课程的测试和实现代码,例如如下构建了简单的占位符:
### START CODE HERE ### (approx. 2 lines)
X = tf.placeholder(tf.float32, [n_x, None], name = 'X')
Y = tf.placeholder(tf.float32, [n_y, None], name = 'Y')
### END CODE HERE ###
return X, Y
return parameters, v, s
复制代码
定义变量和常量的方法:
a = tf.constant(2, tf.int16)
b = tf.constant(4, tf.float32)
g = tf.constant(np.zeros(shape=(2,2), dtype=np.float32))
d = tf.Variable(2, tf.int16)
e = tf.Variable(4, tf.float32)
h = tf.zeros([11], tf.int16)
i = tf.ones([2,2], tf.float32)
k = tf.Variable(tf.zeros([2,2], tf.float32))
l = tf.Variable(tf.zeros([5,6,5], tf.float32))
return parameters, v, s
复制代码
初始化参数的方法:
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())
return parameters, v, s
复制代码
运行计算图:
a = tf.constant(2, tf.int16)
b = tf.constant(4, tf.float32)
graph = tf.Graph()
with graph.as_default():
a = tf.Variable(8, tf.float32)
b = tf.Variable(tf.zeros([2,2], tf.float32))
with tf.Session(graph=graph) as session:
tf.global_variables_initializer().run()
print(f)
print(session.run(a))
print(session.run(b))
#输出:
>>> <tf.Variable 'Variable_2:0' shape=() dtype=int32_ref>
>>> 8
>>> [[ 0. 0.]
>>> [ 0. 0.]]
return parameters, v, s
复制代码
在大神吴恩达的第四课里咱们学习的是卷积神经网络也就是 CNN,这一章的习题是让你用 Numpy 实现一个卷积层和一个池化层同时还有前馈和反向传播。你所能用到的包有:
Numpy:一个基本的在 Python 里用来作科学计算的包。
Matplotlib:用来画图。
列举一下你将要学习实现的函数:
1. 卷积函数,包括:
零填充(zero padding)
卷积窗(convolve window)
前向卷积(convolution forward)
反向卷积(convolution backward)
2. 池化函数,包括:
前向池化(Pooling forward)
建立掩码(create mask)
分布值(distribute value)
反向池化(Pooling backward)
第一个做业要求用 Numpy 一点点实现这些函数,下一个做业要求用 TensorFlow 里的函数创建模型。
第三章里讲了卷积神经网络、池化层和卷积神经网络的反向传播。卷积神经网络这部分讲了零填充、单步卷积和前馈卷积网络;池化层这部分讲了前向池化;卷积神经网络的反向传播这部分讲了卷积层反传和池化层反传。
虽然编程框架使卷积易于使用,但卷积还是深度学习里最难懂的一部分。卷积网络大体上会像下图同样把输入转化成输出:
为了帮助你们进一步理解卷积,小编在这里着重写一下卷积的操做。
在这部分,咱们会实现一个单步的卷积,就是你用一个滤波器(filter)在输入的单个位置上执行一下,而后整个的卷积结果就是不断地拖动这个滤波器在输入值的全部位置上执行。咱们要作的:
1:拿到输入数据;
2:使用滤波器在输入数据的每个位置上执行一下;
3:输出另外一个数据(通常和输入数据大小不同)。
在计算机视觉里,矩阵中每个值对应的都是单个的像素值,咱们用一个 3*3 大小的滤波器去卷图片,就是在每个位置上,用滤波器里的每个值去乘原始矩阵里对应位置上的值,而后求和以后再加上一个误差数值,而后再拖动这个滤波器去下一个位置上,这就是卷积,每一次拖动的距离叫作步长。在第一步练习里,你将要实现一个一步的卷积,这个一步的卷积是使用一个滤波器在输入数据一个位置上卷积获得的单个的实数输出。
练习:实现 conv_single_step() 函数
代码:
# GRADED FUNCTION: conv_single_step
def conv_single_step(a_slice_prev, W, b): """ Apply one filter defined by parameters W on a single slice → (a_slice_prev)oftheoutputactivation of the previous layer. Arguments: a_slice_prev -- slice of input data of shape (f, f, n_C_prev) W -- Weight parameters contained in a window - matrix of shape (f, → f,n_C_prev) b -- Bias parameters contained in a window - matrix of shape (1, 1, → 1) Returns: Z -- a scalar value, result of convolving the sliding window (W, b) → onaslicexoftheinputdata """
### START CODE HERE ### ( 2 lines of code)
# Element-wise product between a_slice and W. Add bias. s = a_slice_prev * W + b
# Sum over all entries of the volume s
Z = np.sum(s)
### END CODE HERE ###
return Z
return parameters, v, s
复制代码
再大体讲一下卷积神经网络前传(Forward pass)。
以前咱们讲了怎样用一个滤波器去作卷积,在前传里是用好多个滤波器一个一个地卷积而后把结果(2D 的)一层一层地堆成一个 3D 的结构。
详细信息更有意思,请学习吴恩达的课程。
池化层很好玩,为了下降输入数据的大小,减小计算量,就有了池化层,同时池化层也会帮助特征检测器更独立于位置信息。这里介绍两种池化层:
最大池化层
滑动一个 (f,f) 大小的窗口到输入的数据上,在窗口里取最大的一个值为输出而后把这个值存到准备输出的数据里。
平均池化层
从名字就能够看出它须要一样地滑动一个 (f,f) 大小的窗口到输入数据上面,而后求窗口中数据的平均值,再把这个值储存到要输出的值里。
这些池化层没有参数能够被训练,但对于窗口的大小 f,你能够本身去尝试而后选择最好的。
在这一部分里吴老师讲了 TensorFlow 模型、建立占位符、初始参数、前向传播、计算损失及模型。
在这里咱们聊一聊怎么初始化参数吧。你须要用 tf.contrib.layers.xavier_initializer(seed=0) 来初始化权重/滤波器 W1 和 W2。你不须要担忧偏重值由于很快你就能发现 TensorFlow 函数已经解决了这一点。注意,你只需初始 conv2d 函数的权重/滤波器,TensorFlow 会自动初始全链接部分的层。咱们会在以后的做业里看到更多。
练习:实现 initialize_parameters(). 每一组滤波器/权重的维度已经提供给你们。记住,在 TensorFlow 里初始化一个形状为 [1,2,3,4] 的参数 W 用:
W = tf.get_variable("W", [1,2,3,4], initializer = ...)复制代码
More Info. 更多的信息:
More Info.更多的信息:
# GRADED FUNCTION: initialize_parameters
def initialize_parameters(): """ Initializes weight parameters to build a neural network with → tensorflow.Theshapesare: W1 : [4, 4, 3, 8] W2 : [2, 2, 8, 16] Returns: parameters -- a dictionary of tensors containing W1, W2 """
tf.set_random_seed(1) # so that your → "random"numbersmatchours
### 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
复制代码
这一部分讲了一个做业(幸福家),怎样用 Keras 建模型、总结、用本身的图片去测试其余很是有用的 Keras 函数。在这里咱们着重讲一下幸福家是什么:
3.3.1 幸福家
下一次放假旅行,你决定和你的 5 个在学校认识的朋友一块儿度过一周。这附近有一个很是方便的房子能够作不少事情。但最重要的福利是在房子里的时候每一个人都必需要快乐。因此每一个想进房间的人都要提供他们如今的幸福情形。
做为一个深度学习专家,要确保「开心」这一规则被坚定的执行了,你要去建一个算法来经过前门的摄像头获得的照片来检查这我的是否是开心。
你已经收集到了你和朋友在前门照的照片,数据库已经被标注了。0 表明不开心,1 表明开心。
跑一下下面的程序让数据库更加标准化,而后学习一下它的形态。
X_train_orig, Y_train_orig, X_test_orig, Y_test_orig, classes = → load_dataset()
# Normalize image vectors
X_train = X_train_orig/255.
X_test = X_test_orig/255.
# Reshape
Y_train = Y_train_orig.T
Y_test = Y_test_orig.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))
#output
number of training examples = 600
number of test examples = 150
X_train shape: (600, 64, 64, 3)
Y_train shape: (600, 1)
X_test shape: (150, 64, 64, 3)
Y_test shape: (150, 1)
复制代码
幸福家数据库的细节:
图片数据大小为 (64, 64, 3)
训练数据:600
测试数据:150
如今去解决「快乐」挑战吧!
这一部分介绍了很是深的深度神经网络的问题,如何构建残差模块、残差链接、卷积块等,并组合它们而建造第一个残差网络模型以及用本身的图片去实验。
残差网络能够解决一些很是深的深度神经网络所具备的问题,咱们在这里着重谈一下很是深的深度网络的问题。
近几年,神经网络变得愈来愈深了,最前沿的网络有几层的,也有超过一百层的。
深度神经网络最主要的优点是它能够表示很是复杂的函数。它也能够从不一样的抽象等级去学习从边缘特征(浅层)到复杂的特征(深层)。可是,用一个更深的神经网络不老是有效。一个大缺点是训练模型的时候梯度会消失:很是深的网络常常会很是快地梯度降低到 0。这样会让梯度降低变得不可忍受的慢,由于每一次只会更新一点点。更具体地,在梯度降低的时候,当你反向传播从最后一层一直到第一层的时候,每一步都在乘以权重矩阵,因此梯度会以指数函数的速率降低到 0(或者在有些极少的状况里,梯度以指数函数的速率产生爆炸)。
在训练的时候,你也能看到前面层的梯度数值很是快地降低到 0。
你如今能够用残差网络解决这个问题。
这一部分讲了:问题叙述、YOLO、模型细节、用一个门槛来过滤一个班的分数、非最大抑制、包装过滤器、在图片上测试 YOLO 模型、定义类、转折点和图片大小、加载一个训练好的模型、转化输出模型到一个可用的边界盒张量、过滤盒及对图片跑计算图。
在这里咱们讲一下问题是什么:
你如今在作一个自动驾驶车,做为一个重要的部分,你想先建一个车辆检测系统,当你开车时候这个系统会每隔几秒照一下前面的路。
你如今已经收集了全部的这些图片到一个文件夹里而后也已经用框标注出了每个你能够找到的车。这里是例子:
p 表明了你有多自信圈出来的是什么,c 表明了你认为圈出来的是什么。
若是你想让 YOLO 认出 80 种类别, 你可让 c 表示 1 到 80 中的一个数,或者 c 是一个 80 长度的矢量。视频课里已经用了后一种表示。在这个笔记里,咱们两种都用了,这取决于哪一种更好用。在这个练习里,你将要学习 YOLO 怎样工做,怎样运用这个区检测车。由于 YOLO 训练的时候很是耗费计算量,咱们将会加载训练好的权重来用。
在这一张里咱们能够看到:简略脸部识别,脸部图片编成一我的 128 维度的矢量,使用 ConvNet 来计算编码,三联损失,加载训练好的模型和运用训练好的模型。
咱们着重介绍一下简略脸部识别:
在脸部识别里,给你两张图片而后你必须告诉我两我的是不是同一个。最简单的作法是比较两张图片中的每个像素,若是两张原始图片的比较结果小于一个门槛值则能够说两张图片是一我的。
固然,这个算法的性能很是差,由于像素的值会随着光的改变,方向的改变,甚至镜像改变头的位置而剧烈的改变。你将看到除了用原始图片你更愿意编码一个 f(image) 来比较每个像素这样会给你一个关于两张照片是否是一我的的问题更准确的答案。
在这一章节中,咱们将尝试实现神经风格迁移,并使用算法生成新颖的艺术风格图像。在神经风格迁移中,重点是咱们须要优化成本函数得到像素的值。以下所示,咱们使用某张图像的风格,并迁移到须要这种风格的图像中:
神经风格迁移主要使用预训练的卷积神经网络,并在它的顶部构建新的层级。这种使用预训练模型,并将其应用到新任务的方法能够称为迁移学习。卷积网络的迁移学习很是简单,通常来讲,咱们能够将最后几个分类层的权重随机初始化,再在新的数据集上训练而快速得到优秀的性能。
在 NST 原论文中,咱们会使用 VGG-19 网络,它会预先在 ImageNet 上实现训练。所以在 Wan Zhen 的笔记中,咱们能够运行如下命令下载模型及参数;
model = load_vgg_model("pretrained-model/imagenet-vgg-verydeep-19.mat")
print(model)复制代码
而后使用 assign 方法将图像做为模型的输入:
model["input"].assign(image)复制代码
随后,咱们就能使用如下代码获取特定层级的激活值;
sess.run(model["conv4_2"])复制代码
在神经风格迁移中,重点是如下三个步骤:
构建须要迁移风格的图片损失函数 J_content(C, G)
构建风格损失函数 J_style(S, G)
将它们组合为最终的损失函数 J(G) =α J_content(C, G) +β J_style(S, G)
使用这样的损失函数,最终咱们能以迁移学习的方法实现神经风格迁移。