乐于分享
好东西不私藏

AI slop一则:Python的“史前史”

AI slop一则:Python的“史前史”

Salicylic:

之前的那篇AI slop一则:谁在决定我用什么代码工作?不够切题,因此这次是问了更细分的问题的报告。和过去的报告一样,AI还是有那种“本科时写课程论文,决定写综述,结果每个领域只能一笔带过”的感觉。

Python潜伏在其他语言中的史前史:从“胶水语言”到深度学习通用语的黎明时刻

引言:解构“深度学习造就Python”的历史迷思

在当代计算科学与工业界的广泛认知中,存在一种极具误导性的历史简化论:即Python编程语言之所以能够成为现代科学计算与人工智能领域的绝对首选,完全是因为2010年代深度学习(Deep Learning)框架(如TensorFlow和PyTorch)的爆炸性普及。这种观点认为,是一群机器学习研究者在偶然间选中了一门通用脚本语言,从而将其推上了神坛。然而,这种认知彻底抹杀了Python在科学计算领域长达二十年的“史前史”,忽略了一个至关重要的事实:深度学习的爆发并没有“创造”Python的科学计算生态,相反,深度学习之所以能在Python中爆发,是因为几代跨学科科学家早已在该语言内部极其耐心地构建了庞大、坚固且高度优化的底层基础设施。

要真正理解Python如何在人工智能时代加冕,就必须将目光投向更早的岁月,审视其在Fortran、C/C++以及MATLAB等老牌霸主的夹缝中潜伏与生长的过程。这是一段由社区驱动的基础设施建设史,涉及底层内存布局标准的制定、多维数组结构的统一、将高级动态脚本与传统编译语言紧密缝合的“胶水”技术,以及由此引发的科学家在认知模型上的深刻范式转移。本报告将详尽追溯自1991年Python问世起,直至2012年深度学习黎明时刻的科学计算演进历程。通过具体对比上世纪90年代中期与本世纪初非计算机科学实验室的工作流,本研究将深刻剖析科学家对“科学计算”认知的根本性转变。最后,本报告将从语言设计哲学、硬件架构适配以及生态路径依赖等多个维度,详细论证Python随着深度学习爆火的必然性,并解答为何Ruby、Haskell、Lisp等少数派语言在这一历史进程中彻底出局。

早期科学计算的“寒武纪”:底层性能与高层交互的割裂

在上世纪90年代初及中期,科学计算的生态呈现出极其严重的两极分化现象。这是一种被“双语言难题”(Two-Language Problem)所困扰的时代,科学家必须在执行性能与开发效率之间做出痛苦的妥协。

在光谱的一端,是负责提供极致算力的底层编译语言,主要以Fortran和C/C++为代表。早在1957年由IBM的John Backus开发的Fortran(公式翻译器),由于其对多维数组和复杂数学运算的原生支持,长期垄断着超级计算机、流体力学、量子物理及天气预报等重度计算领域。然而,Fortran和C的开发体验对非计算机专业的领域科学家极不友好。这些语言的设计初衷是优化机器执行速度,而非提升人类的编程效率。例如,在早期的Fortran 77中,由于缺乏动态内存分配功能(直到Fortran 90才被引入),科学家在编写程序时必须在代码中硬编码(Hardcode)数组的最大预期尺寸。这种僵化的内存管理不仅经常导致内存溢出错误,还极大地增加了代码的维护成本。每一次参数的微调都意味着重新经历漫长的编译过程,试错成本极其高昂。

在光谱的另一端,是提供高层交互的专有领域特定语言(DSL)和商业软件生态,如MATLAB、IDL,以及主要用于统计分析的SAS、SPSS和Stata。例如,MATLAB最初在上世纪80年代作为LINPACK和EISPACK线性代数库的交互式外壳被开发出来,它极大地降低了矩阵运算的门槛,并内置了丰富的绘图功能。然而,这些商业工具虽然提升了开发效率,却伴随着高昂的软件授权许可费用,严重阻碍了跨国界、跨机构的学术合作与代码共享。此外,作为闭源的“带墙花园”,科学家很难将MATLAB或Stata的代码与外部操作系统、网络协议或实验室自行开发的特定硬件驱动程序进行深度整合。

