MLP多层感知机用BP算法更新权值解决异或问题(机器学习实验二)

本文实现只有一层隐藏层。贴上221网络解决两元素异或以及331网络解决三元素异或问题。
原理不懂可以参考以下博客,建议手推一遍bp怎样链式反向求导。

  1. 多层感知机(MultiLayer Perceptron)以及反向传播算法(Backpropagation)
  2. 机器学习——神经网络(四):BP神经网络
  3. 如果还不清楚这里有视频:PyTorch深度学习实践强烈推荐!!讲的太清了,还讲了pytorch的代码。)

BP算法的核心就是从后向前更新权重。网络上大部分代码实现两元素异或都是2-4-1的网络,因为没有加偏置项所以隐含层不得不设置4个节点才能分离。但实验要求是用221网络分离两元素异或,以及331网络分离三元素异或,所以我们再需要求出loss(损失)对bias(偏置项)的导数。
不细细推了,先看隐藏层到输出层权值更新
Δ w j i = − η ∂ E d ∂ w j i = η ( t j − o j ) o j ( 1 − o j ) x j i \Delta w_{j i}=-\eta \frac{\partial E_{d}}{\partial w_{j i}}=\eta\left(t_{j}-o_{j}\right) o_{j}\left(1-o_{j}\right) x_{j i} Δwji=ηwjiEd=η(tjoj)oj(1oj)xji
t j − o j t_{j}-o_{j} tjoj实际就是本应该输出的标签减去得到的结果。
o j ( 1 − o j ) o_{j}(1-o_{j}) oj(1oj)就是输出对 s i g m o i d sigmoid sigmoid函数的导数 x ( 1 − x ) x(1-x) x(1x)
x j i x_{ji} xji就是未经过 s i g m o i d sigmoid sigmoid函数的输出对 w w w的导数。
如果是隐藏层到输出层的偏置的导数,那么很简单,不要 x j i x_{ji} xji这一项就行,因为 b i a s bias bias的系数就是1。
∂ y i o ( k ) ∂ b o = ∂ ( ∑ h p w h o h o h ( k ) − b o ) ∂ b o = 1 \frac{\partial y i_{o}(k)}{\partial b_{o}}=\frac{\partial\left(\sum_{h}^{p} w_{h o} h o_{h}(k)-b_{o}\right)}{\partial b_{o}}=1 boyio(k)=bo(hpwhohoh(k)bo)=1
所以隐藏层到输出层的偏置 b 0 b_{0} b0应该这么更新
Δ b 0 = − η ∂ E d ∂ b 0 = η ( t j − o j ) o j ( 1 − o j ) \Delta b_{0}=-\eta \frac{\partial E_{d}}{\partial b_{0}}=\eta\left(t_{j}-o_{j}\right) o_{j}\left(1-o_{j}\right) Δb0=ηb0Ed=η(tjoj)oj(1oj)
输入到隐藏层公式就不细讲了,主要latax敲公式不太熟。但偏置同理导数为1。

网上的代码都是隐藏层4个 s i g m o i d sigmoid sigmoid函数节点来分,而不是像下图一样加上偏置只需要2个 s i g m o i d sigmoid sigmoid节点
demo
但是上述图片的隐层函数是阶跃函数。而我的代码隐层非线性函数为 s i g m o i d sigmoid sigmoid。所以最终的权值会不一样。
对2个元素异或的bp源代码:

import numpy as np
import matplotlib.pyplot as plt

rate=0.1 #学习率
sample_num=4 #样本数据量

class my_mlp:
    def __init__(self, input_size, hidden_size, output_size):
        self.w1 = np.random.normal(size=(hidden_size, input_size))#输入层到隐藏层
        self.w2 = np.random.normal(size=(hidden_size,output_size))#隐藏层到输出层
        self.b1 = np.random.normal(size=(hidden_size))
        self.b2 = np.random.normal(size=(output_size))
        self.h_out = np.zeros(1)
        self.out = np.zeros(1)

    @staticmethod
    def sigmoid(x):
        '''sigmoid函数作为激活函数'''
        return 1 / (1 + np.exp(-x))
    @staticmethod
    def d_sigmoid(x):
        '''相对误差对输出和隐含层求导'''
        return x * (1 - x)
    def forward(self,input):
        self.h_out = my_mlp.sigmoid(np.dot(input, self.w1)+self.b1)
        self.out = my_mlp.sigmoid(np.dot(self.h_out, self.w2)+self.b2)

    def backpropagation(self,input,output,lr=rate):
        self.forward(input)
        L2_delta=(output-self.out) * my_mlp.d_sigmoid(self.out)
        L1_delta = L2_delta.dot(self.w2.T) * my_mlp.d_sigmoid(self.h_out)
        d_w2 = rate * self.h_out.T.dot(L2_delta)
        d_w1 = rate * input.T.dot(L1_delta)
        self.w2 += d_w2
        self.w1 += d_w1
        d_b2 = np.ones((1,sample_num)).dot(L2_delta)
        d_b1 = np.ones((1,sample_num)).dot(L1_delta)
        self.b2 += rate*d_b2.reshape(d_b2.shape[0]*d_b2.shape[1],)
        self.b1 += rate*d_b1.reshape(d_b1.shape[0]*d_b1.shape[1],)



