Las redes de neuronas artificiales son un modelo computacional inspirado en el funcionamiento del cerebro humano. Una neurona artificial es una unidad de cómputo bastante simple, que recibe una serie de entradas, las procesa y produce una salida. La salida de una neurona puede ser la entrada de otra neurona, formando así una red de neuronas interconectadas, donde cada conexión tiene un peso asociado. Es esta red, que a veces contiene miles y millones de neuronas, la que dota de gran potencia de cálculo a este modelo, siendo capaces de aprender patrones de datos muy complejos, como imágenes, texto o sonido, y por tanto, se utilizan a menudo en tareas de clasificación o regresión.
El aprendizaje en una red neuronal consiste en ajustar los pesos de las conexiones para minimizar el error entre la salida predicha y la salida real. Este proceso se realiza mediante algoritmos de optimización, como el del gradiente descendente que ya se vio en el capítulo de regresión.
5.1 Ejercicios Resueltos
Para la realización de esta práctica se requieren los siguientes paquetes:
usingCSV# Para la lectura de archivos CSV.usingDataFrames# Para el manejo de datos tabulares.usingGLMakie# Para el dibujo de gráficas.usingMLJ# Para la creación y entrenamiento de modelos de aprendizaje automático.usingFlux# Para la creación y entrenamiento de redes neuronales.usingMLJFlux# Interfaz de Flux para MLJ.usingOptimisers# Para la optimización de funciones.usingStatistics# Para las funciones de coste.
Ejercicio 5.1 El conjunto de datos viviendas.csv contiene información sobre el precio de venta de viviendas en una ciudad.
Cargar los datos del archivo viviendas.csv en un data frame.
Solución
usingCSV, DataFrames# Creamos un data frame a partir del archivo CSV.df = CSV.read(download("https://aprendeconalf.es/aprendizaje-automatico-practicas-julia/datos/viviendas.csv"), DataFrame)# Mostramos las primeras cinco filas del data frame.first(df, 5)
5×13 DataFrame
Row
precio
area
dormitorios
baños
habitaciones
calleprincipal
huespedes
sotano
calentador
climatizacion
garaje
centrico
amueblado
Int64
Int64
Int64
Int64
Int64
String3
String3
String3
String3
String3
Int64
String3
String15
1
13300000
7420
4
2
3
si
no
no
no
si
2
si
amueblado
2
12250000
8960
4
4
4
si
no
no
no
si
3
no
amueblado
3
12250000
9960
3
2
2
si
no
si
no
no
2
si
semi-amueblado
4
12215000
7500
4
2
2
si
no
si
no
si
3
si
amueblado
5
11410000
7420
4
1
2
si
si
si
no
si
2
no
amueblado
Extraer las columnas area y precio del data frame y convertirlas a un vector de tipo Float32. Pasar el precio a miles de euros.
Solución
# Extraemos las columnas area y precio.X =Float32.(df.area)y =Float32.(df.precio) ./1000
Dibujar un diagrama de dispersión entre el precio y el area de las viviendas.
Solución
usingGLMakiefig =Figure()ax =Axis(fig[1, 1], title ="Precio vs Area", xlabel ="Área (m²)", ylabel ="Precio (€)")scatter!(ax, X, y)fig
┌ Warning: Found `resolution` in the theme when creating a `Scene`. The `resolution` keyword for `Scene`s and `Figure`s has been deprecated. Use `Figure(; size = ...` or `Scene(; size = ...)` instead, which better reflects that this is a unitless size and not a pixel resolution. The key could also come from `set_theme!` calls or related theming functions.
└ @ Makie ~/.julia/packages/Makie/ux0Te/src/scenes.jl:238
Construir un modelo lineal simple usando un perceptrón como el de la figura, tomando como función de activación la función identidad.
.
Inicializar los parámetros del modelo a 0 y dibujarlo en el diagrama de dispersión.
Solución
# Definimos el modelo lineal.perceptron(W, b, x) = @. W[1] * x + b[1]# Inicializamos los pesos y el término independiente.W =Float32[0]b =Float32[0]lines!(ax, X, perceptron(W, b, X), label ="Modelo 0", color =:red)fig
Aplicar el modelo a los datos y calcular el error cuadrático medio del modelo.
Solución
usingStatistics# Definimos la función de coste.coste(W, b, X, y) =mean((y .-perceptron(W, b, X)).^2)# Calculamos el coste del modelo inicial.println("Error cuadrático medio: ", coste(W, b, X, y))
Error cuadrático medio: 2.6213836e7
Se observa que el error cuadrático medio es bastante alto, lo que indica que el modelo no se ajusta bien a los datos.
¿En qué dirección deben modificarse los parámetros del modelo para reducir el error cuadrático medio? Actualizar los parámetros del modelo en esa dirección utilizando una tasa de aprendizaje . Comprobar que el error cuadrático medio ha disminuido con los nuevos parámetros.
Ayuda
Los parámetros deben modificarse en la dirección en la que más rápidamente decrezca el error cuadrático medio. Esta dirección está dada por el gradiente del error cuadrático respecto a los parámetros, que se puede calcular como:
Solución
usingFlux# Declaramos los pesos como variables simbólicas# Calculamos el gradiente del coste.∂E_∂W, ∂E_∂b =gradient(coste, W, b, X, y)# Mostramos el gradiente.println("Gradiente del coste: ($∂E_∂W, $∂E_∂b)")# Definimos la tasa de aprendizaje.η =1e-8# Mostramos los parámetros iniciales.println("Parámetros iniciales: W = $W, b = $b")# Actualizamos los parámetros en la dirección deW -= η * ∂E_∂Wb -= η * ∂E_∂b# Mostramos los nuevos parámetros.println("Nuevos parámetros: W = $W, b = $b")# Comprobamos que el error cuadrático medio ha disminuido.println("Error cuadrático medio: ", coste(W, b, X, y))# Dibujamos el nuevo modelo en el diagrama de dispersión.lines!(ax, X, perceptron(W, b, X), label ="Modelo 1")fig
Gradiente del coste: (Float32[-5.344584f7], Float32[-9533.46])
Parámetros iniciales: W = Float32[0.0], b = Float32[0.0]
Nuevos parámetros: W = [0.5344584], b = [9.5334599609375e-5]
Error cuadrático medio: 6.569670916877353e6
Definir una función para entrenar el perceptrón modificando los pesos en la dirección opuesta al gradiente del error cuadrático medio.
Solución
functionentrenar_perceptron!(W, b, X, y, η)""" Función para entrenar el perceptrón. W: peso del modelo. b: término independiente del modelo. X: vector de entradas. y: vector de salidas. η: tasa de aprendizaje. """# Calculamos el gradiente del coste. ∂E_∂W, ∂E_∂b =gradient(coste, W, b, X, y)# Actualizamos los parámetros en la dirección opuesta al gradiente. W .-= η * ∂E_∂W b .-= η * ∂E_∂bend
entrenar_perceptron! (generic function with 1 method)
Usar la función anterior para entrenar el perceptrón y repetir el proceso durante 9 iteraciones más. Dibujar los modelos actualizados en el diagrama de dispersión.
Solución
# Repetimos el proceso de entrenamiento del perceptrón.for i =2:10entrenar_perceptron!(W, b, X, y, η)# Mostramos los parámetros y el coste del modelo. ecm =coste(W, b, X, y)println("Iteración ", i, ", Parámetros: W = $W, b = $b, Coste: $ecm")# Dibujamos el modelo actualizado en el diagrama de dispersión.lines!(ax, X, perceptron(W, b, X), label ="Modelo $i")endaxislegend(ax)fig
Iteración 2, Parámetros: W = [0.7351053379977437], b = [0.00013561418157921425], Coste: 3.8010036630367776e6
Iteración 3, Parámetros: W = [0.8104324229132014], b = [0.0001552249559885306], Coste: 3.4107850089995693e6
Iteración 4, Parámetros: W = [0.838711796053412], b = [0.00016707622479181458], Coste: 3.355787208775712e6
Iteración 5, Parámetros: W = [0.8493284674839952], b = [0.00017601441178095897], Coste: 3.348035761002203e6
Iteración 6, Parámetros: W = [0.8533141887596891], b = [0.00018385896650121626], Coste: 3.3469432599931033e6
Iteración 7, Parámetros: W = [0.8548105117157216], b = [0.00019129294862501068], Coste: 3.34678927740313e6
Iteración 8, Parámetros: W = [0.8553722621219417], b = [0.00019857279313692855], Coste: 3.3467675705099306e6
Iteración 9, Parámetros: W = [0.855583154313161], b = [0.00020579477113007419], Coste: 3.3467645066817994e6
Iteración 10, Parámetros: W = [0.855662326942257], b = [0.00021299502480003158], Coste: 3.3467640704253544e6
Definir de nuevo el perceptrón como una red neuronal de una sola capa con una entrada y una salida con el paquete Flux.jl y mostrar los parámetros iniciales del modelo.
Ayuda
Utilizar la función Dense(n => m) del paquete Flux.jl para definir una capa de neuronas con entradas cada una. Por defecto la función de activación es la identidad.
Flux inicializa los pesos de las conexiones de forma aleatoria y el término independiente a cero.
Solución
# Definimos una capa con una sola neurona con una entrada.modelo =Dense(1=>1)# Mostramos los parámetros del modelo.println("Pesos: ", modelo.weight, ", Término independiente: ", modelo.bias)
Calcular las predicciones de los precios de las viviendas con el modelo inicial.
Ayuda
Para obtener las salidas de una red neuronal definida con Flux, debe pasarse al modelo una matriz con las entradas, donde cada columna es un caso. Para convertir el vector de las areas en una matriz de una sola fila se puede usar la función reshape.
Solución
# Convertimos el vector de las areas en una matriz de una sola fila.X =reshape(X, 1, length(X))ŷ =modelo(X)
Definir una función de coste que calcule el error cuadrático medio entre la salida del modelo y la salida real usando el paquete Flux.jl. Calcular el coste del modelo inicial.
Ayuda
Usar la función Flux.mse para calcular el error cuadrático medio entre la salida del modelo y la salida real.
Para calcular el coste de un modelo en Flux, el vector con las etiquetas también debe ser una matriz de una fila.
Solución
# Convertimos el vector de los precios en una matriz de una sola columna.y =reshape(y, 1, length(y))# Definimos la función de coste como el error cuadrático medio.coste(modelo, X, y) = Flux.mse(modelo(X),y)coste(modelo, X, y)
3.3639158f6
Definir una función para entrenar el modelo con y usarla para entrenar el modelo hasta que la reducción en el error cuadrático medio sea menor del %. ¿Cuántas iteraciones hacen falta? ¿Cuál es el coste del último modelo? Dibujar el coste en cada iteración.
Solución
functionentrenar_modelo!(modelo, coste, X, y, η)""" Función para entrenar el modelo. modelo: modelo a entrenar. coste: función de coste. X: matriz de entradas. y: matriz de salidas. η: tasa de aprendizaje. """# Calculamos el gradiente del coste. ∇ =gradient(coste, modelo, X, y)# Actualizamos los parámetros del modelo en la dirección opuesta al gradiente. @. modelo.weight = modelo.weight - η * ∇[1].weight @. modelo.bias = modelo.bias - η * ∇[1].biasend# Creamos un vector para guardar los costes del proceso de entrenamiento.costes = [coste(modelo, X, y)]reduccion_coste =Infiteraciones =0# Iteramos el proceso de aprendizaje hasta que la reducción del coste sea menor del 0.01%.while reduccion_coste >0.0001 iteraciones +=1entrenar_modelo!(modelo, coste, X, y, η)# Calculamos el nuevo coste y lo añadimos al vector de costes.push!(costes, coste(modelo, X, y))# Calculamos la reducción del coste. reduccion_coste =abs((costes[end] - costes[end-1]) / costes[end])end# Mostramos el número de iteraciones y el coste final.println("Número de iteraciones: ", iteraciones)println("Coste final: ", costes[end])# Dibujamos el coste en cada iteración.fig2 =Figure()ax2 =Axis(fig2[1, 1], title ="Evolución del coste en el entrenamiento", xlabel ="Iteraciones", ylabel ="Coste")lines!(ax2, 0:iteraciones, costes)fig2
Número de iteraciones: 3
Coste final: 3.3468115e6
┌ Warning: Found `resolution` in the theme when creating a `Scene`. The `resolution` keyword for `Scene`s and `Figure`s has been deprecated. Use `Figure(; size = ...` or `Scene(; size = ...)` instead, which better reflects that this is a unitless size and not a pixel resolution. The key could also come from `set_theme!` calls or related theming functions.
└ @ Makie ~/.julia/packages/Makie/ux0Te/src/scenes.jl:238
Mostrar el modelo final en el diagrama de dispersión y compararlo con el último modelo obtenido con el perceptrón.
Solución
# Dibujamos el modelo final en el diagrama de dispersión.lines!(ax, vec(X), vec(modelo(X)), label ="Modelo final", color =:red, linewidth =2)fig
Se observa que el modelo final prácticamente coincide con el último modelo obtenido con el perceptrón, lo que indica que ambos modelos son equivalentes.
Crear una red neuronal para predecir el precio de las viviendas usando todas las características de las viviendas y mostrar los pesos y el término independiente del modelo.
Ayuda
Ahora el modelo tiene que tener tantas entradas como características tenga el conjunto de datos, en este caso 12 características de entrada y una salida para el precio.
Solución
# Definimos el modelo con 12 entradas y 1 salida.modelo =Dense(12=>1)# Mostramos los parámetros del modelo.println("Pesos: ", modelo.weight, ", Término independiente: ", modelo.bias)
Extraer las características de entrada del conjunto de datos y convertir las que sean cualitativas en cuantitativas.
Ayuda
Usar la función coerce! del paquete MLJScientificTypes.jl para convertir los tipos de las columnas del data frame.
Solución
usingMLJ# Extraemos las etiquetas.y =Float32.(df.precio /1000)# Extraemos las características de entrada.X =select(df, Not(:precio))# Convertimos las columnas cualitativas en cuantitativas.schema(X)
Las columnas calleprincipal, huespedes, sotano, calentador, climatizacion, centrico y amueblado son cualitativas y deben convertirse a cuantitativas.
# Convertimos las columnas de tipo texto a tipo categórico.coerce!(X, Textual => Multiclass)# Convertimos las columnas categóricas a tipo numérico.coerce!(X, Multiclass => Count)# Convertimos las columnas de tipo Int64 a tipo Int32 para ganar eficiencia.X =Float32.(X)# Observamos el nuevo esquema del data frame.schema(X)
Convertir el data frame a una matriz, transponerla y normalizar los datos.
Ayuda
Cuando se trabaja con variables de entrada de diferentes escalas, es recomendable normalizarlas para que todas tengan la misma importancia en el modelo. Para ello, se puede usar la función normalise del paquete Flux.jl para normalizar los datos.
Solución
# Convertimos el data frame a una matriz y la transponemos.X =Matrix(X)'X = Flux.normalise(X)y = y'# Definimos como función de coste el error cuadrático medio.coste(modelo, X, y) = Flux.mse(modelo(X), y)# Calculamos el coste del modelo inicial.println("Error cuadrático medio: ", coste(modelo, X, y))
Error cuadrático medio: 2.621381e7
Definir una función para entrenar el modelo con y usarla para entrenar el modelo hasta que la reducción en el error cuadrático medio sea menor de . ¿Cuántas iteraciones hacen falta? ¿Cuál es el coste del último modelo? Dibujar el coste en cada iteración. ¿Es mejor modelo que el percetrón?
Solución
functionentrenar_modelo!(modelo, coste, X, y, η)""" Función para entrenar el modelo. modelo: modelo a entrenar. coste: función de coste. X: matriz de entradas. y: matriz de salidas. η: tasa de aprendizaje. """# Calculamos el gradiente del coste. ∇ =gradient(coste, modelo, X, y)# Actualizamos los parámetros del modelo en la dirección opuesta al gradiente. @. modelo.weight = modelo.weight - η * ∇[1].weight @. modelo.bias = modelo.bias - η * ∇[1].biasend# Definimos la tasa de aprendizaje.η =1e-2# Creamos un vector para guardar los costes del proceso de entrenamiento.costes = [coste(modelo, X, y)]reduccion_coste =Infiteraciones =0# Iteramos el proceso de aprendizaje hasta que la reducción del coste sea menor del 0.01%.while reduccion_coste >1e-4 iteraciones +=1entrenar_modelo!(modelo, coste, X, y, η)# Calculamos el nuevo coste y lo añadimos al vector de costes.push!(costes, coste(modelo, X, y))# Calculamos la reducción del coste. reduccion_coste =abs((costes[end] - costes[end-1]))end# Mostramos el número de iteraciones y el coste final.println("Número de iteraciones: ", iteraciones)println("Coste final: ", costes[end])
Número de iteraciones: 413
Coste final: 1.1411414e6
Ahora dibujamos la evolución del coste con las iteraciones en el entrenamiento.
# Dibujamos el coste en cada iteración.fig3 =Figure()ax3 =Axis(fig3[1, 1], title ="Evolución del coste en el entrenamiento", xlabel ="Iteraciones", ylabel ="Coste")lines!(ax3, 0:iteraciones, costes)fig3
┌ Warning: Found `resolution` in the theme when creating a `Scene`. The `resolution` keyword for `Scene`s and `Figure`s has been deprecated. Use `Figure(; size = ...` or `Scene(; size = ...)` instead, which better reflects that this is a unitless size and not a pixel resolution. The key could also come from `set_theme!` calls or related theming functions.
└ @ Makie ~/.julia/packages/Makie/ux0Te/src/scenes.jl:238
El coste final es menor que el del perceptrón, lo que indica que el modelo es mejor.
Finalmente, mostramos los parámetros del modelo entrenado.
# Mostramos los pesos y el término independiente del modelo.println("Pesos: ", modelo.weight, ", Término independiente: ", modelo.bias)
Convertir las columnas Longitud_pico, Profundidad_pico, Longitud_ala a tipo científico Continuous y la columna Especie a tipo Multiclass.
Ayuda
Usar la función coerce! del paquete MLJ para transformar las variables categóricas en variables numéricas.
Solución
# Convertimos la longitud del ala a tipo científico continuo.coerce!(df, :Longitud_ala => Continuous)# Convertimos la columna Especie a tipo Multiclass.coerce!(df, Textual => Multiclass)# Mostramos el nuevo esquema del data frame.schema(df)
Dividir el data frame en dos partes, una con las variables de entrada y otra con la variable de salida (Especie).
Ayuda
Usar la función unpack del paquete MLJ para dividir el data frame en dos partes, una con las columnas de entrada del modelo y otra con la columna de salida.
Solución
y, X =unpack(df, ==(:Especie), name ->true);
Crear un modelo de red neuronal con la siguiente estructura.
Capa de entrada con 3 neuronas (una por cada variable de entrada).
Una capa oculta con 6 neuronas y función de activación relu.
Capa de salida con 3 neuronas (una por cada especie de pingüino) y función de activación softmax.
Usar el algoritmo de aprendizaje Adam (Adaptative Moment Estimation) con una tasa de aprendizaje de . Introducir en el modelo 0 etapas (epochs) de entrenamiento, para trabajar con los pesos aleatorios iniciales.
Ayuda
Cargar el constructor de modelos de redes neuronales NeuralNetworkClassifier del paquete MLJFlux e inicializarlo con los siguientes parámetros:
builder: Permite definir el tipo de red neuronal. En este caso, usar la función MLP (Multi Layer Perceptron) para crear el modelo de red neuronal. Indicar el número de neuronas de las capas ocultas con hidden y la función de activación con σ.
optimiser: Permite definir el optimizador, es decir, el algoritmo de aprendizaje. En este caso usar el optimizador Adam del paquete Optimisers.jl con una tasa de aprendizaje de .
batch_size: Tamaño del lote de entrenamiento. En este caso usar un tamaño de 10.
epochs: Número de etapas de entrenamiento. En este caso usar 0.
acceleration: Permite usar la aceleración de la GPU si se dispone de tarjeta gráfica. Normalmente CUDALibs().
Usar la función machine del paquete MLJ para crear una máquina de aprendizaje con el modelo y los datos.
Solución
usingFlux, MLJFlux, Optimisers# Cargamos el código que define las redes neuronales.RedNeuronal =@load NeuralNetworkClassifier pkg ="MLJFlux"# Creamos un modelo de red neuronal con los parámetros por defecto.modelo =RedNeuronal( builder = MLJFlux.MLP(; hidden = (6,), σ = relu), optimiser=Optimisers.Adam(0.01), batch_size =10, epochs =0,# acceleration = CUDALibs() # Para utilizar targetas gráficas GPU )# Creamos una máquina de aprendizaje con el modelo y los datos.mach =machine(modelo, X, y)
[ Info: For silent loading, specify `verbosity=0`.
Entrenar el modelo con el conjunto de ejemplos de entrenamiento y predecir la especie de los pingüinos del conjunto de prueba. Calcular la matriz de confusión y la precisión del modelo y la entropía cruzada.
Ayuda
Usar la función fit! del paquete MLJ para entrenar el modelo con el conjunto de entrenamiento.
Para predecir la especie de los pingüinos del conjunto de prueba, usar la función predict del paquete MLJ.
# Entrenamos el modelo con el conjunto de entrenamiento.fit!(mach, rows = train)# Predecimos las probabilidades de cada ejemplo de pertenecer a cada clase.ŷ =predict(mach, rows = test)
[ Info: Training machine(NeuralNetworkClassifier(builder = MLP(hidden = (6,), …), …), …).
[ Info: MLJFlux: converting input data to Float32
Finalmente calculamos la precisión del modelo y la entropía cruzada.
# Calculamos la precisión del modelo.precision =sum(mode.(ŷ) .== y[test]) /length(test)# O directamente usando la función accuracyaccuracy(mode.(ŷ), y[test])println("Precisión del modelo: ", precision)# Calculamos la entropía cruzada.println("Entropía cruzada: ", cross_entropy(ŷ, y[test]))
Precisión del modelo: 0.3592233009708738
Entropía cruzada: 14.96195555472543
Entrenar el modelo durante 100 etapas y evaluar de nuevo la precisión del modelo y la entropía cruzada. ¿Ha mejorado el modelo?
Ayuda
Usar la función evaluate del paquete MLJ para evaluar el modelo. Los parámetros más importantes de esta función son:
resampling: Indica el método de muestreo para definir los conjuntos de entrenamiento y test. Los métodos más habituales son:
Holdout(fraction_train = p): Divide el conjunto de datos tomando una proporción de ejemplos en el conjunto de entrenamiento y en el conjunto de test.
CV(nfolds = n, shuffle = true|false): Utiliza validación cruzada con n iteraciones. Si se indica shuffle = true, se utiliza validación cruzada aleatoria.
StratifiedCV(nfolds = n, shuffle = true|false): Utiliza validación cruzada estratificada con n iteraciones. Si se indica shuffle = true, se utiliza validación cruzada estratificada aleatoria.
InSample(): Utiliza el conjunto de entrenamiento como conjunto de test.
measures: Indica las métricas a utilizar para evaluar el modelo. Las métricas más habituales son:
cross_entropy: Pérdida de entropía cruzada.
confusion_matrix: Matriz de confusión.
true_positive_rate: Tasa de verdaderos positivos.
true_negative_rate: Tasa de verdaderos negativos.
ppv: Valor predictivo positivo.
npv: Valor predictivo negativo.
accuracy: Precisión.
Se puede indicar más de una en un vector.
Solución
# Definimos el número de épocas de entrenamiento.modelo.epochs =100# Actualizamos la máquina de aprendizaje con el nuevo modelo.mach =machine(modelo, X, y)# Entrenamos el modelo con el conjunto de entrenamiento y evaluamos el modelo.evaluate!(mach, resampling =Holdout(fraction_train =0.7, rng =123), measure = [accuracy, cross_entropy])
La precisión del modelo es muy baja. Esto puede deberse a que la estructura de la red neuronal no es la adecuada, o a que las variables de entrada no están normalizadas.
Estandarizar las variables de entrada y volver a entrenar el modelo una sola etapa. Evaluar la precisión del modelo y la entropía cruzada.
Ayuda
Usar la función Standardizer del paquete MLJ para estandarizar las variables de entrada. La estandarización consiste en restar la media y dividir por la desviación típica de cada variable.
Usar el operador de tubería |> para encadenar la estandarización y la red neuronal en un modelo.
Solución
# Definimos la transformación de estandarización.estandarizacion =Standardizer()# Definimos de nuevo la red neuronal.red =RedNeuronal( builder = MLJFlux.MLP(; hidden = (6,), σ = relu), optimiser = Optimisers.Adam(0.01), batch_size =10, epochs =1 )# Definimos el modelo mediante un flujo que aplique primero la estandarización y luego la red neuronal.modelo = estandarizacion |> red# Creamos una máquina de aprendizaje con el modelo y los datos.mach =machine(modelo, X, y)# Entrenamos el modelo con el conjunto de entrenamiento y evaluamos el modelo.evaluate!(mach, resampling =Holdout(fraction_train =0.7, rng =123), measure = [accuracy, cross_entropy])
Volver a entrenar el modelo durante 100 etapas y evaluar de nuevo la precisión del modelo y la entropía cruzada. ¿Ha mejorado el modelo?
Solución
# Definimos el número de épocas de entrenamiento.red.epochs =100# Actualizamos la máquina de aprendizaje con el nuevo modelo.evaluate!(mach, resampling =Holdout(fraction_train =0.7, rng =123), measure = [accuracy, cross_entropy])
El modelo ha mejorado enormemente y ahora la precisión del modelo es casi del 100%. Esto indica que el modelo se ha ajustado muy bien a los datos de entrenamiento y es capaz de predecir a los datos de prueba casi a la perfección.
Volver a repetir el proceso de entrenamiento y evaluación del modelo con validación cruzada de 10 pliegues y calcular la precisión del modelo y la entropía cruzada.
Volver a repetir el proceso de entrenamiento y evaluación del modelo con validación cruzada tomando distintas tasas de aprendizaje. ¿Para qué tasa de aprendizaje se obtiene el mejor modelo? ¿Cuál es la precisión del modelo y la entropía cruzada?
Ayuda
Usar la función range del paquete MLJ para definir un rango etapas. La función range permite definir un rango de valores para un parámetro del modelo.
Solución
# Definimos un rango de tasas de aprendizaje.r =range(modelo, :(neural_network_classifier.epochs), lower=1, upper=100, scale=:log)# Obtenemos las precisiones para cada número de etapas._, _, etapas, entropia =learning_curve(mach, range = r, resampling =CV(nfolds =10), measure = cross_entropy)usingGLMakiefig =Figure()ax =Axis(fig[1, 1], title ="Precisión del modelo con distintas etapas de entrenamiento", xlabel ="Etapas", ylabel ="Precisión")lines!(ax, etapas, entropia)display(fig)# Obtenemos el número de etapas con la mejor precisión.etapas_optimas = etapas[argmin(entropia)]println("Número de etapas óptimas: ", etapas_optimas)
[ Info: Training machine(ProbabilisticTunedModel(model = ProbabilisticPipeline(standardizer = Standardizer(features = Symbol[], …), …), …), …).
[ Info: Attempting to evaluate 24 models.
Evaluating over 24 metamodels: 8%[==> ] ETA: 0:00:10Evaluating over 24 metamodels: 12%[===> ] ETA: 0:00:06Evaluating over 24 metamodels: 17%[====> ] ETA: 0:00:05Evaluating over 24 metamodels: 21%[=====> ] ETA: 0:00:04Evaluating over 24 metamodels: 25%[======> ] ETA: 0:00:03Evaluating over 24 metamodels: 29%[=======> ] ETA: 0:00:03Evaluating over 24 metamodels: 33%[========> ] ETA: 0:00:02Evaluating over 24 metamodels: 38%[=========> ] ETA: 0:00:02Evaluating over 24 metamodels: 42%[==========> ] ETA: 0:00:02Evaluating over 24 metamodels: 46%[===========> ] ETA: 0:00:02Evaluating over 24 metamodels: 50%[============> ] ETA: 0:00:01Evaluating over 24 metamodels: 54%[=============> ] ETA: 0:00:01Evaluating over 24 metamodels: 58%[==============> ] ETA: 0:00:01Evaluating over 24 metamodels: 62%[===============> ] ETA: 0:00:01Evaluating over 24 metamodels: 67%[================> ] ETA: 0:00:01Evaluating over 24 metamodels: 71%[=================> ] ETA: 0:00:01Evaluating over 24 metamodels: 75%[==================> ] ETA: 0:00:01Evaluating over 24 metamodels: 79%[===================> ] ETA: 0:00:01Evaluating over 24 metamodels: 83%[====================> ] ETA: 0:00:01Evaluating over 24 metamodels: 88%[=====================> ] ETA: 0:00:00Evaluating over 24 metamodels: 92%[======================> ] ETA: 0:00:00Evaluating over 24 metamodels: 96%[=======================> ] ETA: 0:00:00Evaluating over 24 metamodels: 100%[=========================] Time: 0:00:04
┌ Warning: Found `resolution` in the theme when creating a `Scene`. The `resolution` keyword for `Scene`s and `Figure`s has been deprecated. Use `Figure(; size = ...` or `Scene(; size = ...)` instead, which better reflects that this is a unitless size and not a pixel resolution. The key could also come from `set_theme!` calls or related theming functions.
└ @ Makie ~/.julia/packages/Makie/ux0Te/src/scenes.jl:238
Número de etapas óptimas: 39
Entrenar de nuevo el modelo con todo el conjunto de ejemplos y con el número de etapas óptimas, y predecir la especie de los 5 primeros pingüinos del conjunto de ejemplos.
Solución
# Definimos el número de épocas de entrenamiento.red.epochs = etapas_optimas# Entrenamos el modelo con todo el conjunto de ejemplos.fit!(mach)# Predecimos la especie de los 5 primeros pingüinos del conjunto de ejemplos.predict_mode(mach, X[1:5, :])