在这个充满摩擦的生态中,科学家为了将不同工具连接起来,通常需要使用Perl或Unix Shell等脚本语言作为“粘合剂”。但这些脚本语言在处理复杂的数据结构或大规模矩阵时显得力不从心。科学界迫切需要一种既能提供交互式、高生产力开发体验,又能无缝调用底层C/Fortran极致算力的现代编程语言。

上世纪90年代中期非计算机科学实验室的典型一日:批处理与高延迟的认知模型

为了生动描绘当时科学计算生态的局限性,我们可以还原上世纪90年代中期(约1995年),一位典型实验物理学家或生物学家在非计算机科学实验室中的典型一日。

在这个时期,实验室的计算工作流被切割成多个互相独立、物理隔离的孤岛。早晨9点,研究人员抵达实验室,第一项任务通常是启动硬件设备(如激光器或质谱仪),并进行物理对齐和预热。数据采集通常由专门的商用软件(如LabVIEW)控制,这一过程往往需要数小时甚至过夜才能完成,仪器最终会吐出包含原始观测数据的巨大扁平文本文件(Flat Text Files)。

下午,数据分析阶段开始。这时的科学家面对的是一个极其僵硬的“批处理”(Batch Processing)工作流。首先,研究员需要打开文本编辑器(如vi或Emacs),修改遗留的Fortran 77或C语言代码,以适配新的实验参数。接着,在命令行中调用编译器(如f77gcc)生成可执行文件。由于语言层面的非交互性,一旦出现语法错误,科学家只能回到编辑器重新修改并再次编译。编译成功后,可执行文件作为黑盒被抛给操作系统去处理那些庞大的文本数据,科学家只能被动等待程序的运行结束。

由于Fortran和C语言极度缺乏原生的二维或三维数据可视化能力,计算与可视化在物理上和逻辑上是完全分离的。计算结束后,程序会输出另一批包含计算结果的纯文本文件。此时,研究员必须编写一段Perl脚本或Awk命令,利用正则表达式将特定的数值列提取出来,并重新格式化为特定绘图软件所需的输入格式。最后,研究员打开诸如GNUplot、Tecplot或OriginLab等专有桌面绘图软件,通过图形用户界面(GUI)手动导入数据,设置坐标轴和图例,最终生成一张图表。如果图表显示某个实验参数设置错误,或者理论模型存在缺陷,科学家必须从头来过:重新修改Fortran代码,重新编译,重新运行批处理,重新执行Perl脚本,重新导入绘图软件。

90年代对科学计算的认知模式

在上述工作流中,科学家对“科学计算”的认知呈现出以下三个核心特征:

  1. 计算机作为“黑盒预言机”(The Computer as an Oracle):科学家与计算机之间不存在连续的对话。交互模式是高度离散和高延迟的——提交一个批处理任务,然后被动等待答案。这种模式扼杀了快速试错与即兴探索的可能。
  2. “数据清洁工”的认知重负(The Data Janitor Burden):领域科学家将大量最宝贵的智力资源消耗在了与科学研究毫不相干的底层技术细节上:如手动分配内存、编写复杂的文本解析器来转换文件格式、处理不同操作系统间的兼容性问题。正如一位早期计算科学家所反思的,“科学家的工作大部分被计算的技术细节所主导,而非科学本身”。
  3. 计算目标的狭隘性:在这个时期,科学计算主要被视为一种“数值碾压机”(Number Cruncher),用于求解那些已经明确定义好的、解析解无法处理的偏微分方程或物理模拟。科学家尚未形成“数据驱动探索”(Data-Driven Exploration)的概念,计算仅仅是验证已知物理公式的苦力。

Python的渗透与“胶水语言”的黎明 (1995-2000)

