![]() |
pl-nk v0.4.5
Plonk|Plink|Plank are a set of cross-platform C/C++ frameworks for audio software development
|
00001 /* 00002 ------------------------------------------------------------------------------- 00003 This file is part of the Plink, Plonk, Plank libraries 00004 by Martin Robinson 00005 00006 http://code.google.com/p/pl-nk/ 00007 00008 Copyright University of the West of England, Bristol 2011-14 00009 All rights reserved. 00010 00011 Redistribution and use in source and binary forms, with or without 00012 modification, are permitted provided that the following conditions are met: 00013 00014 * Redistributions of source code must retain the above copyright 00015 notice, this list of conditions and the following disclaimer. 00016 * Redistributions in binary form must reproduce the above copyright 00017 notice, this list of conditions and the following disclaimer in the 00018 documentation and/or other materials provided with the distribution. 00019 * Neither the name of University of the West of England, Bristol nor 00020 the names of its contributors may be used to endorse or promote products 00021 derived from this software without specific prior written permission. 00022 00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 00024 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00025 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00026 DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF THE WEST OF ENGLAND, BRISTOL BE 00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 00034 This software makes use of third party libraries. For more information see: 00035 doc/license.txt included in the distribution. 00036 ------------------------------------------------------------------------------- 00037 */ 00038 00039 #ifndef PLONK_NEURALNETWORK_H 00040 #define PLONK_NEURALNETWORK_H 00041 00042 #include "../core/plonk_CoreForwardDeclarations.h" 00043 #include "../containers/plonk_ContainerForwardDeclarations.h" 00044 00045 #include "../core/plonk_SmartPointer.h" 00046 #include "../core/plonk_WeakPointer.h" 00047 00048 #include "plonk_JSON.h" 00049 00050 #define PLANK_NEURALPATTERNF_JSON_TYPE "plank::NeuralPatternF" 00051 #define PLANK_NEURALPATTERNF_JSON_VERSION 0, 1, 1, 0 00052 #define PLANK_NEURALPATTERNF_JSON_INPUT "input" 00053 #define PLANK_NEURALPATTERNF_JSON_TARGET "target" 00054 00055 template<class ValueType> class NeuralNetworkBase; 00056 00057 template<class ValueType> 00058 class NeuralNetworkInternal : public SmartPointer 00059 { 00060 }; 00061 00062 template<> 00063 class NeuralNetworkInternal<float> : public SmartPointer 00064 { 00065 public: 00066 typedef NeuralNetworkBase<float> NetworkType; 00067 typedef NumericalArray<float> VectorType; 00068 typedef PlankNeuralNetworkFActFunction ActFunc; 00069 00070 NeuralNetworkInternal (IntArray const& layers, const float range) throw() 00071 { 00072 ResultCode result = pl_NeuralNetworkF_InitWithLayersAndRange (&network, layers.getArray(), layers.length(), range); 00073 plonk_assert (result == PlankResult_OK); 00074 00075 networkOutputs.referTo (pl_NeuralNetworkF_GetNumOutputs (&network), 00076 const_cast<float*> (pl_NeuralNetworkF_GetOutputsPtr (&network))); 00077 00078 #ifndef PLONK_DEBUG 00079 (void)result; 00080 #endif 00081 } 00082 00083 NeuralNetworkInternal (PlankJSONRef json) throw() 00084 { 00085 ResultCode result = pl_NeuralNetworkF_InitFromJSON (&network, json); 00086 plonk_assert (result == PlankResult_OK); 00087 00088 networkOutputs.referTo (pl_NeuralNetworkF_GetNumOutputs (&network), 00089 const_cast<float*> (pl_NeuralNetworkF_GetOutputsPtr (&network))); 00090 00091 #ifndef PLONK_DEBUG 00092 (void)result; 00093 #endif 00094 } 00095 00096 ~NeuralNetworkInternal() 00097 { 00098 ResultCode result = pl_NeuralNetworkF_DeInit (&network); 00099 plonk_assert (result == PlankResult_OK); 00100 00101 #ifndef PLONK_DEBUG 00102 (void)result; 00103 #endif 00104 } 00105 00106 IntArray getStructure() const throw() 00107 { 00108 IntArray structure; 00109 00110 structure.add (this->getNumInputs()); 00111 00112 const int numLayers = this->getNumLayers() - 1; 00113 00114 for (int i = 0; i < numLayers; ++i) 00115 { 00116 PlankNeuralLayerFRef layer = 0; 00117 00118 ResultCode result = pl_NeuralNetworkF_GetLayer (const_cast<PlankNeuralNetworkF*> (&network), i, &layer); 00119 00120 if (result == 0) 00121 { 00122 const int numNodes = pl_NeuralLayerF_GetNumOutputs (layer); 00123 structure.add (numNodes); 00124 } 00125 } 00126 00127 return structure; 00128 } 00129 00130 private: 00131 inline int getNumInputs() const throw() { return pl_NeuralNetworkF_GetNumInputs (const_cast<PlankNeuralNetworkF*> (&network)); } 00132 inline int getNumOutputs() const throw() { return pl_NeuralNetworkF_GetNumOutputs (const_cast<PlankNeuralNetworkF*> (&network)); } 00133 inline int getNumLayers() const throw() { return pl_NeuralNetworkF_GetNumLayers (const_cast<PlankNeuralNetworkF*> (&network)); } 00134 00135 inline const VectorType& getOutput() const throw() { return networkOutputs; } 00136 00137 inline const VectorType& propogate (VectorType const& inputs) throw() 00138 { 00139 plonk_assert (inputs.length() == this->getNumInputs()); 00140 ResultCode result = pl_NeuralNetworkF_Propogate (&network, inputs.getArray()); 00141 plonk_assert (result == PlankResult_OK); 00142 00143 #ifndef PLONK_DEBUG 00144 (void)result; 00145 #endif 00146 00147 return networkOutputs; 00148 } 00149 00150 inline void propogate (VectorType& outputs, VectorType const& inputs) throw() 00151 { 00152 ResultCode result; 00153 00154 plonk_assert (inputs.length() == this->getNumInputs()); 00155 result = pl_NeuralNetworkF_Propogate (&network, inputs.getArray()); 00156 plonk_assert (result == PlankResult_OK); 00157 00158 outputs.setSize (this->networkOutputs.length(), false); 00159 VectorType::copyData (outputs.getArray(), 00160 this->networkOutputs.getArray(), 00161 this->networkOutputs.length()); 00162 00163 #ifndef PLONK_DEBUG 00164 (void)result; 00165 #endif 00166 } 00167 00168 inline void backProp (VectorType const& inputs, VectorType const& targets) throw() 00169 { 00170 plonk_assert (inputs.length() == this->getNumInputs()); 00171 plonk_assert (targets.length() == this->getNumOutputs()); 00172 00173 ResultCode result = pl_NeuralNetworkF_BackProp (&network, inputs.getArray(), targets.getArray()); 00174 plonk_assert (result == PlankResult_OK); 00175 00176 #ifndef PLONK_DEBUG 00177 (void)result; 00178 #endif 00179 } 00180 00181 inline void setActFunc (ActFunc const& function) throw() 00182 { 00183 ResultCode result = pl_NeuralNetworkF_SetActFunc (&network, function); 00184 plonk_assert (result == PlankResult_OK); 00185 00186 #ifndef PLONK_DEBUG 00187 (void)result; 00188 #endif 00189 } 00190 00191 inline void toJSON (PlankJSONRef json, const bool useBinary) throw() 00192 { 00193 ResultCode result = pl_NeuralNetworkF_ToJSON (&network, json, useBinary); 00194 plonk_assert (result == PlankResult_OK); 00195 00196 #ifndef PLONK_DEBUG 00197 (void)result; 00198 #endif 00199 } 00200 00201 friend class NeuralNetworkBase<float>; 00202 00203 PlankNeuralNetworkF network; 00204 VectorType networkOutputs; 00205 }; 00206 00207 00208 //------------------------------------------------------------------------------ 00209 00211 template<class ValueType> 00212 class NeuralNetworkBase : public SmartPointerContainer<NeuralNetworkInternal<ValueType> > 00213 { 00214 public: 00215 00216 typedef NeuralNetworkInternal<ValueType> Internal; 00217 typedef SmartPointerContainer<Internal> Base; 00218 typedef WeakPointerContainer<NeuralNetworkBase> Weak; 00219 typedef typename Internal::VectorType VectorType; 00220 typedef typename Internal::ActFunc ActFunc; 00221 00222 class Pattern 00223 { 00224 public: 00225 typedef ObjectArray<Pattern> Patterns; 00226 00227 Pattern() throw() { } 00228 Pattern (VectorType const& input, VectorType const& target) throw() 00229 : i (input.deepCopy()), t (target.deepCopy()) 00230 { 00231 } 00232 00233 Pattern (JSON const& json) throw() 00234 { 00235 if (!json.isObject()) return; 00236 if (!json.isObjectType (PLANK_NEURALPATTERNF_JSON_TYPE)) return; 00237 if (json.getVersion() > JSON::versionCode (PLANK_NEURALNETWORKF_JSON_VERSION)) return; 00238 00239 JSON inputJson = json[PLANK_NEURALPATTERNF_JSON_INPUT]; 00240 JSON targetJson = json[PLANK_NEURALPATTERNF_JSON_TARGET]; 00241 00242 i = inputJson; 00243 t = targetJson; 00244 } 00245 00246 const VectorType& getInput() const throw() { return i; } 00247 const VectorType& getTarget() const throw() { return t; } 00248 int getInputLength() const throw() { return i.length(); } 00249 int getTargetLength() const throw() { return t.length(); } 00250 00251 void toJSON (JSON& json, const bool useBinary = false) const throw() 00252 { 00253 JSON jsonPattern = JSON::object(); 00254 jsonPattern.setType (PLANK_NEURALPATTERNF_JSON_TYPE); 00255 jsonPattern.setVersionString (PLANK_NEURALPATTERNF_JSON_VERSION); 00256 jsonPattern.add (PLANK_NEURALPATTERNF_JSON_INPUT, JSON (i, useBinary)); 00257 jsonPattern.add (PLANK_NEURALPATTERNF_JSON_TARGET, JSON (t, useBinary)); 00258 json.add (jsonPattern); 00259 } 00260 00261 static void patternsToJSON (JSON& json, Patterns const& patterns, const bool useBinary = false) throw() 00262 { 00263 const int numPatterns = patterns.length(); 00264 const Pattern* patternArray = patterns.getArray(); 00265 00266 for (int j = 0; j < numPatterns; ++j) 00267 { 00268 patternArray[j].toJSON (json, useBinary); 00269 } 00270 } 00271 00272 friend class NeuralNetworkBase; 00273 00274 private: 00275 VectorType i; 00276 VectorType t; 00277 }; 00278 00279 typedef typename Pattern::Patterns Patterns; 00280 00281 NeuralNetworkBase() throw() 00282 : Base (new Internal (IntArray (1, 1, 1), 0.1f)) 00283 { 00284 } 00285 00286 NeuralNetworkBase (IntArray const& layers, const float range = 0.1f) throw() 00287 : Base (new Internal (layers, range)) 00288 { 00289 } 00290 00291 // NeuralNetworkBase (PlankJSONRef json) throw() 00292 // : Base (new Internal (json)) 00293 // { 00294 // } 00295 00296 NeuralNetworkBase (JSON const& json) throw() 00297 : Base (new Internal (json.getInternal())) 00298 { 00299 } 00300 00301 explicit NeuralNetworkBase (Internal* internalToUse) throw() 00302 : Base (internalToUse) 00303 { 00304 } 00305 00309 static NeuralNetworkBase fromWeak (Weak const& weak) throw() 00310 { 00311 return weak.fromWeak(); 00312 } 00313 00316 NeuralNetworkBase (NeuralNetworkBase const& copy) throw() 00317 : Base (static_cast<Base const&> (copy)) 00318 { 00319 } 00320 00321 // NeuralNetworkBase (Dynamic const& other) throw() 00322 // : Base (other.as<NeuralNetworkBase>().getInternal()) 00323 // { 00324 // } 00325 00327 NeuralNetworkBase& operator= (NeuralNetworkBase const& other) throw() 00328 { 00329 if (this != &other) 00330 this->setInternal (other.getInternal()); 00331 00332 return *this; 00333 } 00334 00335 inline const VectorType& propogate (VectorType const& inputs) throw() 00336 { 00337 return this->getInternal()->propogate (inputs); 00338 } 00339 00340 inline void propogate (VectorType& outputs, VectorType const& inputs) throw() 00341 { 00342 return this->getInternal()->propogate (outputs, inputs); 00343 } 00344 00345 inline void backProp (VectorType const& inputs, VectorType const& targets) throw() 00346 { 00347 return this->getInternal()->backProp (inputs, targets); 00348 } 00349 00350 inline void train (Patterns const& patterns, const int numEpochs) throw() 00351 { 00352 const int numPatterns = patterns.length(); 00353 const Pattern* patternArray = patterns.getArray(); 00354 00355 for (int i = 0; i < numEpochs; ++i) 00356 { 00357 for (int j = 0; j < numPatterns; ++j) 00358 this->backProp (patternArray[j].i, patternArray[j].t); 00359 } 00360 } 00361 00362 void reset (const ValueType amount = 0.1f) throw() 00363 { 00364 pl_NeuralNetworkF_Reset (&this->getInternal()->network, amount); 00365 } 00366 00367 void randomise (const ValueType amount = 0.1f) throw() 00368 { 00369 pl_NeuralNetworkF_Randomise (&this->getInternal()->network, amount); 00370 } 00371 00372 inline void setActFunc (ActFunc const& function) throw() 00373 { 00374 return this->getInternal()->setActFunc (function); 00375 } 00376 00377 // void toJSON (PlankJSONRef json, const bool useBinary = false) throw() 00378 // { 00379 // this->getInternal()->toJSON (json, useBinary); 00380 // } 00381 00382 void toJSON (JSON& json, const bool useBinary = false) throw() 00383 { 00384 this->getInternal()->toJSON (json.getInternal(), useBinary); 00385 } 00386 00387 int getNumInputs() const throw() 00388 { 00389 return this->getInternal()->getNumInputs(); 00390 } 00391 00392 int getNumOutputs() const throw() 00393 { 00394 return this->getInternal()->getNumOutputs(); 00395 } 00396 00397 IntArray getStructure() const throw() 00398 { 00399 return this->getInternal()->getStructure(); 00400 } 00401 00402 PLONK_OBJECTARROWOPERATOR(NeuralNetworkBase); 00403 }; 00404 00405 typedef NeuralNetworkBase<float> FloatNeuralNetwork; 00406 00407 00408 #endif // PLONK_NEURALNETWORK_H