Beispiel #1
0
    def test_init(self):

        cases = [('One', Settings()), ('Two', Settings(x=1))]

        for name, defaults in cases:
            t = SettingsType(name, defaults)
            self.assertEqual(t.name, name)
            self.assertEqual(t.defaults, defaults)
Beispiel #2
0
    def test_initializer(self):

        s = Settings()
        self.assertEqual(len(s.__dict__), 0)

        s = Settings(x=1, y=2)
        self.assertEqual(s.x, 1)
        self.assertEqual(s.y, 2)

        defaults = Settings(x=1, y=2)
        s = Settings(defaults, x=3)
        self.assertEqual(s.x, 3)
        self.assertEqual(s.y, 2)
Beispiel #3
0
def compute_spectrogram_normalization_settings(settings):

    # Get settings with waveform time shifting and spectrogram
    # normalization disabled.
    s = Settings(settings,
                 random_waveform_time_shifting_enabled=False,
                 spectrogram_normalization_enabled=False)

    num_examples = s.pretraining_num_examples
    batch_size = s.pretraining_batch_size
    num_batches = int(round(num_examples / batch_size))

    dataset = create_spectrogram_dataset(s.dataset_name,
                                         DATASET_PART_TRAINING,
                                         DATASET_MODE_TRAINING,
                                         s,
                                         batch_size=batch_size)

    iterator = dataset.make_one_shot_iterator()
    next_batch = iterator.get_next()

    with tf.Session() as session:

        print(('Computing spectrogram normalization settings from {} '
               'examples...').format(num_batches * batch_size))

        start_time = time.time()

        num_values = 0
        values_sum = 0
        squares_sum = 0

        for _ in range(num_batches):

            features, _ = session.run(next_batch)
            grams = features['spectrogram']

            num_values += grams.size
            values_sum += grams.sum()
            squares_sum += (grams**2).sum()

            mean = values_sum / num_values
            std_dev = math.sqrt(squares_sum / num_values - mean**2)

            # print(
            #     'Batch {} of {}: ({}, {})'.format(
            #         i + 1, num_batches, mean, std_dev))

        elapsed_time = time.time() - start_time
        print(('Computed spectrogram normalization settings in {:.1f} '
               'seconds.').format(elapsed_time))

    # The float conversions in the following ensure that the assigned
    # type is Python's `float` instead of a NumPy type. The latter
    # doesn't play nicely with `yaml_utils.dump`.
    scale_factor = float(1 / std_dev)
    offset = float(-mean / std_dev)

    return scale_factor, offset
Beispiel #4
0
def complete_settings(settings):

    # Copy settings so we don't modify the originals.
    s = Settings(settings)

    # Get the nominal start time of the portion of a dataset waveform
    # that is used for training. When time shifting data augmentation
    # is enabled, a random offset is added to the nominal start time
    # for each training example to determine the actual start time.
    s.waveform_start_time = \
        s.event_onset_window_start_time - s.waveform_initial_padding

    if s.spectrogram_clipping_enabled and \
            s.spectrogram_clipping_pretraining_enabled and \
            not s.warm_start_enabled:

        min_value, max_value = compute_spectrogram_clipping_settings(s)

        s.spectrogram_clipping_min = min_value
        s.spectrogram_clipping_max = max_value

    if s.spectrogram_normalization_enabled and \
            s.spectrogram_normalization_pretraining_enabled and \
            not s.warm_start_enabled:

        scale_factor, offset = compute_spectrogram_normalization_settings(s)

        s.spectrogram_normalization_scale_factor = scale_factor
        s.spectrogram_normalization_offset = offset

    return s
Beispiel #5
0
def show_spectrogram_dataset(classifier_name):

    total_num_examples = 2**9
    batch_size = 2**6

    settings = get_completed_settings(classifier_name)

    # Show unclipped and unnormalized spectrograms.
    s = Settings(settings,
                 spectrogram_clipping_enabled=False,
                 spectrogram_normalization_enabled=False)

    dataset = create_spectrogram_dataset(s.dataset_name,
                                         DATASET_PART_TRAINING,
                                         DATASET_MODE_TRAINING,
                                         s,
                                         batch_size=batch_size)

    num_batches = int(round(total_num_examples / batch_size))
    dataset_utils.show_dataset(dataset, num_batches)
Beispiel #6
0
def _create_detector_class(threshold_type, threshold):

    threshold_string = f'{threshold:02d}'

    class_name = f'Detector{threshold_type}{threshold_string}'

    extension_name = (
        f'BirdVoxDetect {birdvoxdetect.__version__} {threshold_type} '
        f'{threshold_string}')

    if threshold_type == 'AT':
        detector_name = 'birdvoxdetect-v03_T-1800_trial-37_network_epoch-023'
    else:
        detector_name = 'birdvoxdetect-v03_trial-12_network_epoch-068'

    settings = Settings(detector_name=detector_name, threshold=threshold)

    class_dict = {'extension_name': extension_name, '_settings': settings}

    cls = type(class_name, (_Detector, ), class_dict)

    globals()[class_name] = cls
Beispiel #7
0
    def __init__(self, settings):

        self._settings = settings

        s = settings
        sample_rate = s.waveform_sample_rate

        # Get waveform trimming start and end indices.
        self._start_time_index = signal_utils.seconds_to_frames(
            s.waveform_start_time, sample_rate)
        waveform_length = signal_utils.seconds_to_frames(
            s.waveform_duration, sample_rate)
        self._end_time_index = self._start_time_index + waveform_length

        # Get spectrogram settings.
        window_size = signal_utils.seconds_to_frames(s.spectrogram_window_size,
                                                     sample_rate)
        hop_size = signal_utils.seconds_to_frames(s.spectrogram_hop_size,
                                                  sample_rate)
        dft_size = tfa_utils.get_dft_size(window_size)
        self._spectrogram_settings = Settings(
            window=data_windows.create_window('Hann', window_size),
            hop_size=hop_size,
            dft_size=dft_size,
            reference_power=1)

        # Get spectrogram shape.
        num_spectra = tfa_utils.get_num_analysis_records(
            waveform_length, window_size, hop_size)
        num_bins = dft_size // 2 + 1
        self._spectrogram_shape = (num_spectra, num_bins)
        self._augmented_spectrogram_shape = (1, ) + self._spectrogram_shape

        # Get spectrogram trimming start and end indices.
        self._start_freq_index = _freq_to_dft_bin_num(
            settings.spectrogram_start_freq, sample_rate, dft_size)
        self._end_freq_index = _freq_to_dft_bin_num(
            settings.spectrogram_end_freq, sample_rate, dft_size) + 1
Beispiel #8
0
 def _load_settings(self):
     path = classifier_utils.get_settings_file_path(self._clip_type)
     text = path.read_text()
     d = yaml_utils.load(text)
     return Settings.create_from_dict(d)
Beispiel #9
0
 def test_create_from_yaml_file(self):
     settings = Settings.create_from_yaml_file(_SETTINGS_FILE_PATH)
     self._check_settings(settings)
Beispiel #10
0
 def test_create_from_commented_out_yaml_file(self):
     settings = Settings.create_from_yaml_file(
         _COMMENTED_OUT_SETTINGS_FILE_PATH)
     self._check_empty_settings(settings)
Beispiel #11
0
 def test_create_from_yaml(self):
     contents = os_utils.read_file(_SETTINGS_FILE_PATH)
     settings = Settings.create_from_yaml(contents)
     self._check_settings(settings)
Beispiel #12
0
 def _load_settings(self):
     path = classifier_utils.get_settings_file_path(self.clip_type)
     logging.info('Loading classifier settings from "{}"...'.format(path))
     text = path.read_text()
     d = yaml_utils.load(text)
     return Settings.create_from_dict(d)