在这样的时代背景下,由荷兰国家数学与计算机科学研究中心(CWI)的Guido van Rossum于1991年首次发布的Python语言,开始悄然潜入科学实验室。Python最初的设计目标是作为ABC语言的继任者,旨在为非专业程序员提供一种易于教学、语法极其清晰的工具。Python强制使用缩进来划分代码块,摒弃了C语言中繁琐的大括号,使其代码读起来就像是可执行的伪代码(Executable Pseudo-code)。

尽管Python最初完全没有为数值计算进行任何特殊设计,但它的几个底层特性精确击中了90年代科学家的痛点:它是一种跨平台、面向对象、具有自动垃圾回收机制的高级动态语言,最重要的是,它被设计为可以极其轻易地使用C语言进行扩展。

这一特性催生了Python在科学计算早期的核心定位:胶水语言(Glue Language)。科学家们敏锐地意识到,他们实际上不需要用Python来执行那些耗时的矩阵乘法,他们只需要用Python来“黏合”并“指挥”底层那些已经存在了几十年的、经过高度优化的Fortran和C语言数学库(如LAPACK和BLAS)。

在90年代中后期,一系列革命性的“胶水”工具应运而生。1995年,洛斯阿拉莫斯国家实验室的理论物理部门的研究员David Beazley开发了SWIG(Simplified Wrapper and Interface Generator)。SWIG能够自动读取C/C++头文件,并生成所有的底层接口代码,使得Python脚本可以直接调用C函数。紧接着在1999年,来自爱沙尼亚的博士生Pearu Peterson发布了f2py项目。f2py是一个不仅能将Fortran代码包装为Python模块,还能自动处理两者之间数组内存布局差异的神奇工具。

借助SWIG和f2py,实验室中的科学家终于摆脱了编写底层C/Fortran包装器的痛苦。他们可以保留实验室继承下来的、运行极快的Fortran核心模拟代码,但在外层使用语法优雅、开发极快的Python来编写控制逻辑、参数解析和数据预处理脚本。这种“C/Fortran主内(负责算力),Python主外(负责逻辑与交互)”的架构,奠定了现代科学计算软件堆栈的基础,也是后来TensorFlow等深度学习框架底层架构的雏形。

阵列计算的“大分裂”与“大一统”:Numeric、Numarray与NumPy的诞生 (1995-2006)

尽管Python作为“胶水”表现优异,但原生Python的内置数据结构(如列表 list)在科学计算面前暴露出了致命的缺陷。Python的列表被设计为动态和异构的(即一个列表中可以同时包含整数、字符串和对象),在底层内存中,它们是指向散落内存各处对象的指针数组。当科学家试图在Python中对包含上百万个浮点数的列表进行逐元素的数学运算时,这种内存碎片化(Memory Fragmentation)导致的CPU缓存未命中(Cache Misses),使得运算速度慢如蜗牛,完全无法用于严肃的科学计算。

为了弥补这一短板,Python社区在1995年成立了一个专门的兴趣小组——matrix-sig(矩阵特别兴趣小组)。这个由物理学家、天文学家和工程师组成的小组,其核心目标是为Python设计一个标准的、底层基于C语言连续内存块的多维数组包。Python的创始人Guido van Rossum也积极参与了该小组,并亲自修改了Python的核心语法(特别是扩展了切片和索引的语法),以适应矩阵计算的需求。

matrix-sig的推动下,Jim Fulton和Jim Hugunin于1995年开发出了具有划时代意义的扩展包——Numeric。Numeric在底层使用紧凑的C语言内存结构来存储同构数据(如纯浮点数),并通过“矢量化”(Vectorization)操作彻底消除了缓慢的Python for循环。借此,Python第一次在科学数组处理上获得了接近C语言的运行速度。

然而,随着科学领域数据量的激增,特别是在天文学等需要处理庞大卫星图像的学科中,Numeric逐渐暴露出设计瓶颈。2001年,空间望远镜科学研究所(STScI)的Perry Greenfield及其团队在处理大型天文数据集时,发现Numeric的性能和灵活性无法满足需求。由于Numeric的C-API不易扩展,他们决定另起炉灶,开发了一个全新的数组处理库——Numarray。Numarray在大数组处理上极具优势,但在小数组运算上却比旧的Numeric慢得多。

