Screen group test

pull/1/head
Yong Zhu 6 years ago
parent b090d746be
commit ae34b07e21

@ -1,5 +1,4 @@
## Frog | 人工生命
(English introduction please see "README_EN.md")
这是一个人工生命试验项目最终目标是创建“有自我意识表现”的模拟生命体技术架构基于02年提出的 [一个人工脑模型](一个人工脑模型.md)。
这个项目永远没有结束的时候,开始于模拟一个简单的生命体,然后是青蛙、狗......, 结束于有“自我意识表现”的人工脑,或者说,结束于被机器人代替人类的那一天。
@ -59,6 +58,7 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什
运行run.bat可以查看演示需要安装Java8和Maven
![result1](https://gitee.com/drinkjava2/frog/raw/master/result1.gif)
另外每步演示的结果(egg)会存盘在根目根目录下名为egg.ser可以删除这个文件以从头开始新的测试。因为还没涉及脑模型的搭建可以看到有些青蛙跑得飞快这是自然选择的结果因为跑在最前面的吃得多。
一些重要的测试参数如显示区大小、是否每次测试要删除保存的蛋等请参见Env.java中开头的常量设定可以手工修改进行不同参数的测试。
2019.03.21 添加了脑图改进随机运动模式为Hungry区驱动。从脑图上可以直观地观察脑结构方便调试。
2019.04.01 改进脑图的显示bug, 每一次生成Frog时添加随机神经元并简单实现"卵+精子->受精卵"算法,以促进种群多样性。
2019-04-12 添加一个简单的眼睛(只有四个感光细胞),自然选择的结果是眼睛被选中,但是和运动区短路了,谈不上智能。但有眼睛后找食效率明显提高了,见下图:
@ -75,13 +75,14 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什
另外发现青蛙其实是有记忆能力的,因为连接本身就是一种记忆,只不过它没有复杂的模式识别能力,例如给个蛇的图片它就认不出来。以后的工作将以模式识别为重点(当然随机连接看起来很有用,以后还可能保留)基本原理是见note中提到的仿照波传播及全息存储原理在思维区逆向成像。而且脑可能改成三维结构并根据逆向成像原理要将所有输入输出器官全移到三维结构的同一侧(即思维区)。这将会是一个非常大的改动下面我简单画了一个3D示意图来说明我想象中的这个模式识别和记忆的原理至于对不对还需要实验来验证:
![3d-model](https://gitee.com/drinkjava2/frog/raw/master/3d-model.gif)
这个模型的最顶层表示眼睛的感光细胞(或任意输入输出细胞),同时也是思维区,红色表示一个长条的图形,兰色表示一个三角图形,如果这两个图形经常有规律地同时出现,就会把它们共有的节点撑大,见紫色的节点,当红色图形单独出现,就会强烈激活紫色节点,然后紫色节点的信号反向传播,就会激活三角图形,反之亦然。这就同时解释了模式识别和记忆(或者说回忆)功能的的原理。一个节点可以被多个感光细胞共享,所以它的存储能力是很强的。而且可能这个原理比较符合生物脑结构。当然,实际编程时,虚拟神经元不一定要排成正立方三角,而可能通过胡乱排放,大致上过得去就行了,也许能乱拳打死老师傅,最终要靠电脑自动随机的排放,然后用优胜劣汰来筛选。目前有个难点是这个记忆功能在思维区成像是如何有条不紊地大体上按串行进行工作的,这个问题先放一放。
2019-08-04 更新了一个分组测试功能,如果测试青蛙数量太多,可以分批来测试,每轮测试最少的青蛙数量可以少到只有一个,这是用时间来换空间。
## 版权 | License
[Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0)
## 期望 | Futures
欢迎发issue提出建意或加入开发组,尤其欢迎能接触到超级计算机的同学加入,随着神经元数量增多,对电脑的速度要求会越来越高,很快将达到台式机性能瓶颈,只能通过拖长运行时间来换取大样本数量了。
另外本项目正式宣布开启哭穷模式比提交一个pull request还能帮助这个项目开发的莫过于提交一个红包了您的赞助将实实在在地转化成我(或其它开发者)的项目开发时间,本项目将建立赞助者名单及收支明细账。
欢迎发issue、私信等方式提出建议或加入开发组。
另外本项目开启哭穷模式比提交一个pull request还能帮助这个项目开发的莫过于提交一个红包了金钱就是时间,您的捐助将只会用于回馈本项目的实际参与开发者。
## 作者其它开源项目 | Other Projects
- [Java持久层工具 jSqlBox](https://gitee.com/drinkjava2/jSqlBox)
@ -92,4 +93,4 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什
## 关注我 | About Me
[Github](https://github.com/drinkjava2)
[码云](https://gitee.com/drinkjava2)
微信:yong99819981(如想长期关注本项目、交流信息,或想参与具体项目开发的,请留言加"人工生命群",如果只是想临时私聊也可加我好友后再删掉,我不介意)
微信:yong99819981(如想长期关注本项目、交流信息,或想参与具体开发的,请留言加"人工生命群",如果只是想临时私聊也可加我好友后再删掉,我不介意)

@ -21,14 +21,22 @@ import com.github.drinkjava2.frog.util.RandomUtils;
* @author Yong Zhu
* @since 1.0
*/
@SuppressWarnings("serial")
@SuppressWarnings("all")
public class Env extends JPanel {
/** Speed of test */
public static int SHOW_SPEED = 20; // 测试速度,-1000~1000,可调, 数值越小,速度越慢
public static final int SHOW_SPEED = 300; // 测试速度,-1000~1000,可调, 数值越小,速度越慢
/** Delete eggs at beginning of each run */
public static final boolean DELETE_EGGS = true;// 每次运行是否先删除保存的蛋
public static final int EGG_QTY = 30; // 每轮下n个蛋可调只有最优秀的前n个青蛙们才允许下蛋
public static final int FROG_PER_EGG = 3; // 每个蛋可以孵出几个青蛙
public static final int SCREEN = 3; // 分几屏测完, 所以每轮待测青蛙总数=EGG_QTY*FROG_PER_EGG*SCREEN
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 模式下会打印出更多的调试信息
@ -52,8 +60,6 @@ public class Env extends JPanel {
public static final int FOOD_QTY = 1500; // 食物数量, 可调
public static final int EGG_QTY = 50; // 每轮下n个蛋可调只有最优秀的前n个青蛙们才允许下蛋
private static final Random r = new Random(); // 随机数发生器
public static boolean pause = false; // 暂停按钮按下将暂停测试
@ -64,12 +70,12 @@ public class Env extends JPanel {
private static final int TRAP_HEIGHT = 10; // 陷阱宽, 0~200
public List<Frog> frogs = new ArrayList<>();
public static List<Frog> frogs = new ArrayList<>(); // 这里存放所有待测的青蛙可能分几次测完由FROG_PER_SCREEN大小来决定
public List<Egg> eggs;
public static List<Egg> eggs = new ArrayList<>(); // 这里存放从磁盘载入或上轮下的蛋每个蛋可能生成1~n个青蛙
static {
System.out.println("唵缚悉波罗摩尼莎诃!"); // 往生咒
System.out.println("唵缚悉波罗摩尼莎诃!"); // 杀生前先打印往生咒见码云issue#IW4H8
if (DELETE_EGGS)
EggTool.deleteEggs();
}
@ -113,29 +119,30 @@ public class Env extends JPanel {
return false;
}
private void rebuildFrogAndFood() {
frogs.clear();
private void rebuildFood() {
for (int i = 0; i < ENV_WIDTH; i++) {// 清除食物
for (int j = 0; j < ENV_HEIGHT; j++) {
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个蛙并随机取一个别的蛋作为精子
int loop = FROG_PER_EGG;
if (eggs.size() > 20) { // 如果数量多进行一些优化让排名靠前的Egg多孵出青蛙
if (i < FROG_PER_EGG)// 0,1,2,3
loop = FROG_PER_EGG + 1;
if (i >= (eggs.size() - FROG_PER_EGG))
loop = FROG_PER_EGG - 1;
}
Random rand = new Random();
for (int i = 0; i < eggs.size(); i++) {// 创建青蛙每个蛋生成4个蛙并随机取一个别的蛋作为精子
int loop = 4;
if (i <= 3)// 0,1,2,3
loop = 6;
if (i >= (eggs.size() - 4))
loop = 2;
for (int j = 0; j < loop; j++) {
Egg zygote = new Egg(eggs.get(i), eggs.get(r.nextInt(eggs.size())));
frogs.add(new Frog(rand.nextInt(ENV_WIDTH), rand.nextInt(ENV_HEIGHT), zygote));
frogs.add(new Frog(RandomUtils.nextInt(ENV_WIDTH), RandomUtils.nextInt(ENV_HEIGHT), zygote));
}
}
System.out.println("Created " + frogs.size() + " frogs");
for (int i = 0; i < Env.FOOD_QTY; i++) // 生成食物
foods[rand.nextInt(ENV_WIDTH)][rand.nextInt(ENV_HEIGHT)] = true;
}
private void drawFood(Graphics g) {
@ -159,57 +166,67 @@ public class Env extends JPanel {
format100.setMaximumFractionDigits(2);
}
private String foodFoundPercent() {// 计算找食效率
private static int foodFoundAmount() {// 统计找食数等
int leftfood = 0;
for (int x = 0; x < ENV_WIDTH; x++)
for (int y = 0; y < ENV_HEIGHT; y++)
if (foods[x][y])
leftfood++;
return format100.format((FOOD_QTY - leftfood) * 1.00 / FOOD_QTY);
return FOOD_QTY - leftfood;
}
private String foodFoundCountText() {// 统计找食数等
int foodFound = foodFoundAmount();
int maxFound = 0;
for (Frog f : frogs)
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();
}
private static void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void run() throws InterruptedException {
EggTool.loadEggs(this); // 从磁盘加载egg或新建一批egg
int round = 1;
public void run() {
EggTool.loadEggs(); // 从磁盘加载egg或新建一批egg
Image buffImg = createImage(this.getWidth(), this.getHeight());
Graphics g = buffImg.getGraphics();
long t1, t2;
long time0;// 计时用
int round = 1;
do {
rebuildFrogs();
for (int screen = 0; screen < SCREEN; screen++) {// 分屏测试每屏FROG_PER_SCREEN个蛙
time0 = System.currentTimeMillis();
if (pause)
do {
if (pause) {
sleep(300);
continue;
}
t1 = System.currentTimeMillis();
rebuildFrogAndFood();
} while (pause);
rebuildFood();
boolean allDead = false;
Frog firstFrog = frogs.get(0);
Frog firstFrog = frogs.get(screen * FROG_PER_SCREEN);
for (int i = 0; i < STEPS_PER_ROUND; i++) {
if (allDead) {
System.out.println("All dead at round:" + i);
if (allDead)
break; // 青蛙全死光了就直接跳到下一轮,以节省时间
}
allDead = true;
for (Frog frog : frogs)
if (frog.active(this))
for (int j = 0; j < FROG_PER_SCREEN; j++) {
Frog f = frogs.get(screen * FROG_PER_SCREEN + j);
if (f.active(this))
allDead = false;
for (Frog frog : frogs)
if (frog.alive && RandomUtils.percent(0.2f)) {// 有很小的机率在青蛙活着时就创建新的器官
if (f.alive && RandomUtils.percent(0.2f)) {// 有很小的机率在青蛙活着时就创建新的器官
RandomConnectGroup newConGrp = new RandomConnectGroup();
newConGrp.initFrog(frog);
frog.organs.add(newConGrp);
newConGrp.initFrog(f);
f.organs.add(newConGrp);
}
}
if (SHOW_SPEED > 0 && i % SHOW_SPEED != 0) // 画青蛙会拖慢速度
if (SHOW_SPEED > 0 && i % SHOW_SPEED != 0) // 用画青蛙的方式来拖慢速度
continue;
if (SHOW_SPEED < 0) // 如果speed小于0人为加入延迟
@ -219,8 +236,10 @@ public class Env extends JPanel {
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.BLACK);
for (Frog frog : frogs)
frog.show(g);
for (int j = 0; j < FROG_PER_SCREEN; j++) {
Frog f = frogs.get(screen * FROG_PER_SCREEN + j);
f.show(g);
}
if (firstFrog.alive) { // 开始显示第一个Frog的动态脑图
if (Application.SHOW_FIRST_FROG_BRAIN) {
@ -231,7 +250,6 @@ 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();
@ -239,10 +257,13 @@ public class Env extends JPanel {
}
Application.brainPic.drawBrainPicture(firstFrog);
EggTool.layEggs(this);
t2 = System.currentTimeMillis();
Application.mainFrame.setTitle("Frog test round: " + round++ + ", 找食效率:" + foodFoundPercent()
+ ", time used: " + (t2 - t1) + " ms");
Application.mainFrame.setTitle(new StringBuilder("Round: ").append(round).append(", screen:")
.append(screen).append(", ").append(foodFoundCountText()).append(", 用时: ")
.append(System.currentTimeMillis() - time0).append("ms").toString());
}
round++;
EggTool.layEggs();
} while (true);
}
}

@ -15,7 +15,6 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@ -39,14 +38,14 @@ public class EggTool {
/**
* Frogs which have higher energy lay eggs
*
* Java (fat)Frog, Frog
*
* Java ()Frog, Frog
* EGG_QTY
*/
public static void layEggs(Env env) {
sortFrogsOrderByEnergyDesc(env);
public static void layEggs() {
sortFrogsOrderByEnergyDesc();
Frog first = env.frogs.get(0);
Frog last = env.frogs.get(env.frogs.size() - 1);
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++) {
@ -55,30 +54,25 @@ public class EggTool {
+ org.organActiveEnergy + ", outputEnergy=" + org.organOutputEnergy);
}
System.out.println("1st 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);
try {
List<Egg> newEggs = new ArrayList<>();
Env.eggs.clear();
for (int i = 0; i < Env.EGG_QTY; i++)
newEggs.add(new Egg(env.frogs.get(i)));
Env.eggs.add(new Egg(Env.frogs.get(i)));
FileOutputStream fo = new FileOutputStream(Application.CLASSPATH + "eggs.ser");
ObjectOutputStream so = new ObjectOutputStream(fo);
so.writeObject(newEggs);
so.writeObject(Env.eggs);
so.close();
env.eggs = newEggs;
System.out
.println("Saved " + env.eggs.size() + " eggs to file '" + Application.CLASSPATH + "eggs.ser" + "'");
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'");
} catch (IOException e) {
System.out.println(e);
}
}
private static void sortFrogsOrderByEnergyDesc(Env env) {// 按能量多少给青蛙排序
Collections.sort(env.frogs, new Comparator<Frog>() {
private static void sortFrogsOrderByEnergyDesc() {// 按能量多少给青蛙排序
Collections.sort(Env.frogs, new Comparator<Frog>() {
public int compare(Frog a, Frog b) {
if (a.energy > b.energy)
return -1;
@ -90,24 +84,6 @@ public class EggTool {
});
}
// private static void sortFrogsOrderByEnergyDesc(Env env) {//
// 按吃到食物数量、剩余能量多少给青蛙排序
// Collections.sort(env.frogs, new Comparator<Frog>() {
// public int compare(Frog a, Frog b) {
// if (a.ateFood > b.ateFood)
// return -1;
// else if (a.ateFood == b.ateFood) {
// // if (a.energy > b.energy)
// // return -1;
// // if (a.energy < b.energy)
// // return 1;
// return 0;
// } else
// return 1;
// }
// });
// }
public static void deleteEggs() {
System.out.println("Delete exist egg file: '" + Application.CLASSPATH + "eggs.ser'");
FrogFileUtils.deleteFile(Application.CLASSPATH + "eggs.ser");
@ -117,25 +93,26 @@ public class EggTool {
* Egg
*/
@SuppressWarnings("unchecked")
public static void loadEggs(Env env) {
public static void loadEggs() {
boolean errorfound = false;
try {
FileInputStream eggsFile = new FileInputStream(Application.CLASSPATH + "eggs.ser");
ObjectInputStream eggsInputStream = new ObjectInputStream(eggsFile);
env.eggs = (List<Egg>) eggsInputStream.readObject();
Env.eggs = (List<Egg>) eggsInputStream.readObject();
System.out.println(
"Loaded " + env.eggs.size() + " eggs from file '" + Application.CLASSPATH + "eggs.ser" + "'.");
"Loaded " + Env.eggs.size() + " eggs from file '" + Application.CLASSPATH + "eggs.ser" + "'.\n");
eggsInputStream.close();
} catch (Exception e) {
errorfound = true;
}
if (errorfound) {
System.out.println("Fail to load egg file at path '" + Application.CLASSPATH + "', created " + Env.EGG_QTY
+ " new eggs to do test.");
env.eggs = new ArrayList<Egg>();
for (int i = 0; i < Env.EGG_QTY; i++)
env.eggs.add(new Egg());
Env.eggs.clear();
for (int j = 0; j < Env.EGG_QTY; j++)
Env.eggs.add(new Egg());
System.out.println("Fail to load egg file at path '" + Application.CLASSPATH + "', created "
+ Env.eggs.size() + " eggs to do test.\n");
}
}
}

@ -47,9 +47,11 @@ ENV_WIDTH:
ENV_HEIGHT: 虚拟环境高度大小通常取值100~1000左右
FROG_BRAIN_DISP_WIDTH: Frog的脑图在屏幕上的显示大小,通常取值100~1000左右
STEPS_PER_ROUND: 每轮测试步数, 每一步相当于脑思考的一桢,所有青蛙的脑神经元被遍历一次。
EGG_QTY: 每次允许Frog下多少个蛋每个蛋可以孵出4个青蛙。通常下蛋取值在10~1000之间。蛋保存着我们测试的结果。实验的最终目标就是获得一个蛋。
EGG_QTY: 每次允许Frog下多少个蛋通常下蛋取值在10~1000之间。蛋保存着我们测试的结果。实验的最终目标就是获得一批蛋。
FROG_PER_EGG 每个蛋可以孵出多少个青蛙。
SCREEN 分屏测试,一轮测试可以分为多个批次进行,这里是屏数。每轮总的青蛙数量=EGG_QTY * FROG_PER_EGG * SCREEN
FOOD_QTY食物的数量食物越多则Frog的生存率就越高能量排名靠前的一批Frog可以下蛋其余的被淘汰。
DELETE_EGGS: 每次运行是否先删除保存的蛋
DELETE_EGGS: 每次运行是否先删除保存的蛋,如果设为false将不删除保存的蛋会接着上次的测试结果续继运行。
DEBUG_MODE: 调试模式开关,如开启会打印出更多的调试信息
```
#### Frog模块

File diff suppressed because one or more lines are too long

@ -57,3 +57,6 @@
2. 青蛙增加一个Active器官它的作用是一直保持激活如果有神经元触突位于这个区就会驱动神经元兴奋这个器官经实践证明比Hungry器官驱动更能提高找食效率。
3. 青蛙增加一个Chance器官,它的作用是引入随机扰动,打破青蛙有时候围着一个食物打转就是吃不着的死循环。
从当前这个版本可以看出,实际上青蛙是有一定的记忆能力的,连接就=记忆只不过没有模式识别能力以后的工作将以模式识别为重点基本原理是见note中提到的仿照全息存储原理在思维区逆向成像。因为逆向成像的限制以后的版本所有的器官会被移到脑图的同一侧不再是随意分布在脑图上了这将是一个比较明显的改动。当然随机连接这个算法看起来比较有用以后还是可能保留的。
### 2019-08-04, Commit: Screen group test
引入分屏测试功能如果青蛙数量多可以分屏来测试每屏青蛙的数量可以少到只有1只。
Loading…
Cancel
Save