小C的第一宇宙
wangc
Nov 15, 2017
阅读本文需要 62 分钟(按字数)

笔记学习自网易云课堂-微专业-深度学习工程师

这是个人的学习笔记,限于能力,难免疏忽。如有错误,欢迎留言批评和交流。

前面介绍了一个隐含层的浅层神经网络,往后正式引入深层神经网络,也就是深度学习的基础。其实深层神经网络也就是浅层神经网络中的运算步骤多重复了几遍而已,这次主要对神经网络基础部分进行一个总结,并正式用Python编写出一个简单完整的神经网络应用。

深层神经网络

深层神经网络简介

深度学习,这个概念从正式提出到现在不过十年时间,已经发展为机器学习领域,甚至整个人工智能领域最火的研究领域,关于深度学习的研究与应用不断涌现。所谓深度学习其实就是指的多层神经网络,一个神经网络的隐含层超过一层我们就可以称之为深(多)层学习网络。 image

为什么使用深层神经网络

为什么深度神经网络会有很好的效果,课程中采取了一种直观的形式来对深度神经网络的效能进行了解释。

多层神经网应用络在图像识别领域效果拔群,那么在识别一张图片的过程中神经网络做了写什么呢?比如用一个三层的神经网络来识别一张图片中的人脸,我们可以这样来理解,神经网络第一层去用来找这个图片的边缘,第二层去找人脸的各个不同部分(鼻子,眼睛),第三层再把这些不同部分放在一起,最终识别出人脸。总的思想是一般从小的细节入手(比如边缘),再一步步到更大更复杂的区域。(后面的卷积神经网络会详细说明这一过程。)

参数与超参数

参数神经网络模型中计算的W和b就是参数,我们训练神经网络的过程就是寻找最优化的W和b。

超参数是需要我们自己来设置的,而超参数的不同也会最终影响到参数的值。比如神经网络的层数,每层神经网络的隐含单元数,激活函数的选择,学习率和迭代的次数这些都是超参数。这些超参数设置的不同会大大的改变神经网络模型的效果,这些数值的设定还是考经验和直觉,因为在不同的情况下,面对不同的问题情况都会有所不同,目前不断的试验和测试是选取超参数最好的途径。 image

神经网络编程

接下来会从头到位的编写一个完整的深层神经网络应用程序,这里面包括了构建一个神经网络的基本步骤,对前面的知识进行了复习和巩固。