这导致了科学Python社区长达数年的灾难性“大分裂”。第三方科学库的开发者被迫站队:一些库基于Numeric编写,另一些则基于Numarray编写,两者互不兼容。生态系统的碎片化使得许多科学家对Python失去了信心,甚至考虑彻底放弃Python转而寻找其他替代品。

直到2005年,一场“大一统”运动挽救了这一濒临崩溃的生态。当时还在学术界的Travis Oliphant意识到了社区分裂的严重性。他决定暂停自己的学术研究,将Numarray中的高级特性(如内存映射、高级切片、灵活的数据类型体系)强行移植并整合到运行迅速的Numeric底层核心中。2006年,这个集大成者的项目作为NumPy 1.0正式发布。NumPy的诞生不仅结束了长达五年的社区内战,还为多维数组(ndarray)提供了一个极其稳定、统一且高效的底层C-API接口标准。自此,所有试图在Python中进行数值操作的第三方库,都有了一个共同的基石。

科学计算生态的全面成型:SciPy与Matplotlib的崛起

伴随着底层数组数据结构的完善,高层算法库与可视化工具的建立同样不可或缺。在2001年前后,Travis Oliphant、Pearu Peterson和Eric Jones等人将他们各自编写的用于信号处理、常微分方程求解、线性代数和优化的零散模块整合在一起,创建了SciPy库。SciPy直接构建在Numeric(后来的NumPy)之上,为Python提供了一个功能可与MATLAB等商业软件匹敌的通用科学算法库。

与此同时,神经生物学家John D. Hunter在分析儿童癫痫的脑电波数据时,因为难以忍受MATLAB高昂的授权费用及其在数据处理上的局限性,决定用Python重写他的分析系统。然而,当时Python缺乏一个强大的2D绘图包。为了填补这一空白,Hunter在2002年开发了Matplotlib。Matplotlib最初的设计极其务实:它有意模仿了MATLAB的绘图命令接口(Pyplot API),使得那些习惯了MATLAB的科学家能够零学习成本地迁移到Python阵营。

到2000年代末期,由NumPy提供数据结构、SciPy提供算法支撑、Matplotlib负责数据可视化的“SciPy生态栈”(SciPy Stack)已全面成熟。这个开源的、免费的、高度可扩展的生态,彻底打破了由MATLAB等专有商业软件垄断的科学计算壁垒。

本世纪第一个十年末期非计算机科学实验室的典型一日:交互式探索与“计算叙事”

基础设施的成熟不仅带来了工具的更迭,更引发了科学家在工作模式上的根本性变革。让我们将目光转向2009年至2012年期间的非计算机科学实验室,观察此时的典型一日。

最显著的改变来自于交互环境的进化。此时,由Fernando Perez等人在2001年发起的IPython项目已经发展成熟,并在2011年演化为了革命性的IPython Notebook(即后来广为人知的Jupyter Notebook)。在这个时期,一位气候学家或量化金融分析师到达实验室后,不再需要打开终端去编写枯燥的批处理编译脚本。

他们会在浏览器中打开一个IPython Notebook。这是一种混合了可执行代码、Markdown格式的文本说明、LaTeX数学公式以及内联图表输出的富文本交互式环境。首先,面对包含数百万行异构数据(如包含缺失值、字符串和不规则时间戳的交易数据或气象传感器数据)的CSV文件,科学家不再需要使用Perl脚本进行清洗。他们导入了一个名为Pandas的新兴库。Pandas由AQR资本管理的量化分析师Wes McKinney于2008年创立,它将R语言中备受赞誉的data.frame结构引入了Python,并巧妙地利用NumPy的高速底层实现了极为高效的向量化操作。只需一行代码 df = pd.read_csv('data.csv'),庞大且脏乱的数据集就被加载为结构化的表格;再通过 df.dropna() 或 df.groupby(),曾需要数百行Fortran循环的“数据清洗”工作瞬间完成。

