python解决异或问题

2022年8月26日 471点热度 0人点赞 0条评论

非线性关系解决异或问题

本文讲解了使用非线性神经网络解决异或问题,谈及了参数初始化的方式,分类问题中使用crossEntropy而不用MSE的原因。


一、正常解决异或关系方法

import numpy as np

import matplotlib.pyplot as plt

x_data = np.array([[1,0,0],

               [1,0,1],

               [1,1,0],

               [1,1,1]])

y_data = np.array([[0],

               [1],

               [1],

               [0]])

# 初始化权值,取值范围为-1~1

v = (np.random.random([3,4])-0.5)*2

w = (np.random.random([4,1])-0.5)*2

lr = 0.11

def sigmoid(x):

    return 1/(1+np.exp(-x))

def d_sigmoid(x):

    return x*(1-x)

def update():

    global x_data,y_data,w,v,lr,L1,L2,L2_new

    L1 = sigmoid(np.dot(x_data,v)) #隐含层的输出4*4矩阵

    L2 = sigmoid(np.dot(L1,w))     #输出层的实际输出4*1

    # 计算输出层和隐含层的误差,然后求取更新量

    #

    L2_delta = (L2-y_data)  # y_data 4*1 矩阵

    L1_delta = L2_delta.dot(w.T)*d_sigmoid(L1)

    # 更新输入层到隐含层的权值和隐含层到输出层的权值

    w_c = lr*L1.T.dot(L2_delta)

    v_c = lr*x_data.T.dot(L1_delta)

    w = w-w_c

    v = v-v_c

L2_new = softmax(L2)

def cross_entropy_error(y, t):

    return -np.sum(t * np.log(y)+(1-t)*np.log(1-y))

def softmax(x):

    exp_x = np.exp(x)

    sum_exp_x = np.sum(exp_x)

    y = exp_x/sum_exp_x

    return y



if __name__=='__main__':

    for i in range(1000):

        update() #更新权值\

        if i%10==0:

            plt.scatter(i,np.mean(cross_entropy_error(L2_new,y_data)))

    plt.title('error curve')

    plt.xlabel('iteration')

    plt.ylabel('error')

    plt.show()

    print(L2)

    print(cross_entropy_error(L2_new,y_data))

图片

先来讲讲输入的数据x:第一列是偏置项恒置为1,后两列分别为x1,x2。而y是x1,x2对应的输出,即异或关系结果的标签。lr是设置的学习率。通过交叉熵计算损失。最终得出图下方的预测结果,不难看出预测结果还是十分接近标签的


二、使用线性关系解决异或问题

import numpy as np

import matplotlib.pyplot as plt


x_data = np.array([[1,0,0],

               [1,0,1],

               [1,1,0],

               [1,1,1]])

y_data = np.array([[0],

               [1],

               [1],

               [0]])

# 初始化权值,取值范围为-1~1

v = (np.random.random([3,4])-0.5)*2

w = (np.random.random([4,1])-0.5)*2

lr = 0.11

def update():

    global x_data,y_data,w,v,lr,L1,L2,L2_new

    L1 = np.dot(x_data,v) #隐含层的输出4*4矩阵

    L2 = np.dot(L1,w)   #输出层的实际输出4*1

    # 计算输出层和隐含层的误差,然后求取更新量

    #

    L2_delta = (L2-y_data)  # y_data 4*1 矩阵

    L1_delta = L2_delta.dot(w.T)

    # 更新输入层到隐含层的权值和隐含层到输出层的权值

    w_c = lr*L1.T.dot(L2_delta)

    v_c = lr*x_data.T.dot(L1_delta)

    w = w-w_c

    v = v-v_c

    L2_new = softmax(L2)

def cross_entropy_error(y, t):

    return -np.sum(t * np.log(y)+(1-t)*np.log(1-y))

def softmax(x):

    exp_x = np.exp(x)

    sum_exp_x = np.sum(exp_x)

    y = exp_x/sum_exp_x

    return y

if __name__=='__main__':

    for i in range(300):

        update() #更新权值

        if i%10==0:

            plt.scatter(i,np.mean(cross_entropy_error(L2_new,y_data)))

    plt.title('error curve')

    plt.xlabel('iteration')

    plt.ylabel('error')

    plt.show()

    print(L2)

print("最终误差大小为:",cross_entropy_error(L2_new,y_data))

图片
不难看出异或问题是不能够使用线性关系解决的

三、使用MSE作为损失函数解决异或问题

import numpy as np

import matplotlib.pyplot as plt

x_data = np.array([[1,0,0],

               [1,0,1],

               [1,1,0],

               [1,1,1]])

y_data = np.array([[0],

               [1],

               [1],

               [0]])

