python - recurrente - ¿Qué hay de malo en mi implementación de redes neuronales?
redes neuronales ejemplos (3)
Además de las respuestas anteriores, también debe tener en cuenta que es posible que tenga que ajustar la learning rate
(estableciendo el valor de learning_rate = value
en el inicializador) de la red. Si elige la tasa a grande, saltará de un mínimo local a otro o rodeará estos puntos, pero en realidad no convergerá (vea la imagen a continuación, tomada desde here ).
Además, también trace la loss
y no solo la precisión de su red. Esto le dará una mejor idea al respecto.
Además, tenga en cuenta que debe utilizar una gran cantidad de datos de entrenamiento y pruebas para obtener una curva más o menos "suave", o incluso una curva representativa; Si está utilizando solo unos pocos (quizás unos pocos cientos) puntos de datos, las métricas resultantes no serán muy precisas, ya que contienen muchas cosas estocásticas. Para resolver este error, no debe capacitar a la red con los mismos ejemplos cada vez, sino que debe cambiar las órdenes de sus datos de capacitación y tal vez dividirla en diferentes mini lotes . Tengo mucha confianza en que puede resolver o incluso reducir su problema intentando recordar estos aspectos e implementarlos.
Dependiendo de su tipo de problema, debe cambiar la función de activación a algo diferente a la función tanh
. Al realizar una clasificación, un OneHotEncoder
también puede ser útil (si sus datos aún no están codificados en caliente); sklearn
framework sklearn
ofrece una implementation de esto.
Quiero trazar la curva de error de aprendizaje de una red neuronal con respecto al número de ejemplos de entrenamiento. Aquí está el código:
import sklearn
import numpy as np
from sklearn.model_selection import learning_curve
import matplotlib.pyplot as plt
from sklearn import neural_network
from sklearn import cross_validation
myList=[]
myList2=[]
w=[]
dataset=np.loadtxt("data", delimiter=",")
X=dataset[:, 0:6]
Y=dataset[:,6]
clf=sklearn.neural_network.MLPClassifier(hidden_layer_sizes=(2,3),activation=''tanh'')
# split the data between training and testing
X_train, X_test, Y_train, Y_test = cross_validation.train_test_split(X, Y, test_size=0.25, random_state=33)
# begin with few training datas
X_eff=X_train[0:int(len(X_train)/150), : ]
Y_eff=Y_train[0:int(len(Y_train)/150)]
k=int(len(X_train)/150)-1
for m in range (140) :
print (m)
w.append(k)
# train the model and store the training error
A=clf.fit(X_eff,Y_eff)
myList.append(1-A.score(X_eff,Y_eff))
# compute the testing error
myList2.append(1-A.score(X_test,Y_test))
# add some more training datas
X_eff=np.vstack((X_eff,X_train[k+1:k+101,:]))
Y_eff=np.hstack((Y_eff,Y_train[k+1:k+101]))
k=k+100
plt.figure(figsize=(8, 8))
plt.subplots_adjust()
plt.title("Erreur d''entrainement et de test")
plt.plot(w,myList,label="training error")
plt.plot(w,myList2,label="test error")
plt.legend()
plt.show()
Sin embargo, obtengo un resultado muy extraño, con curvas fluctuantes, el error de entrenamiento está muy cerca del error de prueba que no parece ser normal. ¿Dónde está el error? No puedo entender por qué hay tantos altibajos y por qué el error de entrenamiento no aumenta, como se esperaría. ¡Cualquier ayuda sería apreciada!
EDITAR: el conjunto de datos que estoy usando es https://archive.ics.uci.edu/ml/datasets/Chess+%28King-Rook+vs.+King%29 donde me deshice de las clases que tienen menos de 1000 instancias. Recodifiqué manualmente los datos literales.
Creo que la razón por la que está viendo este tipo de curva es que la métrica de rendimiento que está midiendo es diferente de la métrica de rendimiento que está optimizando .
Métrica de optimización
La red neuronal minimiza una función de pérdida, y en el caso de las activaciones de Tanh, asumo que está utilizando una versión modificada de la pérdida de entropía cruzada. Si tuviera que graficar la pérdida a lo largo del tiempo, vería una función de error más monótonamente decreciente como espera. (En realidad no es monótono porque las redes neuronales no son convexas, pero eso no viene al caso).
Métrica de rendimiento
La métrica de rendimiento que está midiendo es el porcentaje de precisión, que es diferente de la pérdida. ¿Por qué son diferentes? La función de pérdida nos dice cuánto error tenemos de manera diferenciable (lo cual es importante para los métodos de optimización rápidos). La métrica de precisión nos dice qué tan bien predecimos, lo que es útil para la aplicación de la red neuronal.
Poniendo todo junto
Debido a que está trazando el rendimiento de una métrica relacionada, puede esperar que la gráfica se vea similar a la de su métrica optimizada. Sin embargo, debido a que no son lo mismo, puede que esté introduciendo una variación no contabilizada en su gráfica (como lo demuestra la gráfica que publicó).
Hay un par de maneras de arreglar esto.
- Trazar la pérdida en lugar de la precisión. Esto realmente no soluciona su problema si realmente necesita la gráfica de precisión, pero le dará curvas mucho más suaves.
- Trazar un promedio en varias carreras. Guarde los trazados de precisión en más de 20 ejecuciones independientes de su algoritmo (como en el entrenamiento de la red 20 veces), luego promuévalos juntos y trace esto. Eso reducirá enormemente la varianza.
TL; DR
No espere que la gráfica de precisión siempre sea suave y disminuya monótonamente, no lo será.
Después de editar la pregunta:
Ahora que ha agregado su conjunto de datos, veo algunas otras cosas que pueden estar causando los problemas que está viendo.
Información en magnitud
El conjunto de datos define el rango y el archivo (fila y columna) de varias piezas de ajedrez. Estos se ingresan como un número entero de 1 a 6. Sin embargo, ¿2 es realmente 1 mejor que 1? ¿Es 6 realmente 4 mejor que 2? No creo que este sea el caso en términos de posición de ajedrez.
Imagina que estoy construyendo un clasificador que toma dinero como entrada. ¿Hay alguna cantidad de información representada por la magnitud de mis valores? Sí, $ 1 es bastante diferente de $ 100; y podemos decir que existe una relación basada en la magnitud.
Para un juego de ajedrez, ¿la fila 1 significa algo diferente a la fila 8? En absoluto, de hecho estas dimensiones son simétricas! El uso de una unidad de polarización en su red puede ayudar a explicar la simetría al "reescala" para que sus entradas sean efectivamente de [-3, 4] que ahora están centradas (ish) alrededor de 0.
Soluciones
Sin embargo, creo que obtendría la mayor cantidad de millas de codificación de teselas o de codificación en caliente de cada una de sus funciones. No permita que la red se base en la información contenida en la magnitud de cada función, ya que eso puede hacer que la red se convierta en malos óptimos locales.
Aleatorizar el conjunto de entrenamiento y repetir.
Si desea una comparación justa del efecto del número de muestras de entrenamiento en la precisión, le sugiero que elija n_samples
de su conjunto de entrenamiento en lugar de agregar 100 muestras al lote anterior. También repetiría los tiempos N_repeat
ajustados para cada valor de n_samples
.
Esto daría algo como esto (no probado):
n_samples_array = np.arange(100,len(X_train),100)
N_repeat = 10
for n_samples in n_samples_array:
print(n_samples)
# repeat the fit several times and take the mean
myList_tmp, myList2_tmp = [],[]
for repeat in range(0,N_repeat):
# Randomly pick samples
selection = np.random.choice(range(0,len(X_train)),n_samples,repeat=False)
# train the model and store the training error
A=clf.fit(X_train[selection],Y_train[selection])
myList_tmp.append(1-A.score(X_train[selection],Y_train[selection]))
# compute the testing error
myList2_tmp.append(1-A.score(X_test,Y_test))
myList.append(np.mean(myList_tmp))
myList2.append(np.mean(myList2_tmp))
Arranque en caliente
Cuando utiliza la función de fit
, reinicia la optimización desde cero. Si desea ver la mejora en su optimización al agregar algunas muestras a la misma red entrenada anteriormente, puede usar la opción warm_start=True
Según la documentation :
warm_start: bool, opcional, predeterminado False
Cuando se establece en Verdadero, reutilice la solución de la llamada anterior para que se ajuste como inicialización; de lo contrario, simplemente borre la solución anterior.