Beispiel #13
0
def compute_spectrogram_clipping_settings(settings):

    # Get new settings with waveform time shifting, spectrogram clipping,
    # and spectrogram normalization disabled.
    s = Settings(settings,
                 random_waveform_time_shifting_enabled=False,
                 spectrogram_clipping_enabled=False,
                 spectrogram_normalization_enabled=False)

    num_examples = s.pretraining_num_examples
    batch_size = s.pretraining_batch_size
    num_batches = int(round(num_examples / batch_size))

    hist_min = s.pretraining_histogram_min
    hist_max = s.pretraining_histogram_max
    num_bins = s.pretraining_histogram_num_bins
    bin_size = (hist_max - hist_min) / num_bins
    log_epsilon = math.log(settings.spectrogram_log_epsilon)

    dataset = create_spectrogram_dataset(s.dataset_name,
                                         DATASET_PART_TRAINING,
                                         DATASET_MODE_TRAINING,
                                         s,
                                         batch_size=batch_size)

    iterator = dataset.make_one_shot_iterator()
    next_batch = iterator.get_next()

    with tf.Session() as session:

        print(
            'Computing spectrogram clipping range from {} examples...'.format(
                num_batches * batch_size))

        start_time = time.time()

        histogram = np.zeros(num_bins)

        for _ in range(num_batches):

            features, _ = session.run(next_batch)
            grams = features['spectrogram']

            h, edges = np.histogram(grams, num_bins, (hist_min, hist_max))
            histogram += h

            # If one of the histogram bins includes the log power to which
            # zero spectrogram values are mapped, zero that bin to ensure that
            # it doesn't interfere with computing a good minimum power value.
            if hist_min <= log_epsilon and log_epsilon <= hist_max:
                bin_num = int(math.floor((log_epsilon - hist_min) / bin_size))
                # print('Zeroing histogram bin {}.'.format(bin_num))
                histogram[bin_num] = 0

            # Compute clipping powers.
            cumsum = histogram.cumsum() / histogram.sum()
            threshold = s.pretraining_clipped_values_fraction / 2
            min_index = np.searchsorted(cumsum, threshold, side='right')
            max_index = np.searchsorted(cumsum, 1 - threshold) + 1
            min_value = edges[min_index]
            max_value = edges[max_index]

            # print(
            #     'Batch {} of {}: ({}, {})'.format(
            #         i + 1, num_batches, min_value, max_value))

        elapsed_time = time.time() - start_time
        print('Computed spectrogram clipping range in {:.1f} seconds.'.format(
            elapsed_time))

    # Plot spectrogram value distribution and clipping limits.
    if s.pretraining_value_distribution_plotting_enabled:
        distribution = histogram / histogram.sum()
        plt.figure(1)
        plt.plot(edges[:-1], distribution)
        plt.axvline(min_value, color='r')
        plt.axvline(max_value, color='r')
        plt.xlim((edges[0], edges[-1]))
        plt.title('Distribution of Spectrogram Values')
        plt.xlabel('Log Power')
        plt.show()

    # The float conversions in the following ensure that the assigned
    # type is Python's `float` instead of a NumPy type. The latter
    # doesn't play nicely with `yaml_utils.dump`.
    min_value = float(min_value)
    max_value = float(max_value)

    return min_value, max_value
Beispiel #14
0
 def create_settings_from_yaml(self, s):
     settings = Settings.create_from_yaml(s)
     return Settings(self.defaults, settings)
Beispiel #15
0
 def _assert_created_settings(self, settings):
     expected = Settings(x=1, y=3, z=4)
     self.assertEqual(settings, expected)
Beispiel #16
0
def _thrush_settings(threshold):
    return Settings(_THRUSH_SETTINGS, threshold=threshold / 100)
Beispiel #17
0
def _tseep_settings(threshold):
    return Settings(_TSEEP_SETTINGS, threshold=threshold / 100)
Beispiel #18
0
 def _load_classifier_settings(self):
     s = self._settings
     path = classifier_utils.get_settings_file_path(s.clip_type)
     logging.info('Loading classifier settings from "{}"...'.format(path))
     return Settings.create_from_yaml_file(path)
Beispiel #19
0
from vesper.util.sample_buffer import SampleBuffer
from vesper.util.settings import Settings
import vesper.mpg_ranch.nfc_coarse_classifier_3_0.classifier_utils \
    as classifier_utils
