【吴恩达深度学习week4编程作业】

本文参考该播主实现,需要的文件在博主的文章里:https://blog.csdn.net/u013733326/article/details/79767169

这次我先记录我自己打代码时候的错误,最后把添加注释的代码放到最后;

1.初始化参数b1

在初始化b1的时候我发现我没有把b1初始化为参数为0的数组,并且维度设置的也不对,最后导致错误:

Traceback (most recent call last):
  File "E:/python/pycharm/week4/main.py", line 329, in <module>
    predictions_train = predict(train_x, train_y, parameters) #训练集
  File "E:/python/pycharm/week4/main.py", line 317, in predict
    probas, caches = L_model_forward(X, parameters)
  File "E:/python/pycharm/week4/main.py", line 114, in L_model_forward
    AL,cache = linear_activation_forward(A_prev,parameters['W' + str(L)],parameters['b' + str(L)],'sigmoid')
  File "E:/python/pycharm/week4/main.py", line 81, in linear_activation_forward
    Z,linear_cache = liner_forward(A_prev,W,b)
  File "E:/python/pycharm/week4/main.py", line 67, in liner_forward
    Z = np.dot(W,A) + b #记住这里使用向量化
  File "<__array_function__ internals>", line 6, in dot
ValueError: shapes (1,7) and (12288,209) not aligned: 7 (dim 1) != 12288 (dim 0)

Process finished with exit code 1

代码对比:
正确代码:

W1 = np.random.randn(n_h, n_x) * 0.01
    b1 = np.zeros((n_h, 1))
    W2 = np.random.randn(n_y, n_h) * 0.01
    b2 = np.zeros((n_y, 1))

错误代码:

W1 = np.random.randn(n_h,n_x)*0.01
    b1 = np.random.randn(n_h,1)
    W2 = np.random.randn(n_y,n_h)*0.01
    b2 = np.random.randn(n_y,1)

2.整体代码

import numpy as np
import h5py
import matplotlib.pyplot as plt
import testCases #参见资料包,或者在文章底部copy
from dnn_utils import sigmoid, sigmoid_backward, relu, relu_backward #参见资料包
import lr_utils #参见资料包,或者在文章底部copy


np.random.seed(1)


def initialize_parameters(n_x, n_h, n_y):
    """
    此函数是为了初始化两层网络参数而使用的函数。
    参数:
        n_x - 输入层节点数量
        n_h - 隐藏层节点数量
        n_y - 输出层节点数量

    返回:
        parameters - 包含你的参数的python字典:
            W1 - 权重矩阵,维度为(n_h,n_x)
            b1 - 偏向量,维度为(n_h,1)
            W2 - 权重矩阵,维度为(n_y,n_h)
            b2 - 偏向量,维度为(n_y,1)

    """
    W1 = np.random.randn(n_h, n_x) * 0.01
    b1 = np.zeros((n_h, 1))
    W2 = np.random.randn(n_y, n_h) * 0.01
    b2 = np.zeros((n_y, 1))

    # 使用断言确保我的数据格式是正确的
    assert (W1.shape == (n_h, n_x))
    assert (b1.shape == (n_h, 1))
    assert (W2.shape == (n_y, n_h))
    assert (b2.shape == (n_y, 1))

    parameters = {"W1": W1,
                  "b1": b1,
                  "W2": W2,
                  "b2": b2}

    return parameters


def initialize_parameters_deep(layers_dims):
    """
    此函数是为了初始化多层网络参数而使用的函数。
    参数:
        layers_dims - 包含我们网络中每个图层的节点数量的列表

    返回:
        parameters - 包含参数“W1”,“b1”,...,“WL”,“bL”的字典:
                     W1 - 权重矩阵,维度为(layers_dims [1],layers_dims [1-1])
                     bl - 偏向量,维度为(layers_dims [1],1)
    """
    np.random.seed(3)
    parameters = {}
    L = len(layers_dims)

    for l in range(1, L):
        parameters['W' + str(l)] = np.random.randn(layers_dims[l], layers_dims[l - 1]) / np.sqrt(
            layers_dims[l - 1])  # 用这条语句出来的数据与博客中不符合
        # parameters['W' + str(l)] = np.random.randn(layers_dims[l], layers_dims[l - 1]) *0.01 #使用这条语句符合博客中的数据
        # parameters['b' + str(l)] = np.zeros(layers_dims[l], 1)#np.zeros(layers_dims[l],1),当只有一个()的时候会报错,因为np.zeros(shape)需要给的参数就是一个shape而不是维度
        parameters['b' + str(l)] = np.zeros((layers_dims[l], 1))


    # 确保我要的数据的格式是正确的
    assert (parameters["W" + str(l)].shape == (layers_dims[l], layers_dims[l - 1]))
    assert (parameters["b" + str(l)].shape == (layers_dims[l], 1))


    return parameters


