gagents.cpp

来自「一个由Mike Gashler完成的机器学习方面的includes neural」· C++ 代码 · 共 1,066 行 · 第 1/2 页

CPP
1,066
字号
/*	Copyright (C) 2006, Mike Gashler	This library is free software; you can redistribute it and/or	modify it under the terms of the GNU Lesser General Public	License as published by the Free Software Foundation; either	version 2.1 of the License, or (at your option) any later version.	see http://www.gnu.org/copyleft/lesser.html*/#include "GAgents.h"#include "GArff.h"#include "GNeuralNet.h"#include "GKNN.h"#include "GBits.h"#include "GThread.h"#include "GPointerQueue.h"#include <stdlib.h>// How much inputs to an action construct can vary and still be considered the same concept#define ACTION_CONSTRUCT_INPUT_TOLERANCE .003// How many iterations (on average) before a trial iteration is performed. Note that// trial iterations slow learning somewhat, so this value shouldn't be smaller than 3#define AVE_ITERATIONS_PER_TRIAL 5// The number of construct trees for each sense#define SENSE_POPULATION_SIZE 5// The number of neighbors to use for the sense models#define SENSE_NEIGHBORS 3// The number of neighbors to use for the action models#define ACTION_NEIGHBORS 8// The tolerance-per-input for each sense node#define TOLERANCE_FACTOR .2// The tolerance used for action models#define ACTION_MODEL_TOLERANCE .005// This value balances recent criticism with historical criticism when evaluating a construct node.// Values close to 1 emphasize historical criticism, which smaller values emphacise recent criticisim.#define CRITIQUE_RATE .98// Determines on average how many critique evalations occur per evolutionary pass#define EVALUATIONS_PER_EVOLUTION 10// The mininum number of critiques before a construct node may be axed#define GRACE_CRITIQUES 50// Value used to indicate no memory of any value#define MEM_BLANK 1e200class IncrementalModel{protected:	GArffRelation* m_pRelation;public:	IncrementalModel()	{		m_pRelation = new GArffRelation();	}	virtual ~IncrementalModel()	{		delete(m_pRelation);	}	GArffRelation* GetRelation()	{		return m_pRelation;	}	virtual void Eval(double* pVector) = 0;	virtual void TrainIncremental(double* pVector) = 0;};// -----------------------------------------------------------------------/*class NeuralNetModel : public IncrementalModel{protected:	GNeuralNet* m_pModel;	double m_dSquaredInputTol;	double m_dSquaredOutputTol;public:	NeuralNetModel(int nLayers, const int arrNodeCount[], int nBatchSize, double dInputTol, double dOutputTol)	{		// Make the inputs		int i;		for(i = 0; i < arrNodeCount[nLayers - 1]; i++)			m_pRelation->AddAttribute(new GArffAttribute(true, 0, NULL));		// Make the outputs		for(i = 0; i < arrNodeCount[0]; i++)			m_pRelation->AddAttribute(new GArffAttribute(false, 0, NULL));		// Make the hidden layers		m_pModel = new GNeuralNet(m_pRelation);		m_pModel->SetLearningRate(.1);		for(i = 1; i < nLayers - 1; i++)			m_pModel->AddLayer(arrNodeCount[i]);		// Prepare for incremental training		m_pModel->IncrementalInit(nBatchSize, 0, 1);		// Compute the squared input tol		dInputTol *= 1.4; // 1.4 = INPUT_RANGE in GNeuralNet.cpp. todo: don't hard-code this as a magic value		m_dSquaredInputTol = dInputTol * dInputTol;		// Compute the squared output tol		m_dSquaredOutputTol = dOutputTol * dOutputTol; // because the error is squared		m_dSquaredOutputTol *= m_pRelation->GetOutputCount(); // because the squared error is summed across all the outputs	}	virtual ~NeuralNetModel()	{		delete(m_pModel);	}	GNeuralNet* GetModel()	{		return m_pModel;	}	virtual void Eval(double* pVector)	{		m_pModel->Eval(pVector);	}	void AddTrainingVector(double* pVector)	{		// Convert to the internal form		GArffRelation* pInternalRelation = m_pModel->GetInternalRelation();		double* pInternalVector = new double[pInternalRelation->GetAttributeCount()];		m_pModel->InputsToInternal(pVector, pInternalVector);		m_pModel->OutputsToInternal(pVector, pInternalVector);		// Remove conflicting entries		GArffData* pData = m_pModel->GetInternalTrainingData();		int i;		double* pTmpVector;		for(i = 0; i < pData->GetSize(); i++)		{			pTmpVector = (double*)pData->GetPointer(i);			if(pInternalRelation->ComputeInputDistanceSquared(pInternalVector, pTmpVector) < m_dSquaredInputTol)			{				pData->DeleteVector(i);				i--;			}			}		// Add the new vector to the data		int nSize = pData->GetSize();		if(nSize >= pData->GetGrowBy())			pData->DeleteVector(rand() % nSize);		pData->AddVector(pInternalVector);	}	// Drops any vectors from memory whose input values are close to this	// vector, adds this vector to the memory (bumping a randomely selected	// vector if necessary), then trains the neural net with all the vectors	// in memory until it outputs this vector correctly within the specified	// output tolerance, or it fails to get any better.	virtual void TrainIncremental(double* pVector)	{		int i;		int nInputs = m_pRelation->GetInputCount();		int nOutputs = m_pRelation->GetOutputCount();#ifdef _DEBUG		for(i = 0; i < nInputs + nOutputs; i++)			GAssert(pVector[i] > -.1 && pVector[i] < 1.1, "out of range");#endif // _DEBUG		GTEMPBUF(double, pTmp, nInputs + nOutputs);		memcpy(pTmp, pVector, sizeof(double) * nInputs);		double dSumSquaredError, dError;		AddTrainingVector(pVector);		double dPrevSumSquaredError = 1e100;		while(true)		{			// Evaluate			Eval(pTmp);			// Measure sum squared error			dSumSquaredError = 0;			for(i = 0; i < nOutputs; i++)			{				dError = pVector[nInputs + i] - pTmp[nInputs + i];				dSumSquaredError += (dError * dError);			}			if(dSumSquaredError < m_dSquaredOutputTol || dSumSquaredError >= dPrevSumSquaredError)				break;			dPrevSumSquaredError = dSumSquaredError;			// Train			for(i = 0; i < 10; i++)				m_pModel->TrainEpoch();		}	}};*/// -----------------------------------------------------------------------class InstanceModel : public IncrementalModel{protected:	GKNN* m_pModel;	double m_dInputTol;public:	InstanceModel(int nInputs, int nOutputs, int nNeighbors, double dInputTol)	{		// Make the inputs		int i;		for(i = 0; i < nInputs; i++)			m_pRelation->AddAttribute(new GArffAttribute(true, 0, NULL));		// Make the outputs		for(i = 0; i < nOutputs; i++)			m_pRelation->AddAttribute(new GArffAttribute(false, 0, NULL));		// Make the model		m_pModel = new GKNN(m_pRelation, nNeighbors, true);		// Compute the squared input tol		m_dInputTol = dInputTol;	}	virtual ~InstanceModel()	{		delete(m_pModel);	}	GKNN* GetModel()	{		return m_pModel;	}	virtual void Eval(double* pVector)	{		m_pModel->Eval(pVector);	}	virtual void TrainIncremental(double* pVector)	{		m_pModel->AddVectorAndDeleteNeighborIfClose(pVector, m_dInputTol);	}	double GetTol()	{		return m_dInputTol;	}};// -----------------------------------------------------------------------class ConstructNode{protected:	ConstructNode** m_pInputs;	bool m_bFlag;	int m_nSenseIndex;	InstanceModel* m_pModel;	int m_nActionCount;	InstanceModel** m_pActionModels;	int m_nCritiques;	double m_dError;public:	// Takes ownership of pInputs	ConstructNode(int nIndex, int nInputs, ConstructNode** pInputs, int nSenseCount, int nActionCount, bool bCondemned)	{		m_bFlag = false;		m_nSenseIndex = nIndex;		m_pInputs = pInputs;		double dInputTol = 1.0;		int i;		for(i = 0; i < nInputs; i++)			dInputTol *= (TOLERANCE_FACTOR * pInputs[i]->GetTol());		m_pModel = new InstanceModel(nInputs, 1/*nOutputs*/, SENSE_NEIGHBORS, dInputTol);		m_nActionCount = nActionCount;		m_pActionModels = new InstanceModel*[nActionCount];		int nLeafs = CountLeafs(0);		for(i = 0; i < nActionCount; i++)			m_pActionModels[i] = new InstanceModel(nSenseCount, nLeafs + 1, ACTION_NEIGHBORS, ACTION_MODEL_TOLERANCE);		if(bCondemned)		{			m_nCritiques = GRACE_CRITIQUES;			m_dError = GBits::GetRandomDouble() * 1e50;		}		else		{			m_nCritiques = 0;			m_dError = 0;		}	}	~ConstructNode()	{		delete[] m_pInputs;		delete(m_pModel);		int i;		for(i = 0; i < m_nActionCount; i++)			delete(m_pActionModels[i]);		delete[] m_pActionModels;	}	void Criticize(double dSquaredError)	{		m_dError = (CRITIQUE_RATE * m_dError) + ((1.0 - CRITIQUE_RATE) * dSquaredError);		m_nCritiques++;	}	double GetError()	{		return m_dError;	}	int GetCritiqueCount()	{		return m_nCritiques;	}	double GetTol()	{		return m_pModel->GetTol();	}	bool IsDependency(ConstructNode* pNode)	{		int nInputs = m_pModel->GetRelation()->GetInputCount();		int i;		for(i = 0; i < nInputs; i++)		{			if(m_pInputs[i] == pNode)				return true;		}		return false;	}	bool DoesDependOnSense(int sense)	{		if(m_nSenseIndex == sense)			return true;		int nInputs = m_pModel->GetRelation()->GetInputCount();		int i;		for(i = 0; i < nInputs; i++)		{			if(m_pInputs[i]->DoesDependOnSense(sense))				return true;		}		return false;	}	void ResetFlag()	{		m_bFlag = false;	}	bool IsReady()	{		if(m_bFlag)			return false;		bool bAllInputsFlagged = true;		int nInputs = m_pModel->GetRelation()->GetInputCount();		int i;		for(i = 0; i < nInputs; i++)		{			if(!m_pInputs[i]->m_bFlag)			{				bAllInputsFlagged = false;				break;			}		}		if(bAllInputsFlagged)		{			m_bFlag = true;			return true;		}		else			return false;	}	IncrementalModel* GetModel()	{		return m_pModel;	}	IncrementalModel* GetActionModel(int nAction)	{		return m_pActionModels[nAction];	}	double GetOutputValue()	{		int nSize = m_pModel->GetRelation()->GetAttributeCount();		GTEMPBUF(double, pVector, nSize);		int nInputs = m_pModel->GetRelation()->GetInputCount();		int i;		for(i = 0; i < nInputs; i++)			pVector[i] = m_pInputs[i]->GetOutputValue();		m_pModel->Eval(pVector);		return pVector[nInputs];	}	int CountLeafs(int nDepth)	{		int nInputs = m_pModel->GetRelation()->GetInputCount();		if(nInputs > 0)		{			int nCount = 0;			int i;			for(i = 0; i < nInputs; i++)				nCount += m_pInputs[i]->CountLeafs(nDepth + 1);			return nCount;		}		else		{			if(nDepth > 0)				return 1;			else				return 0;		}	}	int SetLeafValues(double* pVector, int nDepth)	{		int nInputs = m_pModel->GetRelation()->GetInputCount();		if(nInputs > 0)		{			int nCount = 0;			int i;			for(i = 0; i < nInputs; i++)				nCount += m_pInputs[i]->SetLeafValues(&pVector[nCount], nDepth + 1);			return nCount;		}		else		{			if(nDepth > 0)			{				*pVector = GetOutputValue();				return 1;			}			else				return 0;		}	}	int GetInputCount()	{		return m_pModel->GetRelation()->GetInputCount();	}	ConstructNode** GetInputs()	{		return m_pInputs;	}	bool AreInputsConstant(double* pBaselineVector, double* pCurrentVector, double dTolerance)	{		int nInputs = m_pModel->GetRelation()->GetInputCount();		int i, nIndex;		for(i = 0; i < nInputs; i++)		{			nIndex = m_pInputs[i]->m_nSenseIndex;			GAssert(nIndex >= 0, "construct not attached to a sense");			if(ABS(pCurrentVector[nIndex] - pBaselineVector[nIndex]) > dTolerance)				return false;		}		return true;	}	void TrainModel(double dValue)	{		int nInputs = m_pModel->GetRelation()->GetInputCount();		GAssert(m_pModel->GetRelation()->GetInputCount() == nInputs && m_pModel->GetRelation()->GetOutputCount() == 1, "Attribute mismatch");		GTEMPBUF(double, pVector, nInputs + 1);		int i;		for(i = 0; i < nInputs; i++)			pVector[i] = m_pInputs[i]->GetOutputValue();		pVector[nInputs] = dValue;		m_pModel->TrainIncremental(pVector);	}	void TrainFromActionModelOutput(int nSize, double* pVector)	{		GAssert(nSize == m_pModel->GetRelation()->GetAttributeCount(), "Wrong number of inputs");		double dDelta = pVector[nSize - 1];		m_pModel->Eval(pVector);		pVector[nSize - 1] += ((dDelta - .5) * 2);		m_pModel->TrainIncremental(pVector);	}};// -----------------------------------------------------------------------AgentAl::AgentAl(GAgentWorldInterface* pWorld, int nShortTermMemoryCapacity, double dFocus)	: Agent(pWorld){	m_nSenseCount = pWorld->GetSenseCount();	m_nActionCount = pWorld->GetActionCount();	m_bTrialIteration = false;	m_dFocus = dFocus;	// Construct the short term memory	m_nShortTermMemoryCapacity = nShortTermMemoryCapacity;	m_nShortTermMemoryPos = 0;	int nSize = (m_nSenseCount + 1) * m_nShortTermMemoryCapacity;	m_pShortTermMemory = new double[nSize];	int i, j;	for(i = 0; i < nSize; i++)		m_pShortTermMemory[i] = MEM_BLANK;	// Construct the senses	m_nSenseConstructs = m_nSenseCount * SENSE_POPULATION_SIZE;	m_pConstructNodes = new ConstructNode*[m_nSenseConstructs];	for(j = 0; j < m_nSenseCount; j++)	{		for(i = 0; i < SENSE_POPULATION_SIZE; i++)			m_pConstructNodes[j * SENSE_POPULATION_SIZE + i] = new ConstructNode(j, 0, NULL, m_nSenseCount, m_nActionCount, (i == 0 ? false : true));	}	// Make the initial dependency ordering	m_pSenseConstructDependencyOrder = new int[m_nSenseConstructs];	for(i = 0; i < m_nSenseConstructs; i++)		m_pSenseConstructDependencyOrder[i] = i;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?