机器学习-神经网络

一,介绍

神经网络有多种,包括:反向传播神经网络(BP神经网络)、径向基函数神经网络(RBF神经网络)、竞争型学习神经网络(ART神经网络)等。

神经网络可以分为三个部分:输入层、隐藏层、输出层。其中隐藏层根据需要可以有多层。

在这里,我们主要介绍BP神经网络,一种最常用的神经网络。其思想是根据输入层数据加上权值进行计算获得输出层结果,再根据输出层结果和实际结果比较,调整权值,直到权值调整到输出结果符合预期后结束训练。

权重调整公式如下:

其中,η为学习速率,Wi为权重,y为实际输出值,为当前权重计算值,Xi为输入值。下面给出一个具体例子,迭代计算权值。

二,实例

假设,有如下神经网络:

i1,i2为输入层,h1,h2为隐藏层,o1,o2为输出层,b1,b2为阈值。激活函数用sigmoid函数。

step1,计算输入层--隐藏层

(1)计算加权输入

net(h1)=w1*i1+w2*i2+b1=0.15*0.05+0.2*0.1+0.35*1=0.3775

(2)用激活函数计算输出

同理,计算out(h2)=0.59688

step2,计算隐藏层--输出层

(1)计算加权输入

net(o1)=w5*out(h1)+w6*out(h2)+b2=0.4*0.59326+0.45*0.59688 +0.6*1=1.1059

(2)用激活函数计算输出

同理,计算out(o2)=0.77292

step3,计算反向传播误差。

step4,更新隐藏层到输出层权值

这里设定学习速率η=0.5

我们更新权值W5为例:

得到更新后的W5=0.35891。其他的权值,更新类似。

step5,更新输入层到隐藏层权值

同理:

获得:

其他权值更新类似

三,python实现神经网络

确定隐藏层节点数,经验公式如下:

数据如下:

1,青绿,蜷缩,浊响,清晰,凹陷,硬滑,是
2,乌黑,蜷缩,沉闷,清晰,凹陷,硬滑,是
3,乌黑,蜷缩,浊响,清晰,凹陷,硬滑,是
4,青绿,蜷缩,沉闷,清晰,凹陷,硬滑,是
5,浅白,蜷缩,浊响,清晰,凹陷,硬滑,是
6,青绿,稍蜷,浊响,清晰,稍凹,软粘,是
7,乌黑,稍蜷,浊响,稍糊,稍凹,软粘,是
8,乌黑,稍蜷,浊响,清晰,稍凹,硬滑,是
9,乌黑,稍蜷,沉闷,稍糊,稍凹,硬滑,否
10,青绿,硬挺,清脆,清晰,平坦,软粘,否
11,浅白,硬挺,清脆,模糊,平坦,硬滑,否
12,浅白,蜷缩,浊响,模糊,平坦,软粘,否
13,青绿,稍蜷,浊响,稍糊,凹陷,硬滑,否
14,浅白,稍蜷,沉闷,稍糊,凹陷,硬滑,否
15,乌黑,稍蜷,浊响,清晰,稍凹,软粘,否
16,浅白,蜷缩,浊响,模糊,平坦,硬滑,否
17,青绿,蜷缩,沉闷,稍糊,稍凹,硬滑,否为了方便神经网络计算,我们采用独热编码的方式进行编码数据预处理,处理输入如下:

我们尝试采用两种不同的激活函数,sigmoid函数和tanh函数

python代码:

from math import log
import numpy as np
from random import random
import pandas as pd


# sigmoid函数
def logistic(x):
    return 1 / (1 + np.exp(-x))

# sigmoid函数导数
def logistic_derivative(x):
    return x * (1 - x)

# tanh函数
def tanh(x):
    return np.tanh(x)

# tanh函数导数
def tanh_deriv(x):
    return 1.0 - np.tanh(x) * np.tanh(x)

