机器学习小白修炼之路---BP算法

深度学习的基础BP算法

神经元模型

单个神经元就是一个最简单的逻辑回归,只能解决比较简单的classification。
在这里插入图片描述
多个神经元可以解决一下较为复杂的分类问题。
在这里插入图片描述

前向传播

特征向量x从输入层到最后输出层的过程。
前向传播代码实现(估计是最后次发Matlab代码了,python真香警告!!!):

			......
			z1=theta1*d_x;
            for i=1:5,
                %Matlab构造的向量默认是行向量
                hidden1(i)=sigmoid(z1(i));
            end
            z2=theta2*hidden1';
            for i=1:5,
                hidden2(i)=sigmoid(z2(i));
            end
            z3=theta3*hidden2';
            output=sigmoid(z3);
            ......

上面的d_x向量是列向量。

误差逆传播(BP算法的精华部分)

将误差从输出层返传回紧挨着输入层的隐藏层的过程。返回的过程主要是修改每一层每个连接的权重,达到减少误差的过程。
反向传播代码实现(吴恩达 说的向量化代码也打了注释了,ps:向量化用时少,但是真的不好想)

			......
			%反向传播
            %output层的error(损失函数对Z求偏导)计算方法为直接对Z求偏导,链式法则链到a
            error3=(output-y(num))*(1-output)*output;
            %error2=error3*theta3.*hidden2(i).*(1-hidden2(i));
            for i=1:5,
                error2(i)=error3*theta3(:,i)*hidden2(i)*(1-hidden2(i));
            end
            %error1=error2*theta2.*hidden1(i).*(1-hidden1(i));
            for i=1:5,
                error1(i)=error2*theta2(:,i)*hidden1(i)*(1-hidden1(i));
            end
            %更新权重
            %theta1=theta1-interval*error1'*d_x';
            for i=1:5,
                for j=1:3,
                    theta1(i,j)=theta1(i,j)+interval*error1(i)*x(j);
                end
            end
            %theta2=theta2-interval*error2'*hidden1;
            for i=1:5,
                for j=1:5,
                    theta2(i,j)=theta2(i,j)+interval*error2(i)*hidden1(j);
                end
            end
            %theta3=theta3-interval*error3'*hidden2;
            for i=1:5,
                theta3(i)=theta3(i)+interval*error3*hidden2(i);
            end
            ......

在这里插入图片描述

诀窍:(大前提:w1的dimension=[inputsize,hiddensize]…)
从输出层计算error,公式记作:下一层error点乘这一层权重的转置再乘上这层输出函数的导数。(ps:sigmoid函数在a的导数等于sigmoid(a)*(1-sigmoid(a)))
partical J除以partical w(某一层)等于上一层输出的转置点乘这层的error。

完整代码

Matlab

function [ ] = build_bp(  )
    INTERVAL=0.8;
    x=load('D:\machineLearning\逻辑回归\ex4Data\ex4x.dat');
    y=load('D:\machineLearning\逻辑回归\ex4Data\ex4y.dat');
    m=length(x(:,1));
    c_p=find(y==1);
    s_p=find(y==0);
    x(:,1)=(x(:,1)-mean(x(:,1)))./std(x(:,1))
    x(:,2)=(x(:,2)-mean(x(:,2)))./std(x(:,2))
    %plot(x(c_p,1),x(c_p,2),'ro');
    %hold on;
    %plot(x(s_p,1),x(s_p,2),'bs');
    x=[ones(m,1) x];

    %搭建三层神经网络,需要三个权重矩阵
    theta1=rand(5,3)*2*INTERVAL-INTERVAL;
    theta2=rand(5,5)*2*INTERVAL-INTERVAL;
    theta3=rand(1,5)*2*INTERVAL-INTERVAL;
    interval=0.4;
   
    iter=100;
    c=1;
    loss=0;
    while c<=iter,
        t=0;
        for num=1:80,
            transpose_x=x';
            d_x=transpose_x(:,num);
            d_y=y;
            %前向传播
            z1=theta1*d_x;
            for i=1:5,
                %Matlab构造的向量默认是行向量
                hidden1(i)=sigmoid(z1(i));
            end
            z2=theta2*hidden1';
            for i=1:5,
                hidden2(i)=sigmoid(z2(i));
            end
            z3=theta3*hidden2';
            output=sigmoid(z3);
     
            %反向传播
            %output层的error(损失函数对Z求偏导)计算方法为直接对Z求偏导,链式法则链到a
            error3=(output-y(num))*(1-output)*output;
            %error2=error3*theta3.*hidden2(i).*(1-hidden2(i));
            for i=1:5,
                error2(i)=error3*theta3(:,i)*hidden2(i)*(1-hidden2(i));
            end
            %error1=error2*theta2.*hidden1(i).*(1-hidden1(i));
            for i=1:5,
                error1(i)=error2*theta2(:,i)*hidden1(i)*(1-hidden1(i));
            end
            %更新权重
            %theta1=theta1-interval*error1'*d_x';
            for i=1:5,
                for j=1:3,
                    theta1(i,j)=theta1(i,j)+interval*error1(i)*x(j);
                end
            end
            %theta2=theta2-interval*error2'*hidden1;
            for i=1:5,
                for j=1:5,
                    theta2(i,j)=theta2(i,j)+interval*error2(i)*hidden1(j);
                end
            end
            %theta3=theta3-interval*error3'*hidden2;
            for i=1:5,
                theta3(i)=theta3(i)+interval*error3*hidden2(i);
            end
            e=(output-y(num))^2/2;  %计算误差向量  (计算输出-目标输出)  
            t=t+e;
        end
        loss(c)=t;
        c=c+1;
    end
        plot(1:iter,loss);
