我有一个学习人工神经元作为一个简单信号计数器的小程序:我的细胞有四根输入线(也称为树突)和一条输出线(也称为轴突)。如果至少有两个输入信号足够强,轴突就被激活。我认为神经元一旦连续“猜测”出了足够多的输出,就会被学习。
package net.coderodde.ai.neural;
import java.util.Objects;
/**
* This class models artificial neurons.
*
* @author Rodion "rodde" Efremov
*/
public class Neuron {
private final float[] dendriteWeightArray;
private TransitionFunction transitionFunction;
public Neuron(int dendriteAmount) {
this.dendriteWeightArray = new float[dendriteAmount];
}
public float getDendriteWeight(int dendriteIndex) {
checkDendriteIndex(dendriteIndex);
return dendriteWeightArray[dendriteIndex];
}
public void setDendriteWeight(int dendriteIndex, float weight) {
checkDendriteIndex(dendriteIndex);
checkIsFinite(weight);
dendriteWeightArray[dendriteIndex] = weight;
}
public void setTransitionFunction(TransitionFunction transitionFunction) {
Objects.requireNonNull(transitionFunction,
"The input transition function is null.");
this.transitionFunction = transitionFunction;
}
public float process(float... input) {
float sum = 0.0f;
for (int i = 0; i < Math.min(input.length,
dendriteWeightArray.length); ++i) {
sum += input[i] * dendriteWeightArray[i];
}
return transitionFunction.process(sum);
}
public int getDendriteCount() {
return dendriteWeightArray.length;
}
private void checkDendriteIndex(int index) {
if (index < 0) {
throw new IndexOutOfBoundsException(
"The dendrite index is negative: " + index);
}
if (index >= dendriteWeightArray.length) {
throw new IndexOutOfBoundsException(
"The dendrite index is too large: " + index + ", the " +
"amount of dendrites: " + dendriteWeightArray.length);
}
}
private static void checkIsFinite(float f) {
if (Float.isNaN(f)) {
throw new IllegalArgumentException("The value is NaN.");
}
if (Float.isInfinite(f)) {
throw new IllegalArgumentException(
"The value is infinite in absolute value: " + f);
}
}
}package net.coderodde.ai.neural;
/**
* This interface defines the API for a transition function in artificial
* neurons.
*
* @author Rodion "rodde" Efremov
* @version 1.6
*/
@FunctionalInterface
public interface TransitionFunction {
/**
* Maps the input signal to output.
*
* @param input the input signal.
* @return the output signal.
*/
public float process(float input);
}package net.coderodde.ai.neural;
/**
* This class defines the API for neuron learning routines.
*
* @author Rodion "rodde" Efremov
* @version 1.6
*/
public interface NeuronLearner {
/**
* The actual learning method.
*
* @param neuron the neuron to learn.
*/
public void learn(Neuron neuron);
}package net.coderodde.ai.neural;
import java.util.Random;
/**
* This class implements fully random neuron learner routine.
*
* @author Rodion "rodde" Efremov
* @version 1.6
*/
public class RandomNeuronLearner implements NeuronLearner {
private final Random random;
public RandomNeuronLearner(Random random) {
this.random = random;
}
@Override
public void learn(Neuron neuron) {
int dendriteCount = neuron.getDendriteCount();
for (int i = 0; i < dendriteCount; ++i) {
neuron.setDendriteWeight(i, 2.0f * random.nextFloat() - 1.0f);
}
float min = random.nextFloat();
neuron.setTransitionFunction((f) -> {
return f > min ? 1.0f : 0.f;
});
}
}package net.coderodde.ai.neural;
import java.util.Random;
public class Demo {
private static final int MINIMUM_MATCHES = 50;
public static void main(String[] args) {
// This demonstration learns a neuron with four dendrites to act as a
// "counter": if at least two dendrites receive a signal strong
// enough, the axon must be activated.
Neuron neuron = new Neuron(4);
Random random = new Random();
NeuronLearner learner = new RandomNeuronLearner(new Random());
long ta = System.currentTimeMillis();
outer:
for (;;) {
learner.learn(neuron);
for (int i = 0; i < MINIMUM_MATCHES; ++i) {
float[] signal = getRandomSignal(neuron.getDendriteCount(),
random);
if (signalShouldPass(signal) != signalPasses(neuron.process(signal))) {
continue outer;
}
}
break;
}
long tb = System.currentTimeMillis();
System.out.println("The neuron learned in " + (tb - ta) +
" milliseconds.");
}
/**
* Generates a random signal.
*
* @param size the amount of dendrites of a neuron receiving the signal.
* @param random the random number generator.
* @return a random signal.
*/
private static float[] getRandomSignal(int size, Random random) {
float[] ret = new float[size];
for (int i = 0; i < size; ++i) {
ret[i] = random.nextFloat();
}
return ret;
}
/**
* Checks whether the input signal should activate the axon.
*
* @param signal the signal to check.
* @return {@code true} if the input signal should activate the axon.
*/
private static boolean signalShouldPass(float[] signal) {
int count = 0;
for (float f : signal) {
if (f > 0.5) {
count++;
}
}
return count >= 2;
}
/**
* Check whether the axon was activated.
*
* @param output the output of the axon.
* @return {@code true} if the axon was activated.
*/
private static boolean signalPasses(float output) {
return output > 0.7f;
}
}我得到了这样的东西:
神经元在307毫秒内学习。
发布于 2015-07-31 06:49:05
我不喜欢这个程序的概念,因为从数学上讲,你的神经网络实际上不能产生你想要达到的正确结果。
目前的神经网络太原始,无法计算所需的函数。它简单地总结了四个加权输入,并与一个截止值进行了比较,这意味着它所能做的最好的就是做一个相当于:
return (a+b+c+d > X) ? 1.0f : 0.0f;因此,如果您尝试了这样的测试用例(通过排列):
(0,0,0.5,0.5) <-- Tests minimum succeeding case
(1,0.49,0.49,0.49) <-- Tests maximum failing case你会发现没有一个神经网络能够通过每一个边缘的案例测试。实际上,你的程序所做的就是找到一个可以通过50个随机测试用例的神经网络,这意味着随机测试用例不一定是一个很好的成功判断。
从理论的角度来看,我认为你的神经网络至少需要两层。如果神经网络真的“学习”,而不是在失败时随机分配新的权重,那就更有趣了。
https://codereview.stackexchange.com/questions/98592
复制相似问题