"""
前向传播函数分为三个步骤:
1.Liner
2.Liner -> Activation , 其中激活函数会使用Relu或者Sigmoid
3.[Linear -> Relu] x (L-1) -> Linear -> Sigmoid(整个模型)
"""

def linear_forward(A, W, b):
    """
    实现前向传播的线性部分。

    参数:
        A - 来自上一层(或输入数据)的激活,维度为(上一层的节点数量,示例的数量)
        W - 权重矩阵,numpy数组,维度为(当前图层的节点数量,前一图层的节点数量)
        b - 偏向量,numpy向量,维度为(当前图层节点数量,1)

    返回:
         Z - 激活功能的输入,也称为预激活参数
         cache - 一个包含“A”,“W”和“b”的字典,存储这些变量以有效地计算后向传递
    """
    Z = np.dot(W, A) + b
    assert (Z.shape == (W.shape[0], A.shape[1]))
    cache = (A, W, b)

    return Z, cache


def linear_activation_forward(A_prev, W, b, activation):
    """
    实现LINEAR-> ACTIVATION 这一层的前向传播

    参数:
        A_prev - 来自上一层(或输入层)的激活,维度为(上一层的节点数量,示例数)
        W - 权重矩阵,numpy数组,维度为(当前层的节点数量,前一层的大小)
        b - 偏向量,numpy阵列,维度为(当前层的节点数量,1)
        activation - 选择在此层中使用的激活函数名,字符串类型,【"sigmoid" | "relu"】

    返回:
        A - 激活函数的输出,也称为激活后的值
        cache - 一个包含“linear_cache”和“activation_cache”的字典,我们需要存储它以有效地计算后向传递
    """

    if activation == "sigmoid":
        Z, linear_cache = linear_forward(A_prev, W, b)
        A, activation_cache = sigmoid(Z)
    elif activation == "relu":
        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


def L_model_forward(X, parameters):
    """
    实现[LINEAR-> RELU] *(L-1) - > LINEAR-> SIGMOID计算前向传播,也就是多层网络的前向传播,为后面每一层都执行LINEAR和ACTIVATION

    参数:
        X - 数据,numpy数组,维度为(输入节点数量,示例数)
        parameters - initialize_parameters_deep()的输出

    返回:
        AL - 最后的激活值
        caches - 包含以下内容的缓存列表:
                 linear_relu_forward()的每个cache(有L-1个,索引为从0到L-2)
                 linear_sigmoid_forward()的cache(只有一个,索引为L-1)
    """
    caches = []
    A = X
    L = len(parameters) // 2#// 是整除向下取整,因为paremeters里面有W和b,所以整除2 就是隐藏层的个数,我们就需要使用L-1的relu激活函数
    for l in range(1, L):#半包围结构取不到L,取到L-1
        A_prev = A
        A, cache = linear_activation_forward(A_prev, parameters['W' + str(l)], parameters['b' + str(l)], "relu")
        caches.append(cache)

    AL, cache = linear_activation_forward(A, parameters['W' + str(L)], parameters['b' + str(L)], "sigmoid")
    caches.append(cache)

    """为什么是(1,X.shape[1]),AL是一个二分类的输出结果,所以是维度为1 x m 的向量,m就是X.shape[1],就是输入的样本数量"""
    assert (AL.shape == (1, X.shape[1]))  # AL :sigmoid激活函数的输出,也称为激活后的值,也是Yhat,

    return AL, caches