紧接着,科学家在一个单元格(Cell)中调用SciPy中的非线性优化模块对清理后的数据进行拟合。在下一个单元格中,利用Matplotlib进行绘制 plt.plot()。按下执行键后,拟合的彩色曲线图瞬间在浏览器中渲染出来,直接显示在代码的下方。如果科学家对拟合效果不满意,只需向上滚动页面,修改SciPy函数的参数,然后重新执行该单元格。反馈延迟从90年代的数小时缩短到了数百毫秒。

2000年代末对科学计算的认知转移

此时,科学家对“科学计算”的认知模式已经发生了深刻的范式转移:

  1. 计算机作为“交互式搭档”(The Computer as an Interactive Partner):通过REPL(读取-求值-输出循环)环境,科学计算不再是单向的黑盒批处理,而是演变成了科学家与数据之间无缝的、低延迟的连续对话。试错成本的断崖式下降,极大地激发了研究人员的好奇心。
  2. “计算叙事”的诞生(The Birth of Computational Narratives):Notebook环境使得代码不再是单纯的机器指令,而是变成了一篇包含科学推理逻辑的“故事”。数据导入、清洗机制、数学模型与最终的可视化结果被打包在同一个电子实验记录本(e-labbook)中,极大地促进了跨实验室的研究可重复性(Reproducibility)。
  3. 数据清洗的平民化(Democratization of Data Wrangling):由于Pandas等高层抽象工具的出现,科学家终于从底层内存指针和正则解析的繁文缛节中解放出来,得以将全部智力聚焦于领域内真正的科学与统计本质上。

两个时代的实验室工作流对比总结

维度 1990年代中期:批处理驱动的孤岛模式 2000年代末期:数据驱动的交互探索模式
核心计算语言
Fortran 77/90, C/C++
Python (底层封装了优化的C/Fortran库)
执行模型
“黑盒”批处理编译执行 (High-latency)
交互式REPL,单元格即时执行 (Low-latency)
数据清洗工具
Perl脚本、Unix Shell、Awk
Pandas DataFrames (向量化操作)
可视化模式
导出至独立的外部GUI软件(Origin, GNUplot)
经由Matplotlib在Notebook中直接内联渲染
认知定位
验证确立公式的“数值碾压机”
具备数据挖掘能力的“可执行叙事空间”

黎明时刻:深度学习爆发前的基础设施就位 (2007-2012)

正是上述高度成熟的科学计算基础设施,为之后人工智能和机器学习的爆发铺平了道路。在2012年AlexNet引发深度学习海啸之前,机器学习社区已经在Python内部悄然完成了核心工具链的构建。

在经典机器学习领域,David Cournapeau于2007年在Google Summer of Code项目中发起了scikit-learn。2010年,法国国家信息与自动化研究所(INRIA)的Gaël Varoquaux和Alexandre Gramfort等人接手该项目并发布了首个公共版本。Scikit-learn的绝妙之处在于它完全遵循Python科学计算的哲学:它原生建立在NumPy的数组和SciPy的矩阵架构之上,并设计了一套极其优雅统一的API(fitpredicttransform)。这意味着,科学家可以用Pandas清洗数据,直接喂给Scikit-learn进行支持向量机或随机森林的训练,整个过程水到渠成。

而在深度学习的拓荒期,最大的技术瓶颈在于训练神经网络时,计算复杂的反向传播梯度极其繁琐且极易出错。为了解决这个问题,由Yoshua Bengio领导的蒙特利尔学习算法研究所(MILA)于2007年发布了Theano框架。Theano是一个开创性的Python库,它允许研究人员使用类似NumPy的语法定义多维数组(张量)的数学表达式。更强大的是,Theano内置了符号微分(Symbolic Differentiation)引擎,能够自动计算复杂函数的梯度,并将这些计算图即时编译(JIT)为高效的C++或CUDA代码,在CPU或GPU上飞速运行。

Theano向学界证明了一点:Python的高级表达能力与GPU的极限硬件算力是可以完美结合的。这种在底层编译图结构、在表层提供Python化接口(Pythonic API)的设计架构,不仅让当时的深度学习从业者免去了手写CUDA底层的苦役,更为后来的TensorFlow等现代框架设定了标准的架构范式。

