在本文开始之前,首先声明参考了博主,本文的训练集与测试集均来自:【中文】【吴恩达课后编程作业】Course 1 - 神经网络和深度学习 - 第二周作业_吴恩达机器学习课后作业目录对应视频-CSDN博客

再结合自己对于SIgmoid函数的理解,故写下了本文的代码,故想给多方面学习Sigmoid函数的小伙伴一些小参考:

我们要做的事是搭建一个能够【识别猫】 的简单的神经网络。

在开始之前,我们有需要引入的库:

numpy :是用Python进行科学计算的基本软件包。
h5py:是与H5文件中存储的数据集进行交互的常用软件包。
lr_utils :在本文的资料包里,一个加载资料包里面的数据的简单功能的库。

import numpy as np
import h5py, copy, math

接下来是从.h5文件中读取相应的数据:

def load_dataset():

    train_dataset = h5py.File('C:\\Users\\86134\\PycharmProjects\\Machine_learning\\datasets\\train_catvnoncat.h5', 'r')
    train_set_x_orig = np.array(train_dataset['train_set_x'][:])
    train_set_y_orig = np.array(train_dataset['train_set_y'][:])

    test_dataset = h5py.File('C:\\Users\\86134\\PycharmProjects\\Machine_learning\\datasets\\test_catvnoncat.h5', 'r')
    test_set_x_orig = np.array(test_dataset['test_set_x'][:])
    test_set_y_orig = np.array(test_dataset['test_set_y'][:])

    classes = np.array(test_dataset["list_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

直接读取数据可不行,因为直接读取到的图片的维度是(209,64,64,3),如果直接对其进行运算的话不仅加大时间消耗和空间的消耗,因此还得对相应的数据进行平坦化,归一化:

#平坦图片,方便后续操作
def flatten_img(train_set_x_orig, test_set_x_orig):

    #多维数组格式转换为二维矩阵格式
    train_set_x_flatten = train_set_x_orig.reshape(train_set_x_orig.shape[0], -1).T
    test_set_x_flatten = test_set_x_orig.reshape(test_set_x_orig.shape[0], -1).T

    return train_set_x_flatten, test_set_x_flatten

#归一化
def normalize_img(train_set_x_flatten, test_set_x_flatten):

    train_set_x = train_set_x_flatten / 255.0
    test_set_x = test_set_x_flatten / 255.0

    return train_set_x, test_set_x

这里解释一下为什么要对flatten之后的数据要进行转置,因为要确保我们的数据特征在行上,样本在列上。

在进行核心逻辑回归算法之前,还得对w和b进行初始化:

def initialize_parameters(dim):

    #dim为维度,即输入X的维度,为w创建一个维度为(dim,1)的向量。方便后面进行矩阵计算
    w = np.zeros(shape=(dim, 1))
    b = 0.0

    return w, b

接下来是核心的逻辑回归算法了:

sigmoid公式:

def sigmoid(z):

    return 1.0 / (1.0 + np.exp(-z))

计算sigmoid的损失值:
 

def compute_cost_sigmoid(X, y, w, b):

    m = X.shape[1] #样本数量

    # for i in range(m):
    #     z_i = np.dot(X, w) + b
    #     f_wb_i = sigmoid(z_i)
    #     cost += -y[i] * np.log(f_wb_i) - (1 - y[i]) * np.log(1 - f_wb_i)
    #
    # cost /= m

    A = sigmoid(np.dot(w.T, X) + b)
    cost = (-1.0 / m) * np.sum(y * np.log(A) + (1 - y) * np.log(1 - A))

    return cost

这里保留了使用最原始的循环计算,但是效率不高,后面改成了使用向量来直接计算,下面计算梯度也是一样。

计算sigmoid的梯度:

def compute_sigmoid_descent(X, y, w, b):

    # 获取X的行数和列数
    # m, n = X.shape
    # dj_dw = np.zeros((n, ))
    # dj_db = 0.0
    #
    # for i in range(m):
    #     z_i = np.dot(X[i], w) + b
    #     f_wb_i = sigmoid(z_i)
    #     err_i = f_wb_i - y[i] #与目标值的误差
    #
    #     for j in range(n):
    #         dj_dw[j] = dj_dw[j] + err_i * X[i, j] # #计算代价函数对每个权重参数 w_j 的偏导数(梯度)的累加值。
    #     dj_db += err_i
    # dj_dw /= m
    # dj_db /= m

    n, m = X.shape #n为特征数量, m为样本数量

    A = sigmoid(np.dot(w.T, X) + b)
    dz = A - y

    dj_dw = (1.0 / m) * np.dot(X, dz.T)
    dj_db = (1.0 / m) * np.sum(dz)

    return dj_dw, dj_db

接下来是计算梯度更新了:

def gradient_descent(X, y, w_in, b_in, learning_rate, num_iterations):

    j_history = []
    w = copy.deepcopy(w_in)
    b = b_in

    for i in range(num_iterations):
        #计算当前的梯度并且更新参数
        dj_dw, dj_db = compute_sigmoid_descent(X, y, w, b)
        #更新
        w = w - learning_rate * dj_dw
        b = b - learning_rate * dj_db

        #保存当前损失值
        if i < 10000:
            j_history.append(compute_cost_sigmoid(X, y, w, b))

        #输出
        if i % math.ceil(num_iterations / 10) == 0:
            print(f"Iteration {i:4d}: Cost {j_history[-1]} ")

    return w, b, j_history

这里还得实现预测函数,用来判断对应的图片是否是猫:
 

def predict(X, w, b):

    m = X.shape[1] #图片的数量
    Y_prediction = np.zeros((1, m))

    #计算猫在图片中出现的概率
    A = sigmoid(np.dot(w.T, X) + b)

    for i in range(A.shape[1]):
        #将概率a[0, i]转换为实际预测p[0, i]
        Y_prediction[0, i] = 1 if A[0, i] > 0.5 else 0

    return Y_prediction

最后整合一下以上所有的函数,不然全写在main里面显得太乱,观感不好:

def model(X_train, Y_train, X_test, Y_test, learning_rate, num_iterations):

    w_init, b_init = initialize_parameters(X_train.shape[0])

    w, b, costs = gradient_descent(X_train, Y_train, w_init, b_init, learning_rate, num_iterations)

    #进行猫预测
    Y_prediction_train = predict(X_train, w, b)
    Y_prediction_test = predict(X_test, w, b)

    # 打印训练后的准确性
    print("训练集准确性:", format(100 - np.mean(np.abs(Y_prediction_train - Y_train)) * 100), "%")
    print("测试集准确性:", format(100 - np.mean(np.abs(Y_prediction_test - Y_test)) * 100), "%")

    params = {
        "costs": costs,
        "Y_prediction_train": Y_prediction_train,
        "Y_prediction_test": Y_prediction_test,
        "learning_rate": learning_rate,
        "num_iterations": num_iterations,
        "w" : w,
        "b" : b
    }

    return params

最后运行的结果为:

一下是完整的代码:

import numpy as np
import h5py, copy, math

#读取数据
def load_dataset():

    train_dataset = h5py.File('C:\\Users\\86134\\PycharmProjects\\Machine_learning\\datasets\\train_catvnoncat.h5', 'r')
    train_set_x_orig = np.array(train_dataset['train_set_x'][:])
    train_set_y_orig = np.array(train_dataset['train_set_y'][:])

    test_dataset = h5py.File('C:\\Users\\86134\\PycharmProjects\\Machine_learning\\datasets\\test_catvnoncat.h5', 'r')
    test_set_x_orig = np.array(test_dataset['test_set_x'][:])
    test_set_y_orig = np.array(test_dataset['test_set_y'][:])

    classes = np.array(test_dataset["list_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

#平坦图片,方便后续操作
def flatten_img(train_set_x_orig, test_set_x_orig):

    #多维数组格式转换为二维矩阵格式
    train_set_x_flatten = train_set_x_orig.reshape(train_set_x_orig.shape[0], -1).T
    test_set_x_flatten = test_set_x_orig.reshape(test_set_x_orig.shape[0], -1).T

    return train_set_x_flatten, test_set_x_flatten

#归一化
def normalize_img(train_set_x_flatten, test_set_x_flatten):

    train_set_x = train_set_x_flatten / 255.0
    test_set_x = test_set_x_flatten / 255.0

    return train_set_x, test_set_x

"""
    接下来是核心逻辑回归算法
"""

def sigmoid(z):

    return 1.0 / (1.0 + np.exp(-z))

def initialize_parameters(dim):

    #dim为维度,即输入X的维度,为w创建一个维度为(dim,1)的向量。方便后面进行矩阵计算
    w = np.zeros(shape=(dim, 1))
    b = 0.0

    return w, b

#计算sigmoid的损失值
def compute_cost_sigmoid(X, y, w, b):

    m = X.shape[1] #样本数量

    # for i in range(m):
    #     z_i = np.dot(X, w) + b
    #     f_wb_i = sigmoid(z_i)
    #     cost += -y[i] * np.log(f_wb_i) - (1 - y[i]) * np.log(1 - f_wb_i)
    #
    # cost /= m

    A = sigmoid(np.dot(w.T, X) + b)
    cost = (-1.0 / m) * np.sum(y * np.log(A) + (1 - y) * np.log(1 - A))

    return cost

#计算sigmoid的梯度
def compute_sigmoid_descent(X, y, w, b):

    # 获取X的行数和列数
    # m, n = X.shape
    # dj_dw = np.zeros((n, ))
    # dj_db = 0.0
    #
    # for i in range(m):
    #     z_i = np.dot(X[i], w) + b
    #     f_wb_i = sigmoid(z_i)
    #     err_i = f_wb_i - y[i] #与目标值的误差
    #
    #     for j in range(n):
    #         dj_dw[j] = dj_dw[j] + err_i * X[i, j] # #计算代价函数对每个权重参数 w_j 的偏导数(梯度)的累加值。
    #     dj_db += err_i
    # dj_dw /= m
    # dj_db /= m

    n, m = X.shape #n为特征数量, m为样本数量

    A = sigmoid(np.dot(w.T, X) + b)
    dz = A - y

    dj_dw = (1.0 / m) * np.dot(X, dz.T)
    dj_db = (1.0 / m) * np.sum(dz)

    return dj_dw, dj_db

#梯度下降
def gradient_descent(X, y, w_in, b_in, learning_rate, num_iterations):

    j_history = []
    w = copy.deepcopy(w_in)
    b = b_in

    for i in range(num_iterations):
        #计算当前的梯度并且更新参数
        dj_dw, dj_db = compute_sigmoid_descent(X, y, w, b)
        #更新
        w = w - learning_rate * dj_dw
        b = b - learning_rate * dj_db

        #保存当前损失值
        if i < 10000:
            j_history.append(compute_cost_sigmoid(X, y, w, b))

        #输出
        if i % math.ceil(num_iterations / 10) == 0:
            print(f"Iteration {i:4d}: Cost {j_history[-1]} ")

    return w, b, j_history

#实现预测函数
def predict(X, w, b):

    m = X.shape[1] #图片的数量
    Y_prediction = np.zeros((1, m))

    #计算猫在图片中出现的概率
    A = sigmoid(np.dot(w.T, X) + b)

    for i in range(A.shape[1]):
        #将概率a[0, i]转换为实际预测p[0, i]
        Y_prediction[0, i] = 1 if A[0, i] > 0.5 else 0

    return Y_prediction

#整合函数
def model(X_train, Y_train, X_test, Y_test, learning_rate, num_iterations):

    w_init, b_init = initialize_parameters(X_train.shape[0])

    w, b, costs = gradient_descent(X_train, Y_train, w_init, b_init, learning_rate, num_iterations)

    #进行猫预测
    Y_prediction_train = predict(X_train, w, b)
    Y_prediction_test = predict(X_test, w, b)

    # 打印训练后的准确性
    print("训练集准确性:", format(100 - np.mean(np.abs(Y_prediction_train - Y_train)) * 100), "%")
    print("测试集准确性:", format(100 - np.mean(np.abs(Y_prediction_test - Y_test)) * 100), "%")

    params = {
        "costs": costs,
        "Y_prediction_train": Y_prediction_train,
        "Y_prediction_test": Y_prediction_test,
        "learning_rate": learning_rate,
        "num_iterations": num_iterations,
        "w" : w,
        "b" : b
    }

    return params

if __name__ == '__main__':

    learning_rate = 0.01
    num_iterations = 2000

    train_set_x_orig, train_set_y, test_set_x_orig, test_set_y, classes = load_dataset() #加载数据

    train_set_x_flatten, test_set_x_flatten = flatten_img(train_set_x_orig, test_set_x_orig) #平坦数据

    train_set_x, test_set_x = normalize_img(train_set_x_flatten, test_set_x_flatten) #归一化数据

    params = model(train_set_x, train_set_y, test_set_x, test_set_y, learning_rate, num_iterations)
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