Datawhale AI夏令营-多模态Task2学习笔记

Task2学习笔记

学习任务

实现一个基于深度学习的Deepfake检测模型。

预计掌握的内容:

  1. 预训练模型的使用:学习如何加载和微调预训练模型,以加快训练过程并提高模型性能。

  2. 深度学习模型训练流程:掌握模型训练的各个步骤,包括前向传播、损失计算、反向传播和参数更新。

  3. 性能评估与优化:如何通过准确率等指标评估模型性能,并进行相应的优化。

额外补充

由于直播间一学一个不吱声的,看来只是通过问答的方式学习还是不够。

加上吴恩达老师的《深度学习》视频课程后,我通过系统的学习,对于Task2有了更加深入的理解。

基础知识学习/回顾

Part1 深度学习的定义

将深度学习的过程和人的大脑思考过程进行类比是一种危险的行为,但将人的大脑思考过程应用于深度学习的改良又是一种好的方法。——吴恩达

将这句话放在开头也是对吴恩达老师对于如今深度学习的概念正在被加以滥用的担忧。

其实,深度学习(Deep Learning)只是机器学习的一个分支,它使用神经网络模拟人脑的学习方式,从大量数据中自动学习和提取特征,进行预测和决策。它并没有和机器学习彻底割裂,它只是通过更加庞大的计算量,自行确定那些应该用于分类的特征。

例如,通过对NFC信号的识别,若通过机器学习实现,我们会进行下面的操作步骤:

  • 根据ISO-14443-2,确定NFC通信过程中的ATQA信号一定会包含可区分设备的特征。

  • 收集大量的信号数据(1000+条),并将ATQA信号提取出来,形成一个数据集。

  • 若是无监督学习,将它们投入到算法中“炼丹”即可。若是监督学习,则将它们打上标签,将标签作为一个独立的维度一起投入到训练中。

  • 最后用测试数据集测试模型的准确度。

如果是深度学习,那应该会变成以下的步骤:

  • 收集大量的NFC信号数据,根据ISO-14443-2,将NFC通信信号的比特流按顺序摆放好(REQA,ATQA等)。

  • 然后,设计一个深度学习用的多层神经网络,每一层神经元接受前一层神经元的输出,并通过权重和激活函数进行计算,传递到下一层神经元。

  • 将数据投入其中,让神经元在正向传播结束后,通过代价函数和缺失函数反向传播更新权重直到所有的数据都被用完。

  • 最后用测试数据集测试模型准确度。

可见深度学习相较于机器学习有一种用“空间换时间,体力劳动换脑力劳动”的无脑爽感,但是,这个计算量就变大了很多。

Part2 深度学习的训练过程

学校里的老师说过:“人工智能每过一段时间就要火一次。”它火归火,还是要找到"AI中途凉了"的原因,以及“Make AI Great Again”的原因。

神经网络的基本单位是神经元。

神经元模型是模拟生物神经元行为的计算模型,它在人工智能和机器学习领域扮演着核心角色。

神经元就像人体大脑中的微小开关,能够接收来自其他神经元的信号,并根据这些信号的产生反应。

在人工智能中,我们用数学模型来模拟这种生物神经元的行为。

一个简单的神经元模型包括输入、权重、激活函数和输出

  1. 输入就像神经元 树突 接收到的信号,

  2. 权重则像是调整信号强度的小调节器,

  3. 激活函数决定是否产生输出,

  4. 输出则是传递给其他神经元的信号。分为正向和反向。

哦,然后呢?Talk is useless, show me the code.在计算机的视角下,这些东西都必须要能被量化。所以,我们需要明确这些环节的详细过程。

很明显,输入输出用相关设备完成,权重是初始化后自行更新,看来激活函数是我们需要研究的重点。

从上图可见很多的计算用函数,按照吴恩达老师的观点,他最喜欢用tanh——它关于原点对称,好计算,对于深度学习以及机器学习的本质——自适应的逻辑回归算法效率和精确度有着很大的作用。

而作为入门的sigmoid函数,它的计算本身就得丢一定的精度,而且和原点不对称,计算量很大。但是这个函数最后的值一定在[0,1]之间,因此将它用作输出层函数十分合适。

现在最基本的对输出值的量化已经实现了,接下来讨论参数更新的量化问题

深度学习能够通过大量的数据和反复的训练来自动调整这些小开关(权重)的设置,使得整个网络能够越来越准确地完成特定的任务。

这个过程就像是在训练一个聪明的孩子,通过不断的练习和反馈,孩子学会了如何识别物体、理解语言,甚至解决复杂的问题。

然后,我们需要使用特定的公式严格定义更新的度,这便迎来了新的算法。

梯度下降算法