# 初始化权值,取值范围为-1~1

v = (np.random.random([3,4])-0.5)*2

w = (np.random.random([4,1])-0.5)*2

lr = 0.11

def sigmoid(x):

    return 1/(1+np.exp(-x))

def d_sigmoid(x):

    return x*(1-x)

def update():

    global x_data,y_data,w,v,lr,L1,L2,L2_new

    L1 = sigmoid(np.dot(x_data,v)) #隐含层的输出4*4矩阵

    L2 = sigmoid(np.dot(L1,w))     #输出层的实际输出4*1

    #

    L2_delta = (L2-y_data)*d_sigmoid(L2)  # y_data 4*1 矩阵

    L1_delta = L2_delta.dot(w.T)*d_sigmoid(L1)

    # 更新输入层到隐含层的权值和隐含层到输出层的权值

    w_c = lr*L1.T.dot(L2_delta)

    v_c = lr*x_data.T.dot(L1_delta)

    w = w-w_c

    v = v-v_c

    L2_new = softmax(L2)

def softmax(x):

    exp_x = np.exp(x)

    sum_exp_x = np.sum(exp_x)

    y = exp_x/sum_exp_x

    return y

if __name__=='__main__':

    for i in range(1000):

        update() #更新权值\

        if i%10==0:

            plt.scatter(i,np.mean((y_data-L2)**2)/2)

    plt.title('error curve')

    plt.xlabel('iteration')

    plt.ylabel('error')

    plt.show()

    print(L2)

print(np.mean(((y_data-L2)**2)/2))

图片

不难看出使用MSE也不能够解决异或问题,那么是什么原因呢?

从理论上将讲平方损失函数也可以用于分类问题,但不适合。首先,最小化平方损失函数本质上等同于在误差服从高斯分布的假设下的极大似然估计,然而大部分分类问题的误差并不服从高斯分布。而且在实际应用中,交叉熵在和Softmax激活函数的配合下,能够使得损失值越大导数越大,损失值越小导数越小,这就能加快学习速率。然而若使用平方损失函数,则损失越大导数反而越小,学习速率很慢。看下面这张图可以看出其中的问题。

图片

再看上面的第一张结果图和第三章结果图:

图片图片

若是使用MSE作为损失计算时,若出现梯度非常小的时候,是看不出来是离目标近还是离目标远。
使用cross entropy作为损失函数,在一开始的时候,误差下降会很明显,原因是cross entropy一开始误差对参数w的偏导数很大,参数也会更新的大,那么误差下降得更快。
而MSE损失可以看到误差变化地非常平缓,这也很好地印证了上面的三维空间的图,误差变换十分缓慢。
四、初始化权重问题
1.np的random函数
       np.random.randn(d0,d1,...,dn):无参数时返回一个浮点数,有一个参数时返回一个秩为1的数组,参数有两个或以上时生成对应维度的数组。其中的随机数服从标准正态分布,均值为0,标准差为1。
       np.random.rand(d0,d1,...,dn):参数作用与np.random.randn相同。其中随机数服从0~1均匀分布,随机样本值是[0,1),取不到1。
np.random.randint(low,high,size=None,dtype=’l’):low为最小值,high为最大值,size为数组维度的大小,dtype为数据类型,默认为np.int。返回随机整形数组,取值范围为[low,high),取不到high,当high没有填写时,默认生成随机数范围是[0,low)。
2.初始化权重
为了保证输入与输出的差异性,又能够让模型稳定而又快速收敛

图片


为了描述差异性,所以想到了方差。D(x)与Var(x)均表示方差。
运用到两个随机变量乘积的方差公式:

图片

对于前向传播,只有确保所有层的激活值方差近似相等,才能保证训练样本经过神经网络的信息才能保持平滑。
对于反向传播,每层梯度保持近似的方差,也才能够允许信息平滑地反向流动以更新权重。
假设权重,激活值,加权输出,网络原始输出和梯度相互独立。
假设激活值和权重都服从均值为0的均匀分布,那么上面两个随机变量之积的后两项为0。
前向传播中为了使加权输出z的方差近似等于激活值的方差,推荐使用tanh()激活函数,原因是其在原点处tanh(x)≈x。
接下来考虑第L层第j个单元的加权输出:

图片

为了使得样本空间与类别空间差距不大,就是尽可能使得他们之间方差相等即:  图片

那么需要图片

而在反向传播中,同理

需要图片

对于这两个数取调和平均数:图片

图片

(a,b)即为初始化权重的范围。

本例中隐层神经元为4,所以可以近似将权重初始化范围设置为(-1,1)。



81750python解决异或问题

这个人很懒,什么都没留下

文章评论