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

做完该作业将掌握的技能:
  

bullet

会使用numpy,包括函数调用及向量矩阵运算
  

bullet

理解Python中“广播”的概念
  

bullet

利用Python代码实现向量化

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

xsigmoid 的函数。将math.exp(x)用于指数函数。

【提示】

s

i

g

m

o

i

d

(

x

)

=

1

1

+

e

x

sigmoidleft ( x right )=frac{1}{1+e^{-x}}

sigmoid(x)=1+ex1有时也称为逻辑函数。它是一种非线性函数,即可用于机器学习(逻辑回归),也能用于深度学习。

【代码】

# GRADED FUNCTION: basic_sigmoid

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 变成一个向量,如下所示:

【代码】

# GRADED FUNCTION: basic_sigmoid

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


# One reason why we use "numpy" instead of "math" in Deep Learning
x = [1, 2, 3]
result = basic_sigmoid(x)
# you will see this give an error when you run it, because x is a vector.

将看到如下报错信息:

【结果】

Traceback (most recent call last):
  File "C:UsersDellDesktopAI_math_ws2-151.py", line 24, in <module>
    result = basic_sigmoid(x)
  File "C:UsersDellDesktopAI_math_ws2-151.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=(x1,x2,,xn) 是行向量,则 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 )

np.exp(x)=(ex1,ex2,,exn)

【代码】

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

mathbf{x}

x 是向量,则

s

=

x

+

3

mathbf{s}=mathbf{x}+3

s=x+3

s

=

1

x

mathbf{s} = frac{1}{mathbf{x}}

s=x1 之类的Python运算将输出与

x

mathbf{x}

x 维度大小相同的向量

s

mathbf{s}

s

【代码】

# example of vector operation
x = np.array([1, 2, 3])
print(x + 3)

【结果】

[4 5 6]

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

【说明】

x

x

x 可以是实数,向量或矩阵。 我们在numpy中使用的表示向量、矩阵等的数据结构称为numpy数组。
在这里插入图片描述
【代码】

# GRADED FUNCTION: sigmoid

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

sigmoidderivative(x)=σ(x)=σ(x)(1σ(x))

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

  (1)将

s

s

s 设为

x

x

xsigmoid
  (2)计算

σ

(

x

)

=

s

(

1

s

)

sigma ^{'}(x) =s(1-s)

σ(x)=s(1s)

【代码】

# GRADED FUNCTION: sigmoid

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


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

    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向量。
在这里插入图片描述

【练习】:实现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)

(ab,3)的向量,则可以执行以下操作:

v = v.reshape((v.shape[0]*v.shape[1], v.shape[2])) # v.shape[0] = a ; v.shape[1] = b ; v.shape[2] = c

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

【代码】

# GRADED FUNCTION: image2vector

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

xx(将

x

x

x 的每个行向量除以其范数)。

  例如:

x

=

[

0

3

4

2

6

4

]

x = begin{bmatrix} 0 & 3 & 4\ 2 & 6 & 4 end{bmatrix}

x=[023644]
在这里插入图片描述
【练习】:执行normalizeRows()来标准化矩阵的行。 将此函数应用于输入矩阵

x

x

x 之后,

x

x

x 的每一行应为单位长度(即长度为1)向量。

【代码】

# GRADED FUNCTION: normalizeRows

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

    # 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

    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理解为算法需要对两个或多个类进行分类时使用的标准化函数。

【说明】
在这里插入图片描述
【代码】

# GRADED FUNCTION: softmax
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)
    """

    # 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

    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]

### 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 ELEMENT-WISE 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.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]

### 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 ###
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损失函数定义为:
在这里插入图片描述
【代码】

# GRADED FUNCTION: L1
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损失函数定义为:
在这里插入图片描述

【代码】

# GRADED FUNCTION: L2
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

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>