CUDA的降临与Python社区的敏锐捕获

当NVIDIA在2007年正式发布CUDA(统一计算设备架构)时,它并没有从一开始就提供Python接口。最初的CUDA完全是为C/C++程序员设计的,NVIDIA当时的假设是:追求极致性能的高性能计算必然属于底层的编译语言。然而,Python社区却以惊人的速度和极高的效率“捕获”了CUDA。早在2009年,研究员Andreas Klöckner就发布了第三方库PyCUDA,允许科学家在Python脚本中直接编写和编译CUDA内核代码。

为什么Python社区能够比Ruby、Haskell或Lisp等其他社区更快、更高效地采纳GPU计算?答案隐藏在Python此前十年的底层基础设施建设中。由于NumPy在底层完全采用C语言的连续内存块来存储多维数组,且Python引入了强大的“缓冲协议”(Buffer Protocol,PEP 3118)以实现底层内存的无复制共享,将庞大的NumPy矩阵直接传输到GPU的显存中变得极其自然且高效。

相比之下,其他“少数派语言”在对接CUDA时遭遇了底层架构上的严重阻力。Ruby的C-API深度依赖于通用的VALUE对象指针,导致在C语言扩展和Ruby之间转换数据时充满了封箱和拆箱的开销,难以实现对原生连续内存的直接映射。Haskell虽然有类似Accelerate这样的并行计算项目,但其强静态类型和纯函数式、不可变(Immutability)的设计哲学,与GPU底层高度状态化、就地修改(In-place Mutation)的并行内存操作模式产生了巨大的摩擦。而Lisp高度依赖的链表结构更是与GPU处理连续向量数据的硬件要求背道而驰。

NVIDIA最终注意到了Python社区这股不可阻挡的自下而上的洪流。他们意识到,要让机器学习和数据科学真正普及,就必须迎合科学家们最习惯的“胶水语言”。2011年,NVIDIA开源了基于LLVM的CUDA编译器底层代码,这直接促成了诸如Numba等JIT(即时编译)工具的诞生,使得纯Python函数可以直接编译为GPU机器码。到了2013年的GTC大会上,NVIDIA官方高调宣布了对Python的全面支持,并与Continuum Analytics(Anaconda背后的公司)合作推出了NumbaPro。这一历史性的转变,使得在深度学习框架大爆发前夜,Python已经完美具备了调度最先进硬件算力的能力。

当2012年多伦多大学的Alex Krizhevsky团队利用深度卷积神经网络在ImageNet图像识别大赛中以碾压性优势夺冠,正式宣告“深度学习时代”到来时,Python并没有手足无措。它已经在那片寂静中潜伏并武装了十几年:多维数据结构(NumPy)、数据处理管道(Pandas)、经典机器学习算法(Scikit-learn)以及硬件加速与自动求导平台(Theano、PyCUDA)已经全部就位。深度学习的洪流,只是顺理成章地涌入了一条早已由几代跨学科科学家为其开凿好的巨大河床。

结论:不可避免的加冕与少数派语言的败局

综上所述,Python随着深度学习的爆火而成为科学计算绝对首选,在极大程度上是一种历史的必然。这种必然性并非源于Python语言在运行时性能上的优越(事实上由于全局解释器锁GIL的存在,纯Python执行极慢),而是源于其生态系统长达二十年的深耕,以及其作为一种“高层人类接口”去黏合“底层极限算力”的无与伦比的设计定位。

当我们回顾为何爆火的深度学习框架(如PyTorch、TensorFlow)的初始贡献者和整个生态系统最终坚决地选择了Python,而不是在语法特性或学术上同样甚至更加出色的Ruby、Lisp或Haskell等少数派语言时,可以通过以下几个核心维度的历史对比得出明确答案:

1. 为什么不是Ruby?生态错位与面向对象哲学的束缚

Ruby与Python同样诞生于90年代中期(1995年),且同样具备动态、解释型和强调开发者幸福感的特性。然而,Ruby在2005年因Ruby on Rails框架的巨大成功,导致整个社区的智力资源和焦点历史性地向Web开发领域全面倾斜。当Python的开发者正埋头于解决多维数组操作(NumPy)和连接底层Fortran代码(f2py)时,Ruby社区正忙于革新互联网的MVC架构。

