私はへの導入で述べたように最初の部分、私はフロントエンドの開発者です、そして私の母国語ではJavaScriptで、我々はそれを使用して、この記事では私たちのニューラルネットワークを実装します。まず、構造について少しお話します。さまざまな計算されたプロパティとメソッドを除いて、ニューラルネットワークオブジェクトにはレイヤーの配列が含まれ、各レイヤーにはニューロンの配列が含まれ、各ニューロンには「入力」の配列が含まれます。前の入力レイヤー。また、活性化関数、その導関数、学習率など、ネットワーク全体に共通するものがあり、各ニューロンからそれらにアクセスする必要があるため、ニューロンには、その層への_layerリンクがあることに同意しましょう。それは属し、レイヤーには_network(ネットワーク自体へのリンク)があります。
プライベートから一般に移り、最初にニューロンの入力クラスについて説明しましょう。
class Input {
constructor(neuron, weight) {
this.neuron = neuron;
this.weight = weight;
}
}
ここではすべてが非常に簡単です。各入力には、数値の重みと前の層のニューロンへの参照があります。さらに進んでみましょう。ニューロン自体のクラスについて説明しましょう。
class Neuron {
constructor(layer, previousLayer) {
this._layer = layer;
this.inputs = previousLayer
? previousLayer.neurons.map((neuron) => new Input(neuron, Math.random() - 0.5))
: [0];
}
get $isFirstLayerNeuron() {
return !(this.inputs[0] instanceof Input)
}
get inputSum() {
return this.inputs.reduce((sum, input) => {
return sum + input.neuron.value * input.weight;
}, 0);
}
get value() {
return this.$isFirstLayerNeuron
? this.inputs[0]
: this._layer._network.activationFunction(this.inputSum);
}
set input(val) {
if (!this.$isFirstLayerNeuron) {
return;
}
this.inputs[0] = val;
}
set error(error) {
if (this.$isFirstLayerNeuron) {
return;
}
const wDelta = error * this._layer._network.derivativeFunction(this.inputSum);
this.inputs.forEach((input) => {
input.weight -= input.neuron.value * wDelta * this._layer._network.learningRate;
input.neuron.error = input.weight * wDelta;
});
}
}
ここで何が起こっているのか見てみましょう。ニューロンのコンストラクターに2つのパラメーターを渡すことができます。このニューロンが配置されているレイヤーと、これがニューラルネットワークの入力レイヤーでない場合は、前のレイヤーへのリンクです。
コンストラクターでは、前のレイヤーのニューロンごとに、ニューロンを接続してランダムな重みを持つ入力を作成し、すべての入力を入力配列に書き込みます。これがネットワークの入力レイヤーである場合、inputs配列は、入力に渡す単一の数値で構成されます。
$isFirstLayerNeuron - , , . , , .
inputSum - readonly , (, ) .
value - . , , inputSum.
:
input - , .
- error. , , error . , , .
. .
class Layer {
constructor(neuronsCount, previousLayer, network) {
this._network = network;
this.neurons = [];
for (let i = 0; i < neuronsCount; i++) {
this.neurons.push(new Neuron(this, previousLayer));
}
}
get $isFirstLayer() {
return this.neurons[0].$isFirstLayerNeuron;
}
set input(val) {
if (!this.$isFirstLayer) {
return;
}
if (!Array.isArray(val)) {
return;
}
if (val.length !== this.neurons.length) {
return;
}
val.forEach((v, i) => this.neurons[i].input = v);
}
}
- , neurons , , , .
$isFirstLayer - , , , input, , , . , .
, ,
class Network {
static sigmoid(x) {
return 1 / (1 + Math.exp(-x));
}
static sigmoidDerivative(x) {
return Network.sigmoid(x) * (1 - Network.sigmoid(x));
}
constructor(inputSize, outputSize, hiddenLayersCount = 1, learningRate = 0.5) {
this.activationFunction = Network.sigmoid;
this.derivativeFunction = Network.sigmoidDerivative;
this.learningRate = learningRate;
this.layers = [new Layer(inputSize, null, this)];
for (let i = 0; i < hiddenLayersCount; i++) {
const layerSize = Math.min(inputSize * 2 - 1, Math.ceil((inputSize * 2 / 3) + outputSize));
this.layers.push(new Layer(layerSize, this.layers[this.layers.length - 1], this));
}
this.layers.push(new Layer(outputSize, this.layers[this.layers.length - 1], this));
}
set input(val) {
this.layers[0].input = val;
}
get prediction() {
return this.layers[this.layers.length - 1].neurons.map((neuron) => neuron.value);
}
trainOnce(dataSet) {
if (!Array.isArray(dataSet)) {
return;
}
dataSet.forEach((dataCase) => {
const [input, expected] = dataCase;
this.input = input;
this.prediction.forEach((r, i) => {
this.layers[this.layers.length - 1].neurons[i].error = r - expected[i];
});
});
}
train(dataSet, epochs = 100000) {
return new Promise(resolve => {
for (let i = 0; i < epochs; i++) {
this.trainOnce(dataSet);
}
resolve();
});
}
}
, learning rate.
input - , .
prediction - , . .
trainOnce dataset - , , , - . , , . , , , .
train - , . . , .then, main thread.
, . - XOR.
.
const network = new Network(2, 1);
:
const data = [
[[0, 0], [0]],
[[0, 1], [1]],
[[1, 0], [1]],
[[1, 1], [0]],
];
, .
network.train(data).then(() => {
const testData = [
[0, 0],
[0, 1],
[1, 0],
[1, 1],
];
testData.forEach((input, index) => {
network.input = input;
console.log(`${input[0]} XOR ${input[1]} = ${network.prediction}`)
});
});
, . .