吴恩达《神经网络和深度学习》第二周编程作业—numpy入门,函数向量化实现

吴恩达《神经网络和深度学习》—numpy入门,函数向量化实现

※※※※※下一篇:【用神经网络思想实现逻辑回归】※※※※※

做完该作业将掌握的技能:
∙ \bullet ∙ 会使用numpy,包括函数调用及向量矩阵运算
∙ \bullet ∙ 理解广播的概念
∙ \bullet ∙ 向量化实现

1 使用numpy构建基本函数

Numpy是Python中主要的科学计算包。在本练习中,你将学习一些关键的 numpy函数,例如 np.expnp.lognp.reshape

1.1 sigmoid function和np.exp()

在使用 np.exp()之前,你将使用 math.exp()实现 Sigmoid函数。然后,你将知道为什么 np.exp()math.exp()更可取。

【练习】:构建一个返回实数 x x x 的 sigmoid 的函数。将 math.exp(x)用于指数函数。

【提示】:s i g m o i d ( x ) = 1 1 + e − x sigmoid\left ( x \right )=\frac{1}{1+e^{-x}}s i g m o i d (x )=1 +e −x 1 ​有时也称为逻辑函数。它是一种非线性函数,即可用于机器学习(逻辑回归),也能用于深度学习。

【代码】


import math

def basic_sigmoid(x):
"""
    Compute sigmoid of x.

    Arguments:
    x -- A scalar

    Return:
    s -- sigmoid(x)
"""

    s = 1 / (1 + math.exp(-x))

    return s

result = basic_sigmoid(3)
print("result: " + str(result))

【结果】

result: 0.9525741268224334

因为函数的输入是实数,而深度学习中主要使用的是矩阵和向量,因此很少在深度学习中使用 math库,使用更多的是 numpy库。

如果对上述代码稍作修改,把输入变量 x x x 变成一个向量,如下所示:

【代码】


import math

def basic_sigmoid(x):
"""
    Compute sigmoid of x.

    Arguments:
    x -- A scalar

    Return:
    s -- sigmoid(x)
"""

    s = 1 / (1 + math.exp(-x))

    return s

x = [1, 2, 3]
result = basic_sigmoid(x)

将看到如下报错信息:

【结果】

Traceback (most recent call last):
  File "C:\Users\Dell\Desktop\AI_math_ws\2-15\1.py", line 24, in <module>
    result = basic_sigmoid(x)
  File "C:\Users\Dell\Desktop\AI_math_ws\2-15\1.py", line 17, in basic_sigmoid
    s = 1 / (1 + math.exp(-x))
TypeError: bad operand type for unary -: 'list'

如果 x = ( x 1 , x 2 , ⋯ , x n ) \mathbf{x} = \left ( x_{1},x_{2},\cdots ,x_{n} \right )x =(x 1 ​,x 2 ​,⋯,x n ​) 是行向量,则 np.exp(x)会将指数函数应用于 x \mathbf{x}x 的每个元素。 因此,输出为:n p . e x p ( x ) = ( e x 1 , e x 2 , ⋯ , e x n ) np.exp(\mathbf{x})=\left ( e^{x_{1}}, e^{x_{2}}, \cdots , e^{x_{n}}\right )n p .e x p (x )=(e x 1 ​,e x 2 ​,⋯,e x n ​)。

【代码】

import numpy as np

x = np.array([1, 2, 3])
print(np.exp(x))

【结果】

[ 2.71828183  7.3890561  20.08553692]

如果 x \mathbf{x}x 是向量,则 s = x + 3 \mathbf{s}=\mathbf{x}+3 s =x +3或 s = 1 x \mathbf{s} = \frac{1}{\mathbf{x}}s =x 1 ​ 之类的Python运算将输出与 x \mathbf{x}x 维度大小相同的向量 s \mathbf{s}s。

【代码】


x = np.array([1, 2, 3])
print(x + 3)

【结果】

[4 5 6]

【练习】:使用 numpy实现 sigmoid函数。

【说明】:x x x 可以是实数,向量或矩阵。 我们在 numpy中使用的表示向量、矩阵等的数据结构称为 numpy数组。

吴恩达《神经网络和深度学习》第二周编程作业—numpy入门,函数向量化实现
【代码】

import numpy as np

