Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

gnn_gcomm.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  *  @file gnn_gcomm.c
00003  *  @brief gnn_gcomm Implementation.
00004  *
00005  *  @date   : 28-09-03 21:09
00006  *  @author : Pedro Ortega C. <peortega@dcc.uchile.cl>
00007  *  Copyright  2003  Pedro Ortega C.
00008  ****************************************************************************/
00009 /*
00010  *  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU Library General Public License for more details.
00019  *
00020  *  You should have received a copy of the GNU General Public License
00021  *  along with this program; if not, write to the Free Software
00022  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00023  */
00024 
00025 /**
00026  * @defgroup gnn_gcomm_doc gnn_gcomm : Generalized Committee Convergence Node.
00027  * @ingroup gnn_atomic_doc
00028  *
00029  * This node type implements the function given by:
00030  *
00031  * \f[ y_j = \sum_k \alpha_k x_{km+j}, \qquad 0 \leq j \leq m-1 \f]
00032  *
00033  * where \f$k\f$ and \f$j\f$ are uniquely combined in order to run over all
00034  * input indexes \f$i = km+j = 0,\ldots, n-1\f$, and the coefficients
00035  * \f$\alpha_k\f$ are:
00036  *
00037  * \f[ \alpha_k = \frac{w_k^2}{\sum_{k'} w_{k'}^2 } \f]
00038  *
00039  * Note that this assures that
00040  *
00041  * \f[ \sum_k \alpha_k = 1,\qquad 0 \leq \alpha_k \leq 1 \f]
00042  *
00043  * In other words, this function slices the input vector \f$x\f$ into several
00044  * subvectors of size \f$m \times 1\f$ and performs a weighted sum of them.
00045  *
00046  * If the input vector's
00047  * size isn't a multiple of the output vector's size,
00048  * that is, if \f$n\f$ can't be written as \f$km\f$, then the last vector slice
00049  * will consider only the remaining terms, e.g.
00050  * if \f$x=[x_0, \ldots, x_5]^T\f$ and \f$y\f$ is of size
00051  * \f$4 \times 1\f$ then
00052  *
00053  * \f[ y = \left [ \begin{array}{c}
00054  *                     \alpha_0 x_0 + \alpha_1 x_4 \\
00055  *                     \alpha_0 x_1 + \alpha_1 x_5 \\
00056  *                     \alpha_0 x_2 \\
00057  *                     \alpha_0 x_3 \\
00058  *         \end{array} \right ]
00059  * \f]
00060  *
00061  * Schematically, this idea can be depicted as
00062  *
00063  * <img src="images/gnn_gcomm1.png">
00064  *
00065  * The function's gradients are:
00066  * \f[ \frac{\partial E}{\partial x_i}
00067  *     = \frac{\partial E}{\partial x_{km+j}}
00068  *     = \alpha_k \frac{\partial E}{\partial y_j}
00069  * \f]
00070  * and for the \f$w_k\f$:
00071  * \f[ \frac{\partial E}{\partial w_k}
00072  *     = \sum_j \frac{\partial E}{\partial y_j}
00073  *              \sum_{k'} \frac{\partial \alpha_{k'}}{\partial w_k} x_{k'm+j}
00074  * \f]
00075  * and
00076  * \f[ \frac{\partial \alpha_{k'}}{\partial w_k}
00077  *     = \left \{ \begin{array}{ccl}
00078  *          \frac{2w_k \sum_i w_i^2 - w_k^2 2w_k}
00079  *               { \left ( \sum_i w_i^2 \right )^2 } & , & k = k' \\
00080  *         -\frac{w_{k'}^2 2w_k}
00081  *               { \left ( \sum_i w_i^2 \right )^2 } & , & k \neq k' \\
00082  *       \end{array} \right \}
00083  *     = 2 w_k \left ( \delta^{k'}_k - \frac{\alpha_{k'}}{\Sigma} \right )
00084  * \f]
00085  * where \f$\Sigma = \sum_i w_i^2 \f$.
00086  */
00087 
00088 
00089 /******************************************/
00090 /* Include Files                          */
00091 /******************************************/
00092 
00093 #include <gsl/gsl_blas.h>
00094 #include "gnn_gcomm.h"
00095 
00096 
00097 
00098 /******************************************/
00099 /* Static Declaration                     */
00100 /******************************************/
00101 
00102 static int
00103 gnn_gcomm_f (gnn_node *node,
00104              const gsl_vector *x,
00105              const gsl_vector *w,
00106              gsl_vector *y);
00107 
00108 static int
00109 gnn_gcomm_dx (gnn_node *node,
00110               const gsl_vector *x,
00111               const gsl_vector *w,
00112               const gsl_vector *dy,
00113               gsl_vector *dx);
00114 
00115 static int
00116 gnn_gcomm_dw (gnn_node *node,
00117               const gsl_vector *x,
00118               const gsl_vector *w,
00119               const gsl_vector *dy,
00120               gsl_vector *dw);
00121 
00122 static void
00123 gnn_gcomm_destroy (gnn_node *node);
00124 
00125 
00126 
00127 /******************************************/
00128 /* Static Implementation                  */
00129 /******************************************/
00130 
00131 /**
00132  * @brief Computes the output.
00133  * @ingroup gnn_gcomm_doc
00134  *
00135  * @param   node A pointer to the \ref gnn_gcomm node.
00136  * @param x The input vector \f$x\f$.
00137  * @param w The parameter vector \f$w\f$.
00138  * @param y The output buffer vector \f$y\f$.
00139  * @return Returns 0 on success.
00140  */
00141 static int
00142 gnn_gcomm_f (gnn_node *node,
00143              const gsl_vector *x,
00144              const gsl_vector *w,
00145              gsl_vector *y)
00146 {
00147     size_t k;
00148     gnn_gcomm *gnode;
00149 
00150     /* get views */
00151     gnode = (gnn_gcomm *) node;
00152 
00153     /* copy input */
00154     gsl_vector_memcpy (gnode->x, x);
00155 
00156     /* evaluate */
00157     gnode->sumw = gsl_blas_dnrm2 (w);
00158     for (k=0; k<gnode->rep; ++k)
00159     {
00160         double wk;
00161         double alphak;
00162         
00163         /* compute w_k^2 */
00164         wk = gsl_vector_get (w, k);
00165         wk = wk * wk;
00166         
00167         /* compute alpha_k*/
00168         alphak = wk / gnode->sumw;
00169         gsl_vector_set (gnode->alpha, k, alphak);
00170         gsl_blas_daxpy (alphak, gnode->X[k], y);
00171     }
00172 
00173     return 0;
00174 }
00175 
00176 /**
00177  * @brief Computes \f$ \frac{\partial E}{\partial x} \f$.
00178  * @ingroup gnn_gcomm_doc
00179  *
00180  * @param    node A pointer to the \ref gnn_gcomm node.
00181  * @param x  The input vector \f$x\f$.
00182  * @param w  The parameter vector \f$w\f$.
00183  * @param dy The vector \f$\frac{\partial E}{\partial y}\f$.
00184  * @param dx The output buffer vector \f$\frac{\partial E}{\partial x}\f$.
00185  * @return Returns 0 on success.
00186  */
00187 static int
00188 gnn_gcomm_dx (gnn_node *node,
00189               const gsl_vector *x,
00190               const gsl_vector *w,
00191               const gsl_vector *dy,
00192               gsl_vector *dx)
00193 {
00194     size_t k;
00195     gnn_gcomm *gnode;
00196 
00197     /* get views */
00198     gnode = (gnn_gcomm *) node;
00199 
00200     /* evaluate */
00201     for (k=0; k<gnode->rep; ++k)
00202     {
00203         double alphak;
00204         
00205         alphak = gsl_vector_get (gnode->alpha, k);
00206         
00207         gsl_vector_memcpy (gnode->X[k], dy);
00208         gsl_vector_scale (gnode->X[k], alphak);
00209     }
00210 
00211     /* copy buffer to dx */
00212     gsl_vector_memcpy (dx, gnode->x);
00213 
00214     return 0;
00215 }
00216 
00217 /**
00218  * @brief Computes \f$ \frac{\partial E}{\partial w} \f$.
00219  * @ingroup gnn_gcomm_doc
00220  *
00221  * @param    node A pointer to the \ref gnn_gcomm node.
00222  * @param x  The input vector \f$x\f$.
00223  * @param w  The parameter vector \f$w\f$.
00224  * @param dy The vector \f$\frac{\partial E}{\partial y}\f$.
00225  * @param dx The output buffer vector \f$\frac{\partial E}{\partial w}\f$.
00226  * @return Returns 0 on success.
00227  */
00228 static int
00229 gnn_gcomm_dw (gnn_node *node,
00230               const gsl_vector *x,
00231               const gsl_vector *w,
00232               const gsl_vector *dy,
00233               gsl_vector *dw)
00234 {
00235     size_t k;
00236     size_t j;
00237     size_t kp;
00238     gnn_gcomm *gnode;
00239 
00240     /* get views */
00241     gnode = (gnn_gcomm *) node;
00242 
00243     /* copy input vector into sliced buffers */
00244     gsl_vector_set_zero (gnode->x);
00245     gsl_vector_memcpy (gnode->x, x);
00246 
00247     /* evaluate */
00248     for (k=0; k<dw->size; ++k)
00249     {
00250         double dwk;
00251         double wk;
00252         double Sj;
00253         
00254         wk  = gsl_vector_get (w, k);
00255         dwk = gsl_vector_get (dw, k);
00256         Sj  = 0.0;
00257         
00258         for (j=0; j<dy->size; ++j)
00259         {
00260             double dyj;
00261             double Skp;
00262 
00263             Skp = 0.0;
00264             dyj = gsl_vector_get (dy, j);
00265             
00266             for (kp=0; kp<w->size; ++kp)
00267             {
00268                 size_t i;
00269                 double alphakp;
00270                 double dalphakp;
00271                 double xi;
00272                 
00273                 i = kp * dy->size + j;
00274                 xi = gsl_vector_get (gnode->x, i);
00275                 
00276                 alphakp  = gsl_vector_get (gnode->alpha, kp);
00277                 dalphakp = (k == kp)? 1.0 - alphakp / gnode->sumw
00278                                     :     - alphakp / gnode->sumw;
00279 
00280                 Skp += dalphakp * xi;
00281             }
00282 
00283             Sj += dyj * 2 * wk * Skp;
00284         }
00285         
00286         dwk += Sj;
00287         gsl_vector_set (dw, k, Sj);
00288     }
00289 
00290     return 0;
00291 }
00292 
00293 /**
00294  * @brief Computes the output.
00295  * @ingroup gnn_gcomm_doc
00296  *
00297  * @param node A pointer to the \ref gnn_gcomm node.
00298  */
00299 static void
00300 gnn_gcomm_destroy (gnn_node *node)
00301 {
00302     gnn_gcomm *gnode;
00303 
00304     gnode = (gnn_gcomm *) node;
00305 
00306     if (gnode->alpha != NULL)
00307         gsl_vector_free (gnode->alpha);
00308     if (gnode->xbuf != NULL)
00309         gsl_vector_free (gnode->xbuf);
00310     if (gnode->X_view != NULL)
00311         free (gnode->X_view);
00312     if (gnode->X != NULL)
00313         free (gnode->X);
00314 }
00315 
00316 
00317 
00318 /******************************************/
00319 /* Public Interface                       */
00320 /******************************************/
00321 
00322 /**
00323  * @brief Creates an generalized committee node.
00324  * @ingroup gnn_gcomm_doc
00325  *
00326  * This function creates a node of the \ref gnn_gcomm type. The coefficients
00327  * are all initialized at the same value. This is equivalent to set the
00328  * \f$a_k\f$ all to \f$\frac{1}{m}\f$.
00329  *
00330  * @param input_size  The input size \f$n\f$.
00331  * @param output_size The output size \f$m\f$.
00332  * @return A pointer to a new \ref gnn_gcomm node.
00333  */
00334 gnn_node *
00335 gnn_gcomm_new (size_t input_size, size_t output_size)
00336 {
00337     int status;
00338     size_t k;
00339     gsl_vector *w;
00340     gnn_node *node;
00341     gnn_gcomm *gnode;
00342     size_t param_size;
00343 
00344     /* check sizes */
00345     if (output_size < 1)
00346     {
00347         GSL_ERROR_VAL ("output size should be strictly positive",
00348                        GSL_EINVAL, NULL);
00349     }
00350     if (input_size < output_size)
00351     {
00352         GSL_ERROR_VAL ("input size should be greater than the output size",
00353                        GSL_EINVAL, NULL);
00354     }
00355 
00356     /* allocate the node */
00357     gnode = (gnn_gcomm *) malloc (sizeof (gnn_gcomm));
00358     if (gnode == NULL)
00359     {
00360         GSL_ERROR_VAL ("could not allocate memory for gnn_gcomm node",
00361                        GSL_ENOMEM, NULL);
00362     }
00363 
00364     /* get view as a gnn_node */
00365     node = (gnn_node *) gnode;
00366 
00367     /* Initialize the node */
00368     status = gnn_node_init (node,
00369                             "gnn_gcomm",
00370                             gnn_gcomm_f,
00371                             gnn_gcomm_dx,
00372                             gnn_gcomm_dw,
00373                             gnn_gcomm_destroy);
00374     if (status)
00375     {
00376         GSL_ERROR_VAL ("could not initialize gnn_gcomm node",
00377                        GSL_EFAILED, NULL);
00378     }
00379 
00380     /* compute amount of replications */
00381     gnode->rep = (input_size-1) / output_size + 1;
00382     
00383     /* set sizes */
00384     param_size = gnode->rep;
00385     status = gnn_node_set_sizes (node, input_size, output_size, param_size);
00386     if (status)
00387     {
00388         GSL_ERROR_VAL ("could not set sizes for gnn_gcomm node",
00389                        GSL_EFAILED, NULL);
00390     }
00391 
00392     /* create alpha buffer */
00393     gnode->alpha = gsl_vector_calloc (param_size);
00394     
00395     /* create full input vector buffer and its view */
00396     gnode->xbuf  = gsl_vector_calloc (gnode->rep * output_size);
00397 
00398     gnode->X_view =
00399         (gsl_vector_view *) malloc (sizeof (gsl_vector_view) * gnode->rep);
00400 
00401     gnode->X =
00402         (gsl_vector **) malloc (sizeof (gsl_vector *) * gnode->rep);
00403 
00404     if (gnode->xbuf == NULL || gnode->X_view == NULL || gnode->X == NULL)
00405     {
00406         gnn_node_destroy (node);
00407         GSL_ERROR_VAL ("could not allocate buffers for gnn_gcomm node",
00408                        GSL_ENOMEM, NULL);
00409     }
00410 
00411     /* create input vector slices : views and pointers */
00412     gnode->x_view = gsl_vector_subvector (gnode->xbuf, 0, input_size);
00413     gnode->x      = &(gnode->x_view.vector);
00414 
00415     for (k=0; k<gnode->rep; ++k)
00416     {
00417         gnode->X_view[k] =
00418             gsl_vector_subvector (gnode->xbuf, k * output_size, output_size);
00419         gnode->X[k] = &(gnode->X_view[k].vector);
00420 
00421     }
00422 
00423     /* set initial parameter vector */
00424     gsl_vector_set_all (gnode->alpha, 1.0);
00425     gnn_node_param_set (node, gnode->alpha);
00426 
00427     return node;
00428 }
00429 
00430 

Generated on Sun Jun 13 20:50:11 2004 for libgnn Gradient Retropropagation Machine Library by doxygen1.2.18