反向传播代码和BP算法--jupyter notebook

#!/usr/bin/env python
# coding: utf-8

# In[2]:


# %matplotlib具体作用是当你调用matplotlib.pyplot的绘图函数plot()进行绘图的时候,或者生成一个figure画布的时候,
# 可以直接在你的python console里面生成图像。


# In[2]:


from __future__ import division,print_function
import numpy as np
import matplotlib.pyplot as plt
get_ipython().run_line_magic('matplotlib', 'inline')


# In[3]:


##生成训练集X数据,总共500个样本,每个样本2个特征,并添加一个偏置项
num_obs=500
x_mat_1=np.random.uniform(-1,1,size=(num_obs,2))#在下界-1和上届1之间均匀采样
x_mat_bias=np.ones((num_obs,1))
x_mat_full=np.concatenate((x_mat_1,x_mat_bias),axis=1)


# In[4]:


#生成标签值:y=0或1
#np.abs() 是numpy中的一个函数,它的作用是计算一个数组中每个元素的绝对值

y=((np.abs(x_mat_full[:,0])+np.abs(x_mat_full[:,1]))<1).astype(int)####true=1,false=0


# In[5]:


##可视化训练集  x_mat_full[y==1,0],第0列(特征),y_true=1值    x_mat_full[y==1,1],第一列(特征),y_true=1的值
print('shape of  x_mat_full is {}'.format(x_mat_full.shape))
print('shape of y is {}'.format(y.shape))
fig,ax=plt.subplots(figsize=(5,5))
ax.plot(x_mat_full[y==1,0],x_mat_full[y==1,1],'ro',label='class 1')#x轴,y轴
ax.plot(x_mat_full[y==0, 0],x_mat_full[y==0, 1], 'bx', label='class 0')#x轴,y轴
plt.grid(True)

ax.legend(loc='best')
ax.axis('equal')


# In[6]:


def  sigmoid(x):
    return 1.0/(1.0+np.exp(-x))

def loss_fn(y_true,y_pred,eps=1e-16):
    
    y_pred=np.maximum(y_pred,eps)##保证大于0
    y_pred=np.minimum(y_pred,(1-eps))##保证小于1
    
    return -(np.sum(y_true*np.log(y_pred)) + np.sum((1-y_true)*np.log(1-y_pred)))/len(y_true)


# In[16]:


def forward_pass(W1,W2):
    print('W1',W1.shape)#(3, 4)
    print('W2',W2.shape)#(4,)
    global x_mat
    print("x_mat",x_mat.shape)#x_mat (500, 3)
    print("x_mat_len",len(x_mat))#x_mat_len 500
    global y
    z_2=np.dot(x_mat,W_1)#矩阵相乘
#     print(z_2)
    a_2=sigmoid(z_2)
    print("a_2",a_2.shape)#(500, 4)
    print("W2",W2.shape)#(4,)
    print("W2",W2)#W2 [-0.83280111  0.21499121 -0.63179538 -0.83337167]
    z_3=np.dot(a_2,W_2)
    print("z_3",z_3.shape)#fo1 (500,)
    
    y_pred=sigmoid(z_3).reshape((len(x_mat),))
    """
    1 (500,)--->1行500列   元素据(500,3)+标签(500,1)-->(500,4)---计算损失会形成500个数字
    2 (500,)--->1行500列
    3 (500,)
    4 (4,)
    5 (500, 4)
    6 (500, 4)
    8 (500, 4)
    7 (3, 4)
    """
# #     #计算梯度
    J_a_3_grad=y_pred-y#交叉熵损失函数对于预测值求导得到结果为y_pred-y#J(损失公式)_a_3(pred)_grad-->得到500个数
    print("1",J_a_3_grad.shape)
#     print("1",J_a_3_grad)
    a_3_z_3_grad=sigmoid(z_3)*(1-sigmoid(z_3))
    print("2",a_3_z_3_grad.shape)
    J_z_3_grad=J_a_3_grad*a_3_z_3_grad
    print("3",J_z_3_grad.shape)
    J_W_2_grad=np.dot(J_z_3_grad,a_2)#w(0)的参数喂到第一层,生成a(1);W(1)的参数喂到第2层,生成a(2)
    print("4",J_W_2_grad.shape)#1行4列
    print("5",a_2.shape)
    a_2_z_2_grad = sigmoid(z_2)*(1-sigmoid(z_2))
    print("6",a_2_z_2_grad.shape)
    print("8",z_2.shape)#(500,4)
    
    J_W_1_grad=(np.dot((J_z_3_grad).reshape(-1,1),W_2.reshape(-1,1).T)*a_2_z_2_grad).T.dot(x_mat).T#链式法则--》因为z_3_a_2_grad=W_2
    print("7",J_W_1_grad.shape)#(3,4)
    gradient=(J_W_1_grad,J_W_2_grad)
    
     # 计算梯度
