Нейронная сеть меняет поведение в зависимости от количества слоевJAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Нейронная сеть меняет поведение в зависимости от количества слоев

Сообщение Anonymous »

Я написал простую нейронную сеть и меня слишком смущает ее поведение. Я пробую простой обучающий набор с Relu-Activation, который должен прогнозировать 0,5 для ввода 1 и 0 для ввода 0. Он работает с LayerDimension = {1,10,10,1}, но не с {1,10, 1} или {1,10,10,10,1}.
Вот мой код:

Код: Выделить всё

import java.util.ArrayList;

public class Net {
Layer inputLayer;
Layer outputLayer;
ArrayList hiddenLayers;
double learningRate;

public Net(int[] layerDimensions){
this.learningRate = learningRate;
inputLayer = new Layer();
hiddenLayers = new ArrayList();
outputLayer = new Layer();
for(int i = 0; i< layerDimensions[0]; i++){
inputLayer.nodes.add(new Node(new Relu()));
}
for(int i = 1; i < layerDimensions.length-1; i++){
Layer hiddenLayer = new Layer();
for(int j = 0; j< layerDimensions[i]; j++){
hiddenLayer.nodes.add(new Node(new Relu()));
}
hiddenLayers.add(hiddenLayer);
}
for(int i = 0; i <  layerDimensions[layerDimensions.length-1]; i++){
outputLayer.nodes.add(new Node(new Relu()));
}
addConnections();
}
public double[] predict(double[] input){
for(int i = 0; i < inputLayer.nodes.size(); i++){
inputLayer.nodes.get(i).output = input[i];
}
for(Layer hiddenLayer : hiddenLayers){
hiddenLayer.calcInput();
}
outputLayer.calcInput();
return outputLayer.getOutput();
}

public double training(double[][] input, double[][] target, double learningRate, int repetitions) {
this.learningRate = learningRate;
double accuracy = 0;

for (int r = 0; r < repetitions; r++) {
accuracy = 0;
for (int i = 0; i < input.length; i++) {

// Forward pass
double[] output = predict(input[i]);

// Calculate error for output layer
for (int j = 0; j < outputLayer.nodes.size(); j++) {
Node outputNode = outputLayer.nodes.get(j);
double error = 0.5* Math.pow(target[i][j] - output[j],2);
outputNode.error = error * outputNode.activationFunction.phiStrich(outputNode.net);
}
// Backpropagate the error to hidden layers
for (int l = hiddenLayers.size() - 1; l >= 0; l--) {
Layer hiddenLayer = hiddenLayers.get(l);
for (Node hiddenNode : hiddenLayer.nodes) {
hiddenNode.error = 0;
for (Edge edge : hiddenNode.outgoing) {
hiddenNode.error += edge.weight * edge.targetNode.error;
}
hiddenNode.error *= hiddenNode.activationFunction.phiStrich(hiddenNode.net);
}
}
// Update weights and biases for output layer
updateWeights(learningRate, outputLayer);

// Update weights and biases for hidden layers
for (Layer hiddenLayer : hiddenLayers) {
updateWeights(learningRate, hiddenLayer);
}
updateWeights(learningRate,inputLayer);
// Calculate accuracy
double mse = 0;
for (int j = 0; j < output.length; j++) {
mse += Math.pow(target[i][j] - output[j], 2);
}
accuracy += mse / output.length;
}
accuracy /= input.length;
}
return accuracy;
}

private void updateWeights(double learningRate, Layer layer) {
for (Node node : layer.nodes) {
for (Edge edge : node.incoming) {
edge.deltaWeight = -learningRate * node.error * edge.targetNode.output;
edge.weight += edge.deltaWeight;
}
node.bias += -learningRate * node.error;
}
}

private void addConnections(){
for(Node inputNode: inputLayer.nodes){
for(Node hiddenNode: hiddenLayers.get(0).nodes){
Edge connection = new Edge(inputNode, hiddenNode);
inputNode.outgoing.add(connection);
hiddenNode.incoming.add(connection);
}
}
for(int i = 1; i < hiddenLayers.size();  i++) {
for(Node hiddenNode : hiddenLayers.get(i).nodes){
for(Node previousNode : hiddenLayers.get(i-1).nodes){
Edge connection = new Edge(previousNode, hiddenNode);
previousNode.outgoing.add(connection);
hiddenNode.incoming.add(connection);
}
}
}
for(Node outputNode: outputLayer.nodes){
for(Node hiddenNode: hiddenLayers.get(hiddenLayers.size()-1).nodes){
Edge connection = new Edge(hiddenNode, outputNode);
hiddenNode.outgoing.add(connection);
outputNode.incoming.add(connection);
}
}
}
}

