本文翻译自斯坦福大学吴恩达教授机器学习作业
欢迎来到您的第一次作业。这次的练习会像您简要的介绍 Python。尽管你可能从未使用过 Python,这也将帮助您熟悉我们所需要的函数。
操作指示
- 你需要使用 Python 3
- 避免使用显式 for 循环和 while 循环,除非题目要求
- 不要更改(# GRADED FUNCTION [function name])的注释
- 编写完函数后,运行 cell 确认你的输出是正确的
做完这个作业,你能学会
- 使用 IPython Notebooks
- 使用 numpy 的函数以及 numpy 的矩阵/向量运算
- 理解「广播」的概念
- 使用向量化的代码
关于 iPython Notebooks
IPython Notebooks 是嵌入在网页中的交互式编码环境。你将在会在这个课程中使用 IPython Notebooks。你只需要在 ### START CODE HERE ###
和 ### END CODE HERE ###
之间编写代码。编写完成后,你可以通过快捷键「Shift+Enter」或者在笔记本的页眉菜单栏点击「运行单元块」(长得像播放按钮图标)来运行单元块。
我们会在注释中指定 「(≈X lines of code)」来提示你需要些多少行代码。这只是一个粗略的估计,请不要担心如果你的代码实际用了更多的行数或更少的函数。
练习:将下面单元格的 test
的值设为 “Hello World”
然后运行下面两个单元格。
### START CODE HERE ### (≈ 1 line of code)
test = "Hello World"
### END CODE HERE ###
print ("test: " + test)
test: Hello World
期望的输出:test: Hello World
你需要记住:
- 运行你的单元格通过快捷键「Shift+Enter」或者点击「运行单元块」
- 在指定区域只能使用 Python 3 编码
- 请修改指定区域以外的代码
1 – 使用 numpy 构建基本函数
Numpy 是 Python 中主要的科学计算包。由大型社区 (www.numpy.org) 维护。在这个练习中,你将会学到几个关键的 numpy 函数,比如 np.exp, np.log 以及 np.reshape。你需要知道如何使用这些函数去完成练习。
1.1 – sigmoid function 和 np.exp()
在使用 np.exp() 之前,你讲使用 math.exp() 实现 Sigmoid 函数。然后你将知道为什么 np.exp() 比 math.exp() 更可取。
练习:构建一个返回实数x的 sigmoid 的函数。math.exp(x) 用于计算以e为底数x为指数的幂函数。
注意
sigmoid(x) = \frac{1}{1+e^{-x}}
有时候也被称为逻辑函数。它是一种非线性函数,不仅用于机器学习(逻辑回归)也用于深度学习。
要引用特定程序包的函数,可以使用 package_name.function() 对其进行调用。运行下面的代码以查看 math.exp() 的示例。
# GRADED FUNCTION: basic_sigmoid
import numpy as np
import math
import matplotlib.pyplot as plt
%matplotlib inline
def basic_sigmoid(x):
"""
Compute sigmoid of x.
Arguments:
x -- A scalar
Return:
s -- sigmoid(x)
"""
### START CODE HERE ### (≈ 1 line of code)
s = 1.0 / (1.0 + 1.0 / math.exp(x))
### END CODE HERE ###
return s
basic_sigmoid(3)
0.9525741268224334
x = np.linspace(-5,5,1000)
y = []
for i in range(1000):
y.append(basic_sigmoid(x[i]))
plt.plot(x,y,c="r")
[<matplotlib.lines.Line2D at 0x1147761c0>]
期待的输出:
basic_sigmoid(3) | 0.9525741268224334 |
事实上,我们很少在深度学习中使用 “math” 库,因为这些函数的输入都是实数。在深度学习中,我们主要用的是矩阵和向量。这就是为什么说 numpy 是更好用的。
### One reason why we use "numpy" instead of "math" in Deep Learning ###
x = [1, 2, 3]
basic_sigmoid(x) # you will see this give an error when you run it, because x is a vector.
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-12-8ccefa5bf989> in <module> 1 ### One reason why we use "numpy" instead of "math" in Deep Learning ### 2 x = [1, 2, 3] ----> 3 basic_sigmoid(x) # you will see this give an error when you run it, because x is a vector. <ipython-input-9-080ae0163223> in basic_sigmoid(x) 17 18 ### START CODE HERE ### (≈ 1 line of code) ---> 19 s = 1.0 / (1.0 + 1.0 / math.exp(x)) 20 ### END CODE HERE ### 21 TypeError: must be real number, not list
事实上,如果 x=(x_1, x_2, ..., x_n) 是一个行向量,那么 np.exp(x) 会将e的指数函数应用于每个元素。因此输出为:n.exp(x)=(e^{x_1}, e^{x_2}, ..., e^{x_n})
import numpy as np
# example of np.exp
x = np.array([1, 2, 3])
print(np.exp(x)) # result is (exp(1), exp(2), exp(3))
[ 2.71828183 7.3890561 20.08553692]
此外,如果 x 是一个向量,那么 s=x+3 或s=\frac{1}{x} 之类的 Python 运算符将输出与 x 维度相同的向量。
# example of vector operation
x = np.array([1, 2, 3])
print (x + 3)
[4 5 6]
# GRADED FUNCTION: sigmoid
import numpy as np # this means you can access numpy functions by writing np.function() instead of numpy.function()
def sigmoid(x):
"""
Compute the sigmoid of x
Arguments:
x -- A scalar or numpy array of any size
Return:
s -- sigmoid(x)
"""
### START CODE HERE ### (≈ 1 line of code)
s = 1.0 / (1.0 + np.exp(-1.0 * x))
### END CODE HERE ###
return s
x = np.array([1, 2, 3])
sigmoid(x)
print(sigmoid(x))
x = np.linspace(-15,15,1000)
y = sigmoid(x)
plt.plot(x,y,c="r")
plt.show()
[0.73105858 0.88079708 0.95257413]
你可以查看官方文档去获取更多有关numpy函数的信息。
也可以在笔记本中创建一个新单元格,并编写np.exp?
(例如)快速访问文档。
练习:使用numpy实现sigmoid函数。
说明:x可以是实数,向量或矩阵。 我们在numpy中使用的表示向量、矩阵等的数据结构称为numpy数组。现阶段你只需了解这些就已足够。
\text{For } x \in \mathbb{R}^n \text{, } sigmoid(x) = sigmoid\begin{pmatrix} x_1 \\ x_2 \\ ... \\ x_n \\ \end{pmatrix} = \begin{pmatrix} \frac{1}{1+e^{-x_1}} \\ \frac{1}{1+e^{-x_2}} \\ ... \\ \frac{1}{1+e^{-x_n}} \\ \end{pmatrix}\tag{1}
期待的输出:
sigmoid([1,2,3]) | array([ 0.73105858, 0.88079708, 0.95257413]) |
x = np.array([1,2,3])
print(x)
print(x.shape)
print(x.shape[0])
[1 2 3](3,)
3
1.2 – Sigmoid gradient
正如我们在课程中看到的,你需要计算梯度来使用反向传播优化损失函数。让我们开始编写第一个梯度函数吧。
练习:实现函数 sigmoid_grad() 去计算 sigmoid 函数相对于其输入x的梯度,公式为
sigmoid\_derivative(x) = \sigma'(x)=\sigma(x)(1-x) \qquad (2)
你需要按照下面这两步编写函数:
- 将 s 赋值为 x 的 sigmoid 值。你会发现你的写的 sigmoid(x) 函数很好用。
- 计算 \sigma'(x)=s(1-s)
# GRADED FUNCTION: sigmoid_derivative
def sigmoid_derivative(x):
"""
Compute the gradient (also called the slope or derivative) of the sigmoid function with respect to its input x.
You can store the output of the sigmoid function into variables and then use it to calculate the gradient.
Arguments:
x -- A scalar or numpy array
Return:
ds -- Your computed gradient.
"""
### START CODE HERE ### (≈ 2 lines of code)
s = sigmoid(x)
ds = s * (1 - s)
### END CODE HERE ###
return ds
x = np.array([1, 2, 3])
print ("sigmoid_derivative(x) = " + str(sigmoid_derivative(x)))
x = np.linspace(-15,15,1000)
y = sigmoid_derivative(x)
plt.plot(x,y,c="r")
plt.show()
sigmoid_derivative(x) = [0.19661193 0.10499359 0.04517666]
期待的输出:
sigmoid_derivative([1,2,3]) | [ 0.19661193 0.10499359 0.04517666] |
1.3 – 重塑数组
深度学习中两个常用的 numpy 函数是 np.shape 和 np.reshape()
- X.shape 用于获取矩阵/向量X的 shape(维度)
- X.reshape(…) 用于将 X 重塑为其他尺寸。
例如,在计算机科学中,一张图片由 shape 为
(𝑙𝑒𝑛𝑔𝑡ℎ,ℎ𝑒𝑖𝑔ℎ𝑡,𝑑𝑒𝑝𝑡ℎ=3) 的数组表示。
然而,当你读取读取一张图片作为算法的输入时,会将其转换为维度为(length * height * 3, 1) 的向量。换句话说,你可以将 3D 的数组“展开”,或者将其重塑为一个 1D 的向量。
练习:实现 image2vector()
, 输入为 shape(length, height, 3),返回 shape 为 (length*height*3, 1) 的向量。例如,你将要变形一个 shape(a, b, c) 的数组 v 为一个 shape(a*b, c) 的向量,你需要做:
v = v.reshape((v.shape[0]*v.shape[1], v.shape[2]))
# v.shape[0] = a ; v.shape[1] = b ; v.shape[2] = c
请不要将图片的维度定义为一个常量,而是通过 imgage.shape[0]
等来查找需要的数量。
# GRADED FUNCTION: image2vector
def image2vector(image):
"""
Argument:
image -- a numpy array of shape (length, height, depth)
Returns:
v -- a vector of shape (length*height*depth, 1)
"""
### START CODE HERE ### (≈ 1 line of code)
v = image.reshape((image.shape[0] * image.shape[1] * image.shape[2],1))
### END CODE HERE ###
return v
# This is a 3 by 3 by 2 array, typically images will be (num_px_x, num_px_y,3) where 3 represents the RGB values
image = np.array([[[ 0.67826139, 0.29380381],
[ 0.90714982, 0.52835647],
[ 0.4215251 , 0.45017551]],
[[ 0.92814219, 0.96677647],
[ 0.85304703, 0.52351845],
[ 0.19981397, 0.27417313]],
[[ 0.60659855, 0.00533165],
[ 0.10820313, 0.49978937],
[ 0.34144279, 0.94630077]]])
print ("image2vector(image) = " + str(image2vector(image)))
image2vector(image) = [[0.67826139] [0.29380381] [0.90714982] [0.52835647] [0.4215251 ] [0.45017551] [0.92814219] [0.96677647] [0.85304703] [0.52351845] [0.19981397] [0.27417313] [0.60659855] [0.00533165] [0.10820313] [0.49978937] [0.34144279] [0.94630077]]
期待的输出
image2vector(image) | [[ 0.67826139] [ 0.29380381] [ 0.90714982] [ 0.52835647] [ 0.4215251 ] [ 0.45017551] [ 0.92814219] [ 0.96677647] [ 0.85304703] [ 0.52351845] [ 0.19981397] [ 0.27417313] [ 0.60659855] [ 0.00533165] [ 0.10820313] [ 0.49978937] [ 0.34144279] [ 0.94630077]] |
1.4 – 行标准化
另一个我们常用语机器学习和深度学习的技术是将我们的数据标准化。 这将会带来更好的性能,因为梯度下降在归一化之后收敛更快。这里通过归一化,也就是将x 更改为
\frac{x} {||x||}
(将 x 的每个行向量除以其范数)
举个例子,如果
x=\begin{bmatrix} 0 & 3 & 4 \\ 2 & 6 & 4 \\ \end{bmatrix}\tag{3}
那么
\| x\| = np.linalg.norm(x, axis = 1, keepdims = True) = \begin{bmatrix} 5 \\ \sqrt{56} \\ \end{bmatrix}\tag{4}
x\_normalized = \frac{x}{\| x\|} = \begin{bmatrix} 0 & \frac{3}{5} & \frac{4}{5} \\ \frac{2}{\sqrt{56}} & \frac{6}{\sqrt{56}} & \frac{4}{\sqrt{56}} \\ \end{bmatrix}\tag{5}
注意,你可以划分不同大小的矩阵来获得更好的效果:这被称为 广播(broadcasting),我们将在第五部分中学习它。
练习:执行 normalizeRows() 来标准化矩阵的行。将此函数应用于矩阵x的输入,x中的每一行应为单位长度(长度为1)的向量。
# GRADED FUNCTION: normalizeRows
def normalizeRows(x):
"""
Implement a function that normalizes each row of the matrix x (to have unit length).
Argument:
x -- A numpy matrix of shape (n, m)
Returns:
x -- The normalized (by row) numpy matrix. You are allowed to modify x.
"""
### START CODE HERE ### (≈ 2 lines of code)
# Compute x_norm as the norm 2 of x. Use np.linalg.norm(..., ord = 2, axis = ..., keepdims = True)
x_norm = np.linalg.norm(x, axis = 1, keepdims = True)
# Divide x by its norm.
x = x / x_norm
### END CODE HERE ###
return x
x = np.array([
[0, 3, 4],
[1, 6, 4]])
print("normalizeRows(x) = " + str(normalizeRows(x)))
normalizeRows(x) = [[0. 0.6 0.8 ] [0.13736056 0.82416338 0.54944226]]
预期输出:
normalizeRows(x)=[[ 0. 0.6 0.8 ]
[ 0.13736056 0.82416338 0.54944226]]
注意:在 normalizeRows() 中,你可以尝试将 x_norm 和 x 的 shapes 打印出来再返回。你会发现他们的 shapes 是不同的。这是正常的,因为 x_norm 取 x 每一行的范数,所以 x_norm(与 x)有相同的行数,但是只有1列。那么当 x 除以 x_norm 时他是如何工作的呢?这就是广播,我们现在就来学习!
1.5 – 广播和 softmax 函数
在 numpy 中,有一个非常重要的的概念是“广播”(boardcasting)。这对于在不同形状的数组之间做数学运算非常有用。有关广播的完整详细信息,你可以阅读官方的broadcasting documentation.
练习:使用 numpy 实现 softmax 函数。你可以将 softmax 理解为算法需要对两个或多个类进行分类时使用的标准化函数。你将在本专业的第二门课中学到更多的 softmax 知识。
指示:
\text{for } x \in \mathbb{R}^{1\times n} \text{, } softmax(x) = softmax(\begin{bmatrix} x_1 && x_2 && ... && x_n \end{bmatrix}) \\ = \begin{bmatrix} \frac{e^{x_1}}{\sum_{j}e^{x_j}} && \frac{e^{x_2}}{\sum_{j}e^{x_j}} && ... && \frac{e^{x_n}}{\sum_{j}e^{x_j}} \end{bmatrix}
\text{for a matrix } x \in \mathbb{R}^{m \times n} \\ \text{$x_{ij}$ maps to the element in the $i^{th}$ row and $j^{th}$ column of $x$, thus we have: } \\softmax(x) = softmax\begin{bmatrix} x_{11} & x_{12} & x_{13} & \dots & x_{1n} \\ x_{21} & x_{22} & x_{23} & \dots & x_{2n} \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ x_{m1} & x_{m2} & x_{m3} & \dots & x_{mn} \end{bmatrix} \\ = \begin{bmatrix} \frac{e^{x_{11}}}{\sum_{j}e^{x_{1j}}} & \frac{e^{x_{12}}}{\sum_{j}e^{x_{1j}}} & \frac{e^{x_{13}}}{\sum_{j}e^{x_{1j}}} & \dots & \frac{e^{x_{1n}}}{\sum_{j}e^{x_{1j}}} \\ \frac{e^{x_{21}}}{\sum_{j}e^{x_{2j}}} & \frac{e^{x_{22}}}{\sum_{j}e^{x_{2j}}} & \frac{e^{x_{23}}}{\sum_{j}e^{x_{2j}}} & \dots & \frac{e^{x_{2n}}}{\sum_{j}e^{x_{2j}}} \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ \frac{e^{x_{m1}}}{\sum_{j}e^{x_{mj}}} & \frac{e^{x_{m2}}}{\sum_{j}e^{x_{mj}}} & \frac{e^{x_{m3}}}{\sum_{j}e^{x_{mj}}} & \dots & \frac{e^{x_{mn}}}{\sum_{j}e^{x_{mj}}} \end{bmatrix} \\ = \begin{pmatrix} softmax\text{(first row of x)} \\ softmax\text{(second row of x)} \\ ... \\ softmax\text{(last row of x)} \\ \end{pmatrix}
# GRADED FUNCTION: softmax
def softmax(x):
"""Calculates the softmax for each row of the input x.
Your code should work for a row vector and also for matrices of shape (n, m).
Argument:
x -- A numpy matrix of shape (n,m)
Returns:
s -- A numpy matrix equal to the softmax of x, of shape (n,m)
"""
### START CODE HERE ### (≈ 3 lines of code)
# Apply exp() element-wise to x. Use np.exp(...).
x_exp = np.exp(x)
# Create a vector x_sum that sums each row of x_exp. Use np.sum(..., axis = 1, keepdims = True).
x_sum = np.sum(x_exp,axis=1,keepdims=True)
# Compute softmax(x) by dividing x_exp by x_sum. It should automatically use numpy broadcasting.
s = x_exp / x_sum
### END CODE HERE ###
return s
x = np.array([
[9, 2, 5, 0, 0],
[7, 5, 0, 0 ,0]])
print("softmax(x) = " + str(softmax(x)))
softmax(x) = [[9.80897665e-01 8.94462891e-04 1.79657674e-02 1.21052389e-04 1.21052389e-04] [8.78679856e-01 1.18916387e-01 8.01252314e-04 8.01252314e-04 8.01252314e-04]]
期待的输出:
softmax(x) | [[ 9.80897665e-01 8.94462891e-04 1.79657674e-02 1.21052389e-04 1.21052389e-04] [ 8.78679856e-01 1.18916387e-01 8.01252314e-04 8.01252314e-04 8.01252314e-04]] |
注意:如果你在上面把 x_exp, x_sum 以及 s 的 shapes 打印出来,并运行单元格,你会发现 x_sum 是 shape (2, 1) 而 x_exp 和 s 都是 shape 为 (2, 5) 的矩阵。x_exp/x_sum
的计算通过 Python 的广播 (boardcasting)。
恭喜你!现在你已经对 Python numpy 有了很好的理解,并实现了一些在深度学习中用到的函数。
你需要注意的是:
- np.exp(x) 适用于任何 np.array 类型的 x,并将 e 的指数函数应用于每一个元素。
- sigmoid 函数及其梯度
- image2vector 常用于深度学习。
- np.reshape 被广泛用于。在未来,你将会看到,保持你的矩阵/向量维度不变有助于减少很多 bugs。
- numpy 具有高效的内置功能
- 广播(boardcasting) 非常好用
2 – 向量化
在深度学习中,你需要处理非常大的数据集。因此,非计算最佳函数 (non-computationally-optimal function) 可能会成为算法中的瓶颈,并且可能会让模型的运行时间过长。为了确保你的代码的计算是高效的,你需要用到向量化(vectorization)。例如,尝试说出分点/外部/元素乘积之间的区别。
import time
x1 = [9, 2, 5, 0, 0, 7, 5, 0, 0, 0, 9, 2, 5, 0, 0]
x2 = [9, 2, 2, 9, 0, 9, 2, 5, 0, 0, 9, 2, 5, 0, 0]
### CLASSIC DOT PRODUCT OF VECTORS IMPLEMENTATION ###
tic = time.process_time()
dot = 0
for i in range(len(x1)):
dot+= x1[i]*x2[i]
toc = time.process_time()
print ("dot = " + str(dot) + "\n ----- Computation time = " + str(1000*(toc - tic)) + "ms")
### CLASSIC OUTER PRODUCT IMPLEMENTATION ###
tic = time.process_time()
outer = np.zeros((len(x1),len(x2))) # we create a len(x1)*len(x2) matrix with only zeros
for i in range(len(x1)):
for j in range(len(x2)):
outer[i,j] = x1[i]*x2[j]
toc = time.process_time()
print ("outer = " + str(outer) + "\n ----- Computation time = " + str(1000*(toc - tic)) + "ms")
### CLASSIC ELEMENTWISE IMPLEMENTATION ###
tic = time.process_time()
mul = np.zeros(len(x1))
for i in range(len(x1)):
mul[i] = x1[i]*x2[i]
toc = time.process_time()
print ("elementwise multiplication = " + str(mul) + "\n ----- Computation time = " + str(1000*(toc - tic)) + "ms")
### CLASSIC GENERAL DOT PRODUCT IMPLEMENTATION ###
W = np.random.rand(3,len(x1)) # Random 3*len(x1) numpy array
tic = time.process_time()
gdot = np.zeros(W.shape[0])
for i in range(W.shape[0]):
for j in range(len(x1)):
gdot[i] += W[i,j]*x1[j]
toc = time.process_time()
print ("gdot = " + str(gdot) + "\n ----- Computation time = " + str(1000*(toc - tic)) + "ms")
dot = 278 ----- Computation time = 0.10499999999957765ms outer = [[81. 18. 18. 81. 0. 81. 18. 45. 0. 0. 81. 18. 45. 0. 0.] [18. 4. 4. 18. 0. 18. 4. 10. 0. 0. 18. 4. 10. 0. 0.] [45. 10. 10. 45. 0. 45. 10. 25. 0. 0. 45. 10. 25. 0. 0.] [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [63. 14. 14. 63. 0. 63. 14. 35. 0. 0. 63. 14. 35. 0. 0.] [45. 10. 10. 45. 0. 45. 10. 25. 0. 0. 45. 10. 25. 0. 0.] [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [81. 18. 18. 81. 0. 81. 18. 45. 0. 0. 81. 18. 45. 0. 0.] [18. 4. 4. 18. 0. 18. 4. 10. 0. 0. 18. 4. 10. 0. 0.] [45. 10. 10. 45. 0. 45. 10. 25. 0. 0. 45. 10. 25. 0. 0.] [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]] ----- Computation time = 0.2300000000001745ms elementwise multiplication = [81. 4. 10. 0. 0. 63. 10. 0. 0. 0. 81. 4. 25. 0. 0.] ----- Computation time = 0.27100000000057634ms gdot = [19.09952576 19.15860659 22.15014212] ----- Computation time = 0.17800000000001148ms
x1 = [9, 2, 5, 0, 0, 7, 5, 0, 0, 0, 9, 2, 5, 0, 0]
x2 = [9, 2, 2, 9, 0, 9, 2, 5, 0, 0, 9, 2, 5, 0, 0]
### VECTORIZED DOT PRODUCT OF VECTORS ###
tic = time.process_time()
dot = np.dot(x1,x2)
toc = time.process_time()
print ("dot = " + str(dot) + "\n ----- Computation time = " + str(1000*(toc - tic)) + "ms")
### VECTORIZED OUTER PRODUCT ###
tic = time.process_time()
outer = np.outer(x1,x2)
toc = time.process_time()
print ("outer = " + str(outer) + "\n ----- Computation time = " + str(1000*(toc - tic)) + "ms")
### VECTORIZED ELEMENTWISE MULTIPLICATION ###
tic = time.process_time()
mul = np.multiply(x1,x2)
toc = time.process_time()
print ("elementwise multiplication = " + str(mul) + "\n ----- Computation time = " + str(1000*(toc - tic)) + "ms")
### VECTORIZED GENERAL DOT PRODUCT ###
tic = time.process_time()
dot = np.dot(W,x1)
toc = time.process_time()
print ("gdot = " + str(dot) + "\n ----- Computation time = " + str(1000*(toc - tic)) + "ms")
dot = 278 ----- Computation time = 0.11699999999947863ms outer = [[81 18 18 81 0 81 18 45 0 0 81 18 45 0 0] [18 4 4 18 0 18 4 10 0 0 18 4 10 0 0] [45 10 10 45 0 45 10 25 0 0 45 10 25 0 0] [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [63 14 14 63 0 63 14 35 0 0 63 14 35 0 0] [45 10 10 45 0 45 10 25 0 0 45 10 25 0 0] [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [81 18 18 81 0 81 18 45 0 0 81 18 45 0 0] [18 4 4 18 0 18 4 10 0 0 18 4 10 0 0] [45 10 10 45 0 45 10 25 0 0 45 10 25 0 0] [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]] ----- Computation time = 0.2149999999998542ms elementwise multiplication = [81 4 10 0 0 63 10 0 0 0 81 4 25 0 0] ----- Computation time = 0.1020000000000465ms gdot = [19.09952576 19.15860659 22.15014212] ----- Computation time = 0.10400000000032605ms
你可能注意到了,向量化的实现方式更简洁且更高效。对于更大型的向量/矩阵,运行时间的差别会更大。
注意 np.dot()
执行的是矩阵-矩阵或矩阵-向量乘法。这是不同于 np.multiply()
以及运算符 *
(相当于 Matlab/Octave 中的 .*
)执行的是逐个元素之间的乘法。
2.1 实现 L1 和 L2 损失函数
练习:实现 numpy 向量化版本的 L1 损失函数。你会发现 abs(x) 函数(求 x 的绝对值)非常有用。
提醒:
- 损失函数用于评估你的模型的性能。损失越大,预测 (𝑦̂) 和真实值 (𝑦) 的差异就越大。在深度学习中,我们使用优化算法如梯度下降 (Gradient Descent) 去训练你的模型并降低成本 (cost)。
- L1 损失被定义为:
L_1(\hat{y}, y) = \sum_{i=0}^m|y^{(i)} - \hat{y}^{(i)}|\tag{6}
# GRADED FUNCTION: L1
def L1(yhat, y):
"""
Arguments:
yhat -- vector of size m (predicted labels)
y -- vector of size m (true labels)
Returns:
loss -- the value of the L1 loss function defined above
"""
### START CODE HERE ### (≈ 1 line of code)
loss = np.sum(np.abs(y - yhat))
### END CODE HERE ###
return loss
yhat = np.array([.9, 0.2, 0.1, .4, .9])
y = np.array([1, 0, 0, 1, 1])
print("L1 = " + str(L1(yhat,y)))
L1 = 1.1
期待的输出:
L1 | 1.1 |
练习:实现 numpy 向量化版本的 L2 损失函数。实现 L2 损失函数的方法有很多,但你可能会发现 np.dot() 更好用。提醒一下,如果x = [x_1, x_2, …, x_n], 则 np.dot(x,x) = \sum_{j=0}^n x_j^{2}
- L2 函数被定义为
L_2(\hat{y}, y) = \sum_{i=0}^{m}(y^{(i)} - \hat{y}^{(i)})^2\tag{7}
# GRADED FUNCTION: L2
def L2(yhat, y):
"""
Arguments:
yhat -- vector of size m (predicted labels)
y -- vector of size m (true labels)
Returns:
loss -- the value of the L2 loss function defined above
"""
### START CODE HERE ### (≈ 1 line of code)
loss = np.sum(np.power(y - yhat, 2))
### END CODE HERE ###
return loss
yhat = np.array([.9, 0.2, 0.1, .4, .9])
y = np.array([1, 0, 0, 1, 1])
print("L2 = " + str(L2(yhat,y)))
L2 = 0.43
期待的输出:
L2 | 0.43 |
祝贺你完成这次的作业。我们希望这个小小的热身练习能给你未来的作业带来帮助,这会更令人兴奋和有趣!
你需要记住的是:
- 向量化在深度学习中非常重要。它保证了计算的效率和简洁。
- 了解 L1 和 L2 损失函数。
- 掌握 numpy 函数,例如,np.sum, np.dot, np.multiply, np.maximum 等。
文章最后修订于 2021年1月30日
评论 (0)