00001 /*************************************************************************** 00002 * @file gnn_logistic.c 00003 * @brief Logistic Sigmoid transfer function. 00004 * 00005 * @date : 10-08-03 01: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 00027 /** 00028 * @defgroup gnn_logistic_doc gnn_logistic : Logistic Sigmoid Activation Function. 00029 * @ingroup gnn_atomic_doc 00030 * 00031 * The \ref gnn_logistic datatype implements a node that computes the function: 00032 * \f[ y_i = a \frac{1}{1 + \exp(-bx)} \f] 00033 * where \f$i = 1,\ldots,n\f$. 00034 * 00035 * This function is a member of the more general class of sigmoid functions, 00036 * which have the property to "squash" its inputs to a very restricted output 00037 * interval. 00038 * 00039 * The Logistic Sigmoid is assymmetric and its outputs lie between \f$[0,a]\f$. 00040 * It has been said that it leads to slower convergence in training than the 00041 * Hyperbolic Tangent. 00042 */ 00043 00044 00045 00046 /******************************************/ 00047 /* Include Files */ 00048 /******************************************/ 00049 00050 #include "gnn_logistic.h" 00051 #include <math.h> 00052 00053 00054 00055 /******************************************/ 00056 /* Macros and Definitions */ 00057 /******************************************/ 00058 00059 #define GNN_LOGISTIC_A(node) (((gnn_logistic *)(node))->a) 00060 #define GNN_LOGISTIC_B(node) (((gnn_logistic *)(node))->b) 00061 00062 00063 00064 /******************************************/ 00065 /* Static Declaration */ 00066 /******************************************/ 00067 00068 typedef struct _gnn_logistic 00069 { 00070 gnn_node node; 00071 double a; 00072 double b; 00073 } gnn_logistic; 00074 00075 static int 00076 gnn_logistic_f (gnn_node *node, 00077 const gsl_vector *x, 00078 const gsl_vector *w, 00079 gsl_vector *y); 00080 00081 static int 00082 gnn_logistic_dx (gnn_node *node, 00083 const gsl_vector *x, 00084 const gsl_vector *w, 00085 const gsl_vector *dy, 00086 gsl_vector *dx); 00087 00088 00089 00090 /******************************************/ 00091 /* Static Implementation */ 00092 /******************************************/ 00093 00094 /** 00095 * @brief Computes the output. 00096 * @ingroup gnn_logistic_doc 00097 * 00098 * This functions evaluates the logistic sigmoid function. 00099 * 00100 * @param node A pointer to a \ref gnn_logistic node. 00101 * @param x The input vector \f$x\f$. 00102 * @param w The parameter vector \f$w\f$ (which is empty in this case). 00103 * @param y The output buffer vector \f$y\f$. 00104 * @return Returns 0 on success. 00105 */ 00106 static int 00107 gnn_logistic_f (gnn_node *node, 00108 const gsl_vector *x, 00109 const gsl_vector *w, 00110 gsl_vector *y) 00111 { 00112 size_t i; 00113 size_t size; 00114 double a; 00115 double b; 00116 00117 /* get the size */ 00118 size = gnn_node_input_get_size (node); 00119 00120 /* get the parameters */ 00121 a = GNN_LOGISTIC_A (node); 00122 b = GNN_LOGISTIC_B (node); 00123 00124 /* evaluate */ 00125 for (i=0; i<size; ++i) 00126 { 00127 double xi; 00128 double yi; 00129 00130 xi = gsl_vector_get (x, i); 00131 yi = a * 1 / (1 + exp (- b * xi)); 00132 gsl_vector_set (y, i, yi); 00133 } 00134 00135 return 0; 00136 } 00137 00138 /** 00139 * @brief Computes \f$ \frac{\partial E}{\partial X} \f$. 00140 * @ingroup gnn_logistic_doc 00141 * 00142 * This functions computes the gradient of the logistic sigmoid function, 00143 * given dedy (\f$ \frac{\partial E}{\partial Y} \f$). The function is, 00144 * \f[ \frac{\partial E}{\partial x_i} 00145 * = ab \frac{ x_i e^{-bx_i} }{ \left ( 1 + e^{-bx_i} \right )^2 } 00146 * \frac{\partial E}{\partial y_i} 00147 * = b y_i \left ( 1 - \frac{y_i}{a} \right ) 00148 * \frac{\partial E}{\partial y_i} 00149 * \f] 00150 * 00151 * @param node A pointer to a \ref gnn_logistic node. 00152 * @param x The input vector \f$x\f$. 00153 * @param w The parameter vector \f$w\f$ (which is empty in this case). 00154 * @param dy The vector \f$\frac{\partial E}{\partial y}\f$. 00155 * @param dx The output buffer vector \f$\frac{\partial E}{\partial x}\f$. 00156 * @return Returns 0 on success. 00157 */ 00158 static int 00159 gnn_logistic_dx (gnn_node *node, 00160 const gsl_vector *x, 00161 const gsl_vector *w, 00162 const gsl_vector *dy, 00163 gsl_vector *dx) 00164 { 00165 size_t i; 00166 size_t size; 00167 double a; 00168 double b; 00169 00170 /* get the size */ 00171 size = gnn_node_input_get_size (node); 00172 00173 /* get the parameters */ 00174 a = GNN_LOGISTIC_A (node); 00175 b = GNN_LOGISTIC_B (node); 00176 00177 /* evaluate */ 00178 for (i=0; i<size; ++i) 00179 { 00180 double xi; 00181 double yi; 00182 double dxi; 00183 double dyi; 00184 00185 xi = gsl_vector_get (x, i); 00186 yi = a * 1 / (1 + exp (- b * xi)); 00187 dyi = gsl_vector_get (dy, i); 00188 dxi = b * yi * (1.0 - yi / a) * dyi; 00189 00190 gsl_vector_set (dx, i, dxi); 00191 } 00192 00193 return 0; 00194 } 00195 00196 00197 /******************************************/ 00198 /* Public Interface */ 00199 /******************************************/ 00200 00201 /** 00202 * @brief Creates a Logistic Sigmoid activation function node. 00203 * @ingroup gnn_logistic_doc 00204 * 00205 * This function creates a node of the \ref gnn_logistic type. This node 00206 * computes 00207 * \f[ y_i = a \frac{ 1 }{ 1 + e^{-b x_i} } \f] 00208 * where \f$i = 1, \ldots, n\f$, \f$a\f$ and \f$b\f$ constants. 00209 * 00210 * @param input_size The input size \f$n\f$. 00211 * @param a The \f$a\f$ factor. 00212 * @param b The \f$b\f$ factor. 00213 * @return A pointer to a new \ref gnn_logistic node. 00214 */ 00215 gnn_node * 00216 gnn_logistic_new (int input_size, double a, double b) 00217 { 00218 int status; 00219 gnn_node *node; 00220 00221 /* check if sizes are positive */ 00222 if (input_size < 1) 00223 { 00224 GSL_ERROR_VAL ("input size should be stricly positive", 00225 GSL_EINVAL, NULL); 00226 } 00227 00228 /* allocate the node */ 00229 node = (gnn_node *) malloc (sizeof (gnn_logistic)); 00230 if (node == NULL) 00231 { 00232 GSL_ERROR_VAL ("could not allocate memory for gnn_logistic", 00233 GSL_ENOMEM, NULL); 00234 } 00235 00236 /* Initialize the node */ 00237 status = gnn_node_init (node, 00238 "gnn_logistic", 00239 gnn_logistic_f, 00240 gnn_logistic_dx, 00241 NULL, 00242 NULL); 00243 if (status) 00244 { 00245 GSL_ERROR_VAL ("could not initialize gnn_logistic node", 00246 GSL_EFAILED, NULL); 00247 } 00248 00249 status = gnn_node_set_sizes (node, input_size, input_size, 0); 00250 if (status) 00251 { 00252 GSL_ERROR_VAL ("could not set sizes for gnn_logistic node", 00253 GSL_EFAILED, NULL); 00254 } 00255 /* set the constants */ 00256 GNN_LOGISTIC_A (node) = a; 00257 GNN_LOGISTIC_B (node) = b; 00258 00259 return node; 00260 } 00261 00262 /** 00263 * @brief Creates a standard Logistic Sigmoid function node. 00264 * @ingroup gnn_logistic_doc 00265 * 00266 * This function creates a node of the \ref gnn_logistic type: 00267 * \f[ y_i = \frac { 1 } { 1 + e^{-x_i}} \f] 00268 * where \f$i = 1, \ldots, n\f$. 00269 * 00270 * @param input_size The input size \f$n\f$. 00271 * @return A pointer to a new \ref gnn_logistic node. 00272 */ 00273 gnn_node * 00274 gnn_logistic_standard_new (int input_size) 00275 { 00276 return gnn_logistic_new (input_size, 1.0, 1.0); 00277 } 00278 00279 /** 00280 * @brief Returns the amplitude constant \f$a\f$. 00281 * @ingroup gnn_logistic_doc 00282 * 00283 * @param node A pointer to a \ref gnn_logistic node. 00284 * @return The amplitude \f$a\f$ of the sigmoid. 00285 */ 00286 double 00287 gnn_logistic_get_a (gnn_node *node) 00288 { 00289 return GNN_LOGISTIC_A (node); 00290 } 00291 00292 /** 00293 * @brief Sets the amplitude constant \f$a\f$. 00294 * @ingroup gnn_logistic_doc 00295 * 00296 * @param node A pointer to a \ref gnn_logistic node. 00297 * @param a The amplitude factor. 00298 */ 00299 void 00300 gnn_logistic_set_a (gnn_node *node, double a) 00301 { 00302 GNN_LOGISTIC_A (node) = a; 00303 } 00304 00305 /** 00306 * @brief Gets the streching factor \f$b\f$. 00307 * @ingroup gnn_logistic_doc 00308 * 00309 * @param node A pointer to a \ref gnn_logistic node. 00310 * @return The streching factor \f$b\f$. 00311 */ 00312 double 00313 gnn_logistic_get_b (gnn_node *node) 00314 { 00315 return GNN_LOGISTIC_B (node); 00316 } 00317 00318 /** 00319 * @brief Sets the streching factor \f$b\f$. 00320 * @ingroup gnn_logistic_doc 00321 * 00322 * @param node A pointer to a \ref gnn_logistic node. 00323 * @param b The new streching factor \f$b\f$. 00324 */ 00325 void 00326 gnn_logistic_set_b (gnn_node *node, double b) 00327 { 00328 GNN_LOGISTIC_B (node) = b; 00329 } 00330 00331 00332 00333
1.2.18