cns

The main function of the CNS framework. All interaction between MATLAB and a network model on the GPU occurs via the cns function. This includes initializing a model on a GPU, running it, getting and setting fields, etc.

Running One Model at a Time (Synchronously)

We first describe how to run CNS in its simpler mode of operation, in which (for a given instance of MATLAB) there is only a single initialized model (a single session) active at a time. In this mode, every call to the cns function causes MATLAB to wait until the operation is complete. For ease of exposition in these sections, only the single-session, synchronous syntax is given for each command.
Initializing and Deallocating
cns('init')Initialize a network model on a GPU (or CPU).
cns('test')Test initialization, displaying memory usage.
cns('platform')Change the defaults for some 'init' parameters.
cns('done')Deallocate model, freeing resources.

Getting and Setting Fields
cns('get')Retrieve fields from an initialized model.
cns('update')Retrieve all variables from an initialized model.
cns('set')Change the value of fields in an initialized model.

Running the Model
cns('run')Run an initialized model for some number of full iterations, possibly retrieving time series of some variables.
cns('step')Run an initialized model through one or more steps of a single iteration, possibly retrieving some variables.

Running One or More Models Asynchronously

CNS also allows you to write MATLAB scripts that manage multiple CNS models running concurrently and asynchronously from the main MATLAB thread. The most commmon reason to do this is to take advantage of a multi-GPU computer. Another reason is to allow MATLAB to continue working while one or more models are executing on GPUs.
General Remarks on Asynchronous Operation
Asynchronous Mode Syntax: a Multi-Session Example Script
Initializing and Deallocating Sessions
Running and Waiting
Input and Output
Other Useful Commands

cns('init')

Initializes a network model on a GPU (or CPU) using information provided in a model structure.

Syntax

cns('init', m)
cns('init', m, platform)
cns('init', m, platform, nice)
m
The model structure.

platform
One of the following (defaults to 'gpu'):

nice
Applies when using a GPU. One of the following (defaults to 'nice'):

Notes

After calling init, you can call it again to re-initialize using a different model structure, without first calling done, as long as the new model uses the same package and the platform and nice flag do not change. Omitting the done call means you do not release the GPU, avoiding the possibility of it being claimed by another user.

The platform call can be used to change the default values of platform and nice so you do not have to provide values with every init call.

CPU mode is much slower than GPU mode, but is useful when you don't have access to a GPU, or want to use the PRINT and ERROR macros for debugging.

The mean option can be about 10% faster than nice, but it causes CPU usage to stay pinned at 100% even when the only processing is happening on the GPU, making the CPU unavailable to other processes.

Initialization sets the value of ITER_NO to 1.


cns('test')

Performs a test initialization and prints a summary of memory usage, along with any errors. This is useful for determining why an init call might be failing.

Syntax

Parameters are the same as for the init call.

Notes

The test call deallocates the model immediately, whether the initialization succeeds or not.


cns('platform')

Allows you to change the default values of some parameters to the init call so that you do not have to provide them in every init call.

Syntax

cns('platform', platform)
cns('platform', platform, nice)
platform, nice
These have the same meaning as in the init call.

Notes

The settings you provide here become the defaults for the init call. These defaults will persist until MATLAB exits.


cns('done')

Deallocates an initialized model, freeing up GPU (or CPU) resources.

Syntax

cns('done')


cns('get')

Retrieves values from one or more fields of an initialized network model. Usually you will only do this after one or more iterations or steps have been executed.

Syntax

a = cns('get', field-params)
[a, a, ...] = cns('get', {field-params}, {field-params}, ...)
field-params
Identifies a field, or a subrange of a field, to retrieve (click here for details). The number of these must match the number of outputs. The {} can be omitted when only one field/subrange is requested.

a
The value requested. The number of these outputs must match the number of field-params.

cns('update')

Updates a model structure with the current values of all variables in the active model. This allows you to save the state of a running model. If you then deallocate the model, you can use the updated model structure to reactivate it in the same state.

Syntax

m2 = cns('update', m1)
m1
The original model structure.

