Skip to content

Commit

Permalink
unit test for set_random_state, deepcopy for the seed, updated docs
Browse files Browse the repository at this point in the history
  • Loading branch information
pseeth committed Feb 2, 2020
1 parent 8c056bd commit 0cac882
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 74 deletions.
14 changes: 3 additions & 11 deletions docs/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,7 @@ Example: synthesizing 1000 soundscapes in one go
time_stretch_max = 1.2
# generate a random seed for this Scaper object
seed = np.random.randint(0, 100000)
## alternate ways to define random state:
# seed = np.random.RandomState(0)
#
# or don't define any random state. runs will be random and not reproducible in
# this case. you can use np.random.get_state() to reproduce the run after the fact
# if needed:
# seed = None
seed = 123
# create a scaper that will be used below
sc = scaper.Scaper(duration, fg_folder, bg_folder, random_state=seed)
Expand All @@ -70,8 +62,8 @@ Example: synthesizing 1000 soundscapes in one go
print('Generating soundscape: {:d}/{:d}'.format(n+1, n_soundscapes))
# reset the event specifications for foreground and background at the beginning
# of each loop.
# reset the event specifications for foreground and background at the
# beginning of each loop to clear all previously added events
sc.reset_bg_spec()
sc.reset_fg_spec()
Expand Down
17 changes: 14 additions & 3 deletions docs/tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,9 @@ A further argument can be specified to the ``Scaper`` object:
In the latter case, a random state will be constructed. The random state is what will
be used for drawing from any distributions. If the audio kept in all of the folders is
exactly the same and the random state is fixed between runs, the same soundscape will be
generated both times.
generated both times. If you don't define any random state or set seed to None, runs
will be random and not reproducible. You can use np.random.get_state() to reproduce
the run after the fact by recording the seed that was used somewhere.

This can be specified like so (e.g. for a random seed of 0):

