17_神经网络–梯度下降的代码实现

经过上一节的讲解我们已经知道了我们的权重是如何更新的,本节将讲解如何将这个过程通过代码实现。基于python和numpy。

其中:

为了讲解这个过程,我们引入某大学的历史录取数据,用于训练

数据链接github链接:
这个数据集有三个输入数据:
1. GRE分数
2. GPA
3. 本科院校排名(rank),从1到4
排名为1的院校有最高的推荐值,排名四的最低。

image

image

CSV:数据样例

我们的目标是通过给定的三个输入,预测该学生是否被录取。在本例中我们将使用sigmoid函数作为激活函数。

数据清洗

可能我们第一感觉就是这个网络应该就具有三个输入,但事实上我们需要首先对这个数据进行一些转换。排名数据只是一个分类,它的数据并不代表任何一种相对数据。例如排名为2的并不是排名为1的两倍,排名为3的并不是排名为2的1.5倍。我们需要使用“哑变量”对排名数据进行重新编码。将数据新增4列,每一列的值只有0或者1.排名为1的数据在rank1列的值为1,其余列的值为0,以此类推。

我们同样需要使GPA、GRE分数标准化,将数据转换为具有0均值和标准差为1的数据。这是因为Sigmoid函数实际上是会破坏非常小和非常大的输入。超大值和超小值的梯度为0,会导致梯度下降也会变为0.从样例数据中可以看出,GRE和GPA的值非常大。对权重值的初始化就变得非常重要,稍不小心就可能使梯度下降步骤停止,神经网络也不会继续训练。但如果我们将这个数据重新进行标准化,我们就可以针对性的对权重进行初始化,训练过程就变得简单了。

apply函数

apply函数是pandas里面所有函数中自由度最高的函数。该函数如下:

DataFrame.apply(func, axis=0, broadcast=False, raw=False, reduce=None, args=(), **kwds)

该函数最有用的是第一个参数,这个参数是函数,相当于C/C++的函数指针。

这个函数需要自己实现,函数的传入参数根据axis来定,比如axis = 1,就会把一行数据作为Series的数据
结构传入给自己实现的函数中,我们在函数中实现对Series不同属性之间的计算,返回一个结果,则apply函数
会自动遍历每一行DataFrame的数据,最后将所有结果组合成一个Series数据结构并返回。

数据标准化

image

正态分布跟标准分数之间的关系

标准分数(Standard Score,又称z-score、z分数或标准化值),是将集合中的单个数与集合的均值相减的结果除以集合的标准差得到标准化的结果,该方法类似于正态分布的标准化转换,转换函数为:

image

式中x为需要被标准化的原始值,μ为均值,σ为标准差,σ≠0。
z分数标准化处理后的值代表原始值与集合均值之间的距离,以标准差为单位计算。该值存在正负值,低于均值则为负数,反之则正数,其范围为[-∞,+∞],数据均值为0,方差为1。

数据预处理代码

import numpy as np
import pandas as pd

data=pd.read_csv("binary.csv")
data['rank'].astype(int)

def rank1_std(x):
    if x['rank'] == 1:
        return 1
    else:
        return 0
def rank2_std(x):
    if x['rank'] == 2:
        return 1
    else:
        return 0
def rank3_std(x):
    if x['rank'] == 3:
        return 1
    else:
        return 0
def rank4_std(x):
    if x['rank'] == 4:
        return 1
    else:
        return 0

def admit_std(x):
    if x['admit']:
        return True
    else:
        return False

data['rank_1']=data.apply(rank1_std,axis=1)
data['rank_2']=data.apply(rank2_std,axis=1)
data['rank_3']=data.apply(rank3_std,axis=1)
data['rank_4']=data.apply(rank4_std,axis=1)
data['admit']=data.apply(admit_std,axis=1)

gre_mean=data['gre'].mean()
gre_max=data['gre'].max()
gre_min=data['gre'].min()
gre_std=data['gre'].std()

gpa_mean=data['gpa'].mean()
gpa_max=data['gpa'].max()
gpa_min=data['gpa'].min()
gpa_std=data['gpa'].std()

data['gre']=data['gre'].map(lambda x: (x-gre_mean)/gre_std)
data['gpa']=data['gpa'].map(lambda x: (x-gpa_mean)/gpa_std)
del data['rank']
data.head(20)

#完成数据处理

数据处理结果

image

训练神经网络

features=data[['gre','gpa','rank_1','rank_2','rank_3','rank_4']][:380]
targets=data['admit'][:380]
features_test=data[['gre','gpa','rank_1','rank_2','rank_3','rank_4']][380:]
targets_test=data['admit'][380:]
# features.head(10)

def sigmoid(x):
    """
    Calculate sigmoid
    """
    return 1 / (1 + np.exp(-x))
# Use to same seed to make debugging easier
np.random.seed(42)
n_records, n_features = features.shape
last_loss = None

# Initialize weights
weights = np.random.normal(scale=1/n_features**.5, size=n_features)

# Neural Network parameters
epochs = 2000
learnrate = 0.8

for e in range(epochs):
    del_w = np.zeros(weights.shape)
    for x, y in zip(features.values, targets.values):
        # Loop through all records, x is the input, y is the target

        # Activation of the output unit
        output = sigmoid(np.dot(x, weights))

        # The error, the target minues the network output
        error = y - output

        # The gradient descent step, the error times the gradient times the inputs
        del_w += error * output * (1 - output) * x

        # Update the weights here. The learning rate times the 
        # change in weights, divided by the number of records to average
    weights += learnrate * del_w / n_records

    # Printing out the mean square error on the training set
    if e % (epochs / 10) == 0:
        out = sigmoid(np.dot(features, weights))
        loss = np.mean((out - targets) ** 2)
        if last_loss and last_loss < loss:
            print("Train loss: ", loss, "  WARNING - Loss Increasing")
        else:
            print("Train loss: ", loss)
        last_loss = loss
# Calculate accuracy on test data
tes_out = sigmoid(np.dot(features_test, weights))
predictions = tes_out >= 0.5

print(predictions)
print(targets_test.values)
accuracy = np.mean(predictions == targets_test)
print("Prediction accuracy: {:.3f}".format(accuracy))

神经网络训练输出:

image

以上代码包含了我们前两节课对梯度下降解析的全部关键内容,包括误差计算,△w计算,权重更新,全局误差计算等内容,请按照代码注释进行解读。
本次实现的预测正确率还很低,需要进一步调试。

0 回复

发表评论

Want to join the discussion?
Feel free to contribute!

发表评论

邮箱地址不会被公开。 必填项已用*标注