def __init__( self, network, dt=0.001, seed=None, model=None, progress_bar=True): self.closed = False self.progress_bar = progress_bar if model is None: self._model = Model(dt=float(dt), label="%s, dt=%f" % (network, dt), decoder_cache=get_default_decoder_cache()) else: self._model = model if network is not None: # Build the network into the model self._model.build(network, progress_bar=self.progress_bar) # -- map from Signal.base -> ndarray self.signals = SignalDict() for op in self._model.operators: op.init_signals(self.signals) # Order the steps (they are made in `Simulator.reset`) self.dg = operator_depencency_graph(self._model.operators) self._step_order = [op for op in toposort(self.dg) if hasattr(op, 'make_step')] # Add built states to the probe dictionary self._probe_outputs = self._model.params # Provide a nicer interface to probe outputs self.data = ProbeDict(self._probe_outputs) seed = np.random.randint(npext.maxint) if seed is None else seed self.reset(seed=seed)
def __init__(self, network, dt=0.001, seed=None, model=None): self.closed = False if model is None: dt = float(dt) # make sure it's a float (for division purposes) self.model = Model(dt=dt, label="%s, dt=%f" % (network, dt), decoder_cache=get_default_decoder_cache()) else: self.model = model if network is not None: # Build the network into the model self.model.build(network) self.model.decoder_cache.shrink() # -- map from Signal.base -> ndarray self.signals = SignalDict() for op in self.model.operators: op.init_signals(self.signals) # Order the steps (they are made in `Simulator.reset`) self.dg = operator_depencency_graph(self.model.operators) self._step_order = [op for op in toposort(self.dg) if hasattr(op, 'make_step')] # Add built states to the probe dictionary self._probe_outputs = self.model.params # Provide a nicer interface to probe outputs self.data = ProbeDict(self._probe_outputs) seed = np.random.randint(npext.maxint) if seed is None else seed self.reset(seed=seed)
def _get_host_model(network, dt, seeds, seeded): model = nengo.builder.Model( dt=float(dt), label="%s, dt=%f" % (network, dt), decoder_cache=get_default_decoder_cache()) model.seeds.update(seeds) model.seeded.update(seeded) return model
def __init__(self, network, dt=0.001, seed=None, model=None, progress_bar=True, optimize=True): self.closed = True # Start closed in case constructor raises exception self.progress_bar = progress_bar self.optimize = optimize if model is None: self.model = Model( dt=float(dt), label="%s, dt=%f" % (network, dt), decoder_cache=get_default_decoder_cache(), ) else: self.model = model pt = ProgressTracker(progress_bar, Progress("Building", "Build")) with pt: if network is not None: # Build the network into the model self.model.build(network, progress=pt.next_stage("Building", "Build")) # Order the steps (they are made in `Simulator.reset`) self.dg = operator_dependency_graph(self.model.operators) if optimize: with pt.next_stage("Building (running optimizer)", "Optimization"): opmerge_optimize(self.model, self.dg) self._step_order = [ op for op in toposort(self.dg) if hasattr(op, "make_step") ] # -- map from Signal.base -> ndarray self.signals = SignalDict() for op in self.model.operators: op.init_signals(self.signals) # Add built states to the raw simulation data dictionary self._sim_data = self.model.params # Provide a nicer interface to simulation data self.data = SimulationData(self._sim_data) if seed is None: if network is not None and network.seed is not None: seed = network.seed + 1 else: seed = np.random.randint(npext.maxint) self.closed = False self.reset(seed=seed)
def __init__(self, network, dt=0.001, seed=None, model=None, context=None, n_prealloc_probes=32, profiling=None, if_python_code='none', planner=greedy_planner, progress_bar=True): # --- check version if nengo.version.version_info in bad_nengo_versions: raise ValueError( "This simulator does not support Nengo version %s. Upgrade " "with 'pip install --upgrade --no-deps nengo'." % nengo.__version__) elif nengo.version.version_info > latest_nengo_version_info: warnings.warn("This version of `nengo_ocl` has not been tested " "with your `nengo` version (%s). The latest fully " "supported version is %s" % (nengo.__version__, latest_nengo_version)) # --- create these first since they are used in __del__ self.closed = False self.model = None # --- arguments/attributes if context is None and Simulator.some_context is None: print('No context argument was provided to nengo_ocl.Simulator') print("Calling pyopencl.create_some_context() for you now:") Simulator.some_context = cl.create_some_context() if profiling is None: profiling = int(os.getenv("NENGO_OCL_PROFILING", 0)) self.context = Simulator.some_context if context is None else context self.profiling = profiling self.queue = cl.CommandQueue( self.context, properties=PROFILING_ENABLE if self.profiling else 0) if if_python_code not in ['none', 'warn', 'error']: raise ValueError("%r not a valid value for `if_python_code`" % if_python_code) self.if_python_code = if_python_code self.n_prealloc_probes = n_prealloc_probes self.progress_bar = progress_bar # --- Nengo build with Timer() as nengo_timer: if model is None: self.model = Model(dt=float(dt), label="%s, dt=%f" % (network, dt), decoder_cache=get_default_decoder_cache()) else: self.model = model if network is not None: # Build the network into the model self.model.build(network) logger.info("Nengo build in %0.3f s" % nengo_timer.duration) # --- operators with Timer() as planner_timer: operators = list(self.model.operators) # convert DotInc and Copy to MultiDotInc operators = list(map(MultiDotInc.convert_to, operators)) operators = MultiDotInc.compress(operators) # plan the order of operations, combining where appropriate op_groups = planner(operators) assert len([typ for typ, _ in op_groups if typ is Reset ]) < 2, ("All resets not planned together") self.operators = operators self.op_groups = op_groups logger.info("Planning in %0.3f s" % planner_timer.duration) with Timer() as signals_timer: # Initialize signals all_signals = stable_unique(sig for op in operators for sig in op.all_signals) all_bases = stable_unique(sig.base for sig in all_signals) sigdict = SignalDict() # map from Signal.base -> ndarray for op in operators: op.init_signals(sigdict) # Add built states to the probe dictionary self._probe_outputs = dict(self.model.params) # Provide a nicer interface to probe outputs self.data = ProbeDict(self._probe_outputs) # Create data on host and add views self.all_data = RaggedArray( [sigdict[sb] for sb in all_bases], names=[getattr(sb, 'name', '') for sb in all_bases], dtype=np.float32) view_builder = ViewBuilder(all_bases, self.all_data) view_builder.setup_views(operators) for probe in self.model.probes: view_builder.append_view(self.model.sig[probe]['in']) view_builder.add_views_to(self.all_data) self.all_bases = all_bases self.sidx = { k: np.int32(v) for k, v in iteritems(view_builder.sidx) } self._A_views = view_builder._A_views self._X_views = view_builder._X_views self._YYB_views = view_builder._YYB_views del view_builder # Copy data to device self.all_data = CLRaggedArray(self.queue, self.all_data) logger.info("Signals in %0.3f s" % signals_timer.duration) # --- set seed self.seed = np.random.randint(npext.maxint) if seed is None else seed self.rng = np.random.RandomState(self.seed) # --- create list of plans self._raggedarrays_to_reset = {} self._cl_rngs = {} self._python_rngs = {} plans = [] with Timer() as plans_timer: for op_type, op_list in op_groups: plans.extend(self.plan_op_group(op_type, op_list)) plans.extend(self.plan_probes()) logger.info("Plans in %0.3f s" % plans_timer.duration) # -- create object to execute list of plans self._plans = Plans(plans, self.profiling) self.rng = None # all randomness set, should no longer be used self._reset_probes() # clears probes from previous model builds
def __init__( self, network, dt=0.001, seed=None, model=None, partitioner=None, assignments=None, save_file=""): """ A simulator that can be executed in parallel using MPI. Parameters ---------- network : nengo.Network A network object to be built and then simulated. dt : float The length of a simulator timestep, in seconds. seed : int A seed for all stochastic operators used in this simulator. Note that there are not stochastic operators implemented currently, so this parameters does nothing. model : nengo.builder.Model A model object that contains build artifacts to be simulated. Usually the simulator will build this model for you; however, if you want to build the network manually, or to inject some build artifacts in the Model before building the network, then you can pass in an instance of ``MpiModel`` instance or a ``nengo.builder.Model`` instance. If the latter, it will be converted into an ``MpiModel``. partitioner: Partitioner Specifies how to assign nengo objects to MPI processes. ``partitioner`` and ``assignment`` cannot both be supplied. assignments: dict Dictionary mapping from nengo objects to indices of partition components. ``partitioner`` and ``assignment`` cannot both be supplied. save_file: string Name of file that will store all data added to the simulator. The simulator can later be reconstructed from this file. If equal to the empty string, then no file is created. """ print("Beginning build of MPI model...") then = time.time() self.runnable = not save_file if self.runnable and self._open_simulators: raise RuntimeError( "Attempting to create active instance of nengo_mpi.Simulator " "while another instance exists that has not been " "closed. Call `close` on existing instances before " "creating new ones.") if partitioner is not None and assignments is not None: raise ValueError( "Cannot supply both ``assignments'' and ``partitioner'' to " "Simulator.__init__.") if assignments is not None: p = verify_assignments(network, assignments) else: if partitioner is None: partitioner = Partitioner() print(" Partitioning network...") p = partitioner.partition(network) self.n_components, self.assignments = p dt = float(dt) self.model = MpiModel( self.n_components, self.assignments, dt=dt, label="%s, dt=%f" % (network, dt), decoder_cache=get_default_decoder_cache(), save_file=save_file) print(" Calling build...") MpiBuilder.build(self.model, network) self.model.decoder_cache.shrink() print(" Finalizing build...") self.model.finalize_build() # probe -> list self._probe_outputs = self.model.params self.data = ProbeDict(self._probe_outputs) if self.runnable: self._open_simulators.append(self) seed = np.random.randint(npext.maxint) if seed is None else seed self.reset(seed=seed) print("Building network took %f seconds." % (time.time() - then))
def __init__(self, network, dt=0.001, seed=None, model=None, planner=greedy_planner): with Timer() as nengo_timer: if model is None: self.model = Model(dt=float(dt), label="%s, dt=%f" % (network, dt), decoder_cache=get_default_decoder_cache()) else: self.model = model if network is not None: # Build the network into the model self.model.build(network) logger.info("Nengo build in %0.3f s" % nengo_timer.duration) # --- set seed seed = np.random.randint(npext.maxint) if seed is None else seed self.seed = seed self.rng = np.random.RandomState(self.seed) self._step = Signal(np.array(0.0, dtype=np.float64), name='step') self._time = Signal(np.array(0.0, dtype=np.float64), name='time') # --- operators with Timer() as planner_timer: operators = list(self.model.operators) # convert DotInc, Reset, Copy, and ProdUpdate to MultiProdUpdate operators = list(map(MultiProdUpdate.convert_to, operators)) operators = MultiProdUpdate.compress(operators) # plan the order of operations, combining where appropriate op_groups = planner(operators) assert len([typ for typ, _ in op_groups if typ is Reset ]) < 2, ("All resets not planned together") # add time operator after planning, to ensure it goes first time_op = TimeUpdate(self._step, self._time) operators.insert(0, time_op) op_groups.insert(0, (type(time_op), [time_op])) self.operators = operators self.op_groups = op_groups logger.info("Planning in %0.3f s" % planner_timer.duration) with Timer() as signals_timer: # Initialize signals all_signals = signals_from_operators(operators) all_bases = stable_unique([sig.base for sig in all_signals]) sigdict = SignalDict() # map from Signal.base -> ndarray for op in operators: op.init_signals(sigdict) # Add built states to the probe dictionary self._probe_outputs = self.model.params # Provide a nicer interface to probe outputs self.data = ProbeDict(self._probe_outputs) self.all_data = RaggedArray( [sigdict[sb] for sb in all_bases], [getattr(sb, 'name', '') for sb in all_bases], dtype=np.float32) builder = ViewBuilder(all_bases, self.all_data) self._AX_views = {} self._YYB_views = {} for op_type, op_list in op_groups: self.setup_views(builder, op_type, op_list) for probe in self.model.probes: builder.append_view(self.model.sig[probe]['in']) builder.add_views_to(self.all_data) self.all_bases = all_bases self.sidx = builder.sidx self._prep_all_data() logger.info("Signals in %0.3f s" % signals_timer.duration) # --- create list of plans with Timer() as plans_timer: self._plan = [] for op_type, op_list in op_groups: self._plan.extend(self.plan_op_group(op_type, op_list)) self._plan.extend(self.plan_probes()) logger.info("Plans in %0.3f s" % plans_timer.duration) self.n_steps = 0
def __init__(self, network, dt=0.001, seed=None, model=None, planner=greedy_planner): with Timer() as nengo_timer: if model is None: self.model = Model(dt=float(dt), label="%s, dt=%f" % (network, dt), decoder_cache=get_default_decoder_cache()) else: self.model = model if network is not None: # Build the network into the model self.model.build(network) logger.info("Nengo build in %0.3f s" % nengo_timer.duration) # --- set seed seed = np.random.randint(npext.maxint) if seed is None else seed self.seed = seed self.rng = np.random.RandomState(self.seed) self._step = Signal(np.array(0.0, dtype=np.float64), name='step') self._time = Signal(np.array(0.0, dtype=np.float64), name='time') # --- operators with Timer() as planner_timer: operators = list(self.model.operators) # convert DotInc, Reset, Copy, and ProdUpdate to MultiProdUpdate operators = list(map(MultiProdUpdate.convert_to, operators)) operators = MultiProdUpdate.compress(operators) # plan the order of operations, combining where appropriate op_groups = planner(operators) assert len([typ for typ, _ in op_groups if typ is Reset]) < 2, ( "All resets not planned together") # add time operator after planning, to ensure it goes first time_op = TimeUpdate(self._step, self._time) operators.insert(0, time_op) op_groups.insert(0, (type(time_op), [time_op])) self.operators = operators self.op_groups = op_groups logger.info("Planning in %0.3f s" % planner_timer.duration) with Timer() as signals_timer: # Initialize signals all_signals = signals_from_operators(operators) all_bases = stable_unique([sig.base for sig in all_signals]) sigdict = SignalDict() # map from Signal.base -> ndarray for op in operators: op.init_signals(sigdict) # Add built states to the probe dictionary self._probe_outputs = self.model.params # Provide a nicer interface to probe outputs self.data = ProbeDict(self._probe_outputs) self.all_data = RaggedArray( [sigdict[sb] for sb in all_bases], [getattr(sb, 'name', '') for sb in all_bases], dtype=np.float32) builder = ViewBuilder(all_bases, self.all_data) self._AX_views = {} self._YYB_views = {} for op_type, op_list in op_groups: self.setup_views(builder, op_type, op_list) for probe in self.model.probes: builder.append_view(self.model.sig[probe]['in']) builder.add_views_to(self.all_data) self.all_bases = all_bases self.sidx = builder.sidx self._prep_all_data() logger.info("Signals in %0.3f s" % signals_timer.duration) # --- create list of plans with Timer() as plans_timer: self._plan = [] for op_type, op_list in op_groups: self._plan.extend(self.plan_op_group(op_type, op_list)) self._plan.extend(self.plan_probes()) logger.info("Plans in %0.3f s" % plans_timer.duration) self.n_steps = 0
def __init__(self, network, dt=0.001, period=10.0, timescale=1.0): """Create a new Simulator with the given network. Parameters ---------- period : float or None Duration of one period of the simulator. This determines how much memory will be allocated to store precomputed and probed data. timescale : float Scaling factor to apply to the simulation, e.g., a value of `0.5` will cause the simulation to run at half real-time. """ # Add this simulator to the set of open simulators Simulator._add_simulator(self) # Create a controller for the machine and boot if necessary hostname = rc.get("spinnaker_machine", "hostname") machine_width = rc.getint("spinnaker_machine", "width") machine_height = rc.getint("spinnaker_machine", "height") self.controller = MachineController(hostname) self.controller.boot(machine_width, machine_height) # Create the IO controller io_cls = getconfig(network.config, Simulator, "node_io", Ethernet) io_kwargs = getconfig(network.config, Simulator, "node_io_kwargs", dict()) self.io_controller = io_cls(**io_kwargs) # Calculate the machine timestep, this is measured in microseconds # (hence the 1e6 scaling factor). self.timescale = timescale machine_timestep = int((dt / timescale) * 1e6) # Determine the maximum run-time self.max_steps = None if period is None else int(period / dt) self.steps = 0 # Steps simulated # If the simulator is in "run indefinite" mode (i.e., max_steps=None) # then we modify the builders to ignore function of time Nodes and # probes. builder_kwargs = self.io_controller.builder_kwargs if self.max_steps is None: raise NotImplementedError # Create a model from the network, using the IO controller logger.debug("Building model") start_build = time.time() self.model = Model(dt=dt, machine_timestep=machine_timestep, decoder_cache=get_default_decoder_cache()) self.model.build(network, **builder_kwargs) forced_removals = get_force_removal_passnodes(network) optimise_out_passthrough_nodes(self.model, self.io_controller.passthrough_nodes, network.config, forced_removals) logger.info("Build took {:.3f} seconds".format(time.time() - start_build)) self.model.decoder_cache.shrink() self.dt = self.model.dt self._closed = False # Whether the simulator has been closed or not self.host_sim = self._create_host_sim() # Holder for probe data self.data = {} # Holder for profiling data self.profiler_data = {} # Convert the model into a netlist logger.info("Building netlist") start = time.time() self.netlist = self.model.make_netlist(self.max_steps or 0) # Get a system-info object to place & route against logger.info("Getting SpiNNaker machine specification") system_info = self.controller.get_system_info() # Place & Route logger.info("Placing and routing") self.netlist.place_and_route( system_info, place=getconfig(network.config, Simulator, 'placer', rig.place_and_route.place), place_kwargs=getconfig(network.config, Simulator, 'placer_kwargs', {}), ) logger.info("{} cores in use".format(len(self.netlist.placements))) chips = set(six.itervalues(self.netlist.placements)) logger.info("Using {}".format(chips)) # Prepare the simulator against the placed, allocated and routed # netlist. self.io_controller.prepare(self.model, self.controller, self.netlist) # Load the application logger.info("Loading application") self.netlist.load_application(self.controller, system_info) # Check if any cores are in bad states if self.controller.count_cores_in_state(["exit", "dead", "watchdog", "runtime_exception"]): for vertex in self.netlist.vertices: x, y = self.netlist.placements[vertex] p = self.netlist.allocations[vertex][Cores].start status = self.controller.get_processor_status(p, x, y) if status.cpu_state is not AppState.sync0: print("Core ({}, {}, {}) in state {!s}".format( x, y, p, status.cpu_state)) raise Exception("Unexpected core failures.") logger.info("Preparing and loading machine took {:3f} seconds".format( time.time() - start )) logger.info("Setting router timeout to 16 cycles") for x in range(machine_width): for y in range(machine_height): with self.controller(x=x, y=y): if (x, y) in system_info: data = self.controller.read(0xf1000000, 4) self.controller.write(0xf1000000, data[:-1] + b'\x10')
def __init__(self, network, dt=0.001, period=10.0, timescale=1.0, hostname=None, use_spalloc=None, allocation_fudge_factor=0.6): """Create a new Simulator with the given network. Parameters ---------- period : float or None Duration of one period of the simulator. This determines how much memory will be allocated to store precomputed and probed data. timescale : float Scaling factor to apply to the simulation, e.g., a value of `0.5` will cause the simulation to run at half real-time. hostname : string or None Hostname of the SpiNNaker machine to use; if None then the machine specified in the config file will be used. use_spalloc : bool or None Allocate a SpiNNaker machine for the simulator using ``spalloc``. If None then the setting specified in the config file will be used. Other Parameters ---------------- allocation_fudge_factor: Fudge factor to allocate more cores than really necessary when using `spalloc` to ensure that (a) there are sufficient "live" cores in the allocated machine, (b) there is sufficient room for a good place and route solution. This should generally be more than 0.1 (10% more cores than necessary) to account for the usual rate of missing chips. """ # Add this simulator to the set of open simulators Simulator._add_simulator(self) # Create the IO controller io_cls = getconfig(network.config, Simulator, "node_io", Ethernet) io_kwargs = getconfig(network.config, Simulator, "node_io_kwargs", dict()) self.io_controller = io_cls(**io_kwargs) # Calculate the machine timestep, this is measured in microseconds # (hence the 1e6 scaling factor). self.timescale = timescale machine_timestep = int((dt / timescale) * 1e6) # Determine the maximum run-time self.max_steps = None if period is None else int(period / dt) self.steps = 0 # Steps simulated # If the simulator is in "run indefinite" mode (i.e., max_steps=None) # then we modify the builders to ignore function of time Nodes and # probes. builder_kwargs = self.io_controller.builder_kwargs if self.max_steps is None: raise NotImplementedError # Create a model from the network, using the IO controller logger.debug("Building model") start_build = time.time() self.model = Model(dt=dt, machine_timestep=machine_timestep, decoder_cache=get_default_decoder_cache()) self.model.build(network, **builder_kwargs) logger.info("Build took {:.3f} seconds".format(time.time() - start_build)) self.model.decoder_cache.shrink() self.dt = self.model.dt self._closed = False # Whether the simulator has been closed or not self.host_sim = self._create_host_sim() # Holder for probe data self.data = {} # Holder for profiling data self.profiler_data = {} # Convert the model into a netlist logger.info("Building netlist") start = time.time() self.netlist = self.model.make_netlist(self.max_steps or 0) # Determine whether to use a spalloc machine or not if use_spalloc is None: # Default is to not use spalloc; this is indicated by either the # absence of the option in the config file OR the option being set # to false. use_spalloc = (rc.has_option("spinnaker_machine", "use_spalloc") and rc.getboolean("spinnaker_machine", "use_spalloc")) # Create a controller for the machine and boot if necessary self.job = None if not use_spalloc or hostname is not None: # Use the specified machine rather than trying to get one # allocated. if hostname is None: hostname = rc.get("spinnaker_machine", "hostname") else: # Attempt to get a machine allocated to us from spalloc import Job # Determine how many boards to ask for (assuming 16 usable cores # per chip and 48 chips per board). n_cores = self.netlist.n_cores * (1.0 + allocation_fudge_factor) n_boards = int(np.ceil((n_cores / 16.) / 48.)) # Request the job self.job = Job(n_boards) logger.info("Allocated job ID %d...", self.job.id) # Wait until we're given the machine logger.info("Waiting for machine allocation...") self.job.wait_until_ready() # spalloc recommends a slight delay before attempting to boot the # machine, later versions of spalloc server may relax this # requirement. time.sleep(5.0) # Store the hostname hostname = self.job.hostname logger.info("Using %d board(s) of \"%s\" (%s)", len(self.job.boards), self.job.machine_name, hostname) self.controller = MachineController(hostname) self.controller.boot() # Get a system-info object to place & route against logger.info("Getting SpiNNaker machine specification") system_info = self.controller.get_system_info() # Place & Route logger.info("Placing and routing") self.netlist.place_and_route( system_info, place=getconfig(network.config, Simulator, 'placer', rig.place_and_route.place), place_kwargs=getconfig(network.config, Simulator, 'placer_kwargs', {}), ) logger.info("{} cores in use".format(len(self.netlist.placements))) chips = set(six.itervalues(self.netlist.placements)) logger.info("Using {}".format(chips)) # Prepare the simulator against the placed, allocated and routed # netlist. self.io_controller.prepare(self.model, self.controller, self.netlist) # Load the application logger.info("Loading application") self.netlist.load_application(self.controller, system_info) # Check if any cores are in bad states if self.controller.count_cores_in_state( ["exit", "dead", "watchdog", "runtime_exception"]): for vertex, (x, y) in six.iteritems(self.netlist.placements): p = self.netlist.allocations[vertex][Cores].start status = self.controller.get_processor_status(p, x, y) if status.cpu_state is not AppState.sync0: print("Core ({}, {}, {}) in state {!s}".format( x, y, p, status)) print(self.controller.get_iobuf(p, x, y)) raise Exception("Unexpected core failures.") logger.info("Preparing and loading machine took {:3f} seconds".format( time.time() - start)) logger.info("Setting router timeout to 16 cycles") for x, y in system_info.chips(): with self.controller(x=x, y=y): data = self.controller.read(0xf1000000, 4) self.controller.write(0xf1000000, data[:-1] + b'\x10')
def __init__(self, network, dt=0.001, period=10.0, timescale=1.0, hostname=None, use_spalloc=None, allocation_fudge_factor=0.6): """Create a new Simulator with the given network. Parameters ---------- period : float or None Duration of one period of the simulator. This determines how much memory will be allocated to store precomputed and probed data. timescale : float Scaling factor to apply to the simulation, e.g., a value of `0.5` will cause the simulation to run at half real-time. hostname : string or None Hostname of the SpiNNaker machine to use; if None then the machine specified in the config file will be used. use_spalloc : bool or None Allocate a SpiNNaker machine for the simulator using ``spalloc``. If None then the setting specified in the config file will be used. Other Parameters ---------------- allocation_fudge_factor: Fudge factor to allocate more cores than really necessary when using `spalloc` to ensure that (a) there are sufficient "live" cores in the allocated machine, (b) there is sufficient room for a good place and route solution. This should generally be more than 0.1 (10% more cores than necessary) to account for the usual rate of missing chips. """ # Add this simulator to the set of open simulators Simulator._add_simulator(self) # Create the IO controller io_cls = getconfig(network.config, Simulator, "node_io", Ethernet) io_kwargs = getconfig(network.config, Simulator, "node_io_kwargs", dict()) self.io_controller = io_cls(**io_kwargs) # Calculate the machine timestep, this is measured in microseconds # (hence the 1e6 scaling factor). self.timescale = timescale machine_timestep = int((dt / timescale) * 1e6) # Determine the maximum run-time self.max_steps = None if period is None else int(period / dt) self.steps = 0 # Steps simulated # If the simulator is in "run indefinite" mode (i.e., max_steps=None) # then we modify the builders to ignore function of time Nodes and # probes. builder_kwargs = self.io_controller.builder_kwargs if self.max_steps is None: raise NotImplementedError # Create a model from the network, using the IO controller logger.debug("Building model") start_build = time.time() self.model = Model(dt=dt, machine_timestep=machine_timestep, decoder_cache=get_default_decoder_cache()) self.model.build(network, **builder_kwargs) logger.info("Build took {:.3f} seconds".format(time.time() - start_build)) self.model.decoder_cache.shrink() self.dt = self.model.dt self._closed = False # Whether the simulator has been closed or not self.host_sim = self._create_host_sim() # Holder for probe data self.data = {} # Holder for profiling data self.profiler_data = {} # Convert the model into a netlist logger.info("Building netlist") start = time.time() self.netlist = self.model.make_netlist(self.max_steps or 0) # Determine whether to use a spalloc machine or not if use_spalloc is None: # Default is to not use spalloc; this is indicated by either the # absence of the option in the config file OR the option being set # to false. use_spalloc = ( rc.has_option("spinnaker_machine", "use_spalloc") and rc.getboolean("spinnaker_machine", "use_spalloc")) # Create a controller for the machine and boot if necessary self.job = None if not use_spalloc or hostname is not None: # Use the specified machine rather than trying to get one # allocated. if hostname is None: hostname = rc.get("spinnaker_machine", "hostname") else: # Attempt to get a machine allocated to us from spalloc import Job # Determine how many boards to ask for (assuming 16 usable cores # per chip and 48 chips per board). n_cores = self.netlist.n_cores * (1.0 + allocation_fudge_factor) n_boards = int(np.ceil((n_cores / 16.) / 48.)) # Request the job self.job = Job(n_boards) logger.info("Allocated job ID %d...", self.job.id) # Wait until we're given the machine logger.info("Waiting for machine allocation...") self.job.wait_until_ready() # spalloc recommends a slight delay before attempting to boot the # machine, later versions of spalloc server may relax this # requirement. time.sleep(5.0) # Store the hostname hostname = self.job.hostname logger.info("Using %d board(s) of \"%s\" (%s)", len(self.job.boards), self.job.machine_name, hostname) self.controller = MachineController(hostname) self.controller.boot() # Get a system-info object to place & route against logger.info("Getting SpiNNaker machine specification") system_info = self.controller.get_system_info() # Place & Route logger.info("Placing and routing") self.netlist.place_and_route( system_info, place=getconfig(network.config, Simulator, 'placer', rig.place_and_route.place), place_kwargs=getconfig(network.config, Simulator, 'placer_kwargs', {}), ) logger.info("{} cores in use".format(len(self.netlist.placements))) chips = set(six.itervalues(self.netlist.placements)) logger.info("Using {}".format(chips)) # Prepare the simulator against the placed, allocated and routed # netlist. self.io_controller.prepare(self.model, self.controller, self.netlist) # Load the application logger.info("Loading application") self.netlist.load_application(self.controller, system_info) # Check if any cores are in bad states if self.controller.count_cores_in_state(["exit", "dead", "watchdog", "runtime_exception"]): for vertex, (x, y) in six.iteritems(self.netlist.placements): p = self.netlist.allocations[vertex][Cores].start status = self.controller.get_processor_status(p, x, y) if status.cpu_state is not AppState.sync0: print("Core ({}, {}, {}) in state {!s}".format( x, y, p, status)) print(self.controller.get_iobuf(p, x, y)) raise Exception("Unexpected core failures.") logger.info("Preparing and loading machine took {:3f} seconds".format( time.time() - start )) logger.info("Setting router timeout to 16 cycles") for x, y in system_info.chips(): with self.controller(x=x, y=y): data = self.controller.read(0xf1000000, 4) self.controller.write(0xf1000000, data[:-1] + b'\x10')
def __init__(self, network, dt=0.001, seed=None, model=None, dtype=rc.get('precision', 'dtype')): """Initialize the simulator with a network and (optionally) a model. Most of the time, you will pass in a network and sometimes a dt:: sim1 = nengo.Simulator(my_network) # Uses default 0.001s dt sim2 = nengo.Simulator(my_network, dt=0.01) # Uses 0.01s dt For more advanced use cases, you can initialize the model yourself, and also pass in a network that will be built into the same model that you pass in:: sim = nengo.Simulator(my_network, model=my_model) If you want full control over the build process, then you can build your network into the model manually. If you do this, then you must explicitly pass in ``None`` for the network:: sim = nengo.Simulator(None, model=my_model) Parameters ---------- network : nengo.Network instance or None A network object to the built and then simulated. If a fully built ``model`` is passed in, then you can skip building the network by passing in network=None. dt : float The length of a simulator timestep, in seconds. seed : int A seed for all stochastic operators used in this simulator. Note that there are not stochastic operators implemented currently, so this parameters does nothing. model : nengo.builder.Model instance or None A model object that contains build artifacts to be simulated. Usually the simulator will build this model for you; however, if you want to build the network manually, or to inject some build artifacts in the Model before building the network, then you can pass in a ``nengo.builder.Model`` instance. """ dt = float(dt) # make sure it's a float (for division purposes) if model is None: self.model = Model(dt=dt, label="%s, dt=%f" % (network, dt), decoder_cache=get_default_decoder_cache(), dtype=dtype) else: self.model = model #print(network) if network is not None: # Build the network into the model self.model.build(network) self.model.decoder_cache.shrink() self.seed = np.random.randint(npext.maxint) if seed is None else seed self.rng = np.random.RandomState(self.seed) # -- map from Signal.base -> ndarray self.signals = SignalDict( __time__=np.asarray(npext.castDecimal(0), dtype=self.dtype)) #print(self.model) #print(self.model.operators) for op in self.model.operators: op.init_signals(self.signals) self.dg = operator_depencency_graph(self.model.operators) self._step_order = [ node for node in toposort(self.dg) if hasattr(node, 'make_step') ] self._steps = [ node.make_step(self.signals, dt, self.rng) for node in self._step_order ] # Add built states to the probe dictionary self._probe_outputs = self.model.params # Provide a nicer interface to probe outputs self.data = ProbeDict(self._probe_outputs) self.reset()
def __init__(self, network, dt=0.001, seed=None): self.model = Model( dt=float(dt), label="Nengo RS model", decoder_cache=get_default_decoder_cache(), ) self.model.build(network) signal_to_engine_id = {} for signal_dict in self.model.sig.values(): for signal in signal_dict.values(): self.add_sig(signal_to_engine_id, signal) x = SignalU64("step", 0) signal_to_engine_id[self.model.step] = x signal_to_engine_id[self.model.time] = SignalF64("time", 0.0) self._sig_to_ngine_id = signal_to_engine_id dg = BidirectionalDAG(operator_dependency_graph(self.model.operators)) toposorted_dg = toposort(dg.forward) node_indices = {node: idx for idx, node in enumerate(toposorted_dg)} ops = [] for op in toposorted_dg: dependencies = [node_indices[node] for node in dg.backward[op]] if isinstance(op, core_op.Reset): ops.append( Reset( np.asarray(op.value, dtype=np.float64), self.get_sig(signal_to_engine_id, op.dst), dependencies, )) elif isinstance(op, core_op.TimeUpdate): ops.append( TimeUpdate( dt, self.get_sig(signal_to_engine_id, self.model.step), self.get_sig(signal_to_engine_id, self.model.time), dependencies, )) elif isinstance(op, core_op.ElementwiseInc): ops.append( ElementwiseInc( self.get_sig(signal_to_engine_id, op.Y), self.get_sig(signal_to_engine_id, op.A), self.get_sig(signal_to_engine_id, op.X), dependencies, )) elif isinstance(op, core_op.Copy): assert op.src_slice is None and op.dst_slice is None ops.append( Copy( op.inc, self.get_sig(signal_to_engine_id, op.src), self.get_sig(signal_to_engine_id, op.dst), dependencies, )) elif isinstance(op, core_op.DotInc): ops.append( DotInc( self.get_sig(signal_to_engine_id, op.Y), self.get_sig(signal_to_engine_id, op.A), self.get_sig(signal_to_engine_id, op.X), dependencies, )) elif isinstance(op, neurons.SimNeurons): signals = SignalDict() op.init_signals(signals) ops.append( SimNeurons( self.dt, op.neurons.step_math, [signals[s] for s in op.states] if hasattr(op, "states") else [], self.get_sig(signal_to_engine_id, op.J), self.get_sig(signal_to_engine_id, op.output), dependencies, )) elif isinstance(op, processes.SimProcess): signals = SignalDict() op.init_signals(signals) shape_in = (0, ) if op.input is None else op.input.shape shape_out = op.output.shape rng = None state = {k: signals[s] for k, s in op.state.items()} step_fn = op.process.make_step(shape_in, shape_out, self.dt, rng, state) ops.append( SimProcess( op.mode == "inc", lambda *args, step_fn=step_fn: np.asarray( step_fn(*args), dtype=float), self.get_sig(signal_to_engine_id, op.t), self.get_sig(signal_to_engine_id, op.output), None if op.input is None else self.get_sig( signal_to_engine_id, op.input), dependencies, )) elif isinstance(op, core_op.SimPyFunc): ops.append( SimPyFunc( lambda *args, op=op: np.asarray(op.fn(*args), dtype=float), self.get_sig(signal_to_engine_id, op.output), None if op.t is None else self.get_sig( signal_to_engine_id, op.t), None if op.x is None else self.get_sig( signal_to_engine_id, op.x), dependencies, )) else: raise Exception(f"missing: {op}") self.probe_mapping = {} for probe in self.model.probes: self.probe_mapping[probe] = Probe( signal_to_engine_id[self.model.sig[probe]["in"]]) self._engine = Engine(list(signal_to_engine_id.values()), ops, list(self.probe_mapping.values())) self.data = SimData(self) print("initialized") self._engine.reset()
def __init__(self, network, dt=0.001, period=10.0): """Create a new Simulator with the given network. Parameters ---------- period : float or None Duration of one period of the simulator. This determines how much memory will be allocated to store precomputed and probed data. """ # Add this simulator to the set of open simulators Simulator._add_simulator(self) # Create a controller for the machine and boot if necessary hostname = rc.get("spinnaker_machine", "hostname") machine_width = rc.getint("spinnaker_machine", "width") machine_height = rc.getint("spinnaker_machine", "height") self.controller = MachineController(hostname) test_and_boot(self.controller, hostname, machine_width, machine_height) # Create the IO controller io_cls = getconfig(network.config, Simulator, "node_io", Ethernet) io_kwargs = getconfig(network.config, Simulator, "node_io_kwargs", dict()) self.io_controller = io_cls(**io_kwargs) # Determine the maximum run-time self.max_steps = None if period is None else int(period / dt) self.steps = 0 # Steps simulated # Create the IO controller. Function of time nodes are only enabled if # the simulator period is not None. io_cls = getconfig(network.config, Simulator, "node_io", Ethernet) io_kwargs = getconfig(network.config, Simulator, "node_io_kwargs", dict()) self.io_controller = io_cls( function_of_time_nodes=self.max_steps is not None, **io_kwargs ) # Create a model from the network, using the IO controller. Probes are # only built if the simulator period is not None. logger.debug("Building model") start_build = time.time() self.model = Model(dt, decoder_cache=get_default_decoder_cache()) self.model.build(network, build_probes=self.max_steps is not None, **self.io_controller.builder_kwargs) model_optimisations.remove_childless_filters(self.model) logger.info("Build took {:.3f} seconds".format(time.time() - start_build)) self.model.decoder_cache.shrink() self.dt = self.model.dt self._closed = False # Whether the simulator has been closed or not self._running = False self._halt = False self.host_sim = self._create_host_sim() # Holder for probe data self.data = {} # Holder for profiling data self.profiler_data = {} # Convert the model into a netlist logger.info("Building netlist") start = time.time() self.netlist = self.model.make_netlist(self.max_steps or 0) # Get a machine object to place & route against logger.info("Getting SpiNNaker machine specification") machine = self.controller.get_machine() # Place & Route logger.info("Placing and routing") self.netlist.place_and_route(machine) logger.info("{} cores in use".format(len(self.netlist.placements))) chips = set(six.itervalues(self.netlist.placements)) logger.info("Using {}".format(chips)) # Prepare the simulator against the placed, allocated and routed # netlist. self.io_controller.prepare(self.model, self.controller, self.netlist) # Load the application logger.info("Loading application") self.netlist.load_application(self.controller) # Check if any cores are in bad states if self.controller.count_cores_in_state(["exit", "dead", "watchdog", "runtime_exception"]): for vertex in self.netlist.vertices: x, y = self.netlist.placements[vertex] p = self.netlist.allocations[vertex][Cores].start status = self.controller.get_processor_status(p, x, y) if status.cpu_state is not AppState.sync0: print("Core ({}, {}, {}) in state {!s}".format( x, y, p, status.cpu_state)) raise Exception("Unexpected core failures.") logger.info("Preparing and loading machine took {:3f} seconds".format( time.time() - start )) logger.info("Setting router timeout to 16 cycles") for x in range(machine_width): for y in range(machine_height): with self.controller(x=x, y=y): if (x, y) in machine: data = self.controller.read(0xf1000000, 4) self.controller.write(0xf1000000, data[:-1] + b'\x10')
def __init__(self, network, dt=0.001, seed=None, model=None, context=None, n_prealloc_probes=32, profiling=None, ocl_only=False, planner=greedy_planner): # --- create these first since they are used in __del__ self.closed = False self.model = None # --- check version if nengo.version.version_info[:2] != latest_nengo_version_info[:2]: raise ValueError( "This simulator only supports Nengo %s.x (got %s)" % ('.'.join(str(i) for i in latest_nengo_version_info[:2]), nengo.__version__)) elif nengo.version.version_info > latest_nengo_version_info: warnings.warn("This version of `nengo_ocl` has not been tested " "with your `nengo` version (%s). The latest fully " "supported version is %s" % ( nengo.__version__, latest_nengo_version)) # --- arguments/attributes if context is None: print('No context argument was provided to nengo_ocl.Simulator') print("Calling pyopencl.create_some_context() for you now:") context = cl.create_some_context() if profiling is None: profiling = int(os.getenv("NENGO_OCL_PROFILING", 0)) self.context = context self.profiling = profiling if self.profiling: self.queue = cl.CommandQueue(context, properties=PROFILING_ENABLE) else: self.queue = cl.CommandQueue(context) self.n_prealloc_probes = n_prealloc_probes self.ocl_only = ocl_only # --- Nengo build if model is None or model.decoder_cache is None: cache = get_default_decoder_cache() else: cache = model.decoder_cache with cache, Timer() as nengo_timer: if model is None: self.model = Model(dt=float(dt), label="%s, dt=%f" % (network, dt), decoder_cache=cache) else: self.model = model if network is not None: # Build the network into the model self.model.build(network) cache.shrink() logger.info("Nengo build in %0.3f s" % nengo_timer.duration) # --- operators with Timer() as planner_timer: operators = list(self.model.operators) # convert DotInc and Copy to MultiDotInc operators = list(map(MultiDotInc.convert_to, operators)) operators = MultiDotInc.compress(operators) # plan the order of operations, combining where appropriate op_groups = planner(operators) assert len([typ for typ, _ in op_groups if typ is Reset]) < 2, ( "All resets not planned together") self.operators = operators self.op_groups = op_groups logger.info("Planning in %0.3f s" % planner_timer.duration) with Timer() as signals_timer: # Initialize signals all_signals = stable_unique( sig for op in operators for sig in op.all_signals) all_bases = stable_unique(sig.base for sig in all_signals) sigdict = SignalDict() # map from Signal.base -> ndarray for op in operators: op.init_signals(sigdict) # Add built states to the probe dictionary self._probe_outputs = dict(self.model.params) # Provide a nicer interface to probe outputs self.data = ProbeDict(self._probe_outputs) # Create data on host and add views self.all_data = RaggedArray( [sigdict[sb] for sb in all_bases], names=[getattr(sb, 'name', '') for sb in all_bases], dtype=np.float32) view_builder = ViewBuilder(all_bases, self.all_data) view_builder.setup_views(operators) for probe in self.model.probes: view_builder.append_view(self.model.sig[probe]['in']) view_builder.add_views_to(self.all_data) self.all_bases = all_bases self.sidx = { k: np.int32(v) for k, v in iteritems(view_builder.sidx)} self._A_views = view_builder._A_views self._X_views = view_builder._X_views self._YYB_views = view_builder._YYB_views del view_builder # Copy data to device self.all_data = CLRaggedArray(self.queue, self.all_data) logger.info("Signals in %0.3f s" % signals_timer.duration) # --- set seed self.seed = np.random.randint(npext.maxint) if seed is None else seed self._reset_rng() # --- create list of plans self._raggedarrays_to_reset = {} self._cl_rngs = {} with Timer() as plans_timer: self._plan = [] for op_type, op_list in op_groups: self._plan.extend(self.plan_op_group(op_type, op_list)) self._plan.extend(self.plan_probes()) logger.info("Plans in %0.3f s" % plans_timer.duration) # -- create object to execute list of plans self._plans = Plans(self._plan, self.profiling) self._reset_cl_rngs() self._probe_step_time()
def __init__(self, network, dt=0.001, seed=None, model=None): """Initialize the simulator with a network and (optionally) a model. Most of the time, you will pass in a network and sometimes a dt:: sim1 = nengo.Simulator(my_network) # Uses default 0.001s dt sim2 = nengo.Simulator(my_network, dt=0.01) # Uses 0.01s dt For more advanced use cases, you can initialize the model yourself, and also pass in a network that will be built into the same model that you pass in:: sim = nengo.Simulator(my_network, model=my_model) If you want full control over the build process, then you can build your network into the model manually. If you do this, then you must explicitly pass in ``None`` for the network:: sim = nengo.Simulator(None, model=my_model) Parameters ---------- network : nengo.Network instance or None A network object to the built and then simulated. If a fully built ``model`` is passed in, then you can skip building the network by passing in network=None. dt : float, optional The length of a simulator timestep, in seconds. seed : int, optional A seed for all stochastic operators used in this simulator. model : nengo.builder.Model instance or None, optional A model object that contains build artifacts to be simulated. Usually the simulator will build this model for you; however, if you want to build the network manually, or to inject some build artifacts in the Model before building the network, then you can pass in a ``nengo.builder.Model`` instance. """ if model is None: dt = float(dt) # make sure it's a float (for division purposes) self.model = Model(dt=dt, label="%s, dt=%f" % (network, dt), decoder_cache=get_default_decoder_cache()) else: self.model = model if network is not None: # Build the network into the model self.model.build(network) self.model.decoder_cache.shrink() # -- map from Signal.base -> ndarray self.signals = SignalDict(__time__=np.asarray(0.0, dtype=np.float64)) for op in self.model.operators: op.init_signals(self.signals) # Order the steps (they are made in `Simulator.reset`) self.dg = operator_depencency_graph(self.model.operators) self._step_order = [op for op in toposort(self.dg) if hasattr(op, 'make_step')] # Add built states to the probe dictionary self._probe_outputs = self.model.params # Provide a nicer interface to probe outputs self.data = ProbeDict(self._probe_outputs) seed = np.random.randint(npext.maxint) if seed is None else seed self.reset(seed=seed)
def __init__(self, network, dt=0.001, seed=None, model=None, context=None, n_prealloc_probes=32, profiling=None, if_python_code='none', planner=greedy_planner, progress_bar=True): # --- check version if nengo.version.version_info in bad_nengo_versions: raise ValueError( "This simulator does not support Nengo version %s. Upgrade " "with 'pip install --upgrade --no-deps nengo'." % nengo.__version__) elif nengo.version.version_info > latest_nengo_version_info: warnings.warn("This version of `nengo_ocl` has not been tested " "with your `nengo` version (%s). The latest fully " "supported version is %s" % ( nengo.__version__, latest_nengo_version)) # --- create these first since they are used in __del__ self.closed = False self.model = None # --- arguments/attributes if context is None and Simulator.some_context is None: print('No context argument was provided to nengo_ocl.Simulator') print("Calling pyopencl.create_some_context() for you now:") Simulator.some_context = cl.create_some_context() if profiling is None: profiling = int(os.getenv("NENGO_OCL_PROFILING", 0)) self.context = Simulator.some_context if context is None else context self.profiling = profiling self.queue = cl.CommandQueue( self.context, properties=PROFILING_ENABLE if self.profiling else 0) if if_python_code not in ['none', 'warn', 'error']: raise ValueError("%r not a valid value for `if_python_code`" % if_python_code) self.if_python_code = if_python_code self.n_prealloc_probes = n_prealloc_probes self.progress_bar = progress_bar # --- Nengo build with Timer() as nengo_timer: if model is None: self.model = Model(dt=float(dt), label="%s, dt=%f" % (network, dt), decoder_cache=get_default_decoder_cache()) else: self.model = model if network is not None: # Build the network into the model self.model.build(network) logger.info("Nengo build in %0.3f s" % nengo_timer.duration) # --- operators with Timer() as planner_timer: operators = list(self.model.operators) # convert DotInc and Copy to MultiDotInc operators = list(map(MultiDotInc.convert_to, operators)) operators = MultiDotInc.compress(operators) # plan the order of operations, combining where appropriate op_groups = planner(operators) assert len([typ for typ, _ in op_groups if typ is Reset]) < 2, ( "All resets not planned together") self.operators = operators self.op_groups = op_groups logger.info("Planning in %0.3f s" % planner_timer.duration) with Timer() as signals_timer: # Initialize signals all_signals = stable_unique( sig for op in operators for sig in op.all_signals) all_bases = stable_unique(sig.base for sig in all_signals) sigdict = SignalDict() # map from Signal.base -> ndarray for op in operators: op.init_signals(sigdict) # Add built states to the probe dictionary self._probe_outputs = dict(self.model.params) # Provide a nicer interface to probe outputs self.data = ProbeDict(self._probe_outputs) # Create data on host and add views self.all_data = RaggedArray( [sigdict[sb] for sb in all_bases], names=[getattr(sb, 'name', '') for sb in all_bases], dtype=np.float32) view_builder = ViewBuilder(all_bases, self.all_data) view_builder.setup_views(operators) for probe in self.model.probes: view_builder.append_view(self.model.sig[probe]['in']) view_builder.add_views_to(self.all_data) self.all_bases = all_bases self.sidx = { k: np.int32(v) for k, v in iteritems(view_builder.sidx)} self._A_views = view_builder._A_views self._X_views = view_builder._X_views self._YYB_views = view_builder._YYB_views del view_builder # Copy data to device self.all_data = CLRaggedArray(self.queue, self.all_data) logger.info("Signals in %0.3f s" % signals_timer.duration) # --- set seed self.seed = np.random.randint(npext.maxint) if seed is None else seed self.rng = np.random.RandomState(self.seed) # --- create list of plans self._raggedarrays_to_reset = {} self._cl_rngs = {} self._python_rngs = {} plans = [] with Timer() as plans_timer: for op_type, op_list in op_groups: plans.extend(self.plan_op_group(op_type, op_list)) plans.extend(self.plan_probes()) logger.info("Plans in %0.3f s" % plans_timer.duration) # -- create object to execute list of plans self._plans = Plans(plans, self.profiling) self.rng = None # all randomness set, should no longer be used self._reset_probes() # clears probes from previous model builds