问题

有没有必要把机器学习算法自己实现一遍?

回答
是否有必要将机器学习算法自己实现一遍?这是一个在机器学习学习者和实践者中非常常见的问题,而且答案并不是简单的“是”或“否”,而是取决于 你的目标、你的学习阶段、以及你想达到的深度。

下面我将从不同的角度详细阐述这个问题:

1. 有必要,但不是所有人都需要,也不是所有算法都需要

将机器学习算法自己实现一遍,可以极大地加深你对算法原理、数学基础和代码实现的理解。然而,这并不是一个绝对的要求,也不是所有算法都值得你花时间去从头实现。

谁应该考虑自己实现?

初学者,希望打下坚实基础的: 如果你刚开始接触机器学习,并且想真正理解算法是如何工作的,而不是仅仅停留在调用库函数层面,那么从零开始实现一些基础算法(如线性回归、逻辑回归、梯度下降、KMeans、决策树)是非常有益的。
想要深入理解算法细节的: 你可能在使用某个算法时遇到了瓶颈,或者想知道它在不同场景下的表现差异,那么自己实现可以帮助你“解剖”算法,理解其内部运作机制。
需要优化或定制算法的开发者: 如果你需要对现有算法进行修改、组合,或者针对特定硬件(如嵌入式设备)进行性能优化,那么自己实现是不可避免的。
对算法原理充满好奇的研究者: 很多理论上的突破来自于对现有算法的深入理解和创新性实现。
教育者或技术布道者: 为了更好地教授他人,自己实现并能清晰解释算法的实现过程是必不可少的。

哪些算法更值得自己实现?

基础算法: 如上所述,线性回归、逻辑回归、SVM(线性SVM)、KMeans、K近邻(KNN)、决策树、朴素贝叶斯等。这些算法的数学原理相对清晰,代码量也适中,是很好的入门实现项目。
经典但可能被隐藏细节的算法: 例如,一些优化算法(如SGD、Adam的变种)、集成学习方法(如Bagging、Boosting的简单实现)。
如果你要学习的是理论而不是应用: 如果你的目标是成为一名算法工程师、研究员,那么理解并实现算法的核心思想是关键。

哪些算法不一定需要自己实现?

复杂的深度学习模型: 如Transformer、GANs、BERT等。这些模型的结构复杂,涉及大量矩阵运算、并行计算、GPU优化等,从头实现一个完整、高效的模型不仅耗时巨大,而且需要非常深厚的编程和工程功底。通常情况下,我们会利用成熟的深度学习框架(TensorFlow, PyTorch, Keras)来实现这些模型。
需要高度优化的库函数: 很多数学库(如NumPy, SciPy)提供了高度优化的线性代数、优化等函数。如果你只需要利用这些底层能力,而不是理解其实现细节,直接调用即可。
在特定领域已经非常成熟且有标准库的算法: 例如,一些信号处理、图像处理库中的特定算法。

2. 为什么“自己实现”如此重要?(详细阐述)

自己实现机器学习算法,就像学习一门语言时,不仅仅是记住单词和语法,更重要的是尝试用这门语言去写作和表达。以下是更详细的理由:

2.1 深入理解算法原理

“黑箱”的破碎: 当你使用像scikitlearn这样的库时,算法就像一个“黑箱”。你输入数据,它输出结果。但自己实现的过程会让你打开这个黑箱,看到里面的齿轮和逻辑。
数学概念的具象化: 机器学习的核心是数学。例如,梯度下降的每一步更新,损失函数的计算,矩阵乘法在神经网络中的作用,协方差矩阵的意义等等,都需要你在代码中一步步地实现。这使得抽象的数学概念变得具体可感。
理解算法的假设和局限性: 在实现过程中,你会遇到各种假设,比如线性回归的线性假设,KNN的距离度量假设。你也会发现算法在某些情况下的局限性,例如过拟合、欠拟合、对异常值的敏感性等。这些理解是构建直觉和应用经验的基础。
权衡与选择: 不同的算法有不同的优缺点和适用场景。自己实现可以帮助你理解这些权衡:为什么需要正则化?L1和L2正则化有什么区别?梯度下降为什么需要学习率?不同学习率的影响是什么?

