"Aprendizaje automático" de Andrew Ng: implementación de código de regresión lineal


Los conjuntos de datos y los archivos fuente se pueden obtener en el proyecto Github.

Dirección: https://github.com/Raymond-Yang-2001/AndrewNg-Machine-Learing-Homework

1. Regresión lineal univariada

La regresión lineal univariada encuentra una ecuación unidimensional y se ajusta a una línea recta.

Fórmula de regresión lineal univariante

hw , b ( x ) = b + wx h_{w,b}(x)=b+wxhw , b( X )=b+w x
www ybbb es un parámetro. Para facilitar el cálculo, puede darxxx más unx 0 = 1 x_0=1X0=1
hw , b ( x ) = bx 0 + wx 1 h_{w,b}(x)=bx_{0}+wx_{1}hw , b( X )=b x0+ancho x1

función de pérdida

J ( w , b ) = 1 2 m ∑ i = 1 m ( hw , b ( x ( i ) ) − y ( i ) ) 2 J(w,b)=\frac{1}{2m}\sum_{ i=1}^{m}(h_{w,b}(x^{(i)})-y^{(i)})^{2}J ( w ,b )=2m_ _1yo = 1m( hw , b( X( i ) )y( i ) )2
Para evitar pérdidas excesivas o pequeñas causadas por rangos de datos inadecuados (por ejemplo, si el valor de los datos es demasiado grande, la pérdida puede ser1 0 5 10^51 05 o1 0 6 10^61 06 , este orden de magnitud no es adecuado para un análisis intuitivo) Al evaluar la pérdida, puede hw, b (x (i)) h_{w,b}(x^{(i)})hw , b( X( yo ) )sumy( yo ) y^{(i)}y( i ) Primero estandarizar para que el valor de la pérdida esté dentro de un rango evaluable. Pero esto no se hace cuando se hace un descenso de gradiente.

Algoritmo de optimización: descenso de gradiente por lotes (BGD)

wj = wj − α ∂ ∂ wj J ( w , b ) = wj − α 1 m ∑ i = 1 m ( hw , b ( x ( i ) ) − y ( i ) ) x ( i ) w_j=w_{j }-\alpha\frac{\partial}{\partial{w_j}}{J(w,b)}=w_{j}-\alpha \frac{1}{m}\sum_{i=1}^{ m}{(h_{w,b}(x^{(i)})-y^{(i)})x^{(i)}}wj=wjawjJ ( w ,b )=wjametro1yo = 1m( hw , b( X( i ) )y( yo ) )x( i )
bj = bj − α ∂ ∂ bj J ( w , b ) = wj − α 1 m ∑ i = 1 m ( hw , b ( x ( i ) ) − y ( i ) ) b_j=b_{j} -\alpha\frac{\partial}{\partial{b_j}}{J(w,b)}=w_{j}-\alpha \frac{1}{m}\sum_{i=1}^{m }{(h_{w,b}(x^{(i)})-y^{(i)})}bj=bjasegundojJ ( w ,b )=wjametro1yo = 1m( hw , b( X( i ) )y( i ) )
Aquí, podemos usarθ \thetaθ parámetros de identificación unificados, incluidowww ybbb .

