Spaces:
Build error
Build error
Upload 4 files
Browse files- app.py +155 -0
- best_model_accuracy.pt +3 -0
- model.py +83 -0
- requirements.txt +13 -0
app.py
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import torch
|
| 3 |
+
import torchvision
|
| 4 |
+
from torchvision import transforms, models
|
| 5 |
+
from torch.utils.data import DataLoader
|
| 6 |
+
from torch.utils.data.dataset import Dataset
|
| 7 |
+
import numpy as np
|
| 8 |
+
import cv2
|
| 9 |
+
import face_recognition
|
| 10 |
+
from torch.autograd import Variable
|
| 11 |
+
import time
|
| 12 |
+
import sys
|
| 13 |
+
from torch import nn
|
| 14 |
+
import json
|
| 15 |
+
import glob
|
| 16 |
+
import copy
|
| 17 |
+
from PIL import Image as pImage
|
| 18 |
+
import shutil
|
| 19 |
+
import os
|
| 20 |
+
|
| 21 |
+
im_size = 112
|
| 22 |
+
mean=[0.485, 0.456, 0.406]
|
| 23 |
+
std=[0.229, 0.224, 0.225]
|
| 24 |
+
sm = nn.Softmax()
|
| 25 |
+
inv_normalize = transforms.Normalize(mean=-1*np.divide(mean,std),std=np.divide([1,1,1],std))
|
| 26 |
+
|
| 27 |
+
train_transforms = transforms.Compose([
|
| 28 |
+
transforms.ToPILImage(),
|
| 29 |
+
transforms.Resize((im_size,im_size)),
|
| 30 |
+
transforms.ToTensor(),
|
| 31 |
+
transforms.Normalize(mean,std)])
|
| 32 |
+
|
| 33 |
+
class Model(nn.Module):
|
| 34 |
+
def __init__(self, num_classes,latent_dim= 2048, lstm_layers=1 , hidden_dim = 2048, bidirectional = False):
|
| 35 |
+
super(Model, self).__init__()
|
| 36 |
+
model = models.resnext50_32x4d(pretrained=True)
|
| 37 |
+
self.model = nn.Sequential(*list(model.children())[:-2])
|
| 38 |
+
self.lstm = nn.LSTM(latent_dim,hidden_dim, lstm_layers, bidirectional)
|
| 39 |
+
self.relu = nn.LeakyReLU()
|
| 40 |
+
self.dp = nn.Dropout(0.4)
|
| 41 |
+
self.linear1 = nn.Linear(2048,num_classes)
|
| 42 |
+
self.avgpool = nn.AdaptiveAvgPool2d(1)
|
| 43 |
+
|
| 44 |
+
def forward(self, x):
|
| 45 |
+
batch_size,seq_length, c, h, w = x.shape
|
| 46 |
+
x = x.view(batch_size * seq_length, c, h, w)
|
| 47 |
+
fmap = self.model(x)
|
| 48 |
+
x = self.avgpool(fmap)
|
| 49 |
+
x = x.view(batch_size,seq_length,2048)
|
| 50 |
+
x_lstm,_ = self.lstm(x,None)
|
| 51 |
+
return fmap,self.dp(self.linear1(x_lstm[:,-1,:]))
|
| 52 |
+
|
| 53 |
+
class validation_dataset(Dataset):
|
| 54 |
+
def __init__(self,video_names,sequence_length=60,transform=None):
|
| 55 |
+
self.video_names = video_names
|
| 56 |
+
self.transform = transform
|
| 57 |
+
self.count = sequence_length
|
| 58 |
+
|
| 59 |
+
def __len__(self):
|
| 60 |
+
return len(self.video_names)
|
| 61 |
+
|
| 62 |
+
def __getitem__(self,idx):
|
| 63 |
+
video_path = self.video_names[idx]
|
| 64 |
+
frames = []
|
| 65 |
+
a = int(100/self.count)
|
| 66 |
+
first_frame = np.random.randint(0,a)
|
| 67 |
+
for i,frame in enumerate(self.frame_extract(video_path)):
|
| 68 |
+
faces = face_recognition.face_locations(frame)
|
| 69 |
+
try:
|
| 70 |
+
top,right,bottom,left = faces[0]
|
| 71 |
+
frame = frame[top:bottom,left:right,:]
|
| 72 |
+
except:
|
| 73 |
+
pass
|
| 74 |
+
frames.append(self.transform(frame))
|
| 75 |
+
if(len(frames) == self.count):
|
| 76 |
+
break
|
| 77 |
+
frames = torch.stack(frames)
|
| 78 |
+
frames = frames[:self.count]
|
| 79 |
+
return frames.unsqueeze(0)
|
| 80 |
+
|
| 81 |
+
def frame_extract(self,path):
|
| 82 |
+
vidObj = cv2.VideoCapture(path)
|
| 83 |
+
success = 1
|
| 84 |
+
while success:
|
| 85 |
+
success, image = vidObj.read()
|
| 86 |
+
if success:
|
| 87 |
+
yield image
|
| 88 |
+
|
| 89 |
+
def im_convert(tensor):
|
| 90 |
+
image = tensor.to("cpu").clone().detach()
|
| 91 |
+
image = image.squeeze()
|
| 92 |
+
image = inv_normalize(image)
|
| 93 |
+
image = image.numpy()
|
| 94 |
+
image = image.transpose(1,2,0)
|
| 95 |
+
image = image.clip(0, 1)
|
| 96 |
+
return image
|
| 97 |
+
|
| 98 |
+
def predict(model,img):
|
| 99 |
+
fmap,logits = model(img.to('cuda'))
|
| 100 |
+
logits = sm(logits)
|
| 101 |
+
_,prediction = torch.max(logits,1)
|
| 102 |
+
confidence = logits[:,int(prediction.item())].item()*100
|
| 103 |
+
return [int(prediction.item()), confidence]
|
| 104 |
+
|
| 105 |
+
def save_uploaded_file(uploaded_file, save_dir):
|
| 106 |
+
if not os.path.exists(save_dir):
|
| 107 |
+
os.makedirs(save_dir)
|
| 108 |
+
file_path = os.path.join(save_dir, uploaded_file.name)
|
| 109 |
+
with open(file_path, "wb") as f:
|
| 110 |
+
f.write(uploaded_file.getbuffer())
|
| 111 |
+
return file_path
|
| 112 |
+
|
| 113 |
+
def index():
|
| 114 |
+
st.title("Fake Video Detection")
|
| 115 |
+
uploaded_file = st.file_uploader("Upload a video", type=["mp4", "gif", "webm", "avi", "3gp", "wmv", "flv", "mkv"])
|
| 116 |
+
if uploaded_file is not None:
|
| 117 |
+
sequence_length = st.number_input("Enter sequence length", min_value=1, value=60)
|
| 118 |
+
model = Model(2).cuda()
|
| 119 |
+
st.write("Model loaded successfully.")
|
| 120 |
+
st.write("Starting prediction...")
|
| 121 |
+
|
| 122 |
+
# Save the uploaded file to disk
|
| 123 |
+
video_path = save_uploaded_file(uploaded_file, "uploaded_videos")
|
| 124 |
+
|
| 125 |
+
video_dataset = validation_dataset([video_path], sequence_length=sequence_length, transform=train_transforms)
|
| 126 |
+
#model_name = get_accurate_model(sequence_length)
|
| 127 |
+
path_to_model = "/content/drive/MyDrive/DeepFake/best_model_accuracy.pt"
|
| 128 |
+
model.load_state_dict(torch.load(path_to_model))
|
| 129 |
+
model.eval()
|
| 130 |
+
prediction = predict(model, video_dataset[0])
|
| 131 |
+
st.write("Prediction:", "REAL" if prediction[0] == 1 else "FAKE")
|
| 132 |
+
st.write("Confidence:", round(prediction[1], 2))
|
| 133 |
+
|
| 134 |
+
if __name__ == "__main__":
|
| 135 |
+
index()
|
| 136 |
+
|
| 137 |
+
# def index():
|
| 138 |
+
# st.title("Fake Video Detection")
|
| 139 |
+
# uploaded_file = st.file_uploader("Upload a video", type=["mp4", "gif", "webm", "avi", "3gp", "wmv", "flv", "mkv"])
|
| 140 |
+
# if uploaded_file is not None:
|
| 141 |
+
# sequence_length = st.number_input("Enter sequence length", min_value=1, value=60)
|
| 142 |
+
# model = Model(2).cuda()
|
| 143 |
+
# st.write("Model loaded successfully.")
|
| 144 |
+
# st.write("Starting prediction...")
|
| 145 |
+
# video_dataset = validation_dataset([uploaded_file], sequence_length=sequence_length, transform=train_transforms)
|
| 146 |
+
# # model_name = get_accurate_model(sequence_length)
|
| 147 |
+
# path_to_model = "/content/drive/MyDrive/DeepFake/best_model_accuracy.pt" #os.path.join('models', model_name)
|
| 148 |
+
# model.load_state_dict(torch.load(path_to_model))
|
| 149 |
+
# model.eval()
|
| 150 |
+
# prediction = predict(model, video_dataset[0])
|
| 151 |
+
# st.write("Prediction:", "REAL" if prediction[0] == 1 else "FAKE")
|
| 152 |
+
# st.write("Confidence:", round(prediction[1], 2))
|
| 153 |
+
|
| 154 |
+
# if __name__ == "__main__":
|
| 155 |
+
# index()
|
best_model_accuracy.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:529ed118f9053cf4af8eaca0afab477c631489f8392f47f43b5b1b7be858a3ea
|
| 3 |
+
size 226602284
|
model.py
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import warnings
|
| 3 |
+
warnings.filterwarnings('ignore')
|
| 4 |
+
import torch
|
| 5 |
+
from torch import nn
|
| 6 |
+
from torch.autograd import Variable
|
| 7 |
+
import torchvision
|
| 8 |
+
from torchvision import models
|
| 9 |
+
from torchvision import transforms
|
| 10 |
+
from torch.utils.data import DataLoader
|
| 11 |
+
from torch.utils.data.dataset import Dataset
|
| 12 |
+
import os
|
| 13 |
+
import sys
|
| 14 |
+
import time
|
| 15 |
+
import pandas as pd
|
| 16 |
+
import numpy as np
|
| 17 |
+
import cv2
|
| 18 |
+
import matplotlib.pyplot as plt
|
| 19 |
+
import face_recognition
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
#Model with feature visualization
|
| 23 |
+
class Model(nn.Module):
|
| 24 |
+
def __init__(self, num_classes=2,latent_dim= 2048, lstm_layers=1 , hidden_dim = 2048, bidirectional = False):
|
| 25 |
+
super(Model, self).__init__()
|
| 26 |
+
model = models.resnext50_32x4d(pretrained = True) #Residual Network CNN
|
| 27 |
+
self.model = nn.Sequential(*list(model.children())[:-2])
|
| 28 |
+
self.lstm = nn.LSTM(latent_dim,hidden_dim, lstm_layers, bidirectional)
|
| 29 |
+
self.relu = nn.LeakyReLU()
|
| 30 |
+
self.dp = nn.Dropout(0.4)
|
| 31 |
+
self.linear1 = nn.Linear(2048,num_classes)
|
| 32 |
+
self.avgpool = nn.AdaptiveAvgPool2d(1)
|
| 33 |
+
def forward(self, x):
|
| 34 |
+
batch_size,seq_length, c, h, w = x.shape
|
| 35 |
+
x = x.view(batch_size * seq_length, c, h, w)
|
| 36 |
+
fmap = self.model(x)
|
| 37 |
+
x = self.avgpool(fmap)
|
| 38 |
+
x = x.view(batch_size,seq_length,2048)
|
| 39 |
+
x_lstm,_ = self.lstm(x,None)
|
| 40 |
+
return fmap,self.dp(self.linear1(torch.mean(x_lstm,dim = 1)))
|
| 41 |
+
|
| 42 |
+
im_size = 112
|
| 43 |
+
mean=[0.485, 0.456, 0.406]
|
| 44 |
+
std=[0.229, 0.224, 0.225]
|
| 45 |
+
sm = nn.Softmax()
|
| 46 |
+
inv_normalize = transforms.Normalize(mean=-1*np.divide(mean,std),std=np.divide([1,1,1],std))
|
| 47 |
+
def im_convert(tensor):
|
| 48 |
+
""" Display a tensor as an image. """
|
| 49 |
+
image = tensor.to("cpu").clone().detach()
|
| 50 |
+
image = image.squeeze()
|
| 51 |
+
image = inv_normalize(image)
|
| 52 |
+
image = image.numpy()
|
| 53 |
+
image = image.transpose(1,2,0)
|
| 54 |
+
image = image.clip(0, 1)
|
| 55 |
+
cv2.imwrite('./2.png',image*255)
|
| 56 |
+
return image
|
| 57 |
+
|
| 58 |
+
def predict(model,img,path = './'):
|
| 59 |
+
fmap,logits = model(img.to('cuda'))
|
| 60 |
+
params = list(model.parameters())
|
| 61 |
+
weight_softmax = model.linear1.weight.detach().cpu().numpy()
|
| 62 |
+
logits = sm(logits)
|
| 63 |
+
_,prediction = torch.max(logits,1)
|
| 64 |
+
confidence = logits[:,int(prediction.item())].item()*100
|
| 65 |
+
print('confidence of prediction:',logits[:,int(prediction.item())].item()*100)
|
| 66 |
+
idx = np.argmax(logits.detach().cpu().numpy())
|
| 67 |
+
bz, nc, h, w = fmap.shape
|
| 68 |
+
out = np.dot(fmap[-1].detach().cpu().numpy().reshape((nc, h*w)).T,weight_softmax[idx,:].T)
|
| 69 |
+
predict = out.reshape(h,w)
|
| 70 |
+
predict = predict - np.min(predict)
|
| 71 |
+
predict_img = predict / np.max(predict)
|
| 72 |
+
predict_img = np.uint8(255*predict_img)
|
| 73 |
+
out = cv2.resize(predict_img, (im_size,im_size))
|
| 74 |
+
heatmap = cv2.applyColorMap(out, cv2.COLORMAP_JET)
|
| 75 |
+
img = im_convert(img[:,-1,:,:,:])
|
| 76 |
+
result = heatmap * 0.5 + img*0.8*255
|
| 77 |
+
cv2.imwrite('/content/drive/MyDrive/DeepFake/FF++/HeatMaps/3.png',result)
|
| 78 |
+
result1 = heatmap * 0.5/255 + img*0.8
|
| 79 |
+
r,g,b = cv2.split(result1)
|
| 80 |
+
result1 = cv2.merge((r,g,b))
|
| 81 |
+
plt.imshow(result1)
|
| 82 |
+
plt.show()
|
| 83 |
+
return [int(prediction.item()),confidence]
|
requirements.txt
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
glob
|
| 2 |
+
pandas
|
| 3 |
+
numpy
|
| 4 |
+
os
|
| 5 |
+
torch
|
| 6 |
+
torchvision
|
| 7 |
+
face-recognition
|
| 8 |
+
cv2
|
| 9 |
+
matplotlib
|
| 10 |
+
random
|
| 11 |
+
sklearn
|
| 12 |
+
scikit-learn
|
| 13 |
+
seaborn
|