Esempio n. 1
0
    def __init__(self,cf,input_sheet,x=0.0,y=0.0,template=BoundingBox(radius=0.1),
                 mask=patterngenerator.Constant(),
                 min_matrix_radius=1):
        """
        From an existing copy of ConnectionField (CF) that acts as a
        template, create a new CF that shares weights with the
        template CF.  Copies all the properties of CF to stay
        identical except the weights variable that actually contains
        the data.
        
        The only difference from a normal CF is that the weights of
        the CF are implemented as a numpy view into the single master
        copy of the weights stored in the CF template.
        """
        # CEBALERT: There's no call to super's __init__; see JAHACKALERT
        # below.
        template = copy(template)

        if not isinstance(template,Slice):
            template = Slice(template,input_sheet,force_odd=True,
                             min_matrix_radius=min_matrix_radius)

        # Note: if passed in, mask is shared between CFs (but not if created here)
        if not hasattr(mask,'view'):
            mask = _create_mask(patterngenerator.Constant(),
                               template.compute_bounds(input_sheet),
                               input_sheet,True,0.5) 



        self._has_norm_total=False
        self.mask=mask 
        weights_slice = self._create_input_sheet_slice(input_sheet,x,y,template,min_matrix_radius=min_matrix_radius)
        self.weights = weights_slice.submatrix(cf.weights)
Esempio n. 2
0
    def __init__(self,cf,input_sheet,x=0.0,y=0.0,template=BoundingBox(radius=0.1),
                 mask=patterngenerator.Constant(),
                 min_matrix_radius=1):
        """
        From an existing copy of ConnectionField (CF) that acts as a
        template, create a new CF that shares weights with the
        template CF.  Copies all the properties of CF to stay
        identical except the weights variable that actually contains
        the data.
        
        The only difference from a normal CF is that the weights of
        the CF are implemented as a numpy view into the single master
        copy of the weights stored in the CF template.
        """
        # CEBALERT: There's no call to super's __init__; see JAHACKALERT
        # below.
        template = copy(template)

        if not isinstance(template,Slice):
            template = Slice(template,input_sheet,force_odd=True,
                             min_matrix_radius=min_matrix_radius)

        # Note: if passed in, mask is shared between CFs (but not if created here)
        if not hasattr(mask,'view'):
            mask = _create_mask(patterngenerator.Constant(),
                               template.compute_bounds(input_sheet),
                               input_sheet,True,0.5) 



        self._has_norm_total=False
        self.mask=mask 
        weights_slice = self._create_input_sheet_slice(input_sheet,x,y,template,min_matrix_radius=min_matrix_radius)
        self.weights = weights_slice.submatrix(cf.weights)
Esempio n. 3
0
    def test_connection_field_like(self):
        # test a ConnectionField-like example
        sheet = Sheet(nominal_density=10,nominal_bounds=BoundingBox(radius=0.5))
        cf_bounds = BoundingBox(points=((0.3,0.3),(0.6,0.6)))

        slice_ = Slice(cf_bounds,sheet)
        slice_.crop_to_sheet(sheet)

        # check it's been cropped to fit onto sheet...
        self.assertEqual(slice_.tolist(),[0,2,8,10])

        # now check that it gives the correct bounds...
        cropped_bounds = slice_.compute_bounds(sheet)
        
        true_cropped_bounds = BoundingBox(points=((0.3,0.3),(0.5,0.5)))
        for a,b in zip(cropped_bounds.lbrt(),true_cropped_bounds.lbrt()):
            self.assertAlmostEqual(a,b)
Esempio n. 4
0
    def test_connection_field_like(self):
        # test a ConnectionField-like example
        sheet = Sheet(nominal_density=10,nominal_bounds=BoundingBox(radius=0.5))
        cf_bounds = BoundingBox(points=((0.3,0.3),(0.6,0.6)))

        slice_ = Slice(cf_bounds,sheet)
        slice_.crop_to_sheet(sheet)

        # check it's been cropped to fit onto sheet...
        self.assertEqual(slice_.tolist(),[0,2,8,10])

        # now check that it gives the correct bounds...
        cropped_bounds = slice_.compute_bounds(sheet)

        true_cropped_bounds = BoundingBox(points=((0.3,0.3),(0.5,0.5)))
        for a,b in zip(cropped_bounds.lbrt(),true_cropped_bounds.lbrt()):
            self.assertAlmostEqual(a,b)
