多模态纯新手入门,这篇是学习Datawhale AI夏令营围绕kaggle的Deepfake攻防挑战赛开展的多模态教学项目的笔记。包括了解Deepfake和熟悉Baseline。kaggle比赛链接:https://www.kaggle.com/competitions/multi-ffdv
1 Deepfake是什么?
Deepfake是一种使用人工智能技术生成的伪造媒体。这种技术通常涉及到深度学习算法,特别是生成对抗网络(GANs),它们能够学习真实数据的特征,并生成新的、逼真的数据。
Deepfake技术虽然在多个领域展现出其创新潜力,但其滥用也带来了一系列严重的危害。在政治领域,Deepfake可能被用来制造假新闻或操纵舆论。经济上,它可能破坏企业形象,引发市场恐慌,甚至操纵股市。法律体系中,伪造的证据可能误导司法判断。此外,深度伪造技术还可能加剧身份盗窃的风险,成为恐怖分子的新工具,煽动暴力和社会动荡,威胁国家安全。
深度伪造技术通常可以分为四个主流研究方向:
- 面部交换专注于在两个人的图像之间执行身份交换;
- 面部重演强调转移源运动和姿态;
- 说话面部生成专注于在角色生成中实现口型与文本内容的自然匹配;
- 面部属性编辑旨在修改目标图像的特定面部属性;
2 人工识别Deepfake
人工识别Deepfake的图片,可以通过以下步骤:
- 首先,观察图片的细节。仔细检查人物的面部特征,尤其是眼睛和嘴巴,看是否有不自然的眨眼频率或口型与说话内容不同步的现象。
- 接着,检查光线和阴影。分析图片中的光源是否一致,阴影的方向是否与光源相符,不自然的光线或阴影可能是图片被修改的迹象。
- 然后,分析像素。放大图片,寻找是否有模糊或像素化的部分,这可能是Deepfake技术留下的瑕疵。
- 此外,注意背景。检查背景中是否有不协调的元素,比如物体边缘是否平滑,背景中是否有不自然的重复模式。
3 深度学习与Deepfake
深度学习模型,尤其是卷积神经网络(CNN),能够识别图像和视频中的复杂特征。在Deepfake检测中,模型可以学习识别伪造内容中可能存在的微妙异常。
为了训练有效的Deepfake检测模型,需要构建包含各种Deepfake和真实样本的数据集(本次比赛的数据集就是按照这种方式进行组织)。深度学习模型通过这些数据集学习区分真假内容。
4 Baseline 关键步骤
- 数据准备:使用Pandas库读取训练集和验证集的标签,并将图片路径与标签结合,以便于后续处理。
- 定义生成MEL频谱图的函数:**
generate_mel_spectrogram
函数**用于从视频文件中提取音频,并生成MEL频谱图,然后将其转换为图像格式。 - 定义训练、验证和预测函数:
train
、validate
和predict
函数分别用于模型的训练、在验证集上评估模型性能以及生成预测结果。 - 模型初始化和训练:初始化
r**esnet18**
模型,并使用Adam优化器和交叉熵损失函数进行训练。训练过程中使用了学习率调度器,并在每个epoch结束时在验证集上评估模型性能。 - 保存最佳模型:在验证过程中,如果模型的性能超过了之前的最佳性能,则保存模型的权重。
- 生成预测结果:使用训练好的模型对验证集进行预测,并将预测结果保存到
submit.csv
文件中。 - 提交结果:最后,代码将预测的分数与原始的提交模板合并,并保存为最终的提交文件。
加载预训练模型
baseline中预训练模型采用的是ResNet-18。ResNet(残差网络)是一种深度卷积神经网络。ResNet的核心思想是引入了“残差学习”框架,通过添加跳过一层或多层的连接(即残差连接或快捷连接),解决了随着网络深度增加时训练困难的问题。
在下面代码中,
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()
提取音频特征
在识别Deepfake视频时,音频分析之所以简单,是因为Deepfake技术生成的视频中,音频可能存在不自然或重复的模式,例如重复的单词或短语。通过分析音频的频谱图,可以更容易地发现这些异常,从而帮助识别视频是否经过了深度伪造处理。
MEL频谱图(Mel-spectrogram)是一种在音频信号处理领域常用的可视化工具,它基于人耳的听觉特性来表示音频信号的频率内容。梅尔刻度是一种对频率进行非线性缩放的方法,它将线性频率映射到梅尔频率上,使得梅尔刻度上的间隔更接近人耳感知的间隔。
def generate_mel_spectrogram(video_path, n_mels=128, fmax=8000, target_size=(256, 256)):
# 提取音频
audio_path = 'extracted_audio.wav'
video = mp.VideoFileClip(video_path)
video.audio.write_audiofile(audio_path, verbose=False, logger=None)
# 加载音频文件
y, sr = librosa.load(audio_path)
# 生成MEL频谱图
S = librosa.feature.melspectrogram(y=y, sr=sr, n_mels=n_mels)
# 将频谱图转换为dB单位
S_dB = librosa.power_to_db(S, ref=np.max)
# 归一化到0-255之间
S_dB_normalized = cv2.normalize(S_dB, None, 0, 255, cv2.NORM_MINMAX)
# 将浮点数转换为无符号8位整型
S_dB_normalized = S_dB_normalized.astype(np.uint8)
# 缩放到目标大小
img_resized = cv2.resize(S_dB_normalized, target_size, interpolation=cv2.INTER_LINEAR)
return img_resized
定义模型训练步骤
在深度学习中,模型训练通常需要进行多次迭代,而不是单次完成。深度学习模型的训练本质上是一个优化问题,目标是最小化损失函数。梯度下降算法通过计算损失函数相对于模型参数的梯度来更新参数。由于每次参数更新只能基于一个数据批次来计算梯度,因此需要多次迭代,每次处理一个新的数据批次,以确保模型在整个数据集上都能得到优化。
模型训练的流程如下:
- 设置训练模式:通过调用
model.train()
将模型设置为训练模式。在训练模式下,模型的某些层(如BatchNorm
和Dropout
)会按照它们在训练期间应有的方式运行。 - 遍历数据加载器:使用
enumerate(train_loader)
遍历train_loader
提供的数据批次。input
是批次中的图像数据,target
是对应的标签。 - 数据移动到GPU:通过
.cuda(non_blocking=True)
将数据和标签移动到GPU上。non_blocking
参数设置为True
意味着如果数据正在被复制到GPU,此操作会立即返回,不会等待数据传输完成。 - 前向传播:通过
output = model(input)
进行前向传播,计算模型对输入数据的预测。 - 计算损失:使用损失函数
loss = criterion(output, target)
计算预测输出和目标标签之间的差异。 - 梯度归零:在每次迭代开始前,通过
optimizer.zero_grad()
清空(重置)之前的梯度,以防止梯度累积。 - 反向传播:调用
loss.backward()
计算损失相对于模型参数的梯度。 - 参数更新:通过
optimizer.step()
根据计算得到的梯度更新模型的参数。
def train(train_loader, model, criterion, optimizer, epoch):
# switch to train mode
model.train()
end = time.time()
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()
数据集增强
数据增强是一种在机器学习和深度学习中提升模型性能的重要技术。它通过应用一系列随机变换来增加训练数据的多样性,从而提高模型的泛化能力。增加数据多样性是数据增强的核心目的。通过对原始图像进行如旋转、缩放、翻转等操作,可以生成新的训练样本,使模型学习到更丰富的特征表示。
transforms.Compose: 这是一个转换操作的组合,它将多个图像预处理步骤串联起来:
transforms.Resize((256, 256))
:将所有图像调整为256x256像素的大小。transforms.RandomHorizontalFlip()
:随机水平翻转图像。transforms.RandomVerticalFlip()
:随机垂直翻转图像。transforms.ToTensor()
:将PIL图像或Numpy数组转换为torch.FloatTensor
类型,并除以255以将像素值范围从[0, 255]缩放到[0, 1]。transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
:对图像进行标准化,使用ImageNet数据集的均值和标准差。
train_loader = torch.utils.data.DataLoader(
FFDIDataset(train_label['path'], train_label['target'],
transforms.Compose([
transforms.Resize((256, 256)),
transforms.RandomHorizontalFlip(),
transforms.RandomVerticalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
), batch_size=40, shuffle=True, num_workers=4, pin_memory=True
)
5 常见的图像分类网络
图像分类是计算机视觉中的一个基本任务,它涉及到将给定的图像分配到一个或多个预定义的类别中。随着深度学习的发展,已经设计出许多不同的卷积神经网络(CNN)架构来提高图像分类的准确率。
AlexNet,https://en.wikipedia.org/wiki/AlexNet
AlexNet是一种具有深远影响的卷积神经网络(CNN)架构,由Alex Krizhevsky、Ilya Sutskever和Geoffrey Hinton设计。
AlexNet包含八个层次结构,前五个是卷积层,其中一些后跟最大池化层,最后三个是全连接层。具体结构如下:
- 卷积层:AlexNet的前五个层次都是卷积层,每个卷积层后面跟着一个ReLU激活函数,以引入非线性。这些卷积层旨在提取图像的特征。
- 局部响应归一化(LRN):在某些卷积层后使用了局部响应归一化,这是一种提高模型泛化能力的正则化方法。
- 最大池化层:在部分卷积层之后使用最大池化层来降低特征的空间维度,减少计算量和过拟合的风险。
- 全连接层:网络的最后三个层次是全连接层,其中最后两个全连接层后跟有Dropout,以进一步防止过拟合。
- 输出层:最后一个全连接层后是线性层,然后是softmax激活函数,输出1000个类别上的概率分布。
ResNet,https://en.wikipedia.org/wiki/Residual_neural_network
ResNet(残差网络)是一种深度卷积神经网络架构,由微软研究院的研究员何恺明等人提出。ResNet在2015年的ImageNet图像识别大赛中取得了冠军,并在深度学习领域产生了重大影响。它的主要创新点是引入了残差学习的概念,允许训练非常深的网络,从而缓解了深度神经网络训练中的梯度消失和梯度爆炸问题。
ResNet的核心是残差块(residual block),网络通过堆叠这些残差块来构建。一个基本的残差块包含以下几部分:
- 跳跃连接(Skip Connections):这是ResNet最关键的创新,通过跳跃连接,输入可以直接绕过一个或多个层传到输出,输出是输入与这些层的输出的加和。这种结构使得网络可以学习输入到输出的残差,而不是直接学习输出,这有助于缓解梯度消失问题。
- 卷积层:残差块内部包含多个卷积层,通常使用小尺寸的卷积核(如3x3),并且通常会有批量归一化(Batch Normalization)和ReLU激活函数。
- 池化层:在某些残差块之间会插入最大池化层来降低特征图的空间维度。
ResNet有多个变种,包括ResNet-50、ResNet-101、ResNet-152等,数字代表了网络中权重层的数量。
这些变种在网络的深度和宽度上有所不同,但都基于相同的残差学习架构。
ResNet能够成功训练超过100层的网络,这在之前是不可能实现的。
在ImageNet竞赛中,ResNet取得了3.57%的错误率,远低于之前的表现最好的模型。
EfficientNet,https://paperswithcode.com/method/efficientnet
EfficientNet是一种高效的卷积神经网络(CNN)架构,它通过一种新颖的网络缩放方法来提升模型的性能和效率。EfficientNet 的核心是其 compound scaling 方法,该方法通过一个复合系数统一缩放网络的深度、宽度和分辨率。在过去,网络缩放通常是通过任意选择深度、宽度或分辨率的增加来实现的,而EfficientNet的方法则是通过一系列固定的缩放系数来同时增加这三个维度。例如,如果想要使用更多的计算资源,可以通过增加网络深度、宽度和图像大小的特定比例来实现,其中的比例系数是通过在小型模型上进行小规模的网格搜索确定的。
EfficientNet的复合缩放方法的直觉在于,如果输入图像更大,网络就需要更多的层来增加感受野,以及更多的通道来捕捉更细粒度的模式。EfficientNet的架构本质上并不复杂。基本的EfficientNet-B0网络作为后续缩放的基础。作者指出,他们使用NAS来构建基本网络,利用了多目标搜索来同时优化网络的准确性和计算效率。
6 数据增强
通过对训练数据进行多样化的变换,我们可以模拟更真实的世界场景,从而帮助模型更好地泛化,这在提升模型在未见数据上的表现方面起着至关重要的作用。在竞赛和实际应用中,精心设计的数据增强方案往往能够成为获胜的关键。
实操代码地址
- [九月]Deepfake-FFDI-plot_transforms_illustrations: https://www.kaggle.com/code/chg0901/deepfake-ffdi-plot-transforms-illustrations
- original:https://www.kaggle.com/finlay/deepfake-ffdi-ch3
Part1 数据增强基础
数据增强的目的是通过人工方式增加训练数据的多样性,从而提高模型的泛化能力,使其能够在未见过的数据上表现得更好。数据增强涉及对原始数据进行一系列的变换操作,生成新的训练样本。这些变换模拟了真实世界中的变化,对于图像而言,数据增强包括例如视角、光照、遮挡等情况,使得模型能够学习到更加鲁棒的特征表示。
但同时,如果数据增强的变换操作与目标任务的实际场景不符,比如在不需要旋转的图像任务中过度使用旋转,那么这些变换可能会引入无关的噪音。此外过度的数据增强,比如极端的亮度调整、对比度变化或大量的噪声添加,可能会导致图像失真,使得模型难以学习到有效的特征。
在之前的代码中我们使用PyTorch框架来加载和增强图像数据:
- 图像大小调整:使用
transforms.Resize((256, 256))
将所有图像调整到256x256像素的尺寸,这有助于确保输入数据的一致性。 - 随机水平翻转:
transforms.RandomHorizontalFlip()
随机地水平翻转图像,这种变换可以模拟物体在不同方向上的观察,从而增强模型的泛化能力。 - 随机垂直翻转:
transforms.RandomVerticalFlip()
随机地垂直翻转图像,这同样是为了增加数据多样性,让模型能够学习到不同视角下的特征。 - 转换为张量:
transforms.ToTensor()
将图像数据转换为PyTorch的Tensor格式,这是在深度学习中处理图像数据的常用格式。 - 归一化:
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
对图像进行归一化处理,这里的均值和标准差是根据ImageNet数据集计算得出的,用于将图像像素值标准化,这有助于模型的训练稳定性和收敛速度。
train_loader = torch.utils.data.DataLoader(
FFDIDataset(train_label['path'].head(1000), train_label['target'].head(1000),
transforms.Compose([
transforms.Resize((256, 256)),
transforms.RandomHorizontalFlip(),
transforms.RandomVerticalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
), batch_size=40, shuffle=True, num_workers=4, pin_memory=True
)
val_loader = torch.utils.data.DataLoader(
FFDIDataset(val_label['path'].head(1000), val_label['target'].head(1000),
transforms.Compose([
transforms.Resize((256, 256)),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
), batch_size=40, shuffle=False, num_workers=4, pin_memory=True
)
在深度学习中,对输入数据进行归一化是一个标准步骤。归一化有助于加快模型的收敛速度,并提高数值稳定性。对于验证集,应该避免使用如随机翻转等可能引入不必要噪音的增强方法。通常,验证集只需要进行必要的预处理,比如调整大小和归一化。
Part2 图像数据增强方法
torchvision是一个流行的开源Python包,它提供了许多用于深度学习计算机视觉任务的工具和预训练模型。在torchvision中,数据增强方法主要位于
torchvision.transforms
和
torchvision.transforms.v2
模块中。这些增强方法可以用于图像分类、目标检测、图像分割和视频分类等各种任务。
几何变换
- 调整大小:
Resize
可以将图像调整到指定的大小。 - 随机裁剪:
RandomCrop
和RandomResizedCrop
可以随机裁剪图像。 - 中心裁剪:
CenterCrop
从图像的中心裁剪出指定大小。 - 五裁剪和十裁剪:
FiveCrop
和TenCrop
分别裁剪出图像的四个角和中心区域。 - 翻转:
RandomHorizontalFlip
和RandomVerticalFlip
可以水平或垂直翻转图像。 - 旋转:
RandomRotation
可以随机旋转图像。 - 仿射变换:
RandomAffine
可以进行随机的仿射变换。 - 透视变换:
RandomPerspective
可以进行随机的透视变换。
颜色变换
- 颜色抖动:
ColorJitter
可以随机改变图像的亮度、对比度、饱和度和色调。 - 灰度化:
Grayscale
和RandomGrayscale
可以将图像转换为灰度图。 - 高斯模糊:
GaussianBlur
可以对图像进行高斯模糊。 - 颜色反转:
RandomInvert
可以随机反转图像的颜色。 - 颜色 posterize:
RandomPosterize
可以减少图像中每个颜色通道的位数。 - 颜色 solarize:
RandomSolarize
可以反转图像中所有高于阈值的像素值。
自动增强
- 自动增强:
AutoAugment
可以根据数据集自动学习数据增强策略。 - 随机增强:
RandAugment
可以随机应用一系列数据增强操作。 - TrivialAugmentWide:提供与数据集无关的数据增强。
- AugMix:通过混合多个增强操作进行数据增强。
Mixup
MixUp是一种数据增强技术,其原理是通过将两个不同的图像及其标签按照一定的比例混合,从而创建一个新的训练样本。MixUp方法中**混合比例(
alpha
)是一个超参数**。
alpha
是一个在0到1之间的值,表示混合的比例。例如,
alpha=0.5
意味着两个图像各占新图像的一半。
MixUp的混合过程包括以下步骤:
- 从训练集中随机选择两个图像和它们的标签。
- 将这两个图像按照
alpha
的比例混合,得到一个新的图像。 - 将这两个标签按照相同的
alpha
比例混合,得到一个新的标签。
MixUp方法具有以下几个优点:
- 增加数据多样性:通过混合不同的图像和标签,MixUp可以创建更多样化的训练样本,帮助模型学习到更加鲁棒的特征表示。
- 减少过拟合:MixUp可以减少模型对特定训练样本的依赖,从而降低过拟合的风险。
- 提高泛化能力:MixUp可以帮助模型学习到更加泛化的特征表示,从而提高模型在未见过的数据上的表现。
Cutmix
CutMix是一种数据增强技术,它通过将一个图像的一部分剪切并粘贴到另一个图像上来创建新的训练样本。同时,它也会根据剪切区域的大小来调整两个图像的标签。
CutMix方法中,剪切和粘贴操作是关键步骤。具体来说,剪切和粘贴过程包括以下步骤:
- 从训练集中随机选择两个图像和它们的标签。
- 随机选择一个剪切区域的大小和位置。
- 将第一个图像的剪切区域粘贴到第二个图像上,得到一个新的图像。
- 根据剪切区域的大小,计算两个图像的标签的加权平均值,得到一个新的标签。
Part3 音频数据增强方法
https://pytorch.org/audio/stable/tutorials/audio_data_augmentation_tutorial.html
音频数据增强的原理与图像数据增强类似,都是通过对原始数据进行一系列的变换操作,生成新的训练样本。这些变换模拟了真实世界中的变化,例如时间尺度、音调、噪声、房间环境等,使得模型能够学习到更加鲁棒的特征表示。
- 时间拉伸和压缩:改变音频的时间尺度,模拟不同的说话速度或音乐播放速度。
- 音调变换:改变音频的音调,模拟不同的说话人或乐器。
- 添加噪声:向音频中添加不同类型的噪声,如白噪声、粉红噪声等,以提高模型对噪声的抗干扰能力。
- 频率掩码和时间掩码:在频谱图上随机掩盖一些频率或时间区域,迫使模型学习到更加鲁棒的特征表示。
- 混响:模拟不同的房间环境,增加音频的丰富性。
- 声道分离:将多声道音频中的某些声道分离出来,训练模型对不同声道特征的学习。
- 音量调整:调整音频的音量,模拟不同的音量大小。
7 一些思路
- 从音频处理:抽取音频--生成频谱图--图像二分类
- 从图片处理:按帧数抽取图片--计算相似度差异--直方图
- 多模态
难点:数据集很大,视频有100GB。
版权归原作者 墨香温存 所有, 如有侵权,请联系我们删除。