4. 深度学习
4.1. 概念
深度学习是一种机器学习的分支,旨在通过构建和训练多层神经网络模型来实现数据的高级特征表达和复杂模式识别。与传统机器学习算法相比,深度学习具有以下特点:
- 多层表示学习:深度学习使用深层神经网络,允许多个层次的特征表达和抽象,从而能够自动发现和提取输入数据中的重要特征。
- 端到端学习:通过将输入直接映射到输出,深度学习可以实现端到端的学习,无需手工设计特征提取器或预处理步骤。
- 大规模并行计算:深度学习模型通常需要进行大量的矩阵运算,在现代硬件(如GPU)上可以进行高效的并行计算,加快了训练和推断的速度。
- 梯度下降优化:深度学习模型通常使用梯度下降等优化算法来最小化损失函数,并通过反向传播算法有效地更新网络参数。
- 泛化能力强:深度学习模型具有很强的泛化能力,能够在未见过的数据上进行准确的预测和分类。
深度学习在各个领域都取得了重大突破,包括计算机视觉、自然语言处理、语音识别等。它已经应用于图像分类、目标检测、机器翻译、智能助手等众多任务中,并在许多比赛和实际应用中取得优秀的结果。
神经网络功能强大,并且深度学习则是优化了数据分析,建模过程,因此基于神经网络的深度学习可以统一原来的传统机器学习。AlphaGo是深度学习战胜了世界围棋第一人李世石。2016年Google翻译基于深度学习更新,翻译能力得到大幅提升。最新的Google翻译是基于大语言模型。
4.2. 神经网络
4.2.1. 定义
4.2.1.1. 概念
深度学习是一种基于人工神经网络的机器学习方法,其核心思想是通过多层次的神经网络来模拟人脑的神经元之间的连接。深度学习的特点是可以通过大规模的数据来训练模型,并且可以自动学习到数据的特征表示。
上图就是一个神经网络的基本结构图,X1到Xn是输入,O1到Oj是输出,圆圈是神经元(也称感知机),连线带权重参与计算生成下一个神经元。隐层在实际的神经网络中可能会多层,并且都是全连接,所以计算量巨大,所以需要AI CPU、AI GPT等。
4.2.1.2. 感知机
如下图是一个神经元,其有3个输入数据x附加不同的权重w,另外有一个偏置(可以理解为线性函数中的截距)。
h = f(u + b)
我们先假设没有激活函数,来看下神经元的效果。
- 如下图,单层单个元神经元可以用来作为分类。
- 如下图,单层多个神经元可以完全更精细的线性分类分类
通过上面的示例可以看出,在没有激活函数的情况下,无论在多少个神经元作用下,其都是使用累加计算的,总是一阶的,总是线性的。线性函数只能处理一些简单的场景,复杂场景多是需要用曲线或曲面来区分的。如下图,用线段无法区分大小写字母。
我们就需要在神经元加一个函数来加强其能力,这就是激活函数的作用,它让神经元具备非线性表达能力。
我们让激活函数为Sigmoid函数,那么直线与Sigmoid函数相乘,就变成了曲线。
那么在3个神经元在3个激活函数的作用下,就可以形成3条曲线。
3条曲线在不同的权重作用下,可以拟合为一条新的形状,可以达到区分大小写字母的能力。
理论上来说,只要神经元足够多,无论多么复杂的分类都可以实现。
激活函数
激活函数可以选择不同的函数,Sigmoid是以前比较受欢迎的激活函数,但是其存在一些问题。当权重很小时,Sigmoid函数的作用也很小,容易导致梯度消失(简单讲是指区别度不大,导致学习的效率不佳)。ReLU系列的激活函数包括ReLU、Leaky ReLU、PReLU、ELU。
不同的激活函数有不同的应用场景,不同的计算量,需要根据经验进行选择调整。
softmax回归
为了结果更清晰,好对比,我们可能需要将结果进行归一化处理(归一化也被称为单位化,即所有结果之和为1)。
经过softmax回归计算之后,输出的结果可能是这样的:
4.2.2. 损失函数
如何评估神经网络的效果,我们就需要用到损失函数。损失函数(Loss Function)用来估量模型的预测值 f(x) 与真实值 y 的偏离程度。因为误差有正有负,所以可以采用平均绝对误差,均方误差(平均平方误差, Mean Squared Error ,MSE),这些多用于回归问题。用于二分类问题(是/否,对与错),多用交叉熵损失函数(CrossEntropy Loss)。多分类问题,可以用softmax函数,如上图的动物分类。
交叉熵损失函数(CrossEntropy Loss)
熵是用来描述物体混乱程度的概念,越混乱熵越大,也可以理解为数据越随机熵就越大。信息熵越大,事物越具不确定性,事物越复杂。
信息熵公式:
交叉熵主要用于度量两个概率分布之间的差异性。交叉熵越小,表示模型输出分布越接近真实值分布。
在机器学习框架中,交叉熵都有直接提供接口,我们只需要知道交叉熵的概念及其应用场景,知道使用即可。
4.2.3. 计算
4.2.3.1. 前向传播
有如下一个神经网络,3个输入,2个输出,单层神经网络有4个神经元。
转换为数学形式:
一步步从前往后进行计算,这就是前向传播计算。x1、x2、x3总是一起参与计算,其总的输出可以用一个矩阵[x1, x2, x3]表示,所以在神经网络的计算是,需要大量的矩阵计算。所以现在有很专用用于神经网络计算的神经网络处理器(Neural network Processing Unit, NPU)。
前向传播主要用于预测结果。
4.2.3.2. 反向传播
在神经网络学习的过程中,我们通过误差函数来求一个最小误差时的权重和截距(神经网络中叫偏置)。我们可以使用最小二乘法,也可以使用梯度下降法。使用最小二乘法效果好,但是计算量非常大,尤其是在大型神经网络中,如果使用最小二乘法计算量巨大,所以一般使用梯度下降法,梯度下降使用学习率(权重的步进值)这个超参数来控制下降的速度,来提升计算速度。
梯度下降是通过误差函数反向往前推的,所以也被称为反向传播。反向传播主要用于学习(训练)。
4.2.2. 分类
深度学习的主要方法包括卷积神经网络(CNN)、循环神经网络(RNN)和生成对抗网络(GAN)等。
1. 卷积神经网络:
卷积神经网络是一种专门用于处理具有网格结构的数据(如图像和语音)的神经网络。卷积神经网络通过卷积层、池化层和全连接层等组件来提取图像的特征表示,从而实现图像分类、目标检测和图像生成等任务。
2. 循环神经网络:
循环神经网络是一种可以处理序列数据(如语言和时间序列)的神经网络。循环神经网络通过循环连接来处理序列数据的时序信息,并且可以自动学习到序列数据的上下文信息。循环神经网络在自然语言处理、语音识别和机器翻译等领域有广泛应用。
传统的循环神经网络是全连接的,并不关注数据的前后顺序(如语言的前后顺序或时间序列等)。RNN中每个神经元的输出,不仅仅有上一层神经元的输出,还可能把数据序列前处理神经元的输出作为输入。
因为CNN增加了输入,计算量增加了。为了优化RNN,引入了LSTM(长短期记忆网络),减少计算量,并优化了前后依赖关系。
3. 生成对抗网络:
生成对抗网络是一种由生成器和判别器组成的对抗性模型。生成器通过学习训练数据的分布,生成与训练数据相似的新样本;判别器则通过学习区分真实样本和生成样本。生成对抗网络在图像生成、图像修复和文本生成等任务中取得了重要的突破。
4.3. 学习过程
4.3.1. 步骤
- 数据准备:收集和预处理数据,使其适合神经网络训练。这可能包括清理数据、删除异常值和对数据进行编码。
- 网络架构:设计神经网络的架构,包括层数、神经元数和连接方式。
- 初始化权重和偏差:为网络中的权重和偏差分配初始值。
- 前向传播:将输入数据通过网络,计算每个神经元的输出。
- 计算损失:将网络输出与预期输出进行比较,计算损失函数的值。
- 反向传播:使用链式法则计算损失函数相对于网络权重和偏差的梯度。
- 权重更新:使用梯度下降或其他优化算法更新网络权重和偏差,以减少损失。
- 重复步骤 4-7:重复前向传播、计算损失和反向传播的步骤,直到损失函数达到最小值或达到预定义的训练迭代次数。
4.3.2. 超参数
超参数(Hyperparameter)是机器学习模型中需要人为设定的参数,它们不是通过训练数据自动学习得到的,而是需要人工指定的参数。训练深度神经网络涉及调整以下超参数:
- 学习率:控制权重更新的步长。
- 批大小:每次前向和反向传播处理的数据样本数。
- 正则化:防止过拟合的技术,例如权重衰减和 dropout。
- 激活函数:神经元输出的非线性函数。
- 优化器:用于更新权重的算法,例如梯度下降和 Adam。每次训练完成需要更新权重参数,直到损失函数达到要求,退出训练。
4.3.3. 挑战
训练深度神经网络的挑战:
- 过拟合:网络在训练数据上表现良好,但在新数据上表现不佳。
- 欠拟合:网络无法从训练数据中学到足够的模式。
- 梯度消失和爆炸:在反向传播过程中,梯度可能变得非常小或非常大,这会阻碍训练。
- 局部最小值:优化算法可能收敛到局部最小值,而不是全局最小值。
4.3.4. 最佳实践
训练深度神经网络的最佳实践:
- 使用交叉验证来防止过拟合。
- 使用正则化技术来减少过拟合。
- 仔细调整超参数以获得最佳性能。
- 使用早期停止来防止过拟合。
- 使用权重初始化技术来防止梯度消失和爆炸。
4.4. 应用
深度学习理论上可以完全替代传统的机器学习算法,只要神经元足够,训练数据足够。传统机器学习能够达到的效果,深度学习都可以达到,并且可以拟合得更好。大力出奇迹在深度学习中完美体现。
4.4.1. 多元线性回归
如下13个自变量(输入),一个因变量(输出),因为是线性回归,只用一个神经元,且不需要激活函数。训练完成生成模型之后,可以保存模型,下次就直接使用模型来进行预测了。
神经网络识别手写数字
这段代码是使用 PyTorch 实现一个简单的全连接神经网络,用于在 MNIST 数据集上进行手写数字识别。
import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms# Device configuration
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')# Hyper-parameters
input_size = 784
hidden_size = 500
num_classes = 10
num_epochs = 5
batch_size = 100
learning_rate = 0.001# MNIST dataset download
train_dataset = torchvision.datasets.MNIST(root='../../data', train=True, transform=transforms.ToTensor(), download=True)test_dataset = torchvision.datasets.MNIST(root='../../data', train=False, transform=transforms.ToTensor())# Data loader
train_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)test_loader = torch.utils.data.DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=False)# Fully connected neural network with one hidden layer
class NeuralNet(nn.Module):def __init__(self, input_size, hidden_size, num_classes):super(NeuralNet, self).__init__()self.fc1 = nn.Linear(input_size, hidden_size) self.relu = nn.ReLU()self.fc2 = nn.Linear(hidden_size, num_classes) def forward(self, x):out = self.fc1(x)out = self.relu(out)out = self.fc2(out)return outmodel = NeuralNet(input_size, hidden_size, num_classes).to(device)# Loss and optimizer
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate) # Train the model
total_step = len(train_loader)
for epoch in range(num_epochs):for i, (images, labels) in enumerate(train_loader): # Move tensors to the configured deviceimages = images.reshape(-1, 28*28).to(device)labels = labels.to(device)# Forward passoutputs = model(images)loss = criterion(outputs, labels)# Backward and optimizeoptimizer.zero_grad()loss.backward()optimizer.step()if (i+1) % 100 == 0:print ('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}' .format(epoch+1, num_epochs, i+1, total_step, loss.item()))# Test the model
with torch.no_grad():correct = 0total = 0for images, labels in test_loader:images = images.reshape(-1, 28*28).to(device)labels = labels.to(device)outputs = model(images)_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()print('Accuracy of the network on the 10000 test images: {} %'.format(100 * correct / total))# Save the model checkpoint(模型检测点,也即模型参数,供后续直接加载使用)
torch.save(model.state_dict(), 'model.ckpt')
执行结果:
4.4.3. 其他
深度神经网络推荐使用Pytorch。
Github上的代码示例:GitHub - yunjey/pytorch-tutorial: PyTorch Tutorial for Deep Learning Researchers
GitHub - zergtant/pytorch-handbook: pytorch handbook是一本开源的书籍,目标是帮助那些希望和使用PyTorch进行深度学习开发和研究的朋友快速入门,其中包含的Pytorch教程全部通过测试保证可以成功运行
GitHub - chenyuntc/pytorch-book: PyTorch tutorials and fun projects including neural talk, neural style, poem writing, anime generation (《深度学习框架PyTorch:入门与实战》)
GPU测试平台,可以利用Google的免费在线虚拟机器:https://colab.research.google.com/
或阿里云魔搭社区虚拟机,GPT免费36小时:魔搭社区