Compartir tecnología

[Práctica de aprendizaje automático] Datawhale Summer Camp 2: Ataque y defensa de audio y video (deepfake) Explicación de la oración base

2024-07-12

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

#Datawhale #AIsummercamp#summercamp

1. Breve introducción a las preguntas del concurso.

La tarea del concurso es determinar si una imagen de rostro es una imagen Deepfake y generar una puntuación de probabilidad de que sea una imagen Deepfake. Los participantes deben desarrollar y optimizar modelos de detección para hacer frente a diversas tecnologías de generación de deepfake y escenarios de aplicaciones complejos, mejorando así la precisión y solidez de la detección de imágenes de deepfake.

2. Conjunto de datos de preguntas de competencia

El archivo de etiqueta train_label.txt del conjunto de entrenamiento se usa para entrenar el modelo, mientras que el archivo de etiqueta val_label.txt del conjunto de validación solo se usa para ajustar el modelo. Por ejemplo, en train_label.txt o val_label.txt, cada línea contiene dos partes, separadas por comas. La primera parte es el nombre del archivo (sufijo .mp4), la segunda parte es el valor real.
Un valor objetivo de 1 indica audio y vídeo falsos, y un valor objetivo de 0 indica audio y vídeo de rostros reales.

A continuación se muestran ejemplos de train_label.txt y 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

Cada línea del archivo contiene dos partes, separadas por comas. La primera parte es el nombre del archivo de video y la segunda parte es la puntuación de deepfake correspondiente a la predicción del modelo (es decir, el valor de probabilidad de la muestra que pertenece al video de deepfake). Consulte la plantilla de envío a continuación:

prediction.csv

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

La segunda fase sigue a la primera, en la que se lanza el conjunto de pruebas públicas. Los participantes deben enviar el archivo de puntuación de predicción predict_test.csv del conjunto de pruebas al sistema y enviar comentarios sobre los resultados de la prueba en línea en tiempo real.

Después de la segunda etapa, los 30 mejores equipos avanzarán a la tercera etapa. En esta etapa, los concursantes deben enviar informes técnicos y de código acoplable. Los requisitos de Docker incluyen el código de entrenamiento original y la API de prueba (la entrada de la función es la ruta de la imagen y la salida es la puntuación deepfake predicha por el modelo). El patrocinador verificará y volverá a ejecutar el código del algoritmo para reproducir el proceso de capacitación y los resultados de las pruebas.

Solo se permite enviar un modelo y los parámetros de red válidos no deben exceder los 200 M (usegolpeParámetros del modelo de estadísticas de la herramienta).

Solo se permite el entrenamiento previo al modelo con ImageNet1K. Se pueden usar muestras extendidas generadas en base al conjunto de capacitación publicado (a través de herramientas de aumento de datos/deepfake) para la capacitación, pero estas herramientas deben enviarse para su reproducción en la tercera etapa.

3. Indicadores de evaluación

El índice de evaluación utiliza principalmente el AUC bajo la curva ROC como índice. El rango de valores del AUC suele estar dentro.0.5-1entre, de lo contrario pensamosEste no es un buen modelo de aprendizaje automático. . Cuanto más cerca esté el AUC de 1, mejor será el modelo. Si AUC presenta resultados de clasificación ambiguos, utilizamos **TPR (tasa de verdaderos positivos)** como referencia auxiliar. Por supuesto, el método correspondiente es FPR.

Puntuación F1También es un indicador al que podemos referirnos: es la tasa de precisión y la tasa de recuperación.Significado armonico

F 1 _ S núcleo = 2 ∗ ( TP ) / ( 2 TP + FN + FP ) F1_Puntuación = 2*(TP)/(2TP+FN+FP)F1_Scentro=2(TP)/(2TP+Enero 2016+FP)

Antes de aprender el aprendizaje automático debemos revisar dos conceptos importantes:ExactitudyRecordar

Exactitud Precisión = TPTP + FP Precisión = frac{TP}{TP+FP}PAGAGAGRecreoisionorteorte=TP+FPTP, que se utiliza para medir el modeloComprobar rendimiento, la proporción de muestras que se predice que serán positivas entre las muestras predichas correctamente.

Recordar R ecordar = TPTP + FN R ecordar = frac{TP}{TP+FN}RCEatodos=TP+Enero 2016TP, que se utiliza para medir el modeloRendimiento de búsqueda, la proporción de muestras que son realmente positivas entre las muestras que se predice que serán positivas.

Tasa de verdaderos positivos (TPR):
TPR = TP / (TP + FN)
Tasa de falsos positivos (FPR):
FPR = FP / (FP + TN)
en:
TP: La muestra de ataque se identifica correctamente como un ataque;
TN: Las muestras reales se identifican correctamente como reales;
FP: Muestras reales se identifican erróneamente como ataques;
FN: La muestra del ataque se identifica incorrectamente como real.

