Se muestra diagrama conceptual para entrenamiento de una red neuronal multicapa.
El proceso por pasos:
01- Obtener un Dataset en bruto(raw).
02- Discretizar Dataset [Dataset -> Dataset'].
03- Extraer Entradas(E) y Salidas(D) del Dataset'.
04- Pasar Entradas(E) por la Red Neuronal(RN).
05- Obtener Salidas(Y) de la RN.
06- Calcular Error(δ) en base a las Salidas(Y) de la RN y Salida(D) del Dataset'.
07- En base al cálculo del Error(δ), ajustar pesos(W) de la RN.
08- Pasar al siguiente registro del Dataset' volviendo de nuevo al punto 03. Si no existen más registros se pasa al punto 09.
09- Finalizados los registros del Dataset' volver a posicionarse en el 1º registro y volver a empezar desde punto 03, siempre y cuando el Error(δ) general sea inferior o igual (<=) alumbral especificado por el usuario. En tal caso da por finalizado el entrenaminento.
Una forma sencilla y rápida de aprender JAVA, observando y deduciendo cómo se comporta el lenguaje a través de ejemplos prácticos.
Archivo del blog
martes, 27 de agosto de 2019
domingo, 7 de julio de 2019
Perceptrón multicapa. Cálculo real de todas las variables partiendo de un dataset básico.
Tras los posts anteriores (visualizaciones esquemáticas de formulas) el siguiente paso pasa por realizar el cálculo real de todas las variables (salidas, errores y pesos actualizados) partiendo de un dataset(D) de un sólo registro.
Código Java:
package perceptron_p;
import java.util.ArrayList;
import java.util.List;
public class Perceptron_p {
public static void main(String[] args) {
//sketch: num neuronas
List<Integer> nN = new ArrayList<>();
nN.add(2);
nN.add(3);
nN.add(2);
nN.add(1);
double µ = 0.001;
int r = 0; // num. registro del dataset
int nK = nN.size(); // num. de capas = 4
int nE = nN.get(0); // num. de entradas = 2
int nS = nN.get(nK - 1); // num. de salidas = 1
int max = nN.stream().mapToInt(i -> i).max().getAsInt(); // num. max. neuronas por capa
String tmp;
double d_tmp;
// Inicializar dataset (sólo 1 registro o fila)
double[][] D = new double[1][3];
D[0][0] = 0.48d; // entrada 1
D[0][1] = 0.33d; // entrada 2
D[0][2] = 0.81d; // salida 1
// Inicializar pesos W, WBias, Y
double[][][] W = new double[nK][max][max];
double[][] WB = new double[nK][max];
double[][] Y = new double[nK][max];
double[][] E = new double[nK][max];
System.out.println("Inicializar pesos con valores aleatorios:\n");
for (int k = 1; k < nK; k++) {
for (int j = 0; j < nN.get(k); j++) {
for (int i = 0; i < nN.get(k - 1); i++) {
W[k][j][i] = Math.random();
System.out.format("W[%d][%d][%d] = %f\n", k, j, i, W[k][j][i]);
}
WB[k][j] = Math.random();
System.out.format("WB[%d][%d] = %f\n\n", k, j, WB[k][j]);
Y[k][j] = 0.f;
E[k][j] = 0.f;
}
}
// 0.0:-------------------------------------------------------------------
System.out.println("Forward:\n");
int k = 1;
for (int j = 0; j < nN.get(k); j++) {
tmp = "";
d_tmp = 0f;
for (int i = 0; i < nE; i++) {
tmp += String.format("( D[%d][%d] * W[%d][%d][%d] ) + ", r, i, k, j, i);
d_tmp += D[r][i] * W[k][j][i];
}
Y[k][j] = F(d_tmp + (-1 * WB[k][j]), 0);
System.out.format("Y[%d][%d] = F{ %s( -1 * WB[%d][%d] ) } = ", k, j, tmp, k, j);
System.out.println(Y[k][j]);
}
// 0.1:-------------------------------------------------------------------
System.out.println("");
for (k = 2; k < nK; k++) {
for (int j = 0; j < nN.get(k); j++) {
tmp = "";
d_tmp = 0f;
for (int i = 0; i < nN.get(k - 1); i++) {
tmp += String.format("( Y[%d][%d] * W[%d][%d][%d] ) + ", k - 1, i, k, j, i);
d_tmp += Y[k - 1][i] * W[k][j][i];
}
System.out.format("Y[%d][%d] = F{ %s( -1 * WB[%d][%d] ) } = ", k, j, tmp, k, j);
Y[k][j] = F(d_tmp + (-1 * WB[k][j]), 0);
System.out.println(Y[k][j]);
}
System.out.println("");
}
// 1.0:-------------------------------------------------------------------
System.out.println("Backward:\n");
k = nK - 1;
for (int j = 0; j < nS; j++) {
E[k][j] = D[r][nE + j] - Y[k][j];
System.out.format("E[%d][%d] = ( D[%d][%d] - Y[%d][%d] ) = ", k, j, r, nE + j, k, j);
System.out.println(E[k][j]);
}
// 1.1:-------------------------------------------------------------------
System.out.println("");
for (k = k - 1; k > 0; k--) {
for (int j = nN.get(k); j > 0; j--) {
tmp = "";
d_tmp = 0.d;
for (int i = nN.get(k + 1); i > 0; i--) {
tmp += String.format("( E[%d][%d] * W[%d][%d][%d] ) + ", k + 1, i - 1, k + 1, i - 1, j - 1);
d_tmp += E[k + 1][i - 1] * W[k + 1][i - 1][j - 1];
}
System.out.format("E[%d][%d] = %s%s = ", k, j - 1, tmp, "0 ");
System.out.println(d_tmp);
E[k][j - 1] = d_tmp;
}
System.out.println("");
}
// 2.0:-------------------------------------------------------------------
System.out.println("Ajuste pesos:\n");
k = 1;
for (int j = 0; j < nN.get(k); j++) {
for (int i = 0; i < nE; i++) {
W[k][j][i] += (µ * E[k][j] * F(Y[k][j], 1) * D[r][i]);
System.out.format("W'[%d][%d][%d] = W[%d][%d][%d] + ( µ * E[%d][%d] * F'(Y[%d][%d]) * D[%d][%d] ) = ", k, j, i, k, j, i, k, j, k, j, r, i);
System.out.println(W[k][j][i]);
}
WB[k][j] += (µ * E[k][j] * F(Y[k][j], 1) * -1);
System.out.format("WB'[%d][%d] = WB[%d][%d] + ( µ * E[%d][%d] * F'(Y[%d][%d]) * (%d) ) = ", k, j, k, j, k, j, k, j, - 1);
System.out.println(WB[k][j] + "\n");
}
// 2.1:-------------------------------------------------------------------
System.out.println("");
for (k = 2; k < nK; k++) {
for (int j = 0; j < nN.get(k); j++) {
for (int i = 0; i < nN.get(k - 1); i++) {
W[k][j][i] += (µ * E[k][j] * F(Y[k][j], 1) * Y[k - 1][i]);
System.out.format("W'[%d][%d][%d] = W[%d][%d][%d] + ( µ * E[%d][%d] * F'( Y[%d][%d] ) * Y[%d][%d] ) = ", k, j, i, k, j, i, k, j, k, j, k - 1, i);
System.out.println(W[k][j][i]);
}
WB[k][j] += (µ * E[k][j] * F(Y[k][j], 2) * (-1));
System.out.format("WB'[%d][%d] = WB[%d][%d] + ( µ * E[%d][%d] * F'(Y[%d][%d]) * (%d) ) = ", k, j, k, j, k, j, k, j, -1);
System.out.println(WB[k][j] + "\n");
}
System.out.println("");
}
}
// Función Activación - Derivada
private static double F(double n, int op) {
double fx;
switch (op) {
case 0: // función sigmoide
fx = 1.0 / (1.0 + Math.pow(Math.E, -n));
break;
case 1: // derivada función sigmoide
fx = 1.0 / (1.0 + Math.pow(Math.E, -n));
fx = fx * (1 - fx);
break;
default:
fx = 0.f;
break;
}
return fx;
}
}
Resultado:
run:
Inicializar pesos con valores aleatorios:
W[1][0][0] = 0,835049
W[1][0][1] = 0,308429
WB[1][0] = 0,052288
W[1][1][0] = 0,217787
W[1][1][1] = 0,348034
WB[1][1] = 0,588298
W[1][2][0] = 0,961801
W[1][2][1] = 0,796138
WB[1][2] = 0,044188
W[2][0][0] = 0,994101
W[2][0][1] = 0,211034
W[2][0][2] = 0,711812
WB[2][0] = 0,952732
W[2][1][0] = 0,423756
W[2][1][1] = 0,953356
W[2][1][2] = 0,249125
WB[2][1] = 0,973105
W[3][0][0] = 0,842807
W[3][0][1] = 0,794736
WB[3][0] = 0,290240
Forward:
Y[1][0] = F{ ( D[0][0] * W[1][0][0] ) + ( D[0][1] * W[1][0][1] ) + ( -1 * WB[1][0] ) } = 0.6107146316470909
Y[1][1] = F{ ( D[0][0] * W[1][1][0] ) + ( D[0][1] * W[1][1][1] ) + ( -1 * WB[1][1] ) } = 0.40880474360914854
Y[1][2] = F{ ( D[0][0] * W[1][2][0] ) + ( D[0][1] * W[1][2][1] ) + ( -1 * WB[1][2] ) } = 0.6637837549590786
Y[2][0] = F{ ( Y[1][0] * W[2][0][0] ) + ( Y[1][1] * W[2][0][1] ) + ( Y[1][2] * W[2][0][2] ) + ( -1 * WB[2][0] ) } = 0.5530844896875817
Y[2][1] = F{ ( Y[1][0] * W[2][1][0] ) + ( Y[1][1] * W[2][1][1] ) + ( Y[1][2] * W[2][1][2] ) + ( -1 * WB[2][1] ) } = 0.46028147962310223
Y[3][0] = F{ ( Y[2][0] * W[3][0][0] ) + ( Y[2][1] * W[3][0][1] ) + ( -1 * WB[3][0] ) } = 0.6322090580829307
Backward:
E[3][0] = ( D[0][2] - Y[3][0] ) = 0.17779094191706935
E[2][1] = ( E[3][0] * W[3][0][1] ) + 0 = 0.14129683962211012
E[2][0] = ( E[3][0] * W[3][0][0] ) + 0 = 0.1498433870202291
E[1][2] = ( E[2][1] * W[2][1][2] ) + ( E[2][0] * W[2][0][2] ) + 0 = 0.1418609770496571
E[1][1] = ( E[2][1] * W[2][1][1] ) + ( E[2][0] * W[2][0][1] ) + 0 = 0.16632825764793913
E[1][0] = ( E[2][1] * W[2][1][0] ) + ( E[2][0] * W[2][0][0] ) + 0 = 0.2088347664166445
Ajuste pesos:
W'[1][0][0] = W[1][0][0] + ( µ * E[1][0] * F'(Y[1][0]) * D[0][0] ) = 0.8350717767495889
W'[1][0][1] = W[1][0][1] + ( µ * E[1][0] * F'(Y[1][0]) * D[0][1] ) = 0.3084447906938308
WB'[1][0] = WB[1][0] + ( µ * E[1][0] * F'(Y[1][0]) * (-1) ) = 0.05224031629899943
W'[1][1][0] = W[1][1][0] + ( µ * E[1][1] * F'(Y[1][1]) * D[0][0] ) = 0.21780595558207116
W'[1][1][1] = W[1][1][1] + ( µ * E[1][1] * F'(Y[1][1]) * D[0][1] ) = 0.34804701774866154
WB'[1][1] = WB[1][1] + ( µ * E[1][1] * F'(Y[1][1]) * (-1) ) = 0.5882576504954621
W'[1][2][0] = W[1][2][0] + ( µ * E[1][2] * F'(Y[1][2]) * D[0][0] ) = 0.9618160101133663
W'[1][2][1] = W[1][2][1] + ( µ * E[1][2] * F'(Y[1][2]) * D[0][1] ) = 0.7961484238865005
WB'[1][2] = WB[1][2] + ( µ * E[1][2] * F'(Y[1][2]) * (-1) ) = 0.04415614986229021
W'[2][0][0] = W[2][0][0] + ( µ * E[2][0] * F'( Y[2][0] ) * Y[1][0] ) = 0.9941217290526374
W'[2][0][1] = W[2][0][1] + ( µ * E[2][0] * F'( Y[2][0] ) * Y[1][1] ) = 0.21104869817169436
W'[2][0][2] = W[2][0][2] + ( µ * E[2][0] * F'( Y[2][0] ) * Y[1][2] ) = 0.7118355488714299
WB'[2][0] = WB[2][0] + ( µ * E[2][0] * F'(Y[2][0]) * (-1) ) = 0.9527319900854492
W'[2][1][0] = W[2][1][0] + ( µ * E[2][1] * F'( Y[2][1] ) * Y[1][0] ) = 0.4237764313332067
W'[2][1][1] = W[2][1][1] + ( µ * E[2][1] * F'( Y[2][1] ) * Y[1][1] ) = 0.953369304782218
W'[2][1][2] = W[2][1][2] + ( µ * E[2][1] * F'( Y[2][1] ) * Y[1][2] ) = 0.2491472992670435
WB'[2][1] = WB[2][1] + ( µ * E[2][1] * F'(Y[2][1]) * (-1) ) = 0.9731049511389623
W'[3][0][0] = W[3][0][0] + ( µ * E[3][0] * F'( Y[3][0] ) * Y[2][0] ) = 0.8428289253648974
W'[3][0][1] = W[3][0][1] + ( µ * E[3][0] * F'( Y[3][0] ) * Y[2][1] ) = 0.7947544171128877
WB'[3][0] = WB[3][0] + ( µ * E[3][0] * F'(Y[3][0]) * (-1) ) = 0.29024004297076156
BUILD SUCCESSFUL (total time: 2 seconds)
Código Java:
package perceptron_p;
import java.util.ArrayList;
import java.util.List;
public class Perceptron_p {
public static void main(String[] args) {
//sketch: num neuronas
List<Integer> nN = new ArrayList<>();
nN.add(2);
nN.add(3);
nN.add(2);
nN.add(1);
double µ = 0.001;
int r = 0; // num. registro del dataset
int nK = nN.size(); // num. de capas = 4
int nE = nN.get(0); // num. de entradas = 2
int nS = nN.get(nK - 1); // num. de salidas = 1
int max = nN.stream().mapToInt(i -> i).max().getAsInt(); // num. max. neuronas por capa
String tmp;
double d_tmp;
// Inicializar dataset (sólo 1 registro o fila)
double[][] D = new double[1][3];
D[0][0] = 0.48d; // entrada 1
D[0][1] = 0.33d; // entrada 2
D[0][2] = 0.81d; // salida 1
// Inicializar pesos W, WBias, Y
double[][][] W = new double[nK][max][max];
double[][] WB = new double[nK][max];
double[][] Y = new double[nK][max];
double[][] E = new double[nK][max];
System.out.println("Inicializar pesos con valores aleatorios:\n");
for (int k = 1; k < nK; k++) {
for (int j = 0; j < nN.get(k); j++) {
for (int i = 0; i < nN.get(k - 1); i++) {
W[k][j][i] = Math.random();
System.out.format("W[%d][%d][%d] = %f\n", k, j, i, W[k][j][i]);
}
WB[k][j] = Math.random();
System.out.format("WB[%d][%d] = %f\n\n", k, j, WB[k][j]);
Y[k][j] = 0.f;
E[k][j] = 0.f;
}
}
// 0.0:-------------------------------------------------------------------
System.out.println("Forward:\n");
int k = 1;
for (int j = 0; j < nN.get(k); j++) {
tmp = "";
d_tmp = 0f;
for (int i = 0; i < nE; i++) {
tmp += String.format("( D[%d][%d] * W[%d][%d][%d] ) + ", r, i, k, j, i);
d_tmp += D[r][i] * W[k][j][i];
}
Y[k][j] = F(d_tmp + (-1 * WB[k][j]), 0);
System.out.format("Y[%d][%d] = F{ %s( -1 * WB[%d][%d] ) } = ", k, j, tmp, k, j);
System.out.println(Y[k][j]);
}
// 0.1:-------------------------------------------------------------------
System.out.println("");
for (k = 2; k < nK; k++) {
for (int j = 0; j < nN.get(k); j++) {
tmp = "";
d_tmp = 0f;
for (int i = 0; i < nN.get(k - 1); i++) {
tmp += String.format("( Y[%d][%d] * W[%d][%d][%d] ) + ", k - 1, i, k, j, i);
d_tmp += Y[k - 1][i] * W[k][j][i];
}
System.out.format("Y[%d][%d] = F{ %s( -1 * WB[%d][%d] ) } = ", k, j, tmp, k, j);
Y[k][j] = F(d_tmp + (-1 * WB[k][j]), 0);
System.out.println(Y[k][j]);
}
System.out.println("");
}
// 1.0:-------------------------------------------------------------------
System.out.println("Backward:\n");
k = nK - 1;
for (int j = 0; j < nS; j++) {
E[k][j] = D[r][nE + j] - Y[k][j];
System.out.format("E[%d][%d] = ( D[%d][%d] - Y[%d][%d] ) = ", k, j, r, nE + j, k, j);
System.out.println(E[k][j]);
}
// 1.1:-------------------------------------------------------------------
System.out.println("");
for (k = k - 1; k > 0; k--) {
for (int j = nN.get(k); j > 0; j--) {
tmp = "";
d_tmp = 0.d;
for (int i = nN.get(k + 1); i > 0; i--) {
tmp += String.format("( E[%d][%d] * W[%d][%d][%d] ) + ", k + 1, i - 1, k + 1, i - 1, j - 1);
d_tmp += E[k + 1][i - 1] * W[k + 1][i - 1][j - 1];
}
System.out.format("E[%d][%d] = %s%s = ", k, j - 1, tmp, "0 ");
System.out.println(d_tmp);
E[k][j - 1] = d_tmp;
}
System.out.println("");
}
// 2.0:-------------------------------------------------------------------
System.out.println("Ajuste pesos:\n");
k = 1;
for (int j = 0; j < nN.get(k); j++) {
for (int i = 0; i < nE; i++) {
W[k][j][i] += (µ * E[k][j] * F(Y[k][j], 1) * D[r][i]);
System.out.format("W'[%d][%d][%d] = W[%d][%d][%d] + ( µ * E[%d][%d] * F'(Y[%d][%d]) * D[%d][%d] ) = ", k, j, i, k, j, i, k, j, k, j, r, i);
System.out.println(W[k][j][i]);
}
WB[k][j] += (µ * E[k][j] * F(Y[k][j], 1) * -1);
System.out.format("WB'[%d][%d] = WB[%d][%d] + ( µ * E[%d][%d] * F'(Y[%d][%d]) * (%d) ) = ", k, j, k, j, k, j, k, j, - 1);
System.out.println(WB[k][j] + "\n");
}
// 2.1:-------------------------------------------------------------------
System.out.println("");
for (k = 2; k < nK; k++) {
for (int j = 0; j < nN.get(k); j++) {
for (int i = 0; i < nN.get(k - 1); i++) {
W[k][j][i] += (µ * E[k][j] * F(Y[k][j], 1) * Y[k - 1][i]);
System.out.format("W'[%d][%d][%d] = W[%d][%d][%d] + ( µ * E[%d][%d] * F'( Y[%d][%d] ) * Y[%d][%d] ) = ", k, j, i, k, j, i, k, j, k, j, k - 1, i);
System.out.println(W[k][j][i]);
}
WB[k][j] += (µ * E[k][j] * F(Y[k][j], 2) * (-1));
System.out.format("WB'[%d][%d] = WB[%d][%d] + ( µ * E[%d][%d] * F'(Y[%d][%d]) * (%d) ) = ", k, j, k, j, k, j, k, j, -1);
System.out.println(WB[k][j] + "\n");
}
System.out.println("");
}
}
// Función Activación - Derivada
private static double F(double n, int op) {
double fx;
switch (op) {
case 0: // función sigmoide
fx = 1.0 / (1.0 + Math.pow(Math.E, -n));
break;
case 1: // derivada función sigmoide
fx = 1.0 / (1.0 + Math.pow(Math.E, -n));
fx = fx * (1 - fx);
break;
default:
fx = 0.f;
break;
}
return fx;
}
}
Resultado:
run:
Inicializar pesos con valores aleatorios:
W[1][0][0] = 0,835049
W[1][0][1] = 0,308429
WB[1][0] = 0,052288
W[1][1][0] = 0,217787
W[1][1][1] = 0,348034
WB[1][1] = 0,588298
W[1][2][0] = 0,961801
W[1][2][1] = 0,796138
WB[1][2] = 0,044188
W[2][0][0] = 0,994101
W[2][0][1] = 0,211034
W[2][0][2] = 0,711812
WB[2][0] = 0,952732
W[2][1][0] = 0,423756
W[2][1][1] = 0,953356
W[2][1][2] = 0,249125
WB[2][1] = 0,973105
W[3][0][0] = 0,842807
W[3][0][1] = 0,794736
WB[3][0] = 0,290240
Forward:
Y[1][0] = F{ ( D[0][0] * W[1][0][0] ) + ( D[0][1] * W[1][0][1] ) + ( -1 * WB[1][0] ) } = 0.6107146316470909
Y[1][1] = F{ ( D[0][0] * W[1][1][0] ) + ( D[0][1] * W[1][1][1] ) + ( -1 * WB[1][1] ) } = 0.40880474360914854
Y[1][2] = F{ ( D[0][0] * W[1][2][0] ) + ( D[0][1] * W[1][2][1] ) + ( -1 * WB[1][2] ) } = 0.6637837549590786
Y[2][0] = F{ ( Y[1][0] * W[2][0][0] ) + ( Y[1][1] * W[2][0][1] ) + ( Y[1][2] * W[2][0][2] ) + ( -1 * WB[2][0] ) } = 0.5530844896875817
Y[2][1] = F{ ( Y[1][0] * W[2][1][0] ) + ( Y[1][1] * W[2][1][1] ) + ( Y[1][2] * W[2][1][2] ) + ( -1 * WB[2][1] ) } = 0.46028147962310223
Y[3][0] = F{ ( Y[2][0] * W[3][0][0] ) + ( Y[2][1] * W[3][0][1] ) + ( -1 * WB[3][0] ) } = 0.6322090580829307
Backward:
E[3][0] = ( D[0][2] - Y[3][0] ) = 0.17779094191706935
E[2][1] = ( E[3][0] * W[3][0][1] ) + 0 = 0.14129683962211012
E[2][0] = ( E[3][0] * W[3][0][0] ) + 0 = 0.1498433870202291
E[1][2] = ( E[2][1] * W[2][1][2] ) + ( E[2][0] * W[2][0][2] ) + 0 = 0.1418609770496571
E[1][1] = ( E[2][1] * W[2][1][1] ) + ( E[2][0] * W[2][0][1] ) + 0 = 0.16632825764793913
E[1][0] = ( E[2][1] * W[2][1][0] ) + ( E[2][0] * W[2][0][0] ) + 0 = 0.2088347664166445
Ajuste pesos:
W'[1][0][0] = W[1][0][0] + ( µ * E[1][0] * F'(Y[1][0]) * D[0][0] ) = 0.8350717767495889
W'[1][0][1] = W[1][0][1] + ( µ * E[1][0] * F'(Y[1][0]) * D[0][1] ) = 0.3084447906938308
WB'[1][0] = WB[1][0] + ( µ * E[1][0] * F'(Y[1][0]) * (-1) ) = 0.05224031629899943
W'[1][1][0] = W[1][1][0] + ( µ * E[1][1] * F'(Y[1][1]) * D[0][0] ) = 0.21780595558207116
W'[1][1][1] = W[1][1][1] + ( µ * E[1][1] * F'(Y[1][1]) * D[0][1] ) = 0.34804701774866154
WB'[1][1] = WB[1][1] + ( µ * E[1][1] * F'(Y[1][1]) * (-1) ) = 0.5882576504954621
W'[1][2][0] = W[1][2][0] + ( µ * E[1][2] * F'(Y[1][2]) * D[0][0] ) = 0.9618160101133663
W'[1][2][1] = W[1][2][1] + ( µ * E[1][2] * F'(Y[1][2]) * D[0][1] ) = 0.7961484238865005
WB'[1][2] = WB[1][2] + ( µ * E[1][2] * F'(Y[1][2]) * (-1) ) = 0.04415614986229021
W'[2][0][0] = W[2][0][0] + ( µ * E[2][0] * F'( Y[2][0] ) * Y[1][0] ) = 0.9941217290526374
W'[2][0][1] = W[2][0][1] + ( µ * E[2][0] * F'( Y[2][0] ) * Y[1][1] ) = 0.21104869817169436
W'[2][0][2] = W[2][0][2] + ( µ * E[2][0] * F'( Y[2][0] ) * Y[1][2] ) = 0.7118355488714299
WB'[2][0] = WB[2][0] + ( µ * E[2][0] * F'(Y[2][0]) * (-1) ) = 0.9527319900854492
W'[2][1][0] = W[2][1][0] + ( µ * E[2][1] * F'( Y[2][1] ) * Y[1][0] ) = 0.4237764313332067
W'[2][1][1] = W[2][1][1] + ( µ * E[2][1] * F'( Y[2][1] ) * Y[1][1] ) = 0.953369304782218
W'[2][1][2] = W[2][1][2] + ( µ * E[2][1] * F'( Y[2][1] ) * Y[1][2] ) = 0.2491472992670435
WB'[2][1] = WB[2][1] + ( µ * E[2][1] * F'(Y[2][1]) * (-1) ) = 0.9731049511389623
W'[3][0][0] = W[3][0][0] + ( µ * E[3][0] * F'( Y[3][0] ) * Y[2][0] ) = 0.8428289253648974
W'[3][0][1] = W[3][0][1] + ( µ * E[3][0] * F'( Y[3][0] ) * Y[2][1] ) = 0.7947544171128877
WB'[3][0] = WB[3][0] + ( µ * E[3][0] * F'(Y[3][0]) * (-1) ) = 0.29024004297076156
BUILD SUCCESSFUL (total time: 2 seconds)
sábado, 22 de junio de 2019
Perceptrón multicapa. Ajuste pesos.
Siguiendo el hilo anterior en esta ocasión se procede ajustar los pesos (W) para minimizar el error. Para ello son utilizadas las siguientes variables:
μ = Tasa de aprendizaje
δ = Error neurona (E)
Ø = Bias (-1)
ʄ = Función de activación
ʄ' = Derivada de la función de activación
ΔW = Delta de los pesos
Función Sigmoide:
ʄ(x) = 1 / ( 1 + e^(-x) )
Derivada función Sigmoide:
ʄ'(x) = ʄ(x) * ( 1 - ʄ(x) )
Cálculo deltas(Δ) de los pesos:
ΔW = µ * δ * ʄ'(x) * Y
ΔW = µ * δ * ʄ'(x) * Ø -> para ajuste pesos del Bias(Ø)
Ajuste pesos:
W' = W + ΔW
Código Java:
package ajustePesos;
import java.util.ArrayList;
import java.util.List;
public class AjustePesos {
public static void main(String[] args) {
//sketch: num neuronas
List<Integer> nN = new ArrayList<>();
nN.add(2);
nN.add(3);
nN.add(2);
nN.add(1);
double µ = 0.001;
int r = 0; // num. registro del dataset
int nK = nN.size(); // num. de capas = 4
int nE = nN.get(0); // num. de entradas = 2
int nS = nN.get(nK - 1); // num. de salidas = 1
String tmp;
// 2.0:-------------------------------------------------------------------
System.out.println("Ajuste pesos:\n");
k = 1;
for (int j = 0; j < nN.get(k); j++) {
for (int i = 0; i < nE; i++) {
System.out.format("W'[%d][%d][%d] = W[%d][%d][%d] + ( µ * E[%d][%d] * F'(Y[%d][%d]) * D[%d][%d] )\n", k, j, i, k, j, i, k, j, k, j, r, i);
}
System.out.format("WB'[%d][%d] = WB[%d][%d] + ( µ * E[%d][%d] * F'(Y[%d][%d]) * %d)\n\n", k, j, k, j, k, j, k, j, - 1);
}
// 2.1:-------------------------------------------------------------------
System.out.println("");
for (k = 2; k < nK; k++) {
for (int j = 0; j < nN.get(k); j++) {
for (int i = 0; i < nN.get(k - 1); i++) {
System.out.format("W'[%d][%d][%d] = W[%d][%d][%d] + ( µ * E[%d][%d] * F'( Y[%d][%d] ) * Y[%d][%d] )\n", k, j, i, k, j, i, k, j, k, j, k - 1, i);
}
System.out.format("WB'[%d][%d] = WB[%d][%d] + ( µ * E[%d][%d] * F'(Y[%d][%d]) * (%d) )\n\n", k, j, k, j, k, j, k, j, -1);
}
System.out.println("");
}
}
}
Resultado:
run:
Ajuste pesos:
W'[1][0][0] = W[1][0][0] + ( µ * E[1][0] * F'(Y[1][0]) * D[0][0] )
W'[1][0][1] = W[1][0][1] + ( µ * E[1][0] * F'(Y[1][0]) * D[0][1] )
WB'[1][0] = WB[1][0] + ( µ * E[1][0] * F'(Y[1][0]) * -1)
W'[1][1][0] = W[1][1][0] + ( µ * E[1][1] * F'(Y[1][1]) * D[0][0] )
W'[1][1][1] = W[1][1][1] + ( µ * E[1][1] * F'(Y[1][1]) * D[0][1] )
WB'[1][1] = WB[1][1] + ( µ * E[1][1] * F'(Y[1][1]) * -1)
W'[1][2][0] = W[1][2][0] + ( µ * E[1][2] * F'(Y[1][2]) * D[0][0] )
W'[1][2][1] = W[1][2][1] + ( µ * E[1][2] * F'(Y[1][2]) * D[0][1] )
WB'[1][2] = WB[1][2] + ( µ * E[1][2] * F'(Y[1][2]) * -1)
W'[2][0][0] = W[2][0][0] + ( µ * E[2][0] * F'( Y[2][0] ) * Y[1][0] )
W'[2][0][1] = W[2][0][1] + ( µ * E[2][0] * F'( Y[2][0] ) * Y[1][1] )
W'[2][0][2] = W[2][0][2] + ( µ * E[2][0] * F'( Y[2][0] ) * Y[1][2] )
WB'[2][0] = WB[2][0] + ( µ * E[2][0] * F'(Y[2][0]) * (-1) )
W'[2][1][0] = W[2][1][0] + ( µ * E[2][1] * F'( Y[2][1] ) * Y[1][0] )
W'[2][1][1] = W[2][1][1] + ( µ * E[2][1] * F'( Y[2][1] ) * Y[1][1] )
W'[2][1][2] = W[2][1][2] + ( µ * E[2][1] * F'( Y[2][1] ) * Y[1][2] )
WB'[2][1] = WB[2][1] + ( µ * E[2][1] * F'(Y[2][1]) * (-1) )
W'[3][0][0] = W[3][0][0] + ( µ * E[3][0] * F'( Y[3][0] ) * Y[2][0] )
W'[3][0][1] = W[3][0][1] + ( µ * E[3][0] * F'( Y[3][0] ) * Y[2][1] )
WB'[3][0] = WB[3][0] + ( µ * E[3][0] * F'(Y[3][0]) * (-1) )
BUILD SUCCESSFUL (total time: 5 seconds)
μ = Tasa de aprendizaje
δ = Error neurona (E)
Ø = Bias (-1)
ʄ = Función de activación
ʄ' = Derivada de la función de activación
ΔW = Delta de los pesos
Función Sigmoide:
ʄ(x) = 1 / ( 1 + e^(-x) )
Derivada función Sigmoide:
ʄ'(x) = ʄ(x) * ( 1 - ʄ(x) )
Cálculo deltas(Δ) de los pesos:
ΔW = µ * δ * ʄ'(x) * Y
ΔW = µ * δ * ʄ'(x) * Ø -> para ajuste pesos del Bias(Ø)
Ajuste pesos:
W' = W + ΔW
Código Java:
package ajustePesos;
import java.util.ArrayList;
import java.util.List;
public class AjustePesos {
public static void main(String[] args) {
//sketch: num neuronas
List<Integer> nN = new ArrayList<>();
nN.add(2);
nN.add(3);
nN.add(2);
nN.add(1);
double µ = 0.001;
int r = 0; // num. registro del dataset
int nK = nN.size(); // num. de capas = 4
int nE = nN.get(0); // num. de entradas = 2
int nS = nN.get(nK - 1); // num. de salidas = 1
String tmp;
// 2.0:-------------------------------------------------------------------
System.out.println("Ajuste pesos:\n");
k = 1;
for (int j = 0; j < nN.get(k); j++) {
for (int i = 0; i < nE; i++) {
System.out.format("W'[%d][%d][%d] = W[%d][%d][%d] + ( µ * E[%d][%d] * F'(Y[%d][%d]) * D[%d][%d] )\n", k, j, i, k, j, i, k, j, k, j, r, i);
}
System.out.format("WB'[%d][%d] = WB[%d][%d] + ( µ * E[%d][%d] * F'(Y[%d][%d]) * %d)\n\n", k, j, k, j, k, j, k, j, - 1);
}
// 2.1:-------------------------------------------------------------------
System.out.println("");
for (k = 2; k < nK; k++) {
for (int j = 0; j < nN.get(k); j++) {
for (int i = 0; i < nN.get(k - 1); i++) {
System.out.format("W'[%d][%d][%d] = W[%d][%d][%d] + ( µ * E[%d][%d] * F'( Y[%d][%d] ) * Y[%d][%d] )\n", k, j, i, k, j, i, k, j, k, j, k - 1, i);
}
System.out.format("WB'[%d][%d] = WB[%d][%d] + ( µ * E[%d][%d] * F'(Y[%d][%d]) * (%d) )\n\n", k, j, k, j, k, j, k, j, -1);
}
System.out.println("");
}
}
}
Resultado:
run:
Ajuste pesos:
W'[1][0][0] = W[1][0][0] + ( µ * E[1][0] * F'(Y[1][0]) * D[0][0] )
W'[1][0][1] = W[1][0][1] + ( µ * E[1][0] * F'(Y[1][0]) * D[0][1] )
WB'[1][0] = WB[1][0] + ( µ * E[1][0] * F'(Y[1][0]) * -1)
W'[1][1][0] = W[1][1][0] + ( µ * E[1][1] * F'(Y[1][1]) * D[0][0] )
W'[1][1][1] = W[1][1][1] + ( µ * E[1][1] * F'(Y[1][1]) * D[0][1] )
WB'[1][1] = WB[1][1] + ( µ * E[1][1] * F'(Y[1][1]) * -1)
W'[1][2][0] = W[1][2][0] + ( µ * E[1][2] * F'(Y[1][2]) * D[0][0] )
W'[1][2][1] = W[1][2][1] + ( µ * E[1][2] * F'(Y[1][2]) * D[0][1] )
WB'[1][2] = WB[1][2] + ( µ * E[1][2] * F'(Y[1][2]) * -1)
W'[2][0][0] = W[2][0][0] + ( µ * E[2][0] * F'( Y[2][0] ) * Y[1][0] )
W'[2][0][1] = W[2][0][1] + ( µ * E[2][0] * F'( Y[2][0] ) * Y[1][1] )
W'[2][0][2] = W[2][0][2] + ( µ * E[2][0] * F'( Y[2][0] ) * Y[1][2] )
WB'[2][0] = WB[2][0] + ( µ * E[2][0] * F'(Y[2][0]) * (-1) )
W'[2][1][0] = W[2][1][0] + ( µ * E[2][1] * F'( Y[2][1] ) * Y[1][0] )
W'[2][1][1] = W[2][1][1] + ( µ * E[2][1] * F'( Y[2][1] ) * Y[1][1] )
W'[2][1][2] = W[2][1][2] + ( µ * E[2][1] * F'( Y[2][1] ) * Y[1][2] )
WB'[2][1] = WB[2][1] + ( µ * E[2][1] * F'(Y[2][1]) * (-1) )
W'[3][0][0] = W[3][0][0] + ( µ * E[3][0] * F'( Y[3][0] ) * Y[2][0] )
W'[3][0][1] = W[3][0][1] + ( µ * E[3][0] * F'( Y[3][0] ) * Y[2][1] )
WB'[3][0] = WB[3][0] + ( µ * E[3][0] * F'(Y[3][0]) * (-1) )
BUILD SUCCESSFUL (total time: 5 seconds)
miércoles, 12 de junio de 2019
Perceptrón multicapa. Propagación hacia atrás.
Descripción:
En base al valor de salida del dataset (D02), se visualiza la base conceptual para el cálculo de los errores (Exx) de cada neurona (Yxx) de una red neuronal tipo perceptrón multicapa. Todo ese proceso se le llama propagación hacia atrás.
Nomenclatura:
Y[k][j]: Salida neurona (capa, posición j-enésima)
E[k][j]: Error neurona (δ) (capa, posición j-enésima)
W[k][j][i]: Peso (capa, neurona destino, neurona origen)
Código Java:
package backward;
import java.util.ArrayList;
import java.util.List;
public class Backward{
public static void main(String[] args) {
//sketch: num neuronas
List<Integer> nN = new ArrayList<>();
nN.add(2);
nN.add(3);
nN.add(2);
nN.add(1);
int r = 0; // num. registro del dataset
int nK = nN.size(); // num. de capas = 4
int nE = nN.get(0); // num. de entradas = 2
int nS = nN.get(nK - 1); // num. de salidas = 1
String tmp;
// 1.0:-------------------------------------------------------------------
System.out.println("Backward:\n");
int k = nK - 1;
for (int j = 0; j < nS; j++) {
System.out.format("E[%d][%d] = ( D[%d][%d] - Y[%d][%d] )\n", k, j, r, nE + j, k, j);
}
// 1.1:-------------------------------------------------------------------
System.out.println("");
for (k = k - 1; k > 0; k--) {
for (int j = nN.get(k); j > 0; j--) {
tmp = "";
for (int i = nN.get(k + 1); i > 0; i--) {
tmp += String.format("( E[%d][%d] * W[%d][%d][%d] ) + ", k + 1, i - 1, k + 1, i - 1, j - 1);
}
System.out.format("E[%d][%d] = %s%s\n", k, j - 1, tmp, "0 ");
}
System.out.println("");
}
}
}
Resultado:
run:
Backward:
E[3][0] = ( D[0][2] - Y[3][0] )
E[2][1] = ( E[3][0] * W[3][0][1] ) + 0
E[2][0] = ( E[3][0] * W[3][0][0] ) + 0
E[1][2] = ( E[2][1] * W[2][1][2] ) + ( E[2][0] * W[2][0][2] ) + 0
E[1][1] = ( E[2][1] * W[2][1][1] ) + ( E[2][0] * W[2][0][1] ) + 0
E[1][0] = ( E[2][1] * W[2][1][0] ) + ( E[2][0] * W[2][0][0] ) + 0
BUILD SUCCESSFUL (total time: 1 second)
lunes, 10 de junio de 2019
Perceptrón multicapa. Propagación hacia adelante.
Descripción:
En base a los valores de entrada Dxx (dataset), Wxxx (pesos) y WBxx (bias pesos), se visualiza la base conceptual para el cálculo de las salidas de las neuronas (Yxx) de una red neuronal tipo perceptrón multicapa. Todo ese proceso se le llama propagación hacia delante.
Nomenclatura:
Y[k][j]: Salida neurona (capa, posición j-enésima)
W[k][j][i]: Peso (capa, neurona destino, neurona origen)
WB[k][j]: Pesos Bias (capa, posición j-enésima)
F: Función Activación
Dataset:
D[row][col]: Dataset (fila, columna)
0 1 2 col(n)
0 D00 D01 D02 .
1 D10 D11 D12 .
2 D20 D21 D22 .
. . . . .
row(n)
Código Java:
package forward;
import java.util.ArrayList;
import java.util.List;
public class Forward {
public static void main(String[] args) {
//sketch: num neuronas
List<Integer> nN = new ArrayList<>();
nN.add(2);
nN.add(3);
nN.add(2);
nN.add(1);
int r = 0; // num. registro del dataset
int nK = nN.size(); // num. de capas = 4
int nE = nN.get(0); // num. de entradas = 2
int nS = nN.get(nK - 1); // num. de salidas = 1
String tmp;
// 0.0:-------------------------------------------------------------------
System.out.println("Forward:\n");
int k = 1;
for (int j = 0; j < nN.get(k); j++) {
tmp = "";
for (int i = 0; i < nE; i++) {
tmp += String.format("( D[%d][%d] * W[%d][%d][%d] ) + ", r, i, k, j, i);
}
System.out.format("Y[%d][%d] = F{ %s( -1 * WB[%d][%d] ) }\n", k, j, tmp, k, j);
}
// 0.1:-------------------------------------------------------------------
System.out.println("");
for (k = 2; k < nK; k++) {
for (int j = 0; j < nN.get(k); j++) {
tmp = "";
for (int i = 0; i < nN.get(k - 1); i++) {
tmp += String.format("( Y[%d][%d] * W[%d][%d][%d] ) + ", k - 1, i, k, j, i);
}
System.out.format("Y[%d][%d] = F{ %s( -1 * WB[%d][%d] ) }\n", k, j, tmp, k, j);
}
System.out.println("");
}
}
}
Resultado:
run:
Forward:
Y[1][0] = F{ ( D[0][0] * W[1][0][0] ) + ( D[0][1] * W[1][0][1] ) + ( -1 * WB[1][0] ) }
Y[1][1] = F{ ( D[0][0] * W[1][1][0] ) + ( D[0][1] * W[1][1][1] ) + ( -1 * WB[1][1] ) }
Y[1][2] = F{ ( D[0][0] * W[1][2][0] ) + ( D[0][1] * W[1][2][1] ) + ( -1 * WB[1][2] ) }
Y[2][0] = F{ ( Y[1][0] * W[2][0][0] ) + ( Y[1][1] * W[2][0][1] ) + ( Y[1][2] * W[2][0][2] ) + ( -1 * WB[2][0] ) }
Y[2][1] = F{ ( Y[1][0] * W[2][1][0] ) + ( Y[1][1] * W[2][1][1] ) + ( Y[1][2] * W[2][1][2] ) + ( -1 * WB[2][1] ) }
Y[3][0] = F{ ( Y[2][0] * W[3][0][0] ) + ( Y[2][1] * W[3][0][1] ) + ( -1 * WB[3][0] ) }
BUILD SUCCESSFUL (total time: 0 seconds)
domingo, 21 de abril de 2019
Crear una tabla (dataset) usando listas.
En Java no existe el concepto de Listas Multidimensionales. Para ello mediante código se puede simular listas multidimensionales creando listas dentro de otras listas:
List<List<Double>> dataset1 = new ArrayList<List<Double>>();
En el ejemplo se crea una tabla de 3x10 mediante listas con la que se llenará con valores numéricos para luego imprimirlo en pantalla.
Código (DataSets1.java):
package datasets1;
import java.util.ArrayList;
import java.util.List;
public class DataSets1 {
public static void main(String[] args) {
//Dataset 2d
List<List<Double>> dataset1 = new ArrayList<List<Double>>();
//Agregar 3 sublistas (columnas)
for (int i = 0; i < 3; i++) {
dataset1.add(new ArrayList<Double>());
}
/*
@ Añadir datos al dataset (suma)
*/
//operando 1
dataset1.get(0).add(48.0);
dataset1.get(0).add(1.0);
dataset1.get(0).add(41.0);
dataset1.get(0).add(6.0);
dataset1.get(0).add(5.0);
dataset1.get(0).add(18.0);
dataset1.get(0).add(35.0);
dataset1.get(0).add(2.0);
dataset1.get(0).add(44.0);
dataset1.get(0).add(24.0);
//operando 2
dataset1.get(1).add(33.0);
dataset1.get(1).add(38.0);
dataset1.get(1).add(25.0);
dataset1.get(1).add(27.0);
dataset1.get(1).add(42.0);
dataset1.get(1).add(12.0);
dataset1.get(1).add(39.0);
dataset1.get(1).add(17.0);
dataset1.get(1).add(14.0);
dataset1.get(1).add(37.0);
//resultado 1
dataset1.get(2).add(81.0);
dataset1.get(2).add(39.0);
dataset1.get(2).add(66.0);
dataset1.get(2).add(33.0);
dataset1.get(2).add(47.0);
dataset1.get(2).add(30.0);
dataset1.get(2).add(74.0);
dataset1.get(2).add(19.0);
dataset1.get(2).add(58.0);
dataset1.get(2).add(61.0);
//imprimir dataset1
System.out.println("'operando1', 'operando2', 'resultado1'");
for (int i = 0; i <= dataset1.get(0).size() - 1; i++) {
for (int j = 0; j < dataset1.size(); j++) {
System.out.print(dataset1.get(j).get(i) + ";\t");
}
System.out.println("");
}
}
}
Resultado:
run:
'operando1', 'operando2', 'resultado1'
48.0; 33.0; 81.0;
1.0; 38.0; 39.0;
41.0; 25.0; 66.0;
6.0; 27.0; 33.0;
5.0; 42.0; 47.0;
18.0; 12.0; 30.0;
35.0; 39.0; 74.0;
2.0; 17.0; 19.0;
44.0; 14.0; 58.0;
24.0; 37.0; 61.0;
BUILD SUCCESSFUL (total time: 0 seconds)
List<List<Double>> dataset1 = new ArrayList<List<Double>>();
En el ejemplo se crea una tabla de 3x10 mediante listas con la que se llenará con valores numéricos para luego imprimirlo en pantalla.
Código (DataSets1.java):
package datasets1;
import java.util.ArrayList;
import java.util.List;
public class DataSets1 {
public static void main(String[] args) {
//Dataset 2d
List<List<Double>> dataset1 = new ArrayList<List<Double>>();
//Agregar 3 sublistas (columnas)
for (int i = 0; i < 3; i++) {
dataset1.add(new ArrayList<Double>());
}
/*
@ Añadir datos al dataset (suma)
*/
//operando 1
dataset1.get(0).add(48.0);
dataset1.get(0).add(1.0);
dataset1.get(0).add(41.0);
dataset1.get(0).add(6.0);
dataset1.get(0).add(5.0);
dataset1.get(0).add(18.0);
dataset1.get(0).add(35.0);
dataset1.get(0).add(2.0);
dataset1.get(0).add(44.0);
dataset1.get(0).add(24.0);
//operando 2
dataset1.get(1).add(33.0);
dataset1.get(1).add(38.0);
dataset1.get(1).add(25.0);
dataset1.get(1).add(27.0);
dataset1.get(1).add(42.0);
dataset1.get(1).add(12.0);
dataset1.get(1).add(39.0);
dataset1.get(1).add(17.0);
dataset1.get(1).add(14.0);
dataset1.get(1).add(37.0);
//resultado 1
dataset1.get(2).add(81.0);
dataset1.get(2).add(39.0);
dataset1.get(2).add(66.0);
dataset1.get(2).add(33.0);
dataset1.get(2).add(47.0);
dataset1.get(2).add(30.0);
dataset1.get(2).add(74.0);
dataset1.get(2).add(19.0);
dataset1.get(2).add(58.0);
dataset1.get(2).add(61.0);
//imprimir dataset1
System.out.println("'operando1', 'operando2', 'resultado1'");
for (int i = 0; i <= dataset1.get(0).size() - 1; i++) {
for (int j = 0; j < dataset1.size(); j++) {
System.out.print(dataset1.get(j).get(i) + ";\t");
}
System.out.println("");
}
}
}
Resultado:
run:
'operando1', 'operando2', 'resultado1'
48.0; 33.0; 81.0;
1.0; 38.0; 39.0;
41.0; 25.0; 66.0;
6.0; 27.0; 33.0;
5.0; 42.0; 47.0;
18.0; 12.0; 30.0;
35.0; 39.0; 74.0;
2.0; 17.0; 19.0;
44.0; 14.0; 58.0;
24.0; 37.0; 61.0;
BUILD SUCCESSFUL (total time: 0 seconds)
Suscribirse a:
Entradas (Atom)
Con la tecnología de Blogger.