神经网络深入(连载6)物种形成
2017-01-25 13:31
232 查看
游戏编程中的人工智能技术
连载6:物种形成
我在第5章 “建立一种更好遗传算法”中已经介绍过了适应性共享,这就是,通过共享具有相似基因组的个体的适应性分数,来保留差异。在NEAT中,适应性分数是由同一物种的成员所共享的。这实际上就是,在作任何选择前,每一个个体的分数都除以物种的大小。这样,已经长大的物种的进一步生长就会受到它们的尺寸的惩罚而得到约束,而相反,小的物种在演化竞赛中则是在被“用脚向前踢”了,说得形象点的话。
此外,年轻的物种在适应性共享计算中被赋于了更易加速增长的适应性分数。同样,老的物种则受到了惩罚。如果某一物种经历了几代(缺省是15代)都不能显示一点改进,它就会被杀死而离开。与此不同的一个例外是,如果某个物种包含了到目前为止所发现的功能最好的那个个体,则此物种就被允许继续生存下去。
我想我能做的最好的事情来帮助阐明我刚提供的所有信息,就是向你指出计算所有适应性调整的方法。但首先,让我花些时间列出物种类CSpecies的定义:
classCSpecies
{
private:
//为该物种的第一个成员保留一个本地备份(local copy)
CGenome m_Leader;
//指向该物种内所有基因组的指针
vector<CGenome*> m_vecMembers;
//物种需要的一个表识号
int m_iSpeciesID;
//物种到此之前找到的最高适应性分
double m_dBestFitness;
//种类的平均适应性分数
double m_dAvFitness;
//适应性分数改进之后的代的数目,必要时我们可用这一信息来杀死一个物种
int m_iGensNoImprovement;
//物种的年龄
int m_iAge;
//下一代群体这一物种必须孵化出来多少
double m_dSpawnsRqd;
public:
CSpecies(CGenome &FirstOrg, int SpeciesID);
//这一种方法增加年轻基因组的适应性分,惩罚年老基因组的适应性分数,
//然后对该物种的所有成员实行适应性分数的共享
voidAdjustFitnesses();
//把一个新个体加入到物种里
void AddMember(CGenome& new_org);
void Purge();
//计算该物种需要孵化多少后代
void CalculateSpawnAmount();
//从所选物种的最好的CParams::dSurvivalRate百分比中,随机选择
//一个,来孵化出一个个体
CGenome Spawn();
//--------------------------------------供访问用的各种方法
CGenome Leader()const{returnm_Leader;}
double NumToSpawn()const{returnm_dSpawnsRqd;}
int NumNembers()const{returnm_vecMembers.slze();}
int GensNoImprovement()const
{returnm_iGensNoImprovement;}
int ID()const{returnm_iSpeciesID;}
double SpeciesLeaderFitness()const
{returnm_Leader.Fitness()};
double BestFitness()const{returnm_dBestFitness;}
int Age()const(return m_iAge;)
//这样,我们就可以按照适应性的好坏对物种进行排序。最大的排在第一
friend bool operator<(const CSpecies&lhs,
const CSpecies &rhs )
{
return lhs.m_dBestFitness >rhs.m_dBestFitness;
}
};
下面就是调整适应性分数的方法:
void CSpecies::AdjustFitnesses()
{
doubletotal = 0;
for(int gen=O; gen<m_vecMembers.size(); ++gen)
{
double fitness = m_vecNembers[gen]->Fitness();
//如果物种是年轻的,则增加它的适应性分数
if(m_iAge < CParams::iYoungBonusAgeThreshhold)
{
fitness*= CParams::dYoungFitnessBonus;
}
//惩罚年老的物种
if(m_iAge > CParams::iOldAgeThreshold)
{
fitness*= CParams::dOldAgePenalty;
}
total+= fitness;
//把适应性共享应用到调整后各个适当性分数
doubleAdjustedFitness = fitness/m_vecMembers.size();
m_vecMembers[gen]->SetAdjFitness(AdjustedFitness);
}
}
连载6:物种形成
11.4.3.2CSpecies Class(物种的类)
一个个体一旦被指定为某一物种后,它就只能与和它属于同一物种的成员进行配对。但是,单独利用这种物种的形成机制还不能保护群体中新的创新。为了做到后一点,我们必须设法寻找一种能帮助年幼个体调整其适应性的方法,使得在一段合理长度的时期内,能有更多的不同的基因组保持为活跃状态。NEAT中用来实现这一想法的技术我们称之为显式适应性共享(explicit fitness sharing)。我在第5章 “建立一种更好遗传算法”中已经介绍过了适应性共享,这就是,通过共享具有相似基因组的个体的适应性分数,来保留差异。在NEAT中,适应性分数是由同一物种的成员所共享的。这实际上就是,在作任何选择前,每一个个体的分数都除以物种的大小。这样,已经长大的物种的进一步生长就会受到它们的尺寸的惩罚而得到约束,而相反,小的物种在演化竞赛中则是在被“用脚向前踢”了,说得形象点的话。
注: 在NEAT原始的实现中,设计者虽然也结合使用了这种‘物种内部’的匹配,但把这种发生的概率设置的很低。尽管我从来没有观察到使用它时有任何值得注意的表现优化,但对于你来说,当你开始自己来实现这一方法时,这可能仍是一个多少值得一试的练习。 |
我想我能做的最好的事情来帮助阐明我刚提供的所有信息,就是向你指出计算所有适应性调整的方法。但首先,让我花些时间列出物种类CSpecies的定义:
classCSpecies
{
private:
//为该物种的第一个成员保留一个本地备份(local copy)
CGenome m_Leader;
//指向该物种内所有基因组的指针
vector<CGenome*> m_vecMembers;
//物种需要的一个表识号
int m_iSpeciesID;
//物种到此之前找到的最高适应性分
double m_dBestFitness;
//种类的平均适应性分数
double m_dAvFitness;
//适应性分数改进之后的代的数目,必要时我们可用这一信息来杀死一个物种
int m_iGensNoImprovement;
//物种的年龄
int m_iAge;
//下一代群体这一物种必须孵化出来多少
double m_dSpawnsRqd;
public:
CSpecies(CGenome &FirstOrg, int SpeciesID);
//这一种方法增加年轻基因组的适应性分,惩罚年老基因组的适应性分数,
//然后对该物种的所有成员实行适应性分数的共享
voidAdjustFitnesses();
//把一个新个体加入到物种里
void AddMember(CGenome& new_org);
void Purge();
//计算该物种需要孵化多少后代
void CalculateSpawnAmount();
//从所选物种的最好的CParams::dSurvivalRate百分比中,随机选择
//一个,来孵化出一个个体
CGenome Spawn();
//--------------------------------------供访问用的各种方法
CGenome Leader()const{returnm_Leader;}
double NumToSpawn()const{returnm_dSpawnsRqd;}
int NumNembers()const{returnm_vecMembers.slze();}
int GensNoImprovement()const
{returnm_iGensNoImprovement;}
int ID()const{returnm_iSpeciesID;}
double SpeciesLeaderFitness()const
{returnm_Leader.Fitness()};
double BestFitness()const{returnm_dBestFitness;}
int Age()const(return m_iAge;)
//这样,我们就可以按照适应性的好坏对物种进行排序。最大的排在第一
friend bool operator<(const CSpecies&lhs,
const CSpecies &rhs )
{
return lhs.m_dBestFitness >rhs.m_dBestFitness;
}
};
下面就是调整适应性分数的方法:
void CSpecies::AdjustFitnesses()
{
doubletotal = 0;
for(int gen=O; gen<m_vecMembers.size(); ++gen)
{
double fitness = m_vecNembers[gen]->Fitness();
//如果物种是年轻的,则增加它的适应性分数
if(m_iAge < CParams::iYoungBonusAgeThreshhold)
{
fitness*= CParams::dYoungFitnessBonus;
}
//惩罚年老的物种
if(m_iAge > CParams::iOldAgeThreshold)
{
fitness*= CParams::dOldAgePenalty;
}
total+= fitness;
//把适应性共享应用到调整后各个适当性分数
doubleAdjustedFitness = fitness/m_vecMembers.size();
m_vecMembers[gen]->SetAdjFitness(AdjustedFitness);
}
}
相关文章推荐
- 神经网络深入(连载4)拓扑扩张
- 神经网络深入(连载10)一个demo程序
- 神经网络深入(连载5)算子与创新
- 神经网络深入(连载8)基因变成表现形
- 神经网络深入(连载2)直接编码
- 神经网络深入(连载9)神经网络类
- 神经网络深入(连载7)更换时代
- 神经网络深入(连载1)神经网络的拓扑
- 神经网络深入(连载3)间接编码
- 神经网络入门--连载5
- 神经网络入门--连载6
- 神经网络入门--连载2
- 神经网络入门(连载之二)
- 神经网络入门(连载之六)
- 神经网络入门(连载之五)
- 神经网络入门(连载之三)
- 神经网络入门(连载之一)
- 遗传算法入门(连载之十) 神经网络入门(连载预告)
- 神经网络入门(连载之一)
- 神经网络入门(连载之一)