📄 neuron.h
字号:
#ifndef _NEURON_H#define _NEURON_H#include "Link.h"#include "defines.h"#include <string>namespace annie{// Some activation functions and their derivatives/// The identity function, ie, f(x) = xreal identity(real x);/// Derivative of the identity function, thus always returns 1real didentity(real x);/// Sigmoidal activation f(x)real sigmoid(real x);/// Derivative of the sigmoidal functionreal dsigmoid(real x);/// The guassian function. Sigma is taken to be 1.0real gaussian(real x);/// Derivative of the gaussian function (sigma is taken to be 1.0)real dgaussian(real x);/** Signum function * Returns real instead of int because this function can be used * as an activation function too, so wanted to keep the signature * the same as other activation functions. * @param x Real value as input * @return -1 if x<0, +1 if x>=0 */real signum(real x);/// The tansig activation function. Courtesy Jose Ramos (warta@users.sourceforge.net).real tansig(real x);/// Derivative of the tansign activation function. Courtesy Jose Ramos (warta@users.sourceforge.net).real dtansig(real x);/// Activation functions take in a single real value and return a single real value/** These functions are used as activation functions of the neurons, i.e., the function * applied to the raw output of the neurons. * @see identity * @see sigmoid * @see gaussian */typedef real(*ActivationFunction)(real);/// A set of Links, ie, weighted connections between two neuronstypedef std::vector<Link *> LINKS;/** One of the fundamental annie classes - the basic Neuron. This class acts only as a * template, and cannot be instantiated. Each neuron has a (unique) label which is specified * when creating the neuron. Note that no effort has been made to ensure that the labels * are indeed unique, you'll have to take care of that yourself. The MultiLayerNetwork * and RadialBasisNetwork for example assign the label of the neuron as: * <layer number> * Layer::MAX_LAYER_SIZE + <neuron number in layer> * * Each Neuron caches the activation, output and error. The getOutput() and getActivation() * functions merely check if the cache is valid, if so they return the value in the cache * otherwise they force fresh calculation of the output and error. * Different types of neurons will have different ways of calculating the output and * error. Hence, the instantiable sub-classes of this class must implement the * protected functions _recacheOutput() and _recacheError() which calculate the activation, * output and error and update the cache. * * Also, each sub-class must provide the getClassName() function. Since C++ doesn't have * a good class reflection system, this has been provided for some primitive reflection * @see InputNeuron * @see SimpleNeuron * @see CenterNeuron * * @todo why doesn't it have connect?? * @todo the link connecting is really slow... */class Neuron{protected: /// The label of the neuron int _label; /** Flag, true if the cached activation and output are valid and hence calls to * getActivation() and getOutput() can simply return the cached values and don't * have to recalculate. * Set to false by disconnect() and other functions in the sub-classes of this neuron */ mutable bool _outputCacheValid; /// The previously cached activation mutable real _activationCache; /// The previously cached output mutable real _outputCache; /** Flag, true if the cached error is valid */ mutable bool _errorCacheValid; /** * The previously cached error. * In the literature, this is typically \delta_j: * For MLP, this means difference of output from the desired output. (For hidden neurons, * this is summed from errors node connects to * weight * For output neuron: \delta_j = (d_j - y_j) dy_j * For hidden neuron: \delta_j = (\sum_k ( \delta_k w_jk)) * dy_j * where d_j is desired output of neuron j */ mutable real _errorCache; /** The class heirarchy of the neuron. For example, if this list contains * the string "Neuron", "A","B" then it tells you that the particular object * is an instance of class "B", which is a sub-class of "A" which is a sub-class * of Neuron. * * If you ever derive your own Neuron from any of the existing types * of neurons then you MUST add the class name of that neuron to this list. * @see instanceOf */ std::vector<char *> _classHeirarchy; /// Set of input links, i.e., links in which this neuron received input LINKS _inputLinks;public: /** Set of output links, i.e., links in which this neuron provides output * This really shouldn't be public, and thus USE THIS AS IF IT WAS PROTECTED. * I had to keep this public because of an implementation issue. */ LINKS _outputLinks;protected: /// The function that is applied to the activation of the neuron to get the output ActivationFunction _activationFunction; /** This function recalculates output if necessary * Every instantiable sub-class of the basic Neuron class MUST implement this function. * The implementation would first check if the cache is valid and if not then recalculate * the activation and output and update the corresponding cache values. Such a function * would typically look like: * \code * void _recacheOutput() * { * if (_outputCacheValid) * return; * //Calculate the activation of the neuron * _activationCache = activation; * _outputCache = _activationFunction(_activationCache); * _outputCacheValid = true; * } * \endcode */ virtual void _recacheOutput() const =0; /** This function recalculates error if necessary * Every instantiable sub-class of the basic Neuron class MUST implement this function. * The implementation would first check if the cache is valid and if not then recalculate * the error update the cache value. Such a function would typically look like: * \code * void _recacheError() * { * if (_errorCacheValid) * return; * //Calculate the error at the neuron * _errorCache = error; * _errorCacheValid = true; * } * \endcode */ virtual void _recacheError() const =0;public: /** Creates a Neuron with the given label, sets activation, output and error to 0 * @param label The label to be given to this neuron */ Neuron(int label); Neuron(Neuron &neuron); /// Destroys all input and output links virtual ~Neuron(); /** Returns the activation of this neuron * * Calls _recacheOutput() and then returns _activationCache. Most sub-classes will * not need to override this function * @return Activation at this neuron */ virtual real getActivation() const; /** Returns the output of this neuron * Calls _recacheOutput() and then returns _outputCache. Most sub-classes will * not need to override this function * @return Output of this neuron */ virtual real getOutput() const; /** Returns the error of this neuron * Calls _recacheError() and then returns _errorCache. Most sub-classes will * not need to override this function * @return Error estimate at this neuron */ virtual real getError() const; /// The label of this neuron virtual int getLabel() const; /** The size of the input vector taken in by this neuron, ie, the number of neurons that give input to this neuron * @return _inputLinks.size() */ virtual uint getInputCount() const; /** The number of neurons that take the output of this neuron as input * @return _outputLinks.size() */ virtual uint getOutputCount() const; /** Invalidates the output cache of this neuron. Should be called on any structural change * Structural changes such as changes to the input or output links and/or their weights * should invalidate the cache of the neuron using this function. * Causes the cache of all neurons who receive input from this neuron to be invalidated * as well. */ virtual void invalidateOutputCache(); /** Invalidates the error cache of this neuron. * Causes the cache of all neurons who provide input to this neuron to be invalidated * as well */ virtual void invalidateErrorCache(); /** Returns a list of neurons which provide this neuron with input and their weights * @param labels List of neurons (their labels) that provide input to this neuron returned here * @param weights Weights of the links returned here * Thus, the pair (labels[i],weights[i]) specifies where this neuron gets input from * and what the corresponding weights are */ virtual int getInputs(std::vector<int> &labels, Vector &weights); /** * Returns input connection weights * @param out - must be of getInputCount() size! */ void getWeights(Vector &out) const; /** Removes the link between the given neuron and this neuron * @param from The neuron which provides input to this neuron * Invalidates the cache as well */ virtual void disconnect(Neuron *from); /** Returns the weight of the link between the given neuron and this * neuron. * @param from The neuron which provides input to this neuron. * @return The weight of the corresponding link */ virtual real getWeight(Neuron *from) const; /** Formatted string displaying details of this neuron. Useful for debugging. * Sub-classes should implement this function as well in order to display their * characteristics */ virtual operator std::string() const; /** Returns the name of the class that the neuron is an instance of. * This function should be provided by \em every sub-class */ virtual const char *getClassName() const=0; friend class Link; /** Given a string, tells if this object is an instance of that class. * Basically, a work-around the absence of standardized class reflection * techniques in C++. * For example, consider the following: * \code * SimpleNeuron n(32); * n.instanceOf("Neuron"); //returns true * n.instanceOf("SimpleNeuron"); //returns true * n.instanceOf("CenterNeuron"); //returns false * \endcode * DO NOT override this function * @param className Name of the class to check this with * @return true if the object is an instance of the given class, false otherwise */ bool instanceOf(const char *className) const; /** Prints (string) neuron to the provided output stream * try * \code cout<<neuron<<endl; \endcode to see what it does */ friend std::ostream& operator << (std::ostream& s, const Neuron &neuron);};}; //namespace annie#endif // define _NEURON_H
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -