我只是从神经网络开始的,由于没有任何例子的绝对可怕的讲授,我们被遗忘在黑暗中,任务是创建一个单个神经元,该神经元将输入不同学科的3个分数并预测学生对另一个学科的分数
我们将获得历史数据来训练我们的神经元,其中包括3个标记和实际标记。我有点理解该过程如何工作的概念:输入带有初始随机权重的每个标记,应用线性激活函数,然后更新权重。但是,对于代码中的内容或神经元类的构造方式,我一无所知。任何指导表示赞赏。
答案 0 :(得分:2)
让我们从培训开始。该模型(如神经网络)经过迭代训练。
public void train(double[][] xs, double[] ys)
{
if(xs.length != ys.length)
return;
if(xs.length == 0)
return;
int N = xs[0].length;
// init coefficients
if(coefficients == null)
coefficients = new double[N];
// start training
double c0 = cost(xs, ys);
for(int i=0;i<nofEpochs;i++)
{
// execute one epoch of training
epoch(xs, ys);
double c1 = cost(xs, ys);
// quit if cost becomes higher
if(c1 > c0)
break;
c0 = c1;
// print debug output
if(isDebugEnabled)
System.out.println("epoch : " + i + "\tcost : " + c1);
}
}
让我们分解一下。 首先,我们进行一些基本的完整性检查。 xs表示输入,ys表示单个输出。 显然,我们希望xs和ys中的行数相等。
如果行数为零,我们将不费心做任何工作。
然后我们初始化系数(这些是神经网络中连接的权重)
然后我们称为主循环,该循环将根据需要进行多次迭代(或者直到没有任何改进为止)
此外观仅调用epoch
的代码,然后计算成本。
如果成本没有下降,则不会进行进一步的迭代。当然,您可以更改此相当残酷的制止标准。
private void epoch(double[][] xs, double[] ys)
{
int N = xs.length;
int M = xs[0].length;
// calculate gradient
double[] gradient = new double[M];
for(int i=0;i<N;i++)
{
for(int j=0;j<M;j++)
gradient[j] += costDerivative(xs[i], ys[i], coefficients,j);
}
// normalize
for(int i=0;i<M;i++)
{
gradient[i] /= N;
}
// apply
for(int i=0;i<M;i++)
{
coefficients[i] -= (gradient[i] * learningRate);
}
}
此代码代表一个纪元。它计算每个系数(又称权重)的梯度,汇总整个训练集的更新,对总数进行归一化,然后相应地更新系数。
最后,我们需要定义成本函数的导数。 我选择了一种数值方法(这意味着我避免了强迫用户每次更改成本函数时都要输入成本函数的导数的复杂性)
private double costDerivative(double[] x, double y, double[] cfs, int i)
{
double delta = 0.00001;
cfs[i] -= delta;
double c0 = cost(x, y, cfs);
cfs[i] += (delta * 2.0);
double c1 = cost(x, y, cfs);
return (c1 - c0) / (delta * 2.0);
}
这种数值方法只是通过在请求的x值之前和之后稍微计算成本来估算导数。
关于神经网络的聪明之处(如果我们正在谈论多个神经元和层)是可以将这些计算重写为使用矩阵。当然,哪一个可以加快一切速度(并且可以并行化和GPU卸载)