Referencias: Aghajan, H., Augusto, JC y Delgado, RLC (Eds. (2009) (Si no se puede abrir el enlace que figura en el título, haga clic en:Todo el libro)

Aquí está mi script de cálculo de 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 se requiere clasificación, es posible que necesite un umbral. Su relación con el valor previsto es la siguiente:

P redicción = P robabilidad > Umbral P redicción = P robabilidad > UmbralPAGAGAGrediCaionorteorte=PAGAGAGroBebéyoiay>yoyoresyooyod

Después de aprender AUC, otra métrica importante que debes aprender es la pérdida de registros. Para problemas de clasificación binaria, definimos la pérdida de registros como:

Pérdida de registro = − objetivo ∗ log ( p ) − ( 1 − objetivo ) ∗ log ( 1 − p ) Pérdida de registro = -objetivo*log(p) - (1-objetivo)*log(1-p)yoogLóseo=aaagramoramoramoramomiayoogramoramoramoramo(pagag)(1aaagramoramoramoramomia)yoogramoramoramoramo(1pagag)

Entre ellos, el valor objetivo es 0 o 1 y el valor predicho es la probabilidad de que la muestra pertenezca a la categoría 1. La pérdida de registros penaliza tanto las predicciones muy ciertas como las muy incorrectas. Cuanto menor sea la pérdida logarítmica, más cercana estará la probabilidad predicha por el modelo al valor objetivo.

También podemos utilizar estos indicadores en problemas de clasificación:

  • Precisión macropromediada: Calcule la precisión de todas las categorías por separado y luego promedie
  • Precisión micropromediada: Calcule la precisión de todas las categorías y luego calcule su promedio ponderado.
  • Precisión ponderada : Calcule la precisión de todas las categorías y luego calcule su promedio ponderado. El promedio ponderado es el producto de los pesos de cada categoría.

4. Línea de base general

4.1 Calcular el número de muestras.

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

Solo necesitamos contar el número de filas, lo que indica el número de muestras.

4.2 Crear objeto de vídeo

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

Video crea un objeto de video e incrustar significa que cuando se establece en Verdadero, el reproductor de video se mostrará directamente en la salida de la celda del cuaderno.
Después de ejecutar la línea base de Kaggle, deberías ver resultados como este:
Insertar descripción de la imagen aquí

4.3 Descargue las bibliotecas y los conocimientos complementarios necesarios

!pip install moviepy librosa matplotlib numpy timm
  • 1

Enlaces de documentación para las bibliotecas utilizadas:
película
librosa(librosa es una biblioteca de terceros muy potente para el procesamiento de señales de voz de Python. En esta línea de base utilizamos principalmente la generación y conversión de espectrogramas MEL)
Matplotlib (Libro de trabajo matplot)
Numeroso
Tim(Biblioteca de modelos de clasificación de imágenes, cree rápidamente varios modelos sota)

¿Qué es SOTA? El nombre completo de SOTA es State of the arts, que hace referencia al mejor modelo en este campo. SOTA obtiene puntuaciones muy altas en algunos conjuntos de datos de referencia.

Modelo sin extremo a extremo (tubería): en primer lugar, debemos entender qué es un extremo. Los dos extremos se refieren desde el extremo de entrada al extremo de salida. El proceso de aprendizaje automático tradicional consta de múltiples módulos, que son independientes entre sí. El resultado del último módulo depende del nivel del resultado anterior, lo que afecta todo el resultado del entrenamiento.
Modelo de extremo a extremo (de extremo a extremo): en primer lugar, debe comprender que la predicción se genera desde el extremo de entrada hasta el extremo de salida. En comparación con el resultado real, el resultado de esta predicción tendrá un error (debe recordarse). que la tarea central del aprendizaje automático sigue siendopredecir ), este error se propaga a cada capa de la red neuronal y los pesos y parámetros del modelo se ajustan hasta que el modelo converge o se obtienen los resultados que esperamos. Si lo miramos en términos de un sistema de control, este es un sistema de control de circuito cerrado. (por ejemplo, red neuronal BP)
Secuencia a secuencia (seq2seq): Esta es una generalde extremo a extremoMétodo de predicción de secuencia, su estructura es un codificador y un decodificador. Si utiliza el conjunto de datos de preguntas y respuestas para codificar/decodificar, puede obtener un robot de preguntas y respuestas. Esta es una aplicación de secuencia a secuencia.