自下而上的一步步建立神经网络模型。基本步骤如下,:

  • 初始化参数
  • 实现前向传播模型(图中紫色部分)
    • 完成线性部分(得到Z[l]
    • 完成激活函数((relu/sigmoid)
    • 合并 [LINEAR->ACTIVATION]
    • 完成前向传播模型
  • 计算损失函数
  • 实现反向传播模型(图中红色部分)
    • 完成线性部分
    • 完成激活函数((relu_backward/sigmoid_backward)
    • 合并 [LINEAR->ACTIVATION]
    • 完成反向传播模型
  • 更新参数
  • 构建神经网络模型
  • 对实际问题进行训练和预测 image

0 引入相关包

神经网络编程最重要的一个包就是numpy了,并且这里将随机数种子设置为1,以保证后面每次运行的结果一样,方便展示。

import numpy as np
np.random.seed(1)

1 参数初始化

对L层神经网络的参数(W,b)进行初始化。其中随机初始化W(权重矩阵)使用到np.random.randn(shape)*0.01,初始化b(偏移量)为0使用到np.zeros(shape)。(注意对矩阵维数进行检验,养成习惯)

def initialize_parameters_deep(layer_dims):
    """
    Arguments:
    layer_dims -- python array (list) containing the dimensions of each layer in our network
    
    Returns:
    parameters -- python dictionary containing your parameters "W1", "b1", ..., "WL", "bL":
                    Wl -- weight matrix of shape (layer_dims[l], layer_dims[l-1])
                    bl -- bias vector of shape (layer_dims[l], 1)
    """
    
    parameters = {}
    L = len(layer_dims)            # number of layers in the network

    for l in range(1, L):
        parameters['W' + str(l)] = np.random.randn(layer_dims[l], layer_dims[l-1]) / np.sqrt(layer_dims[l-1]) #*0.01
        parameters['b' + str(l)] = np.zeros((layer_dims[l], 1))
        
        assert(parameters['W' + str(l)].shape == (layer_dims[l], layer_dims[l-1]))
        assert(parameters['b' + str(l)].shape == (layer_dims[l], 1))

        
    return parameters

2 实现前向传播模型

实现前向传播模型我们依次完成下面三个部分。

  • LINEAR
  • LINEAR -> ACTIVATION where ACTIVATION will be either ReLU or Sigmoid.
  • [LINEAR -> RELU] ×× (L-1) -> LINEAR -> SIGMOID (whole model) 其中我们在最后一层使用了sigmoid激活函数(用于实现二分分类的输出),其他全部采取ReLU函数。

2.1 线性部分

线性部分的方程为Z[l]=W[l]A[l−1]+b[l],其中A[0] = X。实现矩阵乘法,使用到 np.dot() ,同样的在最后对矩阵维数进行检查。

值得注意的是我们保留了A,W,b的结果,这是为了方便反向传播过程可以直接调用这些值,这是一个实际编程中的小技巧。(后面都会保存进cache)

def linear_forward(A, W, b):
    """
    Implement the linear part of a layer's forward propagation.

    Arguments:
    A -- activations from previous layer (or input data): (size of previous layer, number of examples)
    W -- weights matrix: numpy array of shape (size of current layer, size of previous layer)
    b -- bias vector, numpy array of shape (size of the current layer, 1)

    Returns:
    Z -- the input of the activation function, also called pre-activation parameter 
    cache -- a python dictionary containing "A", "W" and "b" ; stored for computing the backward pass efficiently
    """
    
    Z = W.dot(A) + b
    
    assert(Z.shape == (W.shape[0], A.shape[1]))
    cache = (A, W, b)
    
    return Z, cache

2.2 激活函数

在这个模型中我们用到了一些两个激活函数:

  • Sigmoid:σ(Z)=σ(WA+b)=1/(1+e*(−(WA+b)))
  • ReLU:A=RELU(Z)=max(0,Z)A=RELU(Z)=max(0,Z)。 其中我们保存A,W,b到cache中方便后面直接使用。
def sigmoid(Z):
    """
    Implements the sigmoid activation in numpy
    
    Arguments:
    Z -- numpy array of any shape
    
    Returns:
    A -- output of sigmoid(z), same shape as Z
    cache -- returns Z as well, useful during backpropagation
    """
    
    A = 1/(1+np.exp(-Z))
    cache = Z
    
    return A, cache
def relu(Z):
    """
    Implement the RELU function.
 
    Arguments:
    Z -- Output of the linear layer, of any shape
 
    Returns:
    A -- Post-activation parameter, of the same shape as Z
    cache -- a python dictionary containing "A" ; stored for computing the backward pass efficiently
    """
    
    A = np.maximum(0,Z)
    
    assert(A.shape == Z.shape)
    
    cache = Z 
    return A, cache

2.3 合并

为了更加方便,将线性部分与激活函数的部分进行合并(LINEAR->ACTIVATION ),完成公式A[l]=g(Z[l])=g(W[l]A[l−1]+b[l]),其中“g”可以选择sigmoid() 或 relu()。

def linear_activation_forward(A_prev, W, b, activation):
    """
    Implement the forward propagation for the LINEAR->ACTIVATION layer

    Arguments:
    A_prev -- activations from previous layer (or input data): (size of previous layer, number of examples)
    W -- weights matrix: numpy array of shape (size of current layer, size of previous layer)
    b -- bias vector, numpy array of shape (size of the current layer, 1)
    activation -- the activation to be used in this layer, stored as a text string: "sigmoid" or "relu"

    Returns:
    A -- the output of the activation function, also called the post-activation value 
    cache -- a python dictionary containing "linear_cache" and "activation_cache";
             stored for computing the backward pass efficiently
    """
    
    if activation == "sigmoid":
        # Inputs: "A_prev, W, b". Outputs: "A, activation_cache".
        Z, linear_cache = linear_forward(A_prev, W, b)
        A, activation_cache = sigmoid(Z)
    
    elif activation == "relu":
        # Inputs: "A_prev, W, b". Outputs: "A, activation_cache".
        Z, linear_cache = linear_forward(A_prev, W, b)
        A, activation_cache = relu(Z)
    
    assert (A.shape == (W.shape[0], A_prev.shape[1]))
    cache = (linear_cache, activation_cache)

    return A, cache

2.4 完成前向传播模型

如下图,在L层的神经网络中,将[LINEAR->ACTIVATION]重复L次,前L-1次使用ReLU函数做为激活函数,最后一层使用Sigmoid函数输出0或1作为二分分类的结果。

注意这里我们保留了每一层的cache值。当需要将新值c添加如list列表时,使用list.append(c)。 image

def L_model_forward(X, parameters):
    """
    Implement forward propagation for the [LINEAR->RELU]*(L-1)->LINEAR->SIGMOID computation
    
    Arguments:
    X -- data, numpy array of shape (input size, number of examples)
    parameters -- output of initialize_parameters_deep()
    
    Returns:
    AL -- last post-activation value
    caches -- list of caches containing:
                every cache of linear_relu_forward() (there are L-1 of them, indexed from 0 to L-2)
                the cache of linear_sigmoid_forward() (there is one, indexed L-1)
    """

    caches = []
    A = X
    L = len(parameters) // 2                  # number of layers in the neural network
    
    # Implement [LINEAR -> RELU]*(L-1). Add "cache" to the "caches" list.
    for l in range(1, L):
        A_prev = A 
        A, cache = linear_activation_forward(A_prev, parameters['W' + str(l)], parameters['b' + str(l)], activation = "relu")
        caches.append(cache)
    
    # Implement LINEAR -> SIGMOID. Add "cache" to the "caches" list.
    AL, cache = linear_activation_forward(A, parameters['W' + str(L)], parameters['b' + str(L)], activation = "sigmoid")
    caches.append(cache)
    
    assert(AL.shape == (1,X.shape[1]))
            
    return AL, caches

3 代价函数

现在实现了神经网络的前向传播部分,我们需要计算成本函数用于检查模型的学习效果。计算成本值的公式为:

image

def compute_cost(AL, Y):
    """
    Implement the cost function defined by equation (7).
 
    Arguments:
    AL -- probability vector corresponding to your label predictions, shape (1, number of examples)
    Y -- true "label" vector (for example: containing 0 if non-cat, 1 if cat), shape (1, number of examples)
 
    Returns:
    cost -- cross-entropy cost
    """
    
    m = Y.shape[1]
 
    # Compute loss from aL and y.
    cost = -np.sum(np.multiply(np.log(AL),Y) + np.multiply(np.log(1 - AL), 1 - Y)) / m
    
    cost = np.squeeze(cost)      # To make sure your cost's shape is what we expect (e.g. this turns [[17]] into 17).
    assert(cost.shape == ())
    
    return cost

3 实现反向传播模型

如下图红色部分为反向传播的过程,类似于正向传播部分,我们依次完成下面几个步骤:

  • LINEAR backward
  • LINEAR -> ACTIVATION backward where ACTIVATION computes the derivative of either the ReLU or sigmoid activation
  • [LINEAR -> RELU] ×× (L-1) -> LINEAR -> SIGMOID backward (whole model)

image

3.1 线性部分

对与第l层,线性部分的公式为Z[l]=W[l]A[l−1]+b[l]。假设已经计算出了dZ[l],接着需要用dZ[l]计算出dW[l],db[l]和dA[l−1]

公式如下: image

在实际编程中,我们还可以直接使用前向传播中保留的A,W,b来更快捷的进行计算。

def linear_backward(dZ, cache):
    """
    Implement the linear portion of backward propagation for a single layer (layer l)
 
    Arguments:
    dZ -- Gradient of the cost with respect to the linear output (of current layer l)
    cache -- tuple of values (A_prev, W, b) coming from the forward propagation in the current layer
 
    Returns:
    dA_prev -- Gradient of the cost with respect to the activation (of the previous layer l-1), same shape as A_prev
    dW -- Gradient of the cost with respect to W (current layer l), same shape as W
    db -- Gradient of the cost with respect to b (current layer l), same shape as b
    """
    A_prev, W, b = cache
    m = A_prev.shape[1]
 
    dW = np.dot(dZ, A_prev.T) / m
    db = np.sum(dZ, axis=1, keepdims=True) / m
    dA_prev = np.dot(W.T, dZ)
    
    assert (dA_prev.shape == A_prev.shape)
    assert (dW.shape == W.shape)
    assert (db.shape == b.shape)
    
    return dA_prev, dW, db

4.2 激活函数

接下来构造反向传播中的激活函数sigmoid_backward和relu_backward。设g(.)是激活函数,sigmoid_backward 和 relu_backward 计算的是dZ[l]=dA[l]∗g′(Z[l])。

def sigmoid_backward(dA, cache):
    """
    Implement the backward propagation for a single SIGMOID unit.
 
    Arguments:
    dA -- post-activation gradient, of any shape
    cache -- 'Z' where we store for computing backward propagation efficiently
 
    Returns:
    dZ -- Gradient of the cost with respect to Z
    """
    
    Z = cache
    
    s = 1/(1+np.exp(-Z))
    dZ = dA * s * (1-s)
    
    assert (dZ.shape == Z.shape)
    
    return dZ
def relu_backward(dA, cache):
    """
    Implement the backward propagation for a single RELU unit.
 
    Arguments:
    dA -- post-activation gradient, of any shape
    cache -- 'Z' where we store for computing backward propagation efficiently
 
    Returns:
    dZ -- Gradient of the cost with respect to Z
    """
    
    Z = cache
    dZ = np.array(dA, copy=True) # just converting dz to a correct object.
    
    # When z <= 0, you should set dz to 0 as well. 
    dZ[Z <= 0] = 0
    
    assert (dZ.shape == Z.shape)
    
    return dZ

4.3 合并

同正向传播部分,将线性部分与激活函数部分进行整合。

def linear_activation_backward(dA, cache, activation):
    """
    Implement the backward propagation for the LINEAR->ACTIVATION layer.
    
    Arguments:
    dA -- post-activation gradient for current layer l 
    cache -- tuple of values (linear_cache, activation_cache) we store for computing backward propagation efficiently
    activation -- the activation to be used in this layer, stored as a text string: "sigmoid" or "relu"
    
    Returns:
    dA_prev -- Gradient of the cost with respect to the activation (of the previous layer l-1), same shape as A_prev
    dW -- Gradient of the cost with respect to W (current layer l), same shape as W
    db -- Gradient of the cost with respect to b (current layer l), same shape as b
    """
    linear_cache, activation_cache = cache
    
    if activation == "relu":
        dZ = relu_backward(dA, activation_cache)
        dA_prev, dW, db = linear_backward(dZ, linear_cache)
        
    elif activation == "sigmoid":
        dZ = sigmoid_backward(dA, activation_cache)
        dA_prev, dW, db = linear_backward(dZ, linear_cache)
    
    return dA_prev, dW, db

4.4 反向传播模型

在反向传播过程中,我们调用正向传播中存储的caches,包括(X,W,b, 和 z),用于计算梯度值。

image

def L_model_backward(AL, Y, caches):
    """
    Implement the backward propagation for the [LINEAR->RELU] * (L-1) -> LINEAR -> SIGMOID group
    
    Arguments:
    AL -- probability vector, output of the forward propagation (L_model_forward())
    Y -- true "label" vector (containing 0 if non-cat, 1 if cat)
    caches -- list of caches containing:
                every cache of linear_activation_forward() with "relu" (it's caches[l], for l in range(L-1) i.e l = 0...L-2)
                the cache of linear_activation_forward() with "sigmoid" (it's caches[L-1])
    
    Returns:
    grads -- A dictionary with the gradients
             grads["dA" + str(l)] = ... 
             grads["dW" + str(l)] = ...
             grads["db" + str(l)] = ... 
    """
    grads = {}
    L = len(caches) # the number of layers
    m = AL.shape[1]
    Y = Y.reshape(AL.shape) # after this line, Y is the same shape as AL
    
    # Initializing the backpropagation
    dAL = - (np.divide(Y, AL) - np.divide(1 - Y, 1 - AL))
    
    # Lth layer (SIGMOID -> LINEAR) gradients. Inputs: "AL, Y, caches". Outputs: "grads["dAL"], grads["dWL"], grads["dbL"]
    current_cache = caches[L-1]
    grads["dA" + str(L)], grads["dW" + str(L)], grads["db" + str(L)] = linear_activation_backward(dAL, current_cache, "sigmoid")
    
    for l in reversed(range(L-1)):
        # lth layer: (RELU -> LINEAR) gradients.
        # Inputs: "grads["dA" + str(l + 2)], caches". Outputs: "grads["dA" + str(l + 1)] , grads["dW" + str(l + 1)] , grads["db" + str(l + 1)] 
        current_cache = caches[l]
        dA_prev_temp, dW_temp, db_temp = linear_activation_backward(grads["dA" + str(l + 2)], current_cache, "relu")
        grads["dA" + str(l + 1)] = dA_prev_temp
        grads["dW" + str(l + 1)] = dW_temp
        grads["db" + str(l + 1)] = db_temp
 
    return grads

5 更新参数

说得到了梯度值后,使用梯度下降法来更新神经网络模型的参数,以寻找最优参数。

  • W[l]=W[l]−α dW[l]
  • b[l]=b[l]−α db[l] 其中α为学习率。
def update_parameters(parameters, grads, learning_rate):
    """
    Update parameters using gradient descent
    
    Arguments:
    parameters -- python dictionary containing your parameters 
    grads -- python dictionary containing your gradients, output of L_model_backward
    
    Returns:
    parameters -- python dictionary containing your updated parameters 
                  parameters["W" + str(l)] = ... 
                  parameters["b" + str(l)] = ...
    """
    
    L = len(parameters) // 2 # number of layers in the neural network
 
    # Update rule for each parameter. Use a for loop.
    for l in range(L):
        parameters["W" + str(l+1)] = parameters["W" + str(l+1)] - learning_rate * grads["dW" + str(l+1)]
        parameters["b" + str(l+1)] = parameters["b" + str(l+1)] - learning_rate * grads["db" + str(l+1)]
        
    return parameters

6 多层神经网络模型

上面我们构造了一个神经网络模型需要的所有基本函数:

def initialize_parameters_deep(layer_dims):
    ...
    return parameters 
def L_model_forward(X, parameters):
    ...
    return AL, caches
def compute_cost(AL, Y):
    ...
    return cost
def L_model_backward(AL, Y, caches):
    ...
    return grads
def update_parameters(parameters, grads, learning_rate):
    ...
    return parameters

接下来组装起L层神经网络模型,并且对cost值进行输出,用以检验神经网络模型的学习效率和学习效果。

def L_layer_model(X, Y, layers_dims, learning_rate = 0.0075, num_iterations = 3000, print_cost=False):#lr was 0.009
    """
    Implements a L-layer neural network: [LINEAR->RELU]*(L-1)->LINEAR->SIGMOID.
    
    Arguments:
    X -- data, numpy array of shape (number of examples, num_px * num_px * 3)
    Y -- true "label" vector (containing 0 if cat, 1 if non-cat), of shape (1, number of examples)
    layers_dims -- list containing the input size and each layer size, of length (number of layers + 1).
    learning_rate -- learning rate of the gradient descent update rule
    num_iterations -- number of iterations of the optimization loop
    print_cost -- if True, it prints the cost every 100 steps
    
    Returns:
    parameters -- parameters learnt by the model. They can then be used to predict.
    """
 
    np.random.seed(1)
    costs = []                         # keep track of cost
    
    # Parameters initialization.
    parameters = initialize_parameters_deep(layers_dims)
    
    # Loop (gradient descent)
    for i in range(0, num_iterations):
 
        # Forward propagation: [LINEAR -> RELU]*(L-1) -> LINEAR -> SIGMOID.
        AL, caches = L_model_forward(X, parameters)
        
        # Compute cost.
        cost = compute_cost(AL, Y)
    
        # Backward propagation.
        grads = L_model_backward(AL, Y, caches)
 
        # Update parameters.
        parameters = update_parameters(parameters, grads, learning_rate)
                
        # Print the cost every 100 training example
        if print_cost and i % 100 == 0:
            print ("Cost after iteration %i: %f" %(i, cost))
        if print_cost and i % 100 == 0:
            costs.append(cost)
            
    # plot the cost
    plt.plot(np.squeeze(costs))
    plt.ylabel('cost')
    plt.xlabel('iterations (per tens)')
    plt.title("Learning rate =" + str(learning_rate))
    plt.show()
    
    return parameters

7 应用

我们使用上面的神经网络模型进行二分类,分辨一张图片是不是猫图。

7.1 数据导入&预处理

构造读取数据的函数来读取我们保存在h5文件中的训练集和测试集图片。

def load_data():
    train_dataset = h5py.File('datasets/train_catvnoncat.h5', "r")
    train_set_x_orig = np.array(train_dataset["train_set_x"][:]) # your train set features
    train_set_y_orig = np.array(train_dataset["train_set_y"][:]) # your train set labels

    test_dataset = h5py.File('datasets/test_catvnoncat.h5', "r")
    test_set_x_orig = np.array(test_dataset["test_set_x"][:]) # your test set features
    test_set_y_orig = np.array(test_dataset["test_set_y"][:]) # your test set labels

    classes = np.array(test_dataset["list_classes"][:]) # the list of classes
    
    train_set_y_orig = train_set_y_orig.reshape((1, train_set_y_orig.shape[0]))
    test_set_y_orig = test_set_y_orig.reshape((1, test_set_y_orig.shape[0]))
    
    return train_set_x_orig, train_set_y_orig, test_set_x_orig, test_set_y_orig, classes

读取数据

train_x_orig, train_y, test_x_orig, test_y, classes = load_data()

对所读取的数据进行预处理,首先将图像矩阵变形为一列向量,并且对其中的RGB数值进行标准化到[0,1]区间。

# Reshape the training and test examples 
train_x_flatten = train_x_orig.reshape(train_x_orig.shape[0], -1).T   # The "-1" makes reshape flatten the remaining dimensions
test_x_flatten = test_x_orig.reshape(test_x_orig.shape[0], -1).T

# Standardize data to have feature values between 0 and 1.
train_x = train_x_flatten/255.
test_x = test_x_flatten/255.

7.2 模型创建与训练

这里创建一个3个隐含层的神经网络,并对模型进行训练。

layers_dims = [12288, 20, 7, 5, 1] #  5-layer model
import matplotlib.pyplot as plt
%matplotlib inline

parameters = L_layer_model(train_x, train_y, layers_dims, num_iterations = 2500, print_cost = True)

结果:

Cost after iteration 0: 0.771749
Cost after iteration 100: 0.672053
Cost after iteration 200: 0.648263
Cost after iteration 300: 0.611507
Cost after iteration 400: 0.567047
Cost after iteration 500: 0.540138
Cost after iteration 600: 0.527930
Cost after iteration 700: 0.465477
Cost after iteration 800: 0.369126
Cost after iteration 900: 0.391747
Cost after iteration 1000: 0.315187
Cost after iteration 1100: 0.272700
Cost after iteration 1200: 0.237419
Cost after iteration 1300: 0.199601
Cost after iteration 1400: 0.189263
Cost after iteration 1500: 0.161189
Cost after iteration 1600: 0.148214
Cost after iteration 1700: 0.137775
Cost after iteration 1800: 0.129740
Cost after iteration 1900: 0.121225
Cost after iteration 2000: 0.113821
Cost after iteration 2100: 0.107839
Cost after iteration 2200: 0.102855
Cost after iteration 2300: 0.100897
Cost after iteration 2400: 0.092878

image

7.3 模型测试

进一步测试模型的准确率,导入训练集和测试集,分别输出模型预测的准确率。以下为预测函数的定义:

def predict(X, y, parameters):
    """
    This function is used to predict the results of a  L-layer neural network.
    
    Arguments:
    X -- data set of examples you would like to label
    parameters -- parameters of the trained model
    
    Returns:
    p -- predictions for the given dataset X
    """
    
    m = X.shape[1]
    n = len(parameters) // 2 # number of layers in the neural network
    p = np.zeros((1,m))
    
    # Forward propagation
    probas, caches = L_model_forward(X, parameters)
 
    
    # convert probas to 0/1 predictions
    for i in range(0, probas.shape[1]):
        if probas[0,i] > 0.5:
            p[0,i] = 1
        else:
            p[0,i] = 0
    
    print("Accuracy: "  + str(float(np.sum((p == y))/m)))
        
    return p
predictions_train = predict(train_x, train_y, parameters)
predictions_test = predict(test_x, test_y, parameters)

结果:

Accuracy: 0.9856459330143541
Accuracy: 0.8

从这里来看,0.8的准确率还是可以的。

7.4 结果分析

接下来对于测试集中的图片,我们把模型判断错误的图片进行输出。输出错误图片的函数定义如下:

def print_mislabeled_images(classes, X, y, p):
    """
    Plots images where predictions and truth were different.
    X -- dataset
    y -- true labels
    p -- predictions
    """
    a = p + y
    mislabeled_indices = np.asarray(np.where(a == 1))
    plt.rcParams['figure.figsize'] = (40.0, 40.0) # set default size of plots
    num_images = len(mislabeled_indices[0])
    for i in range(num_images):
        index = mislabeled_indices[1][i]
        
        plt.subplot(2, num_images, i + 1)
        plt.imshow(X[:,index].reshape(64,64,3), interpolation='nearest')
        plt.axis('off')
        plt.title("Prediction: " + classes[int(p[0,index])].decode("utf-8") + " \n Class: " + classes[y[0,index]].decode("utf-8"))
pred_test = predict(test_x, test_y, parameters)
print_mislabeled_images(classes, test_x, test_y, pred_test)

image

我们可以简单总结出模型可能误判的情况:

  • Cat body in an unusual position
  • Cat appears against a background of a similar color
  • Unusual cat color and species
  • Camera Angle
  • Brightness of the picture
  • Scale variation (cat is very large or small in image)

7.5 模型应用

接下来可以自己拿更多的图片进行测试和识别。注意导入图片进入预测模型时,要对图片矩阵进行预处理,也就是进行resize和reshape,并且标准化到0,1区间。

import matplotlib.pyplot as plt
import scipy
from PIL import Image
from scipy import ndimage

my_image = "my_image.jpg" # change this to the name of your image file 
my_label_y = [0] # the true class of your image (1 -> cat, 0 -> non-cat)

fname = "images/" + my_image
image = np.array(ndimage.imread(fname, flatten=False))

num_px = train_x_orig.shape[1] 
my_image = scipy.misc.imresize(image, size=(num_px,num_px)).reshape((num_px*num_px*3,1))
my_predicted_image = predict(my_image/255, my_label_y, parameters)

plt.imshow(image)

print ("y = " + str(np.squeeze(my_predicted_image)) + ", your L-layer model predicts a \"" + classes[int(np.squeeze(my_predicted_image)),].decode("utf-8") +  "\" picture.")

这里我测试了一些图片,效果其实并不是很满意,一方面是训练样本还是比较少(200多张),模型也是最基本的模型,到后面下一部分会对设置超参数的一些常见方法进行进一步学习,并且学习更高级的模型比如卷积神经网络,预计会比现在的预测效果更好。

详见编程作业: Building your Deep Neural Network Step b Step v5.html(刷新后显示)

Deep Neural Network Application v3.html(刷新后显示)