<gh_stars>0
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import cv2
import os
from tqdm import tqdm,trange
from sklearn.model_selection import train_test_split
import sklearn.metrics

import torch
import torch.nn as nn
import torch.nn.functional as F

import warnings
warnings.filterwarnings("ignore")

from torch.utils.data import Dataset, DataLoader
mean = [0.485, 0.456, 0.406]
std = [0.229, 0.224, 0.225]

from pytorchcv.model_provider import get_model
model = get_model("xception", pretrained=True)
#model = get_model("resnet18", pretrained=True)
#model = get_model("resnet50", pretrained=True)

model = nn.Sequential(*list(model.children())[:-1]) # Remove original output layer
model[0].final_block.pool = nn.Sequential(nn.AdaptiveAvgPool2d(1))


class Head(torch.nn.Module):
    def __init__(self, in_f, out_f):
        super().__init__()

        self.f = nn.Flatten()
        
        self.b1 = nn.BatchNorm1d(in_f)#in_f=2048
        self.d1 = nn.Dropout(0.40)
        
        self.l2 = nn.Linear(in_f, 512)
        self.r2  = nn.ReLU()
        self.b2 = nn.BatchNorm1d(512)
        self.d2 = nn.Dropout(0.30)

        self.l3 = nn.Linear(512, 1024)
        self.r3  = nn.ReLU()
        self.b3 = nn.BatchNorm1d(1024)
        self.d3 = nn.Dropout(0.30)
        
        self.o = nn.Linear(1024, out_f)#out_f=1
        
        
       
    def forward(self, x):
        x = self.f(x)#flatte
        x = self.b1(x)
        x = self.d1(x)
        x = self.l2(x)#first hidden layer
        x = self.r2(x)
        x = self.b2(x)
        x = self.d2(x)
        x = self.l3(x)#second hidden layer
        x = self.r3(x)
        x = self.b3(x)
        x = self.d3(x)
        out = self.o(x)#512 dim
        return out

    
class FCN(torch.nn.Module):
    def __init__(self, base, in_f):
        super().__init__()
        self.base = base
        self.h1 = Head(in_f, 1)
  
    def forward(self, x):
        x = self.base(x)
        return self.h1(x)

model = FCN(model, 2048)

def get_path(img_name,suffix):
    path = '../input/deepfake/DeepFake'+suffix+'/DeepFake'+suffix+'/' + img_name.replace(".mp4","")+ '.jpg'
    if not os.path.exists(path):
        raise Exception
    return path

def get_all_paths(df_list,suffixes_list):
    LABELS = ['REAL','FAKE']
    paths = []
    labels = []
    for df,suffix in tqdm(zip(df_list,suffixes_list),total=len(df_list)):
        images = list(df.columns.values)
        for img_name in images:
            try:
                paths.append(get_path(img_name,suffix))
                labels.append(LABELS.index(df[img_name]['label']))
            except Exception as err:
                #print(err)
                pass
    return paths,labels



class ImageDataset(Dataset):
    def __init__(self, X, y, training=True, transform=None):
        self.X = X
        self.y = y
        self.transform = transform
        self.training = training

    def __len__(self):
        return len(self.X)
    
    def __getitem__(self, idx):
        if torch.is_tensor(idx):
            idx = idx.tolist()
        
        img = self.X[idx]

        if self.transform is not None:
          res = self.transform(image=img)
          img = res['image']
        
        img = np.rollaxis(img, 2, 0)
        # img = np.array(img).astype(np.float32) / 255.

        labels = self.y[idx]
        labels = np.array(labels).astype(np.float32)
        return [img, labels]
val_y=[]
for df_val,num in tqdm(zip(df_vals,val_nums),total=len(df_vals)):
    images = list(df_val.columns.values)
    for x in images:
        try:
            val_paths.append(get_path(num,x))
            val_y.append(LABELS.index(df_val[x]['label']))
        except Exception as err:
            #print(err)
            pass
        
def calc_loss(pred, targets):
  return F.binary_cross_entropy(F.sigmoid(pred), targets)