Es decir, jjthj parámetrosθ j \theta_jijDetermine lo siguiente:
θ j = θ j − α ∂ ∂ wj J ( θ ; x ) = wj − α 1 m ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) x ( i ) \theta_{j}=\theta_{j}-\alpha\frac{\partial}{\partial{w_j}}{J(\theta;\mathbf{x})}=w_{j}-\alpha \frac {1}{m}\sum_{i=1^{m}{(h_{\theta}(x^{(i)})-y^{(i)})x^{(i) }}ij=ijawjJ ( θ ;X )=wjametro1yo = 1m( hi( X( i ) )y( yo ) )x( i )
dondeα \alphaα es la tasa de aprendizaje.

2. Regresión lineal multivariable

La regresión lineal multivariable intenta encontrar la relación entre múltiples variables y los valores predichos. Por ejemplo, la relación entre el tamaño de la casa, el número de dormitorios de una casa y los precios de la vivienda.

Escalado de características (normalización)

Cuando las diferencias numéricas entre las diferentes características de la muestra son demasiado grandes, los métodos de optimización basados ​​​​en gradientes tendrán algunos problemas. Por ejemplo, existe la siguiente ecuación de regresión:
h θ ( x ) = θ 0 + θ 1 x 1 + θ 2 x 2 h_{\theta}(x)=\theta_{0}+\theta_{1}x_{ 1}+\ theta_{2}x_{2}hi( X )=i0+i1X1+i2X2
Supongamos x 2 x_ {2}X2El rango es 0 ∼ 1 0\sim101 ,x 1 x_1X1El rango es 1 0 3 ∼ 1 0 4 10^3\sim10^41 031 04 . Optimizamos simultáneamenteθ 0 ∼ θ 2 \theta_0\sim\theta_2i0i2, de modo que todas cambien en el mismo tamaño, entonces obviamente cuando las muestras de entrada son iguales, θ 1 \theta_1i1El cambio será mayor que θ 2 \theta_2i2cambios que conduzcan a una mayor producción. Esto también puede entenderse como el par de modelos θ 1 \theta_1i1Más sensible. Como se muestra en el siguiente diagrama de isolíneas de pérdida, θ 1 \theta_1i1Pequeños cambios pueden traer cambios drásticos en las pérdidas. En este caso, la optimización de los parámetros será más difícil.
Insertar descripción de la imagen aquí
Una forma de resolver este problema es el escalado de funciones, que escala dos funciones al mismo rango. Por ejemplo, se puede realizar la normalización del puntaje z:
xnew = x − μ σ x_{new} = \frac{x-\mu}{\sigma}Xnuevo _ _=pagXmetro
Entre ellos, μ \muμ es la media del conjunto de datos,σ \sigmaσ es la desviación estándar y la distribución de datos nuevos es una distribución con media 0 y desviación estándar 1.
El diagrama de pérdida de parámetros después de la normalización de datos es el siguiente:
Insertar descripción de la imagen aquí

Escalado inverso de parámetros.

Dado que los datos están escalados, los parámetros finales también se escalarán en consecuencia. La relación específica es la siguiente:
θ 0 + θ 1 ∼ d + 1 x 1 ∼ d + 1 − μ x σ x = y − μ y σ y \theta_{0}+\theta_{1\sim d+1} \frac {x_{1\sim d+1}-\mu_{x}}{\sigma_{x}}=\frac{y-\mu_{y}}{\sigma_{y}}i0+i1 d + 1pagxX1 d + 1metrox=pagyymetroy
Aquí estamos hablando de yyy también se ha estandarizado,de hecho, no es necesario hacer esto y no habrá ningún impacto en el rendimiento. Pero la normalización de y hace que los parámetros sean más pequeños y la convergencia se puede lograr más rápido para los parámetros inicializados en 0.

En estandarizaciónEn este caso, la fórmula de escala inversa de los parámetros es:
θ 1 ∼ d + 1 new = θ 1 ∼ d + 1 σ x σ y \theta_{1\sim d+1}^{new}=\frac{\ theta_{1\sim d+1}}{\sigma_{x}}\sigma_{y}i1 re + 1nuevo _ _=pagxi1 d + 1pagy
Fórmula:
θ 0 σ y + θ 1 ∼ d + 1 nuevo ( x 1 ∼ d + 1 − μ x ) = y − μ y \theta_{0}\sigma_{y}+\theta_{1\sim d+1 }^{nuevo}(x_{1\sim d+1}-\mu_{x})=y-\mu_{y}i0pagy+i1 re + 1nuevo _ _( X1 d + 1metrox)=ymetroy

θ 0 nuevo = θ 0 σ y + μ y − θ 1 ∼ d + 1 nuevo μ x \theta_{0}^{new}=\theta_{0}\sigma_{y}+\mu_{y}-\theta_ {1\sim+1}^{nuevo}\mu_{x}i0nuevo _ _=i0pagy+metroyi1 re + 1nuevo _ _metrox
Entre ellos, durante la operación de vectorización, θ 1 ∼ d + 1 new \theta_{1\sim d+1}^{new}i1 re + 1nuevo _ _μ x \mu_{x}metroxTodos son vectores de (1,d), y la multiplicación debe utilizar el producto interno del vector.

3. Implementación del código del algoritmo de regresión lineal

implementación de vectores

Sea el dato x \boldsymbol{x}Las dimensiones de x son(n,d) (n,d)( norte ,d ) , donde n es el número de muestras y d es la dimensión de las características de la muestra. Para facilitar el cálculo, agregamos una dimensión de característica adicional con todos los valores 1 a la muestra, de modo que su dimensión se convierta en( n , d + 1 ) (n, d+1)( norte ,d+1 )

  1. Predicción
    Sea el parámetro θ \boldsymbol{\theta}La dimensión de θ es (1, d+1), entoncesx θ ⊤ \boldsymbol{x\theta^{\top}}_( θ x ⊤ ) ⊤ \boldsymbol{(\theta x^{\top})^{\top}}( θ x )⊤La dimensión se puede obtener como(n, 1) (n,1)( norte ,1 ) Resultado de la predicciónh θ ( x ) h_{\boldsymbol{\theta}}(\boldsymbol{x})hi( X ) .
  2. Dividamos la
    cantidad j entre la cantidad:
    θ j = θ j − α ∂ ∂ wj J ( θ ; x ) = wj − α 1 m ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) x ( i ) \theta_{j}=\theta_{j}-\alpha\frac{\partial}{\partial{w_j}}{J(\theta;\mathbf{x})}=w_ {j }-\alpha\frac{1}{m}\sum_{i=1}^{m}{(h_{\theta}(x^{(i)})-y^{(i)}) x^ {(i)}}ij=ijawjJ ( θ ;X )=wjametro1yo = 1m( hi( X( i ) )y( yo ) )x( i )
    De hecho, aquí ponemosθ 0 \theta_{0}i0Como sesgo, su gradiente debería ser:
    ∂ ∂ w 0 J ( θ ; x ) = w 0 − α 1 m ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) \frac{\ parcial}{\partial{w_0}}{J(\theta;\mathbf{x})}=w_{0}-\alpha \frac{1}{m}\sum_{i=1}^{m}{ (h_{\theta}(x^{(i)})-y^{(i)})}w0J ( θ ;X )=w0ametro1yo = 1m( hi( X( i ) )y( i ) ), ya que complementamos los datos con dimensiones de característicasx 0 x_0X0, por lo que se puede calcular utilizando la fórmula anterior al igual que otros parámetros.
    dejar error errormatriz de error β \boldsymbol{\beta}βh θ ( x ) − x h_{\boldsymbol{\theta}}(\boldsymbol{x})-\boldsymbol{x}hi( X )x , con dimensiones( n , 1 ) (n,1)( norte ,1 ) , entoncesx ⊤ β / n \boldsymbol{x^{\top}\beta} /nX β/nes la dimensión(d + 1, 1) (d+1,1)( d+1 ,1 )的梯度矩阵。
    x ⊤ β = [ x ( 1 ) x ( 2 ) ⋯ ] × [ h ( x ( 1 ) ) − y ( 1 ) h ( x ( 2 ) ) − y ( 2 ) ⋮ ] = [ ∑ i = 1 norte ( h ( x ( i ) ) − y ( i ) ) x 0 ( 1 ) ∑ i = 1 norte ( h ( x ( i ) ) − y ( i ) ) x 1 ( 1 ) ⋮ ] \boldsymbol{x^{\top}\beta}= \left[ \begin{matrix} x^{(1)}& x^{(2)} &\cdots \end{matrix} \right] \times \left[ \begin{matrix} h(x^{(1)})-y^{(1)}\\ h(x^{(2)})-y^{(2)}\\ \vdots \end{matrix} \right] =\left[ \begin{matrix} \sum_{i=1}^{n}{(h(x^{(i)})-y^{(i)})x_ {0}^{(1)}}\\ \sum_{i=1}^{n}{(h(x^{(i)})-y^{(i)})x_{1}^{ (1)}}\\ \vdots \end{matrix} \right]X⊤β _=[X( 1 )X( 2 )]× h ( x( 1 ) )y( 1 )h ( x( 2 ) )y( 2 ) = yo = 1norte( h ( x( i ) )y( yo ) )x0( 1 )yo = 1norte( h ( x( i ) )y( yo ) )x1( 1 )
    x ⊤ β / n \boldsymbol{x^{\top}\beta} /nXCada elemento en β/n