if __name__ == '__main__':
    mlp=my_mlp(2,2,1)
    # x_data x1,x2
    x_data = np.array([[0, 0],
                       [0, 1],
                       [1, 0],
                       [1, 1]])
    # y_data label
    y_data = np.array([[0],
                       [1],
                       [1],
                       [0]])

    for i in range(15000):
        mlp.backpropagation(x_data,y_data)
        out=mlp.out  # 更新权值
        if i % 500 == 0:
            plt.scatter(i, np.mean(np.abs(y_data - out)))
            #print('当前误差:',np.mean(np.abs(y_data - out)))
    plt.title('Error Curve')
    plt.xlabel('iteration')
    plt.ylabel('Error')
    plt.show()
    print('输入层到隐含层权值:\n',mlp.w1)
    print('输入层到隐含层偏置:\n',mlp.b1)
    print('隐含层到输出层权值:\n',mlp.w2)
    print('隐含层到输出层偏置:\n',mlp.b2)

    print('输出结果:\n',out)
    print('忽略误差近似输出:')
    for i in out:
        print(0 if i<=0.5 else 1)

结果:
re1

re2

此外:为了实现可扩展性专门设立一个类定义输入节点数,隐藏节点数和输出节点数,这样只要一层隐含层能实现的功能上述都可以实现。比如我们想实现三元素异或

x 1 x_{1} x1 x 1 x_{1} x1 x 1 x_{1} x1 y y y
0000
0011
0101
0110
1001
1010
1100
1111

只需要调整一些参数即可:

import numpy as np
import matplotlib.pyplot as plt

rate=0.1 #学习率
sample_num=8 #样本数据量

class my_mlp:
    def __init__(self, input_size, hidden_size, output_size):
        self.w1 = np.random.normal(size=(hidden_size, input_size))#输入层到隐藏层
        self.w2 = np.random.normal(size=(hidden_size,output_size))#隐藏层到输出层
        self.b1 = np.random.normal(size=(hidden_size))
        self.b2 = np.random.normal(size=(output_size))
        self.h_out = np.zeros(1)
        self.out = np.zeros(1)

    @staticmethod
    def sigmoid(x):
        '''sigmoid函数作为激活函数'''
        return 1 / (1 + np.exp(-x))
    @staticmethod
    def d_sigmoid(x):
        '''相对误差对输出和隐含层求导'''
        return x * (1 - x)
    def forward(self,input):
        self.h_out = my_mlp.sigmoid(np.dot(input, self.w1)+self.b1)
        self.out = my_mlp.sigmoid(np.dot(self.h_out, self.w2)+self.b2)

    def backpropagation(self,input,output,lr=rate):
        self.forward(input)
        L2_delta=(output-self.out) * my_mlp.d_sigmoid(self.out)
        L1_delta = L2_delta.dot(self.w2.T) * my_mlp.d_sigmoid(self.h_out)
        d_w2 = rate * self.h_out.T.dot(L2_delta)
        d_w1 = rate * input.T.dot(L1_delta)
        self.w2 += d_w2
        self.w1 += d_w1
        d_b2 = np.ones((1,sample_num)).dot(L2_delta)
        d_b1 = np.ones((1,sample_num)).dot(L1_delta)
        self.b2 += rate*d_b2.reshape(d_b2.shape[0]*d_b2.shape[1],)
        self.b1 += rate*d_b1.reshape(d_b1.shape[0]*d_b1.shape[1],)



if __name__ == '__main__':
    mlp=my_mlp(3,3,1)
    # x_data x1,x2
    x_data = np.array([[0, 0, 0],
                       [0, 0, 1],
                       [0, 1, 0],
                       [0, 1, 1],
                       [1, 0, 0],
                       [1, 0, 1],
                       [1, 1, 0],
                       [1, 1, 1]])
    # y_data label
    y_data = np.array([[0],[1],[1],[0],[1],[0],[0],[1]])

    for i in range(15000):
        mlp.backpropagation(x_data,y_data)
        out=mlp.out  # 更新权值
        if i % 500 == 0:
            plt.scatter(i, np.mean(np.abs(y_data - out)))
            #print('当前误差:',np.mean(np.abs(y_data - out)))
    plt.title('Error Curve')
    plt.xlabel('iteration')
    plt.ylabel('Error')
    plt.show()
    print('输入层到隐含层权值:\n',mlp.w1)
    print('输入层到隐含层偏置:\n',mlp.b1)
    print('隐含层到输出层权值:\n',mlp.w2)
    print('隐含层到输出层偏置:\n',mlp.b2)

    print('输出结果:\n',out)
    print('忽略误差近似输出:')
    for i in out:
        print(0 if i<=0.5 else 1)

  • 12
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
mlp多层感知机深度学习密切相关。深度学习是一种机器学习的方法,它基于神经网络的多层结构进行建模和训练。多层感知机(MLP)是最简单的神经网络结构之一,也是深度学习中常用的模型之一。 MLP由多个计算层组成,包括输入层、若干个隐层和输出层。每个隐层都由多个隐单元组成,而隐单元的个数是根据数据集的复杂度来确定的。对于简单的数据集,可以选择较少的隐单元,而对于复杂的数据集,可以选择更多的隐单元,甚至可以添加多个隐层。 例如,当我们使用MLP进行分类任务时,可以使用两个隐层,每个隐层都包含10个隐单元。这样的设置可以通过修改MLPClassifier类的hidden_layer_sizes属性来实现。具体的代码如下所示: ``` mlp = MLPClassifier(solver='lbfgs', random_state=0, hidden_layer_sizes=[10, 10]) ``` 这个设置意味着我们有两个隐层,每个隐层都有10个隐单元。 因此,通过使用MLP多层感知机,我们可以实现深度学习中的模型构建和训练,以解决各种机器学习问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [深度学习简介与MLP多层感知机](https://blog.csdn.net/qq_43355223/article/details/86593078)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值