多层感知机解决异或问题简单实现

问题概述

公式推导

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()

猜你喜欢

转载自blog.csdn.net/CesareBorgia/article/details/120546171