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

gnn_parallel.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  *  @file gnn_parallel.h
00003  *  @brief Parallel Layer.
00004  *
00005  *  @date   : 10-08-03 18:59, 22-08-03 00:19
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_parallel_doc gnn_parallel : Parallel Node Constructor.
00027  * @ingroup gnn_constructor_doc
00028  *
00029  * @todo Optimize this node type
00030  *
00031  * gnn_parallel is a constructor node for implementing parallel computing
00032  * schemes. Given the \f$N\f$ functions \f$g_1, \ldots, g_N\f$ with
00033  * input sizes \f$n_1, \ldots, n_N\f$ and output sizes \f$ m_1, \ldots, m_N \f$,
00034  * it computes the function
00035  * \f$ F: \mathbf{R}^{(n_1 + \cdots + n_N)}
00036  *       \rightarrow \mathbf{R}^{(m_1 + \cdots + m_N)}\f$ given by
00037  * \f[
00038  *     F(X) = [g_1(X_1) g_2(X_2) \ldots g_N(X_N)]
00039  *          = [Y_1 Y_2 \ldots Y_N]
00040  * \f]
00041  * where \f$ \forall i=1,\ldots,N, Y_i = g(X_i) \f$, in this order.
00042  */
00043 
00044 
00045 /******************************************/
00046 /* Include Files                          */
00047 /******************************************/
00048 
00049 #include "gnn_parallel.h"
00050 #include <assert.h>
00051 
00052 
00053 
00054 /******************************************/
00055 /* Static Declaration                     */
00056 /******************************************/
00057 
00058 static int
00059 gnn_parallel_f (gnn_node *node,
00060                 const gsl_vector *x,
00061                 const gsl_vector *w,
00062                 gsl_vector *y);
00063 
00064 static int
00065 gnn_parallel_dx (gnn_node *node,
00066                  const gsl_vector *x,
00067                  const gsl_vector *w,
00068                  const gsl_vector *dy,
00069                  gsl_vector *dx);
00070 
00071 static int
00072 gnn_parallel_dw (gnn_node *node,
00073                  const gsl_vector *x,
00074                  const gsl_vector *w,
00075                  const gsl_vector *dy,
00076                  gsl_vector *dw);
00077 
00078 static void
00079 gnn_parallel_destroy (gnn_node *node);
00080 
00081 
00082 
00083 /******************************************/
00084 /* Static Implementation                  */
00085 /******************************************/
00086 
00087 /**
00088  * @brief Computes the output.
00089  * @ingroup gnn_parallel_doc
00090  *
00091  * This functions computes the parallel function.
00092  *
00093  * @param  node A pointer to a \ref gnn_parallel node.
00094  * @param x    The input vector \f$x\f$.
00095  * @param w    The current parameter vector \f$w\f$.
00096  * @param y    An output vector \f$y\f$ where the result should be stored.
00097  * @return 0 if succeeded.
00098  */
00099 static int
00100 gnn_parallel_f (gnn_node *node,
00101                 const gsl_vector *x,
00102                 const gsl_vector *w,
00103                 gsl_vector *y)
00104 {
00105     gnn_parallel *pnode;
00106     int size;
00107     int i;
00108 
00109     /* get view as parallel node */
00110     pnode = (gnn_parallel *) node;
00111 
00112     /* retrieve size */
00113     size = gnn_node_sub_get_number (node);
00114 
00115     /* foreach of the subnodes, compute output */
00116     for (i=0; i<size; ++i)
00117     {
00118         int in_offset;
00119         int in_length;
00120         int out_offset;
00121         int out_length;
00122         gsl_vector_view sx;
00123         gsl_vector_view sy;
00124         gnn_node *snode;
00125 
00126         /* get subnode */
00127         snode = gnn_node_sub_get_node_at (node, i);
00128 
00129         /* get offsets and lengths */
00130         in_offset  = pnode->in_off[i];
00131         in_length  = pnode->in_size[i];
00132         out_offset = pnode->out_off[i];
00133         out_length = pnode->out_size[i];
00134 
00135         /* get the corresponding views */
00136         sx = gsl_vector_subvector ((gsl_vector *) x, in_offset, in_length);
00137         sy = gsl_vector_subvector (y, out_offset, out_length);
00138         
00139         /* evaluate subnode */
00140         gnn_node_eval_f (snode, &(sx.vector), &(sy.vector));
00141     }
00142 
00143     return 0;
00144 }
00145 
00146 
00147 /**
00148  * @brief Computes \f$ \frac{\partial E}{\partial x} \f$.
00149  * @ingroup gnn_parallel_doc
00150  *
00151  * This functions computes the input gradient of the parallel node.
00152  * Given \f$ \frac{\partial E}{\partial y} =
00153  * [ \frac{\partial E}{\partial y_1}
00154  *   \frac{\partial E}{\partial y_2} \ldots
00155  *   \frac{\partial E}{\partial y_N} ] \f$
00156  * it computes
00157  * \f[ \frac{\partial E}{\partial x} =
00158  *     [ \frac{\partial E}{\partial x_1}
00159  *       \frac{\partial E}{\partial x_2} \ldots
00160  *       \frac{\partial E}{\partial x_N} ]
00161  * \f]
00162  * where \f$ \forall i=1,\ldots,N;  \frac{\partial E}{\partial x_i} \f$ is
00163  * the gradient with respect of its inputs of the \f$i\f$-th function
00164  * \f$ g_i \f$.
00165  *
00166  * @param  node A pointer to a \ref gnn_parallel node.
00167  * @param x    The input vector \f$x\f$.
00168  * @param w    The current parameter vector \f$w\f$.
00169  * @param dy   The error-backpropagation vector
00170  *             \f$\frac{\partial E}{\partial y}\f$
00171  * @param dx   An output vector where the result
00172  *             \f$\frac{\partial E}{\partial x}\f$ should be stored.
00173  * @return 0 if suceeded.
00174  */
00175 static int
00176 gnn_parallel_dx (gnn_node *node,
00177                  const gsl_vector *x,
00178                  const gsl_vector *w,
00179                  const gsl_vector *dy,
00180                  gsl_vector *dx)
00181 {
00182     gnn_parallel *pnode;
00183     int size;
00184     int i;
00185 
00186     /* get view as parallel node */
00187     pnode = (gnn_parallel *) node;
00188 
00189     /* retrieve size */
00190     size = gnn_node_sub_get_number (node);
00191 
00192     /* foreach of the subnodes, compute input gradient */
00193     for (i=0; i<size; ++i)
00194     {
00195         int in_offset;
00196         int in_length;
00197         int out_offset;
00198         int out_length;
00199         gsl_vector_view sdx;
00200         gsl_vector_view sdy;
00201         gnn_node *snode;
00202 
00203         /* get subnode */
00204         snode = gnn_node_sub_get_node_at (node, i);
00205 
00206         /* get offsets and lengths */
00207         in_offset  = pnode->in_off[i];
00208         in_length  = pnode->in_size[i];
00209         out_offset = pnode->out_off[i];
00210         out_length = pnode->out_size[i];
00211 
00212         /* get the corresponding views */
00213         sdy = gsl_vector_subvector ((gsl_vector *) dy, out_offset, out_length);
00214         sdx = gsl_vector_subvector (dx, in_offset, in_length);
00215 
00216         /* evaluate subnode */
00217         gnn_node_eval_dx (snode, &(sdy.vector), &(sdx.vector));
00218     }
00219 
00220     return 0;
00221 }
00222 
00223 /**
00224  * @brief Computes \f$ \frac{\partial E}{\partial w} \f$.
00225  * @ingroup gnn_parallel_doc
00226  *
00227  * This functions computes the parameter gradient of the parallel node.
00228  * Given \f$ \frac{\partial E}{\partial y} =
00229  * [ \frac{\partial E}{\partial y_1}
00230  *   \frac{\partial E}{\partial y_2} \ldots
00231  *   \frac{\partial E}{\partial y_N} ] \f$
00232  * it computes
00233  * \f[ \frac{\partial E}{\partial w} =
00234  *     [ \frac{\partial E}{\partial w_1}
00235  *       \frac{\partial E}{\partial w_2} \ldots
00236  *       \frac{\partial E}{\partial w_N} ]
00237  * \f]
00238  * where \f$ \forall i=1,\ldots,N;  \frac{\partial E}{\partial w_i} \f$ is
00239  * the gradient with respect of its parameters of the \f$i\f$-th function
00240  * \f$ g_i \f$.
00241  *
00242  * @param node A pointer to a \ref gnn_parallel node.
00243  * @param x    The input vector \f$x\f$.
00244  * @param w    The current parameter vector \f$w\f$.
00245  * @param dy   The error-backpropagation vector
00246  *             \f$\frac{\partial E}{\partial y}\f$
00247  * @param dw   Not used, since the stack hasn't any local parameters.
00248  * @return 0 if succeeded.
00249  */
00250 static int
00251 gnn_parallel_dw (gnn_node *node,
00252                  const gsl_vector *x,
00253                  const gsl_vector *w,
00254                  const gsl_vector *dy,
00255                  gsl_vector *dw)
00256 {
00257     int size;
00258     int i;
00259 
00260     /* retrieve size */
00261     size = gnn_node_sub_get_number (node);
00262 
00263     /* foreach of the subnodes, compute dw */
00264     for (i=0; i<size; ++i)
00265     {
00266         gnn_node *snode;
00267 
00268         /* get sublayer */
00269         snode = gnn_node_sub_get_node_at (node, i);
00270 
00271         /* evaluate sublayer and copy result */
00272         gnn_node_eval_dw (snode);
00273     }
00274 
00275     return 0;
00276 }
00277 
00278 /**
00279  * @brief Frees the \ref gnn_parallel specific data.
00280  * @ingroup gnn_parallel_doc
00281  *
00282  * This function (the \ref gnn_parallel destructor) frees the 4 auxiliary
00283  * arrays allocated for the \ref gnn_parallel node.
00284  *
00285  * @param  node A pointer to a \ref gnn_parallel node.
00286  */
00287 static void
00288 gnn_parallel_destroy (gnn_node *node)
00289 {
00290     gnn_parallel *pnode;
00291     
00292     assert (node != NULL);
00293     
00294     /* get view as parallel node */
00295     pnode = (gnn_parallel *) node;
00296     
00297     /* free the info arrays if any */
00298     if (pnode->in_off   != NULL)
00299         free (pnode->in_off);
00300     if (pnode->in_size  != NULL)
00301         free (pnode->in_size);
00302     if (pnode->out_off  != NULL)
00303         free (pnode->out_off);
00304     if (pnode->out_size != NULL)
00305         free (pnode->out_size);
00306 }
00307 
00308 
00309 
00310 
00311 /******************************************/
00312 /* Public Interface                       */
00313 /******************************************/
00314 
00315 /**
00316  * @brief Creates a \ref gnn_parallel node.
00317  * @ingroup gnn_parallel_doc
00318  *
00319  * This function creates a node of the \ref gnn_parallel type. Its inputs
00320  * and outputs are the concatenation of its subnode's inputs and outputs.
00321  *
00322  * Example:
00323  * \code
00324  * gnn_node *parallel, *node1, *node2, *node3;
00325  *
00326  * // build the node 1 to 3
00327  * ...
00328  *
00329  * // build the parallel node
00330  * parallel = gnn_parallel_new (3, node1, node2, node3);
00331  * \endcode
00332  *
00333  * @param size The number of subnodes.
00334  * @param ...  A list of pointers to the subnodes.
00335  * @return A pointer to a new \ref gnn_parallel node.
00336  */
00337 gnn_node *
00338 gnn_parallel_new (size_t size, ...)
00339 {
00340     size_t  i;
00341     va_list args;
00342     gnn_node        *p;
00343     gnn_node_vector *v;
00344     
00345     assert (size > 0);
00346     
00347     /* create node vector */
00348     v = gnn_node_vector_new (size);
00349     if (v == NULL)
00350     {
00351         GSL_ERROR_VAL ("couldn't allocate node vector for parallel node",
00352                        GSL_ENOMEM, NULL);
00353     }
00354 
00355     /* prepare node array */
00356     va_start (args, size);
00357     for (i=0; i<size; ++i)
00358     {
00359         gnn_node *n;
00360         n = (gnn_node *) va_arg (args, gnn_node *);
00361         gnn_node_vector_set (v, i, n);
00362     }
00363     va_end (args);
00364 
00365     /* call parallel node builder */
00366     p = gnn_parallel_new_with_node_vector (v);
00367 
00368     /* free vector */
00369     gnn_node_vector_free (v);
00370     
00371     return p;
00372 }
00373 
00374 /**
00375  * @brief Creates a \ref gnn_parallel node with a given node vector.
00376  * @ingroup gnn_parallel_doc
00377  *
00378  * This function creates a node of the \ref gnn_parallel type. Its inputs
00379  * and outputs are the concatenation of its subnode's inputs and outputs.
00380  *
00381  * Example:
00382  * \code
00383  * gnn_node *parallel;
00384  * gnn_node_vector *vector;
00385  *
00386  * // build the node vector
00387  * vector = gnn_node_vector_new (3);
00388  *
00389  * // build the nodes vector[0], vector[1] and vector[2]
00390  * ...
00391  *
00392  * // build the stack
00393  * parallel = gnn_parallel_new_with_node_vector (vector);
00394  * \endcode
00395  *
00396  * @param v A pointer to a \ref gnn_node_vector.
00397  * @return A pointer to a new \ref gnn_parallel node.
00398  */
00399 gnn_node *
00400 gnn_parallel_new_with_node_vector (gnn_node_vector *v)
00401 {
00402     int i;
00403     int status;
00404     size_t size;
00405     size_t input_size;
00406     size_t output_size;
00407     gnn_node     *node;
00408     gnn_parallel *pnode;
00409 
00410     assert (v != NULL);
00411 
00412     /* get size */
00413     size = gnn_node_vector_count_nodes (v);
00414 
00415     /* allocate parallel node */
00416     node = (gnn_node *) malloc (sizeof (gnn_parallel));
00417     if (node == NULL)
00418     {
00419         GSL_ERROR_VAL ("could not allocate memory for gnn_parallel",
00420                        GSL_ENOMEM, NULL);
00421     }
00422 
00423     /* initialize parallel node */
00424     status = gnn_node_init (node,
00425                             "gnn_parallel",
00426                             gnn_parallel_f,
00427                             gnn_parallel_dx,
00428                             gnn_parallel_dw,
00429                             gnn_parallel_destroy);
00430     if (status)
00431     {
00432         free (node);
00433         GSL_ERROR_VAL ("could not initialize gnn_parallel node",
00434                        GSL_EFAILED, NULL);
00435     }
00436 
00437     /* store layers */
00438     status = gnn_node_sub_install_node_vector (node, v);
00439     if (status)
00440     {
00441         gnn_node_destroy (node);
00442         GSL_ERROR_VAL ("couldn't install subnodes for gnn_parallel",
00443                        GSL_EINVAL, NULL);
00444     }
00445 
00446     /* get view as a parallel node */
00447     pnode = (gnn_parallel *) node;
00448 
00449     /* alloc arrays for holding subnode's info */
00450     pnode->in_off   = (size_t *) malloc (sizeof (size_t) * size);
00451     pnode->in_size  = (size_t *) malloc (sizeof (size_t) * size);
00452     pnode->out_off  = (size_t *) malloc (sizeof (size_t) * size);
00453     pnode->out_size = (size_t *) malloc (sizeof (size_t) * size);
00454 
00455     if (   pnode->in_off   == NULL
00456         || pnode->in_size  == NULL
00457         || pnode->out_off  == NULL
00458         || pnode->out_size == NULL )
00459     {
00460         gnn_node_destroy (node);
00461         GSL_ERROR_VAL ("could not allocate memory for gnn_parallel info arrays",
00462                        GSL_ENOMEM, NULL);
00463     }
00464 
00465     /* compute input and output size and build info arrays */
00466     input_size    = 0;
00467     output_size   = 0;
00468     for (i=0; i<size; ++i)
00469     {
00470         size_t inlen;
00471         size_t outlen;
00472 
00473         gnn_node *subnode;
00474 
00475         subnode = gnn_node_sub_get_node_at (node, i);
00476 
00477         inlen  = gnn_node_input_get_size (subnode);
00478         outlen = gnn_node_output_get_size (subnode);
00479 
00480         pnode->in_off[i]   = input_size;
00481         pnode->in_size[i]  = inlen;
00482         pnode->out_off[i]  = output_size;
00483         pnode->out_size[i] = outlen;
00484 
00485         input_size  += inlen;
00486         output_size += outlen;
00487     }
00488 
00489     /* resize the parallel node's input and output */
00490     gnn_node_set_sizes (node, input_size, output_size, 0);
00491 
00492     return node;
00493 }
00494 
00495 
00496 /**
00497  * @brief Gets the offset of the i-th subnode's input.
00498  * @ingroup gnn_parallel_doc
00499  *
00500  * @param  node A pointer to a \ref gnn_parallel node.
00501  * @param  i    The index.
00502  * @return The offset.
00503  */
00504 int
00505 gnn_parallel_get_input_offset (gnn_node *node, int i)
00506 {
00507     int sub_size;
00508     gnn_parallel *pnode;
00509 
00510     pnode    = (gnn_parallel *) node;
00511     sub_size = gnn_node_sub_get_number (node);
00512     if ( (0 <= i) && (i < sub_size) )
00513         return pnode->in_off[i];
00514     else
00515         GSL_ERROR ("index of parallel layer out of bounds", GSL_EINVAL);
00516 }
00517 
00518 /**
00519  * @brief Gets the length of the i-th subnode's input.
00520  * @ingroup gnn_parallel_doc
00521  *
00522  * @param  node A pointer to a \ref gnn_parallel node.
00523  * @param  i    The index.
00524  * @return The length.
00525  */
00526 int
00527 gnn_parallel_get_input_length (gnn_node *node, int i)
00528 {
00529     int sub_size;
00530     gnn_parallel *pnode;
00531 
00532     pnode    = (gnn_parallel *) node;
00533     sub_size = gnn_node_sub_get_number (node);
00534     if ( (0 <= i) && (i < sub_size) )
00535         return pnode->in_size[i];
00536     else
00537         GSL_ERROR ("index of parallel layer out of bounds", GSL_EINVAL);
00538 }
00539 
00540 /**
00541  * @brief Gets the offset of the i-th subnode's output.
00542  * @ingroup gnn_parallel_doc
00543  *
00544  * @param  node A pointer to a \ref gnn_parallel node.
00545  * @param  i    The index.
00546  * @return The offset.
00547  */
00548 int
00549 gnn_parallel_get_output_offset (gnn_node *node, int i)
00550 {
00551     int sub_size;
00552     gnn_parallel *pnode;
00553 
00554     pnode    = (gnn_parallel *) node;
00555     sub_size = gnn_node_sub_get_number (node);
00556     if ( (0 <= i) && (i < sub_size) )
00557         return pnode->out_off[i];
00558     else
00559         GSL_ERROR ("index of parallel layer out of bounds", GSL_EINVAL);
00560 }
00561 
00562 /**
00563  * @brief Gets the length of the i-th subnode's output.
00564  * @ingroup gnn_parallel_doc
00565  *
00566  * @param  node A pointer to a \ref gnn_parallel node.
00567  * @param  i    The index.
00568  * @return The offset.
00569  */
00570 int
00571 gnn_parallel_get_output_length (gnn_node *node, int i)
00572 {
00573     int sub_size;
00574     gnn_parallel *pnode;
00575 
00576     pnode    = (gnn_parallel *) node;
00577     sub_size = gnn_node_sub_get_number (node);
00578     if ( (0 <= i) && (i < sub_size) )
00579         return pnode->out_size[i];
00580     else
00581         GSL_ERROR ("index of parallel layer out of bounds", GSL_EINVAL);
00582 }
00583 
00584 
00585 

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