A partir de la exploración realizada con anterioridad sobre nuestra base de datos (configuraciones empezando por número de neuronas = atributos+clases / 2) para observar el comportamiento del overfitting y del margen de error, ahora tenemos la información nesesaria para atomatizar la creación de modelos de redes neuronales
El siguiente programa utiliza las funciones de weka implementadas en python
Primero instalamos las dependencias necesarias para hacer un puente entre python y java (weka)
!pip install python-javabridge
!pip install python-weka-wrapper3
A continuación, importamos las librerias que estaremos utilizando para la automatización
import weka.core.jvm as jvm
import weka.core.converters as converters
from weka.classifiers import Classifier, Evaluation
from weka.filters import Filter
from weka.core.packages import install_missing_package, installed_package
Iniciamos la máquina virtual de java
jvm.start(packages=True)
Montamos la partición de archivos de google colaboratory
data_dir = "/content/"
Obtenemos los folders con los que trabajaremos por cada partición (en este caso se toman los del primer experimento)
training = converters.load_any_file(data_dir + "forestFireDB4FoldTrainingSet1.arff")
training.class_is_last()
test = converters.load_any_file(data_dir + "forestFireDB4FoldTestSet1.arff")
test.class_is_last()
Función la cuál se encarga de crear una red neuronal artificial con los parametros que le pasemos o en su defecto con parametros definidos de manera predeterminada. Se utiliza el "MultilayerPerceptron" de weka para este fin.
def rna(trainingSet, testSet, hyParams=["1", "1000", "0.3", "0.2", "10"]):
classifier = Classifier("weka.classifiers.functions.MultilayerPerceptron", options=["-L", hyParams[2], "-M", hyParams[3], "-N", hyParams[1], "-V", hyParams[4], "-S", "0", "-E", "20", "-H", hyParams[0], "-D"])
classifier.build_classifier(trainingSet)
trainingEvaluation = Evaluation(trainingSet)
testEvaluation = Evaluation(trainingSet)
trainingEvaluation.test_model(classifier, trainingSet)
testEvaluation.test_model(classifier, testSet)
return format(trainingEvaluation.error_rate, '.5g'), format(testEvaluation.error_rate, '.5g')
def formatNeuLay(layers, neurons): #12,12,12
param = str(neurons)
for i in range (0,layers-1):
param += ','+str(neurons)
return param
def increaseNeuInlay(neuInLay):
neu = neuInLay.split(",")
aux = list()
for n in neu:
n = int(n)
n += 1
aux.append(n)
cad = str(aux.pop(0))
for n in aux:
cad += ","+str(n)
return cad
def fitValidationSetSize(trainingSet, testSet, modelPerf, noImpLimit=3):
i = 1
newFit=modelPerf[0].copy() #arreglo que contiene los hiperparámetros
no_improvement = 0
performance=[modelPerf] #Lista que contrendrá el desepeño de los modelos al ajustar el validationSetSize
newHyParValue = modelPerf[0][4] #Valor del hiperparámetro
iBestFit = 0
while no_improvement < noImpLimit:
newHyParValue = int(newHyParValue)
newHyParValue -= 1
if newHyParValue <= 2:
break
newHyParValue = str(newHyParValue)
newFit[4] = newHyParValue
errRateTrain, errRateTest = rna(trainingSet, testSet, newFit)
performance.append((newFit.copy(), errRateTrain, errRateTest))
if performance[iBestFit][2] <= performance[i][2]:
no_improvement += 1
else:
iBestFit = i
no_improvement = 0
i += 1
print(f"Mejor ajuste:{performance[iBestFit]}")
return performance[iBestFit]
En esta función se generan los dos bucles para que iterativamente se creen las redes neuronales artificiales y se toma la mejor configuración de rna por cada capa
def fitModel(trainingSet, testSet, hyParams=["1", "2600", "0.3", "0.2", "10"]):
noLayers = hyParams[0].count(',') + 1
resultsPerNeu = list() # en cada posición de la lista almacena la mejor configuración para 1, 2,...n neuronas
resultsPerLay = list()
while noLayers <= 5:
no_neuron_improvement = 0 # contador que indica el número de veces que no ha mejorado el modelo respecto al # de neuronas
iBestExp = 0 # índice que indica el mejor ajuste con x número de neuronas
i = 0
print(f"\nCapa{noLayers}:")
while no_neuron_improvement < 4:
errRateTrain, errRateTest = rna(trainingSet, testSet, hyParams) # Obtiene el resultado del modelo para el 'X' número de neurona(s)
newModel = fitValidationSetSize(trainingSet, testSet, (hyParams.copy(), errRateTrain, errRateTest))
resultsPerNeu.append(newModel)
if resultsPerNeu[iBestExp][2] <= resultsPerNeu[i][2]:
no_neuron_improvement += 1
else:
iBestExp = i
no_neuron_improvement = 0
hyParams[0] = increaseNeuInlay(hyParams[0])
i += 1
print(f"Mejor Ajuste de capa {noLayers}:{resultsPerNeu[iBestExp]}")
resultsPerLay.append(resultsPerNeu.copy())
noLayers += 1
strArr = resultsPerNeu[iBestExp][0][0].split(",")
noNeurons = int(strArr[0])
hyParams[0] = formatNeuLay(noLayers, noNeurons)
resultsPerNeu.clear()
Se procede a entrenar al modelo y probarlo con las instancias de validación, lo que devuelve será:
fitModel(training, test, ["21,21,21", "2600", "0.3", "0.2", "10"])
Capa3: Mejor ajuste:(['21,21,21', '2600', '0.3', '0.2', '8'], '0.06692', '0.070809') Mejor ajuste:(['22,22,22', '2600', '0.3', '0.2', '6'], '0.068026', '0.071218')