def compute_cost(AL, Y):
    """
    实施等式(4)定义的成本函数。

    参数:
        AL - 与标签预测相对应的概率向量,维度为(1,示例数量)
        Y - 标签向量(例如:如果不是猫,则为0,如果是猫则为1),维度为(1,数量)

    返回:
        cost - 交叉熵成本
    """
    m = Y.shape[1]
    cost = -np.sum(np.multiply(np.log(AL), Y) + np.multiply(np.log(1 - AL), 1 - Y)) / m

    cost = np.squeeze(cost)
    assert (cost.shape == ())

    return cost


def linear_backward(dZ, cache):
    """
    为单层实现反向传播的线性部分(第L层)

    参数:
         dZ - 相对于(当前第l层的)线性输出的成本梯度
         cache - 来自当前层前向传播的值的元组(A_prev,W,b)

    返回:
         dA_prev - 相对于激活(前一层l-1)的成本梯度,与A_prev维度相同
         dW - 相对于W(当前层l)的成本梯度,与W的维度相同
         db - 相对于b(当前层l)的成本梯度,与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


def linear_activation_backward(dA, cache, activation="relu"):
    """
    实现LINEAR-> ACTIVATION层的后向传播。

    参数:
         dA - 当前层l的激活后的梯度值
         cache - 我们存储的用于有效计算反向传播的值的元组(值为linear_cache,activation_cache)
         activation - 要在此层中使用的激活函数名,字符串类型,【"sigmoid" | "relu"】
    返回:
         dA_prev - 相对于激活(前一层l-1)的成本梯度值,与A_prev维度相同
         dW - 相对于W(当前层l)的成本梯度值,与W的维度相同
         db - 相对于b(当前层l)的成本梯度值,与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


def L_model_backward(AL, Y, caches):
    """
    对[LINEAR-> RELU] *(L-1) - > LINEAR - > SIGMOID组执行反向传播,就是多层网络的向后传播

    参数:
     AL - 概率向量,正向传播的输出(L_model_forward())
     Y - 标签向量(例如:如果不是猫,则为0,如果是猫则为1),维度为(1,数量)
     caches - 包含以下内容的cache列表:
                 linear_activation_forward("relu")的cache,不包含输出层
                 linear_activation_forward("sigmoid")的cache

    返回:
     grads - 具有梯度值的字典
              grads [“dA”+ str(l)] = ...
              grads [“dW”+ str(l)] = ...
              grads [“db”+ str(l)] = ...
    """
    grads = {}
    L = len(caches)
    m = AL.shape[1]
    Y = Y.reshape(AL.shape)
    dAL = - (np.divide(Y, AL) - np.divide(1 - Y, 1 - AL))

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


def update_parameters(parameters, grads, learning_rate):
    """
    使用梯度下降更新参数

    参数:
     parameters - 包含你的参数的字典
     grads - 包含梯度值的字典,是L_model_backward的输出

    返回:
     parameters - 包含更新参数的字典
                   参数[“W”+ str(l)] = ...
                   参数[“b”+ str(l)] = ...
    """
    L = len(parameters) // 2  # 整除

    """
        一下是博主的代码,我们可以直接写成range(1,L),然后下面就不用写(l + 1)了,因为我们直接从1开始,而不是从0开始,range(start,stop)中start不写,默认就是0
        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)]

        注:运行代码后发现,W1,b1,是相同的,但是W2,b2是有区别的,
        W1 = [[-0.59562069 -0.09991781 -2.14584584  1.82662008]
     [-1.76569676 -0.80627147  0.51115557 -1.18258802]
     [-1.0535704  -0.86128581  0.68284052  2.20374577]]
    b1 = [[-0.04659241]
     [-1.28888275]
     [ 0.53405496]]
    W2 = [[-0.5961597  -0.0191305   1.17500122]]
    b2 = [[-0.74787095]]

    Process finished with exit code 0
    但是用博主的代码就和博主运行结果一致

    再注:我把range(1,L)改为(1,L+1)结果运行就一致了,少运行一次更新参数,导致更新效果不好,甚至W还变大了
        """

    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