Expand All @@ -118,7 +120,7 @@ This can be specified like so (e.g. for a random seed of 0):
import scaper
import os
soundscape_duration = 10.0
seed = 0
seed = 123
foreground_folder = os.path.expanduser('~/audio/foreground/')
background_folder = os.path.expanduser('~/audio/background/')
sc = scaper.Scaper(soundscape_duration, foreground_folder, background_folder,
Expand All @@ -127,7 +129,16 @@ This can be specified like so (e.g. for a random seed of 0):
If the random state is not specified, it defaults to the old behavior which just uses
the RandomState used by np.random. You can also set the random state after creation
via ``Scaper.set_random_state``.
via ``Scaper.set_random_state``. Alternatively, you can set the random state directly:

.. code-block:: python
import numpy as np
seed = np.random.RandomState(123)
sc = scaper.Scaper(soundscape_duration, foreground_folder, background_folder,
random_state=seed)
sc.ref_db = -20
Adding a background and foreground sound events
-----------------------------------------------
Expand Down
3 changes: 2 additions & 1 deletion scaper/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import scipy
import numpy as np
import numbers
from copy import deepcopy


@contextmanager
Expand Down Expand Up @@ -168,7 +169,7 @@ def _check_random_state(seed):
elif isinstance(seed, (numbers.Integral, np.integer, int)):
return np.random.RandomState(seed)
elif isinstance(seed, np.random.RandomState):
return seed
return deepcopy(seed)
else:
raise ValueError('%r cannot be used to seed a numpy.random.RandomState'
' instance' % seed)
Expand Down
138 changes: 79 additions & 59 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -751,8 +751,7 @@ def test_scaper_init():
assert sc.fade_out_len == 0.01 # 10 ms


def test_scaper_reset():

def test_reset_fg_bg_event_spec():
def _add_fg_event(sc):
sc.add_event(label=('const', 'siren'),
source_file=('choose', []),
Expand Down Expand Up @@ -1106,67 +1105,88 @@ def test_generate_with_seeding(atol=1e-4, rtol=1e-8):
scaper.util._check_random_state(10),
scaper.util._check_random_state(20)
]
num_generators = 3
num_generators = 2
for seed in seeds:
generators = []
for i in range(num_generators - 1):
for i in range(num_generators):
generators.append(_create_scaper_with_random_seed(seed))

_compare_generators(generators)


def test_set_random_state(atol=1e-4, rtol=1e-8):
# test a scaper generator with different random seeds. init with same random seed
# over and over to make sure the output wav stays the same
seeds = [
0, 10, 20,
scaper.util._check_random_state(0),
scaper.util._check_random_state(10),
scaper.util._check_random_state(20)
]
num_generators = 2
for seed in seeds:
print(seed)
generators = []
for i in range(num_generators):
_sc = _create_scaper_with_random_seed(None)
_sc.set_random_state(seed)
generators.append(_sc)

_compare_generators(generators)

def _compare_generators(generators, atol=1e-4, rtol=1e-8):
tmpfiles = []
with _close_temp_files(tmpfiles):
wav_files = [
tempfile.NamedTemporaryFile(suffix='.wav', delete=True)
for i in range(len(generators))
]
jam_files = [
tempfile.NamedTemporaryFile(suffix='.jams', delete=True)
for i in range(len(generators))
]
txt_files = [
tempfile.NamedTemporaryFile(suffix='.txt', delete=True)
for i in range(len(generators))
]

tmpfiles += wav_files + jam_files + txt_files
for i, sc in enumerate(generators):
generators[i].generate(
wav_files[i].name, jam_files[i].name, txt_path=txt_files[i].name,
disable_instantiation_warnings=True
)

audio = [soundfile.read(wav_file.name)[0] for wav_file in wav_files]
for i, a in enumerate(audio):
assert np.allclose(audio[0], a, atol=atol, rtol=rtol)

# load all the jams data
# make sure they are all the same as the first one
jams_data = [jams.load(jam_file.name) for jam_file in jam_files]
for x in jams_data:
_compare_scaper_jams(x, jams_data[0])

# load the txt files and compare them
def _load_txt(txt_file):
txt_data = []
with open(txt_file.name) as file:
reader = csv.reader(file, delimiter='\t')
for row in reader:
txt_data.append(row)
txt_data = np.asarray(txt_data)
return txt_data

generators.append(_create_scaper_with_random_seed(seed))
generators[-1].set_random_state(seed)

tmpfiles = []
with _close_temp_files(tmpfiles):
wav_files = [
tempfile.NamedTemporaryFile(suffix='.wav', delete=True)
for i in range(num_generators)
]
jam_files = [
tempfile.NamedTemporaryFile(suffix='.jams', delete=True)
for i in range(num_generators)
]
txt_files = [
tempfile.NamedTemporaryFile(suffix='.txt', delete=True)
for i in range(num_generators)
]

tmpfiles += wav_files + jam_files + txt_files
for i, sc in enumerate(generators):
generators[i].generate(
wav_files[i].name, jam_files[i].name, txt_path=txt_files[i].name,
disable_instantiation_warnings=True
)

audio = [soundfile.read(wav_file.name)[0] for wav_file in wav_files]
for i, a in enumerate(audio):
assert np.allclose(audio[0], a, atol=atol, rtol=rtol)

# load all the jams data
# make sure they are all the same as the first one
jams_data = [jams.load(jam_file.name) for jam_file in jam_files]
for x in jams_data:
_compare_scaper_jams(x, jams_data[0])

# load the txt files and compare them
def _load_txt(txt_file):
txt_data = []
with open(txt_file.name) as file:
reader = csv.reader(file, delimiter='\t')
for row in reader:
txt_data.append(row)
txt_data = np.asarray(txt_data)
return txt_data

txt_data = [_load_txt(txt_file) for txt_file in txt_files]
regtxt_data = txt_data[0]

for t in txt_data:
assert np.allclose([float(x) for x in t[:, 0]],
[float(x) for x in regtxt_data[:, 0]])
assert np.allclose([float(x) for x in t[:, 1]],
[float(x) for x in regtxt_data[:, 1]])
# compare labels
assert (t[:, 2] == regtxt_data[:, 2]).all()
txt_data = [_load_txt(txt_file) for txt_file in txt_files]
regtxt_data = txt_data[0]

for t in txt_data:
assert np.allclose([float(x) for x in t[:, 0]],
[float(x) for x in regtxt_data[:, 0]])
assert np.allclose([float(x) for x in t[:, 1]],
[float(x) for x in regtxt_data[:, 1]])
# compare labels
assert (t[:, 2] == regtxt_data[:, 2]).all()


def _create_scaper_with_random_seed(seed):
Expand Down

0 comments on commit 0cac882

Please sign in to comment.