当前位置: 首页 > Web前端 > JavaScript

机器学习超基础入门-原理

时间:2023-03-27 14:59:24 JavaScript

前言随着前端智能化的普及,AI机器学习进入了前端开发者的视野。AI可以解决编程领域无法通过规则和运算直接解决的问题,并通过自动推理产生最佳策略,成为前端工程师解决问题的又一利器。可能很多同学都跃跃欲试。打开TensorFlow或者Pytorch的官网,然后跟着文档写了一个机器学习的HelloWorld,然后遇到一些不知道是什么的函数。运行示例后,他们不知所措。这是因为TensorFlow和Pytorch是使用机器学习的工具,而不解释什么是机器学习。所以本文以实践为最终目的,介绍机器学习入门的一些基本原理,并加入一点图像处理的卷积,希望能帮助大家理解。基本概念首先,什么是机器学习?机器学习大致相当于找到这样一个函数。比如在语音识别中,输入一段语音,输出文本内容。在图像识别中,输入一张图像,输出图片中的物体。围棋输入棋盘数据输出下一步是什么?去吧,在对话系统里,输入一句hi,输出一个回应,而这个功能是机器自己通过在你写的程序中加入大量的数据来学习的。如何找到这样的函数,让我们从线性模型开始。线性模型形式简单,易于建模,但包含了机器学习中一些重要的基本思想。通过在线性模型的基础上引入层次结构或高维映射,可以获得许多更强大的非线性模型。我们从猫和狗的分类来看线性模型。我们在教孩子区分猫和狗的时候,不是从维基百科给出定义,而是让孩子不断地看到猫和狗,让他判断,然后告诉他正确的答案,纠缠在错误的认知中。机器学习也是一样,不断地告诉计算机什么是正确的,纠正计算机的认知。不同的是,儿童的认知是由人脑自动处理的,而计算机无法自动建立猫狗的记忆。只知道数字。所以我们需要提取出代表猫和狗的特征,然后用数字表示。为了简化示例,我们在这里只使用两个特征,鼻子的大小和耳朵的形状。一般来说,猫的鼻子较小,耳朵较尖,而狗的鼻子较大,耳朵较圆。对于多张图片,我们统计图片中的耳鼻特征,并用二维坐标表示。可以看到猫狗会分布在坐标系的不同区域。肉眼可见,我们可以用直线来区分,但是电脑看不到在哪里划线。如何将信息传递给计算机,让我们定义两个变量,x1代表鼻子的大小,x2代表耳朵的形状,然后定义这样一个直线方程W1·X1+W2·X2-b=0,相当于,y=W1·X1+W2·X2-b,当y大于0时判断为猫,当y小于0时判断为狗。现在,从计算机的角度来看,它有一堆数据,有一个线性模型,还有一个目标/任务。我们的期望是当给定一个没有见过的x时,通过f(x),我们可以得到一个预测值y,这个y应该尽可能接近真实值,这样才会有一个有用的萌宠分类机!如何用数字表达这样的目标?这就需要引入一个概念损失函数(Lossfunction)。损失函数计算预测值和真实值之间的差距。常用的损失函数是绝对值损失函数(Absolutevalueloss),即两个值之差的绝对值,很直观,离目标的距离是多少,加起来,还有asquarelossfunction(leastsquaremethod,Leastsquaresloss)平方损失函数的目标是最小化每个点到回归线的距离,也就是欧式距离。现在,我们对计算机的目标是找到一个最小值。为了找到这个值,让我们回忆一下失传已久的微积分。导数为0的地方是函数的最大值或最小值。对于图中这样一个简单的一元二次方程,我们可以直接推导参数w,得到最小值。但是,如果是像下图这样的函数,很难找到,而且不同的函数有不同的推导公式,那就比较麻烦了。毕竟我们的目标是让机器自己学习。正确的。因此,我们需要一种更通用的计算方法,即梯度下降(Gradientdescent,梯度下降的基本流程如下。首先,我们随机取一个点作为初始值,计算这个点的斜率,即是导数,当斜率为负时,向右走一小步,当斜率为正时,向左走一小步,在每个点重复,计算新的斜率,然后再走一小步步长适当,就会逼近函数某个局部极小值就像一个小球从山上滚下来,只是初始位置不同,会到达不同的局部极小值,不能保证是全局最小值。但是,其实大部分情况下,我们根据问题抽象出的函数基本都是凸函数,可以得到一个最小值,当最小值不唯一时,也可以加入随机数,给跳转机会超出当前最小值v蓝色区域。我们需要明确一点,机器学习的理论支撑是概率论和统计学。我们通过机器学习找到的答案往往不是最优解,而是极优解。想象一个具有两个输入和一个输出的更复杂的二元函数。我们的损失函数可以表示为三维空间中的一个表面。问题就变成了,曲面上的一个点在空间中应该往哪个方向走才能让结果下降最快。步骤还是一样,计算梯度,更新,计算,更新....公开的表达式如下。这时候我们就遇到了第一个超参数η,也就是学习率(Learningrate),机器学习中的一个参数分为两类,模型参数和超参数,模型参数为w,是为了让机器自学习,超参数由开发者在模型训练前指定。通过上面的公式我们可以看出Lossfunction函数对参数w的导数决定了我们前进的方向,而learningrate决定了每个小部分在这个方向上走过的距离。当η太小时,到达最小值的过程会很慢,如果η太大,会因为步幅过大而直接越过最低点。那么,如何选择η的值,比较常规的方式是从0.1这样的值开始,然后呈指数递减,取0.01,0.001,当我们使用较大的学习率时,我们会发现损失函数的值如果几乎没有下降,它可能正在摆动。当我们得到一个更小的值可以让损失函数下降时,再继续往下取,不断缩小范围。这个过程也可以由计算机自动完成。如果有计算资源的话。了解了梯度下降和学习率之后,我们已经可以用线性模型来解决比较简单的问题了。基本步骤:提取特征,设置模型计算梯度,更新,要不要试试看!这里有一个简单的房价预测栗子,大家可以在本地跑一下,尝试调整不同的学习率,看看损失函数的变化。https://github.com/xs7/Machin...关键代码如下:#lossfunctiondeflossFunction(x,y,w,b):cost=np.sum(np.square(x*w+b-y))/(2*x.shape[0])返回成本#推导def推导(x,y,w,b):#wd=((x*w+b-y)*x)/x.shape[0]wd=x.T.dot(x.dot(w)+b-y)/x.shape[0]bd=np.sum(x*w+b-y)/x.shape[0]returnwd,bd#线性回归模型deflinearRegression(x_train,x_test,y_train,y_test,delta,num_iters):w=np.zeros(x.shape[1])#初始化w参数b=0#初始化b参数trainCost=np.zeros(num_iters)#初始化训练setThelossonvalidateCost=np.zeros(num_iters)#初始化验证集上的损失foriinrange(num_iters):#开始迭代trainCost[i]=lossFunction(x_train,y_train,w,b)#计算训练setlossvalidateCost[i]=lossFunction(x_test,y_test,w,b)#计算测试集上的lossGw,Gb=derivation(x_train,y_train,w,b);#计算训练集上的导数Dw=-Gw#Slope>0往负方向走,所以需要加负号Db=-Gb#同上w=w+delta*Dw#更新参数wb=b+delta*Db#更新parameterbreturntrainCost,validateCost,w,b多层感知机我们刚才说的线性模型其实就是一个单层网络,它包含了机器学习的基本要素,模型,训练数据,损失函数和优化算法,但是受限通过线性运算,无法解决更复杂的问题。我们需要更通用的模型来适应不同的数据。喜欢添加额外的层?加一层的效果大约相当于变换坐标轴,可以做更复杂的问题。但它仍然是一个线性模型,没有办法解决非线性问题。比如下图中,用直线是没办法隔开的,但是用y=x2这样的二元一次方程就可以轻松搞定。这就是非线性的好处。加入非线性结构也引入了神经网络中的另一个基本概念,激活函数(ActivationFunction)。常见的激活函数如下:Relu函数只保留正元素,清除负元素。值在0和1之间变换,tanh函数可以把元素的值在-1和1之间变换,用的最多的就是看似最简单的Relu。Relu函数就像人脑中的一个神经元。当它达到神经元的刺激阈值时,它输出,如果没有达到阈值,则设置为零。激活函数的选择应考虑输入、输出和数据的变化。例如,sigmoid通常用作输出层的激活函数。比如在做分类任务的时候,将结果映射到0~1,给每个预设的类别一个从0到1的预测概率值。可以理解为我们提供一个非线性函数,然后神经网络通过本身,使用我们提供的非线性元件,可以逼近任何非线性函数,因此它可以应用于许多非线性模型。添加激活函数后,我们就有了一个多层感知器。多层感知器是由至少一个隐藏层的全连接层组成的神经网络,每个隐藏层的输出都经过激活函数处理。转换。与上图类似,就形成了一个简单的多层感知网络,即深度神经网络。网络层级变复杂后,仍然采用梯度下降法进行迭代优化,但梯度的计算变得更加复杂。网络中的每一行都有一个w的权重参数,需要使用损失函数计算每个w的梯度。粗略估算一下,假设输入层有10个节点和两个隐藏层,每个隐藏层从输入层到隐藏层1再到隐藏层2有30000*3个参数,参数之间如果存在函数关系,最终输出损失对第一个隐藏层的w的推导需要逐层推导。计算量为++++++n。直接推导是绝对不可能的,所以我们需要反向传播算法(Backpropagation,bp算法)。反向传播算法反向传播算法用于快速计算多层网络中的梯度,其推导相对复杂。在使用框架的时候..直接调用API就好了,没有开发者调整的地方,大家应该..不想写代码计算偏导数..那么作为进阶内容,先挖个坑..下次补上..中途总结到现在我们应该对神经网络计算有了一个基本印象,回想起来,就是给一个多层网络结构模型,然后输入数据,不断求梯度更新参数的模型,不断降低模型预测的误差。使用梯度更新参数的速度由超参数学习率决定,用伪代码表示:foriiniterations:loss=预测值与真实值的差距d=lossderivativew=w-d*learning至此,我们已经知道了一个深度神经网络的基本结构和计算过程,可以看懂一些使用神经网络的简单代码。回去阅读Pytorch官方教程。结果demo里全是图像栗子,so...再看看什么是卷积神经网络。卷积神经网络在我们前面提到的网络模型中,相邻两个层之间的任意两个节点之间都存在连接,称为全连接网络(FullyConnectedLayer)。当我们使用深度网络模型处理图片时,可以使用图片中每个像素的rgb值作为输入。对于一张100*100的图片,网络的输入层有100*100*3个节点,即使只有一个隐藏层,从输入层到隐藏层也已经有30000*100个参数。如果多加几层或者换一张稍大一点的图片,参数量就会爆炸。图像需要处理的数据量太大,使用全连接网络计算成本太高,效率很低。直到卷积神经网络(CNN)的出现,才解决了图像处理的问题。让我们直接看一下卷积神经网络是什么样的。典型的卷积神经网络包括三部分:卷积层、池化层和全连接层。卷积层用来提取图像的特征,池化层用来减少参数,全连接层用来输出我们想要的结果。我们先来看卷积。输入一张图片,然后给一个卷积核(kernel,也叫滤镜filter)在图像上滑动filter,对对应的位置进行乘法求和,滑动后得到一个新的二维数组,这就是卷积运算,是的..这是一个如此简单的添加。如果加入卷积核,则运算完成后得到两个通道的数组。二维卷积层输出的二维数组可以看作是输入在空间维度(宽和高)上某一层级的表示,也称为特征图。节点的输入源区域称为它的感受野。比如featuremap中第一个节点3的输入域就是输入图像左上角的3*3区域。如果再对结果进行卷积,最终特征图中第一个节点17的感受野就变成了其输入节点感受野的并集,即图像左上角的4*4区域。我们可以使用更深的卷积神经网络,使特征图中单个元素的感受野更宽,从而在输入上捕获更大规模的特征。这其实是在模拟人类视觉的原理。当我们接收到一个视觉信号时,大脑皮层中的一些细胞会做初步的处理,找到边缘和方向,然后将其抽象出来,判断眼前物体的形状是圆的还是方的,进而判断是什么一个抽象对象。通过多层神经网络,下层神经元识别初级图像特征,若干个下层特征形成上层特征,最终得到最高抽象特征得到分类结果。了解了多层卷积是一个从局部抽象到全局抽象的识别过程,我们再回头看看卷积核本身。从函数的角度来看,卷积过程是将图像的每个位置进行线性变换,映射成一个新的值,逐层映射,整体形成一个复杂的函数的过程。从模板匹配的角度来看,卷积核定义了一定的模式,卷积运算就是计算每个位置与模式的相似度,或者说每个位置有多少个分量有这个模式,当前位置和模式越多模式相似,反应越强。例如,边缘检测算子用于卷积。sobel算子包含两组3*3的矩阵,分别是水平的和垂直的,与图像进行卷积。如果A代表原图,G(x)和G(y)分别代表水平和垂直边缘检测到的图像:sobel在x方向的边缘检测计算结果如下:看一些栗子直观的展示不同卷积核算子的效果,你觉得卷积的方法好不好?当然,我们可以直接找一些有趣的卷积核来使用,比如用卷积来检测图像边缘,也可以通过数据学习卷积核,让神经网络学习不同的算子。刚才在卷积计算的时候,每次滑动一个小格子,也就是stride步长为1。其实stride也可以加大,每次滑动2个小格子,也可以跳过这个值以扩大接受范围,或者为了保持输出数组的长宽与输入一致,可以在原图的边缘加上一圈padding。作为最基本的入门,这里就不展开了。回到我们的网络结构,我们可以看到两层神经元之间只有部分连接,连接越少代表参数越少。但这还不够。图片中的像素太多。即使我们只取局部特征,我们仍然需要很多参数,所以我们需要池化。池化层的作用其实就是对图像进行下采样和缩小。pooling的计算也很简单。它计算输出数据的固定大小窗口的元素,然后将它们输出。最大池化(MaxPooling)是取池化窗口内元素的最大值,而平均池化是取输入窗口元素的平均值。除了下采样和减小图片尺寸外,池化还可以缓解卷积层对位置的过度敏感,避免模型的过拟合。举个极端的例子,一张图片只有四个像素。如果某个位置像素是255,我们就判定它是某类item。如果我们输入训练集图片进行学习,每张图片左上角第一个像素是255,如果没有pooling,模型训练的结果是,当左上角第一个像素是255时,那么输出被判断为item。当我们用这个模型去预测右上角像素为255的图片时,模型会认为它不是物体,判断错误。而如果有pooling,无论哪里出现255,pooling后都会取255,判断为item。经过多个卷积层和池化层降维后,数据来到全连接层进行高级抽象特征分类。终于到这里,你应该已经介绍了了解Pytorch/Tensorflow官网入门教程所需要的大部分原理知识了。大家可以愉快的运行官网的图片分类例子,自己写网络。具体框架用法见下一篇《超基础的机器学习入门-实践篇》。最后的Deco智能代码项目是O2ConvexLabs在“前端智能”方向的探索。我们尝试从设计稿开始生成代码(DesignToCode)为切入点,对现有设计进行补充研发。完成,从而提高产学研效率。其中,大量的AI能力被用来实现对设计稿的分析识别。欢迎感兴趣的童鞋关注我们的账号“凹凸实验室”(知乎、掘金)。参考资料[](http://speech.ee.ntu.edu.tw/~...)[](https://www.jiqizhixin.com/ar...)[](https://www.cnblogs.com/shine...)[](https://www.jianshu.com/p/233...)[](https://zh.wikipedia.org/wiki...)[](https://medium.com/@pkqiang49...)[](http://cs231n.stanford.edu/)欢迎来到傲途实验室博客:aotu.io或傲途实验室公众号(AOTULabs),推送文章来自不时。