#
# def two_layer_model(X, Y, layers_dims, learning_rate=0.0075, num_iterations=3000, print_cost=False, isPlot=True):
#     """
#     实现一个两层的神经网络,【LINEAR->RELU】 -> 【LINEAR->SIGMOID】
#     参数:
#         X - 输入的数据,维度为(n_x,例子数)
#         Y - 标签,向量,0为非猫,1为猫,维度为(1,数量)
#         layers_dims - 层数的向量,维度为(n_y,n_h,n_y)
#         learning_rate - 学习率
#         num_iterations - 迭代的次数
#         print_cost - 是否打印成本值,每100次打印一次
#         isPlot - 是否绘制出误差值的图谱
#     返回:
#         parameters - 一个包含W1,b1,W2,b2的字典变量
#     """
#     np.random.seed(1)
#     grads = {}
#     costs = []
#     (n_x, n_h, n_y) = layers_dims
#
#     """
#     初始化参数
#     """
#     parameters = initialize_parameters(n_x, n_h, n_y)
#
#     W1 = parameters["W1"]
#     b1 = parameters["b1"]
#     W2 = parameters["W2"]
#     b2 = parameters["b2"]
#
#     """
#     开始进行迭代
#     """
#     for i in range(0, num_iterations):
#         # 前向传播
#         A1, cache1 = linear_activation_forward(X, W1, b1, "relu")
#         A2, cache2 = linear_activation_forward(A1, W2, b2, "sigmoid")
#
#         # 计算成本
#         cost = compute_cost(A2, Y)
#
#         # 后向传播
#         ##初始化后向传播
#         dA2 = - (np.divide(Y, A2) - np.divide(1 - Y, 1 - A2))
#
#         ##向后传播,输入:“dA2,cache2,cache1”。 输出:“dA1,dW2,db2;还有dA0(未使用),dW1,db1”。
#         dA1, dW2, db2 = linear_activation_backward(dA2, cache2, "sigmoid")
#         dA0, dW1, db1 = linear_activation_backward(dA1, cache1, "relu")
#
#         ##向后传播完成后的数据保存到grads
#         grads["dW1"] = dW1
#         grads["db1"] = db1
#         grads["dW2"] = dW2
#         grads["db2"] = db2
#
#         # 更新参数
#         parameters = update_parameters(parameters, grads, learning_rate)
#         W1 = parameters["W1"]
#         b1 = parameters["b1"]
#         W2 = parameters["W2"]
#         b2 = parameters["b2"]
#
#         # 打印成本值,如果print_cost=False则忽略
#         if i % 100 == 0:
#             # 记录成本
#             costs.append(cost)
#             # 是否打印成本值
#             if print_cost:
#                 print("第", i, "次迭代,成本值为:", np.squeeze(cost))
#     # 迭代完成,根据条件绘制图
#     if isPlot:
#         plt.plot(np.squeeze(costs))
#         plt.ylabel('cost')
#         plt.xlabel('iterations (per tens)')
#         plt.title("Learning rate =" + str(learning_rate))
#         plt.show()
#
#     # 返回parameters
#     return parameters


# train_set_x_orig , train_set_y , test_set_x_orig , test_set_y , classes = lr_utils.load_dataset()
#
# train_x_flatten = train_set_x_orig.reshape(train_set_x_orig.shape[0], -1).T
# test_x_flatten = test_set_x_orig.reshape(test_set_x_orig.shape[0], -1).T
#
# train_x = train_x_flatten / 255
# train_y = train_set_y
# test_x = test_x_flatten / 255
# test_y = test_set_y
#
#
# n_x = 12288
# n_h = 7
# n_y = 1
# layers_dims = (n_x,n_h,n_y)
#
# parameters = two_layer_model(train_x, train_set_y, layers_dims = (n_x, n_h, n_y), num_iterations = 2500, print_cost=True,isPlot=True)


def predict(X, y, parameters):
    """
    该函数用于预测L层神经网络的结果,当然也包含两层

    参数:
     X - 测试集
     y - 标签
     parameters - 训练模型的参数

    返回:
     p - 给定数据集X的预测
    """

    m = X.shape[1]
    n = len(parameters) // 2  # 神经网络的层数
    p = np.zeros((1, m))

    # 根据参数前向传播
    probas, caches = L_model_forward(X, parameters)

    for i in range(0, probas.shape[1]):
        if probas[0, i] > 0.5:
            p[0, i] = 1
        else:
            p[0, i] = 0

    print("准确度为: " + 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) #测试集