def train_model(epoch, optimizer, scheduler=None, history=None):
    model.train()
    total_loss = 0
    
    t = tqdm(train_loader)
    for i, (img_batch, y_batch) in enumerate(t):
        img_batch = img_batch.cuda().float()
        y_batch = y_batch.cuda().float()

        optimizer.zero_grad()

        out = model(img_batch)
        loss = calc_loss(out, y_batch)

        total_loss += loss
        t.set_description(f'Epoch {epoch+1}/{n_epochs}, LR: %6f, Loss: %.4f'%(optimizer.state_dict()['param_groups'][0]['lr'],total_loss/(i+1)))

        if history is not None:
          history.loc[epoch + i / len(X), 'train_loss'] = loss.data.cpu().numpy()
          history.loc[epoch + i / len(X), 'lr'] = optimizer.state_dict()['param_groups'][0]['lr']

        loss.backward()
        optimizer.step()
        if scheduler is not None:
          scheduler.step()

def evaluate_model(epoch, scheduler=None, history=None):
    model.eval()
    loss = 0
    pred = []
    real = []
    with torch.no_grad():
        for img_batch, y_batch in val_loader:
            img_batch = img_batch.cuda().float()
            y_batch = y_batch.cuda().float()

            op = model(img_batch)
            temp_loss = calc_loss(op, y_batch)
            loss += temp_loss
            
            for j in op:
              pred.append(F.sigmoid(j))
            for i in y_batch:
              real.append(i.data.cpu())
    
    pred = [p.data.cpu().numpy() for p in pred]
    f_pred = pred
    pred = [np.round(p) for p in pred]
    pred = np.array(pred)
    acc = sklearn.metrics.recall_score(real, pred, average='macro')

    real = [r.item() for r in real]
    f_pred = np.array(f_pred).clip(0.1, 0.9)
    

    loss = loss/len(val_loader)
    
    if history is not None:
        history.loc[epoch, 'dev_loss'] = loss.cpu().numpy()
    
    if scheduler is not None:
      scheduler.step(loss)

    print(f'Development loss: %.4f, Acc: %.6f'%(loss,acc))
    
    return loss

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import cv2
import os
from tqdm import tqdm,trange
from sklearn.model_selection import train_test_split
import sklearn.metrics

import torch
import torch.nn as nn
import torch.nn.functional as F

import warnings
warnings.filterwarnings("ignore")

from torch.utils.data import Dataset, DataLoader
mean = [0.485, 0.456, 0.406]
std = [0.229, 0.224, 0.225]

from pytorchcv.model_provider import get_model
model = get_model("xception", pretrained=True)
#model = get_model("resnet18", pretrained=True)
#model = get_model("resnet50", pretrained=True)

model = nn.Sequential(*list(model.children())[:-1]) # Remove original output layer
model[0].final_block.pool = nn.Sequential(nn.AdaptiveAvgPool2d(1))


class Head(torch.nn.Module):
    def __init__(self, in_f, out_f):
        super().__init__()

        self.f = nn.Flatten()
        
        self.b1 = nn.BatchNorm1d(in_f)#in_f=2048
        self.d1 = nn.Dropout(0.40)
        
        self.l2 = nn.Linear(in_f, 512)
        self.r2  = nn.ReLU()
        self.b2 = nn.BatchNorm1d(512)
        self.d2 = nn.Dropout(0.30)

        self.l3 = nn.Linear(512, 1024)
        self.r3  = nn.ReLU()
        self.b3 = nn.BatchNorm1d(1024)
        self.d3 = nn.Dropout(0.30)
        
        self.o = nn.Linear(1024, out_f)#out_f=1
        
        
       
    def forward(self, x):
        x = self.f(x)#flatte
        x = self.b1(x)
        x = self.d1(x)
        x = self.l2(x)#first hidden layer
        x = self.r2(x)
        x = self.b2(x)
        x = self.d2(x)
        x = self.l3(x)#second hidden layer
        x = self.r3(x)
        x = self.b3(x)
        x = self.d3(x)
        out = self.o(x)#512 dim
        return out

    
class FCN(torch.nn.Module):
    def __init__(self, base, in_f):
        super().__init__()
        self.base = base
        self.h1 = Head(in_f, 1)
  
    def forward(self, x):
        x = self.base(x)
        return self.h1(x)

model = FCN(model, 2048)

