BP反向传播

举报
诡途 发表于 2022/02/23 18:01:18 2022/02/23
【摘要】 """案例:研究生学院录取数据,用梯度下降训练一个网络。数据有三个输入特征:GRE 分数、GPA 分数和本科院校排名(从 1 到 4)。排名 1 代表最好,排名 4 代表最差。"""# ----------分隔线-------------"""数据解读说明:admit 0未录取 1 录取gre分数 gpa绩点分数 rank 本科院校等级#数据预处理admit --目标标签ran...
"""
案例:研究生学院录取数据,用梯度下降训练一个网络。
数据有三个输入特征:GRE 分数、GPA 分数和本科院校排名(从 1 到 4)。排名 1 代表最好,排名 4 代表最差。
"""
# ----------分隔线-------------
"""
数据解读说明:
admit  0未录取 1 录取
gre分数   gpa绩点分数     rank 本科院校等级

#数据预处理
admit --目标标签
rank ---分类变量--》亚编码|one-hot独热编码,相当于去除量纲的影响
gre,gpa ---连续变量---》标准化,去除量纲影响
"""
import numpy as np
import pandas as pd

# 设置显示内容属性,防止pandas打印不全
pd.set_option('display.max_columns', 1000)
pd.set_option('display.width', 1000)
pd.set_option('display.max_colwidth', 1000)

admissions = pd.read_csv('./datas/11.csv')


def data_explore(admissions):
    print(admissions.head(n=10))
    print(admissions.info())  # 查看是否有空值,以及数据类型
    print(admissions.describe())  # 再次可以看到是否有空值,以及值范围,需要考虑做数据变换。
    print('各个样本相应的数量为:{}'.format(admissions['admit'].value_counts()))  # 查看样本是否均衡
    # 100:1是不均衡的,1的样本是学不会的


"""
一、数据清理
    1、分类变量哑编码
    rank 是类别特征,其中的数字并不表示任何相对的值。排名第 2 并不是排名第 1 的两倍;
    排名第 3 也不是排名第 2 的 1.5 倍。因此,我们需要用哑变量 来对 rank 进行编码。
    把数据分成 4 个新列,用 0 或 1 表示。排名为 1 的行对应 rank_1 列的值为 1 ,其余三列的值为 0;
    排名为 2 的行对应 rank_2 列的值为 1 ,其余三列的值为 0,以此类推。
    2、连续变量标准化
    把 GRE 和 GPA 数据标准化,变成均值为 0,标准偏差为 1。因为 sigmoid 函数会挤压很大或者很小的输入。
    很大或者很小输入的梯度为 0,这意味着梯度下降的步长也会是 0。
"""


def data_transform(admissions):
    """
    一  rank代表学校等级(1--4),转成哑变量
    1、 用pd.get_dummies 将rank列,转成哑变量,新变量名前缀为:prefix='rank'
    2、将原数据集admissions 和 1 进行列拼接;
    3、drop原始的rank列。
    """
    data = pd.concat([admissions, pd.get_dummies(admissions['rank'], prefix='rank')], axis=1)
    data = data.drop('rank', axis=1)

    """
    二、gre和gpa变量的标准化
    标准做法:先拆分数据集--使用训练数据集的统计量 去标准化 验证和测试。
    """

    for field in ['gre', 'gpa']:
        mean, std = data[field].mean(), data[field].std()
        data.loc[:, field] = (data[field] - mean) / std

    """
    三、数据拆分:分成训练 和 测试数据集
    1、设置随机数种子,确保大家执行和我们这里演示的结果一致;
    2、使用np.random.choice,随机选择数据集中90% 数据的index
    """
    # 随机打乱,并将数据集拆分为  90%训练---10%测试数据集。
    np.random.seed(42)
    sample = np.random.choice(data.index, size=int(len(data) * 0.9), replace=False)
    train_data, test_data = data.iloc[sample], data.drop(sample)

    """
    四、 将自变量(features)和目标值分离
    """
    features_train, targets_train = train_data.drop('admit', axis=1), train_data['admit']
    features_test, targets_test = test_data.drop('admit', axis=1), test_data['admit']

    return features_train, targets_train, features_test, targets_test


# ***************************************
"""
GRE带隐藏层反向传播案例
   先介绍 伪代码 和 梯度求导 流程
"""


# ***************************************


def sigmoid(x):
    # 激活函数  1/(1+e^(-z))
    return 1 / (1 + np.exp(-x))


def gre_bp_answer(features_train, targets_train, features_test, targets_test):
    """
    gre反向传播函数
    :return:
    """
    # 1、设置超参数
    n_hidden = 2  # 隐藏层节点数量
    epochs = 1000  # 迭代的次数
    learning_rate = 0.05  # 学习率
    # 2、获取样本的数量和特征数量
    n_reords, n_features = features_train.shape
    last_loss = None
    # 3、构建模型权重(2个权重)--无偏置项,因为数据是标准化后的,偏置项为0
    weights_input_hidden = np.random.normal(
        loc=0.0, scale=1 / n_features ** 0.5, size=(n_features, n_hidden)  # loc 均值   scale标准差 1/根号下n_features
    )
    weights_hidden_output = np.random.normal(
        scale=1 / n_hidden ** 0.5, size=n_hidden
    )
    # 4、构建模型循环
    for e in range(1, epochs):
        # 定义2个del_w 并初始化为0,用于存储梯度值的
        del_w_input_hidden = np.zeros(weights_input_hidden.shape)
        del_w_hidden_output = np.zeros(weights_hidden_output.shape)
        # 构建遍历数据集的循环
        for x, y in zip(features_train.values, targets_train):
            # 5、正向传播
            hidden_input = np.matmul(x, weights_input_hidden)
            hidden_output = sigmoid(hidden_input)

            output = sigmoid(np.matmul(hidden_output, weights_hidden_output))
            # 6、反向传播
            error = output - y
            output_error_term = error * output * (1 - output)   # 标量

            hidden_error = output_error_term * weights_hidden_output  # (n_hidden, ) 向量
            hidden_error_term = hidden_error * hidden_output * (1-hidden_output)  # (n_hidden, ) 向量

            del_w_input_hidden += x[:, None] * hidden_error_term
            del_w_hidden_output += hidden_output * output_error_term
        # 7、执行梯度下降,更新权重
        weights_hidden_output -= del_w_hidden_output * learning_rate/n_reords
        weights_input_hidden -= del_w_input_hidden * learning_rate/n_reords

        # 8、每20个迭代,打印1次模型损失
        if e % 20 == 0:
            hidden_output = sigmoid(np.dot(features_train, weights_input_hidden))
            out = sigmoid(np.dot(hidden_output, weights_hidden_output))  # out就是预测值
            loss = np.mean((out - targets_train)**2)

            if last_loss and last_loss < loss:
                print('警告,模型损失在上升')
            else:
                print('Epoch:{} — Train  Loss:{}'.format(e, loss))
            last_loss = loss
    # 9、计算测试集准确率
    hidden = sigmoid(np.matmul(features_test.values, weights_input_hidden))
    out = sigmoid(np.matmul(hidden, weights_hidden_output))  # 测试数据集的预测值
    predictions = out > 0.5
    accuracy = np.mean(predictions == targets_test)
    print("Test ACC:{}".format(accuracy))


if __name__ == '__main__':
    features_train, targets_train, features_test, targets_test = data_transform(admissions)
    # data_explore(admissions)
    gre_bp_answer(features_train, targets_train, features_test, targets_test)
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。