최종 5등 solution
생성 딥러닝 모델의 발전으로 유용한 형태의 데이터를 생성할 수 있게 되었지만 동시에 우리는 지능형 사이버 위협에 노출되어있다. 특히 원본 영상을 변조하여 생성되는 딥페이크(DeepFake) 영상은 진위 여부를 가리기 여러워 적으로부터 보안, 국방에서의 심각한 공격으로 이어질 수 있다. 따라서 원본 영상과 딥페이크 영상을 구분하는 AI 모델을 설계하여 이러한 위협으로부터 기술적으로 탈피하고자 하는 것을 목표로 한다.
- 학습 데이터의 구조는 아래와 같다.
dataset/
- train/
- fake/
- fake_video_1.mp4
...
- fake_video_3500.mp4
- real/
- real_video_1.mp4
...
- real_video_3500.mp4
- test/
- video_1.mp4
...
- 학습데이터는 3500개의 fake video와 3500개의 real video로 구성되어 있다.
- real 데이터는 15초에서부터 1분 50초 까지 다양한 길이를 가진다.
- fake 데이터는 대부분 15-20초 내외의 길이를 가진다.
- 영상은 제한된 환경에서 촬영된 것으로 보인다.
- 정지한 화자의 얼굴이 화면 정 중앙에 등장하고 정해진 대사를 말하는 것으로 보인다.
- 오디오는 없다.
- Fake 비디오의 경우 얼굴 부분의 눈코입만 변조된 것 처럼 보였다.
- Fake 비디오의 형태로 미루어보아 Keypoint Detection 이후에 target에 붙여넣기 하는 방식으로 만들어진 DeepFake로 추정된다.
- 우리가 찾아야하는 DeepFake는 영상의 중앙에만 존재하기 때문에 YOLO v5 모델로 얼굴을 detect 하여 사용
- YOLO v5 모델은 얼굴이 아닌 사람 class만 존재해 얼굴보다 더 넓은 영역을 탐지하므로, 탐지영역의 약 50% 영역을 CenterCrop 하여 사용
- 이 방법을 적용하고 72%에서 90%까지 Public Accuracy 성능 향상이 있었음
- DeepFake에서 느낄 수 있는 어색함은 source face와 target face 사이의 색감이 불일치하여 발생
- 이것을 정량적으로 나타내는 Co-occurrence matrix를 도입하여 같이 모델에 적용
아래 세가지 방법 사용을 고민
- 3D Conv for some frames
- CNN + RNN or Transformer for video
- CNN for one frame
제한된 시간아래에서 모든 방법론을 시도해보지 못할 것 같아 하나의 방법을 정해서 대회기간동안 시도
하나의 영상이 DeepFake로 만들어진 영상이면 모든 프레임에 DeepFake가 적용되었다고 판단하여 3의 방법을 채택
GAN based or Diffusion으로 Deepfake 영상을 생성하기 때문에 관련 논문을 탐색하였음 On the detection of synthetic images generated by diffusion model 논문을 통해 저수준에서의 특정한 pattern이 존재하며 저수준의 정보를 보존하고, 활용하는 방법을 사용해야겠다고 생각하였음.
최종적으로 Detecting GAN generated Fake Images using Co-occurrence Matrices의 방법론과 FCN을 사용하기로 결정하였음
Co-occurence
# rgb이미지 픽셀의 상하좌우 4방향으로 co-occurrence matrices를 반환하는 함수
def _get_co_occurrence_matrix(self, frames):
frames = torch.squeeze(frames, 0) # (3,256,256)
# 이미지를 그레이스케일로 변환
transform = transforms.Grayscale()
gray_image = transform(frames)
# PyTorch Tensor를 NumPy 배열로 변환하고 [0, 255] 범위로 스케일 조정
gray_image_np = (gray_image.numpy() * 255).astype(np.uint8)
# Co-occurrence matrix 계산
distances = [1, 2, 3] # 거리 설정
angles = [0, np.pi/4, np.pi/2, 3*np.pi/4] # 방향 설정
co_occurrence_matrices = []
for channel in range(gray_image_np.shape[0]):
co_occurrence_matrix = graycomatrix(gray_image_np[channel], distances=distances, angles=angles, levels=256, symmetric=True, normed=True)
co_occurrence_matrices.append(co_occurrence_matrix)
# 각 채널별로 계산된 co-occurrence matrix를 합치기
co_occurrence_matrix_combined = np.stack(co_occurrence_matrices, axis=0) # (1, 256, 256, 3, 4)
co_occurrence_matrix_combined = torch.from_numpy(co_occurrence_matrix_combined)
co_occurrence_matrix_combined = torch.squeeze(co_occurrence_matrix_combined, 0)
co_occurrence_matrix_combined = rearrange(co_occurrence_matrix_combined, 'w h x y -> (x y) w h') # (12,256,256)
co_occurrence_matrix_combined = torch.unsqueeze(co_occurrence_matrix_combined ,0)
Model
class CustomModel(nn.Module):
def __init__(self, num_classes=1):
super().__init__()
self.effi = timm.create_model("efficientnet_b0", pretrained=True)
self.effi.conv_stem = nn.Conv2d(15, 32, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
self.effi.bn2 = nn.Conv2d(1280, 64, kernel_size=1, stride=1)
self.effi.drop = nn.Identity()
self.effi.act = nn.Identity()
self.effi.global_pool = nn.Identity()
self.effi.classifier = nn.Flatten()
self.fc = nn.Sequential(
nn.Linear(4096, 1000),
nn.ReLU(inplace=True),
nn.Dropout(p=0.3),
nn.Linear(1000, 1)
)
def forward(self, x):
# concat with entropy map
x = self.effi(x)
x = self.effi.global_pool(x)
x = self.effi.classifier(x)
x = self.fc(x)
x = F.sigmoid(x)
return x
최종 모형은 3개의 모델(EfficientN(co_occurrence_matrix 미사용), EfficientNetB0(co_occurrence_matrix 사용), ResNet152)의 각각 가중치 2:2:1 소프트 보팅 앙상블 기법 사용하여 예측 수행
co-occurence | yolo | FCN | voting | public LB(ACC) |
---|---|---|---|---|
X | X | X | X | 60 |
O | X | X | X | 73 |
O | O | X | X | 90 |
O | O | O | X | 95.9 |
O | O | O | O | 96.6 |
아쉬운 점
- 주어진 과제의 데이터 타입은 동영상으로 연속적인 이미지의 집합이라고 할 수 있다. 이러한 연속적인 이미지 사이의 시계열성 정보, 프레임 간의 상관성을 고려하여 적용해볼 시간이 없어 아쉬었다.
- 7000개나 되는 동영상을 빠른 시간내에 다 살필 수 없어서 그냥 일부만 보고 진행했었는데 추후 살펴보니 영상의 명암이 심하게 차이가 나거나 너무 어두워 영상이 보이지 않는 경우의 outlier들이 일부 존재했다. 학습을 할 때 한번씩 train loss가 이상하게 올라가는 현상이 있었는데 당시에는 원인을 찾지 못했지만 이런 특이성이 있는 학습 데이터 때문으로 보인다.
- 코드의 통일성 및 개발 환경 문제(네트워크 및 IDE), 대회장의 환경이 개발을 집중하기에는 약간의 트러블이 있었고 익숙하지 않아 아쉬웠다.
최종 등수는 정량평가 70%와 정성평가 30%를 합산하여 산정되었으며, 총 15팀 중 5등(제네시스 랩 후원기업상)으로 마무리하였습니다.
(대회 시간 이슈로 인해 코드가 뒤죽박죽입니다. 추후 수정 예정)
이름 | 깃허브 |
---|---|
박시형 | Github Link |
홍성래 | Github Link |
이준석 | Github Link |
고건영 | Github Link |