Exemplo n.º 1
0
def calculate_min_activity(columns, active, distances, inhibition_area, activity, min_activity_threshold):
    """
    Calculates the minActivity matrix from the paper (p. 4).
    :param columns: the 4-dimensional array of HTM columns: a 4-dimensional
                    array of shape *shape* that represents the HTM columns and
                    their synapses; each element columns[a, b, c, d] contains
                    the permanence value of the synapse connecting the column
                    with coordinates (a, b) to input with coordinates (c, d).
    :param active: array of shape (columns.shape[0], columns.shape[0]);
                   each element active[a, b] is True if the column [a, b]
                   is active this iteration and False otherwise.
    :param distances: a 4-dimensional array of the same shape as *columns*;
                      each element distances[a, b, c, d] contains the euclidean
                      distance from (a, b) to (c, d).
    :param inhibition_area: the BSP's inhibitionArea parameter (p. 3, 4).
    :param activity: the BSP's activity matrix (p. 4).
                     This parameter is modified and returned.
                     It is a dictionary with tuples (y, x) of HTM column
                     coordinates as keys and deque (a queue implementation)
                     instances as values. The queue for key [a, b] stores a 1
                     each iteration the the column [a, b] is active during the
                     last 1000 iterations.
    :param min_activity_threshold: the BSP's minActivityThreshold parameter
                                   (p. 4).
    :return: the BSP's minActivity matrix (p. 4); an array min_activity of
             shape (columns.shape[0], columns.shape[1]), where each
             min_activity[a b] represents the calculated minActivity for the
             column [a, b]:

             minActivity([a, b]) = max(activity[u, v]) * minActivityThreshold

             where the column [u, v] is a neighbour of [y, x] (within
             inhibitionArea)
    """
    # Initialize the min_activity array.
    min_activity = np.zeros(shape=columns.shape[:2])

    # For each active column [y, x], ...
    for y, x, _ in iter_columns(columns, active_matrix=active):
        c = (y, x)
        max_activity = 0
        # get the neighbours of [y, x] ...
        neighbours = iter_neighbours(columns, y, x, distances, inhibition_area)
        # and for each neighbour [u, v] of [y, x], ...
        for u, v, _ in neighbours:
            n = (u, v)
            # calculate the how many times [u, v] was active during the
            # last 1000 iterations, ...
            activity_count = activity[n].sum()
            # and choose the maximum count among all the neighbours of
            # [y, x].
            if activity_count > max_activity:
                max_activity = activity_count
        # Finally, scale the maximum activity count among the neighbours of
        # [y, x] by min_activity_threshold.
        min_activity[c] = max_activity * min_activity_threshold

    return min_activity
Exemplo n.º 2
0
def update_inhibition_area(columns, connect_threshold):
    """
    Implements the updateInhibitionArea function from the paper (p. 4).
    :param columns: the 4-dimensional array of HTM columns: a 4-dimensional
                    array of shape *shape* that represents the HTM columns and
                    their synapses; each element columns[a, b, c, d] contains
                    the permanence value of the synapse connecting the column
                    with coordinates (a, b) to input with coordinates (c, d).
    :param connect_threshold: threshold over which a potential synapse is
                              considered *connected*. All potential synapses
                              start with a permanence value within 0.1 of
                              this parameter.
    :return: the inhibition area for the algorithm, calculated as the mean size
             of the receptive fields of all columns, where a column's receptive
             field is calculated as \pi*d^2/16, with:
                d = max([a, b], x) - min([a, b], x) +
                    max([a, b], y) - min([a, b], y) + 2
             where max and min return the the maximum and minimum x and y
             values of all connected synapses belonging to column [a, b].
    """
    # Initialize the inhibition area accumulator.
    inhibition_area = 0
    # Get the shape of the synapse's matrix
    shape = columns.shape[2:]
    # Generate matrix of synapse's coordinates. For instane, for a synapse's
    # matrix of shape (5, 5), coord_matrix would be:
    # [[0, 1, 2, 3, 4],
    #  [1, 2, 3, 4, 5],
    #  [2, 3, 4, 5, 6],
    #  [3, 4, 5, 6, 7],
    #  [4, 5, 6, 7, 8]]
    coord_matrix = np.array([i + j for i in range(shape[0]) for j in range(shape[1])], dtype=np.float)
    coord_matrix = coord_matrix.reshape(shape)
    # For each column ...
    for _, _, syn_matrix in iter_columns(columns):
        # create matrices to calculate the synapse's min and max coordinates
        min_matrix, max_matrix = create_min_max_matrices(coord_matrix, syn_matrix, connect_threshold)
        # calculate the synapse's min and max coordinates
        min_y, min_x, max_y, max_x = calculate_min_max_y_x(min_matrix, max_matrix)
        # set d = max([a, b], y) - min([a, b], y)
        #         + max([a, b], x) - min([a, b], x)
        #         + 2, ...
        d = max_y - min_y + max_x - min_x + 2
        # calculate the receptive field based on d, ...
        receptive_radius = d / 4
        receptive_field = np.pi * receptive_radius ** 2
        # add the receptive field of the column [y, x] to the accumulator, ...
        inhibition_area += receptive_field

    # and finally calculate the average of all receptive fields.
    inhibition_area /= columns.shape[0] * columns.shape[1]

    return inhibition_area
