吴恩达深度学习第一章第三周编程作业

文章目录

  • 一、题目描述
  • 二、编程步骤
    • 1.引入库
    • 2.训练数据准备
    • 2.逻辑回归完成二分类
    • 3.构建隐藏层数量为1的神经网络
      • 3.1公式推导
      • 3.2初始化
      • 3.3 激活函数
      • 3.4正向传播
      • 3.5 反向传播
      • 3.6 计算loss
      • 3.7 预测函数
      • 3.8 主控函数
    • 4 运行
  • 总结


一、题目描述

吴恩达深度学习第一章第三周编程作业_第1张图片

吴恩达深度学习第一章第三周编程作业_第2张图片

二、编程步骤

1.引入库

  这次编程作业涉及到的库与上次作业基本相同,主要是numpy和matplotlib。

2.训练数据准备

  我们可以根据numpy库有目的的生成训练集。

def load_planar_dataset():
    np.random.seed(1)
    m = 400  # number of examples
    N = int(m / 2)  # number of points per class
    D = 2  # dimensionality
    X = np.zeros((m, D))  # data matrix where each row is a single example
    Y = np.zeros((m, 1), dtype='uint8')  # labels vector (0 for red, 1 for blue)
    a = 4  # maximum ray of the flower

    for j in range(2):
        ix = range(N * j, N * (j + 1))
        t = np.linspace(j * 3.12, (j + 1) * 3.12, N) + np.random.randn(N) * 0.2  # theta
        r = a * np.sin(4 * t) + np.random.randn(N) * 0.2  # radius
        X[ix] = np.c_[r * np.sin(t), r * np.cos(t)]
        Y[ix] = j

    X = X.T
    Y = Y.T

    return X, Y

  这里通过函数 load_planar_dataset 生成了数据集X(2,400),和标签集Y(1,400)。通过matplotlib 绘制散点图:
吴恩达深度学习第一章第三周编程作业_第3张图片
  以上就是我们这次作业需要使用的数据集。

2.逻辑回归完成二分类

上一周作业中我们手撸了一遍逻辑回归代码,从激活函数到损失函数再到正向反向传播,逻辑回归模型可以看成是隐藏层数量为0的神经网络结构。python中其实已经提供了相关的机器学习库(sklearn)来帮助我们快速的建立逻辑回归模型,我们利用sklearn库建立逻辑回归模型来对我们生成的数据进行分类。

import sklearn
from planar_utils import load_planar_dataset, plot_decision_boundary
import matplotlib.pyplot as plt
import numpy as np

X, Y = load_planar_dataset()
clf = sklearn.linear_model.LogisticRegressionCV()
clf.fit(X.T, Y.T)

plot_decision_boundary(lambda x: clf.predict(x), X, Y)  # 绘制决策边界
plt.title("Logistic Regression")  # 图标题
LR_predictions = clf.predict(X.T)  # 预测结果
print("逻辑回归的准确性: %d " % float((np.dot(Y, LR_predictions) +
                               np.dot(1 - Y, 1 - LR_predictions)) / float(Y.size) * 100) +
      "% " + "(正确标记的数据点所占的百分比)")

  结果如下:
在这里插入图片描述
  利用matplotlib绘制逻辑回归的决策边界。
吴恩达深度学习第一章第三周编程作业_第4张图片
  从结果可以看出逻辑回归模型表现效果很差,也可以认为隐藏层数量为0的神经网络结构表现效果较差。

3.构建隐藏层数量为1的神经网络

  根据题目要求,我们可以将神经网络设计为如下结构:
吴恩达深度学习第一章第三周编程作业_第5张图片
  隐藏层的神经单元使用的激活函数为 tanh ,因为本次任务为二分类任务,输出层的激活函数可以为sigmoid。

3.1公式推导

  编程的重难点在于反向传播,作为初学者,加之这个神经网络结构比较简单,可以推导一下我们需要使用到的公式。
吴恩达深度学习第一章第三周编程作业_第6张图片
(在计算dz1的时候,W2需要转置,漏掉了个T)

3.2初始化

  我将单层神经网络封装成类 SimpleNN