Esempio n. 5
0
class SparseCFProjection(CFProjection):
    """
    A projection composed of SparseConnectionFields from a Sheet into
    a ProjectionSheet.

    SparseCFProjection computes its activity using a response_fn which
    can either be an optimized function implemented as part of the
    sparse matrix class or an unoptimized function, which requests the
    weights in dense format.  The initial contents of the
    SparseConnectionFields mapping from the input Sheet into the
    target ProjectionSheet are controlled by the weights_generator,
    cf_shape, and weights_output_fn parameters, while the location of
    the ConnectionField is controlled by the coord_mapper parameter.

    Any subclass has to implement the interface activate(self) that
    computes the response from the input and stores it in the activity
    array.
    """

    cf_type = param.Parameter(default=SparseConnectionField,doc="""
        Type of ConnectionField to use when creating individual CFs.""")

    learning_fn = param.Callable(default=CFPLF_Hebbian_Sparse,doc="""
        Function for computing changes to the weights based on one activation step.""")

    response_fn = param.Callable(default=CFPRF_DotProduct_Sparse,doc="""
        Function for computing the Projection response to an input pattern.""")

    weights_output_fns = param.HookList(default=[CFPOF_DivisiveNormalizeL1_Sparse],doc="""
        Functions applied to each CF after learning.""")

    initialized = param.Boolean(default=False)


    def __init__(self,initialize_cfs=True,**params):
        """
        Initialize the Projection with a set of cf_type objects
        (typically SparseConnectionFields), each located at the
        location in the source sheet corresponding to the unit in the
        target sheet. The cf_type objects are stored in the 'cfs'
        array.

        The nominal_bounds_template specified may be altered: the
        bounds must be fitted to the Sheet's matrix, and the weights
        matrix must have odd dimensions. These altered bounds are
        passed to the individual connection fields.

        A mask for the weights matrix is constructed. The shape is
        specified by cf_shape; the size defaults to the size
        of the nominal_bounds_template.
        """

        super(CFProjection,self).__init__(**params)

        self.weights_generator.set_dynamic_time_fn(None,sublistattr='generators')
        # get the actual bounds_template by adjusting a copy of the
        # nominal_bounds_template to ensure an odd slice, and to be
        # cropped to sheet if necessary
        self._slice_template = Slice(copy(self.nominal_bounds_template),
                                     self.src,force_odd=True,
                                     min_matrix_radius=self.min_matrix_radius)

        self.bounds_template = self._slice_template.compute_bounds(self.src)

        self.mask_template = _create_mask(self.cf_shape,self.bounds_template,
                                         self.src,self.autosize_mask,
                                         self.mask_threshold)

        self.n_units = self._calc_n_units()

        self.activity = np.array(self.dest.activity)
        self.norm_total = np.array(self.dest.activity,dtype=np.float64)
        self.has_norm_total = False

        if initialize_cfs:
            self._create_cfs()

        self.input_buffer = None


    def __getstate__(self):
        """
        Method to support pickling of sparse weights object.
        """

        state_dict = self.__dict__.copy()
        state_dict['triplets'] = state_dict['weights'].getTriplets()
        state_dict['weight_shape'] = (self.src.activity.shape,self.dest.activity.shape)
        del state_dict['weights']
        return state_dict


    def __setstate__(self,state_dict):
        """
        Method to support unpickling of sparse weights object.
        """

        self.__dict__.update(state_dict)
        self.weights = sparse.csarray_float(self.weight_shape[0],self.weight_shape[1])
        rowInds, colInds, values = self.triplets
        self.weights.setTriplets(rowInds,colInds,values)
        del self.triplets
        del self.weight_shape


    def _create_cfs(self):
        """
        Creates the CF objects, initializing the weights one by one
        and adding them to the sparse weights object in chunks.
        """

        vectorized_create_cf = simple_vectorize(self._create_cf)
        self.cfs = vectorized_create_cf(*self._generate_coords())
        self.flatcfs = list(self.cfs.flat)
        self.weights = sparse.csarray_float(self.src.activity.shape,self.dest.activity.shape)

        cf_x,cf_y = self.dest.activity.shape
        src_x,src_y = self.src.activity.shape

        y_array = np.zeros((src_x*src_y*cf_y),dtype=np.int32)
        x_array = np.zeros((src_x*src_y*cf_y),dtype=np.int32)
        val_array = np.zeros((src_x*src_y*cf_y),dtype=np.float32)

        # Iterate over the CFs
        for x in range(cf_x):
            temp_sparse = sparse.csarray_float(self.src.activity.shape,self.dest.activity.shape)
            idx = 0
            for y in range(cf_y):
                x1,x2,y1,y2 = self.cfs[x][y].input_sheet_slice.tolist()
                if self.same_cf_shape_for_all_cfs:
                    mask_template = self.mask_template
                else:
                    mask_template = _create_mask(self.cf_shape,self.bounds_template,
                                                 self.src,self.autosize_mask,
                                                 self.mask_threshold)
                weights = self.cfs[x][y]._init_weights(mask_template)
                cn_x,cn_y = weights.shape
                y_val = x * cf_y + y
                for cnx in range(cn_x):
                    val_array[idx:idx+cn_y] = weights[cnx,:]
                    x_val = (x1+cnx) * src_y + y1
                    x_array[idx:idx+cn_y] = range(x_val,x_val+cn_y)
                    y_array[idx:idx+cn_y] = y_val
                    idx += cn_y
            nnz_idx = val_array.nonzero()
            temp_sparse.setTriplets(x_array[nnz_idx],y_array[nnz_idx],val_array[nnz_idx])
            self.weights += temp_sparse
            x_array *= 0; y_array *= 0; val_array *= 0.0
        del temp_sparse
        self.weights.compress()
        self.apply_learn_output_fns()
        print self.name , "loaded"


    def _create_cf(self,x,y):
        """
        Create a ConnectionField at x,y in the src sheet.
        """

        try:
            CF = self.cf_type(template=self._slice_template,projection=self,input_sheet=self.src,x=x,y=y,
                              weights_generator=self.weights_generator,
                              min_matrix_radius=self.min_matrix_radius)
        except NullCFError:
            if self.allow_null_cfs:
                CF = None
            else:
                raise

        return CF


    def activate(self,input_activity):
        """Activate using the specified response_fn and output_fn."""
        if self.input_fns:
            input_activity = input_activity.copy()
        for iaf in self.input_fns:
            iaf(input_activity)
        self.input_buffer = input_activity
        self.activity *=0.0
        self.response_fn(self)
        for of in self.output_fns:
            of(self.activity)


    def learn(self):
        """
        For a SparseCFProjection, learn consists of calling the learning_fn.
        """
        # Learning is performed if the input_buffer has already been set,
        # i.e. there is an input to the Projection.
        if self.input_buffer != None:
            self.learning_fn(self)


    def apply_learn_output_fns(self,active_units_mask=True):
        """
        Apply the weights_output_fns to each unit.
        """
        for of in self.weights_output_fns: of(self)


    def n_bytes(self):
        """
        Estimates the size on the basis of the number non-zeros in the
        sparse matrix, asssuming indices and values are stored using
        32-bit integers and floats respectively.
        """
        return self.n_conns() * (3 * 4)


    def n_conns(self):
        """
        Returns number of nonzero weights.
        """
        return self.weights.getnnz()
