问题概述
公式推导
Numpy实现
# -*- coding: utf-8 -*-
# @Time : 2021/9/29 18:02
# @Author : Amonologue
# @software : pycharm
# @File : 2021-9-29.py
import numpy as np
import matplotlib.pyplot as plt
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def derivative_sigmoid(x):
return sigmoid(x) * (1 - sigmoid(x))
def MSE(y, y_hat):
return sum((y - y_hat) ** 2) / 2
def accuracy(y, y_hat):
cnt = 0
y_hat = [1 if i > 0.5 else 0 for i in y_hat]
for i in range(len(y)):
if y[i] == y_hat[i]:
cnt += 1
return cnt / len(y)
if __name__ == '__main__':
# 初始参数
w1 = np.random.normal(size=(2, 2))
w2 = np.random.normal(size=(2, 1))
b1 = np.ones((1, 2))
b2 = np.ones((1, 1))
# 训练数据
X = np.array([0, 0, 0, 1, 1, 0, 1, 1]).reshape(4, 2)
Y = np.array([0, 1, 1, 0]).reshape(4, 1)
# 超参数
num_epochs = 2000
lr = 1
# train
print('开始训练...')
loss_list = []
acc_list = []
for epoch in range(num_epochs):
# forward layer1
z1 = X @ w1 + b1
a1 = sigmoid(z1)
# forward layer2
z2 = a1 @ w2 + b2
a2 = sigmoid(z2)
# loss function
loss = MSE(Y, a2)
# accuracy
acc = accuracy(Y, a2)
# 将loss 和 acc 加入到绘图数据中
loss_list.append(loss), acc_list.append(acc)
# 每100轮输出一次训练结果
if epoch % 100 == 0:
print(f'epoch {
epoch}: loss = {
loss}; accuracy = {
accuracy(Y, a2)}')
# 计算输出层残差
delta = (Y - a2) * derivative_sigmoid(z2)
w2_grad = a1.T @ delta
b2_grad = np.sum(delta, axis=0)
# 更新残差
delta = delta @ w2.T * derivative_sigmoid(z1)
w1_grad = X.T @ delta
b1_grad = np.sum(delta, axis=0)
# 更新权重w和偏置b
w1 += lr * w1_grad
b1 += lr * b1_grad
w2 += lr * w2_grad
b2 += lr * b2_grad
print('训练结束...')
# predict
y = sigmoid(sigmoid(X @ w1 + b1) @ w2 + b2)
print('使用MLP解决异或问题:')
for i in range(len(X)):
print(f'输入 x_1 = {
X[i][0]} x2 = {
X[i][1]} 输出 y_1 = {
1 if y[i][0] > 0.5 else 0}')
line1, = plt.plot(list(range(num_epochs)), loss_list)
line2, = plt.plot(list(range(num_epochs)), acc_list)
plt.legend([line1, line2], ['loss', 'acc'], loc=2)
plt.show()