Recuerda que R's cos()
trabaja en radianes. Así que 1:3000 es un muchos ciclos, todos apretados. (Haz plot(x,y)
para ver los datos de entrenamiento que está dando al modelo de aprendizaje profundo).
Sin embargo, creo que el problema de fondo que tiene es que "x" es su única variable de predicción. Usted entrena en valores de x de 1 a 2000, y luego le pregunta lo que podría dar de 2500 a 3000. Eso es bastante difícil.
Creo que podrías obtener mejores resultados si divides los datos de entrenamiento al azar; ver h2o.splitFrame()
. Entonces, por ejemplo, podría entrenarse en x=1,2,4,5,6,8 y se le pide que prediga x=3 y x=7. Puede que sea capaz de aprender la relación entre x=3 y los valores de x cercanos.
BTW, de forma más general, lo primero que yo intentaría es deshacerme de todos los sus argumentos, y utilizar un modelo por defecto. Los ajustes por defecto de H2O suelen ser buenos. Supongo que podría aumentar las épocas, desde las 10 por defecto, dado que los datos no son demasiado grandes:
m = h2o.deeplearning(
"C1",
"C2",
as.h2o(traincos),
as.h2o(validcos),
epochs=1e3
)
Y luego añadir un argumento de ajuste a la vez, para ver si hace las cosas mejor o peor.
En lugar de jugar con las tasas de aprendizaje, o los parámetros más exóticos, el primer ajuste que podría probar es una red más profunda. Por ejemplo hidden=[200,200,200]
en lugar de la opción por defecto [200,200]
.
ACTUALIZACIÓN:
Hice algunos experimentos. También obtuve malos resultados, al menos hasta que probé todas las ideas juntas. Aquí están algunas de las cosas que probé, y lo que sucedió:
Elección de una región más estrecha
En lugar de x = 1:3000
Lo intenté:
x = seq(0, 30, length.out = 3000)
Esto da algo más de 3 ciclos completos.
Esto fue lo que marcó la mayor diferencia.
Red más profunda:
epochs = 1000, activation = "Tanh", hidden = c(40,40,40,40,40)
El cambio a Tanh se debe a que tengo inestabilidad numérica.
Esto no ayudó mucho cuando x
fue 1:3000
pero lo hizo cuando x
fue sólo de 3 ciclos. Sin embargo, no experimenté más allá para acotar lo que es óptimo. Me llevó entre 600 y 700 épocas conseguir el mejor error de validación.
Algunas pistas:
x2 = x^2
x3 = x^3
x4 = x^4
x5 = x^5
x^3, x^5 y x^7 deberían ser suficientes para dar una buena predicción de -PI a +PI (Ver http://pages.pacificcoast.net/~cazelais/187/maclaurin-sin.pdf ). Pretendiendo ser honesto probé sólo las primeras 5 potencias. Más tarde añadí también x^6 y x^7.
El modelo por defecto con estas pistas no era mejor que sin ellas. Pero sí ayudaron al modelo profundo, y éste fue mejor con x^6 y x^7 que sin ellas.
Con las pistas hasta x^7, y utilizando la red profunda, y usando solo 3 ciclos, este fue el mejor resultado que obtuve:
(el verde corresponde a los datos de entrenamiento, el azul a los de validación y el rojo a los de prueba).
Uso de splitFrame
Sólo experimenté brevemente con esto; a juzgar por el historial de puntuaciones, no estaba aprendiendo muy bien. Sin embargo, sólo lo probé cuando x=1:3000
...así que vamos a probarlo con mi último experimento... El código de división:
x = seq(0,30,length.out = 3000)
y = cos(x)
x2 = x^2
x3 = x^3
x4 = x^4
x5 = x^5
x6 = x^6
x7 = x^7
data = as.h2o(data.frame(y, x, x2, x3, x4, x5, x6, x7))
parts = h2o.splitFrame(data, c(0.67, 0.167))
train = parts[[1]]
valid = parts[[2]]
test = parts[[3]]
Las proporciones divididas significan que sigo entrenando con 2000 valores, utilizando 500 para la validación y 500 para la prueba.
A continuación, la construcción de la maqueta:
m_deep = h2o.deeplearning(2:ncol(data), "y",
training_frame = train,
validation_frame=valid,
epochs = 1000,
activation = "Tanh",
hidden = c(40,40,40,40,40)
)
m_deep
h2o.performance(m_deep, test)
plot(m_deep)
Notarás que el MSE es ahora muy bajo, y el gráfico del historial de puntuaciones también parece satisfactorio.
Por último, las predicciones y el trazado:
m=m_deep
# The -1 in next few lines means exclude the answer
pt = as.data.frame(h2o.predict(m, train[,-1]))
ptdata = data.frame(as.data.frame(train$x),y=pt)
pv = as.data.frame(h2o.predict(m, valid[,-1]))
pvdata = data.frame(as.data.frame(valid$x),y=pv)
p = as.data.frame(h2o.predict(m, test[,-1]))
pdata = data.frame(as.data.frame(test$x),y=p)
plot(as.data.frame(data[,c(2,1)]), type="p",pch=".")
points(ptdata, col="green",pch=".")
points(pvdata, col="blue",pch=".")
points(pdata, col="red",pch=".")
El gráfico muestra que las predicciones sobre datos no vistos son básicamente tan buenas como las de los datos de entrenamiento. Muestra que no es muy bueno en la predicción de los valores extremos (ya que nunca vio suficientes ejemplos de ellos ):