m2
The updated model structure.

Notes

In many situations, the updated model structure will be a lot larger than the one used to initialize the network in the first place. Variables with default values will probably no longer be at those values, and even if they were, the update call would still store separate values for every cell and synapse in the updated model structure.


cns('set')

Changes values in one or more fields of an initialized network model. Most commonly done to introduce new input data.

Syntax

cns('set', field-params, a)
cns('set', {field-params, a}, {field-params, a}, ...)
field-params
Identifies a field, or a subrange of a field, to set (click here for details). The {} can be omitted when only one field/subrange is being set.

a
The new value for the corresponding field/subrange. Its size must match that of the field/subrange, or it can be a scalar, which sets the entire field/subrange to the same value.

cns('run')

Runs an initialized model for some number of full iterations. Can also retrieve the values of variables at regular intervals as the model iterates.

Syntax

cns('run')
cns('run', iterations)

[s, s, ...] = cns('run', {field-params}, {field-params}, ...)
[s, s, ...] = cns('run', iterations, {field-params}, {field-params}, ...)
[s, s, ...] = cns('run', iterations, sampleRate, {field-params}, {field-params}, ...)
[s, s, ...] = cns('run', iterations, sampleRate, bufferSize, {field-params}, {field-params}, ...)
iterations
The number of full iterations of the model to perform. Defaults to 1.

field-params
Identifies a variable, or a subrange of a variable, to retrieve (click here for details). The number of these must match the number of outputs. By default, the variable/subrange will be retrieved at the end of each iteration; this can be changed by specifying sampleRate.

s
The value requested. The number of these outputs must match the number of field-params. Because sampling may have occurred multiple times (depending on iterations and sampleRate), each output will have an additional dimension representing the sample number. This will be dimension 1.

sampleRate
Number of iterations between each sampling of the requested variable(s). Defaults to 1.

bufferSize
By default, CNS attempts to collect all the outputs [s, s, ...] in GPU memory and transfer them back to MATLAB when the run call is complete. This is fastest, but may require more GPU memory than is available. Setting bufferSize to n means CNS will perform a GPU-MATLAB transfer whenever it has collected n samples (and any remaining samples will get transferred when the run call completes).

Notes

The run call automatically increments ITER_NO after every iteration.


cns('step')

Runs an initialized model through one or more steps of a single iteration. Can optionally retrieve the values of some variables when done.

Syntax

cns('step', step)
cns('step', step1, step2)

[a, a, ...] = cns('step', step, {field-params}, {field-params}, ...)
[a, a, ...] = cns('step', step1, step2, {field-params}, {field-params}, ...)
step
A single step number to execute.

step1, step2
A range of step numbers to execute.

field-params
Identifies a variable, or a subrange of a variable, to retrieve when finished (click here for details). The number of these must match the number of outputs.

a
The value requested. The number of these outputs must match the number of field-params.

Notes

The step call does not update ITER_NO, although you may do so yourself via a set call.


Field Parameters

The get and set calls, and optionally the run and step calls, all involve identifying fields or subranges of fields.

Entire Fields

Identifying an entire field takes these two parameters.

z, field

z
The layer number, or 0 for a model-level field.

field
The name of the field.

Subranges

For some field classes, you can optionally identify only a subrange to retrieve or set. By "subrange" we mean: This is done using additional arguments, i.e.:

z, field, additional-arguments

These are as follows:

Field Class Optional Additional Arguments
Single-Valued Multivalued
parameter none
values
N-D array
c1, c2, ...
value
value, c1, c2, ...
cell field
c1, c2, ...
values
values, c1, c2, ...
synapse field
synapses
synapses, c1, c2, ...
values
values, synapses
values, synapses, c1, c2, ...
ITER_NO none n/a

values
Identifies certain values of a multivalued field. A scalar number indicates one value, a two-element vector indicates a range of values, and [] indicates all values. Defaults to [].

value
For multivalued N-D array fields. Identifies one particular value. (Note: this parameter is actually required.)