código pitón

import numpy as np


def square_loss(pred, target):
    """
    计算平方误差
    :param pred: 预测
    :param target: ground truth
    :return: 损失序列
    """
    return np.sum(np.power((pred - target), 2))


def compute_loss(pred, target):
    """
    计算归一化平均损失
    :param pred: 预测
    :param target: ground truth
    :return: 损失
    """
    pred = (pred - pred.mean(axis=0)) / pred.std(axis=0)
    target = (pred - target.mean(axis=0)) / target.std(axis=0)
    loss = square_loss(pred, target)
    return np.sum(loss) / (2 * pred.shape[0])


class LinearRegression:
    """
    线性回归类
    """

    def __init__(self, x, y, val_x, val_y, epoch=100, lr=0.1):
        """
        初始化
        :param x: 样本, (sample_number, dimension)
        :param y: 标签, (sample_numer, 1)
        :param epoch: 训练迭代次数
        :param lr: 学习率
        """
        self.theta = None
        self.loss = []
        self.val_loss = []
        self.n = x.shape[0]
        self.d = x.shape[1]

        self.epoch = epoch
        self.lr = lr

        t = np.ones(shape=(self.n, 1))

        self.x_std = x.std(axis=0)
        self.x_mean = x.mean(axis=0)
        self.y_mean = y.mean(axis=0)
        self.y_std = y.std(axis=0)

        x_norm = (x - self.x_mean) / self.x_std
        y_norm = (y - self.y_mean) / self.y_std

        self.y = y_norm
        self.x = np.concatenate((t, x_norm), axis=1)

        self.val_x = val_x
        self.val_y = val_y

    def init_theta(self):
        """
        初始化参数
        :return: theta (1, d+1)
        """
        self.theta = np.zeros(shape=(1, self.d + 1))

    def validation(self, x, y):
        x = (x - x.mean(axis=0)) / x.std(axis=0)
        y = (y - y.mean(axis=0)) / y.std(axis=0)
        outputs = self.predict(x)
        curr_loss = square_loss(outputs, y) / (2 * y.shape[0])
        return curr_loss

    def gradient_decent(self, pred):
        """
        实现梯度下降求解
        """
        # error (n,1)
        error = pred - self.y
        # gradient (d+1, 1)
        gradient = np.matmul(self.x.T, error)
        # gradient (1,d+1)
        gradient = gradient.T / pred.shape[0]
        # update parameters
        self.theta = self.theta - (self.lr / self.n) * gradient

    def train(self):
        """
        训练线性回归
        :return: 参数矩阵theta (1,d+1); 损失序列 loss
        """
        self.init_theta()

        for i in range(self.epoch):
            # pred (1,n); theta (1,d+1); self.x.T (d+1, n)
            pred = np.matmul(self.theta, self.x.T)
            # pred (n,1)
            pred = pred.T
            curr_loss = square_loss(pred, self.y) / (2 * self.n)
            val_loss = self.validation(self.val_x, self.val_y)
            self.gradient_decent(pred)
            
            self.val_loss.append(val_loss)
            self.loss.append(curr_loss)
            print("Epoch: {}/{}\tTrain Loss: {:.4f}\tVal loss: {:.4f}".format(i + 1, self.epoch, curr_loss, val_loss))

        # un_scaling parameters
        self.theta[0, 1:] = self.theta[0, 1:] / self.x_std.T * self.y_std[0]
        self.theta[0, 0] = self.theta[0, 0] * self.y_std[0] + self.y_mean[0] - np.dot(self.theta[0, 1:], self.x_mean)
        return self.theta, self.loss, self.val_loss

    def predict(self, x):
        """
        回归预测
        :param x: 输入样本 (n,d)
        :return: 预测结果 (n,1)
        """
        # (d,1)
        t = np.ones(shape=(x.shape[0], 1))
        x = np.concatenate((t, x), axis=1)
        pred = np.matmul(self.theta, x.T)
        return pred.T


4. Resultados experimentales

Regresión univariada

Conjunto de entrenamiento de visualización de conjuntos de datos
Insertar descripción de la imagen aquí
y división del conjunto de pruebas
blog.csdnimg.cn/c92b41d0e88f4afab794315c992525a0.png)

from LinearRegression import LinearRegression

epochs = 200
alpha = 1
linear_reg = LinearRegression(x=train_x_ex,y=train_y_ex,val_x=val_x_ex, val_y=val_y_ex, lr=alpha,epoch=epochs)
start_time = time.time()
theta,loss, val_loss = linear_reg.train()
end_time = time.time()
Train Time: 0.0309s
Val Loss: 6.7951

Visualización del proceso de entrenamiento
Insertar descripción de la imagen aquí
y curva de predicción de comparación de sk-learn.
Insertar descripción de la imagen aquí

regresión multivariable

Conjunto de visualización y entrenamiento de datos y conjunto de validación.
Insertar descripción de la imagen aquí

from LinearRegression import LinearRegression

alpha = 0.1
epochs = 1000
multi_lr = LinearRegression(train_x,train_y_ex,val_x=val_x,val_y=val_y_ex, epoch=epochs,lr=alpha)
start_time = time.time()
theta, loss, val_loss = multi_lr.train()
end_time = time.time()
Train Time: 0.1209s
Val Loss: 4.187(采用归一化后数据计算损失)

Visualización del proceso de formación.
Insertar descripción de la imagen aquí

Plano de predicción (en comparación con sk-learn),
donde el azul es el plano de predicción de este algoritmo y el gris es el plano de predicción de sk-learn.
Insertar descripción de la imagen aquí

Resumen del experimento

Para que la implementación del algoritmo de regresión lineal logre un mejor rendimiento, puede intentar ajustar la tasa de aprendizaje o el número de iteraciones para obtener un mejor rendimiento. Dado que se utilizan operaciones matriciales en lugar de bucles, el tiempo de entrenamiento se reduce considerablemente, pero aún no ha alcanzado el nivel de la función de la biblioteca sk-learn.

Supongo que te gusta

Origin blog.csdn.net/d33332/article/details/128455218
Recomendado
Clasificación