2.2 培养严谨的编程和工程能力

数据预处理的必要性: 你会发现数据预处理(特征缩放、缺失值处理、编码等)是多么重要,因为很多算法对输入数据的格式和范围非常敏感。
数值稳定性: 在实现过程中,你可能会遇到数值不稳定的问题(例如除以零、浮点数精度问题),这会促使你学习如何处理这些问题,编写更健壮的代码。
效率与优化: 你会开始思考如何提高代码的效率,例如避免不必要的计算、使用更高效的数据结构、利用NumPy等库进行向量化操作,甚至在某些情况下考虑并行计算。这为后续学习更高级的优化技巧打下基础。
调试与测试: 自己实现意味着你需要自己找出代码中的bug。这个过程极大地锻炼了你的逻辑思维能力和调试能力。你也会开始学习如何为你的模型编写测试用例。

2.3 构建机器学习的“工具箱”和直觉

建立核心概念的模块化思维: 你会把算法分解成不同的模块:数据加载、特征工程、模型训练、预测、评估。这种模块化的思维方式非常重要,有助于你理解和构建更复杂的系统。
形成解决问题的直觉: 当你遇到一个新问题时,你不再只是茫然地搜索某个库函数,而是能根据问题的特点,联想到自己实现过的类似算法,从而选择或调整合适的模型。
理解模型参数的意义: 例如,在逻辑回归中,权重参数的符号和大小往往能提供关于特征重要性的直观信息。自己实现才能更深刻地体会这一点。

2.4 为更高级的学习和研究打下基础

理解框架内部工作原理: 即使你最终会使用深度学习框架,但如果你自己实现过神经网络的前向传播和反向传播,你就能更好地理解框架是如何自动计算梯度的(自动微分)。
进行算法创新和改进: 如果你想提出新的算法或改进现有算法,必须从理解核心原理开始。自己实现是迈向这一步的必经之路。
阅读和理解研究论文: 许多研究论文会详细描述算法的实现细节和推导过程。如果你没有亲手实现过,很多推导和细节可能难以消化。

3. 如何有策略地进行“自己实现”?

并非所有算法都需要从头开始写每一个数学公式。以下是一些策略和建议:

3.1 从基础算法开始,逐步深入

线性回归/逻辑回归: 使用NumPy从零实现,理解梯度下降的整个过程。
KMeans: 实现聚类中心更新和样本分配的逻辑。
KNN: 实现距离计算和最近邻查找。
决策树: 实现信息增益或基尼系数的计算,以及节点分裂的逻辑。
SVM(线性): 实现支持向量机的决策边界和惩罚项。
朴素贝叶斯: 实现概率计算和条件独立性假设。

3.2 利用基础库,专注于算法逻辑

使用NumPy/SciPy进行矩阵运算和优化: 对于大部分算法,底层的矩阵运算都可以交给NumPy。你的重点在于实现算法的逻辑,如数据点分配、梯度更新公式等。
不刻意去优化底层数学运算: 例如,在实现梯度下降时,你不需要自己写矩阵乘法的汇编代码,而是调用`np.dot()`。

3.3 理解框架的组件,而非整个框架

深度学习框架: 如果你想理解深度学习,可以尝试用NumPy手动实现一个简单的多层感知机(MLP),包括前向传播、损失函数、反向传播(手动计算梯度)和权重更新。这会让你对神经网络的工作原理有深刻的认识。之后,再学习PyTorch或TensorFlow,你会发现很多概念是相通的,只是实现方式更高效、更自动化。
数据处理和评估: 你可以尝试手动实现一些数据预处理(如标准化、归一化)和模型评估指标(如准确率、精确率、召回率、F1分数)。

3.4 循序渐进,结合对比

先理解理论: 阅读教材、博客或论文,理解算法的数学原理。
先尝试使用库: 使用成熟的库(如scikitlearn)跑通一个例子,了解输入输出。
再尝试自己实现: 基于理论和库的经验,尝试自己实现。
对比结果: 将自己的实现结果与库函数的结果进行对比,检查是否有错误。