#     J_z_3_grad = -y + y_pred
#     J_W_2_grad = np.dot(J_z_3_grad, a_2)
#     a_2_z_2_grad = sigmoid(z_2)*(1-sigmoid(z_2))
#     J_W_1_grad = (np.dot((J_z_3_grad).reshape(-1,1), W_2.reshape(-1,1).T)*a_2_z_2_grad).T.dot(x_mat).T
#     gradient = (J_W_1_grad, J_W_2_grad)
    return y_pred,gradient
    
    
    
    


# In[17]:


np.random.seed(1241)

W_1=np.random.uniform(-1,1,size=(3,4))##表示前面3个神经元,后面4个神经元
W_2=np.random.uniform(-1,1,size=(4))##表示前面4个神经元,后面一个神经元->向量  1*4就不能这么处理,4*1可以


# In[22]:


num_iter=5000
learning_rate=0.001
x_mat=x_mat_full

loss_vals,accuracies=[],[]

for i in range(num_iter):
    y_pred,(J_W_1_grad,J_W_2_grad)=forward_pass(W_1,W_2)#首先前向传播和梯度下降得到所有组参数梯度值w上标1(这里就是J_W_1_grad)和w上标2这里就是J_W_2_grad)
    
    W_1=W_1-learning_rate*J_W_1_grad#然后对每个参数梯度组进行梯度计算,得到更新后的梯度
    W_2=W_2-learning_rate*J_W_2_grad
#     print(y_pred)
    curr_loss=loss_fn(y,y_pred)#计算损失,这里只是计算损失值而已,做个记录而已。梯度下降需要的损失,已经在J_a_3_grad=y_pred-y做了
    loss_vals.append(curr_loss)
    
#     print(y)
    acc=np.sum((y_pred>.5)==y)/num_obs#有一个判断,这里是大于还是大于等于,结果一样,就不要纠结了
    print(acc)
    accuracies.append(acc)
    
    if ((i %200)==0):
        print('iteration {}, log loss is {:.4f}, accuracy is {}'.format(
            i, curr_loss, acc))


# In[ ]:



反向传播代码和BP算法--jupyter notebook_第1张图片

 二、BP算法

#!/usr/bin/env python
# coding: utf-8

# In[1]:


import numpy as np


# In[2]:


def sigmoid(x):
    """
    Sigmoid函数
    """
    return 1.0/(1.0+np.exp(-x))##1/(1+e^-1)=t


# In[5]:


def  loss_fn(y_true,y_pred):##损失的作用,是对应真实值  ##这里就是保证输出的结果,与真实值对应
    """
    损失函数
    """
    return (y_true-y_pred)**2/2########除2用于求导的时候消去2


# In[6]:


def _w(i):
    global w
    return w[i-1]
def _b(i):
    global b
    return b[i-1]
def _x(i):
    global x
    return x[i-1]
def _y(i):
    global y
    return y[i-1]


# In[31]:


