Práctica de redes profundas Vamos a probar una red profunda para nuestro problema de las casas. Vamos a elegir la siguiente arquitectura: 13 entradas, 10 procesadores en la primera capa oculta, 8 en la segunda, 5 en la tercera, 3 en la cuarta y el de salida. Matlab Analizaremos los siguientes casos: 1. Ninguna precaución 2. Ajuste detenido por conjunto de validación 3. Penalización de valor de pesos (hipótesis de pesos nulos con varianza general) 4. Regresión bayesiana (varianza adaptada) 5. Penalizar el exceso de activación en los procesadores ocultos 6. Desactivar aleatoriamente los procesadores ocultos durante el ajuste 7. Utilizar autocodicadores para la inicialización Para los casos 1 a 4 utilizaremos la toolbox propia de Matlab. Para los casos 5 a 7 usaremos la toolbox de DeepLearning. Aquí vamos dando las indicaciones propias de cada caso, pero ten presente que el criterio de comparación no puede ser el error residual de ajuste, ni siquiera el de prueba, sino que debes reinicializar el proceso varias veces y mirar la estadística de error en el conjunto de prueba. 1. No podemos usar las herramientas grácas, porque van automáticamente el caso 2 red1=fitnet([10 8 5 3]); red1.divideParam.valRatio=0; [red1,tr]=train(red1,p,t); Vigila el valor de Performance y cuando lleve un rato que no progresa detén el ajuste, o si no se acaba de parar, déjalo llegar a las 1000 iteraciones. Mira el resultado del gráco de regresión y anota el R² del conjunto de prueba. Para hacer la siguiente prueba: red1=init(red1); [red1,tr]=train(red1,p,t); Repite varias veces hasta tener una cierta estadística del resultado en el conjunto de prueba. 2. Para el caso inicial usaremos el gradiente conjugado. En este caso, déjalo que pare por sí mismo. red2=fitnet([10 8 5 3],'trainscg'); [red2,tr]=train(red2,p,t); La reinicialización es igual. 3. Tenemos que cambiar la función de medida y no podemos usar Levemberg-Marquardt, porque no lo admite; aquí se propone el método de cuasi-Newton. El valor de la regularización puedes jugar con él. En todo caso, con el valor que te quedes haz varias pruebas y páralo cuando el error no progrese o déjalo llegar a las 1000 iteraciones. red3=fitnet([10 8 5 3],'trainbfg'); red3.divideParam.valRatio=0; red3.performFcn = 'msereg'; red3.performParam.ratio = 0.5; [red3,tr]=train(red3,p,t); 4. Es una variante del caso 1, pero usando la función de ajuste especialmente diseñada al efecto. Además, no separa conjunto de prueba automáticamente, por lo que tenemos que hacerlo aparte. red4=fitnet([10 8 5 3],'trainbr'); [ajind,valind,pruind]=dividerand(506,0.7,0,0.15); paj=p(:,ajind); taj=t(ajind); ppru=p(:,pruind); tpru=t(pruind); [red4,tr]=train(red4,paj,taj); redpru=red4(ppru); plotregression(tpru,redpru); En cada reinicialización hay que repetir la partición de la muestra, es decir: [ajind,valind,pruind]=dividerand(506,0.7,0,0.15); paj=p(:,ajind); taj=t(ajind); ppru=p(:,pruind); tpru=t(pruind); red4=init(red4); [red4,tr]=train(red4,paj,taj); redpru=sim(red4,ppru); plotregression(tpru,redpru); 5. Nuevamente tenemos que hacer a mano la división de la muestra y además tenemos que hacer el escalado a 0-1. Lo siguiente supone que tenemos los directorios de la toolbox de DeepLearning en nuestra ruta. Suele dar mejor resultado empezar el descenso gradiente estocástico con paso individual. Puedes jugar con los parámetros, pero con la jugada que te quedes, mídela varias veces. maxp=max(p'); maxt=max(t); pesc=p./repmat(maxp',1,506); tesc=0.1+0.8*t/maxt; [ajind,valind,pruind]=dividerand(506,0.85,0,0.15); paj=pesc(:,ajind); taj=tesc(ajind); ppru=pesc(:,pruind); tpru=t(pruind); red5 = nnsetup([13 10 8 5 3 1]); red5.nonSparsityPenalty=0.1; red5.sparsityTarget = 0.25; opc.numepochs = 10; opc.batchsize = 1; red5 = nntrain(red5, paj', taj', opc); opc.numepochs = 200; opc.batchsize = 10; red5 = nntrain(red5, paj', taj', opc); red5=nnff(red5,ppru',tpru'); redpru=red5.a{end}; redpru=(redpru-0.1)*maxt/0.8; plotregression(tpru,redpru); Para cada siguiente prueba repetimos los comandos desde dividerand 6. Parecido al anterior, cambiando los parámetros. Este método y el anterior van bien con capas aún mayores (del orden del centenar de procesadores), pero podemos plantear una fracción pequeña. maxp=max(p'); maxt=max(t); pesc=p./repmat(maxp',1,506); tesc=0.1+0.8*t/maxt; [ajind,valind,pruind]=dividerand(506,0.85,0,0.15); paj=pesc(:,ajind); taj=tesc(ajind); ppru=pesc(:,pruind); tpru=t(pruind); red6 = nnsetup([13 10 8 5 3 1]); red6.learningRate = 1; red6.dropoutFraction = 0.05; opc.numepochs = 20; opc.batchsize = 1; red6 = nntrain(red6, paj', taj', opc); opc.numepochs = 100; opc.batchsize = 10; red6 = nntrain(red6, paj', taj', opc); red6.dropoutFraction = 0; red6=nnff(red6,ppru',tpru'); redpru=red6.a{end}; redpru=(redpru-0.1)*maxt/0.8; plotregression(tpru,redpru); 7. Ahora se trata de crear los autocodicadores primero y luego construir con ellos el perceptrón, con una pasada de ajuste nal, que afecte sólo a una parte de los pesos. En esta propuesta, se le deja tocar las dos últimas capas. También es fácil de hacer y da buenos resultados, dejar ajustar sólo los pesos independientes de todas las capas y jar el resto de pesos de todas las capas menos la de salida. En cualquier caso, pararemos el ajuste cuando veamos que el error se estabiliza maxp=max(p'); maxt=max(t); pesc=p./repmat(maxp',1,506); opc.batchsize=10; opc.numepochs=20; [ajind,valind,pruind]=dividerand(506,0.85,0,0.15); paj=pesc(:,ajind); taj=t(ajind); ppru=pesc(:,pruind); tpru=t(pruind); autocod=saesetup([13 10 8 5 3]); autocod.ae{1}.learningRate=1; autocod.ae{2}.learningRate=1; autocod.ae{3}.learningRate=1; autocod.ae{4}.learningRate=1; autocod=saetrain(autocod,paj',opc); red7=fitnet([10 8 5 3]); red7.layers{1}.transferFcn='logsig'; red7.layers{2}.transferFcn='logsig'; red7.layers{3}.transferFcn='logsig'; red7.layers{4}.transferFcn='logsig'; red7=configure(red7,paj,taj); red7=init(red7); red7.divideFcn='dividetrain'; red7.IW{1}=autocod.ae{1}.W{1}; red7.inputWeights{1}.learn=false; red7.LW{2,1}=autocod.ae{2}.W{1}; red7.layerWeights{2,1}.learn=false; red7.LW{3,2}=autocod.ae{3}.W{1}; red7.layerWeights{3,2}.learn=false; red7.LW{4,3}=autocod.ae{4}.W{1}; red7.b{1}=autocod.ae{1}.b{1}; red7.biases{1}.learn=false; red7.b{2}=autocod.ae{2}.b{1}; red7.biases{2}.learn=false; red7.b{3}=autocod.ae{3}.b{1}; red7.biases{3}.learn=false; red7.b{4}=autocod.ae{4}.b{1}; [red7,tr]=train(red7,paj,taj); redpru=red7(ppru); plotregression(tpru,redpru); Como anteriormente, cada repetición la hacemos desde dividerand Octave Analizaremos los siguientes casos: 1. Ninguna precaución 2. Penalización de valor de pesos (hipótesis de pesos nulos con varianza general) 3. Penalizar el exceso de activación en los procesadores ocultos 4. Desactivar aleatoriamente los procesadores ocultos durante el ajuste 5. Utilizar autocodicadores para la inicialización No utilizaremos netlab porque sólo está preparada para una capa oculta. Usaremos la toolbox de DeepLearning, así que tendremos sus directorios en nuestra ruta 1 . Aquí vamos dando las indicaciones propias de cada caso, pero ten presente que el criterio de comparación no puede ser el error residual de ajuste, ni siquiera el de prueba, sino que debes reinicializar el proceso varias veces y mirar la estadística de error en el conjunto de prueba. 1. red1 = nnsetup([13 10 8 5 3 1]); % Constante del método de gradiente %Se puede jugar. Puede ser más alto red1.learningRate = 1; % Número de pasadas %Lo puedes aumentar según tu paciencia opts.numepochs = 100; % Cada cuantos casos aplica optimización. 1 addpath(genpath('...DeepLearnToolbox')) %Tiene que ser divisor de los que haya en la muestra de ajuste opts.batchsize = 57; %Para regular la salida opts.silent = 1; red1 = nntrain(red1, p, t, opts); red1=nnff(red1,pprueba,tprueba); salidas1=red1.a{red1.n}; Mira el resultado grácamente y anota el R² del conjunto de prueba. Repite varias veces hasta tener una cierta estadística del resultado. 2. Es como el anterior, pero añadiendo red2.weightPenaltyL2 = 0.001;. El valor de la regularización puedes jugar con él. En todo caso, con el valor que te quedes haz varias pruebas. 3. Vamos a ver una estrategia que suele dar buen resultado: empezar el descenso gradiente estocástico con paso individual. En la toolbox de DeepLearning no disponemos más que de este algoritmo. Puedes jugar con los parámetros, pero con la jugada que te quedes, mídela varias veces. Como la red que tenemos no tiene tantos procesadores, vamos a aumentarla y a penalizarla si usa para un mismo caso toda la capa. Por ejemplo: cuadruplicamos el tamaño y le ponemos como objetivo que sólo use la cuarta parte cada vez (pero no va a ser el mismo cuarto en cada caso). red3 = nnsetup([13 40 32 20 12 1]); red3.nonSparsityPenalty=0.2; red3.sparsityTarget = 0.25; opc.numepochs = 10; opc.batchsize = 1; red3 = nntrain(red3, p, t, opc); opc.numepochs = 200; opc.batchsize = 8; red3 = nntrain(red3, p, t, opc); red3=nnff(red3,pprueba,tprueba); 4. Parecido al anterior, cambiando los parámetros. Este método y el anterior van bien con capas aún mayores (del orden del centenar de procesadores), pero lo planteamos para que lo veas. red4 = nnsetup([13 20 16 10 6 1]); red4.learningRate = 1; red4.dropoutFraction = 0.5; opc.numepochs = 20; opc.batchsize = 1; red4 = nntrain(red4, p, t, opc); opc.numepochs = 100; opc.batchsize = 8; red4 = nntrain(red4, p, t, opc); red4.dropoutFraction = 0; %El dropout era para constreñir el ajuste. En predicción posterior no se usa red4=nnff(red4,pprueba,tprueba); 5. Ahora se trata de crear los autocodicadores primero y luego construir con ellos el perceptrón, con una pasada de ajuste nal. autocod=saesetup([13 10 8 5 3]); autocod.ae{1}.learningRate=1; autocod.ae{2}.learningRate=1; autocod.ae{3}.learningRate=1; autocod.ae{4}.learningRate=1; autocod=saetrain(autocod,p,opc); red5 = nnsetup([13 10 8 5 3 1]); red5.W{1}=autocod.ae{1}.W{1}; red5.W{2}=autocod.ae{2}.W{1}; red5.W{3}=autocod.ae{3}.W{1}; red5.W{4}=autocod.ae{4}.W{1}; red5.b{1}=autocod.ae{1}.b{1}; red5.b{2}=autocod.ae{2}.b{1}; red5.b{3}=autocod.ae{3}.b{1}; red5.b{4}=autocod.ae{4}.b{1}; red5.learningRate = 0.1; % o lo que pruebes opts.numepochs = 200; opts.batchsize = 57; %divisor del cardinal de muestra de ajuste opts.silent = 1; red5 = nntrain(red5, p, t, opts); red5=nnff(red5,pprueba,tprueba); salidas5=red5.a{red5.n};