def get_path(img_name,suffix):
    path = '../input/deepfake/DeepFake'+suffix+'/DeepFake'+suffix+'/' + img_name.replace(".mp4","")+ '.jpg'
    if not os.path.exists(path):
        raise Exception
    return path

def get_all_paths(df_list,suffixes_list):
    LABELS = ['REAL','FAKE']
    paths = []
    labels = []
    for df,suffix in tqdm(zip(df_list,suffixes_list),total=len(df_list)):
        images = list(df.columns.values)
        for img_name in images:
            try:
                paths.append(get_path(img_name,suffix))
                labels.append(LABELS.index(df[img_name]['label']))
            except Exception as err:
                #print(err)
                pass
    return paths,labels



class ImageDataset(Dataset):
    def __init__(self, X, y, training=True, transform=None):
        self.X = X
        self.y = y
        self.transform = transform
        self.training = training

    def __len__(self):
        return len(self.X)
    
    def __getitem__(self, idx):
        if torch.is_tensor(idx):
            idx = idx.tolist()
        
        img = self.X[idx]

        if self.transform is not None:
          res = self.transform(image=img)
          img = res['image']
        
        img = np.rollaxis(img, 2, 0)
        # img = np.array(img).astype(np.float32) / 255.

        labels = self.y[idx]
        labels = np.array(labels).astype(np.float32)
        return [img, labels]
val_y=[]
for df_val,num in tqdm(zip(df_vals,val_nums),total=len(df_vals)):
    images = list(df_val.columns.values)
    for x in images:
        try:
            val_paths.append(get_path(num,x))
            val_y.append(LABELS.index(df_val[x]['label']))
        except Exception as err:
            #print(err)
            pass
        
def calc_loss(pred, targets):
  return F.binary_cross_entropy(F.sigmoid(pred), targets)

def train_model(epoch, optimizer, scheduler=None, history=None):
    model.train()
    total_loss = 0
    
    t = tqdm(train_loader)
    for i, (img_batch, y_batch) in enumerate(t):
        img_batch = img_batch.cuda().float()
        y_batch = y_batch.cuda().float()

        optimizer.zero_grad()

        out = model(img_batch)
        loss = calc_loss(out, y_batch)

        total_loss += loss
        t.set_description(f'Epoch {epoch+1}/{n_epochs}, LR: %6f, Loss: %.4f'%(optimizer.state_dict()['param_groups'][0]['lr'],total_loss/(i+1)))

        if history is not None:
          history.loc[epoch + i / len(X), 'train_loss'] = loss.data.cpu().numpy()
          history.loc[epoch + i / len(X), 'lr'] = optimizer.state_dict()['param_groups'][0]['lr']

        loss.backward()
        optimizer.step()
        if scheduler is not None:
          scheduler.step()

def evaluate_model(epoch, scheduler=None, history=None):
    model.eval()
    loss = 0
    pred = []
    real = []
    with torch.no_grad():
        for img_batch, y_batch in val_loader:
            img_batch = img_batch.cuda().float()
            y_batch = y_batch.cuda().float()

            op = model(img_batch)
            temp_loss = calc_loss(op, y_batch)
            loss += temp_loss
            
            for j in op:
              pred.append(F.sigmoid(j))
            for i in y_batch:
              real.append(i.data.cpu())
    
    pred = [p.data.cpu().numpy() for p in pred]
    f_pred = pred
    pred = [np.round(p) for p in pred]
    pred = np.array(pred)
    acc = sklearn.metrics.recall_score(real, pred, average='macro')

    real = [r.item() for r in real]
    f_pred = np.array(f_pred).clip(0.1, 0.9)
    

    loss = loss/len(val_loader)
    
    if history is not None:
        history.loc[epoch, 'dev_loss'] = loss.cpu().numpy()
    
    if scheduler is not None:
      scheduler.step(loss)

    print(f'Development loss: %.4f, Acc: %.6f'%(loss,acc))
    
    return loss
#model = get_model("resnet18", pretrained=True) #model = get_model("resnet50", pretrained=True) # Remove original output layer #in_f=2048 #out_f=1 #flatte #first hidden layer #second hidden layer #512 dim #print(err) # img = np.array(img).astype(np.float32) / 255. #print(err)