优秀的编程知识分享平台

网站首页 > 技术文章 正文

感知器算法超详细讲解实战「原理+手撸代码实现」+spark应用实践

nanyue 2024-07-23 13:42:39 技术文章 19 ℃

学校期间刚接触到机器学习的时候就学习过感知器算法了,最近正好用到了这个模型就索性拿出来温习一下,这里我将感知器构建和计算的几个关键步骤整体出来,具体的算法原理如下所示:

感知器算法可以说是最简单最基础的神经网络模型了,因为它只有一层的网络结构,计算能力和表述能力都十分有限,这里的有限并不是说它的计算能力很弱,针对线性计算问题:理论上来说感知器可以拟合出来任何形式的线性计算模型;针对实际问题或者是非线性问题来说:由于现实生活中的大多数计算都是非线性的表述关系,感知器模型想要准确捕捉到数据的特点还是比较困难的,神经网络的出现很好了解决了这个问题,这里就不多展开了。感知器是模拟生物神经元的机器模型,一个简单的感知器模型结构示意图如下图所示:

给定一个n维的输入 ,其中w和b是参数,w为权重,每一个输入对应一个权值,b为偏置项,需要从数据中训练得到。激活函数则有较多的选择,较为常见的有sigmoid函数和阶跃函数。这里关于公式上的计算我就不多说明了,这里为了更加清晰地看出来两种激活函数的异同点,这里我进行了可视化处理,先给出来具体的代码实现,如下所示:

1.	def jieyueFunc(x): 
2.	 ''''' 
3.	 定义感知器阶跃函数 
4.	 ''' 
5.	 return np.where(x<0,0,1) 
6.	 
7.	 
8.	def jieyueFuncDerivative(x): 
9.	 ''''' 
10.	 定义感知器阶跃函数导函数 
11.	 ''' 
12.	 return np.where(x<0,0,0) 
13.	 
14.	 
15.	def sigmoid(x): 
16.	 ''''' 
17.	 定义sigmoid函数 
18.	 ''' 
19.	 return 1.0/(1.0+np.exp(-x)) 
20.	 
21.	 
22.	def sigmoidDerivative(x): 
23.	 ''''' 
24.	 定义sigmoid导函数 
25.	 ''' 
26.	 return sigmoid(x)*(1-sigmoid(x)) 

上述代码定义了sigmoid函数和阶跃函数以及各自对应的导函数,下面对其函数曲线进行可视化,实现如下:

1.	x=np.arange(-10,10,0.1) 
2.	y1=sigmoid(x) 
3.	y2=jieyueFunc(x) 
4.	y11=sigmoidDerivative(x) 
5.	y22=jieyueFuncDerivative(x) 
6.	plt.clf() 
7.	plt.plot(x,y1,label='sigmoid') 
8.	plt.plot(x,y2,label='jieyue') 
9.	plt.plot(x,y11,label='sigmoidDerivative') 
10.	plt.plot(x,y22,label='jieyueDerivative') 
11.	plt.title('ActivateFunction Compare') 
12.	plt.legend() 
13.	plt.show() 

结果如下图所示:

上图对比一目了然,从原函数取值区间上来说二者并无太大差别,sigmoid函数是一种渐变的趋势,阶跃函数是一种突变的趋势;从导函数上来说:sigmoid导函数曲线呈现出“正态分布”的特点,而阶跃函数导函数恒为0。

关于感知器算法进一步的理论介绍本文就不过多地涉及了,网上也有很多的学习资料可供参考,今天主要是结合实际应用需求来实践感知器算法模型。

这里我们随机构建了5个样本点的数据集【仅作演示讲解使用,可根据自己实际情况修改】,具体如下所示:

其中,数据集一共分为两类:0和1,分别包含2个和3个样本数据,第一列No表示的是Id序号并无实际用途,最后一列表示样本数据的标签。

在讲解具体的实现之前先给出来模型分类结果的可视化数据如下图所示:

其中,蓝色点表示标签为0的样本数据,红色点表示标签为1的样本数据,可以看到模型正确实现了分类。

下面我们来看具体的代码实现,如下:

1.	def demoModel(datasets,x_total,W,n,iters,pic_path='demo_res.png'): 
2.	 ''''' 
3.	 感知器模型 
4.	 ''' 
5.	 if not os.path.exists('my/'): 
6.	 os.mkdir('my/') 
7.	 x1,x2,t=datasets[:, 1], datasets[:, 2], datasets[:, 3] 
8.	 label_list=[x_total[i][-1] for i in range(len(x_total))] 
9.	 print('label_list: ',label_list) 
10.	 index,right=0,0 
11.	 for i in range(iters): 
12.	 if index>=5: 
13.	 index,right=0,0 
14.	 node=inputNetCal(x_total[index][:3],W) 
15.	 bias=biasCal(label_list[index],node,1) 
16.	 if x_total[index][3]==1 and node<=0: 
17.	 W=netWadjust(W,n,x_total[index][:3],1) 
18.	 elif x_total[index][3]==0 and node>=0: 
19.	 W=netWadjust(W,n,x_total[index][:3],-1) 
20.	 plt.cla() 
21.	 for j in range(len(x1)): 
22.	 if t[j]==1: 
23.	 plt.plot(x1[j],x2[j],'ro') 
24.	 else: 
25.	 plt.plot(x1[j],x2[j],'bo') 
26.	 plt.xlim(-1.5,1.5) 
27.	 plt.ylim(-3,3) 
28.	 plt.grid(c='g') 
29.	 plt.title('Dynamic Ploter') 
30.	 x_list=np.arange(-2,2,0.01) 
31.	 plt.plot(x_list,-((W[1]/W[2])*x_list)-(W[0]/W[2])) 
32.	 plt.savefig('my/'+str(i)+'.png') 
33.	 plt.pause(0.1) 
34.	 if x_total[index][3]==1 and node>0: 
35.	 right+=1 
36.	 elif x_total[index][3]==0 and node<0: 
37.	 right+=1 
38.	 index+=1 
39.	 print('index: {0}, right: {1}'.format(index,right)) 
40.	 if right==5: 
41.	 print('Best W: ',W) 
42.	 plt.savefig('demoModel.png') 
43.	 break 
44.	 return W.tolist(),bias 

上述代码实现了感知器算法模型,并对我们提供的数据集中的样本数据进行了分类处理。

代码的实现很简单,这里就不过多地解释说明了,因为就是基于感知器的理论实现的,接下来对其中几个关键点进行说明。

网络权重自适应调整与偏置项计算:

1.	def netWadjust(W,n,X,flag): 
2.	 ''''' 
3.	 网络权重自适应调整 
4.	 ''' 
5.	 return W+((n*X)*flag) 
6.	 
7.	 
8.	def biasCal(label,output,n): 
9.	 ''''' 
10.	 计算偏置项 
11.	 ''' 
12.	 bias=label-output 
13.	 bias+=n*bias 
14.	 return bias 

单次神经元计算:

1.	def inputNetCal(X,W): 
2.	 ''''' 
3.	 计算 
4.	 ''' 
5.	 print('W====>',W) 
6.	 res=np.dot(X,W) 
7.	 return res 

Excel数据集加载处理:

1.	def write2Excel(data_list,targetfile='res.xls'): 
2.	 ''''' 
3.	 将txt中的内容转置后写到Excel中 
4.	 ''' 
5.	 j=0 
6.	 book=xlwt.Workbook(encoding='utf-8') 
7.	 table=book.add_sheet('w_b') 
8.	 for one_list in data_list: 
9.	 for i in range(len(one_list)): 
10.	 table.write(i,j,one_list[i]) 
11.	 j+=1 
12.	 book.save(targetfile) 
13.	 
14.	 
15.	def readOneExcelData(data='data/Homework4.xlsx',row=1,col=1): 
16.	 ''''' 
17.	 row: 起始行索引 
18.	 col: 起始列索引 
19.	 ''' 
20.	 workbook=xlrd.open_workbook(data,encoding_override="utf-8") 
21.	 table=workbook.sheets()[0] 
22.	 row_num,col_num=table.nrows,table.ncols 
23.	 data_list=[] 
24.	 for i in range(row,row_num): 
25.	 one_list=[] 
26.	 for j in range(col,col_num): 
27.	 one_list.append(table.cell_value(i,j)) 
28.	 data_list.append(one_list) 
29.	 return np.array(data_list),[np.array(one) for one in data_list] 

到此,完整的实现过程就介绍完成了,实际运行上述代码的时候可以动态地绘制每一轮中的分类情况,实现了模型输出的动态可视化,同时我将每一次的分类结果与最终的分类结果图像都进行了保存。

如果在PPT或者是讲解过程中需要用到动态可视化的效果,可以基于此前保存好的单次分类结果数据进行合成即可,合成gif代码如下:

1.	def createGif(picDir='pic/',save_path='a.gif',duration=0.35): 
2.	 ''''' 
3.	 创建gif图像 
4.	 ''' 
5.	 pic_list=os.listdir(picDir) 
6.	 pic_list.sort() 
7.	 image_list=[picDir+one for one in pic_list] 
8.	 frames=[] 
9.	 for image_name in image_list: 
10.	 frames.append(imageio.imread(image_name)) 
11.	 imageio.mimsave(save_path,frames,'GIF',duration=duration) 
12.	 print('Finished!!!!') 

短短几行代码就实现了静态图像数据合成gif动图,其中PicDir表示的是原始静态图片数据的存储路径,save_path表示的是生成gif图像的保存路径,duration表示的是创建图像时相邻两张图像之间的时间间隔。