Exemplo n.º 3
0
def calculate_overlap(input_vector, columns, min_overlap, connect_threshold,
                      boost):
    """
    Implements the calculateOverlap function from the paper (p. 3).
    :param input_vector: a single input_vector from the images set.
    :param columns: the 4-dimensional array of HTM columns: a 4-dimensional
                    array of shape *shape* that represents the HTM columns and
                    their synapses; each element columns[a, b, c, d] contains
                    the permanence value of the synapse connecting the column
                    with coordinates (a, b) to input with coordinates (c, d).
    :param min_overlap: the BSP's minOverlap parameter (p. 3). Type: float.
    :param connect_threshold: the BSP's connectThreshold parameter (p. 3).
                              Type: float.
    :param boost: the BSP's boost matrix (pp. 3, 4).
                  It is a matrix of shape (columns.shape[0], columns.shape[1])
    :param overlap_sum: the BSP's overlapSum matrix (p. 4). This parameter is
                        modified and returned. It is a dictionary with tuples
                        (y, x) of HTM column coordinates as keys and deque
                        (a queue implementation) instances as values. The queue
                        for key [a, b] stores a 1 each time the overlap of the
                        column [a, b] was above the minOverlap threshold during
                        the last 1000 iterations.
    :return: a tuple (overlap, overlap_sum). *overlap* is an array of shape
             (columns.shape[0], columns.shape[0]); each element overlap[a, b]
             contains the overlap of the column [a, b] with the input_vector.
             *overlap_sum* is the parameter of the same name; the queue in
             overlap_sum[a, b] will have a 1 pushed into it if the overlap for
             the column [a, b] was above the min_overlap threshold this
             iteration.
    """
    # Initialize the overlap array.
    overlap = np.zeros(columns.shape[:2])
    # for each column ...
    for y, x, syn_matrix in iter_columns(columns):  # @UnusedVariable
        c = (y, x)
        # calculate the overlap as the sum of pixel's values in the
        # input_vector assigned to *connected* synapses and, ...
        # (numexpr.evaluate optimizes and carries out the operations defined in
        # its string argument, it is used here because numpy has some
        # problems when comparing NaNs with numbers)
        active_synapses = ne.evaluate('syn_matrix >= connect_threshold')
        overlap[c] = input_vector[active_synapses].sum()
        # if the overlap is not enough, ...
        if overlap[c] < min_overlap:
            # reset it, but, ...
            overlap[c] = 0
        # if the overlap is enough, ...
        else:
            # then boost it.
            overlap[c] *= boost[c]

    return overlap
