Partage de technologie

[Pratique d'apprentissage automatique] Datawhale Summer Camp 2 : attaque et défense audio et vidéo (deepfake) Explication de la phrase de base

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

#Datawhale #AIsummercamp#summercamp

1. Brève introduction aux questions du concours

La tâche du concours est de déterminer si une image de visage est une image Deepfake et d'obtenir un score de probabilité indiquant qu'il s'agit d'une image Deepfake. Les participants doivent développer et optimiser des modèles de détection pour faire face à diverses technologies de génération de deepfake et à des scénarios d'application complexes, améliorant ainsi la précision et la robustesse de la détection d'images deepfake.

2. Ensemble de données sur les questions de compétition

Le fichier d'étiquette train_label.txt de l'ensemble de formation est utilisé pour entraîner le modèle, tandis que le fichier d'étiquette val_label.txt de l'ensemble de validation n'est utilisé que pour le réglage du modèle. Par exemple, dans train_label.txt ou val_label.txt, chaque ligne contient deux parties séparées par des virgules. La première partie est le nom du fichier (suffixe .mp4), la deuxième partie est la valeur réelle.
Une valeur cible de 1 indique un son et une vidéo profondément faux, et une valeur cible de 0 indique un son et une vidéo de visage réel.

Vous trouverez ci-dessous des exemples de train_label.txt et val_label.txt :

train_label.txt

video_name,target
96b04c80704f02cb426076b3f624b69e.mp4,0
16fe4cf5ae8b3928c968a5d11e870360.mp4,1
  • 1
  • 2
  • 3
  • 4
  • 5

val_label.txt

video_name,target
f859cb3510c69513d5c57c6934bc9968.mp4,0
50ae26b3f3ea85babb2f9dde840830e2.mp4,1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Chaque ligne du fichier contient deux parties séparées par des virgules. La première partie est le nom du fichier vidéo et la deuxième partie est le score deepfake correspondant à la prédiction du modèle (c'est-à-dire la valeur de probabilité de l'échantillon appartenant à la vidéo deepfake). Veuillez vous référer au modèle de soumission ci-dessous :

prediction.csv

video_name,score
658042526e6d0c199adc7bfeb1f7c888.mp4,0.123456
a20cf2d7dea580d0affc4d85c9932479.mp4,0.123456
  • 1
  • 2
  • 3
  • 4
  • 5

La deuxième phase fait suite à la première phase, au cours de laquelle l'ensemble de tests publics est publié. Les participants doivent soumettre le fichier de score de prédiction prédiction_test.csv de l'ensemble de tests au système et commenter les résultats du test en ligne en temps réel.

Après la deuxième étape, les 30 meilleures équipes passeront à la troisième étape. À ce stade, les candidats doivent soumettre un code docker et des rapports techniques. Les exigences de Docker incluent le code de formation d'origine et l'API de test (l'entrée de la fonction est le chemin de l'image et la sortie est le score deepfake prédit par le modèle). Le sponsor vérifiera et réexécutera le code de l'algorithme pour reproduire le processus de formation et les résultats des tests.

Un seul modèle peut être soumis et les paramètres réseau valides ne doivent pas dépasser 200 M (utilisezhouhouParamètres du modèle de statistiques d'outil).

Seule la formation pré-modèle avec ImageNet1K est autorisée. Des échantillons étendus générés sur la base de l'ensemble de formation publié (via des outils d'augmentation de données/deepfake) peuvent être utilisés pour la formation, mais ces outils doivent être soumis pour reproduction lors de la troisième étape.

3. Indicateurs d'évaluation

L'indice d'évaluation utilise principalement l'AUC sous la courbe ROC comme indice. La plage de valeurs de l'AUC se situe généralement dans les limites.0.5-1entre, sinon on penseCe n'est pas un bon modèle d'apprentissage automatique . Plus l’AUC est proche de 1, meilleur est le modèle. Si l'AUC présente des résultats de classement ambigus, nous utilisons alors le **TPR (taux de vrais positifs)** comme référence auxiliaire. Bien entendu, la méthode correspondante est FPR.

Score F1C'est aussi un indicateur auquel on peut se référer : c'est le taux de précision et le taux de rappelmoyenne harmonique

F 1 _ S noyau = 2 ∗ ( TP ) / ( 2 TP + FN + FP ) F1_Score = 2*(TP)/(2TP+FN+FP)F1_Scœur=2(TP)/(2TP+FN+PF)

Avant d’apprendre l’apprentissage automatique, nous devons revoir deux concepts importants :PrécisionetRappel

Précision Précision = TPTP + FP Précision = frac{TP}{TP+FP}Precjemjeouuuuuun=TP+PFTP, qui est utilisé pour mesurer le modèleVérifier les performances, la proportion d'échantillons qui devraient être positifs parmi les échantillons correctement prédits.

Rappel Rappel = TPTP + FN Rappel = frac{TP}{TP+FN}Rceunll=TP+FNTP, qui est utilisé pour mesurer le modèlePerformances de recherche, la proportion d'échantillons réellement positifs parmi les échantillons qui devraient être positifs.

Taux de vrais positifs (TPR) :
TPR = TP / (TP + FN)
Taux de faux positifs (FPR) :
FPR = FP / (FP + TN)
dans:
TP : L'échantillon d'attaque est correctement identifié comme une attaque ;
TN : Les échantillons réels sont correctement identifiés comme étant réels ;
FP : Des échantillons réels sont identifiés à tort comme des attaques ;
FN : L'échantillon d'attaque est identifié à tort comme étant réel.

Références : Aghajan, H., Augusto, JC et Delgado, RLC (Eds.) (Si le lien indiqué dans le titre ne peut pas être ouvert, veuillez cliquer :livre entier)

Voici mon script de calcul TPR :

l1 = [0,1,1,1,0,0,0,1]
l2 = [0,1,0,1,0,1,0,0]

def accuracy(y_true, y_pred):
    # 正确预测数初始化一个简单计数器
    correct_counter = 0
    # 遍历y_true, y_pred中所有元素
    # zip函数接受多个元组,返回他们组成的列表
    for yt, yp in zip(y_true, y_pred):
        if yt == yp:
            # 如果预测标签与真实标签相同,则增加计数器
            correct_counter += 1
    # 返回正确率,正确标签数/总标签数
    return correct_counter / len(y_true)
    
def false_positive(y_true, y_pred):
    # 初始化假阳性样本计数器
    fp = 0
    # 遍历y_true,y_pred中所有元素
    for yt, yp in zip(y_true, y_pred):
        # 若真实标签为负类但预测标签为正类,计数器增加
        if yt == 0 and yp == 1:
            fp += 1
    return fp

def false_negative(y_true, y_pred):
    # 初始化假阴性样本计数器
    fn = 0
    # 遍历y_true,y_pred中所有元素
    for yt, yp in zip(y_true, y_pred):
        # 若真实标签为正类但预测标签为负类,计数器增加
        if yt == 1 and yp == 0:
            fn += 1
    return fn
    
def true_positive(y_true, y_pred):
    # 初始化真阳性样本计数器
    tp = 0
    # 遍历y_true,y_pred中所有元素
    for yt, yp in zip(y_true, y_pred):
        # 若真实标签为正类且预测标签也为正类,计数器增加
        if yt == 1 and yp == 1:
            tp += 1
    return tp

def true_negative(y_true, y_pred):
    # 初始化真阴性样本计数器
    tn = 0
    # 遍历y_true,y_pred中所有元素
    for yt, yp in zip(y_true, y_pred):
        # 若真实标签为负类且预测标签也为负类,计数器增加
        if yt == 0 and yp == 0:
            tn += 1
    # 返回真阴性样本数
    return tn
    
# 您可以尝试更好的精确度计算方式
def accuracy_v2(y_true, y_pred):
  # 真阳性样本数
  tp = true_positive(y_true, y_pred)
  # 假阳性样本数
  fp = false_positive(y_true, y_pred)
  # 假阴性样本数
  fn = false_negative(y_true, y_pred)
  # 真阴性样本数
  tn = true_negative(y_true, y_pred)
  # 准确率
  accuracy_score = (tp + tn) / (tp + tn + fp + fn)
  return accuracy_score
  
# F1-score的计算方法
def f1(y_true,y_pred):
    p = precision(y_true, y_pred)
    r = recall(y_true,y_pred)
    score = 2*p*r/(p+r)
    return score
    

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

Si une classification est requise, vous aurez peut-être besoin d'un seuil. Sa relation avec la valeur prédite est la suivante :

Prédiction = Probabilité > Seuil Prédiction = Probabilité > SeuilPconcernantdjectjeouuuuuun=Probébéljetet>Thréshouuuuuuld

Après avoir appris l'AUC, une autre mesure importante que vous devriez apprendre est la perte de journal. Pour les problèmes de classification binaire, nous définissons la perte de log comme :

L og Perte = − cible ∗ log ( p ) − ( 1 − cible ) ∗ log ( 1 − p ) LogPerte = -cible*log(p) - (1-cible)*log(1-p)LouuuuuugLos=tunlgetttlouuuuuug(p)(1tunlgettt)louuuuuug(1p)

Parmi elles, la valeur cible est 0 ou 1, et la valeur prédite est la probabilité que l'échantillon appartienne à la catégorie 1. La perte de log pénalise à la fois les prédictions très certaines et très fausses. Plus la perte logarithmique est faible, plus la probabilité prédite par le modèle est proche de la valeur cible.

On peut également utiliser ces indicateurs dans des problèmes de classification :

  • Précision macro-moyenne: Calculez la précision de toutes les catégories séparément, puis faites la moyenne
  • Précision micro-moyenne: Calculez la précision de toutes les catégories, puis calculez leur moyenne pondérée.
  • Précision pondérée : Calculez la précision de toutes les catégories, puis calculez leur moyenne pondérée. La moyenne pondérée est le produit des poids de chaque catégorie.

4. Base de référence globale

4.1 Calculer le nombre d'échantillons

# “word count” 的缩写,是一个用于计数的 Unix 命令。-l 只计算行数
!wc -l /kaggle/input/ffdv-sample-dataset/ffdv_phase1_sample/train_label.txt
!wc -l /kaggle/input/ffdv-sample-dataset/ffdv_phase1_sample/val_label.txt
  • 1
  • 2
  • 3

Il suffit de compter le nombre de lignes, ce qui indique le nombre d'échantillons.

4.2 Créer un objet vidéo

from IPython.display import Video
Video("/kaggle/input/ffdv-sample-dataset/ffdv_phase1_sample/valset/00882a2832edbcab1d3dfc4cc62cfbb9.mp4", embed=True)
  • 1
  • 2

Video crée un objet vidéo et embed signifie que lorsqu'il est défini sur True, le lecteur vidéo sera affiché directement dans la sortie de la cellule du bloc-notes.
Après avoir exécuté la ligne de base de Kaggle, vous devriez voir des résultats comme celui-ci :
Insérer la description de l'image ici

4.3 Téléchargez les bibliothèques requises et les connaissances supplémentaires

!pip install moviepy librosa matplotlib numpy timm
  • 1

Liens de documentation pour les bibliothèques utilisées :
filmpy
libraire(librosa est une bibliothèque tierce très puissante pour le traitement du signal vocal Python. Dans cette ligne de base, nous utilisons principalement la génération de spectrogrammes MEL et la conversion de spectrogrammes)
matplotlib
numpy
Timothée(Bibliothèque de modèles de classification d'images, créez rapidement divers modèles sota)

Qu’est-ce que SOTA ? Le nom complet de SOTA est State of the arts, qui fait référence au meilleur modèle en la matière. SOTA obtient des scores très élevés sur certains ensembles de données de référence.

Modèle non de bout en bout (pipeline) : Tout d'abord, nous devons comprendre ce qu'est une fin. Les deux extrémités font référence à l'extrémité d'entrée à l'extrémité de sortie. Le processus d'apprentissage automatique traditionnel se compose de plusieurs modules indépendants les uns des autres. Le résultat de ce dernier module dépend du niveau du résultat précédent, affectant l'ensemble du résultat de la formation.
Modèle de bout en bout (de bout en bout) : Tout d'abord, vous devez comprendre que la prédiction est générée de l'extrémité d'entrée à l'extrémité de sortie. Ce résultat de prédiction aura une erreur par rapport au résultat réel (il faut s'en souvenir). que la tâche principale de l'apprentissage automatique est toujoursprédire ), cette erreur se propage à chaque couche du réseau neuronal, et les poids et paramètres du modèle sont ajustés jusqu'à ce que le modèle converge ou que les résultats attendus soient obtenus. Si nous l’examinons en termes de système de contrôle, il s’agit d’un système de contrôle en boucle fermée. (par exemple, réseau neuronal BP)
Séquence à séquence (seq2seq) : il s'agit d'une méthode généralede bout en boutMéthode de prédiction de séquence, sa structure est un encodeur et un décodeur. Si vous utilisez l'ensemble de données de questions et réponses pour encoder/décoder, vous pouvez obtenir un robot de questions et réponses. Il s'agit d'une application séquence à séquence.

La question revient à Baseline elle-même, qu’est-ce que Baseline ?La référence fait généralement référence à un modèle de référence simple et facile à mettre en œuvre.
Dans le processus de réglage de l'algorithme et d'ajustement des paramètres, la tâche de Baseline est de se comparer à lui-même pour améliorer de plus en plus le modèle.

Le benchmark est aussi un concept important, sa signification estRepères . Il fait généralement référence à une méthode standardisée d'évaluation et de comparaison des performances d'algorithmes, de modèles ou de méthodes, utilisée pour mesurer les différences entre les modèles.

Vous pouvez les voir fréquemment sur les sites Web d’analyse comparative des modèles.Par exempleSi Nan

4.4 Définir la configuration des graines aléatoires et&CUDNN de pytorch

Lorsque j'ai exécuté la ligne de base, une erreur de configuration CUDA s'est produite. Veuillez utiliser un autre accélérateur :

Insérer la description de l'image ici

import torch
# 设置pytorch的种子
torch.manual_seed(0)
# deterministic当设置为False时,cuDNN将允许一些操作的非确定性优化
torch.backends.cudnn.deterministic = False
# benchmark设置为true允许cuDNN在每个前向传播中自动寻找最适合当前配置的卷积算法,以提高性能。
torch.backends.cudnn.benchmark = True
# 导入必要的库,我们需要用到cv2,glob,os,PIL
import torchvision.models as models
import torchvision.transforms as transforms
import torchvision.datasets as datasets
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.autograd import Variable
from torch.utils.data.dataset import Dataset
import timm
import time

import pandas as pd
import numpy as np
import cv2, glob, os
from PIL import Image
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

4.5 Prétraitement audio et vidéo

Les paramètres acceptés par generate_mel_spectrogram incluent le chemin du fichier vidéo, le nombre de filtres pour diviser la fréquence Mel, la fréquence la plus élevée (contrôlant la plage spectrale calculée) et la taille de l'image cible.

import moviepy.editor as mp
import librosa
import numpy as np
import cv2

def generate_mel_spectrogram(video_path, n_mels=128, fmax=8000, target_size=(256, 256)):
    # 提取音频
    audio_path = 'extracted_audio.wav'
    # video_path 应该是之前定义的变量,包含了要处理的视频文件的路径。创建了一个 VideoFileClip 对象,存储在 video 变量中。
    video = mp.VideoFileClip(video_path)
    # video.audio 访问视频的音频轨道。write_audiofile() 方法将音频写入文件。verbose=False: 设置为False表示不在控制台输出处理进度。logger=None: 设置为None表示不使用日志记录器。实际上我们做这个预测没有这样的需求,也就不消耗占存。
    # 其默认参数:write_audiofile(self, filename, fps=None, nbytes=2, buffersize=2000, codec=None, bitrate=None, ffmpeg_params=None, write_logfile=False, verbose=True, logger='bar')
    video.audio.write_audiofile(audio_path, verbose=False, logger=None)

    # 加载音频文件,加载采样率
    y, sr = librosa.load(audio_path)

    # 生成MEL频谱图(梅尔频谱图,与之相对应的有mel倒频谱图)
    # 默认参数:librosa.feature.melspectrogram(y=None, sr=22050, S=None, n_fft=2048, hop_length=512, power=2.0, **kwargs)
    # 参数解释:y:音频时间序列,sr:采样率,n_mels 是指在计算梅尔频谱图时,将频谱图划分为多少个梅尔频率滤波器(Mel filters),其决定了最终生成的梅尔频谱图的分辨率,也可以理解为梅尔频谱图的高度。
    S = librosa.feature.melspectrogram(y=y, sr=sr, n_mels=n_mels)

    # 将频谱图转换为dB单位,S:输入功率,ref:作为参考,如果是标量,则振幅 abs(S) 相对于 ref: 10 * log10(S / ref) 进行缩放。此处np.max指的是将谱图中的最大值作为参考值,这也是一种常用的参考值取法
    S_dB = librosa.power_to_db(S, ref=np.max)

    # 归一化到0-255之间,NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化。
    S_dB_normalized = cv2.normalize(S_dB, None, 0, 255, cv2.NORM_MINMAX)
    
    # 将浮点数转换为无符号8位整型
    S_dB_normalized = S_dB_normalized.astype(np.uint8)

    # 缩放到目标大小256,256
    img_resized = cv2.resize(S_dB_normalized, target_size, interpolation=cv2.INTER_LINEAR)

    return img_resized

# 使用示例
video_path = '/kaggle/input/ffdv-sample-dataset/ffdv_phase1_sample/trainset/001b0680999447348bc9f89efce0f183.mp4'  # 替换为您的视频文件路径
mel_spectrogram_image = generate_mel_spectrogram(video_path)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

4.6 Créer un dossier de données d'entraînement

!mkdir ffdv_phase1_sample
!mkdir ffdv_phase1_sample/trainset
!mkdir ffdv_phase1_sample/valset
  • 1
  • 2
  • 3

4.7 Générer un spectrogramme Mel

La quantité de données est trop énorme, je ne publierai donc pas de photo ici, mais je publierai un diagramme de Mel dans des circonstances normales :
Insérer la description de l'image ici
Source des images :Université Simon Fraser
Si vous l'allumez et l'écoutez, c'est un morceau audio qui diminue progressivement.

# 使用glob.glob函数查找/kaggle/input/ffdv-sample-dataset/ffdv_phase1_sample/trainset/目录下前400个.mp4视频文件的路径。
for video_path in glob.glob('/kaggle/input/ffdv-sample-dataset/ffdv_phase1_sample/trainset/*.mp4')[:400]:
    mel_spectrogram_image = generate_mel_spectrogram(video_path)
    cv2.imwrite('./ffdv_phase1_sample/trainset/' + video_path.split('/')[-1][:-4] + '.jpg', mel_spectrogram_image)
# a. 调用generate_mel_spectrogram(video_path)函数生成梅尔频谱图,并将其存储在mel_spectrogram_image变量中。b. 使用cv2.imwrite函数将梅尔频谱图保存为JPEG图像。图像被保存在./ffdv_phase1_sample/trainset/目录下,并使用与原始视频文件相同的名称(但扩展名改为.jpg)。
for video_path in glob.glob('/kaggle/input/ffdv-sample-dataset/ffdv_phase1_sample/valset/*.mp4'):
    mel_spectrogram_image = generate_mel_spectrogram(video_path)
    cv2.imwrite('./ffdv_phase1_sample/valset/' + video_path.split('/')[-1][:-4] + '.jpg', mel_spectrogram_image)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

4.8 Définir AverageMeter et ProgressMeter

La classe AverageMeter est utilisée pour calculer et stocker la valeur moyenne et actuelle d'une variable.

  • name : Le nom de la variable.
  • fmt : chaîne de format, utilisée pour la sortie formatée.
  • reset() : réinitialise toutes les statistiques (val, avg, sum, count).
  • update(val, n=1) : mettre à jour les statistiques, val est la valeur actuelle et n est le poids de la valeur (généralement le nombre d'échantillons).
  • str() : renvoie une chaîne formatée, comprenant la valeur actuelle et la valeur moyenne.
class AverageMeter(object):
    """Computes and stores the average and current value"""
    def __init__(self, name, fmt=':f'):
        self.name = name
        self.fmt = fmt
        self.reset()

    def reset(self):
        self.val = 0
        self.avg = 0
        self.sum = 0
        self.count = 0

    def update(self, val, n=1):
        self.val = val
        self.sum += val * n
        self.count += n
        self.avg = self.sum / self.count

    def __str__(self):
        fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})'
        return fmtstr.format(**self.__dict__)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

La classe ProgressMeter est utilisée pour générer des informations de lot actuelles et des indicateurs statistiques pendant le processus de formation.

  • num_batches : nombre total de lots.
  • mètres : une liste contenant des objets AverageMeter utilisés pour stocker différentes métriques.
  • prefix : Le préfixe de la ligne de sortie.
  • print(batch) : Imprime les informations du lot actuel, y compris le numéro de lot actuel et la valeur actuelle de chaque indicateur.
  • _get_batch_fmtstr(num_batches) : génère des chaînes de format par lots pour garantir l'alignement et le formatage de la sortie.
class ProgressMeter(object):
   def __init__(self, num_batches, *meters):
       self.batch_fmtstr = self._get_batch_fmtstr(num_batches)
       self.meters = meters
       self.prefix = ""


   def pr2int(self, batch):
       entries = [self.prefix + self.batch_fmtstr.format(batch)]
       entries += [str(meter) for meter in self.meters]
       print('t'.join(entries))

   def _get_batch_fmtstr(self, num_batches):
       num_digits = len(str(num_batches // 1))
       fmt = '{:' + str(num_digits) + 'd}'
       return '[' + fmt + '/' + fmt.format(num_batches) + ']'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

4.9 Processus d'apprentissage profond et d'évaluation des modèles (points clés)

La fonction de validation évalue régulièrement les performances du modèle sur l'ensemble de validation pendant le processus de formation, et calcule et imprime la précision Top-1.

def validate(val_loader, model, criterion):
    batch_time = AverageMeter('Time', ':6.3f')# 批处理时间
    losses = AverageMeter('Loss', ':.4e')# 损失
    top1 = AverageMeter('Acc@1', ':6.2f')# Top-1准确率
    progress = ProgressMeter(len(val_loader), batch_time, losses, top1)# 输出ProgressMeter

    # switch to evaluate mode,eval()为评估函数,关闭训练时使用的一些特定层(如 Dropout),并启用 Batch Normalization 层的运行统计。
    model.eval()

    with torch.no_grad():# 定时设置requires_grad为False,防止梯度计算并节省内存。
        end = time.time()
        for i, (input, target) in enumerate(val_loader):
            input = input.cuda()# 将输入数据和目标数据转移到GPU计算
            target = target.cuda()

            # compute output
            output = model(input)
            loss = criterion(output, target)# 计算训练损失

            # measure accuracy and record loss,acc百分比显示
            acc = (output.argmax(1).view(-1) == target.float().view(-1)).float().mean() * 100
            losses.update(loss.item(), input.size(0))
            top1.update(acc, input.size(0))
            # measure elapsed time
            batch_time.update(time.time() - end)
            end = time.time()

        # TODO: this should also be done with the ProgressMeter
        print(' * Acc@1 {top1.avg:.3f}'
              .format(top1=top1))
        return top1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

La fonction de prédiction est utilisée pour effectuer des inférences sur l'ensemble de test et prend en charge l'utilisation de l'augmentation du temps de test (TTA) pour améliorer la stabilité des prédictions du modèle en effectuant plusieurs prédictions et en faisant des moyennes.

def predict(test_loader, model, tta=10):
    # switch to evaluate mode
    model.eval()
    # TTA(Test Time Augmentation)
    test_pred_tta = None
    for _ in range(tta):# 执行 TTA 次数的循环,每次循环会生成一个略有不同的输入数据。
        test_pred = []
        with torch.no_grad():
            end = time.time()
            for i, (input, target) in enumerate(test_loader):
                input = input.cuda()
                target = target.cuda()

                # compute output
                output = model(input)
                output = F.softmax(output, dim=1)# 对模型输出进行 softmax 归一化处理,以获得类别概率。
                output = output.data.cpu().numpy()

                test_pred.append(output)
        test_pred = np.vstack(test_pred)
    
        if test_pred_tta is None:
            test_pred_tta = test_pred
        else:
            test_pred_tta += test_pred
    
    return test_pred_tta
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

La fonction d'entraînement est chargée de former le modèle, de mettre à jour les paramètres du modèle en calculant la fonction de perte et la précision, et d'effectuer des étapes de rétropropagation et d'optimisation.

def train(train_loader, model, criterion, optimizer, epoch):
    batch_time = AverageMeter('Time', ':6.3f')
    losses = AverageMeter('Loss', ':.4e')
    top1 = AverageMeter('Acc@1', ':6.2f')
    progress = ProgressMeter(len(train_loader), batch_time, losses, top1)

    # 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)

        # measure accuracy and record loss
        losses.update(loss.item(), input.size(0))

        acc = (output.argmax(1).view(-1) == target.float().view(-1)).float().mean() * 100
        top1.update(acc, input.size(0))# 更新 top1 计量器,记录当前批次的准确率。

        # compute gradient and do SGD step
        optimizer.zero_grad() # 清除之前累积的梯度。
        loss.backward()# 计算损失相对于模型参数的梯度
        optimizer.step()# 根据 backward() 计算的梯度更新模型参数。

        # measure elapsed time
        batch_time.update(time.time() - end)# 更新 batch_time 计量器,记录当前批次的处理时间。
        end = time.time()

        if i % 100 == 0:
            progress.pr2int(i)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

4.10 Charger des étiquettes pour les ensembles de données de formation et de validation

train_label = pd.read_csv("/kaggle/input/ffdv-sample-dataset/ffdv_phase1_sample/train_label.txt")
val_label = pd.read_csv("/kaggle/input/ffdv-sample-dataset/ffdv_phase1_sample/val_label.txt")

train_label['path'] = '/kaggle/working/ffdv_phase1_sample/trainset/' + train_label['video_name'].apply(lambda x: x[:-4] + '.jpg')
val_label['path'] = '/kaggle/working/ffdv_phase1_sample/valset/' + val_label['video_name'].apply(lambda x: x[:-4] + '.jpg')

train_label = train_label[train_label['path'].apply(os.path.exists)]
val_label = val_label[val_label['path'].apply(os.path.exists)]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

4.11 Chargement d'images et conversion d'images

transform laisse un paramètre pour l'amélioration ultérieure des données, et la valeur par défaut est Aucun.
L'image est convertie en mode RVB.
Les étiquettes sont renvoyées sous forme de torch.Tensor.

class FFDIDataset(Dataset):
    def __init__(self, img_path, img_label, transform=None):
        self.img_path = img_path
        self.img_label = img_label
        
        if transform is not None:
            self.transform = transform
        else:
            self.transform = None
    
    def __getitem__(self, index):
        img = Image.open(self.img_path[index]).convert('RGB')
        
        if self.transform is not None:
            img = self.transform(img)
        
        return img, torch.from_numpy(np.array(self.img_label[index]))
    
    def __len__(self):
        return len(self.img_path)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

4.12 Mettre en place le processus de formation (points clés)

Fait référence à la classe FFDID définie ci-dessus.

train_loader = torch.utils.data.DataLoader(
    FFDIDataset(train_label['path'].values, train_label['target'].values, 
            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=12, pin_memory=True
)

val_loader = torch.utils.data.DataLoader(
    FFDIDataset(val_label['path'].values, val_label['target'].values, 
            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=10, pin_memory=True
)
# 重点:这里调用timm提供的resnet18模型,因为分类为0/1(真视频/假视频),可以在后续改进,比如换用更深的网络ResNet-34、ResNet-50或是其他变体
model = timm.create_model('resnet18', pretrained=True, num_classes=2)
model = model.cuda()

# 交叉熵损失,针对多类别
criterion = nn.CrossEntropyLoss().cuda()
# Adam优化器,学习率设置为0.003。
optimizer = torch.optim.Adam(model.parameters(), 0.003)
# 每4个epoch将学习率按0.85的因子进行调整。
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=4, gamma=0.85)
# 初始化最优acc
best_acc = 0.0
for epoch in range(10):
    scheduler.step()
    print('Epoch: ', epoch)
	# 调用train函数
    train(train_loader, model, criterion, optimizer, epoch)
    # 调用validate函数
    val_acc = validate(val_loader, model, criterion)
    
    if val_acc.avg.item() > best_acc:
        best_acc = round(val_acc.avg.item(), 2)
        torch.save(model.state_dict(), f'./model_{best_acc}.pt')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

Sortir:

Epoch:  0
[ 0/10]	Time  6.482 ( 6.482)	Loss 7.1626e-01 (7.1626e-01)	Acc@1  35.00 ( 35.00)
 * Acc@1 64.000
Epoch:  1
[ 0/10]	Time  0.819 ( 0.819)	Loss 4.6079e-01 (4.6079e-01)	Acc@1  80.00 ( 80.00)
 * Acc@1 75.500
Epoch:  2
[ 0/10]	Time  0.914 ( 0.914)	Loss 1.4983e-01 (1.4983e-01)	Acc@1  97.50 ( 97.50)
 * Acc@1 88.500
Epoch:  3
[ 0/10]	Time  0.884 ( 0.884)	Loss 2.4681e-01 (2.4681e-01)	Acc@1  87.50 ( 87.50)
 * Acc@1 84.000
Epoch:  4
[ 0/10]	Time  0.854 ( 0.854)	Loss 5.3736e-02 (5.3736e-02)	Acc@1 100.00 (100.00)
 * Acc@1 90.500
Epoch:  5
[ 0/10]	Time  0.849 ( 0.849)	Loss 5.9881e-02 (5.9881e-02)	Acc@1  97.50 ( 97.50)
 * Acc@1 89.500
Epoch:  6
[ 0/10]	Time  0.715 ( 0.715)	Loss 1.6215e-01 (1.6215e-01)	Acc@1  92.50 ( 92.50)
 * Acc@1 65.000
Epoch:  7
[ 0/10]	Time  0.652 ( 0.652)	Loss 5.3892e-01 (5.3892e-01)	Acc@1  80.00 ( 80.00)
 * Acc@1 78.500
Epoch:  8
[ 0/10]	Time  0.847 ( 0.847)	Loss 6.6098e-02 (6.6098e-02)	Acc@1  97.50 ( 97.50)
 * Acc@1 81.000
Epoch:  9
[ 0/10]	Time  0.844 ( 0.844)	Loss 9.4254e-02 (9.4254e-02)	Acc@1  97.50 ( 97.50)
 * Acc@1 81.500
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

4.12.1 Idées pour améliorer le modèle resnet18

Réseaux plus profonds : si vous avez besoin de performances plus élevées et de capacités d'extraction de fonctionnalités plus complexes, vous pouvez envisager d'utiliser des réseaux plus profonds tels que ResNet-34, ResNet-50 ou des variantes ResNet encore plus grandes (telles que ResNet-101 ou ResNet-152).

Autres modèles pré-entraînés : en plus de la série ResNet, il existe de nombreux autres modèles pré-entraînés parmi lesquels choisir, tels que :

EfficientNet : offre d'excellentes performances et une excellente efficacité des paramètres.
DenseNet : une structure de réseau densément connectée permet de mieux utiliser les fonctionnalités.
Série VGG : Architecture simple et classique, adaptée à une utilisation sous contraintes de ressources.
Modèle personnalisé : en fonction des caractéristiques spécifiques de l'ensemble de données et des exigences de la tâche, vous pouvez également envisager de concevoir et de former une architecture de modèle personnalisée, ce qui peut nécessiter davantage de débogage et d'expérimentation.

Apprentissage d'ensemble : envisagez d'utiliser des méthodes d'apprentissage d'ensemble telles que le bagging ou le boosting pour combiner les prédictions de plusieurs modèles afin d'améliorer encore les performances et la stabilité.

Réglage des hyperparamètres : en plus de la sélection du modèle, les performances du modèle peuvent également être optimisées en ajustant le taux d'apprentissage, la taille du lot, la sélection de l'optimiseur et les stratégies d'augmentation des données.

4.12.2 Amélioration de la sélection de la fonction de perte

Envisagez d'appliquer Dice Loss pour améliorer la fonction de perte à l'avenir. Dice Loss mesure la similarité entre le résultat de la prédiction et le masque cible et convient mieux aux tâches de classification binaire avec des limites évidentes. Il s’agit d’une fonction de perte qui fonctionne mieux en termes de prédiction au niveau des pixels.

Gardez également un œil sur la perte focale. Spécialement conçu pour résoudre le problème du déséquilibre des classes, il peut encore améliorer les performances du modèle sur les catégories minoritaires en réduisant le poids des échantillons faciles à classer pour se concentrer sur les échantillons difficiles.

4.12.3 Améliorations de la sélection des optimiseurs

RAdam est une amélioration par rapport à Adam qui améliore la stabilité et les performances en ajustant dynamiquement la correction du taux d'apprentissage.

AdamW est une variante d'Adam qui introduit une dégradation du poids pour résoudre les problèmes de performances qu'Adam peut introduire dans certains cas, notamment lorsque le nombre de paramètres du modèle est important.

AdamW est une variante d'Adam qui introduit une dégradation du poids pour résoudre les problèmes de performances qu'Adam peut introduire dans certains cas, notamment lorsque le nombre de paramètres du modèle est important.

4.13 Modèle d'évaluation

# 用模型 (model) 对验证数据集 (val_loader) 进行预测。这部分假设 [:, 1] 给出了类别1的概率。
val_pred = predict(val_loader, model, 1)[:, 1]
# 赋值,预测的概率(或者预测值)赋给了 val_label 数据框中名为 "y_pred" 的列
val_label["y_pred"] = val_pred
  • 1
  • 2
  • 3
  • 4

4.14 Intégration de l'ensemble de données final

submit = pd.read_csv("/kaggle/input/multi-ffdv/prediction.txt.csv")
# 使用 merge 函数将提交文件 (submit) 中的数据与验证数据集标签 (val_label) 中的 video_name 和 y_pred 列合并
merged_df = submit.merge(val_label[['video_name', 'y_pred']], on='video_name', suffixes=('', '_df2'), how='left', )
# 将合并后的数据中 y_pred_df2 列(从验证集中获取的预测结果)的值填充到 y_pred 列中
merged_df['y_pred'] = merged_df['y_pred_df2'].combine_first(merged_df['y_pred'])
merged_df[['video_name', 'y_pred']].to_csv('submit.csv', index=None)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

5. Conclusion

Il ne faut pas 10 minutes pour terminer l'exécution de la ligne de base. Elle sera généralement bloquée à 4,7 pour générer le spectrogramme Mel. Mais cela demande 5 heures d’exploration patiente. Voici un résumé silencieux des processus clés :

  • Calculer le nombre d'échantillons
  • Créer des objets audio et vidéo
  • Importer un ensemble de données d'entraînement
  • Importer des données audio et vidéo
  • Définir une graine aléatoire/CUDNN
  • Prétraitement audio et vidéo
  • Générer un spectrogramme mel
  • Définir les méthodes d'ensemble de validation, d'ensemble de prédiction et d'ensemble d'entraînement
  • conversion d'images
  • Utiliser la formation SOTA, modèle d'optimisation-évaluation fourni par timm

6. Développer

6.1 Définition des tâches de l'apprentissage profond

La définition de la tâche de l'apprentissage profond peut en fait être résumée par « rétro-propagation », car son cœur est d'utiliser l'algorithme de rétro-propagation pour ajuster les paramètres du modèle afin de minimiser la fonction de perte définie.

Il est très approprié d'utiliser l'apprentissage profond pour gérer de telles tâches audio et vidéo. Je pense que le premier est l'énorme quantité de données audio et vidéo et la nécessité d'une classification complexe de ces données.Le mécanisme de l'apprentissage profond détermine qu'il nécessite une énorme quantité de données, et en fait, un point très important est que le deepfake lui-même nécessiteClassificationLa pensée est essentiellement une tâche de classification, et l'apprentissage profond présente de grands avantages dans les grands volumes de données et la classification raffinée. Un exemple familier est le réseau de génération contradictoire GAN.

Deuxièmement, des données statistiquement similaires sont créées en grande quantité et peuvent apprendre la distribution d'énormes quantités de données. Il peut également effectuer la tâche inverse.

6.2 La relation entre AIGC et Deepfake

Insérer la description de l'image ici

AIGC devrait inclure Deepfake. Du point de vue du développement, le développement et la dimensionnalité de la technologie Deepfake augmenteront certainement avec la puissance de traitement de l'AIGC. Nous serons confrontés à une vaste mer de données réelles et fausses. Bien sûr, nous devons également voir à quoi sert. ces vidéos l'est. Si elle peut sauver L'énergie des créateurs d'histoires est sans aucun doute bénéfique au développement du divertissement littéraire et artistique, si elle est utilisée à des fins de tromperie, elle sera bientôt confrontée à des défis éthiques et moraux.

L'une de mes pensées est que, s'il est combiné à l'engouement actuel pour les courts métrages dramatiques, Deepfake peut permettre au public d'obtenir une expérience de divertissement audiovisuel à très faible coût, mais il remet également en question l'industrie traditionnelle du cinéma et de la télévision et même le type d'acteurs. et la stimulation audiovisuelle dont les yeux humains ont besoin. C'est un sujet discutable.