AI learning note 3 -- 程序实战

AI learning note

程序实战

在学习完第一章后,开始学习实战优化的同时,将构建神经网络的实战代码又复习了一边,这里直接将学到的DNN的构建部分和过程做一个记录并将其中拓展学习到的知识点做一个总结,算是入门的小里程碑。

内容是使用DNN模型下训练一个识别动物的神经网络。


一、工具库导入

# 加载工具库
import numpy as np
import h5py
import matplotlib.pyplot as plt
from dnn_utils import *

h5py是python 用于分析处理hdf5数据文件的一个工具库

最近有在学习一点数据库的知识,在MYSQL的命令里学到了" * "代表的意思就是全部

dnn_utils中是 sigmoid,relu函数以及通过它们的求导公式去计算最后一层的dz(最后一层z的偏导数)的实现代码,也包含了h5py中读取文件,并将数据赋予对应变量的方法。 这些与DNN的整体架构无关,这里不再附贴代码。

二、设置画图的相关参数

# 设置画图相关参数
plt.rcParams['figure.figsize'] = (5.0, 4.0)  # 视图窗口大小,英寸表示
plt.rcParams['image.interpolation'] = 'nearest'  # 插值方式
# interpolation,即插值,利用已知邻近像素点的灰度值来产生未知像素点的灰度值
plt.rcParams['image.cmap'] = 'gray'  # 使用灰度输出

关于matplotlib的学习实在是很少,只知道很简单的一些函数参数的应用,几乎是遇到一个用的都不认识,以后关于图形处理还要多加学习。

PS:话说今天听了一个教授的图像处理讲座的第一课,学到了图像处理的对象是针对自然界中真实存在的画面,而图形处理才是针对计算机生成画出来的结果。(实在是太小白了,路还长,慢慢走)

三、初始化DNN各层参数

# 初始化dnn各层神经网络的w,b参数
def initialize_parameters_deep(layer_dims):
    np.random.seed(1)
    parameters = {}  # 存储初始化参数
    L = len(layer_dims)  # 获取神经网络总层数(包含了输入层)
    # 遍历每一层,并初始化相关参数
    for i in range(1, L):  # 输入层不包括在内
        parameters['W' + str(i)] = np.random.randn(layer_dims[i], layer_dims[i - 1]) / np.sqrt(layer_dims[i - 1])
        parameters['b' + str(i)] = np.zeros((layer_dims[i], 1))

        assert (parameters['W' + str(i)].shape == (layer_dims[i], layer_dims[i - 1]))
        assert (parameters['b' + str(i)].shape == (layer_dims[i], 1))

    return parameters

关于参数初始化,多层神经网络W不能初始化为0不必再说,但对于有列表出现的时候(这里layer_dims是一个包含第一层数据输入及各层数神经元个数的列表)由于列表的第一个索引值为0,而我们要存储的参数的下标为神经网络层数(不包含输入层,从1开始),所以一定要认真核对,进行测试,保证不出现逻辑错误导致代码运行出现下标溢出现象。

四、构建模型所需的工具函数

1. 线性前向传播