Exemplo n.º 4
0
def learn_synapse_connections(columns, active, input_vector, p_inc,
                              p_dec, activity, min_activity, boost, b_inc,
                              p_mult, connect_threshold, distances, b_max):
    """
    Calculates the minActivity matrix from the paper (p. 6).
    :param columns: the 4-dimensional array of HTM columns: a 4-dimensional
                    array of shape *shape* that represents the HTM columns and
                    their synapses; each element columns[a, b, c, d] contains
                    the permanence value of the synapse connecting the column
                    with coordinates (a, b) to input with coordinates (c, d).
    :param active: array of shape (columns.shape[0], columns.shape[0]);
                   each element active[a, b] is True if the column [a, b]
                   is active this iteration and False otherwise.
    :param input_vector: the input to be learned. A 2-dimensional array of
                         shape (columns.shape[0], columns.shape[1]).
    :param p_inc: the BSP'perm pInc parameter (p. 4). A float that indicates
                  the amount by which a synapse'perm permanence must be
                  incremented.
    :param p_dec: the BSP'perm pDec parameter (p. 4). A float that indicates
                  the amount by which a synapse'perm permanence must be
                  decremented.
    :param activity: the BSP'perm activity matrix (p. 4).
                     This parameter is modified and returned.
                     It is a dictionary with tuples (y, x) of HTM column
                     coordinates as keys and deque (a queue implementation)
                     instances as values. The queue for key [a, b] stores a 1
                     each iteration the the column [a, b] is active during the
                     last 1000 iterations.
    :param overlap_sum: the BSP'perm overlapSum matrix (p. 4). This parameter
                        is modified and returned. It is a dictionary with
                        tuples (y, x) of HTM column coordinates as keys and
                        deque (a queue implementation) instances as values. The
                        queue for key [a, b] stores a 1 each time the overlap
                        of the column [a, b] was above the minOverlap threshold
                        during the last 1000 iterations.
    :param min_activity: the BSP'perm minActivity matrix (p. 4); an array
                         min_activity of shape
                         (columns.shape[0], columns.shape[1]), where each
                         min_activity[a b] represents the calculated
                         minActivity for the column [a, b].
    :param boost: the BSP'perm boost matrix (pp. 3, 4).
                  It is a matrix of shape (columns.shape[0], columns.shape[1])
    :param b_inc: the BSP'perm bInc parameter (p. 4). A float that indicates
                  the amount by which a column'perm boost must be incremented.
    :param p_mult: the BSP'perm pMult parameter (p. 4). A float that indicates
                   the amount by which a synapse'perm permanence must be
                   multiplied.
    :param connect_threshold: threshold over which a potential synapse is
                              considered *connected*. All potential synapses
                              start with a permanence value within 0.1 of
                              this parameter.
    :param distances: a 4-dimensional array of the same shape as *columns*;
                      each element distances[a, b, c, d] contains the euclidean
                      distance from (a, b) to (c, d).
    :param b_max: boost threshold (p. 6).
    :return: a tuple (columns, synapse_modified). *columns* is the  parameter
             of the same name, modified according to the BSP learning
             algorithm. *synapse_modified* is a boolean indicating whether any
             synapses were modified in the course of learning.
    """
    # Assume no synapse will be modified.
    synapse_modified = False
    mean_input = np.nanmean(input_vector)

    # Store which synapses are connecter and which aren't.
    pre_col_matrix = ne.evaluate('columns >= connect_threshold')
    # For each active column [y, x] ...
    for _, _, syn_matrix in iter_columns(columns, active_matrix=active):
        # for each potential synapse [u, v] of [y, x] with permanence perm,
        # (NOTE: by definition, perm = syn_matrix[u, v])
        for u, v, perm in iter_synapses(syn_matrix, only_potential=True):
            s = (u, v)
            if (input_vector[s] > mean_input and
                    perm >= connect_threshold):
                syn_matrix[s] = min(perm + p_inc, 1)
            elif (input_vector[s] > mean_input and
                    perm < connect_threshold):
                syn_matrix[s] = min(perm + p_inc,
                                    connect_threshold - p_inc)
            else:
                syn_matrix[s] = max(perm - p_dec, 0)

    # For each column [y, x] ...
    for y, x, syn_matrix in iter_columns(columns):
        c = (y, x)
        # if the activity of [y, x] over the last 1000 iterations was too low,
        if activity[c].sum() < min_activity[c]:
            # increment the boost by b_inc (in the paper this is done inside
            # the if clause in lines 14-15 of algorithm 3 in page 6), ...
            boost[c] += b_inc
            # if its boost is too high, ...
            if boost[c] > b_max:
                # define a function to filter all synapses with a permanence
                # value below the threshold, ...
                def filter_permanences(s):
                    u, v, perm = s
                    if perm < connect_threshold:
                        return (perm, distances[c][u, v])
                    else:
                        return -np.infty

                # reset the boost for column [y, x], ...
                boost[c] = 1
                # select the disconnected synapse with the highest permanence,
                # choosing the nearest synapse in case of tie, ...
                max_syn = max(iter_synapses(syn_matrix),
                              key=filter_permanences)
                max_s = max_syn[:2]
                # and set the selected synapse's permanence value to p_inc
                # above the threshold.
                syn_matrix[max_s] = connect_threshold + p_inc

    # Set synapse_modified to True if any synapse change from connected to
    # disconnected or vice-versa by this algorithm.
    if (pre_col_matrix !=
            ne.evaluate('columns >= connect_threshold')).any():
        synapse_modified = True

    # Return the columns array, with its synapses modified.
    return columns, synapse_modified
