Commit ce0078af authored by Pavel KORSHUNOV's avatar Pavel KORSHUNOV

Merge branch 'tensorflow-support' into 'master'

Tensorflow support

Added bob.learn.tensorflow package and an algorithm that uses tensorflow's model for evaluation

See merge request !6
parents 622d8d63 2114b559
Pipeline #6002 passed with stages
in 18 minutes and 22 seconds
from .gmm_algorithm import GmmAlgorithm
from .logregr_algorithm import LogRegrAlgorithm
# to fix sphinx warnings of not able to find classes, when path is shortened
GmmAlgorithm.__module__ = "bob.pad.voice.algorithm"
LogRegrAlgorithm.__module__ = "bob.pad.voice.algorithm"
from .tensorflow_algorithm import TensorflowAlgo
# gets sphinx autodoc done right - don't remove it
def __appropriate__(*args):
......@@ -22,5 +19,6 @@ def __appropriate__(*args):
__appropriate__(
GmmAlgorithm,
LogRegrAlgorithm,
TensorflowAlgo,
)
__all__ = [_ for _ in dir() if not _.startswith('_')]
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# @author: Pavel Korshunov <pavel.korshunov@idiap.ch>
# @date: Wed 19 Oct 23:43:22 2016
from bob.pad.base.algorithm import Algorithm
import numpy
from bob.learn.tensorflow.network.SequenceNetwork import SequenceNetwork
from bob.learn.tensorflow.datashuffler import DiskAudio
import bob.io.base
import tensorflow as tf
import logging
logger = logging.getLogger("bob.pad.voice")
class TensorflowAlgo(Algorithm):
"""This class is used to test all the possible functions of the tool chain, but it does basically nothing."""
def __init__(self,
**kwargs):
"""Generates a test value that is read and written"""
# call base class constructor registering that this tool performs everything.
Algorithm.__init__(
self,
performs_projection=True,
requires_projector_training=False,
)
self.data_reader = DiskAudio([0], [0])
# self.session = tf.Session()
self.dnn_model = None
# def __del__(self):
# self.session.close()
def _check_feature(self, feature):
"""Checks that the features are appropriate."""
if not isinstance(feature, numpy.ndarray) or feature.ndim != 1 or feature.dtype != numpy.float32:
raise ValueError("The given feature is not appropriate", feature)
return True
def load_projector(self, projector_file):
logger.info("Loading pretrained model from {0}".format(projector_file))
self.dnn_model = SequenceNetwork()
# self.dnn_model.load(bob.io.base.HDF5File(projector_file), session=self.session)
self.dnn_model.load(projector_file, True)
def project_feature(self, feature):
logger.debug(" .... Projecting %d features vector" % feature.shape[0])
frames, labels = self.data_reader.extract_frames_from_wav(feature, 0)
frames = numpy.asarray(frames)
logger.debug(" .... And %d frames are extracted to pass into DNN model" % frames.shape[0])
frames = numpy.reshape(frames, (frames.shape[0], -1, 1))
forward_output = self.dnn_model(frames)
# return tf.nn.log_softmax(tf.nn.log_softmax(forward_output)).eval(session=self.session)
return forward_output
def project(self, feature):
"""project(feature) -> projected
This function will project the given feature.
It is assured that the :py:meth:`load_projector` was called once before the ``project`` function is executed.
**Parameters:**
feature : object
The feature to be projected.
**Returns:**
projected : object
The projected features.
Must be writable with the :py:meth:`write_feature` function and readable with the :py:meth:`read_feature` function.
"""
if len(feature) > 0:
feature = numpy.cast['float32'](feature)
self._check_feature(feature)
return self.project_feature(feature)
else:
return numpy.zeros(1, dtype=numpy.float64)
def score_for_multiple_projections(self, toscore):
"""scorescore_for_multiple_projections(toscore) -> score
**Returns:**
score : float
A score value for the object ``toscore``.
"""
scores = numpy.asarray(toscore, dtype=numpy.float32)
real_scores = scores[:, 0]
logger.debug("Mean score %f", numpy.mean(real_scores))
return [numpy.mean(real_scores)]
def score(self, toscore):
"""Returns the evarage value of the probe"""
logger.debug("score() score %f", toscore)
# return only real score
return [toscore[0]]
algorithm = TensorflowAlgo()
......@@ -4,8 +4,8 @@ import bob.pad.voice.database
# directory where the wave files are stored
asvspoof_input_dir = "[YOUR_AVSPOOF_WAV_DIRECTORY]"
asvspoof_input_ext = ".wav"
asvspoof_input_dir = "/idiap/temp/pkorshunov/avspoof_cqcc/ASVspoof_d3"
asvspoof_input_ext = ".mat"
database = bob.pad.voice.database.ASVspoofPadDatabase(
......
......@@ -4,12 +4,12 @@ import bob.pad.voice.database
# directory where the wave files are stored
avspoof_input_dir = "[YOUR_AVSPOOF_WAV_DIRECTORY]"
avspoof_input_ext = ".wav"
avspoof_input_dir = "/idiap/temp/pkorshunov/avspoof_cqcc/AVspoof_d3/btas2016/features/"
avspoof_input_ext = ".mat"
database = bob.pad.voice.database.AVspoofPadDatabase(
protocol='greattest',
protocol='grandtest',
original_directory=avspoof_input_dir,
original_extension=avspoof_input_ext,
training_depends_on_protocol=True,
......
#!/usr/bin/env python
from bob.pad.voice.database import CPqDReplayPadDatabase
# directory where the wave files are stored
voicepa_input_dir = "/idiap/resource/database/CPqD/"
voicepa_input_ext = ".wav"
database = CPqDReplayPadDatabase(
protocol='cpqdlspk1',
original_directory=voicepa_input_dir,
original_extension=voicepa_input_ext,
training_depends_on_protocol=True,
)
......@@ -9,7 +9,7 @@ voicepa_input_ext = ".wav"
database = bob.pad.voice.database.VoicePAPadDatabase(
protocol='greattest',
protocol='grandtest',
original_directory=voicepa_input_dir,
original_extension=voicepa_input_ext,
training_depends_on_protocol=True,
......
......@@ -4,6 +4,7 @@ from .avspoof import AVspoofPadDatabase
from .replay import ReplayPadDatabase
from .replaymobile import ReplayMobilePadDatabase
from .voicepa import VoicePAPadDatabase
from .cpqd_replay import CPqDReplayPadDatabase
# gets sphinx autodoc done right - don't remove it
def __appropriate__(*args):
......@@ -26,5 +27,6 @@ __appropriate__(
ReplayPadDatabase,
ReplayMobilePadDatabase,
VoicePAPadDatabase,
CPqDReplayPadDatabase,
)
__all__ = [_ for _ in dir() if not _.startswith('_')]
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# Pavel Korshunov <pavel.korshunov@idiap.ch>
# Tue 11 Oct 15:43:22 2016
"""
This is a high level interface for presentation attack CPqD Replay database.
It is an extension of an interface defined inside bob.pad.base PAD framework.
"""
from bob.pad.voice.database import PadVoiceFile
from bob.pad.base.database import PadDatabase
class CPqDReplayPadFile(PadVoiceFile):
def __init__(self, f):
"""
Initializes this File object with a File equivalent from the underlying FileList-based interface for
CPqD Replay database.
"""
attacktype = f.attack_type
if attacktype:
attacktype = str(attacktype)
super(CPqDReplayPadFile, self).__init__(client_id=f.client_id, path=f.path, attack_type=attacktype, file_id=f.id)
self.__f = f
class CPqDReplayPadDatabase(PadDatabase):
"""
Implements verification API for querying CPqD Replay database.
"""
def __init__(self, protocol='grandtest', **kwargs):
# call base class constructors to open a session to the database
PadDatabase.__init__(self, name='cpqd_replay', protocol=protocol, **kwargs)
from bob.db.cpqd_replay.query import Database as LowLevelDatabase
self.__db = LowLevelDatabase()
# Since the high level API expects different group names than what the low
# level API offers, you need to convert them when necessary
# self.low_level_group_names = ('train', 'dev', 'eval')
# self.high_level_group_names = ('train', 'dev', 'eval')
def objects(self, groups=None, protocol=None, purposes=None, model_ids=None, **kwargs):
"""Returns a set of Files for the specific query by the user.
Keyword Parameters:
groups
One of the groups ('train', 'dev', 'eval') or a tuple with several of them.
If 'None' is given (this is the default), it is considered the same as a
tuple with all possible values.
protocol
The protocol for which the clients should be retrieved.
The protocol is dependent on your database.
If you do not have protocols defined, just ignore this field.
purposes
The purposes can be either 'real' or 'attack'.
model_ids
This parameter is not supported in this implementation.
Returns: A set of Files with the specified properties.
"""
# we do not need to convert group names, since we have the same ('train', 'dev', 'eval') names as
# high level API
# matched_groups = self.convert_names_to_lowlevel(
# groups, self.low_level_group_names, self.high_level_group_names)
objects = self.__db.objects(protocol=protocol, groups=groups, purposes=purposes, **kwargs)
return [CPqDReplayPadFile(f) for f in objects]
......@@ -4,6 +4,7 @@ from .vectors_ratios import VectorsRatios
from .glcms import GLCMs
from .spectrogram_extended import SpectrogramExtended
from .lbp_histograms import LBPHistograms
from .dummy_tensorflow import DummyTF
# gets sphinx autodoc done right - don't remove it
def __appropriate__(*args):
......@@ -26,5 +27,6 @@ __appropriate__(
GLCMs,
SpectrogramExtended,
LBPHistograms,
DummyTF,
)
__all__ = [_ for _ in dir() if not _.startswith('_')]
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# Pavel Korshunov <pavel.korshunov@idiap.ch>
# Tue 15 Nov 15:43:22 CEST 2016
from bob.bio.base.extractor import Extractor
from bob.bio.spear.preprocessor import Base
import numpy
import logging
logger = logging.getLogger("bob.pad.voice")
class DummyTF(Base, Extractor):
"""
This class can be used as a simple preprocessor (reads data only) and a dummy extractor (reads saved data)
"""
def __init__(self, **kwargs):
Base.__init__(self, **kwargs)
Extractor.__init__(self, requires_training=False, split_training_data_by_client=False, **kwargs)
def __call__(self, input_data, annotations):
"""
We assume here that this will be called only once in the capacity of Preprocessor.
If it is called as an Extractor, it will break. To avoid it, make sure path to preprocessing directory
and extraction directory are the same. It will ensure that both preprocessing and extraction files are
exactly the same, and this called will be executed only the first time (when preprocessing)
"""
# create empty labels array, since this what read/write function of Base accepts
labels = numpy.ones(len(input_data[1]))
return input_data[0], input_data[1], labels
dummytf = DummyTF()
......@@ -61,9 +61,10 @@ class Interface(BaseInterface):
return '0.0.1'
def files(self):
from pkg_resources import resource_filename
raw_files = ('*.wav',)
return [resource_filename(__name__, k) for k in raw_files]
# from pkg_resources import resource_filename
# raw_files = ('*.wav',)
# return [resource_filename(__name__, k) for k in raw_files]
return ()
def type(self):
return 'rawfiles'
......
......@@ -3,11 +3,33 @@
[buildout]
parts = scripts
develop = .
eggs = bob.pad.voice
eggs = bob.pad.voice
bob.pad.base
bob.bio.base
bob.bio.spear
extensions = bob.buildout
newest = false
mr.developer
auto-checkout = *
develop = src/bob.learn.tensorflow
src/bob.bio.base
src/bob.pad.base
src/bob.bio.spear
.
; options for bob.buildout
debug = true
verbose = true
newest = false
[sources]
bob.bio.base = git git@gitlab.idiap.ch:bob/bob.bio.base.git
bob.pad.base = git git@gitlab.idiap.ch:bob/bob.pad.base.git
bob.bio.spear = git git@gitlab.idiap.ch:bob/bob.bio.spear.git
bob.learn.tensorflow = git git@gitlab.idiap.ch:bob/bob.learn.tensorflow.git
[scripts]
recipe = bob.buildout:scripts
......
......@@ -4,7 +4,6 @@
[buildout]
parts = scripts
eggs = gridtk
eggs = bob.pad.voice
bob.bio.spear
......@@ -18,6 +17,10 @@ eggs = bob.pad.voice
bob.db.avspoof
bob.db.voicepa
bob.extension
bob.learn.tensorflow
bob.pad.db
bob.bio.db
bob.db.cpqd_replay
gridtk
extensions = bob.buildout
......@@ -29,11 +32,15 @@ develop = src/bob.bio.spear
src/bob.db.asvspoof
src/bob.db.avspoof
src/bob.db.voicepa
src/bob.db.cpqd_replay
src/bob.pad.base
src/bob.bio.base
src/bob.db.base
src/bob.ap
src/bob.extension
src/bob.learn.tensorflow
src/bob.bio.db
src/bob.pad.db
.
; options for bob.buildout
......@@ -43,7 +50,6 @@ newest = false
[sources]
bob.bio.gmm = git git@gitlab.idiap.ch:bob/bob.bio.gmm.git
bob.bio.spear = git git@gitlab.idiap.ch:bob/bob.bio.spear.git
bob.db.avspoof = git git@gitlab.idiap.ch:bob/bob.db.avspoof.git
bob.db.asvspoof = git git@gitlab.idiap.ch:bob/bob.db.asvspoof.git
bob.db.base = git git@gitlab.idiap.ch:bob/bob.db.base.git
......@@ -52,6 +58,11 @@ bob.pad.base = git git@gitlab.idiap.ch:bob/bob.pad.base.git
bob.ap = git git@gitlab.idiap.ch:bob/bob.ap.git
bob.db.voicepa = git git@gitlab.idiap.ch:bob/bob.db.voicepa.git
bob.extension = git git@gitlab.idiap.ch:bob/bob.extension.git
bob.learn.tensorflow = git branch=epoch git@gitlab.idiap.ch:bob/bob.learn.tensorflow.git
bob.bio.db = git git@gitlab.idiap.ch:bob/bob.bio.db.git
bob.pad.db = git git@gitlab.idiap.ch:bob/bob.pad.db.git
bob.bio.spear = git branch=cpqd git@gitlab.idiap.ch:bob/bob.bio.spear.git
bob.db.cpqd_replay = git git@gitlab.idiap.ch:bob/bob.db.cpqd_replay.git
[scripts]
recipe = bob.buildout:scripts
......
......@@ -112,9 +112,11 @@ setup(
'avspoof = bob.pad.voice.config.database.avspoof:database',
'asvspoof = bob.pad.voice.config.database.asvspoof:database',
'voicepa = bob.pad.voice.config.database.voicepa:database',
'cpqd_replay = bob.pad.voice.config.database.cpqd_replay:database',
],
'bob.pad.algorithm': [
'tensorflow = bob.pad.voice.algorithm.tensorflow_algorithm:algorithm',
'dummy-algo = bob.pad.voice.algorithm.dummy_algorithm:algorithm',
# compute scores based on different energy bands
'logregr = bob.pad.voice.algorithm.logregr_algorithm:algorithm',
......@@ -128,6 +130,8 @@ setup(
],
'bob.pad.preprocessor': [
'cqcc20p = bob.bio.spear.config.extractor.cqcc20:cqcc20', # Empty preprocessor for CQCC features
'dummytfp = bob.pad.voice.extractor.dummy_tensorflow:dummytf', # For tensorflow
'energy-2gauss = bob.bio.spear.config.preprocessor.energy_2gauss:preprocessor', # two Gauss energy
'energy-thr = bob.bio.spear.config.preprocessor.energy_thr:preprocessor',
# thresholded energy
......@@ -136,6 +140,8 @@ setup(
],
'bob.pad.extractor': [
'cqcc20e = bob.bio.spear.config.extractor.cqcc20:cqcc20', # Extractor (reads Matlab files) for CQCC features
'dummytfe = bob.pad.voice.extractor.dummy_tensorflow:dummytf', # For tensorflow
'glcms = bob.pad.voice.extractor.glcms:extractor',
'lbp-hist = bob.pad.voice.extractor.lbp_histograms:extractor',
# LBP-based features as per the paper from Eurecom
......
......@@ -3,4 +3,5 @@ bob.io.image
bob.measure
bob.db.asvspoof
bob.db.avspoof
bob.db.voicepa
\ No newline at end of file
bob.db.voicepa
bob.db.cpqd_replay
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment