Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reload tf_indices outside while in get_tensor #57

Merged
merged 4 commits into from
Oct 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .ci/run_checks.bat
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
set DEVICE="/gpu:0"
set DEVICE=%1

cd ..
set DIR=%cd%
set PYOPENCL_CTX=0

pylint nengo_dl --rcfile=setup.cfg
pylint ../nengo_dl --rcfile=../setup.cfg
pytest --pyargs nengo --device=%DEVICE% --dtype=float32 --unroll_simulation=1 || goto :exit
pytest --gpu --device=%DEVICE% --dtype=float32 --unroll_simulation=1 || goto :exit
python nengo_dl/benchmarks.py performance_samples --device %DEVICE% || goto :exit
pytest ../nengo_dl --device=%DEVICE% --dtype=float32 --unroll_simulation=1 || goto :exit
python ../nengo_dl/benchmarks.py performance_samples --device %DEVICE% || goto :exit

cd %TEMP%
python %DIR%docs/whitepaper/whitepaper2018_plots.py --no-show --reps 1 test || goto :exit
python %DIR%/../docs/whitepaper/whitepaper2018_plots.py --no-show --reps 1 test || goto :exit

:exit
cd %DIR%.ci
cd %DIR%
exit /b %errorlevel%
11 changes: 11 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,25 @@ Release History
1.2.1 (unreleased)
------------------

**Added**

- Added a warning if users run one-timestep training with a network containing
synaptic filters.

**Changed**

- Test Simulator parameters are now controlled through pytest arguments,
rather than environment variables.
- Disable INFO-level TensorFlow logging (from C side) on import. Added a
NengoDL log message indicating the device the simulation will run on, as
a more concise replacement.

**Fixed**

- Avoid backpropagating NaN gradients from spiking neurons.
- Fixed an error that was thrown when calling ``get_tensor`` on a ``Signal``
that was first initialized inside the Simulation while loop
(`#56 <https://github.com/nengo/nengo-dl/issues/56>`_)

1.2.0 (September 5, 2018)
-------------------------
Expand Down
14 changes: 10 additions & 4 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import pkg_resources

import nengo.conftest
from nengo.conftest import seed # pylint: disable=unused-import
from nengo.tests import test_synapses, test_learning_rules
Expand All @@ -9,8 +11,8 @@


def pytest_runtest_setup(item):
if getattr(item.obj, "gpu", False) and not item.config.getvalue("--gpu"):
pytest.skip("GPU tests not requested")
if getattr(item.obj, "gpu", False) and not pytest.gpu_installed:
pytest.skip("This test requires tensorflow-gpu")
elif (hasattr(item, "fixturenames") and
"Simulator" not in item.fixturenames and
item.config.getvalue("--simulator-only")):
Expand All @@ -21,8 +23,6 @@ def pytest_runtest_setup(item):


def pytest_addoption(parser):
parser.addoption("--gpu", action="store_true", default=False,
help="Run GPU tests")
parser.addoption("--simulator-only", action="store_true", default=False,
help="Only run tests involving Simulator")
parser.addoption("--inference-only", action="store_true", default=False,
Expand All @@ -36,6 +36,12 @@ def pytest_addoption(parser):
help="device parameter for Simulator")


def pytest_namespace():
installed_dists = [d.project_name for d in pkg_resources.working_set]
return {"gpu_installed": ("tensorflow-gpu" in installed_dists or
"tf-nightly-gpu" in installed_dists)}