def L_layer_model(X, Y, layers_dims, learning_rate=0.0075, num_iterations=3000, print_cost=False, isPlot=True):
    """
    实现一个L层神经网络:[LINEAR-> RELU] *(L-1) - > LINEAR-> SIGMOID。

    参数:
	    X - 输入的数据,维度为(n_x,例子数)
        Y - 标签,向量,0为非猫,1为猫,维度为(1,数量)
        layers_dims - 层数的向量,维度为(n_y,n_h,···,n_h,n_y)
        learning_rate - 学习率
        num_iterations - 迭代的次数
        print_cost - 是否打印成本值,每100次打印一次
        isPlot - 是否绘制出误差值的图谱

    返回:
     parameters - 模型学习的参数。 然后他们可以用来预测。
    """
    np.random.seed(1)
    costs = []

    parameters = initialize_parameters_deep(layers_dims)

    for i in range(0, num_iterations):
        AL, caches = L_model_forward(X, parameters)

        cost = compute_cost(AL, Y)

        grads = L_model_backward(AL, Y, caches)

        parameters = update_parameters(parameters, grads, learning_rate)

        # 打印成本值,如果print_cost=False则忽略
        if i % 100 == 0:
            # 记录成本
            costs.append(cost)
            # 是否打印成本值
            if print_cost:
                print("第", i, "次迭代,成本值为:", np.squeeze(cost))
    # 迭代完成,根据条件绘制图
    if isPlot:
        plt.plot(np.squeeze(costs))
        plt.ylabel('cost')
        plt.xlabel('iterations (per tens)')
        plt.title("Learning rate =" + str(learning_rate))
        plt.show()
    return parameters


train_set_x_orig , train_set_y , test_set_x_orig , test_set_y , classes = lr_utils.load_dataset()

train_x_flatten = train_set_x_orig.reshape(train_set_x_orig.shape[0], -1).T
test_x_flatten = test_set_x_orig.reshape(test_set_x_orig.shape[0], -1).T

train_x = train_x_flatten / 255
train_y = train_set_y
test_x = test_x_flatten / 255
test_y = test_set_y

layers_dims = [12288, 20, 7, 5, 1] #  5-layer model
parameters = L_layer_model(train_x, train_y, layers_dims, num_iterations = 2500, print_cost = True,isPlot=True)

pred_train = predict(train_x, train_y, parameters) #训练集
pred_test = predict(test_x, test_y, parameters) #测试集

def print_mislabeled_images(classes, X, y, p):
    """
	绘制预测和实际不同的图像。
	    X - 数据集
	    y - 实际的标签
	    p - 预测
    """
    a = p + y
    #np.asarray() : 将输入转化为数组
    #np.where有两种用法
# 1.np.where(condition,x,y) 当where内有三个参数时,第一个参数表示条件,当条件成立时where方法返回x,当条件不成立时where返回y
# 2.np.where(condition) 当where内只有一个参数时,那个参数表示条件,当条件成立时,where返回的是每个符合condition条件元素的坐标,返回的是以元组的形式

    mislabeled_indices = np.asarray(np.where(a == 1))
    plt.rcParams['figure.figsize'] = (40.0, 40.0)  # set default size of plots设置绘图的默认尺寸,default:默认的;违约(figure.figsize : 图像显示大小)
    num_images = len(mislabeled_indices[0])
    for i in range(num_images):
        index = mislabeled_indices[1][i]
# plt.subplot(2,3,1)也可以简写plt.subplot(231)表示把显示界面分割成2*3的网格。其中,第一个参数是行数,第二个参数是列数,第三个参数表示图形的标号
        plt.subplot(2, num_images, i + 1)
        plt.imshow(X[:, index].reshape(64, 64, 3), interpolation='nearest')
        plt.axis('off')#plt.axis(‘off’) 关闭坐标轴 ;plt.axis(‘square’) 作图为正方形,并且x,y轴范围相同 ; plt.axis(‘equal’) x,y轴刻度等长
        plt.title(
            "Prediction: " + classes[int(p[0, index])].decode("utf-8") + " \n Class: " + classes[y[0, index]].decode(
                "utf-8"))


print_mislabeled_images(classes, test_x, test_y, pred_test)

后续有问题还会补充!!!

你可能感兴趣的:(吴恩达深度学习,python函数,笔记,深度学习,python,人工智能)