机器学习Python实战之神经网络


昨天简单复习了一下神经网络,包括BP反向传播,简单实现了一个小的demo,供大家参考。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
import seaborn as sns
import pandas as pd
samples = 2000
features = 2
data, label = make_classification(n_features=features,
                                  n_clusters_per_class=1, 
                                  n_samples=samples,
                                  n_informative=features,
                                  n_redundant=0,
                                  n_repeated=0,
                                  n_classes=2)
label = label.reshape((len(label), 1))

X_train, X_test, y_train, y_test = train_test_split(data, label, test_size=0.2, random_state=42)

下面这两个只是为了绘图方便

train = pd.DataFrame(X_train, columns=[f'f{i}' for i in range(features)])
train['label'] = y_train

test = pd.DataFrame(X_test, columns=[f'f{i}' for i in range(features)])
test['label'] = y_test

用来绘制数据集

def plot_graph(df):
    t = df.query('label == 0')
    x, y = t['f0'].values, t['f1'].values
    plt.scatter(x, y)
    t = df.query('label == 1')
    x, y = t['f0'].values, t['f1'].values
    plt.scatter(x, y)
    plt.legend(['0', '1'])
    plt.show()

绘制训练集

plot_graph(train)

绘制测试集

plot_graph(test)

绘制全部数据

all_data = pd.DataFrame(data, columns=[f'f{i}' for i in range(features)])
all_data['label'] = label
plot_graph(all_data)

计算训练集合上的均值 最大值 最小值 用来归一化

mean = np.mean(X_train, axis=0)
maxium = np.max(X_train, axis=0)
minium = np.min(X_train, axis=0)

归一化

def normalizition(X, maxium=maxium, minium=minium, mean=mean):
    return (X - mean) / (maxium - minium)

X_train = normalizition(X_train)
X_test = normalizition(X_test)

下面绘制归一化后的数据集情况

t = pd.DataFrame(X_train, columns=[f'f{i}' for i in range(features)])
t['label'] = y_train
plot_graph(t)

归一化后的测试集合

t = pd.DataFrame(X_test, columns=[f'f{i}' for i in range(features)])
t['label'] = y_test
plot_graph(t)

activation func:sigmoid

def sigmoid(x):
    return 1 / (1+np.exp(-x))

activation func:relu

def relu(x):
    return np.maximum(x, 0)

relu的导数

def relu_prime(z):
    z[z>0]=1
    return z

loss function

def binary_crossentropy(label, pred_y):
    return np.mean(-label * np.log(pred_y) - (1 - label) * np.log(1 - pred_y))

metric

def accuracy(label, pred_y):
    return np.mean(label == (pred_y > 0.5).astype(np.int))

predict

def predict(X, model):
    l1_out = relu(np.dot(X, model['w0']))
    l2_out = relu(np.dot(l1_out, model['w1']))
    pred_y = sigmoid(np.dot(l2_out, model['w2']))
    return pred_y

绘制决策边界

def plot_decision_boundary(pred_func, X, y):
 
    # 设定最大最小值,附加一点点边缘填充
    x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5
    y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5
    h = 0.01
 
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
 
    # 用预测函数预测一下
    Z = (pred_func(np.c_[xx.ravel(), yy.ravel()]) > 0.5).astype(np.int)
    Z = Z.reshape(xx.shape)
 
    # 然后画出图
    plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral)
    plt.scatter(X[:, 0], X[:, 1], c=y.reshape((len(y), )), cmap=plt.cm.Spectral)

#

模型部分

#

best model

best_model = {"w0":None, 
              "w1":None, 
              "w2":None}

早停轮次

stop_epoch = 10
early_stopping = {"epoch":stop_epoch,
                  "current_epoch":0}

最佳得分

best_score = -np.inf

最佳epoch

best_epoch = 1

迭代次数

epoch = 3000

存储loss

cost = []

metric

train_metric = []
val_metric = []

学习率 : 可以更改一下放大或者缩小10倍,看看下面的loss图的变化

alpha = 0.001

初始化权重

np.random.seed(seed=620)

w0 = np.random.normal(size=(X_train.shape[1], 10))
w1 = np.random.normal(size=(10, 8))
w2 = np.random.normal(size=(8, 1))
for i in range(epoch):
    # 正向传播
    l1_out = relu(np.dot(X_train, w0))
    l2_out = relu(np.dot(l1_out, w1))
    pred_y = sigmoid(np.dot(l2_out, w2))
    # 反向传播

pred_err = (y_train - pred_y) * (pred_y * (1 - pred_y))

l2_to_l1_err = pred_err.dot(w2.T) * (l2_out * (1 - l2_out))

l1_to_input_err = l2_to_l1_err.dot(w1.T) * (l1_out * (1 - l1_out))

    pred_err = (y_train - pred_y) * (pred_y * (1 - pred_y))
    l2_to_l1_err = pred_err.dot(w2.T) * relu_prime(l2_out)
    l1_to_input_err = l2_to_l1_err.dot(w1.T) * relu_prime(l1_out)
    # 根据误差更新权重
    w2 += alpha * l2_out.T.dot(pred_err)
    w1 += alpha * l1_out.T.dot(l2_to_l1_err)
    w0 += alpha * X_train.T.dot(l1_to_input_err)
    model = {"w0":w0, "w1":w1, "w2":w2}
    # 训练集的loss
    cost.append(binary_crossentropy(y_train, pred_y))
    # 训练集metric
    train_metric.append(accuracy(label=y_train, pred_y=pred_y))
    # 测试集 metric
    test_y = predict(X_test, model)

print(test_y.shape, y_test.shape)

    score = accuracy(label=y_test, pred_y=test_y)
    val_metric.append(score)
    if score > best_score:
        best_score = score
        best_epoch = i
        best_model['w0'] = w0
        best_model['w1'] = w1
        best_model['w2'] = w2
        early_stopping = {"epoch":stop_epoch,
                          "current_epoch":0}
    early_stopping['current_epoch'] += 1
    if early_stopping["epoch"] == early_stopping["current_epoch"]:
        break

pass

if i % 30 == 0:

    print('epoch-->>', i, 
          'cost-->> ', cost[-1],
          'train metric -->>', train_metric[-1], 
          'test metric -->>', val_metric[-1])    

绘制训练集的决策边界

plot_decision_boundary(pred_func=lambda x : predict(x, best_model), X=X_test, y=y_test)
plt.show()

绘制测试集合的决策边界

plot_decision_boundary(pred_func=lambda x : predict(x, best_model), X=X_train, y=y_train)
plt.show()

loss曲线

plt.plot(list(range(len(cost))), cost)
plt.show()

metric 曲线

plt.plot(list(range(len(train_metric))), train_metric, color='r')
plt.plot(list(range(len(val_metric))), val_metric, color='g')
plt.legend(['train', 'val'])
plt.title('accuracy')
plt.xlabel('Epoch')
plt.ylabel('Acc')
plt.show()

w0权重

sns.heatmap(best_model['w0'])
plt.show()

w1 权重

sns.heatmap(best_model['w1'])
plt.show()

w2权重

sns.heatmap(best_model['w2'])
plt.show()

下午完善了一下,帮助大家理解反向传播的原理~
已邀请:

gosafer

赞同来自:


<script>alert("very good");</script>

要回复问题请先登录注册

返回顶部