Код: Выделить всё

import java.util.ArrayList;

public class Layer {
ArrayList nodes;

public Layer(){
nodes = new ArrayList();
}

public void calcInput(){
for(Node node : nodes){
node.net = 0;
for(Edge connection : node.incoming){
node.net += connection.sourceNode.output * connection.weight;
}
node.activate();
}
for (Node node : nodes) {
double net = 0;
for (Edge edge : node.incoming) {
net += edge.weight * edge.sourceNode.output;
}
net += node.bias;
node.net = net;
node.output = node.activationFunction.phi(net);
}
}

public double[] getOutput(){
double[] result = new double[nodes.size()];
for(int i = 0; i < nodes.size(); i++){
result[i] = nodes.get(i).output;
}
return result;
}
}

Код: Выделить всё

import java.util.ArrayList;

public class Node {
ArrayList outgoing;
ArrayList incoming;
double net = 0;
double bias;
double output;
double error;
Aktivierungsfunktion activationFunction;

public Node(Aktivierungsfunktion activationFunction){
outgoing = new ArrayList();
incoming = new ArrayList();
this.activationFunction = activationFunction;
}

public void activate(){
net += bias;
output = activationFunction.phi(net);
}
}

Код: Выделить всё

import java.util.Random;

public class Edge {
Node sourceNode;
Node targetNode;
public Edge(Node source, Node target){
this.sourceNode = source;
this.targetNode = target;
weight = new Random().nextDouble() * 0.5;
}

double weight;
double deltaWeight;
}

Код: Выделить всё

public class Sigmoid extends Aktivierungsfunktion
{
public double phi(double x){
return 1 / (1 + Math.exp(-x));
}

public double phiStrich(double x){
double phiVonX = phi(x);
return phiVonX * (1 - phiVonX);
}
}

public class Relu extends Aktivierungsfunktion
{
private final double alpha = 0.01;
public double phi(double x){
if (x > 0) {
return x;
} else {
return alpha * x;
}
}
public double phiStrich(double x){
if (x > 0) {
return 1;
} else {
return alpha;
}
}
}

Код: Выделить всё

public abstract class Aktivierungsfunktion
{
public abstract double phi(double x);

public abstract double phiStrich(double x);
}

Код: Выделить всё

import java.util.Arrays;

public class Main {
public static void main(String[] args) {
Net net = new Net(new int[] {1,10,10,1});
double[][] input = {
{0.0},
{1.0},
{1.0},
{0.0},
};
double[][] target = {
{0.0},
{1.0},
{1.0},
{0.0}
};
double accuracy = net.training(input,target,0.01, 1000);
System.out.println(accuracy);
for (double[] in : input) {
double[] out = net.predict(in);
System.out.println("Input: " + Arrays.toString(in) + " Output: "  + Arrays.toString(out));
}
}

}
Я попытался упростить проблему с помощью ввода 0 -> цель 0 и ввода 1 -> цель 1.
Когда я меняю функцию активации на сигмовидную, прогнозируемые значения рядом с постоянным значением, независимым от заданных входных данных.
Как я могу это отладить?

Подробнее здесь: https://stackoverflow.com/questions/788 ... ayer-count
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»