import vesper.mpg_ranch.nfc_coarse_classifier_3_0.dataset_utils \
    as dataset_utils
import vesper.util.open_mp_utils as open_mp_utils
import vesper.util.signal_utils as signal_utils

# TODO: Consider specifying threshold on a scale from 0 to 100 rather
# than on a scale from 0 to 1, since that's how scores are presented
# in the UI.

_TSEEP_SETTINGS = Settings(clip_type='Tseep',
                           input_chunk_size=3600,
                           hop_size=50,
                           threshold=.9,
                           initial_clip_padding=.1,
                           clip_duration=.4)

_THRUSH_SETTINGS = Settings(clip_type='Thrush',
                            input_chunk_size=3600,
                            hop_size=50,
                            threshold=.9,
                            initial_clip_padding=.2,
                            clip_duration=.6)

# Constants controlling detection score output. The output is written to
# a stereo audio file with detector audio input samples in one channel
# and detection scores in the other. It is useful for detector debugging,
# but should be disabled in production.
_SCORE_OUTPUT_ENABLED = False
Beispiel #20
0
TSEEP_SETTINGS = Settings(
    clip_type='Tseep',
    class_count=dataset_utils.CLASS_COUNT,
    waveform_sample_rate=24000,

    # Call start time settings. During training, waveforms are sliced so
    # that call start times are uniformly distributed in the interval
    # from `waveform_slice_min_call_start_time` to
    # `waveform_slice_max_call_start_time`. Set the min and max start
    # times equal to make all calls start at a particular time.
    # waveform_slice_min_call_start_time=.200,
    # waveform_slice_max_call_start_time=.200,
    waveform_slice_min_call_start_time=.000,
    waveform_slice_max_call_start_time=.400,
    waveform_slice_duration=.600,

    # `True` if and only if the waveform amplitude scaling data
    # augmentation is enabled. This augmentation scales each waveform
    # randomly to distribute the waveform log RMS amplitudes uniformly
    # within a roughly 48 dB window.
    waveform_amplitude_scaling_data_augmentation_enabled=False,

    # spectrogram settings
    spectrogram_window_size=.005,
    spectrogram_hop_size=20,
    spectrogram_log_epsilon=1e-10,

    # spectrogram frequency axis slicing settings
    spectrogram_start_freq=4000,
    spectrogram_end_freq=10500,

    # The maximum spectrogram frequency shift for data augmentation,
    # in bins. Set this to zero to disable this augmentation.
    max_spectrogram_frequency_shift=0,
    spectrogram_background_normalization_percentile_rank=40,

    # training settings
    training_batch_size=128,
    training_epoch_step_count=12,  # epoch size is batch size times step count
    training_epoch_count=100,
    model_save_period=5,  # epochs
    dropout_rate=.3,

    # validation settings
    validation_batch_size=1,
    validation_step_count=1000,
)
Beispiel #21
0
 def _load_classifier_settings(self):
     s = self._settings
     path = classifier_utils.get_settings_file_path(s.clip_type)
     logging.info('Loading classifier settings from "{}"...'.format(path))
     return Settings.create_from_yaml_file(path)
Beispiel #22
0
 def create_settings_from_dict(self, d):
     settings = Settings.create_from_dict(d)
     return Settings(self.defaults, settings)