end


图像

在这里插入图片描述

python

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

class Neural_Network(object):
    def __init__(self):
        self.inputSize=2
        self.outputSize=1
        self.hiddenSize = 3
        self.alpha=0.2
        self.iterations=100
        self.count_error=[]
        self.w1=np.random.randn(self.inputSize,self.hiddenSize)
        self.w2=np.random.randn(self.hiddenSize,self.hiddenSize)
        self.w3=np.random.randn(self.hiddenSize, self.outputSize)

    def sigmoid(self,s):
        return 1/(1+np.exp(-s))

    def forward(self,x,y):
        self.z1=np.dot(x,self.w1)
        self.hidden1=self.sigmoid(self.z1)
        self.z2=np.dot(self.hidden1,self.w2)
        self.hidden2=self.sigmoid(self.z2)
        self.z3=np.dot(self.hidden2,self.w3)
        self.output=self.sigmoid(self.z3)
        self.count_error.append(np.mean(np.square(y-self.output)))
        return self.output

    def backward(self,x,y,output):
        #error2表示损失值对Z求偏导数。链式法则:先对a求偏导,再乘以a对Z求偏导
        self.error3=(output-y)*(1-output)*output
        #链式法则,链接到下一层Z求解
        self.error2=self.error3.dot(self.w3.T).dot(np.dot((1-self.hidden2),self.hidden2))
        self.error1=self.error2.dot(self.w2.T).dot(np.dot((1-self.hidden1),self.hidden1))

        self.w1-=self.alpha*x.T.dot(self.error1)
        self.w2-=self.alpha*self.hidden1.T.dot(self.error2)
        self.w3-=self.alpha*self.hidden2.T.dot(self.error3)

    def train(self,x,y):
        for i in range(self.iterations):
            output=self.forward(x,y)
            self.backward(x,y,output)

if __name__=="__main__":
    x=np.array(([0.3,1],[0.2,0.5],[0.4,0.8]),dtype=float)
    y=np.array(([0.9],[0.8],[0.7]),dtype=float)
    #plt.scatter(x[:,0],x[:,1])
    #plt.show()
    NN=Neural_Network()
    NN.train(x,y)

    plt.plot(range(1,NN.iterations+1),NN.count_error)
    plt.title('error')
    plt.xlabel('iteration')
    plt.ylabel('error')
    plt.show()




图像

在这里插入图片描述

分析总结

手搓BP反向传播算法,其实Matlab的代码,写好晾了几乎有一礼拜了,之前一直觉得loss值有问题就一直在思考着:loss值振荡是什么鬼东西?其实说到底一个Neuron也就是简单的逻辑回归,逻辑回归的loss函数说到底是个交叉熵,如下图(参考自李宏毅老师的深度学习课程讲解):
在这里插入图片描述

如果你记录的loss值不是一轮训练完之后的平均值,而是整个数据集中的单个样本计算出来的loss值,那么有振荡现象是很正常的。当你的记录loss值是一轮训练完之后的平均值的时候,那loss函数的图像应该就会是正常缓慢下降的了。
现在深度学习框架中封装好的损失函数,一般也都是在一轮训练结束后取的平均误差。比如说均方误差,一听名字就知道了。
而且python喂数据的形式和matlab也不一样,二维张量是所有组一起喂到网络里面迭代的。如果在matlab的话会是一次进一组数去迭代,再下一轮进下一组数。
这么想也就明白了奇怪的图像了。

发布了33 篇原创文章 · 获赞 5 · 访问量 2303

猜你喜欢

转载自blog.csdn.net/cj1561435010/article/details/101177473