Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
yinglinzheng committed Sep 1, 2021
0 parents commit 07f0c03
Show file tree
Hide file tree
Showing 73 changed files with 13,235 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
checkpoints/
*.py[cod]
*.pyc.*
*$py.class
.vscode/
output/
examples/*.pth
*/__pycache__/
56 changes: 56 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Exploring Temporal Coherence for More General Video Face Forgery Detection(FTCN)

Yinglin Zheng, Jianmin Bao, Dong Chen, Ming Zeng, Fang Wen
### [Paper](https://arxiv.org/abs/2108.06693)

## Abstract
> Although current face manipulation techniques achieve impressive performance regarding quality and controllability, they are struggling to generate temporal coherent face videos. In this work, we explore to take full advantage of the temporal coherence for video face forgery detection. To achieve this, we propose a novel end-to-end framework, which consists of two major stages. The first stage is a fully temporal convolution network (FTCN). The key insight of FTCN is to reduce the spatial convolution kernel size to 1, while maintaining the temporal convolution kernel size unchanged. We surprisingly find this special design can benefit the model for extracting the temporal features as well as improve the generalization capability. The second stage is a Temporal Transformer network, which aims to explore the long-term temporal coherence. The proposed framework is general and flexible, which can be directly trained from scratch without any pre-training models or external datasets. Extensive experiments show that our framework outperforms existing methods and remains effective when applied to detect new sorts of face forgery videos.


# Setup
First setup python environment with pytorch 1.4.0 installed, **it's highly recommended to use docker image [pytorch/pytorch:1.4-cuda10.1-cudnn7-devel](https://hub.docker.com/layers/pytorch/pytorch/1.4-cuda10.1-cudnn7-devel/images/sha256-c612782acc39256aac0637d58d297644066c62f6f84f0b88cfdc335bb25d0d22), as the pretrained model and the code might be incompatible with higher version pytorch.**

then install dependencies for the experiment:

```
pip install -r requirements.txt
```

# Test

## Inference Using Pretrained Model on Raw Video
Download pretrained `FTCN+TT` model from [here]() and place it under `./checkpoints` folder
```bash
python test_on_raw_video.py examples/shining.mp4 output
```
the output will be a video under folder `output` named `shining.avi`

![](./examples/shining.gif)

# TODO

- [x] Release inference code.
- [ ] Release training code.
- [ ] Code cleaning.


# Acknowledgments

This code borrows heavily from [SlowFast](https://github.com/facebookresearch/SlowFast).

The face detection network comes from [biubug6/Pytorch_Retinaface](https://github.com/biubug6/Pytorch_Retinaface).

The face alignment network comes from [cunjian/pytorch_face_landmark](https://github.com/cunjian/pytorch_face_landmark).



# Citation
If you use this code for your research, please cite our paper.
```
@article{zheng2021exploring,
title={Exploring Temporal Coherence for More General Video Face Forgery Detection},
author={Zheng, Yinglin and Bao, Jianmin and Chen, Dong and Zeng, Ming and Wen, Fang},
journal={arXiv preprint arXiv:2108.06693},
year={2021}
}
```
138 changes: 138 additions & 0 deletions config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
#!/usr/bin/python
# Borrow from tensorpack,credits goes to yuxin wu

# the loaded sequnce is
# default config in this file
# -> provided setting file (you can not add new config after this)
# -> manully overrided config
# -> computed config in finalize config (you can change config after this)

import os
import pprint
import yaml

__all__ = ["config", "finalize_configs"]


class AttrDict:
_freezed = False
""" Avoid accidental creation of new hierarchies. """

def __getattr__(self, name):
if self._freezed:
raise AttributeError(name)
ret = AttrDict()
setattr(self, name, ret)
return ret

def __setattr__(self, name, value):
if self._freezed and name not in self.__dict__:
raise AttributeError("Cannot create new attribute!")
super().__setattr__(name, value)

def __str__(self):
return pprint.pformat(self.to_dict(), indent=1)

__repr__ = __str__

def to_dict(self):
"""Convert to a nested dict. """
return {
k: v.to_dict() if isinstance(v, AttrDict) else v
for k, v in self.__dict__.items()
if not k.startswith("_")
}

def update_args(self, args):
"""Update from command line args. """
for cfg in args:
keys, v = cfg.split("=", maxsplit=1)
keylist = keys.split(".")
dic = self
# print(keylist)
if len(keylist) == 1:
assert keylist[0] in dir(dic), "Unknown config key: {}".format(
keylist[0]
)
for i, k in enumerate(keylist[:-1]):
assert k in dir(dic), "Unknown config key: {}".format(k)
dic = getattr(dic, k)
key = keylist[-1]
assert key in dir(dic), "Unknown config key: {}".format(key)
oldv = getattr(dic, key)
if not isinstance(oldv, str):
v = eval(v)
setattr(dic, key, v)

def update_with_yaml(self, rel_path):
base_path = os.path.dirname(os.path.abspath(__file__))
setting_path = os.path.normpath(os.path.join(base_path, "setting", rel_path))
setting_name = os.path.basename(setting_path).split(".")[0]

with open(setting_path, "r") as f:
overrided_setting = yaml.load(f,Loader=yaml.FullLoader)
# if 'setting_name' not in overrided_setting:
# raise RuntimeError('you must provide a setting name for non root_setting: {}'.format(rel_path))
self.update_with_dict(overrided_setting)
setattr(self, "setting_name", setting_name)

def init_with_yaml(self):
base_path = os.path.dirname(os.path.abspath(__file__))
setting_path = os.path.normpath(os.path.join(base_path, "root_setting.yaml"))
with open(setting_path, "r") as f:
overrided_setting = yaml.load(f,Loader=yaml.FullLoader)
self.update_with_dict(overrided_setting)

def update_with_text(self,text):
overrided_setting = yaml.load(text, Loader=yaml.FullLoader)
self.update_with_dict(overrided_setting)

def update_with_dict(self, dicts):
for k, v in dicts.items():
if isinstance(v, dict):
getattr(self, k).update_with_dict(v)
else:
setattr(self, k, v)

def freeze(self):
self._freezed = True
for v in self.__dict__.values():
if isinstance(v, AttrDict):
v.freeze()

# avoid silent bugs
def __eq__(self, _):
raise NotImplementedError()

def __ne__(self, _):
raise NotImplementedError()


config = AttrDict()
_C = config # short alias to avoid coding


# you can directly write setting here as _C.model_dir='.\checkpoint' or in root_setting.yaml


#


def finalize_configs(input_cfg=_C, freeze=True, verbose=True):

# _C.base_path = os.path.dirname(os.path.abspath(__file__))
input_cfg.base_path = os.path.dirname(__file__)

# for running in remote server
# for k, v in input_cfg.path.__dict__.items():
# v = os.path.normpath(os.path.join(input_cfg.base_path, v))
# setattr(input_cfg.path, k, v)
if freeze:
input_cfg.freeze()
# if verbose:
# logger.info("Config: ------------------------------------------\n" + str(_C))


if __name__ == "__main__":
print("?")
print(os.path.dirname(__file__))
Binary file added examples/shining.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/shining.mp4
Binary file not shown.
4 changes: 4 additions & 0 deletions model/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/python
# -*- coding: UTF-8 -*-


Loading

0 comments on commit 07f0c03

Please sign in to comment.