梯度下降是一种优化算法,用于最小化函数。梯度是损失函数关于模型参数的导数,它指示了参数的调整方向,以减少损失函数的值。这些梯度告诉我们如何调整权重和偏置以减少损失。

梯度下降算法基于这样一个原理:损失函数的梯度指向函数增长最快的方向。本质上是贪心算法的应用。

因此,如果我们希望减少损失函数的值,我们就需要沿着梯度的反方向调整模型的参数。这样,每次迭代都会使模型参数朝着减少损失的方向移动。

在深度学习中,我们希望最小化损失函数,即模型预测值与真实值之间的差异。

在训练循环中,我们首先加载一小批量数据,将其输入到神经网络中进行前向传播,计算出网络的输出。然后,我们使用损失函数来计算当前批次的损失,并通过反向传播算法计算损失函数关于每个参数的梯度。

当数据集非常大时,一次性处理所有数据可能会导致内存不足或计算过于缓慢。通过将数据分成小批量,我们可以更频繁地更新模型参数,这使得训练过程更加高效。

但是这个算法也有以下几个问题:

  1. 若是依照上面的定义,一般都是想着通过循环遍历所有的数据,但是深度学习的数据量级……这将会带来巨大的耗时。

  2. 它继承了贪心算法的局限性:结果其实只能达到甚至只能趋近一个数学定义上的极小值(条件最值),一旦区间内出现了其它的波谷,那梯度下降算法就将失效。

然而这些问题是可以改善的,以从循环耗时为例:

解决耗时,就是要解决造成耗时的元凶——那些预计会写入到代码中的显式for循环(或者while)

可目前逻辑上我们还没有突破遍历的底层,所以我们本质上其实也是逐个扫描。但是就如同RSA的蒙哥马利算法,只出现在底层的遍历和出现在代码上的遍历依旧是两个等级的速度。

实际上,随着多核CPU的出现,底层的扫描还可以享受到并发的红利

以本次的实操代码为例:

既然一条一条的扫描太慢了,那我们能一次性接入多条吗?答案是可以的,因为计算机的所有计算在底层都是线性运算,而说到线性运算,大学不来点线性代数那可说不过去了。

所以,与其一行行的输入,不如让数据形成的数组先转置成列向量,然后拼接成矩阵投入呢?

这样,通过矩阵乘法,我们不仅可以一次算出所有的结果,还可以直接将所有的结果进行维护,然后直接投入下一层进行训练。

不得不说,终于在数据结构机试和大一的课程以外我可算是能够将线性代数的知识充分利用了。

同时,从上图中,我们还可以通过使用Python的Numpy库,让计算过程吃到底层的并发优化,即CPU,GPU的SIMD指令。

不过,由于逻辑没变化,这个过程还是“空间换时间了”,但这样很值得。

Pytorch训练代码

让我们回顾一下在Task1 的PyTorch 代码,我们在训练一个分类模型

def train(train_loader, model, criterion, optimizer, epoch):
​
    # switch to train mode
    model.train() # eval()
​
    for i, (input, target) in enumerate(train_loader):
    
        input = input.cuda(non_blocking=True)
        target = target.cuda(non_blocking=True)
​
        # compute output
        output = model(input)
        loss = criterion(output, target)
​
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

首先,我们需要准备一批图片数据(通过train_loader)和这些图片对应的正确标签(target)。

在开始训练之前,将模型设置为训练模式( model.train() ),这样模型就知道现在是学习时间了。

接着,开始喂给模型图片数据,并让它尝试预测这些图片的内容。

模型会基于它目前的学习给出预测结果(output),而会计算这些预测结果与实际标签之间的差异,这个差异就是损失(loss)。

为了让模型学会准确预测,需要指出它的错误,并更新它的内部参数来减少这些错误(通过loss.backward()optimizer.step())。

这个过程就像是模型在自我调整,以便在下一次遇到类似图片时能够做出更准确的预测。

回到初始化环节

现在一切都就绪了,开始运行吧。先给所有的空位先初始化一个值占坑位。

等一下!这可是一个没有量化的不严谨的说法。看来还得解决一个问题:怎么初始化?

那全置0可以吗?看上去可以,实际上全置0不行

假设一个最简单的神经网络,有一个仅一层2个神经元构成的隐藏层,一个输入层,一个输出层。如果此时将所有参数置0,那将数据投入的结果,算出来也全是0,那最后梯度也全是0,就是所有的数据都投入进去了,这个神经网络也跑不起来。

全置0将会导致对称失效问题,因此这方面不要自作聪明,直接随机初始化都比置0初始化好

好像哪里不对

我们探讨对称失效,是为了防止梯度被自己一顿作死行为整得一直不更新。