class SimpleNN(object):
    def __init__(self, input_layer, hidden_layer, output_layer):
        """
        初始化神经网络,这里的隐藏层只有一层
        :param input_layer: 输入层神经元个数
        :param hidden_layer: 隐藏层神经元个数
        :param output_layer: 输出层神经元个数
        """
        self.w = []
        self.b = []
        self.z = []
        self.a = []
        self.input_layer = input_layer
        self.hidden_layer = hidden_layer
        self.output_layer = output_layer
        self.initialize_parameters()

  隐藏层层数的设置默认为1层,没有考虑其他情况。需要注意的是,在正向传播时我们需要保存每一层 az 的计算结果,这也是视频中说的 cache

  当我们获得了各层的参数时,可以对 wb 进行初始化。

    def initialize_parameters(self):
        w1 = np.random.randn(self.hidden_layer, self.input_layer)
        w2 = np.random.randn(self.output_layer, self.hidden_layer)

        assert (w1.shape == (self.hidden_layer, self.input_layer))
        assert (w2.shape == (self.output_layer, self.hidden_layer))

        self.w = [w1, w2]

        b1 = numpy.zeros(shape=(self.hidden_layer, 1))
        b2 = numpy.zeros(shape=(self.output_layer, 1))

        assert (b1.shape == (self.hidden_layer, 1))
        assert (b2.shape == (self.output_layer, 1))

        self.b = [b1, b2]

3.3 激活函数

  隐藏层的激活函数为tanh,numpy库有自带的函数完成tanh函数功能。sigmoid函数需要自己编写。

    def sigmoid(self, z):
        """
        sigmoid激活函数,用于output层
        :param z: 输入
        :return:
        """
        return 1 / (1 + np.exp(-z))

  接下来可以根据计算顺序来设计相应的函数。

3.4正向传播

  正向传播比较容易实现。

 def forward(self, X):
        """
        前向传播
        :param X: 样本集
        :return:
        """
        m = X.shape[1]
        Z1 = np.dot(self.w[0], X) + self.b[0]
        A1 = np.tanh(Z1)

        Z2 = np.dot(self.w[1], A1) + self.b[1]
        A2 = self.sigmoid(Z2)

        self.z = [Z1, Z2]
        self.a = [X, A1, A2]

3.5 反向传播

    def backward(self, Y, learning_rate):
        """
        反向传播
        :param Y: 实际标签值
        :param learning_rate: 学习率
        :return:
        """
        sample_num = Y.shape[1]
        dZ2 = self.a[2] - Y
        dW2 = (1 / sample_num) * np.dot(dZ2, self.a[1].T)
        db2 = (1 / sample_num) * np.sum(dZ2, axis=1, keepdims=True)

        dZ1 = np.multiply(np.dot(self.w[1].T, dZ2), 1 - np.power(self.a[1], 2))
        dW1 = (1 / sample_num) * np.dot(dZ1, self.a[0].T)
        db1 = (1 / sample_num) * np.sum(dZ1, axis=1, keepdims=True)

        self.w[0] = self.w[0] - learning_rate * dW1
        self.w[1] = self.w[1] - learning_rate * dW2

        self.b[0] = self.b[0] - learning_rate * db1
        self.b[1] = self.b[1] - learning_rate * db2

  注意有的地方用的是点乘np.dot有的地方是np.multiply().

3.6 计算loss

    def compute_loss(self, A, Y):
        """
        计算损失函数
        :param A: 预测结果
        :param Y: 实际结果
        :return:
        """
        m = Y.shape[1]
        total_loss = (-1) * np.multiply(Y, np.log(A)) + np.multiply((1 - Y), np.log(1 - A))
        cost = (1 / m) * np.sum(total_loss)
        cost = float(np.squeeze(cost))
        assert (isinstance(cost, float))

        return cost

3.7 预测函数

    def predict(self, X):
        """
        预测函数
        :param X: 输入数据
        :return: 
        """
        self.forward(X)
        return np.round(self.a[2])

3.8 主控函数

    def nn_model(self, X, Y, learning_rate, iterations):
        """
        主控函数
        :param X: 输入样本
        :param Y: 实际标签值
        :param learning_rate: 学习率
        :param iterations: 迭代次数
        :return:
        """
        for i in range(0, iterations):
            self.forward(X)
            self.backward(Y, learning_rate)
            cost = self.compute_loss(self.a[2], Y)

4 运行

 X, Y = load_planar_dataset()
    nn = SimpleNN(2, 4, 1)
    nn.nn_model(X, Y, iterations=10000, learning_rate=0.5)
    # 绘制边界
    plot_decision_boundary(lambda x: nn.predict(x.T), X, Y)
    plt.title("Decision Boundary for hidden layer size " + str(4))
    plt.show()

    predictions = nn.predict(X)
    print('准确率: %d' % float((np.dot(Y, predictions.T) + np.dot(1 - Y, 1 - predictions.T)) / float(Y.size) * 100) + '%')

  运行结果:
在这里插入图片描述

  绘制决策边界:
吴恩达深度学习第一章第三周编程作业_第7张图片
  可以看出增加一层隐藏层后,效果增加明显。

总结

  具体代码已经放入百度网盘中,提取码:ck6t。代码质量不是太高,请见谅。

你可能感兴趣的