@pytest.fixture(scope="session")
def Simulator(request):
"""Simulator class to be used in tests (use this instead of
Expand Down
9 changes: 7 additions & 2 deletions nengo_dl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
tensorflow_patch.patch_state_grads()

# filter out "INFO" level log messages
import tensorflow as tf # pylint: disable=wrong-import-order,wrong-import-position
# pylint: disable=wrong-import-order,wrong-import-position
import os
import tensorflow as tf
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "1"
tf.logging.set_verbosity(tf.logging.WARN)
del tf # we don't want a nengo_dl.tf attribute
# we don't want a nengo_dl.tf/os attribute
del os
del tf
27 changes: 18 additions & 9 deletions nengo_dl/simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,16 @@ def __init__(self, network, dt=0.001, seed=None, model=None,

# TODO: multi-GPU support

if device is None:
# check GPU support
installed_dists = [d.project_name for d in
pkg_resources.working_set]
if ("tensorflow-gpu" not in installed_dists and
"tf-nightly-gpu" not in installed_dists):
warnings.warn(
"No GPU support detected. It is recommended that you "
"install tensorflow-gpu (`pip install tensorflow-gpu`).")
installed_dists = [d.project_name for d in pkg_resources.working_set]
if device is None and ("tensorflow-gpu" not in installed_dists and
"tf-nightly-gpu" not in installed_dists):
warnings.warn(
"No GPU support detected. It is recommended that you "
"install tensorflow-gpu (`pip install tensorflow-gpu`).")
logger.info("Running on CPU")
else:
logger.info("Running on %s", "CPU/GPU" if device is None else (
"CPU" if "cpu" in device else "GPU"))

ProgressBar = (utils.ProgressBar if progress_bar else
utils.NullProgressBar)
Expand Down Expand Up @@ -500,6 +501,14 @@ def train(self, inputs, targets, optimizer, n_epochs=1, objective="mse",
raise ValidationError(
"Network was created with inference_only=True, cannot "
"be trained", "inference_only")
if (n_steps == 1 and self.model.toplevel is not None and
any(x.synapse is not None for x in
(self.model.toplevel.all_connections +
list(targets.keys())))):
warnings.warn(
"Training for one timestep, but the network contains "
"synaptic filters (which will introduce at least a "
"one-timestep delay); did you mean to set synapse=None?")

# check for non-differentiable elements in graph
# utils.find_non_differentiable(
Expand Down
5 changes: 5 additions & 0 deletions nengo_dl/tensor_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,11 @@ def get_tensor(self, sig):
tensor_sig = self.signals[sig]

base = self.base_vars[tensor_sig.key][0]

if "while/" in tensor_sig.tf_indices.name:
# rebuild tf indices outside the while loop
tensor_sig._tf_indices = None

return tf.gather(base, tensor_sig.tf_indices)

def mark_signals(self):
Expand Down
10 changes: 8 additions & 2 deletions nengo_dl/tests/test_benchmarks.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import pytest
import nengo
import tensorflow as tf

from nengo_dl import benchmarks, SoftLIFRate

Expand Down Expand Up @@ -93,10 +94,15 @@ def _test_random(net, dimensions, neurons_per_d, neuron_type, n_ensembles,


@pytest.mark.parametrize("train", (True, False))
def test_run_profile(train):
def test_run_profile(train, pytestconfig):
net = benchmarks.integrator(3, 2, nengo.RectifiedLinear())

benchmarks.run_profile(net, train=train, n_steps=10, do_profile=False)
benchmarks.run_profile(
net, train=train, n_steps=10, do_profile=False,
device=pytestconfig.getvalue("--device"),
unroll_simulation=pytest.config.getvalue("--unroll_simulation"),
dtype=(tf.float32 if pytest.config.getvalue("dtype") == "float32" else
tf.float64))

assert net.config[net].inference_only == (False if train else True)

Expand Down
56 changes: 53 additions & 3 deletions nengo_dl/tests/test_simulator.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from collections import OrderedDict
import logging
import os

import nengo
Expand Down Expand Up @@ -491,9 +492,13 @@ def test_model_passing(Simulator, seed):
assert np.allclose(sim.data[p], canonical)


@pytest.mark.gpu
@pytest.mark.parametrize("device", ["/cpu:0", "/gpu:0", None])
def test_devices(Simulator, device, seed):
def test_devices(Simulator, device, seed, caplog, pytestconfig):
if device == "/gpu:0" and not pytest.gpu_installed:
pytest.skip("This test requires tensorflow-gpu")

caplog.set_level(logging.INFO)

with nengo.Network(seed=seed) as net:
inp = nengo.Node([0])
ens = nengo.Ensemble(10, 1)
Expand All @@ -508,6 +513,16 @@ def test_devices(Simulator, device, seed):
sim.run_steps(50)
assert np.allclose(sim.data[p], canonical)

if device == "/cpu:0":
assert "Running on CPU" in caplog.text
elif device == "/gpu:0":
assert "Running on GPU" in caplog.text
elif pytest.gpu_installed:
assert "Running on CPU/GPU" in caplog.text
else:
# device is None but gpu not installed
assert "Running on CPU" in caplog.text


def test_side_effects(Simulator):
class MyFunc:
Expand Down Expand Up @@ -1292,7 +1307,7 @@ def test_inference_only(Simulator, neuron_type, seed):
# validation checks (can't do train/gradients in inference-only mode)
with pytest.raises(ValidationError):
sim2.train({a: np.zeros((1, 10, 1))}, {p: np.zeros((1, 10, 1))},
tf.train.GradientDescentOptimizer(1))
tf.train.GradientDescentOptimizer(1))

with pytest.raises(ValidationError):
sim2.check_gradients()
Expand All @@ -1302,3 +1317,38 @@ def test_dtype(Simulator):
with pytest.warns(DeprecationWarning):
with Simulator(None, dtype=tf.float32) as sim:
assert sim.tensor_graph.dtype == tf.float32


@pytest.mark.training
def test_synapse_warning(Simulator):
with nengo.Network() as net:
a = nengo.Node([0])
b = nengo.Ensemble(10, 1)
c = nengo.Connection(a, b, synapse=1)
p = nengo.Probe(b)
p2 = nengo.Probe(b)

def does_warn(n_steps=1):
with Simulator(net, unroll_simulation=1) as sim:
with pytest.warns(UserWarning) as rec:
sim.train({a: np.zeros((1, n_steps, 1))},
{p: np.zeros((1, n_steps, 1))},
tf.train.GradientDescentOptimizer(0))
return any(str(w.message).startswith("Training for one timestep")
for w in rec)

# warning from connection
assert does_warn()

# warning from probe
c.synapse = None
p.synapse = 1
assert does_warn()

# no warning for >1 step training
assert not does_warn(n_steps=2)

# no warning from non-target probe
p.synapse = None
p2.synapse = 1
assert not does_warn()
21 changes: 21 additions & 0 deletions nengo_dl/tests/test_tensor_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,3 +395,24 @@ def test_create_signals_partition():
graph = dummies.TensorGraph(plan, tf.float32, 10)
graph.create_signals(sigs)
assert len(graph.base_arrays_init) == 4


def test_get_tensor(Simulator):
with nengo.Network() as net:
a = nengo.Node([1])
b = nengo.Ensemble(10, 1)
c = nengo.Connection(a, b.neurons, transform=np.arange(10)[:, None],
synapse=None)
p = nengo.Probe(c)

# build a signal probe so that the indices get loaded into the sim
# (checks that the indices reloading works properly)
nengo.Probe(c, "weights")

with Simulator(net) as sim:
tensor = sim.tensor_graph.get_tensor(sim.model.sig[c]["weights"])

assert np.allclose(sim.sess.run(tensor), np.arange(10)[:, None])

sim.run_steps(10)
assert np.allclose(sim.data[p], np.arange(10)[None, :])