我正在实现进化神经网络。当涉及两个 double 值的交叉时,我遇到了问题。我正在改进神经网络中链接的权重。
//Get the weights that I want to crossover
double weightA = a.getWeight();
double weightB = b.getWeight();
//Round to 6 decimal numbers.
weightA = (double)Math.round(weightA * 1000000) / 1000000;
weightB = (double)Math.round(weightB * 1000000) / 1000000;
//Convert the doubles to binary strings
String binaryA = Long.toBinaryString(Double.doubleToRawLongBits(weightA));
String binaryB = Long.toBinaryString(Double.doubleToRawLongBits(weightB));
//Define random crossover point.
int crossOverPoint = randInt(0, binaryA.length());
//Put the strings together based on the crossover point.
String newBinary = binaryA.substring(0,crossOverPoint) + binaryB.substring(crossOverPoint+1,binaryB.length());
double newWeight = Double.longBitsToDouble(new BigInteger(newBinary, 2).longValue());
我遇到的问题是,交叉后我得到的权重非常大或非常小,这可能是由于每个字符串中小数位使用了多少位造成的。我应该如何做到这一点才能在交叉后获得与两个 parent 相似的值?
我有一个解决这个问题的方法,它给了我不错的结果,但我相当确定这不是正确的方法,它基本上找到两个值之间的平均值,并根据原始两个值。
double interval = Math.abs(weightA-weightB);
double newWeight = (weightA+weightB)*0.5 + r.nextGaussian()*interval*2;
最佳答案
我对遗传算法不太熟悉,但据我所知,您对 double 的处理似乎不是解决它的好方法:
我在这里假设您想要使用第一个 double 的二进制表示的前 crossOverPoint
位和第二个 double 的最后 (64-crossOverPoint)
位(如我错了请纠正我)。如果您使用字符串,则必须确保包含前导 0。更简单的方法是使用位运算组合长整型的二进制表示形式:
long weightALong = Double.doubleToRawLongBits(weightA);
long weightBLong = Double.doubleToRawLongBits(weightB);
long mask = -1L; // all bits set to 1
int crossOverPoint = randInt(0, Long.SIZE);
long combined;
// treat special cases because of modulo Long.SIZE of second parameter of shifting operations
if (crossOverPoint == 0) {
combined = weightBLong;
} else if (combined == Long.SIZE) {
combined = weightALong;
} else {
combined = (weightALong & (mask << (Long.SIZE - crossOverPoint))) |
(weightBLong & (mask >>> crossOverPoint));
}
double newWeight = Double.longBitsToDouble(combined);
但是从 binary representation of doubles我猜想以这种方式组合二进制表示可能不是组合 double 的最佳方式:
- 如果第一位不同,正确选择
crossOverPoint
(1)就可以改变符号。 - 在所有情况下 (52/64),指数完全来自
weightA
。
如果尾数中出现不幸的组合, NaN
、POSITIVE_INFINITY
和NEGATIVE_INFINITY
可以由不同于这三个值的值生成.
我想你的解决方法似乎是更好的选择。 (也许你应该在 https://cs.stackexchange.com/ 上问这个问题)
关于Java:将两个双位串混合在一起以进行遗传算法交叉,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23970715/