class BPNeuralNetwork:
    def __init__(self, activation='tanh'):
        self.input_num = 0    # 输入层节点数
        self.hide_num = 0     # 隐藏层节点数
        self.output_num = 0   # 输出层节点数

        self.input_value = []   # 输入层输出
        self.hide_value = []    # 隐藏层输出
        self.output_value = []  # 输出层输出

        self.inputToHide_w = []  # 输入层到隐藏层权值
        self.hideToOutput_w = [] # 隐藏层到输出层权值
        self.hide_b = []         # 隐藏层阀值
        self.output_b = []       # 输出层阀值

        if activation == 'logistic':
            self.activation = logistic
            self.activation_deriv = logistic_derivative
        elif activation == 'tanh':
            self.activation = tanh
            self.activation_deriv = tanh_deriv

    # 读取数据
    def createDataSet(self):
        dataSet=[]
        fr = open('watermelon.txt')
        for line in fr.readlines():
            lineArr = line.strip().split(',')
            dataSet.append(lineArr[:])  # 添加数据
        labels = ['编号','色泽','根蒂','敲声','纹理','头部','触感','好瓜']
        return dataSet, labels

    # 创建随机数
    def rand(self,a, b):
        return (b - a) * random() + a

    # 创建BP神经网络
    def createBPNN(self, ni, nh, no):
        self.input_num = ni  # 输入层节点数
        self.hide_num = nh  # 隐藏层节点数
        self.output_num = no  # 输出层节点数

        self.input_value = np.zeros(self.input_num)    # 输入层输出
        self.hide_value = np.zeros(self.hide_num)      # 隐藏层输出
        self.output_value = np.zeros(self.output_num)  # 输出层输出

        self.inputToHide_w = np.zeros([self.input_num, self.hide_num])     # 输入到隐藏层权值矩阵
        self.hideToOutput_w = np.zeros([self.hide_num, self.output_num])   # 隐藏到输出层权值矩阵
        for i in range(self.input_num):
            for h in range(self.hide_num):
                self.inputToHide_w[i][h] = self.rand(0, 1)                   # 随机赋值
        for h in range(self.hide_num):
            for j in range(self.output_num):
                self.hideToOutput_w[h][j] = self.rand(0, 1)                  # 随机赋值

        self.hide_b = np.zeros(self.hide_num)  # 创建隐藏层阀值矩阵
        self.output_b = np.zeros(self.output_num)  # 创建输出层阀值矩阵
        for h in range(self.hide_num): self.hide_b[h] = self.rand(0, 1)  # 初始化隐藏层阀值矩阵
        for j in range(self.output_num): self.output_b[j] = self.rand(0, 1)  # 初始化输出层阀值矩阵

    # 计算隐藏层和输出层的输出值
    def Pred(self, x):
        for i in range(self.input_num):
            self.input_value[i] = x[i]         # 输入层赋值

        for h in range(self.hide_num):
            total = 0.0
            for i in range(self.input_num):
                total += self.input_value[i] * self.inputToHide_w[i][h]    # 计算net(h)
            self.hide_value[h] = self.activation(total - self.hide_b[h])          # 计算out(h)

        for j in range(self.output_num):
            total = 0.0
            for h in range(self.hide_num):
                total += self.hide_value[h] * self.hideToOutput_w[h][j]   # 计算net(o)
            self.output_value[j] = self.activation(total - self.output_b[j])     # 计算out(o)

    # 反向传播更新权值
    def BackPropagate(self, data_in, data_out, lr, epochs=10000):
        for k in range(epochs):
            i = np.random.randint(len(data_in))
            x = data_in[i]
            y = data_out[i]
            self.Pred(x)

            output_grid = np.zeros(self.output_num)
            for j in range(self.output_num):
                output_grid[j] = (y[j] - self.output_value[j]) * self.activation_deriv(self.output_value[j])
                # output_grid[j] = (y[j] - self.output_value[j]) * self.output_value[j] * (1 - self.output_value[j])    # 计算 (эE/эout(o))*(эout(o)/эnet(o))

            hide_grid = np.zeros(self.hide_num)
            for h in range(self.hide_num):
                for j in range(self.output_num):
                    hide_grid[h] += self.hideToOutput_w[h][j] * output_grid[j]
                    hide_grid[h] = hide_grid[h] * self.activation_deriv(self.hide_value[h])
                    # hide_grid[h] = hide_grid[h] * self.hide_value[h] * (1 - self.hide_value[h])              # 计算输入层到隐藏层ΔW=-η*ΔE=-η*(out(h)-h)*out(h)*(1-out(h))*out(i)

            for h in range(self.hide_num):
                for j in range(self.output_num):
                    self.hideToOutput_w[h][j] += lr * output_grid[j] * self.hide_value[h]    # 更新隐藏层到输出层的权值 w+η*(эE/эout(o))*(эout(o)/эnet(o))*w

            for i in range(self.input_num):
                for h in range(self.hide_num):
                    self.inputToHide_w[i][h] += lr * hide_grid[h] * self.input_value[i]                # 更新输入层到隐藏层权值 w+η*(

            for j in range(self.output_num):
                self.output_b[j] -= lr * output_grid[j]              # 更新输出层阀值

            for h in range(self.hide_num):
                self.hide_b[h] -= lr * hide_grid[h]                  # 更新隐藏层阀值

    # 训练神经网络
    def TrainStandard(self, data_in, data_out, lr=0.5):
        e_k = np.zeros([len(data_in),self.output_num])
        self.BackPropagate(data_in, data_out, lr)
        error = np.zeros(self.output_num)
        for k in range(len(data_in)):
            self.Pred(data_in[k])
            y=data_out[k]
            for j in range(self.output_num):
                error[j]=(self.output_value[j] - y[j])
            e_k[k] = error
        # 训练总误差
        return  e_k

if __name__ == '__main__':
    Bpnn = BPNeuralNetwork('logistic')                        # 选择激活函数logistic或tanh
    myData,label = Bpnn.createDataSet()                       # 读取数据

    df = pd.DataFrame(x[1:8] for x in myData)
    df.columns = label[1:8]

    dataProcessing = pd.get_dummies(df)

    dataIn = dataProcessing.iloc[:,0:17].values.tolist()                        # 输入
    dataOut = dataProcessing.iloc[:,17:19].values.tolist()                        # 输出
    Bpnn.createBPNN(17,6,2)

    e_k = Bpnn.TrainStandard(dataIn,dataOut)
    print(e_k)
当使用学习速率为0.5,logistic作为激活函数,训练1W次的时候,获得以下结果:

当使用学习速率为0.5,tanh作为激活函数,训练1W次的时候,获得以下结果:

猜你喜欢

转载自blog.csdn.net/lyn5284767/article/details/81067738