Esempio n. 6
0
class SparseCFProjection(CFProjection):
    """
    A projection composed of SparseConnectionFields from a Sheet into
    a ProjectionSheet.

    SparseCFProjection computes its activity using a response_fn which
    can either be an optimized function implemented as part of the
    sparse matrix class or an unoptimized function, which requests the
    weights in dense format.  The initial contents of the
    SparseConnectionFields mapping from the input Sheet into the
    target ProjectionSheet are controlled by the weights_generator,
    cf_shape, and weights_output_fn parameters, while the location of
    the ConnectionField is controlled by the coord_mapper parameter.

    Any subclass has to implement the interface activate(self) that
    computes the response from the input and stores it in the activity
    array.
    """

    cf_type = param.Parameter(default=SparseConnectionField,doc="""
        Type of ConnectionField to use when creating individual CFs.""")

    learning_fn = param.Callable(default=CFPLF_Hebbian_Sparse,doc="""
        Function for computing changes to the weights based on one activation step.""")

    response_fn = param.Callable(default=CFPRF_DotProduct_Sparse,doc="""
        Function for computing the Projection response to an input pattern.""")

    weights_output_fns = param.HookList(default=[CFPOF_DivisiveNormalizeL1_Sparse],doc="""
        Functions applied to each CF after learning.""")

    initialized = param.Boolean(default=False)


    def __init__(self,initialize_cfs=True,**params):
        """
        Initialize the Projection with a set of cf_type objects
        (typically SparseConnectionFields), each located at the
        location in the source sheet corresponding to the unit in the
        target sheet. The cf_type objects are stored in the 'cfs'
        array.

        The nominal_bounds_template specified may be altered: the
        bounds must be fitted to the Sheet's matrix, and the weights
        matrix must have odd dimensions. These altered bounds are
        passed to the individual connection fields.

        A mask for the weights matrix is constructed. The shape is
        specified by cf_shape; the size defaults to the size
        of the nominal_bounds_template.
        """

        super(CFProjection,self).__init__(**params)

        self.weights_generator.set_dynamic_time_fn(None,sublistattr='generators')
        # get the actual bounds_template by adjusting a copy of the
        # nominal_bounds_template to ensure an odd slice, and to be
        # cropped to sheet if necessary
        self._slice_template = Slice(copy(self.nominal_bounds_template),
                                     self.src,force_odd=True,
                                     min_matrix_radius=self.min_matrix_radius)

        self.bounds_template = self._slice_template.compute_bounds(self.src)

        self.mask_template = _create_mask(self.cf_shape,self.bounds_template,
                                         self.src,self.autosize_mask,
                                         self.mask_threshold)

        self.n_units = self._calc_n_units()

        self.activity = np.array(self.dest.activity)
        self.norm_total = np.array(self.dest.activity,dtype=np.float64)
        self.has_norm_total = False

        if initialize_cfs:
            self._create_cfs()

        if self.apply_output_fns_init:
            self.apply_learn_output_fns()

        self.input_buffer = None


    def __getstate__(self):
        """
        Method to support pickling of sparse weights object.
        """

        state_dict = self.__dict__.copy()
        state_dict['triplets'] = state_dict['weights'].getTriplets()
        state_dict['weight_shape'] = (self.src.activity.shape,self.dest.activity.shape)
        del state_dict['weights']
        return state_dict


    def __setstate__(self,state_dict):
        """
        Method to support unpickling of sparse weights object.
        """

        self.__dict__.update(state_dict)
        self.weights = sparse.csarray_float(self.weight_shape[0],self.weight_shape[1])
        rowInds, colInds, values = self.triplets
        self.weights.setTriplets(rowInds,colInds,values)
        del self.triplets
        del self.weight_shape


    def _create_cfs(self):
        """
        Creates the CF objects, initializing the weights one by one
        and adding them to the sparse weights object in chunks.
        """

        vectorized_create_cf = simple_vectorize(self._create_cf)
        self.cfs = vectorized_create_cf(*self._generate_coords())
        self.flatcfs = list(self.cfs.flat)
        self.weights = sparse.csarray_float(self.src.activity.shape,self.dest.activity.shape)

        cf_x,cf_y = self.dest.activity.shape
        src_x,src_y = self.src.activity.shape

        y_array = np.zeros((src_x*src_y*cf_y),dtype=np.int32)
        x_array = np.zeros((src_x*src_y*cf_y),dtype=np.int32)
        val_array = np.zeros((src_x*src_y*cf_y),dtype=np.float32)

        # Iterate over the CFs
        for x in range(cf_x):
            temp_sparse = sparse.csarray_float(self.src.activity.shape,self.dest.activity.shape)
            idx = 0
            for y in range(cf_y):
                cf = self.cfs[x][y]
                label = cf.label + ('-%d' % self.seed if self.seed is not None else '')
                name = "%s_CF (%.5f, %.5f)" % ('' if label is None else label, cf.x,cf.y)
                x1,x2,y1,y2 = cf.input_sheet_slice.tolist()
                if self.same_cf_shape_for_all_cfs:
                    mask_template = self.mask_template
                else:
                    mask_template = _create_mask(self.cf_shape,self.bounds_template,
                                                 self.src,self.autosize_mask,
                                                 self.mask_threshold, name=name)
                weights = self.cfs[x][y]._init_weights(mask_template)
                cn_x,cn_y = weights.shape
                y_val = x * cf_y + y
                for cnx in range(cn_x):
                    val_array[idx:idx+cn_y] = weights[cnx,:]
                    x_val = (x1+cnx) * src_y + y1
                    x_array[idx:idx+cn_y] = range(x_val,x_val+cn_y)
                    y_array[idx:idx+cn_y] = y_val
                    idx += cn_y
            nnz_idx = val_array.nonzero()
            temp_sparse.setTriplets(x_array[nnz_idx],y_array[nnz_idx],val_array[nnz_idx])
            self.weights += temp_sparse
            x_array *= 0; y_array *= 0; val_array *= 0.0
        del temp_sparse
        self.weights.compress()
        self.debug("Sparse projection %r loaded" % self.name)


    def _create_cf(self,x,y):
        """
        Create a ConnectionField at x,y in the src sheet.
        """

        label = self.hash_format.format(name=self.name,
                                        src=self.src.name,
                                        dest=self.dest.name)
        try:
            CF = self.cf_type(template=self._slice_template,
                              projection=self,input_sheet=self.src,x=x,y=y,
                              weights_generator=self.weights_generator,
                              min_matrix_radius=self.min_matrix_radius,
                              label=label)
        except NullCFError:
            if self.allow_null_cfs:
                CF = None
            else:
                raise

        return CF

    def get_sheet_mask(self):
        return np.ones(self.activity.shape, dtype=self.activity.dtype)

    def get_active_units_mask(self):
        return np.ones(self.activity.shape, dtype=self.activity.dtype)


    def activate(self,input_activity):
        """Activate using the specified response_fn and output_fn."""
        if self.input_fns:
            input_activity = input_activity.copy()
        for iaf in self.input_fns:
            iaf(input_activity)
        self.input_buffer = input_activity
        self.activity *=0.0
        self.response_fn(self)
        for of in self.output_fns:
            of(self.activity)


    def learn(self):
        """
        For a SparseCFProjection, learn consists of calling the learning_fn.
        """
        # Learning is performed if the input_buffer has already been set,
        # i.e. there is an input to the Projection.
        if self.input_buffer is not None:
            self.learning_fn(self)


    def apply_learn_output_fns(self,active_units_mask=True):
        """
        Apply the weights_output_fns to each unit.
        """
        for of in self.weights_output_fns: of(self)


    def n_bytes(self):
        """
        Estimates the size on the basis of the number non-zeros in the
        sparse matrix, asssuming indices and values are stored using
        32-bit integers and floats respectively.
        """
        return self.n_conns() * (3 * 4)


    def n_conns(self):
        """
        Returns number of nonzero weights.
        """
        return self.weights.getnnz()