#!/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[ ]:
#!/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[ ]: