¡Avísame si esto te parece valioso y continuaré!
Uno de los conceptos más simples pero poderosos es el modelo lineal.
En ML, uno de nuestros objetivos principales es hacer predicciones basadas en datos. El modelo lineal es como el "Hola mundo" del aprendizaje automático: es sencillo pero constituye la base para comprender modelos más complejos.
Construyamos un modelo para predecir los precios de las viviendas. En este ejemplo, el resultado es el "precio de la vivienda" esperado, y sus entradas serán cosas como "sqft", "num_bedrooms", etc...
def prediction(sqft, num_bedrooms, num_baths): weight_1, weight_2, weight_3 = .0, .0, .0 home_price = weight_1*sqft, weight_2*num_bedrooms, weight_3*num_baths return home_price
Notarás un "peso" para cada entrada. Estos pesos son los que crean la magia detrás de la predicción. Este ejemplo es aburrido ya que siempre generará cero ya que los pesos son cero.
Entonces, descubramos cómo podemos encontrar estos pesos.
El proceso para encontrar los pesos se llama "entrenar" el modelo.
data = [ {"sqft": 1000, "bedrooms": 2, "baths": 1, "price": 200000}, {"sqft": 1500, "bedrooms": 3, "baths": 2, "price": 300000}, # ... more data points ... ]
home_price = prediction(1000, 2, 1) # our weights are currently zero, so this is zero actual_value = 200000 error = home_price - actual_value # 0 - 200000 we are way off. # let's square this value so we aren't dealing with negatives error = home_price**2
Ahora que tenemos una manera de saber qué tan equivocados (error) estamos para un punto de datos, podemos calcular el error promedio en todos los puntos de datos. Esto se conoce comúnmente como error cuadrático medio.
Por supuesto, podríamos elegir números aleatorios y seguir guardando el mejor valor a medida que avanzamos, pero eso es ineficiente. Entonces, exploremos un método diferente: el descenso de gradiente.
El descenso de gradiente es un algoritmo de optimización que se utiliza para encontrar los mejores pesos para nuestro modelo.
El gradiente es un vector que nos dice cómo cambia el error a medida que hacemos pequeños cambios en cada peso.
Intuición de la barra lateral
Imagínese que se encuentra en un paisaje montañoso y su objetivo es alcanzar el punto más bajo (el error mínimo). La pendiente es como una brújula que siempre señala el ascenso más empinado. Al ir en contra de la dirección del gradiente, estamos dando pasos hacia el punto más bajo.
Así es como funciona:
¿Cómo calculamos el gradiente para cada error?
Una forma de calcular el gradiente es hacer pequeños cambios en el peso, ver cómo eso afectó nuestro error y ver hacia dónde debemos movernos a partir de ahí.
def calculate_gradient(weight, data, feature_index, step_size=1e-5): original_error = calculate_mean_squared_error(weight, data) # Slightly increase the weight weight[feature_index] = step_size new_error = calculate_mean_squared_error(weight, data) # Calculate the slope gradient = (new_error - original_error) / step_size # Reset the weight weight[feature_index] -= step_size return gradient
Desglose paso a paso
Parámetros de entrada:
Calcular error original:
original_error = calculate_mean_squared_error(weight, data)
Primero calculamos el error cuadrático medio con nuestras ponderaciones actuales. Esto nos da nuestro punto de partida.
weight[feature_index] = step_size
Aumentamos el peso en una pequeña cantidad (step_size). Esto nos permite ver cómo un pequeño cambio en el peso afecta nuestro error.
new_error = calculate_mean_squared_error(weight, data)
Calculamos nuevamente el error cuadrático medio con el peso ligeramente aumentado.
gradient = (new_error - original_error) / step_size
Este es el paso clave. Nos preguntamos: "¿Cuánto cambió el error cuando aumentamos ligeramente el peso?"
La magnitud nos dice qué tan sensible es el error a los cambios en este peso.
weight[feature_index] -= step_size
Volvimos a colocar el peso en su valor original ya que estábamos probando qué pasaría si lo cambiáramos.
return gradient
Devolvemos el gradiente calculado para este peso.
Esto se llama "cálculo de gradiente numérico" o "método de diferencias finitas". Estamos aproximando el gradiente en lugar de calcularlo analíticamente.
Ahora que tenemos nuestros gradientes, podemos empujar nuestros pesos en la dirección opuesta al gradiente restando el gradiente.
weights[i] -= gradients[i]
Si nuestro gradiente es demasiado grande, fácilmente podríamos sobrepasar nuestro mínimo actualizando demasiado nuestro peso. Para solucionar este problema, podemos multiplicar el gradiente por un número pequeño:
learning_rate = 0.00001 weights[i] -= learning_rate*gradients[i]
Y así es como lo hacemos para todos los pesos:
def gradient_descent(data, learning_rate=0.00001, num_iterations=1000): weights = [0, 0, 0] # Start with zero weights for _ in range(num_iterations): gradients = [ calculate_gradient(weights, data, 0), # sqft calculate_gradient(weights, data, 1), # bedrooms calculate_gradient(weights, data, 2) # bathrooms ] # Update each weight for i in range(3): weights[i] -= learning_rate * gradients[i] if _ % 100 == 0: error = calculate_mean_squared_error(weights, data) print(f"Iteration {_}, Error: {error}, Weights: {weights}") return weights
¡Por fin tenemos nuestras pesas!
Una vez que tengamos nuestros pesos entrenados, podemos usarlos para interpretar nuestro modelo:
Por ejemplo, si nuestros pesos entrenados son [100, 10000, 15000], significa:
Los modelos lineales, a pesar de su simplicidad, son herramientas poderosas en el aprendizaje automático. Proporcionan una base para comprender algoritmos más complejos y ofrecen información interpretable sobre problemas del mundo real.
Descargo de responsabilidad: Todos los recursos proporcionados provienen en parte de Internet. Si existe alguna infracción de sus derechos de autor u otros derechos e intereses, explique los motivos detallados y proporcione pruebas de los derechos de autor o derechos e intereses y luego envíelos al correo electrónico: [email protected]. Lo manejaremos por usted lo antes posible.
Copyright© 2022 湘ICP备2022001581号-3