DataMining
  • Process
  • Feature Extractor
  • Code
  • Trained network

Programa de automatización parar encontar la mejor configuración de una red neuronal¶

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)

In [ ]:
!pip install python-javabridge
!pip install python-weka-wrapper3

A continuación, importamos las librerias que estaremos utilizando para la automatización

In [ ]:
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

In [ ]:
jvm.start(packages=True)

Montamos la partición de archivos de google colaboratory

In [ ]:
data_dir = "/content/"

Obtenemos los folders con los que trabajaremos por cada partición (en este caso se toman los del primer experimento)

In [ ]:
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.

In [ ]:
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')
In [ ]:
def formatNeuLay(layers, neurons): #12,12,12
  
  param = str(neurons)
  for i in range (0,layers-1):
    param += ','+str(neurons)

  return param
In [ ]:
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
In [ ]:
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

In [ ]:
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á:

  • El mejor ajuste por cada neurona
  • La mejor configuración por cada capa
In [ ]:
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')

exp3cap3.pngexp3cap2.pngexp3cap1.pngexp2cap3.pngexp2cap2.pngexp2cap1.pngexp1cap3.pngexp1cap2.pngexp1cap1.png