def forward_pass():
    #######下_第一层#####
    neth1=_w(1)*_x(1)+_w(2)*_x(2)+_b(1)#w0x0+w1x1+b0       ---->第一个神经元
    outh1=sigmoid(neth1)
    
    neth2=_w(3)*_x(1)+_w(4)*_x(2)+_b(1)#w2x0+w3x1+b0       ——>第二个神经元
    outh2=sigmoid(neth2)
    
    neth3=_w(5)*_x(1)+_w(6)*_x(2)+_b(1)#w4x0+w5x1+b0       ----->第三个神经元
    outh3=sigmoid(neth3)
    
    """
    (3*2)   (2*1)  (3*1)
    w0 w1           w0x0+w1x1  b(0)
    w2 w3    x0     w2x0+w3x1  b(0)
    w4 w5    x1     w4x0+w5x1  b(0) 
    
    
    每一层神经元都要假如相同的b,输出结果。同一层神经元假的b是相同的,不同层神经元加的b不同。
    """
    ##############下_第二层############
    neto1=_w(7)*outh1+_w(9)*outh2+_w(11)*outh3+_b(2)##w6*outh1+w(8)*outh2+w(10)*outh3+b(1)  --->第一个神经元
    outo1=sigmoid(neto1)##预测值1
    neto2=_w(8)*outh1+_w(10)*outh2+_w(12)*outh3+_b(2)##w6*outh1+w(8)*outh2+w(10)*outh3+b(1) ---->第二个神经元
    outo2=sigmoid(neto2)##预测值2
    
    y_pred=np.asarray([outo1,outo2])
    loss1=loss_fn(_y(1),outo1)
    loss2=loss_fn(_y(2),outo2)
    E=loss1+loss2##总损失值
    
    
    """
    链式求导:
    grad_E_outo1
    grad_outo1_neto1##激活函数对神经元求导
    
    grad_neto1_w7
    grad_w7
    
    grad_neto1_w9
    grad_w9
    
    grad_neto1_w11
    grad_w11
    
    """
    grad_E_outo1=outo1 - _y(1)#对预测值求导
    grad_outo1_neto1=outo1*(1-outo1)  #t的导数=t(1-t)
    ##########下_第二层神经元(2个) outo1、outo2
    
    """
    (2*3)        (3*1)     (2*1)      (2*1)
                 outh1     neto1      outo1
    w7 w9  w11   outh2     neto2      outo2
    w8 w10 w12   outh3
    
    参数计算:输入a(2)个特征(x1,x2..);第一层神经元个数:b(3);第二层神经元个数c(2);最后输出2
    那么参数计算为:a*b+b*c+c*2=2*3+3*2+2*2=20
    
    """
    grad_neto1_w7=outh1##关于某一层参数的求导,如果此参数不是最开始输入层,那么链式法则求导梯度,
    #最后乘的就是神经元经过激活后的输出值,参数与哪个神经元连接,乘的就是那个神经元经过激活后的输出值
    grad_w7=grad_E_outo1*grad_outo1_neto1*grad_neto1_w7
    grad_neto1_w9=outh2
    grad_w9=grad_E_outo1*grad_outo1_neto1*grad_neto1_w9
    grad_neto1_w11=outh3
    grad_w11=grad_E_outo1*grad_outo1_neto1*grad_neto1_w11
    
    grad_E_outo2=outo2-_y(2)
    grad_outo2_neto2=outo2*(1-outo2)
    grad_neto2_w8=outh1
    grad_w8=grad_E_outo2*grad_outo2_neto2*grad_neto2_w8
    grad_neto2_w10=outh2
    grad_w10=grad_E_outo2*grad_outo2_neto2*grad_neto2_w10
    grad_neto2_w12=outh3
    grad_w12=grad_E_outo2*grad_outo2_neto2*grad_neto2_w12
    
    
    #################下_第一层神经元(3) outh1、outh2、outh3
    grad_Eo1_outh1=grad_E_outo1*grad_outo1_neto1*_w(7)
    grad_Eo2_outh1=grad_E_outo2*grad_outo2_neto2*_w(8)
    grad_outh1_neth1=outh1*(1-outh1)##对激活函数求导
    grad_neth1_w1=_x(1)#神经元。后面跟激活函数,前面就是具体的参数
    grad_w1=(grad_Eo1_outh1+grad_Eo2_outh1)*grad_outh1_neth1*grad_neth1_w1
    grad_neth1_w2=_x(2)#关于某一层参数的求导,如果此参数是最开始输入层,那么链式法则求导梯度,
    #最后乘的就是输入的特征值,参数与哪个特征值(x1,x2...)连接,乘的就是那个特征值
    grad_w2=(grad_Eo1_outh1+grad_Eo2_outh1)*grad_outh1_neth1*grad_neth1_w2
    
    
    grad_Eo1_outh2=grad_E_outo1*grad_outo1_neto1*_w(9)
    grad_Eo2_outh2=grad_E_outo2*grad_outo2_neto2*_w(10)
    grad_outh2_neth2=outh2*(1-outh2)
    grad_neth2_w3=_x(1)
    grad_w3 = (grad_Eo1_outh2+grad_Eo2_outh2)*grad_outh2_neth2*grad_neth2_w3
    grad_neth2_w4=_x(2)
    grad_w4 = (grad_Eo1_outh2+grad_Eo2_outh2)*grad_outh2_neth2*grad_neth2_w4
    
    grad_Eo1_outh3=grad_E_outo1*grad_outo1_neto1*_w(11)
    grad_Eo2_outh3=grad_E_outo2*grad_outo2_neto2*_w(12)
    grad_outh3_neth3=outh3*(1-outh3)
    grad_neth3_w5=_x(1)
    grad_w5 = (grad_Eo1_outh2+grad_Eo2_outh2)*grad_outh3_neth3*grad_neth3_w5
    grad_neth3_w6=_x(2)
    grad_w6 = (grad_Eo1_outh2+grad_Eo2_outh2)*grad_outh3_neth3*grad_neth3_w6
    
    grad_w=[grad_w1,grad_w2,grad_w3,grad_w4,grad_w5,grad_w6,grad_w7,grad_w8,grad_w9,grad_w10,grad_w11,grad_w12]
    
    return y_pred,grad_w


# In[32]:


#####初始化
x=[5,10]
y=[0.01,0.99]
w=[0.1,0.15,0.2,0.25,0.3,0.35,0.4,0.45,0.5,0.55,0.6,0.65]
b=[0.35,0.65]###看网络几层,也就看b的值就好。 每一层神经元都要假如相同的b,输出结果。同一层神经元假的b是相同的,不同层神经元加的b不同。


# In[35]:


num_iter=100000
learning_rate=.05

loss_vals=[]
for i in range(num_iter):#训练次数
    y_pred,grad_w=forward_pass()
    print(y_pred)
    loss_val=loss_fn(_y(1),y_pred[0])+loss_fn(_y(2),y_pred[1])###这里就是保证输出的结果,与真实值对应
    
    loss_vals.append(loss_val)
    
    for i in range(len(w)):#梯度更新
        w[i]=w[i]-learning_rate*grad_w[i]
        


# In[34]:


loss_vals


# In[41]:


import matplotlib.pyplot  as plt
#%matplotlib inline
plt.plot(loss_vals)
plt.xlabel('iterations')
plt.title('Loss')
# plt.grid(True)


# In[ ]:




 

你可能感兴趣的:(jupyter,python,numpy)