Exemplo n.º 5
0
def inhibit_columns(columns, distances, inhibition_area, overlap, activity, desired_activity):
    """
    Implements the inhibitColums function from the paper (pp. 3, 4)
    :param columns: the 4-dimensional array of HTM columns: a 4-dimensional
                    array of shape *shape* that represents the HTM columns and
                    their synapses; each element columns[a, b, c, d] contains
                    the permanence value of the synapse connecting the column
                    with coordinates (a, b) to input with coordinates (c, d).
    :param distances: a 4-dimensional array of the same shape as *columns*;
                      each element distances[a, b, c, d] contains the euclidean
                      distance from (a, b) to (c, d).
    :param inhibition_area: the BSP's inhibitionArea parameter (p. 3, 4).
    :param overlap: an array of shape (columns.shape[0], columns.shape[0]);
                    each element overlap[a, b] contains the overlap of the
                    column [a, b] with the image.
    :param activity: the BSP's activity matrix (p. 4).
                     This parameter is modified and returned.
                     It is a dictionary with tuples (y, x) of HTM column
                     coordinates as keys and deque (a queue implementation)
                     instances as values. The queue for key [a, b] stores a 1
                     each iteration the the column [a, b] is active during the
                     last 1000 iterations.
    :param desired_activity: the BSP's desiredActivity parameter (p. 4).
    :return: a tuple (active, activity). *active* is an array of shape
             (columns.shape[0], columns.shape[0]); each element active[a, b] is
             True if the column [a, b] is active this iteration and False
             otherwise. *activity* is the parameter of the same name; the queue
             in activity[a, b] will have a 1 pushed into it if the the column
             [a, b] was active this iteration.
    """
    # Initialize the active array filling it with False.
    active = np.zeros(shape=columns.shape[:2], dtype=np.bool)

    # For each column [y, x]...
    for y, x, _ in iter_columns(columns):
        # if [y, x] reacted to the input at all, ...
        # (NOTE: This test is not present in the ASP paper, but it is present
        # in the original HTM paper. However it does make sense that a column
        # should be active only if some synapses were exited by the input.)
        if overlap[y, x] > 0:
            # initialize the activity counter, ...
            activity_sum = 0
            # obtain the list of neighbours of the column [y, x], ...
            neighbours = iter_neighbours(columns, y, x, distances, inhibition_area)
            # for each neighbour [u, v] of [y, x] ...
            for u, v, _ in neighbours:
                # if the neighbour's overlap is over this column's overlap, ...
                if overlap[u, v] > overlap[y, x]:
                    # count it towards the activity, ...
                    activity_sum += 1

            # and if the neighbours of [y, x] are not too active, ...
            if activity_sum < desired_activity:
                # set [y, x] as active, ...
                active[y, x] = True
                # and then update the activity array, indicating that
                # the column [y, x] was active in this iteration.
                activity[y, x].append(1)
            else:
                # and then update the activity array, indicating that
                # the column [y, x] was inactive in this iteration.
                activity[y, x].append(0)
        else:
            # update the activity array, indicating that
            # the column [y, x] was inactive in this iteration.
            activity[y, x].append(0)

    return active, activity