人工智能与深度学习框架:认识AI世界的建筑大师
AI积木双雄会:PyTorch与TensorFlow的奇妙世界
第一部分:走进人工智能的神奇世界
从会思考的机器说起
你有没有想过,为什么你的手机能认识你的脸?为什么智能音箱能听懂你说话?为什么导航软件能告诉你哪条路不堵车?这些看似神奇的功能,其实都藏着一个共同的秘密——人工智能,英文缩写是AI(Artificial Intelligence)。
人工智能就像是给机器装上了一个会思考的大脑。传统的程序就像是一份详细的做菜食谱,每一步都要写清楚:先放油,等油热了,放葱花炝锅,再放菜,翻炒几下,放盐,出锅。但人工智能不一样,它更像是一个跟大厨学习的学生,看大厨做很多次菜之后,自己就学会了怎么做。
人工智能这个概念其实很早就有了。1956年夏天,一群聪明的科学家在美国达特茅斯大学开会,第一次提出了“人工智能”这个词。那时候的计算机又大又慢,科学家们梦想着有一天计算机能像人一样思考。几十年来,人工智能经历了起起落落,有过辉煌的突破,也有过暗淡的低谷。直到2010年左右,随着计算能力的大幅提升和海量数据的积累,人工智能终于迎来了它的黄金时代,开始真正改变我们的日常生活。
现在的人工智能已经能做很多惊人的事情:它能在成千上万张照片里瞬间找到你的那张脸,准确率比人眼还高;它能把你说的话转换成文字,甚至能用和你一模一样的声音回复你;它能根据你的喜好推荐你可能感兴趣的视频和歌曲;它还能帮助医生诊断疾病、帮助农民识别病虫害、帮助科学家发现新药。可以说,人工智能正在深刻地改变着各行各业。
什么是机器学习:让计算机从数据中学习
说到人工智能,就不得不提机器学习(Machine Learning)。你可以把机器学习理解为人工智能的核心技术——一种让计算机从数据中学习、而不是被明确编程的技术。
想象一下,你要教一个机器人分辨猫和狗。传统的方法是写一堆规则告诉它:猫有尖耳朵、狗有垂耳朵、猫的脸比较小、狗的鼻子比较长……但这样写规则既麻烦又不准确,因为总有例外——有的狗也有尖耳朵,有的猫鼻子也很长。
机器学习的方法完全不同。你不需要告诉计算机具体的规则,而是给它看大量的猫和狗的图片,让它自己总结出规律。看完几万张图片之后,机器人自己就明白了:哦,原来猫和狗的区别在于……它可能说不清楚具体是哪些特征,但它就是能分辨出来。
这就是机器学习的魔力——它能从数据中自动发现规律,而不需要人类手动编写规则。机器学习有几种主要类型:
监督学习就像是有老师指导的学习。你告诉计算机每个例子正确答案是什么,比如“这是猫的照片”“那是狗的照片”。计算机通过大量的例子学习,慢慢就掌握了分辨的本领。监督学习是最常用的机器学习方法,常用于分类(比如分辨猫狗)和回归(比如预测房价)任务。
无监督学习则像是没有标准答案的自学。计算机只能看到一堆数据,自己去发现数据里有什么规律。比如给它看很多张照片,它可能会发现有些照片里的人都是长头发,有些照片里的背景都是蓝色的——这些分类不是我们告诉它的,而是它自己发现的。无监督学习常用于聚类(把相似的东西分组)和降维(简化数据的表示)任务。
强化学习则像是通过试错来学习。一个智能体(可以理解为一个小机器人)在环境中做出动作,根据得到奖励或惩罚来调整自己的策略。比如下棋的时候,赢了就得到奖励,输了就得到惩罚,通过无数次的对弈,机器人就能学会下棋的技巧。强化学习在游戏、机器人控制等领域有广泛应用。
深度学习:像大脑一样的多层神经网络
如果说机器学习是人工智能的核心技术,那么深度学习就是机器学习中最耀眼的那颗明星。深度学习让机器能够从海量数据中自动学习复杂的特征表示,在很多任务上的表现已经超过了人类。
深度学习的核心是神经网络(Neural Network)。有意思的是,这个技术的灵感确实来自于人脑的工作方式。我们的大脑由数以亿计的神经元组成,每个神经元接收来自其他神经元的信号,经过处理后再传递给下一层。神经网络就是模仿这种结构设计的。
一个最简单的神经网络长什么样呢?想象你有好多小球排列成几排,每排叫做一层。第一层是输入层,接收数据,比如一张图片的每个像素值;最后一层是输出层,给出结果,比如这张图片是猫还是狗;在输入和输出之间还有好几层,叫做隐藏层。信息从输入层一层一层传递到输出层,每一层的神经元都在做计算和转换。
为什么叫“深度”学习呢?因为这种网络有很多层,少则五六层,多则几百层。每一层都在提取不同级别的特征:最底层的可能只检测简单的边缘和纹理;中间层的可能组合出轮廓和形状;最上层的可能识别出具体的物体部件,最后组合成完整的物体识别结果。这种从简单到复杂、从低级到高级的特征提取方式,恰恰模仿了人类视觉系统的工作原理。
深度学习的强大之处在于它的表示学习能力。传统机器学习需要人类专家手动设计特征,比如告诉计算机“猫有尖耳朵”这样的知识,这叫做特征工程,是一项既耗时又需要专业知识的工作。深度学习则可以端到端地学习,直接从原始数据(比如像素)到最终输出(比如类别标签),自动学习出有用的特征表示。这大大降低了人工智能系统的开发门槛,也让很多以前无法解决的问题变得可以解决。
深度学习在很多领域都取得了突破性进展。在计算机视觉领域,深度学习让计算机能够准确地识别图像中的物体、人脸、甚至推断出照片里人物的情感。在自然语言处理领域,深度学习让机器能够理解人类语言、进行机器翻译、写文章、甚至和人对话。在语音识别、推荐系统、医疗诊断、游戏对战等众多领域,深度学习都发挥着越来越重要的作用。
第二部分:深度学习框架——建造AI大厦的工具箱
为什么需要深度学习框架
现在我们知道了深度学习是什么。但是,要真正搭建一个深度学习模型,需要做很多事情:设计神经网络的结构、计算数据在前向传播中怎么流动、计算预测结果和真实答案之间的差距(损失)、通过反向传播算法计算每个参数应该怎么调整、用优化算法更新参数、批量处理数据、模型训练过程中的监控和调参……这其中涉及大量的数学计算和工程实现。
如果每一件事都要从零开始写代码,那光是写一个简单的图像分类器,可能就要花上好几个月,而且代码里很可能会布满各种bug。深度学习框架(Framework)的出现,就是为了解决这个难题。
你可以把深度学习框架想象成一个巨大的工具箱,里面有各种各样的工具:锤子、螺丝刀、锯子、扳手……有了这个工具箱,你不需要自己从头制造工具,只需要学会怎么使用这些现成的工具,就能高效地搭建起自己的深度学习系统。
具体来说,深度学习框架提供了以下重要功能:
张量运算是最基础的功能。张量(Tensor)听起来很高级,其实它就是一种数据的容器。最简单的标量(一个数字)是0阶张量,向量是一阶张量,矩阵是二阶张量,三维数组是三阶张量,以此类推。深度学习里的所有数据——图像、文本、声音——最终都可以表示成张量的形式。框架提供了各种张量运算:加减乘除、矩阵乘法、卷积、激活函数……这些都是构建神经网络的积木。
自动微分是深度学习框架最核心的技术之一。反向传播算法需要计算损失函数对每个参数的导数,这些导数的计算极其复杂,手工推导和实现几乎不可能。框架提供了自动微分功能,你只需要定义前向计算(模型怎么从输入得到输出),框架就能自动帮你计算出反向的梯度。这大大解放了生产力。
GPU加速让深度学习变得实用。训练深度学习模型需要海量的计算,CPU(中央处理器)虽然通用,但并行计算能力有限。GPU(图形处理器)最初是为了处理图形渲染设计的,但它天然适合深度学习中那种大量矩阵运算,训练速度可以比CPU快几十甚至上百倍。主流框架都支持GPU加速,有些还支持TPU(张量处理器)等专用硬件。
预训练模型和迁移学习让深度学习更容易落地。训练一个深度学习模型需要大量的数据和计算资源,从头开始训练可能需要几天甚至几周。框架通常提供预训练模型,这些模型已经在超大规模数据集上训练好了,你只需要在自己的小数据集上进行微调,就能得到不错的效果。这就是迁移学习的思想。
PyTorch与TensorFlow:两座不同的建筑公司
现在我们来认识这本书的两位主角——PyTorch和TensorFlow。它们都是目前最流行的深度学习框架,被全球数百万开发者和研究人员使用。但它们就像两家不同的建筑公司,各有各的特色和擅长的领域。
TensorFlow是由谷歌大脑团队开发的,2015年正式开源,是最早流行的深度学习框架之一。谷歌在人工智能领域投入巨大,TensorFlow也得到了广泛的应用,从小小的手机应用到大规模的云端服务器,都能见到它的身影。TensorFlow的名字很有意思:Tensor是张量,Flow是流动,合起来就是“张量流动”,形象地描述了数据在神经网络中一层一层流动处理的过程。
PyTorch是由Facebook(现在的Meta)的人工智能研究团队开发的,2016年发布。PyTorch的特点是设计简洁、代码易读、使用灵活,特别受到学术研究人员的喜爱。很多最新的深度学习论文都是用PyTorch实现的,PyTorch也因此成为了深度学习研究的首选框架。近年来,PyTorch在工业界的应用也越来越广泛。
让我们用一个建筑工地的比喻来更好地理解它们。假设我们要把一堆原材料(数据)建成一座高楼(训练好的模型)。
TensorFlow就像是使用传统建筑方式的大公司。他们有完整的图纸规范(静态图执行),需要先画好整个建筑的设计图,然后按照图纸一步步施工。这种方式的优点是计划周全,执行效率高,特别适合大规模部署和生产环境。但灵活性稍差,改动设计可能需要重新画图。
PyTorch则更像是采用模块化建筑方式的创新团队。他们可以先搭建一个房间,看看效果,满意了再搭下一个房间。PyTorch使用的是动态图执行方式,你可以在Python代码中随时使用Python的控制流,随时打印中间结果,随时修改模型结构。这种“所见即所得”的方式让开发和调试变得非常直观。
TensorFlow后来也推出了Eager Execution模式,让TensorFlow 2.0也支持动态图执行;PyTorch也推出了TorchScript,用于生产环境部署。两者正在相互借鉴,变得越来越像。但它们的核心设计哲学仍然有所不同:TensorFlow更偏向于“定义-运行”分离,适合大规模部署;PyTorch更偏向于“define-by-run”,适合研究实验。
除了这两大巨头,还有一些其他框架值得关注。比如来自微软的CNTK(微软认知工具包),来自亚马逊的MXNet(被选为AWS的默认框架),来自百度的PaddlePaddle(飞桨),以及专门用于科研的JAX等。但从市场占有率和使用范围来看,PyTorch和TensorFlow绝对是双雄争霸,各领风骚。
第三部分:动手实践——你的第一个深度学习程序
Python基础:和计算机对话的语言
在开始学习PyTorch和TensorFlow之前,我们需要先掌握一门和计算机对话的语言——Python。Python是一种简单易学的编程语言,它的语法(语法就是编程语言的“说话规则”)非常接近人类的自然语言,非常适合初学者。
打个比方,如果计算机是一种来自外太空的生物,它只听得懂一种特殊的语言。那么Python就是地球人和这种外星人交流时使用的一种简单语言。Python的创造者Guido van Rossum设计它的初衷就是让编程变得简单有趣,让更多人能够享受编程的乐趣。
让我们从最基本的开始。Python里,你可以通过`print`函数让计算机在屏幕上显示文字:
```python print("Hello, World!") ```
这行代码的意思是:让计算机显示“Hello, World!”这段文字。运行这行代码,你会在屏幕上看到`Hello, World!`这几个字。`print`函数就像是一个输出命令,括号里的内容就是你要输出的内容。
在Python中,你可以用变量(Variable)来存储数据。变量就像是一个有名字的盒子,你把东西放进去,以后可以通过名字找到它:
```python my_name = "小明" my_age = 10 print(my_name) print(my_age) ```
这里我们创建了两个变量:`my_name`存储的是文字(叫做字符串,用引号括起来),`my_age`存储的是数字。变量名可以自己起,但最好起有意义的名字,比如用`my_name`而不是`a`来表示名字,这样代码更容易读懂。
Python支持各种数学运算:
```python a = 10 b = 3 print(a + b) # 加法:13 print(a - b) # 减法:7 print(a * b) # 乘法:30 print(a / b) # 除法:3.333... print(a // b) # 整除:3 print(a % b) # 取余:1 print(a ** b) # 幂运算:10的3次方=1000 ```
Python还有几种重要的数据结构:列表(List)是有序的元素集合,可以存放很多东西:
```python fruits = ["苹果", "香蕉", "橙子"] print(fruits[0]) # 第一个元素:苹果 print(fruits[2]) # 第三个元素:橙子 fruits.append("葡萄") # 添加一个新元素 print(len(fruits)) # 列表长度:4 ```
字典(Dictionary)存储的是键值对,就像真实的字典一样,通过“键”查找“值”:
```python student = {"name": "小明", "age": 10, "grade": "四年级"} print(student["name"]) # 获取名字:小明 student["hobby"] = "画画" # 添加新的键值对 ```
了解了Python的基础知识后,让我们来写一个真正使用PyTorch的程序。
初识PyTorch:让计算机识别数字
PyTorch的名字很有趣:Py来自Python,Torch来自Torch( torches ),合起来就是"Python + Torch"。Torch原本是一个用Lua语言写的机器学习库,后来Facebook的团队用Python重新实现并命名为PyTorch。
让我们用PyTorch来写一个能识别手写数字的程序。手写数字识别是一个经典的深度学习入门问题:让计算机看一张手写的数字图片(比如“3”),它能告诉你这是哪个数字。MNIST数据集就是为此设计的,包含70000张手写数字图片,每张图片是28×28像素的灰度图。
```python import torch import torchvision from torchvision import transforms
1. 准备数据
transforms用来对图片进行预处理
transform = transforms.Compose([ transforms.ToTensor(), # 把图片转换成张量 transforms.Normalize((0.5,), (0.5,)) # 归一化,让数值在-1到1之间 ])
下载并加载训练集
trainset = torchvision.datasets.MNIST( root='./data', train=True, download=True, transform=transform )
trainloader = torch.utils.data.DataLoader( trainset, batch_size=32, shuffle=True )
2. 定义神经网络
class SimpleNet(torch.nn.Module): def __init__(self): super(SimpleNet, self).__init__() self.flatten = torch.nn.Flatten() self.fc1 = torch.nn.Linear(784, 256) # 全连接层 self.relu = torch.nn.ReLU() # 激活函数 self.fc2 = torch.nn.Linear(256, 10) # 输出10个类别
def forward(self, x): x = self.flatten(x) # 把28x28的图片展平成一维 x = self.fc1(x) # 第一个全连接层 x = self.relu(x) # 激活 x = self.fc2(x) # 第二个全连接层 return x
3. 创建模型
model = SimpleNet() print(model)
4. 定义损失函数和优化器
criterion = torch.nn.CrossEntropyLoss() # 交叉熵损失 optimizer = torch.optim.Adam(model.parameters(), lr=0.001) # Adam优化器
5. 训练模型
for epoch in range(5): # 训练5个轮次 running_loss = 0.0 for i, data in enumerate(trainloader, 0): inputs, labels = data
optimizer.zero_grad() # 清零梯度 outputs = model(inputs) # 前向传播 loss = criterion(outputs, labels) # 计算损失 loss.backward() # 反向传播 optimizer.step() # 更新参数
running_loss += loss.item() if i % 200 == 199: print(f'Epoch {epoch+1}, Batch {i+1}, Loss: {running_loss/200:.3f}') running_loss = 0.0
print('Training Fini