但是之前也有一个问题没有提及到:

由于计算机底层全是线性运算,激活函数如果还是线性运算将会产生同构问题,如此神经网络将会失去分层的意义!

所以,激活函数必须是非线性的。

可非线性的函数在计算的时候就得泰勒展开,就得丢失余项,就是缺失精度。

所以,能不能让激活函数尽量有一些可以利用的线性部分呢?这就诞生了ReLU(修正线性单元)以及它的一系列变种(见前面激活函数的那一系列"LU"即可)。

算得是挺快的,可是这些函数在自变量为0时,从数学角度上不存在导数,换言之,如果修正的时候,给下一层的值出现了0,那就得自己规定这个值的梯度是多少——这其实从逻辑上就破坏了深度学习的自主能力。

但我们又赌不起,万一出现0了又没额外规定,跑了半天结果出现报错那晚上都没法合眼了。

不是,哥们?凭什么啊?

新的知识

Part3 深度学习与迁移学习

迁移学习是一种机器学习技术,它将已在一个任务上学到的知识(如模型参数、特征表示等)应用到另一个相关任务上。

这种技术特别有用,因为它允许模型在数据稀缺的情况下也能表现出色。

通常使用在大规模数据集上预训练的模型作为起点,例如在ImageNet数据集上预训练的卷积神经网络(CNN)。

在预训练模型的基础上,使用少量标记数据对模型进行微调,以适应新任务。

但是,这本质上也是一种对其他数据集的引用,因此在人工智能安全中,一个重要的课题就是如何通过加入噪声在尽量减小对模型精度的干扰下,防止他人通过不法手段窃取到模型参数/反推训练集数据以及之后的生成对抗网络攻击。但这些都是后话了。

开玩笑,自己弄的数据集,要是未经同意成了别人的嫁衣,被人窃取了工作量,我非跟他拼命。

自己养的数据集变成别人的了,这又何尝不是一种NTR?

在此处先以ImageNet为例。

ImageNet 介绍

ImageNet 包含超过1400万张注释过的图像,这些图像分布在超过2.2万个类别中。它的规模之大使得它成为深度学习模型训练和评估的理想数据集。ImageNet 数据集中的图像包含了各种场景、物体、背景和遮挡情况,这为算法提供了极大的挑战。这种多样性使得在 ImageNet 上训练的模型能够学习到鲁棒的特征,从而在现实世界应用中表现良好。

ImageNet 提供了一个标准的性能基准,研究者可以通过在 ImageNet 上的表现来比较不同模型的性能。此外许多在 ImageNet 上预训练的模型被用作迁移学习的起点,这些模型在新任务上通常表现出色。

迁移学习的实现方法

某运输大队长曾言:“机枪向左移五米!”,乃真微操大师也!

微调(Fine-tuning)是深度学习中一种有效的迁移学习策略,它允许我们利用预训练模型对特定任务进行优化。

其基本原理是,首先在一个大规模的数据集上预训练一个深度学习模型,捕捉通用的特征表示,

然后将这个预训练模型作为起点,在目标任务上进行进一步的训练以提升模型的性能。

微调的过程通常开始于选择一个在大型数据集上预训练的模型,这个预训练模型已经学到了丰富的特征表示,这些特征在广泛的领域内都是通用的。接着,我们将这个预训练模型适配到新的目标任务上。适配过程通常涉及以下步骤:

  • 我们会替换模型的输出层,以匹配目标任务的类别数量和类型。例如,如果目标任务是图像分类,而预训练模型原本用于不同的分类任务,我们就需要将模型的最后一层替换成适合新任务类别数的新层。

  • 【可做可不做】我们冻结预训练模型中的大部分层,这样可以防止在微调过程中这些层学到的通用特征被破坏。通常情况下,只对模型的最后一部分层进行解冻,这些层负责学习任务特定的特征。

  • 使用目标任务的数据集对模型进行训练。在这个过程中,我们会用梯度下降等优化算法更新模型的权重,从而使模型能够更好地适应新的任务。训练时,可能会使用比预训练时更低的学习率,以避免过度拟合目标数据集。

在下面代码中,timm.create_model('resnet18', pretrained=True, num_classes=2)这行代码就是加载了一个预训练的ResNet-18模型,其中pretrained=True表示使用在ImageNet数据集上预训练的权重,num_classes=2表示模型的输出层被修改为有2个类别的输出,以适应二分类任务(例如区分真实和Deepfake图像)。通过model = model.cuda()将模型移动到GPU上进行加速。

import timm
model = timm.create_model('resnet18', pretrained=True, num_classes=2)
model = model.cuda()

天天都是CUDA,CUDA的。

AMD! Intel! 我***硬件加速呢?