synapses
For synapse fields. Identifies certain synapses. A scalar number indicates one synapse, a two-element vector indicates a range of synapses, and [] indicates all synapses. Defaults to [].

c1, c2, ...
For cell and synapse fields, identifies a particular cell in layer z using from 1 to N indices, where N is the dimensionality of layer z. (See cns_iconv for an explanation of using less than N indices.) If no indices are provided, defaults to the entire layer.

For N-D array fields, identifies a particular element using from 1 to N indices, where N is the dimensionality of the array. If no indices are provided, defaults to the entire array.


General Remarks on Asynchronous Operation

It is increasingly common for a single computer to have more than one GPU. Since communication between the host and GPU (or between two different GPUs) is much slower than the internal memory bandwidth inside a single GPU, CNS cannot automatically decompose a single large model into parts that run on multiple GPUs. However, CNS does allow you to initialize and run multiple models simultaneously, from a single instance of MATLAB, as long as each model runs on a single GPU (on the same computer). This allows you to (manually) decompose models that are too large to run in one GPU into multiple smaller models -- as long as you are prepared to write the MATLAB code that manages communication between the parts. Asynchronous operation also allows you to instantiate the same model on multiple GPUs to increase overall throughput (this case is illustrated in the next section).

Even in single-GPU systems, asynchronous operation can help maximize use of computing resources by allowing a MATLAB script to perform (CPU-based) processing while a model is executing on the GPU.

Note 1: this functionality is currently only available under Linux or Mac OS. Your compiler must have the <pthread.h> library.

Note 2: concurrency involving multiple computers is outside the scope of CNS, but since CNS is called just like any other MATLAB program, it will be compatible with any multi-computer concurrency solution that can run MATLAB jobs.

To run one or more models asynchronously, one writes a MATLAB script that:

This "run asynchronously and wait" model was chosen for compatibility with MATLAB's fundamentally single-threaded programming model, in which strategies like asynchronous callbacks are not allowed. An example script is shown below.


Asynchronous Mode Syntax: a Multi-Session Example Script

This script uses CNS in asynchronous mode to process images through a model using all available GPUs. Note that in this example, each GPU will be running the exact same model, but this is not required in general.

Most cns commands are the same as in the synchronous case, but with the addition of a session ID to identify which concurrently running session is being referred to. The session ID variable is shown in red below. When given as input, the session ID is always the second argument to the cns function, right after the command name ('run', 'get', etc.) There are also a few new commands (e.g. the 'wait' command) that only work with session IDs.

m     = ...; % a model structure
z_in  = ...; % number of the model's input layer
z_out = ...; % number of the model's output layer
paths = ...; % a cell array of image paths

% Create one session per GPU.  Initially none of them will be running.
% Note we are assuming the GPUs have been configured for exclusive access.
for i = 1 : cns('devcount')
    sid = cns('init', m);       % Initialize a new session and get its session ID.
    cns('set', sid, 'imno', 0); % Create session property 'imno' and set it to 0.
end

next_imno = 1;
while true

    % Read the next image.  If this is not the first time through the loop, this can happen
    % while earlier images are still being processed.
    if next_imno <= numel(paths)
        im = imread(paths{next_imno});
    end

    % Wait for any session to finish processing the image it's currently working on.  If
    % we're just starting, all sessions will be waiting and the one with the lowest session
    % ID will be chosen.  When we've run out of images, code below will start closing the
    % sessions.  When there are no more open sessions, we're done.
    sid = cns('wait', 'any');
    if isempty(sid), break; end

    % Retrieve the image number the session was working on (stored in the 'imno' property).
    imno = cns('get', sid, 'imno');
    if imno > 0
        out = cns('get', sid, z_out, 'val'); % Retrieve the output.
        ...                                  % Do something useful with the output here.
    end

    % If there are still images left to process, load the next one into the waiting session
    % and start it running again.  Otherwise, close the session.
    if next_imno <= numel(paths)
        cns('set', sid, z_in, 'val', im);   % Load the input image.
        cns('set', sid, 'imno', next_imno); % Remember the image number.
        cns('run', sid);                    % Process the image (asynchronously).
        next_imno = next_imno + 1;
    else
        cns('done', sid);
    end