def linear_forward(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

2. 激活函数映射

# 然后是 套用激活函数的前向传播,使线性变为非线性传播
def linear_activation_forward(A_prev, W, b, activation):
    Z, linear_cache = linear_forward(A_prev, W, b)  # 线性前向传播得出线性预测值
    if activation == 'sigmoid':
        A = sigmoid(Z)  # 得出前向传播预测值
    elif activation == 'relu':
        A = relu(Z)

    assert (A.shape == (W.shape[0], A_prev.shape[1]))
    cache = (linear_cache, Z)

    return A, cache

在写这部分的时候,想起来了之前学到高阶函数可以直接把函数名赋给变量,然后用变量直接充当函数,第一次耍小聪明写出来了

A = activation(Z)

这样的代码,但是缺点也很明显,在调用函数的时候容易赋值不清楚,而且整个代码也会结构不清楚,逻辑不直白通顺,以后还是要按照赋值的逻辑来写,便于调用也便于提高多值域时代码的可读性。

3. 完整前向传播模型

# 构建一个完整的前向传播过程
def L_model_forward(X, parameters):
    A_prev = X  # 输入初始化
    caches = []  # 存储过程中产生的变量值,为反向传播做准备
    L = len(parameters) // 2  # 取得神经网络的层数(不包含输入层)
    # 遍历第 1~L-1 层 这L-1层使用relu作为激活函数
    for i in range(1, L):
        # 取出本层的w,b参数
        W = parameters['W' + str(i)]
        b = parameters['b' + str(i)]

        # 进行激活函数套用
        A_prev, linear_cache = linear_activation_forward(A_prev, W, b, activation='relu')
        caches.append(linear_cache)

    # 第L层我们使用sigmoid函数作为激活函数
    WL = parameters['W' + str(L)]
    bL = parameters['b' + str(L)]
    AL, final_cache = linear_activation_forward(A_prev, WL, bL, activation='sigmoid')
    caches.append(final_cache)

    assert (AL.shape == (1, X.shape[1]))
    return AL, caches

4. 成本 / 损失计算函数

def compute_cost(AL, Y):
    m = Y.shape[1]
    cost = - np.sum(Y * np.log(AL) + (1 - Y) * np.log(1 - AL)) / m
    cost = np.squeeze(cost)
    assert (cost.shape == ())

    return cost

这里的squeeze是保证返回的cost不是一个数组而是数值,编写代码的时候Pycharm也友好的提醒我这个cost是ndarray类型

关于numpy中的数组处理常用的搞得也差不多清楚了,之后要系统的学习一下,然后再加以总结。

5. 线性反向传播

# 计算线性反向传播
def linear_backward(dZ, cache):
    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

6. 激活函数反向传播

# 计算激活函数后的反向传播
def linear_activation_backward(dA, cache, activation):
    linear_cache, activation_cache = cache
    if activation == 'sigmoid':
        dZ = sigmoid_backward(dA, activation_cache)
    elif activation == 'relu':
        dZ = relu_backward(dA, activation_cache)
    dA_prev, dW, db = linear_backward(dZ, linear_cache)

    return dA_prev, dW, db

7. 完整反向传播模型

# 构建整个反向传播的模型
def L_model_backward(AL, Y, caches):
    grads = {}  # 用来存放各层的参数
    L = len(caches)  # caches列表长度就为神经网络的层数(不包括输入层)
    Y = Y.reshape(AL.shape)  # 保证真实标签与预测标签维度一致
    dAL = - (Y / AL) + (1 - Y) / (1 - AL)  # 求出最后一层A的偏导数
    grads['dA' + str(L - 1)], grads['dW' + str(L)], grads['db' + str(L)] = linear_activation_backward(dAL,
                                                                                                      caches[-1],
                                                                                                      'sigmoid')
    for i in reversed(range(1, L)):  # 遍历神经网络的第1~L-1层,并将各层的参数计入grads,递归式的求出梯度
        grads['dA' + str(i - 1)], grads['dW' + str(i)], grads['db' + str(i)] = linear_activation_backward(
            grads['dA' + str(i)],
            caches[i - 1],
            activation='relu')

    return grads

8. 各层参数更新

# 根据梯度,对每一层的神经元的w,b参数进行更新
def update_parameters(parameters, grads, learning_rate):
    L = len(parameters) // 2
    for i in range(1, L + 1):
        parameters['W' + str(i)] = parameters['W' + str(i)] - learning_rate * grads['dW' + str(i)]
        parameters['b' + str(i)] = parameters['b' + str(i)] - learning_rate * grads['db' + str(i)]
    return parameters

五、构建DNN模型

# 整合构建一个深度神经网络训练模型
def dnn_model(X, Y, layers_dim, learning_rate=0.0075, num_iterations=3000, print_cost=False):
    np.random.seed(1)
    A_prev = X
    costs = []
    # 初始化各层的w,b参数
    parameters = initialize_parameters_deep(layers_dim)

    for i in range(num_iterations):
        AL, caches = L_model_forward(X, parameters)  # 前向传播

        grads = L_model_backward(AL, Y, caches)  # 反向传播求梯度

        parameters = update_parameters(parameters, grads, learning_rate)  # 对w,b参数进行更新

        if i % 100 == 0 and i != 0:  # 每一百次打印出成本
            cost = compute_cost(AL, Y)
            costs.append(cost)
            if print_cost:
                print('训练%i次后,成本为 %f' % (i, 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

六、预测函数

# 编写预测函数
def dnn_predict(X, parameters):
    m = X.shape[1]  # 获取样本数量,为了生成一个对应的0,1矩阵表示X的预测结果
    p = np.zeros((1, m))
    A, caches = L_model_forward(X, parameters)  # 进行一次前向传播,得出预测结果
    # 将预测结果转化为一个0,1矩阵,通过设置的阈值来进行分类 (这里使用p来表示最后结果,不去对A进行直接修改)
    # 目的应该有节省内存使用和保证代码的条理性
    for i in range(m):
        if A[0, i] > 0.5:
            p[0, i] = 1

    return p

七、示例测试

# 测试一个神经网络示例
train_x_orig, train_y, test_x_orig, test_y, classes = load_data()  # 加载数据集
m_train = train_x_orig.shape[0]  # 取得训练样本数
m_test = test_x_orig.shape[0]  # 取得测试样本数
num_px = train_x_orig.shape[1]  # 取得图片的长宽像素

# 对样本数据进行扁平化与转置 目的是为了进行正常的矩阵运算 处理后的维度含义为(样本数据,样本数)
train_x_flatten = train_x_orig.reshape(train_x_orig.shape[0], -1).T
test_x_flatten = test_x_orig.reshape(test_x_orig.shape[0], -1).T

# 对样本数据进行简单的标准化
train_x = train_x_flatten / 255
test_x = test_x_flatten / 255

# 设置神经网络的维度
layer_dims = [12288, 20, 7, 5, 1]

# 进行模型的训练
parameters = dnn_model(train_x, train_y, layer_dims, num_iterations=2000, print_cost=True)

# 对训练数据和测试数据分别进行预测
train_predict = dnn_predict(train_x, parameters)
print('对训练数据的预测准确率为: ' + str(np.sum(train_predict == train_y) / m_train * 100) + '%')
test_predict = dnn_predict(test_x, parameters)
print('对测试数据的预测准确率为: ' + str(np.sum(test_predict == test_y) / m_test * 100) + '%')

# 查看一张图片预测是否正确
index = 40
plt.imshow(test_x[:, index].reshape(num_px, num_px, 3))
plt.show()
print('这张图的标签为'
      + str(test_y[0, index])
      + ',预测结果为'
      + str(int(test_predict[0, index]))
      + '即这是一张'
      + str(classes[int(test_predict[0, index])].decode())
      + '图')

八、实验结果

成本及准确率:

训练100次后,成本为 0.672053
训练200次后,成本为 0.648263
训练300次后,成本为 0.611507
训练400次后,成本为 0.567047
训练500次后,成本为 0.540138
训练600次后,成本为 0.527930
训练700次后,成本为 0.465477
训练800次后,成本为 0.369126
训练900次后,成本为 0.391747
训练1000次后,成本为 0.315187
训练1100次后,成本为 0.272700
训练1200次后,成本为 0.237419
训练1300次后,成本为 0.199601
训练1400次后,成本为 0.189263
训练1500次后,成本为 0.161189
训练1600次后,成本为 0.148214
训练1700次后,成本为 0.137775
训练1800次后,成本为 0.129740
训练1900次后,成本为 0.121225
对训练数据的预测准确率为: 98.08612440191388%
对测试数据的预测准确率为: 80.0%
在这里插入图片描述

个例查看:

这张图的标签为1,预测结果为1即这是一张cat图
在这里插入图片描述

九、总结

实现出了一个入门级别的DNN,进步感还是有的,但是不足暴露的越来越多越来越多,但是谁让自己喜欢呢,选择了人工智能这条长路,道阻且长,就慢慢走下去吧。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值