上面我们自己实现了简单的感知器算法模型,在spark中提供了对于多层感知机模型的封装,可以很方便地进行调用、实例和实验分析,这里也一并简单说明一下,感兴趣的话可以去我博客里面的系列文章详细去看。

MLP是一种前向结构的人工神经网络,映射一组输入向量到一组输出向量。MLP可以被看做是一个有向图,由多个节点层组成,每一层全连接到下一层。除了输入节点,每个节点都是一个带有非线性激活函数的神经元(或称处理单元)。一种被称为反向传播算法的监督学习方法常被用来训练MLP。MLP是感知器的推广,克服了感知器无法实现对线性不可分数据识别的缺点。多层感知器(Multi-Layer Perceptron,MLP)也叫人工神经网络(Artificial Neural Network,ANN),除了输入输出层,它中间可以有多个隐层。最简单的MLP需要有一层隐层,即输入层、隐层和输出层才能称为一个简单的神经网络。

感兴趣的话可以关注我的CSDN博客里面的pyspark系列实践的内容,下面简单对使用进行介绍。

一个简单的MLP结果示意图如下所示:

上面是隐藏层只有一层的MLP神经网络模型,下面是隐藏层为两层的神经网络结果示意图:

pyspark顾名思义就是由python和spark组合使用的。Spark提供了一个Python_Shell,即pyspark,从而可以以交互的方式使用Python编写Spark程序。有关Spark的基本架构以及pyspark环境配置相关的内容本篇博客就不再多加阐述了,网络上也有很多不错的讲解。

接下来回归正题,基于pyspark的MLP分类模型实现如下:

1.	#!usr/bin/env python 
2.	#encoding:utf-8 
3.	from __future__ import division 
4.	 
5.	 
6.	''''' 
7.	__Author__:沂水寒城 
8.	功能: pyspark 机器学习实践之【多层感知器分类器模型】 
9.	''' 
10.	 
11.	 
12.	 
13.	import findspark 
14.	findspark.init() 
15.	import pyspark 
16.	from pyspark import SparkConf 
17.	from pyspark.ml import Pipeline 
18.	from pyspark.context import SparkContext 
19.	from pyspark.sql.session import SparkSession 
20.	from pyspark.ml.classification import DecisionTreeClassifier 
21.	from pyspark.ml.evaluation import MulticlassClassificationEvaluator 
22.	from pyspark.ml.feature import StringIndexer, VectorIndexer,IndexToString 
23.	 
24.	 
25.	 
26.	conf=SparkConf().setAppName('MLDemo') 
27.	sc = SparkContext('local') 
28.	spark = SparkSession(sc) 
29.	 
30.	 
31.	def MLPClassifier(data="mllib/sample_multiclass_classification_data.txt"): 
32.	 ''''' 
33.	 多层感知器分类器(MLPC)是基于前馈人工神经网络的分类器。 MLPC由多层节点组成。 每层完全连接到网络中的下一层。 输入层中的节点表示输入数据。 所有其他节点通过输入与节点权重w和偏差b的线性组合将输入映射到输出,并应用激活函数。 
34.	 多层感知机分类器 
35.	 ''' 
36.	 #加载LIBSVM格式的数据集 
37.	 data = spark.read.format("libsvm").load(data) 
38.	 #训练集、测试集划分 
39.	 splits = data.randomSplit([0.6, 0.4], 1234) 
40.	 train = splits[0] 
41.	 test = splits[1] 
42.	 #指定神经网络的层 
43.	 #输入层4个神经元,隐藏层两层神经元数量分别为:5、4,输出层3个神经元 
44.	 layers = [4, 5, 4, 3] 
45.	 trainer = MultilayerPerceptronClassifier(maxIter=100, layers=layers, blockSize=128, seed=1234) 
46.	 model = trainer.fit(train) 
47.	 result = model.transform(test) 
48.	 predictionAndLabels = result.select("prediction", "label") 
49.	 evaluator = MulticlassClassificationEvaluator(metricName="accuracy") 
50.	 print("Test set accuracy = " + str(evaluator.evaluate(predictionAndLabels))) 
51.	 
52.	 
53.	 
54.	if __name__=='__main__': 
55.	 MLPClassifier(data="mllib/sample_multiclass_classification_data.txt") 

述使用到的数据集是pyspark自带的机器学习模型中提供的实验数据集。如果有数据集上的需求可以从这里获取,我构建了一个日常分析挖掘会经常使用到的数据集的资源仓库,链接如下:

 https://github.com/yishuihanhan/myDataset

数据资源仓库截图如下所示,上述用到的数据集就存储在下方红色线框标记的目录下。

简单的测试结果输出如下:

很高兴在自己温习回顾知识的同时能写下点分享的东西出来,如果说您觉得我的内容还可以或者是对您有所启发、帮助,还希望得到您的赞赏鼓励支持,谢谢!【下方有我的赞赏码】

Tags:

最近发表
标签列表