Saltar al contenido

Red neuronal para aproximación al cuadrado (x^2)

Siéntete en la libertad de compartir nuestra página y códigos en tus redes, necesitamos tu ayuda para hacer crecer esta comunidad.

Solución:

Estás cometiendo dos errores muy básicos:

  • Su modelo ultra simple (una red de una sola capa con una sola unidad) difícilmente califica como una red neuronal, y mucho menos como una de “aprendizaje profundo” (como está etiquetada su pregunta)
  • Del mismo modo, su conjunto de datos (solo 20 muestras) también es ultrapequeño

Ciertamente se entiende que las redes neuronales deben ser de cierta complejidad si van a resolver problemas incluso tan “simples” como x*x; y donde realmente brillan es cuando se alimentan con grandes conjuntos de datos de entrenamiento.

La metodología cuando se trata de resolver tales aproximaciones de funciones no es solo enumerar las (pocas posibles) entradas y luego alimentarlas al modelo, junto con las salidas deseadas; recuerde, los NN aprenden a través de ejemplos y no a través del razonamiento simbólico. Y cuantos más ejemplos, mejor. Lo que solemos hacer en casos similares es generar una gran cantidad de ejemplos, que posteriormente alimentamos al modelo para el entrenamiento.

Habiendo dicho eso, aquí hay una demostración bastante simple de una red neuronal de 3 capas en Keras para aproximar la función x*xutilizando como entrada 10.000 números aleatorios generados en [-50, 50]:

import numpy as np
import keras
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import Adam
from keras import regularizers
import matplotlib.pyplot as plt

model = Sequential()
model.add(Dense(8, activation='relu', kernel_regularizer=regularizers.l2(0.001), input_shape = (1,)))
model.add(Dense(8, activation='relu', kernel_regularizer=regularizers.l2(0.001)))
model.add(Dense(1))

model.compile(optimizer=Adam(),loss='mse')

# generate 10,000 random numbers in [-50, 50], along with their squares
x = np.random.random((10000,1))*100-50
y = x**2

# fit the model, keeping 2,000 samples as validation set
hist = model.fit(x,y,validation_split=0.2,
             epochs= 15000,
             batch_size=256)

# check some predictions:
print(model.predict([4, -4, 11, 20, 8, -5]))
# result:
[[ 16.633354]
 [ 15.031291]
 [121.26833 ]
 [397.78638 ]
 [ 65.70035 ]
 [ 27.040245]]

Bueno, ¡no tan mal! Recuerda que los NN son función aproximadores: debemos esperar que ellos tampoco exactamente reproducir la relación funcional ni “saber” que los resultados para 4 y -4 debería ser idéntico.

Vamos a generar algunos nuevos datos aleatorios en [-50,50] (recuerde, a todos los efectos prácticos, estos son invisible datos para el modelo) y graficarlos, junto con los originales, para obtener una imagen más general:

plt.figure(figsize=(14,5))
plt.subplot(1,2,1)
p = np.random.random((1000,1))*100-50 # new random data in [-50, 50]
plt.plot(p,model.predict(p), '.')
plt.xlabel('x')
plt.ylabel('prediction')
plt.title('Predictions on NEW data in [-50,50]')

plt.subplot(1,2,2)
plt.xlabel('x')
plt.ylabel('y')
plt.plot(x,y,'.')
plt.title('Original data')

Resultado:

ingrese la descripción de la imagen aquí

Bueno, podría decirse que parece una buena aproximación de hecho…

También puede echar un vistazo a este hilo para una aproximación sinusoidal.

Lo último a tener en cuenta es que, aunque obtuvimos una aproximación decente incluso con nuestro modelo relativamente simple, lo que deberíamos no esperar es extrapolaciónes decir, buen rendimiento fuera [-50, 50]; para más detalles, vea mi respuesta en ¿Es malo el aprendizaje profundo para ajustar funciones no lineales simples fuera del alcance del entrenamiento?

El problema es ese x*x es una bestia muy diferente a a*x.

Tenga en cuenta lo que hace una “red neuronal” habitual: se acumula y = f(W*x + b) un par de veces, nunca multiplicando x consigo mismo Por lo tanto, nunca obtendrá una reconstrucción perfecta de x*x. A menos que establezca f(x) = x*x o similar.

Lo que puede obtener es una aproximación en el rango de valores presentados durante el entrenamiento (y quizás un poco de extrapolación). De todos modos, te recomiendo que trabajes con un rango de valores más pequeño, será más fácil optimizar el problema.

Y en una nota filosófica: en el aprendizaje automático, encuentro más útil pensar en bueno/malo, en lugar de correcto/incorrecto. Especialmente con la regresión, no puede obtener el resultado “correcto” a menos que tenga el modelo exacto. En cuyo caso no hay nada que aprender.


En realidad, hay algunas arquitecturas NN que se multiplican f(x) con g(x), sobre todo LSTM y redes de autopistas. Pero incluso estos tienen uno o ambos de f(x), g(s) acotados (por sigmoide logístico o tanh), por lo que no pueden modelar x*x completamente.


Dado que hay algunos malentendidos expresados ​​en los comentarios, permítanme enfatizar algunos puntos:

  1. puede aproximar tu información.
  2. Para hacerlo bien en cualquier sentido, necesitas un capa oculta.
  3. Pero sin mas datos es necesario, aunque si cubre el espacio, el modelo encajará más de cerca, vea la respuesta de desernaut.

Como ejemplo, aquí hay un resultado de un modelo con una sola capa oculta de 10 unidades con activación tanh, entrenado por SGD con tasa de aprendizaje 1e-3 para 15k iteraciones para minimizar el MSE de sus datos. Mejor de cinco carreras:

Desempeño de un NN simple entrenado en datos de OP

Aquí está el código completo para reproducir el resultado. Lamentablemente, no puedo instalar Keras/TF en mi entorno actual, pero espero que se pueda acceder al código de PyTorch 🙂

#!/usr/bin/env python
import torch
import torch.nn as nn
import matplotlib.pyplot as plt

X = torch.tensor([range(-10,11)]).float().view(-1, 1)
Y = X*X

model = nn.Sequential(
    nn.Linear(1, 10),
    nn.Tanh(),
    nn.Linear(10, 1)
)

optimizer = torch.optim.SGD(model.parameters(), lr=1e-3)
loss_func = nn.MSELoss()
for _ in range(15000):
    optimizer.zero_grad()
    pred = model(X)
    loss = loss_func(pred, Y)
    loss.backward()
    optimizer.step()

x = torch.linspace(-12, 12, steps=200).view(-1, 1)
y = model(x)
f = x*x

plt.plot(x.detach().view(-1).numpy(), y.detach().view(-1).numpy(), 'r.', linestyle='None')
plt.plot(x.detach().view(-1).numpy(), f.detach().view(-1).numpy(), 'b')
plt.show()

Comentarios y puntuaciones

Si posees alguna desconfianza o capacidad de arreglar nuestro noticia te inspiramos realizar una aclaración y con deseo lo interpretaremos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *