This commit is contained in:
Yong Zhu 2019-08-05 20:00:09 -06:00
parent ae34b07e21
commit cf2a2d4d84
18 changed files with 456 additions and 183 deletions

View File

@ -67,28 +67,42 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什
![resut3](https://gitee.com/drinkjava2/frog/raw/master/result3.gif)
2019-06-26 找食效率太低又改回到4.12的用连接数量代替权值这个逻辑人为设计的算法居然比不过随机连接。Pain器官的加入没有提高找食效率必须与感光细胞合用才能知道是哪个边界急需引入记忆功能。
2019-06-28 为了让青蛙看到边界又加了个新的眼睛它是一个可自进化的nxn点阵的眼睛将来会取代只有四个象素点(但能看得远)的老眼睛。到目前为止,依然还没有进行模式识别和记忆功能开发。另外脑图可以动态显示了,用一个红圈标记出被动态跟踪显示的青蛙。
2019-07-28
有以下改动1.在Env区中间加了一个陷阱区Trap以增加趣味性自然选择的结果是青蛙会自动绕开陷阱区。2.增加一个Active器官它的作用是一直保持激活发现比Hungry器官驱动更能提高找食效率。3.增加一个Chance器官,它的作用是引入随机扰动,打破青蛙有时候围着一个食物打转就是吃不着的死循环。目前进食奖励信号没用到,白白浪费了。
2019-07-28 有以下改动: 1.在Env区中间加了一个陷阱区Trap以增加趣味性自然选择的结果是青蛙会自动绕开陷阱区。2.增加一个Active器官它的作用是一直保持激活发现比Hungry器官驱动更能提高找食效率。3.增加一个Chance器官,它的作用是引入随机扰动,打破青蛙有时候围着一个食物打转就是吃不着的死循环。目前进食奖励信号没用到,白白浪费了。
另外Chance和Eye类里也再次运用了随机试错原理去确定关键参数效果还不错有兴趣的可以看一看源码。
![resut4](https://gitee.com/drinkjava2/frog/raw/master/result4.gif)
另外发现青蛙其实是有记忆能力的,因为连接本身就是一种记忆,只不过它没有复杂的模式识别能力,例如给个蛇的图片它就认不出来。以后的工作将以模式识别为重点(当然随机连接看起来很有用,以后还可能保留)基本原理是见note中提到的仿照波传播及全息存储原理在思维区逆向成像。而且脑可能改成三维结构并根据逆向成像原理要将所有输入输出器官全移到三维结构的同一侧(即思维区)。这将会是一个非常大的改动下面我简单画了一个3D示意图来说明我想象中的这个模式识别和记忆的原理至于对不对还需要实验来验证:
![3d-model](https://gitee.com/drinkjava2/frog/raw/master/3d-model.gif)
这个模型的最顶层表示眼睛的感光细胞(或任意输入输出细胞),同时也是思维区,红色表示一个长条的图形,兰色表示一个三角图形,如果这两个图形经常有规律地同时出现,就会把它们共有的节点撑大,见紫色的节点,当红色图形单独出现,就会强烈激活紫色节点,然后紫色节点的信号反向传播,就会激活三角图形,反之亦然。这就同时解释了模式识别和记忆(或者说回忆)功能的的原理。一个节点可以被多个感光细胞共享,所以它的存储能力是很强的。而且可能这个原理比较符合生物脑结构。当然,实际编程时,虚拟神经元不一定要排成正立方三角,而可能通过胡乱排放,大致上过得去就行了,也许能乱拳打死老师傅,最终要靠电脑自动随机的排放,然后用优胜劣汰来筛选。目前有个难点是这个记忆功能在思维区成像是如何有条不紊地大体上按串行进行工作的,这个问题先放一放。
2019-08-04 更新了一个分组测试功能,如果测试青蛙数量太多,可以分批来测试,每轮测试最少的青蛙数量可以少到只有一个,这是用时间来换空间。
2019-08-05 有了分组测试功能后,顺手加上了一个青蛙走跷跷板自动平衡的演示,它每次只出场一个青蛙, 每轮包括100场测试大约跑90多轮半个小时(电脑慢)后,出现了下面的画面:
![result5](https://gitee.com/drinkjava2/frog/raw/master/result5_seesaw.gif)
这个版本的目的是为了增加一点趣味性,显得青蛙还是有点"用处"的,省得让人以为这个项目不务正业,青蛙只会找食。这个版本青蛙的脑结构和找食版的青蛙基本相同,区别只是在于环境不同,也就是说它的表现随着环境而变化,这符合"通用人工智能"的概念,即信号感受器官是统一的(通常是眼睛)但能根据不同的环境完成不同的任务。走跷跷板演示是最后一个2维脑的版本今后这个项目将沉寂一段较长时间我将致力于将青蛙脑重构为3D金字塔形脑结构(见上文)因为这个项目的缺点已经很明显它不具备对2维图像的模式识别能力用随机试错的方式只能处理非常简单的、信号在视网膜的固定区域出现的图像信号。
青蛙的找食效率以及走跷跷板平衡的能力都没有优化到顶点,一些构想中的复杂的器官如“与门”、“或门”(不要怀疑大自然能否进化出这些复杂器官)等都没加上器官的用进废退、奖励信号的利用都没反映但我认为这些还不关键目前最急迫的任务应该是先进行3D脑结构建模让青蛙能具备2维图形的模式识别(和回忆)功能,这个大的架构重构是它能处理复杂图像信息的立足之本,它的图像识别能力和通常的用上千张图片来训练识别一个图片这种工作模式完全不同,它是一种通用的,可自动分类识别所有图像的模式,更符合动物脑的工作模式,记住并回忆出某个图像(或任意输入信号场景的组合),可能只需要这种场景重复出现过几次即可,它是一种无外界信号判定,自动分类的识别模式。
如果想要运行这个项目的以前版本可以结合gitk命令和参考"版本提交记录.md"的介绍用git reset命令回复到以前任一个版本例如用:
git reset --hard ae34b07e 可以转回到上一个分组测试的找食版本。
## 重要参数 | Parameters
在Env.java类中以下有以下可调整参数请手工修改这些参数进行不同的测试前5个参数很重要:
```
SHOW_SPEED 调整实验的速度(1~1000),值越小则越慢。
DELETE_EGGS: 每次运行是否先删除保存的蛋,如果设为false将不删除保存的蛋会接着上次的测试结果续继运行。
EGG_QTY: 每次允许Frog下多少个蛋通常下蛋取值在10~1000之间。蛋保存着我们测试的结果。实验的最终目标就是获得一批蛋。
FROG_PER_EGG 每个蛋可以孵出多少个青蛙。
SCREEN 分屏测试,一轮测试可以分为多个批次进行,这里是屏数。每轮总的青蛙数量=EGG_QTY * FROG_PER_EGG, 每屏青蛙数=总数/SCREEN
ENV_WIDTH: 虚拟环境的宽度大小通常取值100~1000左右
ENV_HEIGHT: 虚拟环境高度大小通常取值100~1000左右
FROG_BRAIN_DISP_WIDTH: Frog的脑图在屏幕上的显示大小,通常取值100~1000左右
STEPS_PER_ROUND: 每轮测试步数, 每一步相当于脑思考的一桢,所有青蛙的脑神经元被遍历一次。
FOOD_QTY食物的数量食物越多则Frog的生存率就越高能量排名靠前的一批Frog可以下蛋其余的被淘汰。
```
## 版权 | License
[Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0)
## 期望 | Futures
欢迎发issue、私信等方式提出建议或加入开发组。
另外本项目开启了哭穷模式比提交一个pull request还能帮助这个项目开发的莫过于提交一个红包了金钱就是时间您的捐助将只会用于回馈本项目的实际参与开发者。
## 作者其它开源项目 | Other Projects
- [Java持久层工具 jSqlBox](https://gitee.com/drinkjava2/jSqlBox)
- [微型IOC/AOP工具 jBeanBox](https://gitee.com/drinkjava2/jBeanBox)
- [前端写SQL工具 GoSqlGo](https://gitee.com/drinkjava2/gosqlgo)
- [MyBatis增强插件 MyFatFat](https://gitee.com/drinkjava2/myfatfat)
欢迎发issue、评论等方式提出建议或加入开发组。
另外本项目开启了哭穷模式比提交一个pull request还能帮助这个项目开发的莫过于提交一个红包了金钱就是时间您的捐助会用于回馈本项目的参与开发者或用于发布开发任务。
## 关注我 | About Me
[Github](https://github.com/drinkjava2)

View File

@ -6,13 +6,16 @@ import java.awt.Image;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JPanel;
import com.github.drinkjava2.frog.brain.group.RandomConnectGroup;
import com.github.drinkjava2.frog.egg.Egg;
import com.github.drinkjava2.frog.egg.EggTool;
import com.github.drinkjava2.frog.objects.Food;
import com.github.drinkjava2.frog.objects.Material;
import com.github.drinkjava2.frog.objects.Object;
import com.github.drinkjava2.frog.objects.SeeSaw;
import com.github.drinkjava2.frog.util.RandomUtils;
/**
@ -24,22 +27,19 @@ import com.github.drinkjava2.frog.util.RandomUtils;
@SuppressWarnings("all")
public class Env extends JPanel {
/** Speed of test */
public static final int SHOW_SPEED = 300; // 测试速度-1000~1000,可调, 数值越小速度越慢
public static final int SHOW_SPEED = 1; // 测试速度-1000~1000,可调, 数值越小速度越慢
/** Delete eggs at beginning of each run */
public static final boolean DELETE_EGGS = true;// 每次运行是否先删除保存的蛋
public static final boolean DELETE_EGGS = false;// 每次运行是否先删除保存的蛋
public static final int EGG_QTY = 30; // 每轮下n个蛋可调只有最优秀的前n个青蛙们才允许下蛋
public static final int EGG_QTY = 25; // 每轮下n个蛋可调只有最优秀的前n个青蛙们才允许下蛋
public static final int FROG_PER_EGG = 3; // 每个蛋可以孵出几个青蛙
public static final int FROG_PER_EGG = 4; // 每个蛋可以孵出几个青蛙
public static final int SCREEN = 3; // 分几屏测完, 所以每轮待测青蛙总数=EGG_QTY*FROG_PER_EGG*SCREEN
public static final int SCREEN = 100; // 分几屏测完
public static final int FROG_PER_SCREEN = EGG_QTY * FROG_PER_EGG / SCREEN; // 每屏上显示几个青蛙这个数值由上面三个参数计算得来
/** Debug mode will print more debug info */
public static final boolean DEBUG_MODE = false; // Debug 模式下会打印出更多的调试信息
/** Draw first frog's brain after some steps */
public static int DRAW_BRAIN_AFTER_STEPS = 50; // 以此值为间隔动态画出脑图设为0则关闭这个动态脑图功能只显示一个静态不闪烁的脑图
@ -60,20 +60,16 @@ public class Env extends JPanel {
public static final int FOOD_QTY = 1500; // 食物数量, 可调
private static final Random r = new Random(); // 随机数发生器
public static boolean pause = false; // 暂停按钮按下将暂停测试
private static final boolean[][] foods = new boolean[ENV_WIDTH][ENV_HEIGHT];// 食物数组定义
private static final int TRAP_WIDTH = 350; // 陷阱高, 0~200
private static final int TRAP_HEIGHT = 10; // 陷阱宽, 0~200
public static byte[][] bricks = new byte[ENV_WIDTH][ENV_HEIGHT];// 组成环境的材料0=, 1=, 其它=其它...
public static List<Frog> frogs = new ArrayList<>(); // 这里存放所有待测的青蛙可能分几次测完由FROG_PER_SCREEN大小来决定
public static List<Egg> eggs = new ArrayList<>(); // 这里存放从磁盘载入或上轮下的蛋每个蛋可能生成1~n个青蛙
public static Object[] things = new Object[] { new SeeSaw() };
static {
System.out.println("唵缚悉波罗摩尼莎诃!"); // 杀生前先打印往生咒见码云issue#IW4H8
if (DELETE_EGGS)
@ -94,40 +90,22 @@ public class Env extends JPanel {
return x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT;
}
public static boolean foundFood(int x, int y) {// 如果指定点看到食物
return !(x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT) && Env.foods[x][y];
}
public static boolean closeToEdge(Frog f) {// 青蛙靠近边界? 离死不远了
return f.x < 20 || f.y < 20 || f.x > (Env.ENV_WIDTH - 20) || f.y > (Env.ENV_HEIGHT - 20);
}
public static boolean inTrap(int x, int y) {// 如果指定点看到食物
return x >= ENV_WIDTH / 2 - TRAP_WIDTH / 2 && x <= ENV_WIDTH / 2 + TRAP_WIDTH / 2
&& y >= ENV_HEIGHT / 2 - TRAP_HEIGHT / 2 && y <= ENV_HEIGHT / 2 + TRAP_HEIGHT / 2;
public static boolean foundAnyThing(int x, int y) {// 如果指定点看到任意东西或超出边界
return x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT || Env.bricks[x][y] >= Material.VISIBLE;
}
public static boolean foundAnyThing(int x, int y) {// 如果指定点看到食物或超出边界
return x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT || Env.foods[x][y] || inTrap(x, y);
}
public static boolean foundAndDeleteFood(int x, int y) {// 如果x,y有食物将其清0返回true
if (foundFood(x, y)) {
foods[x][y] = false;
public static boolean foundAndAteFood(int x, int y) {// 如果x,y有食物将其清0返回true
if (insideEnv(x, y) && Env.bricks[x][y] == Material.FOOD) {
bricks[x][y] = 0;
return true;
}
return false;
}
private void rebuildFood() {
for (int i = 0; i < ENV_WIDTH; i++) {// 清除食物
for (int j = 0; j < ENV_HEIGHT; j++)
foods[i][j] = false;
}
for (int i = 0; i < Env.FOOD_QTY; i++) // 生成食物
foods[RandomUtils.nextInt(ENV_WIDTH)][RandomUtils.nextInt(ENV_HEIGHT)] = true;
}
private void rebuildFrogs() {
frogs.clear();
for (int i = 0; i < eggs.size(); i++) {// 创建青蛙每个蛋生成n个蛙并随机取一个别的蛋作为精子
@ -139,26 +117,26 @@ public class Env extends JPanel {
loop = FROG_PER_EGG - 1;
}
for (int j = 0; j < loop; j++) {
Egg zygote = new Egg(eggs.get(i), eggs.get(r.nextInt(eggs.size())));
Egg zygote = new Egg(eggs.get(i), eggs.get(RandomUtils.nextInt(eggs.size())));
frogs.add(new Frog(RandomUtils.nextInt(ENV_WIDTH), RandomUtils.nextInt(ENV_HEIGHT), zygote));
}
}
}
private void drawFood(Graphics g) {
private void drawWorld(Graphics g) {
byte brick;
for (int x = 0; x < ENV_WIDTH; x++)
for (int y = 0; y < ENV_HEIGHT; y++)
if (foods[x][y]) {
g.fillOval(x, y, 4, 4);
for (int y = 0; y < ENV_HEIGHT; y++) {
brick = bricks[x][y];
if (brick != 0) {
g.setColor(Material.color(brick));
if (brick == Material.FOOD)
g.fillRoundRect(x, y, 4, 4, 2, 2); // show food bigger
else
g.drawLine(x, y, x, y); // only 1 point
}
}
private void drawTrap(Graphics g) {// 所有走到陷阱边沿上的的青蛙都死掉
g.fillRect(ENV_HEIGHT / 2 - TRAP_WIDTH / 2, ENV_HEIGHT / 2 - TRAP_HEIGHT / 2, TRAP_WIDTH, TRAP_HEIGHT);
g.setColor(Color.white);
g.fillRect(ENV_HEIGHT / 2 - TRAP_WIDTH / 2 + 3, ENV_HEIGHT / 2 - TRAP_HEIGHT / 2 + 3, TRAP_WIDTH - 6,
TRAP_HEIGHT - 6);
g.setColor(Color.black);
}
g.setColor(Color.BLACK);
}
static final NumberFormat format100 = NumberFormat.getPercentInstance();
@ -170,7 +148,7 @@ public class Env extends JPanel {
int leftfood = 0;
for (int x = 0; x < ENV_WIDTH; x++)
for (int y = 0; y < ENV_HEIGHT; y++)
if (foods[x][y])
if (bricks[x][y] == 1)
leftfood++;
return FOOD_QTY - leftfood;
}
@ -182,7 +160,7 @@ public class Env extends JPanel {
if (f.ateFood > maxFound)
maxFound = f.ateFood;
return new StringBuilder("找食率:").append(format100.format(foodFound * 1.00 / FOOD_QTY)).append(", 平均: ")
.append(foodFound * 1.0f / (EGG_QTY * FROG_PER_EGG)).append(",最多:").append(maxFound).toString();
.append(foodFound * 1.0f / FROG_PER_SCREEN).append(",最多:").append(maxFound).toString();
}
private static void sleep(long millis) {
@ -207,19 +185,21 @@ public class Env extends JPanel {
do {
sleep(300);
} while (pause);
rebuildFood();
for (Object thing : things) // 创建食物陷阱等物体
thing.build();
boolean allDead = false;
Frog firstFrog = frogs.get(screen * FROG_PER_SCREEN);
for (int i = 0; i < STEPS_PER_ROUND; i++) {
for (Object thing : things)// 调用食物陷阱等物体的动作
thing.active(screen);
if (allDead)
break; // 青蛙全死光了就直接跳到下一轮,以节省时间
allDead = true;
for (int j = 0; j < FROG_PER_SCREEN; j++) {
Frog f = frogs.get(screen * FROG_PER_SCREEN + j);
if (f.active(this))
allDead = false;
if (f.alive && RandomUtils.percent(0.2f)) {// 有很小的机率在青蛙活着时就创建新的器官
if (f.alive && RandomUtils.percent(0.5f)) {// 有很小的机率在青蛙活着时就创建新的器官
RandomConnectGroup newConGrp = new RandomConnectGroup();
newConGrp.initFrog(f);
f.organs.add(newConGrp);
@ -236,6 +216,7 @@ public class Env extends JPanel {
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.BLACK);
drawWorld(g);
for (int j = 0; j < FROG_PER_SCREEN; j++) {
Frog f = frogs.get(screen * FROG_PER_SCREEN + j);
f.show(g);
@ -250,16 +231,16 @@ public class Env extends JPanel {
if (DRAW_BRAIN_AFTER_STEPS > 0 && i % DRAW_BRAIN_AFTER_STEPS == 0)
Application.brainPic.drawBrainPicture(firstFrog);
}
drawTrap(g);
drawFood(g);
Graphics g2 = this.getGraphics();
g2.drawImage(buffImg, 0, 0, this);
}
Application.brainPic.drawBrainPicture(firstFrog);
Application.mainFrame.setTitle(new StringBuilder("Round: ").append(round).append(", screen:")
.append(screen).append(", ").append(foodFoundCountText()).append(", 用时: ")
.append(System.currentTimeMillis() - time0).append("ms").toString());
.append(System.currentTimeMillis() - time0).append("ms").append(", energy:")
.append(firstFrog.energy).toString());
for (Object thing : things)// 去除食物陷阱等物体
thing.destory();
}
round++;
EggTool.layEggs();

View File

@ -21,6 +21,7 @@ import javax.imageio.ImageIO;
import com.github.drinkjava2.frog.brain.Cell;
import com.github.drinkjava2.frog.brain.Organ;
import com.github.drinkjava2.frog.egg.Egg;
import com.github.drinkjava2.frog.objects.Material;
/**
* Frog = organs + brain cells
@ -63,14 +64,16 @@ public class Frog {
}
public boolean active(Env v) {
if (!alive || energy < 0 || Env.outsideEnv(x, y) || Env.inTrap(x, y)) {// 如果能量小于0则死
energy -= 100; // 死掉的青蛙也要消耗能量保证淘汰出局
// 如果能量小于0则死出界与非食物的点重合则判死
if (!alive || energy < 0 || Env.outsideEnv(x, y) || Env.bricks[x][y] >= Material.KILLFROG) {
energy -= 100; // 死掉的青蛙也要消耗能量确保淘汰出局
alive = false;
return false;
}
energy -= 20;
for (Organ o : organs)
for (Organ o : organs) {
o.active(this);
}
return alive;
}

View File

@ -52,7 +52,7 @@ public class RandomConnectGroup extends Group {
x = Env.FROG_BRAIN_WIDTH / 2;
y = Env.FROG_BRAIN_WIDTH / 2;
r = Env.FROG_BRAIN_WIDTH / 2;
inputZone = RandomUtils.randomPosInAnyFrogOrgan(f);
inputZone = RandomUtils.randomPosMostInNewEye(f);
outputZone = RandomUtils.randomPosInAnyFrogOrgan(f);
}

View File

@ -22,7 +22,7 @@ public class Eat extends Organ {// Eat这个类将食物转化为能量能量
@Override
public void active(Frog f) {
if (Env.foundAndDeleteFood(f.x, f.y)) {
if (Env.foundAndAteFood(f.x, f.y)) {
f.ateFood++;
// 所有的硬编码都是bug包括这个1000
f.energy += 1000;// 如果青蛙的坐标与食物重合吃掉food能量境加

View File

@ -58,7 +58,7 @@ public class Eye extends Organ {// 这个Eye是老版的眼睛只能看到四
@Override
public Organ[] vary() {
if (RandomUtils.percent(5)) {
if (RandomUtils.percent(5)) { // 可视距离有5%的机率变异
seeDistance = seeDistance + 1 - 2 * RandomUtils.nextInt(2);
if (seeDistance < 1)
seeDistance = 1;
@ -78,55 +78,55 @@ public class Eye extends Organ {// 这个Eye是老版的眼睛只能看到四
Zone seeLeft = new Zone(x - q3Radius, y, qRadius);
Zone seeRight = new Zone(x + q3Radius, y, qRadius);
boolean seeFood = false;
boolean foodAtUp = false;
boolean foodAtDown = false;
boolean foodAtLeft = false;
boolean foodAtRight = false;
boolean seeSomething = false;
boolean atUp = false;
boolean atDown = false;
boolean atLeft = false;
boolean atRight = false;
for (int i = 1; i < seeDistance; i++)
if (Env.foundFood(f.x, f.y + i)) {
seeFood = true;
foodAtUp = true;
if (Env.foundAnyThing(f.x, f.y + i)) {
seeSomething = true;
atUp = true;
break;
}
for (int i = 1; i < seeDistance; i++)
if (Env.foundFood(f.x, f.y - i)) {
seeFood = true;
foodAtDown = true;
if (Env.foundAnyThing(f.x, f.y - i)) {
seeSomething = true;
atDown = true;
break;
}
for (int i = 1; i < seeDistance; i++)
if (Env.foundFood(f.x - i, f.y)) {
seeFood = true;
foodAtLeft = true;
if (Env.foundAnyThing(f.x - i, f.y)) {
seeSomething = true;
atLeft = true;
break;
}
for (int i = 1; i < seeDistance; i++)
if (Env.foundFood(f.x + i, f.y)) {
seeFood = true;
foodAtRight = true;
if (Env.foundAnyThing(f.x + i, f.y)) {
seeSomething = true;
atRight = true;
break;
}
if (seeFood)
if (seeSomething)
for (Cell cell : f.cells) {
if (cell.energy < 100)
for (Input input : cell.inputs) {
if (input.nearby(this)) {
if (foodAtUp && input.nearby(seeUp)) {
if (atUp && input.nearby(seeUp)) {
input.cell.energy += organOutputEnergy;
}
if (foodAtDown && input.nearby(seeDown)) {
if (atDown && input.nearby(seeDown)) {
input.cell.energy += organOutputEnergy;
}
if (foodAtLeft && input.nearby(seeLeft)) {
if (atLeft && input.nearby(seeLeft)) {
input.cell.energy += organOutputEnergy;
}
if (foodAtRight && input.nearby(seeRight)) {
if (atRight && input.nearby(seeRight)) {
input.cell.energy += organOutputEnergy;
}
}

View File

@ -18,7 +18,6 @@ import com.github.drinkjava2.frog.brain.Cell;
import com.github.drinkjava2.frog.brain.Input;
import com.github.drinkjava2.frog.brain.Organ;
import com.github.drinkjava2.frog.brain.Zone;
import com.github.drinkjava2.frog.util.RandomUtils;
/**
* Eye is an organ can see environment, and active brain cells which inputs are
@ -29,7 +28,7 @@ import com.github.drinkjava2.frog.util.RandomUtils;
*/
public class NewEye extends Organ {// 这个新版的眼睛有nxn个感光细胞可以看到青蛙周围nxn网络内有没有食物
private static final long serialVersionUID = 1L;
public int n = 3; // 眼睛有n x n个感光细胞 用随机试错算法自动变异(加1或减1最小是3x3)
public int n = 13; // 眼睛有n x n个感光细胞 用随机试错算法自动变异(加1或减1最小是3x3)
@Override
public void initFrog(Frog f) { // 仅在Frog生成时这个方法会调用一次缺省啥也不干通常用于Organ类的初始化
@ -60,13 +59,13 @@ public class NewEye extends Organ {// 这个新版的眼睛有nxn个感光细胞
@Override
public Organ[] vary() {
if (RandomUtils.percent(50)) {
n = n + 1 - 2 * RandomUtils.nextInt(2);
if (n < 3)
n = 3;
if (n > 12)
n = 12;
}
// if (RandomUtils.percent(50)) {
// n = n + 1 - 2 * RandomUtils.nextInt(2);
// if (n < 3)
// n = 3;
// if (n > 12)
// n = 12;
// }
return new Organ[] { this };
}

View File

@ -22,7 +22,6 @@ import java.util.List;
import com.github.drinkjava2.frog.Application;
import com.github.drinkjava2.frog.Env;
import com.github.drinkjava2.frog.Frog;
import com.github.drinkjava2.frog.brain.Organ;
import com.github.drinkjava2.frog.brain.organ.Chance;
import com.github.drinkjava2.frog.brain.organ.Eye;
import com.github.drinkjava2.frog.util.FrogFileUtils;
@ -47,13 +46,6 @@ public class EggTool {
Frog first = Env.frogs.get(0);
Frog last = Env.frogs.get(Env.frogs.size() - 1);
if (Env.DEBUG_MODE)
for (int i = 0; i < first.organs.size(); i++) {
Organ org = first.organs.get(i);
System.out.println("Organ(" + i + ")=" + org + ", fat=" + org.fat + ", organWasteEnergy="
+ org.organActiveEnergy + ", outputEnergy=" + org.organOutputEnergy);
}
try {
Env.eggs.clear();
for (int i = 0; i < Env.EGG_QTY; i++)
@ -65,7 +57,7 @@ public class EggTool {
System.out.print("\r1st frog has " + first.organs.size() + " organs, energy=" + first.energy + ", seeDist="
+ ((Eye) first.organs.get(6)).seeDistance + ", chance=" + ((Chance) first.organs.get(10)).percent);
System.out.println(", Last frog has " + last.organs.size() + " organs, energy=" + last.energy);
System.out.println("Saved 1 group eggs to file '" + Application.CLASSPATH + "eggs.ser'");
System.out.println("Saved "+Env.eggs.size() +" eggs to file '" + Application.CLASSPATH + "eggs.ser'");
} catch (IOException e) {
System.out.println(e);
}

View File

@ -0,0 +1,48 @@
/* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
* applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
* OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package com.github.drinkjava2.frog.objects;
import static com.github.drinkjava2.frog.Env.ENV_HEIGHT;
import static com.github.drinkjava2.frog.Env.ENV_WIDTH;
import static com.github.drinkjava2.frog.Env.FOOD_QTY;
import static com.github.drinkjava2.frog.Env.bricks;
import com.github.drinkjava2.frog.util.RandomUtils;
/**
* Food randomly scatter on Env
*
* @author Yong Zhu
* @since 1.0
*/
public class Food implements Object {
@Override
public void build() {
for (int i = 0; i < FOOD_QTY; i++) // 生成食物
bricks[RandomUtils.nextInt(ENV_WIDTH)][RandomUtils.nextInt(ENV_HEIGHT)] = Material.FOOD;
}
@Override
public void destory() {
for (int i = 0; i < ENV_WIDTH; i++) {// 清除食物
for (int j = 0; j < ENV_HEIGHT; j++)
if (bricks[i][j] == Material.FOOD)
bricks[i][j] = 0;
}
}
@Override
public void active(int screen) {
// Food do not have any active
}
}

View File

@ -0,0 +1,40 @@
/* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
* applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
* OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package com.github.drinkjava2.frog.objects;
import java.awt.Color;
/**
* Object means some thing in Env
*
* @author Yong Zhu
* @since 1.0
*/
public class Material {
public static final byte VISIBLE = 10; // if>=10 will visible to frog
public static final byte KILLFROG = 20; // if>=20 will kill frog
public static final byte NO = 0;
public static final byte SEESAW_BASE = 1; // 1~9 is invisible to frog
public static final byte FOOD = VISIBLE + 1;
public static final byte SEESAW = VISIBLE + 2; // if <0 will not cause frog die
public static final byte BRICK = KILLFROG + 1;
public static final byte TRAP = KILLFROG + 2;
public static Color color(byte material) {
if (material == TRAP)
return Color.LIGHT_GRAY;
else
return Color.BLACK;
}
}

View File

@ -0,0 +1,26 @@
/* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
* applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
* OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package com.github.drinkjava2.frog.objects;
/**
* Object means some thing in Env
*
* @author Yong Zhu
* @since 1.0
*/
public interface Object {
public void build();
public void destory();
public void active(int screen);
}

View File

@ -0,0 +1,93 @@
/* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
* applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
* OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package com.github.drinkjava2.frog.objects;
import static com.github.drinkjava2.frog.Env.ENV_HEIGHT;
import static com.github.drinkjava2.frog.Env.ENV_WIDTH;
import static com.github.drinkjava2.frog.Env.bricks;
import com.github.drinkjava2.frog.Env;
import com.github.drinkjava2.frog.Frog;
import com.github.drinkjava2.frog.util.RandomUtils;
/**
* This is a seesaw to train frog's balance
*
* @author Yong Zhu
* @since 2.0.1
*/
public class SeeSaw implements Object {
private static final int LEGNTH = 300;
private static final int CENTER_X = Env.ENV_WIDTH / 2;
private static final int CENTER_Y = Env.ENV_HEIGHT / 2;
private double angle = 0;// -PI/4 to PI/4
private double leftWeight = 0;
private double rightWeight = 0;
@Override
public void build() {
angle = 0;
}
@Override
public void destory() {
}
@Override
public void active(int screen) {
for (int i = 0; i < ENV_WIDTH; i++) {// 清除食物
for (int j = 0; j < ENV_HEIGHT; j++)
if (bricks[i][j] == Material.SEESAW)
bricks[i][j] = 0;
}
if (RandomUtils.percent(2))
leftWeight = RandomUtils.nextFloat() * 3;
if (RandomUtils.percent(2))
rightWeight = RandomUtils.nextFloat() * 3;
Frog f = Env.frogs.get(screen);
if (f.x < (CENTER_X - LEGNTH / 2) || f.x > (CENTER_X + LEGNTH / 2))
f.energy -= 100000; // 如果走出跷跷板外则扣分出局
double left = leftWeight - (f.x - CENTER_X);
double right = rightWeight + (f.x - CENTER_X);
// right - left need in -100 to +100
angle = angle + (right - left) * Math.PI * .000001;
if (angle > Math.PI / 6) {
angle = Math.PI / 6;
f.energy -= 200;
}
if (angle < -Math.PI / 6) {
angle = -Math.PI / 6;
f.energy -= 200;
}
f.y = CENTER_Y + (int) Math.round((f.x - CENTER_X) * Math.tan(angle));
f.energy -= Math.abs(angle) * 180; // 角度越大扣分越多
int x;
int y;
for (int l = -LEGNTH / 2; l <= LEGNTH / 2; l++) {
x = (int) Math.round(l * Math.cos(angle));
y = (int) Math.round(l * Math.sin(angle));
Env.bricks[CENTER_X + x][CENTER_Y + y] = Material.SEESAW;
}
// 画底座
for (int i = 1; i < 10; i++) {
Env.bricks[CENTER_X - i][CENTER_Y + i] = Material.SEESAW_BASE;
Env.bricks[CENTER_X + i][CENTER_Y + i] = Material.SEESAW_BASE;
}
for (int i = -10; i < 10; i++)
Env.bricks[CENTER_X + i][CENTER_Y + 10] = Material.SEESAW_BASE;
}
}

View File

@ -0,0 +1,56 @@
/* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
* applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
* OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package com.github.drinkjava2.frog.objects;
import static com.github.drinkjava2.frog.Env.ENV_HEIGHT;
import static com.github.drinkjava2.frog.Env.ENV_WIDTH;
import static com.github.drinkjava2.frog.Env.bricks;
import com.github.drinkjava2.frog.Frog;
/**
* Trap will kill all frogs inside of it, if frog's position has material and
* it's not food, frog will die
*
* @author Yong Zhu
* @since 2019-08-05
*/
@SuppressWarnings("all")
public class Trap implements Object {
private static final int X1 = ENV_WIDTH / 2 - 350 / 2; // 陷阱左上角
private static final int Y1 = ENV_HEIGHT / 2 - 20 / 2; // 陷阱左上角
private static final int X2 = ENV_WIDTH / 2 + 350 / 2; // 陷阱右下角
private static final int Y2 = ENV_HEIGHT / 2 + 20 / 2; // 陷阱右下角
@Override
public void build() {
for (int x = X1; x <= X2; x++)
for (int y = Y1; y <= Y2; y++)
bricks[x][y] = Material.TRAP;
}
@Override
public void destory() {
for (int x = X1; x <= X2; x++)
for (int y = Y1; y <= Y2; y++)
bricks[x][y] = 0;
}
@Override
public void active(int screen) {
}
public static boolean inTrap(Frog f) {
return f.x >= X1 && f.x <= X2 && f.y >= Y1 && f.y <= Y2;
}
}

View File

@ -46,64 +46,70 @@ public class RandomUtils {
return randomZoneInZone(f.organs.get(RandomUtils.nextInt(Egg.FIXED_ORGAN_QTY)));
}
/** Return a random zone inside of frog's random organ */
public static Zone randomPosMostInNewEye(Frog f) {
if (f.organs == null || f.organs.size() == 0)
throw new IllegalArgumentException("Can not call randomPosInRandomOrgan method when frog has no organ");
if (RandomUtils.percent(95))
return randomZoneInZone(f.organs.get(7));// 这是一个硬编码大部分新联接建立在newEye中
return randomZoneInZone(f.organs.get(RandomUtils.nextInt(Egg.FIXED_ORGAN_QTY)));
}
public static boolean percent(float percent) {
return rand.nextFloat() * 100 < percent;
}
// /** vary a zone position, size a little bit */
// public static void varyZone(Zone z) {
// int i = rand.nextInt(100);
// if (i < 95) // 有95的机率不变异
// return;
// z.x = varyByRate(z.x, 0.01f);
// z.y = varyByRate(z.y, 0.01f);
// z.r = varyByRate(z.r, 0.03f);
// }
// public static float varyByRate(float f, float rate) { // 用指定的机率变异
// boolean bigger = rand.nextInt(2) > 0;
// if (bigger)
// f = f + f * rate * rand.nextFloat() + .001f;
// else
// f = f - f * rate * rand.nextFloat() - .001f;
// if (Float.isNaN(f))
// f = 0f;
// if (f > 1000000f)
// f = 1000000f;
// else if (f < -1000000f)
// f = -1000000f;
// return f;
// }
// /** vary a zone position, size a little bit */
// public static void varyZone(Zone z) {
// int i = rand.nextInt(100);
// if (i < 95) // 有95的机率不变异
// return;
// z.x = varyByRate(z.x, 0.01f);
// z.y = varyByRate(z.y, 0.01f);
// z.r = varyByRate(z.r, 0.03f);
// }
// public static float vary(float f) { // 大部分时候不变有极小机会变异,有极极小机会大变异有极极极小机会大大大变异
// int i = rand.nextInt(100);
// if (i < 50) // 有50的机率不变异
// return f;
// float rate = 0.2f; // 50%机率在0.2倍范围变异
// if (i > 80)
// rate = 1f; // 有20%的机率在1倍的范围变异
// if (i > 90)
// rate = 10f; // 有10%的机率在10倍的范围变异
// if (i > 95)
// rate = 100f; // 有5%的机率在100倍的范围变异
// if (i > 98)
// rate = 1000f; // 有1%的机率在1000倍的范围变异
//
// boolean bigger = rand.nextInt(2) > 0;
// if (bigger)
// f = f + f * rate * rand.nextFloat() + .001f;
// else
// f = f - f * rate * rand.nextFloat() - .001f;
// if (Float.isNaN(f))
// f = 0f;
// if (f > 1000000f)
// f = 1000000f;
// else if (f < -1000000f)
// f = -1000000f;
// return f;
// }
// public static float varyByRate(float f, float rate) { // 用指定的机率变异
// boolean bigger = rand.nextInt(2) > 0;
// if (bigger)
// f = f + f * rate * rand.nextFloat() + .001f;
// else
// f = f - f * rate * rand.nextFloat() - .001f;
// if (Float.isNaN(f))
// f = 0f;
// if (f > 1000000f)
// f = 1000000f;
// else if (f < -1000000f)
// f = -1000000f;
// return f;
// }
// public static float vary(float f) { // 大部分时候不变有极小机会变异,有极极小机会大变异有极极极小机会大大大变异
// int i = rand.nextInt(100);
// if (i < 50) // 有50的机率不变异
// return f;
// float rate = 0.2f; // 50%机率在0.2倍范围变异
// if (i > 80)
// rate = 1f; // 有20%的机率在1倍的范围变异
// if (i > 90)
// rate = 10f; // 有10%的机率在10倍的范围变异
// if (i > 95)
// rate = 100f; // 有5%的机率在100倍的范围变异
// if (i > 98)
// rate = 1000f; // 有1%的机率在1000倍的范围变异
//
// boolean bigger = rand.nextInt(2) > 0;
// if (bigger)
// f = f + f * rate * rand.nextFloat() + .001f;
// else
// f = f - f * rate * rand.nextFloat() - .001f;
// if (Float.isNaN(f))
// f = 0f;
// if (f > 1000000f)
// f = 1000000f;
// else if (f < -1000000f)
// f = -1000000f;
// return f;
// }
}

BIN
eggs.ser Normal file

Binary file not shown.

BIN
result5_seesaw.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

View File

@ -40,19 +40,18 @@ Frog
#### Env模块
见Env.java这个模块模拟一个生物生存区用不同形状的图形点阵来表达和模拟食物、天敌、障碍等物体这个虚拟空间由程序员全权控制和设计将随着Frog的脑进化而不断变得越来越复杂通过完成人为设计的一个又一个任务来引导青蛙的进化。
Env.java中的可调整参数说明:
Env.java中的可调整参数说明(请手工修改这些参数进行不同的测试前5个参数很重要):
```
SHOW_SPEED 调整实验的速度(1~1000),值越小则越慢。
DELETE_EGGS: 每次运行是否先删除保存的蛋,如果设为false将不删除保存的蛋会接着上次的测试结果续继运行。
EGG_QTY: 每次允许Frog下多少个蛋通常下蛋取值在10~1000之间。蛋保存着我们测试的结果。实验的最终目标就是获得一批蛋。
FROG_PER_EGG 每个蛋可以孵出多少个青蛙。
SCREEN 分屏测试,一轮测试可以分为多个批次进行,这里是屏数。每轮总的青蛙数量=EGG_QTY * FROG_PER_EGG, 每屏青蛙数=总数/SCREEN
ENV_WIDTH: 虚拟环境的宽度大小通常取值100~1000左右
ENV_HEIGHT: 虚拟环境高度大小通常取值100~1000左右
FROG_BRAIN_DISP_WIDTH: Frog的脑图在屏幕上的显示大小,通常取值100~1000左右
STEPS_PER_ROUND: 每轮测试步数, 每一步相当于脑思考的一桢,所有青蛙的脑神经元被遍历一次。
EGG_QTY: 每次允许Frog下多少个蛋通常下蛋取值在10~1000之间。蛋保存着我们测试的结果。实验的最终目标就是获得一批蛋。
FROG_PER_EGG 每个蛋可以孵出多少个青蛙。
SCREEN 分屏测试,一轮测试可以分为多个批次进行,这里是屏数。每轮总的青蛙数量=EGG_QTY * FROG_PER_EGG * SCREEN
STEPS_PER_ROUND: 每轮测试步数, 每一步相当于脑思考的一桢,所有青蛙的脑神经元被遍历一次。
FOOD_QTY食物的数量食物越多则Frog的生存率就越高能量排名靠前的一批Frog可以下蛋其余的被淘汰。
DELETE_EGGS: 每次运行是否先删除保存的蛋,如果设为false将不删除保存的蛋会接着上次的测试结果续继运行。
DEBUG_MODE: 调试模式开关,如开启会打印出更多的调试信息
```
#### Frog模块
见Frog.java, 这是人工生命的主体,目前起名叫青蛙(Frog)其实叫什么都一样。Frog不是生命的全盘模拟它主要模拟生物的脑结构和功能它主要具备以下与脑功能相关的器官
@ -70,3 +69,4 @@ Group.java
Group.java类的DrawOnBrainPicture方法需要重写每个Group实例负责自已在脑图上的显示绘制。
目前青蛙脑还没有引入更多的算法(如记忆、模式识别功能),也就是说这个青蛙的开发还处在起步阶段,脑的结构是程序员要解决的问题,也是要获取的最终目标。脑模型的生成由电脑优胜夯汰、循环迭代进化生成,但这个模型的进化过程还是必须由程序员来掌控,一步步探索出来。
另外这个项目不要局限于已有的编码,而要着眼于它的总体思路,大胆试错,现有的编码只是暂时的,随时都可能被推翻。

View File

@ -1,11 +1,16 @@
## 版本提交记录
如果想要运行这个项目的以前版本可以结合gitk命令和参考"版本提交记录.md"的介绍用git reset命令回复到以前任一个版本例如用:
git reset --hard ae34b07e 可以转回到2019-08-04提交的分组测试的找食版本。
### 2018-1-3
项目启动,主要是文字方面的一些构想。
### 2019-3-11 1.0.0版, Commit:Go frog go!
开发环境完成演示第一个人工生命诞生。但是所有Frog脑部为空因为运动神经元被短路只能固定向一个方向运动。
这是第一个发布版,演示了生命的随机进化和优胜劣汰。
这是第一个发布版,演示了生命的随机进化和优胜劣汰。
![result1](https://gitee.com/drinkjava2/frog/raw/master/result1.gif)
### 2019-3-18, Commit:Brain picture!
添加了脑结构图形用于调试用可以显示第一个胜出的Frog的脑结构但是运动神经元依然被短路只能固定向一个方向运动。
@ -37,14 +42,16 @@
下面要考虑逻辑了,也就是思考判断能力(后天条件反射的建立)。
### 2019-04-12, Commit:Random frog
没做大改动,只是将青蛙改成按整个地图随机分布,看起来眼睛的作用就比较明显了,比起随机运动,明显食物被吃掉更多。
没做大改动,只是将青蛙改成按整个地图随机分布,看起来眼睛的作用就比较明显了,比起随机运动,明显食物被吃掉更多。
![resut2](https://gitee.com/drinkjava2/frog/raw/master/result2.gif)
### 2019-05-23, Commit:2 eyes no helps
没做大改动只是演示添加两个眼睛后对它的进化没有帮助到此为此逐渐看出问题了没有记忆能力和模式识别能力。目前存在两个比较大的硬编码导致它不能进一步进化1.用CellGroup这种硬编码方式导致在Frog的生存期不能产生记忆功能而需要多次淘汰这不符合现实中青蛙从小学到大这样的实际过程它不需要死很多次。另一个问题是眼睛部分存在硬编码因此只能起到感光作用但是不具备根据外在图像进行模式识别能力。所以下面要开始进行非常大的结构改进。将把CellGroup作为器官引入但是它的内部细胞是动态生成的而且不是随机生成的而是任两个细胞在它的区内活跃就生成新的细胞(将来也可以参与新建细胞)。CellGroup的数量、大小、网格密度直接影响到神经元生成多少和算法快慢)会参与遗传和进化快乐和痛苦器官会对新细胞生成的类型有影响。fat参数用来指示它的肥胖度。Fat高的遗传时会保留并可能变大、变小、内部允行连接数更多、分化成更多CellGroup但是它的内部连接(新建的细胞)不会参与遗传这样每个个体都出生时都是一张白纸虽然也许CellGroup已经进化得很多层很复杂。同一个位置可以存在多个CellGroup,这样由多层大小、位置不同的Layer就同时具备了模式识别和记忆功能而且这个算法比较简单很好理解。大范围的Cellgroup可以解释条件反射的形成两件不相干的事之间形成联系)小范围的Cellgroup可以解释模式识别相邻感光细胞同时激活经过层层处理后汇总到最上层的某个Cellgroup的激活)。而所有这些CellGroup的形成(结构和层级)都可以用非常简单的"用进废退"规则(Fat值控制遗传、随机变异和适者生存来探索最优解)来最终进化出来。
### 2019-06-13, Commit: Happy & Pain
主要做了一些清理,将所有器官移到单独的类里删除OrganDesc类。将一些类(如Applicaton移到根包下)移到不同的包下。这个版本是比较大的一个重构,最大的进步是将算法当成一个器官引入,当然,这个版本只存在一个随机连接两端的算法,以后会扩充。
另外顺手加上了Happy和Pain两个器官分别对应进食愉快感和痛苦感后者在靠近边界时激发。观查它的表现果然不出所料痛苦感立即生效有一些Frog移动到边界后就不再前进而是顺着边界溜下去了不傻但是Happy器官没有生效这也很显然因为Happy属于进食反射链的一部分在没有记忆器官算法引入之前是没有途径使用上进食奖励信号的。
另外顺手加上了Happy和Pain两个器官分别对应进食愉快感和痛苦感后者在靠近边界时激发。观查它的表现果然不出所料痛苦感立即生效有一些Frog移动到边界后就不再前进而是顺着边界溜下去了不傻但是Happy器官没有生效这也很显然因为Happy属于进食反射链的一部分在没有记忆器官算法引入之前是没有途径使用上进食奖励信号的。
![resut3](https://gitee.com/drinkjava2/frog/raw/master/result3.gif)
### 2019-06-26, Commit: Back to many connections
找食效率太低又改回到4.12的用连接数量代替权值这个逻辑权值这种人为设计的算法居然比不过随机试错失败。先暂时去掉Pain器官Pain的加入并没有提高找食效率必须与感光细胞合用才能知道是哪个方向的边界下个版本急需引入记忆功能也就是说要将感光细胞的活跃和痛苦器官的活跃关联起来。
@ -57,6 +64,14 @@
2. 青蛙增加一个Active器官它的作用是一直保持激活如果有神经元触突位于这个区就会驱动神经元兴奋这个器官经实践证明比Hungry器官驱动更能提高找食效率。
3. 青蛙增加一个Chance器官,它的作用是引入随机扰动,打破青蛙有时候围着一个食物打转就是吃不着的死循环。
从当前这个版本可以看出,实际上青蛙是有一定的记忆能力的,连接就=记忆只不过没有模式识别能力以后的工作将以模式识别为重点基本原理是见note中提到的仿照全息存储原理在思维区逆向成像。因为逆向成像的限制以后的版本所有的器官会被移到脑图的同一侧不再是随意分布在脑图上了这将是一个比较明显的改动。当然随机连接这个算法看起来比较有用以后还是可能保留的。
以下为运行图像:
![resut4](https://gitee.com/drinkjava2/frog/raw/master/result4.gif)
### 2019-08-04, Commit: Screen group test
引入分屏测试功能如果青蛙数量多可以分屏来测试每屏青蛙的数量可以少到只有1只。
### 2019-08-04, Commit: Screen group test
引入分屏测试功能如果青蛙数量多可以分屏来测试每屏青蛙的数量可以少到只有1只。
2019-08-05 commit: Seesaw
有了分屏测试功能后,顺便随手加上了一个青蛙走跷跷板自动平衡的演示,它每次只出场一个青蛙, 每轮包括100场测试大约跑90多轮半个小时(电脑慢)后,出现了下面的画面:
![result5](https://gitee.com/drinkjava2/frog/raw/master/result5_seesaw.gif)
这个版本的目的是为了增加一点趣味性,显得青蛙还是有点"用处"的,省得让人以为这个项目不务正业,只会让青蛙找食。这个版本青蛙的脑结构和找食版的青蛙基本相同,区别只是在于环境不同,也就是说它的表现随着环境而变化,这符合"通用人工智能"的概念,即信号感受器官是统一的(通常是眼睛)但能根据不同的环境完成不同的任务。走跷跷板演示是最后一个2维脑的版本今后这个项目将沉寂一段较长时间今后将致力于将青蛙脑重构为3D金字塔形脑结构(见上文)因为这个项目的缺点已经很明显它不具备对2维图像的模式识别能力用随机试错的方式只能处理非常简单的、信号在视网膜的固定区域出现的图像信号。
青蛙的找食效率以及走跷跷板平衡的能力都没有优化到顶点,一些构想中的复杂的器官如“与门”、“或门”(不要怀疑大自然能否进化出这些复杂器官)等都没加上但我认为这不重要目前最高优先级是先进行3D脑结构建模让青蛙能具备2维图形的模式识别(和回忆)功能,这个大的架构重构是它能处理复杂图像信息的立足之本,它的图像识别能力和通常的用上千张图片来训练识别一个图片这种工作模式不同,它是一种通用的,可自动分类识别所有图像的模式,更符合动物脑的工作模式,记住并回忆出某个图像(或任意输入信号场景的组合),可能只需要这种场景重复出现过几次即可,它是一种无外界信号判定,自动分类的识别模式。