def sigmoid(x):
"""
    Compute the sigmoid of x

    Arguments:
    x -- A scalar or numpy array of any size

    Return:
    s -- sigmoid(x)
"""

    s = 1 / (1 + np.exp(-x))

    return s

x = np.array([1, 2, 3])
result = sigmoid(x)
print("result: " + str(result))

【结果】

result: [0.73105858 0.88079708 0.95257413]

1.2 Sigmoid gradient

正如你在教程中所看到的,我们需要计算梯度来使用反向传播优化损失函数。 让我们开始编写第一个梯度函数吧。

【练习】:创建函数 sigmoid_grad()计算 sigmoid函数相对于其输入 x x x 的梯度。 公式为:s i g m o i d d e r i v a t i v e ( x ) = σ ′ ( x ) = σ ( x ) ( 1 − σ ( x ) ) sigmoid_derivative(x) = \sigma ^{‘}(x) = \sigma (x)(1-\sigma (x))s i g m o i d d ​e r i v a t i v e (x )=σ′(x )=σ(x )(1 −σ(x ))

【提示】:我们通常分两步编写此函数代码:

(1)将 s s s 设为 x x x 的 sigmoid
(2)计算 σ ′ ( x ) = s ( 1 − s ) \sigma ^{‘}(x) =s(1-s)σ′(x )=s (1 −s )

【代码】


import numpy as np

def sigmoid(x):
"""
    Compute the sigmoid of x

    Arguments:
    x -- A scalar or numpy array of any size

    Return:
    s -- sigmoid(x)
"""

    s = 1 / (1 + np.exp(-x))

    return s

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.

"""

    s = sigmoid(x)
    ds = s * (1 - s)

    return ds

x = np.array([1, 2, 3])
print("sigmoid_derivative(x) = " + str(sigmoid_derivative(x)))

【结果】

sigmoid_derivative(x) = [0.19661193 0.10499359 0.04517666]

1.3 重塑数组

深度学习中两个常用的 numpy函数是 np.shapenp.reshape()

∙ \bullet ∙ X.shape用于获取矩阵/向量X的shape(维度)
∙ \bullet ∙ X.reshape(…)用于将X重塑为其他尺寸

例如,在计算机科学中,图像由 shape(length, height, depth = 3)的3D数组表示。但是,当你读取图像作为算法的输入时,会将其转换为维度为 (length*height*3, 1)的向量。换句话说,将3D阵列”展开”或重塑为1D向量。

吴恩达《神经网络和深度学习》第二周编程作业—numpy入门,函数向量化实现

【练习】:实现 image2vector(),该输入采用维度为 (length, height, 3)的输入,并返回维度为 (length*height*3, 1)的向量。

【说明】:例如,如果你想将形为( a , b , c ) (a,b,c)(a ,b ,c )的数组 v v v 重塑为维度为( a ∗ b , 3 ) (a*b, 3)(a ∗b ,3 )的向量,则可以执行以下操作:

v = v.reshape((v.shape[0]*v.shape[1], v.shape[2]))

请不要将图像的尺寸硬编码为常数。而是通过 image.shape[0]等来查找所需的数量。

【代码】


import numpy as np

def image2vector(image):
"""
    Argument:
    image -- a numpy array of shape (length, height, depth)

    Returns:
    v -- a vector of shape (length*height*depth, 1)
"""

    v = image.reshape(image.shape[0] * image.shape[1] * image.shape[2], 1)

    return v

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]]

1.4 行标准化

我们在机器学习和深度学习中使用的另一种常见技术是对数据进行标准化。 由于归一化后梯度下降的收敛速度更快,通常会表现出更好的效果。 通过归一化,也就是将 x x x 更改为 x ∥ x ∥ \frac{x}{\left \| x \right \|}∥x ∥x ​(将 x x x 的每个行向量除以其范数)。

例如:x = [ 0 3 4 2 6 4 ] x = \begin{bmatrix} 0 & 3 & 4\ 2 & 6 & 4 \end{bmatrix}x =[0 2 ​3 6 ​4 4 ​]

吴恩达《神经网络和深度学习》第二周编程作业—numpy入门,函数向量化实现
【练习】:执行 normalizeRows()来标准化矩阵的行。 将此函数应用于输入矩阵 x x x 之后,x x x 的每一行应为单位长度(即长度为1)向量。

【代码】


import numpy as np

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.

"""

    x_norm = np.linalg.norm(x, axis=1, keepdims=True)

    x = x / x_norm

    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)中,你可以尝试 print查看 x_norm和 x x x 的维度,然后重新运行练习。 你会发现它们具有不同的维度。 鉴于 x_norm采用 x x x 的每一行的范数,这是正常的。因此, x_norm与 x x x 有相同的行数,但只有1列。 那么,当你将 x x x 除以 x_norm时,它是如何工作的? 这就是所谓的广播 broadcasting,我们现在将讨论它!

1.5 广播和softmax函数

numpy中要理解的一个非常重要的概念是”广播”。 这对于在不同形状的数组之间执行数学运算非常有用。有关广播的完整详细信息,你可以阅读官方的broadcasting documentation.

【练习】:使用 numpy实现 softmax函数。 你可以将 softmax理解为算法需要对两个或多个类进行分类时使用的标准化函数。

【说明】

吴恩达《神经网络和深度学习》第二周编程作业—numpy入门,函数向量化实现
【代码】

import numpy as np

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)
"""

    x_exp = np.exp(x)

    x_sum = np.sum(x_exp, axis=1, keepdims=True)

    s = x_exp / x_sum

    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]]

【注意】:如果你在上方输出 x_expx_sums的维度并重新运行练习单元,则会看到 x_sum的纬度为( 2 , 1 ) (2,1)(2 ,1 ),而 x_exps的维度为( 2 , 5 ) (2,5)(2 ,5 )。 x_exp/x_sum可以使用python广播。

2 向量化

2.1 向量和矩阵的点积、内积和对应元素逐个相乘运算

在深度学习中,通常需要处理非常大的数据集。 因此,非计算最佳函数可能会成为算法中的巨大瓶颈,并可能使模型运行一段时间。 为了确保代码的高效计算,我们将使用向量化。 在这里,需要重点区分点积( dot product)、外积( outer product)和对应元素逐个相乘( element-wise)。

首先,我们使用 for循环来实现向量和向量以及矩阵和向量的上述三种运算。

【代码】

import numpy as np
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]

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")

tic = time.process_time()
outer = np.zeros((len(x1), len(x2)))
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")

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")

W = np.random.rand(3, len(x1))
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.08447300000002933ms
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.22404599999992225ms
elementwise multiplication = [81.  4. 10.  0.  0. 63. 10.  0.  0.  0. 81.  4. 25.  0.  0.]
 ----- Computation time = 0.10582699999994727ms
gdot = [26.19713459 12.20793127 23.40980652]
 ----- Computation time = 0.15482099999997168ms

然后,我们使用向量化来实现上述运算。

【代码】

import numpy as np
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]

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")

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")

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")

W = np.random.rand(3, len(x1))
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.0ms
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.0ms
elementwise multiplication = [81  4 10  0  0 63 10  0  0  0 81  4 25  0  0]
 ----- Computation time = 0.0ms
gdot = [21.71177187 29.73904226 17.07432149]
 ----- Computation time = 0.0ms

你可能注意到了,向量化的实现更加简洁高效。对于更大的向量/矩阵,运行时间的差异变得更大。

2.2 实现L1和L2损失函数

【练习】:实现L1损失函数的Numpy向量化版本。 我们会发现函数 abs(x)(x x x 的绝对值)很有用。

【说明】:损失函数用于评估模型的性能。 损失越大,预测值 y ^ \hat{y}y ^​ 与真实值 y y y 之间的差异也就越大。在深度学习中,我们使用诸如梯度下降算法(Gradient Descent)之类的优化算法来训练模型并最大程度地降低成本。L1损失函数定义为:

吴恩达《神经网络和深度学习》第二周编程作业—numpy入门,函数向量化实现
【代码】

import numpy as np

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
"""

    loss = np.sum(np.abs(y - yhat))

    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

【练习】:实现L2损失函数的Numpy向量化版本。有好几种方法可以实现L2损失函数,但是还是 np.dot()函数更好用。L2损失函数定义为:

吴恩达《神经网络和深度学习》第二周编程作业—numpy入门,函数向量化实现

【代码】


import numpy as np

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
"""

    loss = np.dot((y - yhat), (y - yhat).T)

    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

Original: https://blog.csdn.net/qq_29923461/article/details/121222457
Author: Roar冷颜
Title: 吴恩达《神经网络和深度学习》第二周编程作业—numpy入门,函数向量化实现

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/761192/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球