3 @brief Neural Network: Pulse Coupled Neural Network
4 @details Implementation based on paper @cite book::image_processing_using_pcnn.
6 @authors Andrei Novikov (pyclustering@yandex.ru)
8 @copyright BSD-3-Clause
15 import matplotlib.pyplot
as plt
16 import matplotlib.animation
as animation
22 from pyclustering.core.wrapper
import ccore_library
24 import pyclustering.core.pcnn_wrapper
as wrapper
31 @brief Parameters for pulse coupled neural network.
37 @brief Default constructor of parameters for pulse-coupled neural network.
38 @details Constructor initializes parameters by default non-zero values that can be
39 used for simple simulation.
78 @brief Represents output dynamic of PCNN (pulse-coupled neural network).
85 @brief (list) Returns oscillato outputs during simulation.
97 @brief (list) Returns sampling times when dynamic is measured during simulation.
103 return list(range(len(self)))
108 @brief Constructor of PCNN dynamic.
110 @param[in] dynamic (list): Dynamic of oscillators on each step of simulation. If ccore pointer is specified than it can be ignored.
111 @param[in] ccore (ctypes.pointer): Pointer to CCORE pcnn_dynamic instance in memory.
123 @brief Default destructor of PCNN dynamic.
132 @brief (uint) Returns number of simulation steps that are stored in dynamic.
143 @brief Allocate clusters in line with ensembles of synchronous oscillators where each
144 synchronous ensemble corresponds to only one cluster.
146 @return (list) Grours (lists) of indexes of synchronous oscillators.
147 For example, [ [index_osc1, index_osc3], [index_osc2], [index_osc4, index_osc5] ].
155 traverse_oscillators = set()
157 number_oscillators = len(self.
__dynamic[0])
159 for t
in range(len(self.
__dynamic) - 1, 0, -1):
161 for i
in range(number_oscillators):
163 if i
not in traverse_oscillators:
164 sync_ensemble.append(i)
165 traverse_oscillators.add(i)
167 if sync_ensemble != []:
168 sync_ensembles.append(sync_ensemble)
170 return sync_ensembles
175 @brief Analyses output dynamic of network and allocates spikes on each iteration as a list of indexes of oscillators.
176 @details Each allocated spike ensemble represents list of indexes of oscillators whose output is active.
178 @return (list) Spike ensembles of oscillators.
186 number_oscillators = len(self.
__dynamic[0])
191 for index
in range(number_oscillators):
193 spike_ensemble.append(index)
195 if len(spike_ensemble) > 0:
196 spike_ensembles.append(spike_ensemble)
198 return spike_ensembles
203 @brief Analyses output dynamic and calculates time signal (signal vector information) of network output.
205 @return (list) Time signal of network output.
212 signal_vector_information = []
214 signal_vector_information.append(sum(self.
__dynamic[t]))
216 return signal_vector_information
221 @brief Visualizer of output dynamic of pulse-coupled neural network (PCNN).
228 @brief Shows time signal (signal vector information) using network dynamic during simulation.
230 @param[in] pcnn_output_dynamic (pcnn_dynamic): Output dynamic of the pulse-coupled neural network.
234 time_signal = pcnn_output_dynamic.allocate_time_signal()
235 time_axis = range(len(time_signal))
238 plt.plot(time_axis, time_signal,
'-')
239 plt.ylabel(
"G (time signal)")
240 plt.xlabel(
"t (iteration)")
248 @brief Shows output dynamic (output of each oscillator) during simulation.
250 @param[in] pcnn_output_dynamic (pcnn_dynamic): Output dynamic of the pulse-coupled neural network.
251 @param[in] separate_representation (list): Consists of lists of oscillators where each such list consists of oscillator indexes that will be shown on separated stage.
255 draw_dynamics(pcnn_output_dynamic.time, pcnn_output_dynamic.output, x_title =
"t", y_title =
"y(t)", separate = separate_representation)
260 @brief Shows animation of output dynamic (output of each oscillator) during simulation.
262 @param[in] pcnn_output_dynamic (pcnn_dynamic): Output dynamic of the pulse-coupled neural network.
263 @param[in] image_size (tuple): Image size represented as (height, width).
267 figure = plt.figure()
269 time_signal = pcnn_output_dynamic.allocate_time_signal()
270 spike_ensembles = pcnn_output_dynamic.allocate_spike_ensembles()
274 for t
in range(len(time_signal)):
275 image_color_segments = [(255, 255, 255)] * (image_size[0] * image_size[1])
277 if time_signal[t] > 0:
278 for index_pixel
in spike_ensembles[ensemble_index]:
279 image_color_segments[index_pixel] = (0, 0, 0)
283 stage = numpy.array(image_color_segments, numpy.uint8)
284 stage = numpy.reshape(stage, image_size + ((3),))
285 image_cluster = Image.fromarray(stage,
'RGB')
287 spike_animation.append( [ plt.imshow(image_cluster, interpolation=
'none') ] )
290 im_ani = animation.ArtistAnimation(figure, spike_animation, interval=75, repeat_delay=3000, blit=
True)
296 @brief Model of oscillatory network that is based on the Eckhorn model.
298 @details CCORE option can be used to use the pyclustering core - C/C++ shared library for processing that significantly increases performance.
300 Here is an example how to perform PCNN simulation:
302 from pyclustering.nnet.pcnn import pcnn_network, pcnn_visualizer
304 # Create Pulse-Coupled neural network with 10 oscillators.
305 net = pcnn_network(10)
307 # Perform simulation during 100 steps using binary external stimulus.
308 dynamic = net.simulate(50, [1, 1, 1, 0, 0, 0, 0, 1, 1, 1])
310 # Allocate synchronous ensembles from the output dynamic.
311 ensembles = dynamic.allocate_sync_ensembles()
313 # Show output dynamic.
314 pcnn_visualizer.show_output_dynamic(dynamic, ensembles)
322 def __init__(self, num_osc, parameters=None, type_conn=conn_type.ALL_TO_ALL, type_conn_represent=conn_represent.MATRIX, height=None, width=None, ccore=True):
324 @brief Constructor of oscillatory network is based on Kuramoto model.
326 @param[in] num_osc (uint): Number of oscillators in the network.
327 @param[in] parameters (pcnn_parameters): Parameters of the network.
328 @param[in] type_conn (conn_type): Type of connection between oscillators in the network (all-to-all, grid, bidirectional list, etc.).
329 @param[in] type_conn_represent (conn_represent): Internal representation of connection in the network: matrix or list.
330 @param[in] height (uint): Number of oscillators in column of the network, this argument is used
331 only for network with grid structure (GRID_FOUR, GRID_EIGHT), for other types this argument is ignored.
332 @param[in] width (uint): Number of oscillotors in row of the network, this argument is used only
333 for network with grid structure (GRID_FOUR, GRID_EIGHT), for other types this argument is ignored.
334 @param[in] ccore (bool): If True then all interaction with object will be performed via CCORE library (C++ implementation of pyclustering).
349 if parameters
is not None:
354 if (ccore
is True)
and ccore_library.workable():
355 network_height = height
356 network_width = width
358 if (type_conn == conn_type.GRID_FOUR)
or (type_conn == conn_type.GRID_EIGHT):
359 if (network_height
is None)
or (network_width
is None):
360 side_size = num_osc ** (0.5)
361 if side_size - math.floor(side_size) > 0:
362 raise NameError(
'Invalid number of oscillators in the network in case of grid structure')
364 network_height = int(side_size)
365 network_width = int(side_size)
372 super().
__init__(num_osc, type_conn, type_conn_represent, height, width)
383 @brief Default destructor of PCNN.
393 @brief (uint) Returns size of oscillatory network.
405 @brief Performs static simulation of pulse coupled neural network using.
407 @param[in] steps (uint): Number steps of simulations during simulation.
408 @param[in] stimulus (list): Stimulus for oscillators, number of stimulus should be equal to number of oscillators.
410 @return (pcnn_dynamic) Dynamic of oscillatory network - output of each oscillator on each step of simulation.
414 if len(stimulus) != len(self):
415 raise NameError(
'Number of stimulus should be equal to number of oscillators. Each stimulus corresponds to only one oscillators.')
424 for step
in range(1, steps, 1):
432 def _calculate_states(self, stimulus):
434 @brief Calculates states of oscillators in the network for current step and stored them except outputs of oscillators.
436 @param[in] stimulus (list): Stimulus for oscillators, number of stimulus should be equal to number of oscillators.
438 @return (list) New outputs for oscillators (do not stored it).
447 for index
in range(0, self.
_num_osc, 1):
450 feeding_influence = 0.0
451 linking_influence = 0.0
453 for index_neighbour
in neighbors:
457 feeding_influence *= self.
_params.VF
458 linking_influence *= self.
_params.VL
460 feeding[index] = self.
_params.AF * self.
_feeding[index] + stimulus[index] + feeding_influence
461 linking[index] = self.
_params.AL * self.
_linking[index] + linking_influence
464 internal_activity = feeding[index] * (1.0 + self.
_params.B * linking[index])
467 if internal_activity > self.
_threshold[index]:
473 if self.
_params.FAST_LINKING
is not True:
477 if self.
_params.FAST_LINKING
is True:
479 previous_outputs = outputs[:]
481 while output_change
is True:
482 current_output_change =
False
484 for index
in range(0, self.
_num_osc, 1):
485 linking_influence = 0.0
488 for index_neighbour
in neighbors:
489 linking_influence += previous_outputs[index_neighbour] * self.
_params.W
491 linking_influence *= self.
_params.VL
492 linking[index] = linking_influence
494 internal_activity = feeding[index] * (1.0 + self.
_params.B * linking[index])
497 if internal_activity > self.
_threshold[index]:
502 current_output_change |= (outputs[index] != previous_outputs[index])
504 output_change = current_output_change
506 if output_change
is True:
507 previous_outputs = outputs[:]
510 if self.
_params.FAST_LINKING
is True:
511 for index
in range(0, self.
_num_osc, 1):