La pregunta se remonta al propio Baseline: ¿qué es Baseline?La línea de base generalmente se refiere a un modelo de línea de base simple y fácil de implementar.
En el proceso de ajuste del algoritmo y ajuste de parámetros, la tarea de Baseline es compararse consigo mismo para hacer que el modelo sea cada vez mejor.

El punto de referencia también es un concepto importante, su significado esPuntos de referencia . Suele referirse a un método estandarizado de evaluación y comparación del desempeño de algoritmos, modelos o métodos, utilizado para medir las diferencias entre modelos.

Puede verlos con frecuencia en sitios web de evaluación comparativa de modelos.Por ejemploSi nan

4.4 Establecer la configuración de semilla aleatoria y CUDNN de pytorch

Cuando ejecuté la línea de base, se produjo un error de configuración de CUDA. Utilice otro acelerador:

Insertar descripción de la imagen aquí

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 Preprocesamiento de audio y video

Los parámetros aceptados por generate_mel_spectrogram incluyen la ruta del archivo de video, la cantidad de filtros para dividir la frecuencia Mel, la frecuencia más alta (que controla el rango del espectro calculado) y el tamaño de la imagen de destino.

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 Crear carpeta de datos de entrenamiento

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

4.7 Generar espectrograma Mel

La cantidad de datos es demasiado grande, por lo que no publicaré una imagen aquí, sino un diagrama de Mel en circunstancias normales:
Insertar descripción de la imagen aquí
Fuente de imagen:Universidad Simon Fraser
Si lo enciendes y lo escuchas es un fragmento de audio que va disminuyendo poco a poco.

# 使用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 Definir AverageMeter y ProgressMeter

La clase AverageMeter se utiliza para calcular y almacenar el valor promedio y actual de una variable.

  • nombre: El nombre de la variable.
  • fmt: cadena de formato, utilizada para salida formateada.
  • reset(): Restablece todas las estadísticas (val, avg, sum, count).
  • actualización (val, n = 1): actualiza las estadísticas, val es el valor actual y n es el peso del valor (generalmente el número de muestras).
  • cadena(): Devuelve una cadena formateada, incluido el valor actual y el valor promedio.
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 clase ProgressMeter se utiliza para generar información de lotes actuales e indicadores estadísticos durante el proceso de capacitación.

  • num_batches: número total de lotes.
  • metros: una lista que contiene objetos AverageMeter utilizados para almacenar diferentes métricas.
  • prefijo: el prefijo de la línea de salida.
  • imprimir (lote): imprime la información del lote actual, incluido el número de lote actual y el valor actual de cada indicador.
  • _get_batch_fmtstr (num_batches): genera cadenas de formato por lotes para garantizar la alineación y el formato de salida.
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 Proceso de evaluación de modelos y aprendizaje profundo (puntos clave)

La función de validación evalúa periódicamente el rendimiento del modelo en el conjunto de validación durante el proceso de entrenamiento y calcula e imprime la precisión 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 función de predicción se utiliza para hacer inferencias sobre el conjunto de pruebas y admite el uso de aumento del tiempo de prueba (TTA) para mejorar la estabilidad de las predicciones del modelo mediante la realización de múltiples predicciones y promediaciones.

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 función de tren es responsable de entrenar el modelo, actualizar los parámetros del modelo calculando la función de pérdida y la precisión, y realizar pasos de optimización y retropropagación.

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 Cargar etiquetas para conjuntos de datos de entrenamiento y validación

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 Carga de imágenes y conversión de imágenes

transform deja un parámetro para la mejora posterior de los datos y el valor predeterminado es Ninguno.
La imagen se convierte al modo RGB.
Las etiquetas se devuelven como antorcha.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 Configurar el proceso de capacitación (puntos clave)

Hace referencia a la clase FFDID establecida anteriormente.

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

Producción:

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 Ideas para mejorar el modelo resnet18

Redes más profundas: si necesita un mayor rendimiento y capacidades de extracción de características más complejas, puede considerar el uso de redes más profundas como ResNet-34, ResNet-50 o variantes de ResNet incluso más grandes (como ResNet-101 o ResNet-152).

Otros modelos previamente entrenados: además de la serie ResNet, hay muchos otros modelos previamente entrenados para elegir, como por ejemplo:

EfficientNet: tiene un excelente rendimiento y eficiencia de parámetros.
DenseNet: la estructura de red densamente conectada ayuda a utilizar mejor las funciones.
Serie VGG: Arquitectura simple y clásica, adecuada para su uso con limitaciones de recursos.
Modelo personalizado: según las características específicas del conjunto de datos y los requisitos de la tarea, también puede considerar diseñar y entrenar una arquitectura de modelo personalizada, lo que puede requerir más depuración y experimentación.