3.5 保持耐心和好奇心

自己实现算法是一个需要耐心和毅力的过程。遇到困难是正常的,关键在于坚持下去,并从中学到东西。保持对技术的好奇心,不断探索和学习,你会发现其中的乐趣。

结论

总而言之,是否需要将机器学习算法自己实现一遍,取决于你的学习目标和阶段。

对于初学者和渴望深入理解的人来说,强烈建议从基础算法开始,亲手实现。 这会为你打下坚实的理论和工程基础,培养宝贵的直觉和解决问题的能力。
对于需要快速应用或处理复杂模型的人来说,过度投入时间和精力去从零实现所有算法可能不是最高效的方式。 可以优先利用成熟的库和框架,同时有选择性地对关键或不熟悉的算法进行深入理解和实现。

最好的方法是找到一个平衡点: 理解核心算法的原理,并能对其关键部分进行实现和解释,同时善于利用成熟的工具来提高效率和解决实际问题。自己实现的过程不是为了“造轮子”,而是为了更好地理解“轮子”的原理,甚至在某些场景下,能自己“造出”更适合自己需求的“轮子”。

网友意见

user avatar

哈哈哈哈,我觉得很多人都有这个疑问吧。机器学习好高大上,多么牛逼的东西,光是看公式就已经眼花缭乱了,总觉得自己该全部去实现一遍,有的时候太懒,有的时候觉得能力不够。道理虽然明白——任何事情自己亲手做一做还是更好的,但机器学习已经有了大量的库了,SVM-Light,R里面的glm()方程,自己实现一遍,最后又不敢用(因为不知道算法究竟是否正确),或者不能用(一是速度赶不上大神写的库那么快,二是精度没有专业库那么高),耗时耗力的写了一堆后究竟有什么用?

这里很多答案都提供了一些解释,但我想从另一个角度来聊聊这个问题。

我在1年半前(本科阶段)就开始接触计算心理学和机器学习方面的研究,在NAACL(自然语言处理排名第三的论坛)上发表了一篇文章,用的计算机教授写的算法库,跑的是经过AdaGrad优化的向量支持机(SVM)算法。在这种论坛发文章,你是必须去做海报展示的,站在自己的大幅海报面前傻傻的待4个小时,我的两位教授(一位是认知语言学教授,一位是计算机教授)都在那里。我的位置不太好,在最边缘的角落里,本来以为就可以赢得一份清净,Philip Resnik走了过来。直到那一刹那之前,我一直不知道他是谁。但经过教授介绍后,他是马里兰大学的机器学习和自然语言处理教授,在这个领域混了多年,在Google Schoar上的论文引用数高达12,853。



他走过来的第一句话是:“假设我一点也不懂数学,告诉我你这篇论文做的是什么。”我解释后,看到我的计算机教授走了过来和Resnik聊天,Resnik问我的教授:“你用的是不是hinge loss(辛基损失函数)?”我的教授说:“是。但不是全局优化,所以我没有叫这玩意SVM……”(我凭回忆打出来的,可能不完全精确)。当时我站在一旁觉得这他们能这样大聊特聊数学,甚至是向量支持机(我当时认为这是最厉害的算法——除神经网络以外),简直是太厉害了,我一点也听不懂他们在讲什么。

直到现在,我才明白所谓的“辛基损失函数(Hinge loss)”其实就是Max(a,b)函数,就是比较 a 和 b 谁大谁小,然后选大的那个。这玩意究竟有什么难理解的?为什么要那么高大上?你让一个五岁的小孩,问他:“有一堆红球,一堆绿球,哪一堆的球更多啊?”这个小孩都能告诉你正确答案。

当然这说的有点偏题了。后来我非常幸运的考上了研究生,才终于开始了对“高档”算法的学习。第一个学期被Christopher Manning(克里斯多夫·曼宁)的CS224N自然语言处理虐了一番,这个学期开始上Andrej Karpathy(安杰·卡帕西)的神经网络(CS231N),该君是李菲菲教授(音译,Fei-Fei Li)的爱徒,在推特上有14.9K关注者,我越看他那张方块脸,越觉得他长得像贾斯丁·汀布莱克(Justin Timberlake)。这里有篇他的新闻报道:

Karpathy打败了Google的超级人工智能,但也许再没有下次了



我其实也是自控能力很差的人,在上安杰·卡帕西的课之前,也从没有萌生过自己去写机器学习算法的想法。原因在文章开头有提过:1. 我的代码运行速度肯定赶不上经过多次迭代的专业库的运行速度;2. 我咋知道我的代码写的就是对的呢??

我直到现在都这样认为:不考虑对方的环境和条件,知识与技能,就一味要求对方把机器学习算法都实现一遍,估计是最无理取闹的行为了吧。前天晚上,我跟另一个研究生Jason Freeman(杰森·弗里曼)聊天,他在微软的西雅图总部工作了4年,在目前越来越有名的TypeScript团队工作了3年(TypeScript是静态的JavaScript语言,正在国内和国外开始流行)——他告诉我他和安德斯·海尔斯伯格(Anders Hejlsberg)一起工作,他还经常顶撞安德斯。我的第一反应是:“他是谁……”(安德斯·海尔斯伯格是Delphi和C#之父,但我不熟悉这两门语言,所以不会崇拜他——小广告:Scala是我目前最喜欢的语言)。

我和杰森讨论的是3月份开始究竟要不要选吴恩达(Andrew Ng)的机器学习课(CS229)。我持的立场是我可能不打算上那门课,因为我已经看过大部分他的视频了,还读了他讲义的一部分(这里是讲义链接:

CS 229: Machine Learning (Course handouts)

)。因为我已经确定以后要做神经网络方面的研究,所以觉得他课上的一些其他内容比如特征降维(PCA),对我而言用处不大,我只需要会用就行了。我不仅用过特征降维,还用过更好的降维可视化(tSNE算法)。这玩意和我的领域不搭,为什么我要浪费时间去学?

杰森的论点是,如果我学了它们的理论(甚至把它们实现一遍),就能更好的应用它们。我说:你把直觉(intuition)当什么了?在我看来,对算法进行“直观”上的了解,就已经很足够了。什么是向量支持机?就是拿一个平面去分隔一堆点。更术语一点的解释不外乎是拿一个超平面(Hyperplane)在高维空间里去分割。什么是特征降维?就是看如何把高维度的点阵降到两三个维度。什么是alpha值?就是看这个算法学得有多快。什么是正则化(regularization)?就是别让你的算法过度拟合数据(当然L1,L2等等都有区别,但这些区别都很简单,L1让你关注某个值,L2让你利用所有的值)。

为什么我谈这么多关于理论的问题?在我看来,学习机器学习的算法的进度是这样的:应用 -》理论 -》实现。就跟教小孩折射一样,你先让他看看筷子在水中如何弯折(应用),再告诉他光的折射原因(理论),再让他自己用其他物体来试试(实现)。实现,是这个漫长学习过程的最后一步。一开始就来谈实现,实在是很神奇的事情。

让我准确论述一下我的观点:如果你是学界精英,那么去学习那些你将要使用的算法的理论,最后再自己尝试着实现他们,是很有必要的,除非你是只做应用(比如社会科学,心理学,商学等等)。如果是普通的程序员/工程师,不需要强迫自己去实现这些算法。没人会给你一个小奖章,大公司招这类员工的时候,也是更看重学历,而不是看“哦,我把‘所有’的机器学习算法都实现了一遍”。

最后送上一点我觉得实现机器学习算法最好的路径:

最好用Python和Numpy库。这两样宝具会让你非常轻松。安杰·卡帕西(Andrej)推荐用ipython notebook(现在改名叫Jupyter了),来可视化数据,以及实验算法。昨天有一个下午茶会,我们系举办的,也邀请了安杰,我跑去凑热闹,跟安杰谈到了这个问题,他说就算是大公司做研究,也是这种路径,先从ipython notebook开始(这点让我很惊讶)。

机器学习算法最难的部分其实不是写出来,而是高效率的实现,让你的算法跑快一点。其中一个技巧叫做“矢量化”(Vectorization)。矢量化就是说,能做矩阵操作就矩阵操作,最好连一个外循环都不写。

这是我写的Softmax算法的测评:(在500个样本上跑的)

       naive loss: 2.384533e+00 computed in 0.255952s vectorized loss: 2.384533e+00 computed in 0.004148s      

第一个是用普通的Python和循环写出来的,第二个是用矢量化操作写出来的,可以看到64倍速度的提升——侧面也可以看到Python有多垃圾(慢)。

这个是SVM(支持向量机)算法的测评:(同样500个样本)

       Naive loss: 9.102322e+00 computed in 0.136226s Vectorized loss: 9.102322e+00 computed in 0.005909s      

这次的速度提升没有那么明显,但也是26倍的提速。

但我只想说:矢量化真是很难的事情。数学家随便就写公式,也不考虑考虑可怜的计算机科学孩子们。原初的公式几十分钟就搞定,矢量化要一两个小时的冥思苦想。

最后,对于那些读懂了理论,实在是闲得无聊,或者想要进军更高级的学术界的同志们,这里是安杰·卡帕西课代码的链接:

CS231n Convolutional Neural Networks for Visual Recognition

。如果你不属于这个类别,就不要瞎掺合啦,用用别人的库又怎么了?骇客精神(Hacker Code)中一条就是:“不要重复劳动,有库就要用库,不然就是对库写作者的不尊重。”

(如果你还是不知道究竟该不该实现,欢迎阅读下面我增加的内容)

------------------

最近这篇文章被学姐前辈Danqi Chen看到了。。所以我稍微补充几句,免得被大牛们看到后笑话。。- ___ - || Danqi前辈是清华姚班的高材生,Chris Manning的博士,在224N课上是首席助教,然后被我缠着问了好多次问题……

这篇文章有点接近“反智”文章的边缘,大意是实用主义至上,自己实现的必要性不大。这个观点还是有很多争议的,比如目前有一个答案就“实名”反对这个答案。机器学习是一个交叉学科,作为学生而言,从不同的部门学到的机器学习,必然是不一样的。在统计学部门学到的机器学习,和在计算机部门学的机器学习,肯定是两个样。我秋天的时候跟一位概率教授上了一节课,当我告诉他斯坦福计算机入门概率课要介绍MLE(最大拟然估值)和蒙特拉罗模拟(Monte Carlo Simulation)的时候,他沉重的摇摇头,说这么早就介绍这样深刻的概念,是很不应该的,在他的部门,要第三年的学生才接触这样的知识,因为直到那时,学生才有足够的知识框架去理解这些知识。

我写这篇文章是有一定的原因的。我认识一些国内的大学同学,都异常优秀,他们努力的程度是我一辈子都比不上的,他们中一部分人因为运气不好(高考),不幸去了一些相对不是那么优异的大学,但是他们用努力弥补这个缺陷,对数学和各种学科展开攻克,很多人的阅读量和数学解题技巧也是我不能企及的。还有一部分人,是处于业界转型边缘,本来已是成熟的程序员,或者数据分析师,但是想要进一步提升自己,亦或是转型。我把这两类人定做这篇回答的目标受众。我希望为他们写一篇回答,不让他们走我走过的弯路,不受太多的误导。

开复先生(李开复)最近说深度学习急缺人才。我非常的不赞同。深度学习领域是处于半饱和状态的,实际上就业情况就是一堆熠熠生辉(Scintillating)的博士们在学术界待腻了,想要去赚点钱玩玩,就跑去业界晃一圈的状况。这和大部分人的就业状况根本是不搭边的。深度学习,以及理论机器学习,除非是平台很高,起点很高,是很难得到广泛认可的。

我最近刚买了一本书:


这本书很详细的在讲Lasso Loss(L1),写SVM的部分也非常不错,很神奇的是,三位作者,两位是斯坦福统计学系的,一位是伯克利的。如果我能读完这本书,会上来改进一下这个答案的。

最近我想提一提答案末尾写的,关于“实现”的问题。我过去几周一直在写我自己的Theano库(是的,放着牛逼的Lasagne不用,非要自己手写),终于把CNN写完后,现在在写RNN的部分。当我已经花费这么多的时间,然后意识到,我的代码暂时还只能在CPU上跑,因为我暂时还没有用Theano的CUDA库,又意识到,仅仅几周后,我的两门春季课已经开始教TensorFlow了,于是觉得自己是个傻子。

所以我自己都陷入了我回答中所写的那个陷阱:实现之后却不能使用,但又不愿意放弃自己的代码,于是只有投入更多的时间去改代码,而不是去理解数学。愿与各位共勉。

-------------------

user avatar

底下的回答简直是个个抛github啊,我也上一个

首先说结论:非常有必要

我记得很清楚在我刚上研究生时问老师机器学习怎么能算学到位。当时老师回我:学机器学习很容易,但是你要学会改造。

咱们知道感知机是划分超平面,SVM有个核函数,隐马是状态链观测链。这些都看过了,全会了。

但是当你开始写代码了才发现,原来还是不会,很多推导上不占地方的细节没注意真写不下去。最主要的是写的过程中你会有新的理解,真正明白了它的工作原理。

当你以后发现用某某模型性能不够好时,能一下子想到是程序哪块地方可能有问题,怎么改。这是很重要的。


最后推销一下我的github,每行代码都带注释,里面还有我写的配套博客链接。我希望机器学习的入门难度不会阻碍每一个初学者。


我对象都能看懂,确定不来看看吗?

user avatar

我想这个题目我还是比较有发言权的,读书时候曾经把PRML所有算法实现过一遍。最后发布了一个库,现在是Github上星星最多的Matlab库之一(应该是排第二)。读PRML的同学可以参考一下,代码注释给出了重要部分对应的公式在PRML的出处。变量命名也尽量与书做了统一。希望对学习PRML的同学有所帮助。大家觉得有用请帮忙点星星。

GitHub - PRML/PRMLT: Pattern Recognition and Machine Learning Toolbox

这个经历对我的帮助大概有以下几个方面:
1) 对算法细节的理解更加深刻了。书中毕竟不会给出所有细节,而且书本身可能就是错的。为了写出代码,我几乎是把所有公式重新推了一遍,自己存下的note里面公式数量绝对远远多于书本身,期间也发现了书中无数的错误,这些错误在初读的时候根本意识不到。这样一遍下来,让我对推公式的信心大增,看论文不会怕看不懂公式了。遇到看不懂的就推一遍,推不出的就抄一遍,之后总会懂的。一个side effect就是让我变得愤青了,看什么paper都觉得烂。因为读paper的时候,你会发现,很多paper违背基本常识,即使影响力非常大的一些paper里也有这样那样的错误。
2) 可以了解很多看书学不到的各种trick。所有算法几乎都有坑。比如hyper-parameter什么意义怎么设,怎么初始化,numerical stability的怎么保证,如何保证矩阵正定,计算机rounding error的影响,numerical underflow和overflow问题等等。
3) 对整个领域各个算法的关联有更深刻的了解,思维形成一个关系网。看到一个算法就会自然的去想跟其他算法的联系,怎么去扩展。如果一篇paper我不能把它纳入到这个关系网里,我就觉得自己没懂。要么推出联系,要么推出矛盾证明这篇paper垃圾。另一个side effect就是我看paper从来不根据实验好坏判断优劣。
虽然自己动手实现算法有好处,但是性价比几何还是个见仁见智的问题,毕竟这是一个很费时的过程。我并不认为一定有必要自己实现书上所有算法,毕竟每个人所能关注的领域还是有限的,懂得算法大致原理,具体用的时候在细研究就可以。很多算法我也是写完了从来没用过。几年过去后,我在回头看自己的代码也很难看的懂,细节还得看公式。

但是对于自己的研究领域我建议还是有必要把经典算法动手实现一遍加深理解。

类似的话题

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有