end
The following sections discuss asynchronous mode cns commands in more detail.


Asynchronous Mode: Initializing and Deallocating Sessions

In asynchronous mode, a session is initialized (or reinitialized) using one of these variations on the basic cns('init') command:
sid = cns('init', m, ...)

      cns('init', sid, m, ...)
sid = cns('init', sid, m, ...)
The first version creates a new session and returns the session ID. The second or third version is used to re-initialize an existing session with a new model structure (unless the input session ID is cns_newsession in which case a new session is created). Other arguments (not shown here) are identical to those in the basic cns('init') command. Note that setting exclusive access can be very helpful when working with multiple sessions.

The cns_newsession function can be used to preallocate an array of session IDs, like this:

sids = cns_newsession(1, 4);
for i = 1 : 4
    sids(i) = cns('init', m, ...);
end
Sessions can be closed using the following commands:
cns('done', sids)
cns('done', 'all')
Where:

Asynchronous Mode: Running and Waiting

The asynchronous versions of cns('run') and cns('step') are:
cns('run', sid, ...)
cns('step', sid, ...)
Aside from the session ID, all the arguments are the same as in the synchronous case, except that there can be no output arguments. You can still request variables to be retrieved (i.e. you can still specify field-params), but if you supply output arguments, then CNS will block your MATLAB script until the 'run' or 'step' call is complete -- i.e. the call will not be asynchronous. If you want the call to return immediately so that your MATLAB script can move on to do something else while the 'run' or 'step' call executes, you have to omit the outputs arguments. You can pick up any outputs later using a cns('output') call.

Once you have issued an asynchronous 'run' or 'step' call for a session, making any other cns call for that session (for example, a 'get' or 'set' call) will implicitly cause MATLAB to stop and wait for the previous asynchronous call to complete.

Waiting can be explicitly controlled using the following commands, both of which block MATLAB until at least one of a list of sessions completes its work:

sid = cns('wait', sids)
sid = cns('wait', 'any')
The first version waits for any of a list of sessions whose IDs you supply; the second waits for any active session. The return value will be the ID of the first session of interest to complete. (If sids is empty, or there are no active sessions, the return value will be empty.)

The following commands are similar, except that there is no waiting; these calls always return immediately:

sid = cns('poll', sids)
sid = cns('poll', 'any')
Here, if any of the sessions of interest have completed, the return value will be one of their IDs; otherwise the return value will be empty. It is an error to call this function with sids empty or with no active sessions.


Asynchronous Mode: Input and Output

As mentioned above, there is one additional output command that applies to asynchronous mode. It is used to retrieve any outputs requested by an asynchronous cns('run') or cns('step') command.
[s, s, ...] = cns('output', sid)
[a, a, ...] = cns('output', sid)
The number of output parameters must match the number of outputs requested in the 'run' or 'step' call.

The other input/output commands ('get', 'update', and 'set') all have identical syntax to their synchronous counterparts, except that the second argument is a session ID. All these commands, and the 'output' command, implicitly cause MATLAB to wait if the session is still executing.


Asynchronous Mode: Other Useful Commands

When working asynchronously with multiple sessions, you usually need to keep track of what you asked a given session to do so that you can respond appropriately when it completes. It's helpful to be able to 'tag' a session with some piece of data. This is illustrated in the example above, where we associate an 'imno' (image number) property with every session. This information doesn't need to be propagated over to the GPU; it just needs to be available from within MATLAB. Such 'session properties' can be set and retrieved as follows:
        cns('set', sid, propname, value)
value = cns('get', sid, propname)
The following call reports the number of devices (e.g. GPUs) your computer has:
count = cns('devcount')
count = cns('devcount', platform)
The first version reports this number for the currently selected platform ('gpu' by default). The second version reports this number for the platform you supply.
if the platform is:count will be:
'gpu'the number of GPUs in the computer
'gpu#'1
'cpu' or 'debug'inf
Finally, the following call returns a vector of session IDs for all active sessions:
sids = cns('sessions')