Aprendizaje en conjunto: considere utilizar métodos de aprendizaje en conjunto, como embolsado o impulso, para combinar las predicciones de múltiples modelos para mejorar aún más el rendimiento y la estabilidad.

Ajuste de hiperparámetros: además de la selección del modelo, el rendimiento del modelo también se puede optimizar ajustando la tasa de aprendizaje, el tamaño del lote, la selección del optimizador y las estrategias de aumento de datos.

4.12.2 Mejora en la selección de la función de pérdida

Considere aplicar Dice Loss para mejorar la función de pérdida en el futuro. Dice Loss mide la similitud entre el resultado de la predicción y la máscara objetivo, y es mejor para tareas de clasificación binaria con límites obvios. Es una función de pérdida que funciona mejor en la predicción a nivel de píxeles.

También esté atento a la pérdida focal. Diseñado específicamente para resolver el problema del desequilibrio de clases, puede mejorar aún más el rendimiento del modelo en categorías minoritarias al reducir el peso de muestras fáciles de clasificar para centrarse en muestras difíciles.

4.12.3 Mejoras en la selección del optimizador

RAdam es una mejora de Adam que mejora la estabilidad y el rendimiento al ajustar dinámicamente la corrección de la tasa de aprendizaje.

AdamW es una variante de Adam que introduce una disminución de peso para resolver los problemas de rendimiento que Adam puede introducir en algunos casos, especialmente cuando la cantidad de parámetros del modelo es grande.

AdamW es una variante de Adam que introduce una disminución de peso para resolver los problemas de rendimiento que Adam puede introducir en algunos casos, especialmente cuando la cantidad de parámetros del modelo es grande.

4.13 Modelo de evaluación

# 用模型 (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 Integración del conjunto de datos 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. Conclusión

No se necesitan 10 minutos para terminar de ejecutar la línea de base. Por lo general, estará bloqueado en 4,7 para generar el espectrograma Mel. Pero se necesitan 5 horas de exploración del paciente. Aquí hay un resumen silencioso de los procesos clave:

  • Calcular el número de muestras.
  • Crear objetos de audio y vídeo.
  • Importar conjunto de datos de entrenamiento
  • Importar datos de audio y vídeo
  • Establecer semilla aleatoria/CUDNN
  • Preprocesamiento de audio y vídeo.
  • Generar espectrograma mel
  • Definir métodos de conjunto de validación, conjunto de predicción y conjunto de entrenamiento
  • conversión de imagen
  • Utilice el modelo de evaluación de optimización y capacitación SOTA proporcionado por timm

6. Ampliar

6.1 Definición de tareas de aprendizaje profundo

La definición de tarea del aprendizaje profundo en realidad se puede resumir como "propagación hacia atrás", porque su núcleo es utilizar el algoritmo de propagación hacia atrás para ajustar los parámetros del modelo para minimizar la función de pérdida definida.

Es muy adecuado utilizar el aprendizaje profundo para manejar este tipo de tareas de audio y video. Creo que el primero es la gran cantidad de datos de audio y video y la necesidad de una clasificación compleja de estos datos.El mecanismo del aprendizaje profundo determina que requiere una gran cantidad de datos y, de hecho, un punto muy importante es que el propio deepfake requiereClasificaciónEl pensamiento es esencialmente una tarea de clasificación, y el aprendizaje profundo tiene grandes ventajas en grandes volúmenes de datos y clasificación refinada. Un ejemplo familiar es la red de generación adversaria GAN.

En segundo lugar, se crean grandes cantidades de datos estadísticamente similares y se puede aprender la distribución de grandes cantidades de datos. También puede realizar la tarea inversa.

6.2 La relación entre AIGC y Deepfake

Insertar descripción de la imagen aquí

AIGC debería incluir Deepfake. Desde una perspectiva de desarrollo, el desarrollo y la dimensionalidad de la tecnología Deepfake definitivamente aumentarán con el poder de procesamiento de AIGC. Nos enfrentaremos a un vasto mar de datos reales y falsos. Por supuesto, también debemos ver cuál es su propósito. Si estos videos pueden salvar la energía de los creadores de historias, sin duda serán beneficiosos para el desarrollo del entretenimiento literario y artístico; si se utilizan para engañar, pronto enfrentarán desafíos éticos y morales;

Uno de mis pensamientos es que si se combina con la moda actual de los dramas cortos, Deepfake puede permitir al público obtener una experiencia de entretenimiento audiovisual de costo ultra bajo, pero también desafía a la industria tradicional del cine y la televisión e incluso a qué tipo de actores. y estimulación audiovisual que los ojos humanos necesitan. Este es un tema discutible.