Beispiel #23
0
TSEEP_SETTINGS = Settings(
    clip_type='Tseep',
    bound_type='Start',
    waveform_sample_rate=24000,
    positive_example_probability=.5,
    positive_example_call_start_offset=.025,
    waveform_slice_duration=.080,

    # `True` if and only if the waveform amplitude scaling data
    # augmentation is enabled. This augmentation scales each waveform
    # randomly to distribute the waveform log RMS amplitudes uniformly
    # within a roughly 48 dB window.
    waveform_amplitude_scaling_data_augmentation_enabled=False,

    # spectrogram settings
    spectrogram_window_size=.005,
    spectrogram_hop_size=20,
    spectrogram_log_epsilon=1e-10,

    # spectrogram frequency axis slicing settings
    spectrogram_start_freq=4000,
    spectrogram_end_freq=10500,

    # The maximum spectrogram frequency shift for data augmentation,
    # in bins. Set this to zero to disable this augmentation.
    max_spectrogram_frequency_shift=2,
    spectrogram_background_normalization_percentile_rank=30,

    # training settings
    training_batch_size=128,
    training_epoch_step_count=100,  # epoch size is batch size times step count
    training_epoch_count=30,
    model_save_period=5,  # epochs
    dropout_rate=.25,

    # validation settings
    validation_batch_size=1,
    validation_step_count=1000,

    # evaluation plot settings
    max_evaluation_inlier_diff=20,

    # offsets for converting inference value to spectrogram index
    call_start_index_offset=23,
    call_end_index_offset=22,
)
Beispiel #24
0
 def create_settings_from_yaml_file(self, file_path):
     settings = Settings.create_from_yaml_file(file_path)
     return Settings(self.defaults, settings)
Beispiel #25
0
 def _load_settings(self):
     path = classifier_utils.get_settings_file_path(self.clip_type)
     logging.info('Loading classifier settings from "{}"...'.format(path))
     text = path.read_text()
     d = yaml_utils.load(text)
     return Settings.create_from_dict(d)
Beispiel #26
0
 def _create_test_settings_type(self):
     defaults = Settings(x=1, y=2)
     return SettingsType('Bobo', defaults)
Beispiel #27
0
def _create_at_settings(threshold):
    return Settings(threshold_adaptation_enabled=True, threshold=threshold)
Beispiel #28
0
from pathlib import Path
import os
import sys

from vesper.util.settings import Settings
from vesper.util.settings_type import SettingsType
import vesper.archive_paths as archive_paths


# TODO: Provide an upgrade path from SQLite for PostgreSQL, then deprecate
# SQLite, and then eliminate the `database.engine` setting.


_DEFAULT_SETTINGS = Settings.create_from_yaml('''
database:
    engine: SQLite
''')


_SETTINGS_TYPE = SettingsType('Archive Settings', _DEFAULT_SETTINGS)


_SETTINGS_FILE_NAME = 'Archive Settings.yaml'


def _create_settings():
    archive_dir_path = Path(os.getcwd())
    settings = _load_settings_file(archive_dir_path)
    archive_paths.initialize(archive_dir_path, settings)
    return settings
Beispiel #29
0
 def test_create_from_dict(self):
     contents = os_utils.read_file(_SETTINGS_FILE_PATH)
     d = yaml_utils.load(contents)
     settings = Settings.create_from_dict(d)
     self._check_settings(settings)
Beispiel #30
0
in which the server starts. The archive settings are the composition
of a set of default settings (hard-coded in this module) and settings
(optionally) specified in the file "Archive Settings.yaml" in the
archive directory.
"""

from pathlib import Path
import os
import sys

from vesper.util.settings import Settings
from vesper.util.settings_type import SettingsType
import vesper.archive_paths as archive_paths

_DEFAULT_SETTINGS = Settings.create_from_yaml('''
database:
    engine: SQLite
''')

_SETTINGS_TYPE = SettingsType('Archive Settings', _DEFAULT_SETTINGS)

_SETTINGS_FILE_NAME = 'Archive Settings.yaml'


def _create_settings():
    archive_dir_path = Path(os.getcwd())
    settings = _load_settings_file(archive_dir_path)
    archive_paths.initialize(archive_dir_path, settings)
    return settings


def _load_settings_file(archive_dir_path):
Beispiel #31
0
 def test_create_from_empty_yaml(self):
     settings = Settings.create_from_yaml('')
     self._check_empty_settings(settings)
Beispiel #32
0
def load_training_settings(training_name):
    file_path = get_training_settings_file_path(training_name)
    logging.info(f'Loading annotator settings from "{file_path}"...')
    text = file_path.read_text()
    dict_ = yaml_utils.load(text)
    return Settings.create_from_dict(dict_)
Beispiel #33
0
 def test_create_from_commented_out_yaml(self):
     settings = Settings.create_from_yaml('#')
     self._check_empty_settings(settings)