此外,Ruby坚守纯粹的面向对象编程(Pure OOP)理念,在Ruby中一切皆对象。这意味着在Ruby中调用一个变量的长度或总和,必须使用方法调用的形式(如 array.length 或 array.sum)。而科学和数学领域长久以来的书写习惯是基于函数式的操作(如数学符号  映射为 len(array) 或 sum(array)),Python支持多范式编程(尤其是允许强大的全局函数存在),这在心智模型上极大地契合了那些并非出身于计算机科班的物理学家和数学家的直觉。

2. 为什么不是Lisp/Scheme?底层内存架构与现代硬件的背离

Lisp(及其方言Scheme)具有强大的宏能力和学术底蕴,甚至麻省理工学院曾长期将其作为计算机科学入门语言。然而,Lisp的致命缺陷在于其核心数据结构——链表(Linked List)——与现代高性能计算的硬件现实存在根本性冲突。

在进行深度学习矩阵乘法时,CPU和GPU的缓存局部性(Cache Locality)是决定性能的生死线。Lisp的链表结构使得数据通过指针随机散落在内存的各个角落,处理器在进行遍历时会产生灾难性的寻址延迟。反观Python的NumPy架构,其多维数组在底层完全是以C语言的连续内存块(Contiguous Memory Blocks)形式存储的。当把这样一个密集的内存块推送给现代向量处理器或GPU引擎时,计算速度能实现数量级的飞跃。此外,Lisp高度依赖括号的前缀表达式语法,对习惯了标准代数表达式的科研人员构成了极高的学习壁垒。

3. 为什么不是Haskell?静态纯函数的洁癖与科学探索的摩擦

Haskell作为一门纯函数式(Pure Functional)、强静态类型的语言,在保证系统安全性和消除副作用方面登峰造极。但在科学计算中,研究往往是一个极其混乱、不断试错(Quick and Dirty)的迭代过程。科学家常常需要随意改变变量类型、就地修改(Mutate)庞大的数据矩阵、处理不规则的缺失值。

Haskell的纯函数不可变性(Immutability)特性意味着,如果要更改一个包含百万元素的数组中的一个值,往往需要生成一个新的结构副本。这在处理PB级数据的机器学习中不仅是不现实的,甚至许多基本的线性时间复杂度的随机访问数组算法在Haskell中都难以实现最优表达。Python的“鸭子类型”(Duck Typing)和动态特性允许科学家在IPython Notebook中随心所欲地操作内存状态,最大化了灵感探索的效率。

4. 为什么不是Lua?从Torch到PyTorch的最终证明

深度学习对Python的选择,最经典的案例莫过于PyTorch的诞生历史。早期的Torch框架是用Lua语言编写的,结合了极为快速的LuaJIT(即时编译器),在性能上表现极佳。然而,Lua语言完全缺乏一个像Python那样丰富的科学工具外围生态。

当研究人员使用Lua训练神经网络时,如果他们需要加载一个复杂的CSV文件、需要对时间序列进行统计清洗、或者想要绘制一张损失函数的可视化折线图,他们会发现Lua社区根本无法提供类似Pandas或Matplotlib这样成熟的工具。为了不让科学家在不同语言间来回切换(重演90年代双语言难题的悲剧),Torch的开发者别无选择,只能将框架重写并深度绑定到Python的生态系统中,最终造就了主宰当今AI界的PyTorch。

综上,深度学习引爆了Python,但这绝非运气的眷顾。Python在长达二十年的“史前史”中,由一群不受商业公司主导的科学家、研究生和极客,以去中心化的方式,逐个攻克了C/Fortran接口、统一了底层连续数组内存标准、引入了现代交互式计算范式,并提供了平民化的数据清洗工具。正是这一座由无数行胶水代码筑起的隐形巴别塔,使得Python在深度学习黎明破晓之际,成为了那个唯一准备好承载通用人工智能未来与算力的编程语言。