神经元(也可以叫感知机,本质没有太大区别),是神经网络的基本组成单位,这里实现一个简单的神经元进行逻辑回归,并利用sigmoid函数看看对糖尿病数据集二分类的处理效果如何。
基本流程可以先看看这篇,感知机。
完整工程代码点击这里。
一、神经元方程式
其中x是我们输入的数据向量,x=[x1,x2,x3,x4,…,xn],n为特征数目。
w为我们神经元的参数,b是常数项。
拆开看为
z=w1x1 + w2x2 + w3x3 + ... + wnxn + b
其中
为激活函数,激活函数有很多,比如tanh双曲正切函数,ReLu函数,Sigmoid函数,这里入门使用了Sigmoid函数。点击这里查看常见激活函数和对应的函数表达式。
其中y是数据的正确标签,是已知值 ,a为预测的答案。
这里的损失函数L(a,y)采用的是交叉熵损失函数。
二、导函数求解进行反向计算
这里如何更新参数w涉及梯度下降法,导函数的计算涉及链式法则,下面我将进行关于损失函数L和我们的求解目标参数w的导数计算,最后再使用梯度下降法进行参数优化求解。
导数求解证明过程如下:
注意这里的w和x都是向量,w=[w1,w2,w3,…,wn] , x=[x1,x2,x3,…,xn]
所以根据梯度下降法更新时,
w1=w1 - lr * (a-y)x1
w2=w2 - lr * (a-y)x2
....
wn=wn - lr * (a-y)xn
b=b - lr*(a-y)#关于dZ/db=1
三、代码实现
这里使用了糖尿病数据集diabetes.txt
数据集包含8个特征,标签Outcome表示是否患有糖尿病(1表示患病,0表示没患病)。
是比较典型的二分类问题,我们直接用来训练我们的单个神经元,看看效果。
代码如下
import pandas as pd
import numpy as np
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt
N=8#特征数目
lr=0.0001#学习率
step=10000#迭代次数
w = np.random.rand(1,N+1)[0]*0.01#随机初始化参数,w[N]看成是b
def function(w,x):
return np.sum(w[0:N]*x)+w[N]
def Sigmoid(z):#激活函数
return 1/(1+np.e**(-z))
def Loss(w,x,y):#损失函数
loss=0
for i in range(len(x)):
a=Sigmoid(function(w,x[i]))
loss+=(-(y[i]*np.log(a)+(1-y[i])*np.log(1-a)))
return loss/len(x)#取平均
def derivative_function(w,x,y):#导数
derivative=[]
for j in range(N):
averge=0
for i in range(len(x)):
averge+=Sigmoid(function(w,x[i]))*x[i][j]
averge/=len(x)#取平均
derivative.append(averge)#储存下每个参数wj的平均下降梯度
averge=0
for i in range(len(x)):#针对参数b
averge+=Sigmoid(function(w,x[i]))
averge/=len(x)
derivative.append(averge)
return np.array(derivative)
def Predict_function(w,x):
pred=[]
for i in range(len(x)):
res=Sigmoid(function(w,x[i]))
if res>=0.5:
pred.append(1)
else:
pred.append(0)
return np.array(pred)
data=pd.read_csv('download/diabetes.txt',header=None).values
M=len(data)#数据集大小
x=data[:,0:N]
x=x/(np.max(x)-np.min(x))#归一化
y=data[:,-1]
train_x=x[0:int(M*0.8)]
train_y=y[0:int(M*0.8)]
#按8:2划分训练集和验证集
test_x=x[int(M*0.8):]
test_y=y[int(M*0.8):]
los=[]
best_w=w.copy()
best_loss=1e9
for i in range(step):
loss=Loss(w,train_x,train_y)
if i%10==0:
print('step=',i,' loss=',loss)
if loss<best_loss:#找最优参数
best_loss=loss
best_w=w.copy()
los.append(loss)
f=derivative_function(w,x,y)
w=w-lr*f#乘上学习率,开始梯度下降法
y_pre = Predict_function(best_w,test_x)
print("accuracy_score: %.4lf" % accuracy_score(test_y,y_pre))
plt.plot(los)
plt.show()
运行结果
最后准确率为0.6429,尽力了,因为单个神经元的学习能力实在很弱,这里主要演示下单个神经元如何实现,主要找不到合适的数据集,糖尿病数据集8个特征信息,已经算是比较复杂的数据信息了。
PS:实验中,模型存在发散现象,一开始模型不断拟合,损失降低,但是逐渐到达某个峰值后开始发散,损失不断增大,我反复做了实验对比,思考原因可能是学习率不够小,其次数据集也存在问题,因为我没有分批次训练,而是整个数据集导入训练取梯度平均,这样的过程很容易带来很大的误差,导致模型拟合到一定结果时因为这个细微的误差开始出现发散,其次的原因还有就是,虽然我们尽可能让数据误差呈现凸函数方便使用梯度下降法求解,但实际中数据呈现的函数形式可能更复杂,不是标准的凸函数形式,这样模型迭代就容易陷入这种局部危险中。
希望我的分享对你的学习有所帮助,如果有问题请及时指出,谢谢~