哦,老黄为了CUDA忍辱负重了很多年吗?那没事了。

Part4 常见的图像分类网络

图像分类是计算机视觉中的一个基本任务,它涉及到将给定的图像分配到一个或多个预定义的类别中。随着深度学习的发展,已经设计出许多不同的卷积神经网络(CNN)架构来提高图像分类的准确率。

图像分类是计算机视觉中的一个基本任务,它涉及到将给定的图像分配到一个或多个预定义的类别中。随着深度学习的发展,已经设计出许多不同的卷积神经网络(CNN)架构来提高图像分类的准确率。

AlexNet

AlexNet是一种具有深远影响的卷积神经网络(CNN)架构,由Alex Krizhevsky、Ilya Sutskever和Geoffrey Hinton设计。

它在2012年的ImageNet大规模视觉识别挑战赛(ILSVRC)中取得了突破性的成绩,大幅度超越了之前的图像分类技术(非深度学习技术)

AlexNet包含八个层次结构,前五个是卷积层,其中一些后跟最大池化层,最后三个是全连接层。具体结构如下:

  1. 卷积层:AlexNet的前五个层次都是卷积层,每个卷积层后面跟着一个ReLU激活函数,以引入非线性。这些卷积层旨在提取图像的特征。

  2. 局部响应归一化(LRN):在某些卷积层后使用了局部响应归一化,这是一种提高模型泛化能力的正则化方法。

  3. 最大池化层:在部分卷积层之后使用最大池化层来降低特征的空间维度,减少计算量和过拟合的风险。

  4. 全连接层:网络的最后三个层次是全连接层,其中最后两个全连接层后跟有Dropout,以进一步防止过拟合。

  5. 输出层:最后一个全连接层后是线性层,然后是softmax激活函数,输出1000个类别上的概率分布。

ResNet

ResNet(残差网络)是一种深度卷积神经网络架构,由微软研究院的研究员何恺明等人提出。ResNet在2015年的ImageNet图像识别大赛中取得了冠军,并在深度学习领域产生了重大影响。它的主要创新点是引入了残差学习的概念,允许训练非常深的网络,从而缓解了深度神经网络训练中的梯度消失和梯度爆炸问题。

ResNet的核心是残差块(residual block),网络通过堆叠这些残差块来构建。一个基本的残差块包含以下几部分:

  1. 跳跃连接(Skip Connections):这是ResNet最关键的创新,通过跳跃连接,输入可以直接绕过一个或多个层传到输出,输出是输入与这些层的输出的加和。这种结构使得网络可以学习输入到输出的残差,而不是直接学习输出,这有助于缓解梯度消失问题。

  2. 卷积层:残差块内部包含多个卷积层,通常使用小尺寸的卷积核(如3x3),并且通常会有批量归一化(Batch Normalization)和ReLU激活函数。

  3. 池化层:在某些残差块之间会插入最大池化层来降低特征图的空间维度。

ResNet有多个变种,包括ResNet-50、ResNet-101、ResNet-152等,数字代表了网络中权重层的数量。

这些变种在网络的深度和宽度上有所不同,但都基于相同的残差学习架构。

ResNet能够成功训练超过100层的网络,这在之前是不可能实现的。

在ImageNet竞赛中,ResNet取得了3.57%的错误率,远低于之前的表现最好的模型。

EfficientNet

EfficientNet是一种高效的卷积神经网络(CNN)架构,它通过一种新颖的网络缩放方法来提升模型的性能和效率。EfficientNet 的核心是其 compound scaling 方法,该方法通过一个复合系数统一缩放网络的深度、宽度和分辨率。在过去,网络缩放通常是通过任意选择深度、宽度或分辨率的增加来实现的,而EfficientNet的方法则是通过一系列固定的缩放系数来同时增加这三个维度。例如,如果想要使用更多的计算资源,可以通过增加网络深度、宽度和图像大小的特定比例来实现,其中的比例系数是通过在小型模型上进行小规模的网格搜索确定的。

EfficientNet的复合缩放方法的直觉在于,如果输入图像更大,网络就需要更多的层来增加感受野,以及更多的通道来捕捉更细粒度的模式。EfficientNet的架构本质上并不复杂。基本的EfficientNet-B0网络作为后续缩放的基础。作者指出,他们使用NAS来构建基本网络,利用了多目标搜索来同时优化网络的准确性和计算效率。

Datawhale的点拨

Part5 一些思路

  1. 多帧提取,面部识别,相似比较。

  2. 音频fake:通过Task1的MEL刻度,我们可以发现Deepfake的结果有着不自然的重复。

  3. 特征提取:还有其它可用的特征吗?总不能只在一棵树上死磕。

  • 30
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值