Práctica de problemas de varias categorías basada en jupyter

Ejercicio 3: Problemas de Clasificación Múltiple


introducir

En este ejercicio, utilizaremos la regresión logística para reconocer dígitos escritos a mano (0 a 9). Ampliaremos la implementación de la regresión logística en el Ejercicio 2 y la aplicaremos a un problema de clasificación uno contra muchos.

Antes de comenzar el ejercicio, debe descargar los siguientes archivos para la carga de datos :

  • ex3data1.mat - conjunto de entrenamiento de dígitos escritos a mano
    inserte la descripción de la imagen aquí

A lo largo del ejercicio, están involucradas las siguientes asignaciones obligatorias :

1 multicategoría

En esta parte del ejercicio, extenderá el algoritmo de regresión logística que implementó anteriormente para aplicarlo a un problema de clasificación múltiple .

1.1 Conjunto de datos

Los datos del archivo ex3data1.matcontienen un conjunto de entrenamiento de 5000 dígitos escritos a mano. Cada muestra es una imagen en escala de grises de 20 píxeles por 20 píxeles, y cada píxel está representado por un número de punto flotante, que representa la intensidad en escala de grises de la posición.
Al expandir la cuadrícula de 20x20 píxeles en un vector de 400 dimensiones, cada muestra de entrenamiento se convierte en una fila de vectores en la matriz de datos. Como se muestra en la imagen a continuación, el archivo nos brinda una matriz de 5000x400 donde cada fila es una muestra de una imagen de un dígito escrito a mano.

inserte la descripción de la imagen aquí

La segunda parte del conjunto de entrenamiento es un vector de 5000 dimensiones yy que contiene las etiquetas del conjunto de entrenamiento.y

1.2 Visualización de datos

inserte la descripción de la imagen aquí

Las imágenes se representan en la matriz X como vectores de 400 dimensiones (de los cuales hay 5000). Las "características" de 400 dimensiones son las intensidades en escala de grises de cada píxel en la imagen original de 20 x 20. Las etiquetas de clase están en el vector y como las clases numéricas que representan los dígitos en la imagen.

A continuación, necesitamos cargar los datos.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.io import loadmat

data = loadmat('/home/jovyan/work/ex3data1.mat')
data
{'__header__': b'MATLAB 5.0 MAT-file, Platform: GLNXA64, Created on: Sun Oct 16 13:09:09 2011',
 '__version__': '1.0',
 '__globals__': [],
 'X': array([[0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        ...,
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.]]),
 'y': array([[10],
        [10],
        [10],
        ...,
        [ 9],
        [ 9],
        [ 9]], dtype=uint8)}

y verifique la matriz de datos XX usando la función incorporada de formaX, y y La forma de y :

data['X'].shape, data['y'].shape
((5000, 400), (5000, 1))

1.3 Vectorización de regresión logística

En esta parte del ejercicio, debe modificar la implementación de la regresión logística para que esté completamente vectorizada (es decir, sin la alternativa para forf o bucle). Esto se debe a que el código vectorizado, además de ser conciso, puede aprovechar las optimizaciones del álgebra lineal y suele ser mucho más rápido que el código iterativo. Sin embargo, si vimos en el ejercicio 2 que nuestra función de costo tiene una implementación completamente vectorizada, entonces podemos reutilizar la misma implementación aquí.

1.3.1 Vectorización de la función de costo

Necesita escribir código para vectorizar la función de costo . Ya sabemos que la función de coste es:

J ( θ ) = 1 metro ∑ yo = 1 metro [ − y ( yo ) Iniciar sesión ⁡ ( h θ ( X ( yo ) ) ) − ( 1 − y ( yo ) ) Iniciar sesión ⁡ ( 1 − h θ ( x ( yo ) ) ) ] J\left( \theta \right)=\frac{1}{m}\sum\limits_{i=1}^{m}{[-{y }^{(i)}}\log \left( { {h}_{\theta }}\left( { {x}^{(i)}} \right) \right)-\left( 1-{ {y}^{(i)}} \right)\log \left( 1-{ {h}_{\theta }}\left( { {x}^{(i)}} \right ) \ right ) ] } j( yo )=metro1yo = 1m[ - y( yo )iniciar sesión( hi( X( yo ) ))( 1y( yo ) )iniciar sesión( 1hi( X( i ) ))]
Para calcular cada elemento en la suma, necesitamos calcular para cada muestraiii
h θ ( x ( i ) ) { {h}_{\theta }}\left( { {x}^{(i)}} \right)hi( X( i ) )。其中,
h θ ( x ) = gramo ( θ TX ) { {h}_{\theta }}\left( x \right)=g\left({ { { \theta }^{T}}X} \right)\\hi( X )=gramo( yoTX )_
Y la función sigmoidea es:
g ( z ) = 1 1 + e − zg\left( z \right)=\frac{1}{1+{ { e}^{-z}}}\\gramo( z )=1+miz1
Resulta que, para todos los ejemplos, podemos calcular rápidamente con la multiplicación de matrices. Definimos XXXθ \thetaθ es:
inserte la descripción de la imagen aquí

Luego, realiza la multiplicación de matrices X θ X\theta , calculado para obtener:
inserte la descripción de la imagen aquí

En la última ecuación, si aaa ybbb son ambos vectores, podemos usara T b = b T aa^Tb=b^TaaTb _=bEl hecho de que T aθ T x ( i ) \theta^Tx^{(i)}
se pueden calcular en una línea de códigoiTX _( yo )

###在这里填入代码###
def sigmoid(z):
    return 1 / (1 + np.exp(-z))

def cost(theta, X, y):
    theta = np.matrix(theta)
    X = np.matrix(X)
    y = np.matrix(y)
    first = np.multiply(-y, np.log(sigmoid(X * theta.T)))
    second = np.multiply((1 - y), np.log(1 - sigmoid(X * theta.T))) 
    return np.sum(first - second) / len(X)

1.3.2 Vectorización de gradiente

Sabemos que esta función de costo debe minimizarse mediante el descenso de gradiente. En resumen, el gradiente de la función de costo de regresión logística es un vector cuyo jjthj个元素定义为
∂ J ∂ θ j = 1 metro ∑ yo = 1 metro [ h θ ( x ( yo ) ) − y ( yo ) ] xj ( yo ) \frac{\parcial J}{\parcial \theta_j} = \frac{1}{m}\sum\limits_{i=1}^{m}{[{ {h}_{\theta }}\left( { {x}^{(i)}} \right)-{ {y}^{(i)}}]x_{_{j}}^{(i ) } }θj J=metro1yo = 1m[ hi( X( yo ) )y( yo ) ]xj( yo )
Para vectorizar esta operación, necesitamos tomar todos los θ j \theta_jijLas derivadas parciales de se escriben:

inserte la descripción de la imagen aquí
en:
inserte la descripción de la imagen aquí

Nota x (i) x^{(i)}X( i ) es una cantidad unidireccional, y( h θ ( x ( i ) ) − y ( i ) ) (h_\theta(x^{(i)})-y^{(i)})( hi( X( yo ) )y( i ) )es un índice (número).
β yo = ( h θ ( x ( yo ) ) − y ( yo ) ) \beta_i = ({ {h}_{\theta }}\left( { {x}^{(i)}} \right)-{ { y}^{(i)}})byo=( hi( X( yo ) )y( i ) )puede entenderse de la siguiente manera:
inserte la descripción de la imagen aquí

Después de vectorizar la operación, sabemos que el cálculo de la derivada parcial se puede realizar sin usar el ciclo LOOP. A continuación, debe escribir código para implementar una versión vectorizada del código anterior .

###在这里填入代码###
def gradient(theta, X, y):
    theta = np.matrix(theta)
    X = np.matrix(X)
    y = np.matrix(y)
    
    parameters = int(theta.ravel().shape[1])
    error = sigmoid(X * theta.T) - y
    
    grad = ((X.T * error) / len(X)).T
    
    return grad

1.3.3 Vectorización de regresión logística regularizada

En el Ejercicio 2, implementamos la función de costo y la función de cálculo de gradiente del algoritmo de regresión logística regularizada. Su función de costo es:

J ( θ ) = 1 m ∑ i = 1 m [ − y ( i ) log ⁡ ( h θ ( x ( i ) ) ) − ( 1 − y ( i ) ) log ⁡ ( 1 − h θ ( x ( i ) ) ) ] + λ 2 m ∑ j = 1 n θ j 2 J\left( \theta \right)=\frac{1}{m}\sum\limits_{i=1}^{m}{[-{ {y}^{(i)}}\log \left( { {h}_{\theta }}\left( { {x}^{(i)}} \right) \right)-\left( 1-{ {y}^{(i)}} \right)\log \left( 1-{ {h}_{\theta }}\left( { {x}^{(i)}} \right) \right)]}+\frac{\lambda }{2m}\sum\limits_{j=1}^{n}{\theta _{j}^{2}} j( yo )=metro1yo = 1m[ - y( yo )iniciar sesión( hi( X( yo ) ))( 1y( yo ) )iniciar sesión( 1hi( X( yo ) ))]+2 metrosyoj = 1nij2
Tenga en cuenta que no hay necesidad de θ o \theta_oio进行正则化,其用于偏差的计算。
对应地,其梯度的计算公式如下:
R e p e a t   u n t i l   c o n v e r g e n c e    ⁣ ⁣ {  ⁣ ⁣     θ 0 : = θ 0 − a 1 m ∑ i = 1 m [ h θ ( x ( i ) ) − y ( i ) ] x 0 ( i )   θ j : = θ j − a 1 m ∑ i = 1 m [ h θ ( x ( i ) ) − y ( i ) ] x j ( i ) + λ m θ j    ⁣ ⁣ }  ⁣ ⁣   R e p e a t \begin{align} & Repeat\text{ }until\text{ }convergence\text{ }\!\!\{\!\!\text{ } \\ & \text{ }{ {\theta }_{0}}:={ {\theta }_{0}}-a\frac{1}{m}\sum\limits_{i=1}^{m}{[{ {h}_{\theta }}\left( { {x}^{(i)}} \right)-{ {y}^{(i)}}]x_{_{0}}^{(i)}} \\ & \text{ }{ {\theta }_{j}}:={ {\theta }_{j}}-a\frac{1}{m}\sum\limits_{i=1}^{m}{[{ {h}_{\theta }}\left( { {x}^{(i)}} \right)-{ {y}^{(i)}}]x_{j}^{(i)}}+\frac{\lambda }{m}{ {\theta }_{j}} \\ & \text{ }\!\!\}\!\!\text{ } \\ & Repetir \\ \end{align }Repetir hasta la co n v e r g e n c i a _ _ _ _ _   {   i0:=i0ametro1yo = 1m[ hi( X( yo ) )y( yo ) ]x0( yo ) ij:=ijametro1yo = 1m[ hi( X( yo ) )y( yo ) ]xj( yo )+metroyoij } Repetir _ _ _ _ _
A continuación, debe escribir código que implemente una implementación vectorizada de la función de costo y el gradiente del algoritmo de regresión logística regularizada .

###在这里填入代码###
def costReg(theta, X, y, learningRate):
    theta = np.matrix(theta)
    X = np.matrix(X)
    y = np.matrix(y)
    first = np.multiply(-y, np.log(sigmoid(X * theta.T)))
    second = np.multiply((1 - y), np.log(1 - sigmoid(X * theta.T)))
    reg = (learningRate / (2 * len(X))) * np.sum(np.power(theta[:,1:theta.shape[1]], 2))
    return np.sum(first - second) / len(X) + reg

def gradientReg(theta, X, y, learningRate):
    theta = np.matrix(theta)
    X = np.matrix(X)
    y = np.matrix(y)
    
    parameters = int(theta.ravel().shape[1])
    error = sigmoid(X * theta.T) - y
    
    grad = ((X.T * error) / len(X)).T + ((learningRate / len(X)) * theta)
    
    # intercept gradient is not regularized
    grad[0, 0] = np.sum(np.multiply(error, X[:,0])) / len(X)
    
    return np.array(grad).ravel()

1.4 Multi-Clasificación - Clasificador

Ahora que hemos definido las funciones de costo y gradiente, necesitamos construir un clasificador. Para el reconocimiento de escritura a mano, tenemos 10 clases posibles (0-9), pero la regresión logística es un problema de clasificación binaria.

En este ejercicio, su tarea es implementar un método de clasificación completo uno a uno con kkK etiquetas de diferentes clases tienenkkk clasificadores, cada clasificador en "categoríaiiyo " y "noyoi " para decidir entre. Envolveremos el entrenamiento del clasificador en una función que calcula los pesos finales para cada uno de los 10 clasificadores y devuelve los pesos como [ k , n + 1 ][k,n+1][ k ,norte+1 ] , dondennn es el número de parámetros.

Tenga en cuenta que :

  • Necesito sumar θ 0 \theta_0i0para calcular el término de intersección.
  • Convierta $y$ de etiquetas de clase a binario para cada clasificador (ya sea clase i o no clase i).
  • Use la función de minimización de la clase de optimización de la biblioteca scipy para minimizar la función de costo de cada clasificador.
  • Asigne los parámetros óptimos encontrados a la matriz de parámetros y devuelva la forma como [ k , n + 1 ] [k,n+1][ k ,norte+1 ] la matriz de parámetros.

Entre ellos, la parte más importante de implementar código vectorizado es asegurarse de que todas las matrices se escriban correctamente y sus dimensiones sean correctas.

###在这里填入代码###
from scipy.optimize import minimize

def one_vs_all(X, y, num_labels, learning_rate):
    rows = X.shape[0]
    params = X.shape[1]
    
    # k个分类器的参数,形状为(k,n+1)
    all_theta = np.zeros((num_labels, params + 1))
    
    # 插入值为1的列,用于计算截距项
    X = np.insert(X, 0, values=np.ones(rows), axis=1)
    
    # 将分类标签转换为0-1标识
    for i in range(1, num_labels + 1):
        theta = np.zeros(params + 1)
        y_i = np.array([1 if label == i else 0 for label in y])
        y_i = np.reshape(y_i, (rows, 1))
        
        # 使用minimize函数最小化代价函数
        fmin = minimize(fun=costReg, x0=theta, args=(X, y_i, learning_rate), method='TNC', jac=gradientReg)
        all_theta[i-1,:] = fmin.x
    
    return all_theta

Verifiquemos las variables que deben inicializarse y la forma de las variables:

rows = data['X'].shape[0]
params = data['X'].shape[1]

all_theta = np.zeros((10, params + 1))

X = np.insert(data['X'], 0, values=np.ones(rows), axis=1)

theta = np.zeros(params + 1)

y_0 = np.array([1 if label == 0 else 0 for label in data['y']])
y_0 = np.reshape(y_0, (rows, 1))

X.shape, y_0.shape, theta.shape, all_theta.shape
((5000, 401), (5000, 1), (401,), (10, 401))

Entre ellos, theta thetathe t a es una matriz 1D, por lo que cuando se convierte en una matriz en el código de gradiente de cálculo, adquiere la forma ( 1 , 401 ) ( 1 401)( 1 ,401 ) matriz. Al mismo tiempo, tenemos que comprobaryyLas etiquetas de clase en y .

np.unique(data['y'])#看下有几类标签
array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10], dtype=uint8)

Luego, para asegurarse de que la función de entrenamiento funcione correctamente, ejecute el siguiente código para ver si obtiene un resultado razonable.

###请运行并测试你的代码###
all_theta = one_vs_all(data['X'], data['y'], 10, 1)
all_theta
array([[-2.38373823e+00,  0.00000000e+00,  0.00000000e+00, ...,
         1.30440684e-03, -7.49607957e-10,  0.00000000e+00],
       [-3.18277385e+00,  0.00000000e+00,  0.00000000e+00, ...,
         4.46416745e-03, -5.08967467e-04,  0.00000000e+00],
       [-4.79656036e+00,  0.00000000e+00,  0.00000000e+00, ...,
        -2.87471064e-05, -2.47976297e-07,  0.00000000e+00],
       ...,
       [-7.98398219e+00,  0.00000000e+00,  0.00000000e+00, ...,
        -8.95642491e-05,  7.22603652e-06,  0.00000000e+00],
       [-4.57124969e+00,  0.00000000e+00,  0.00000000e+00, ...,
        -1.33504169e-03,  9.98035730e-05,  0.00000000e+00],
       [-5.40535662e+00,  0.00000000e+00,  0.00000000e+00, ...,
        -1.16457336e-04,  7.86968213e-06,  0.00000000e+00]])

1.5 Predicción usando clasificadores

Ahora estamos listos para el paso final donde necesita usar el clasificador entrenado para predecir una etiqueta para cada imagen .

Para este paso, calcularemos la probabilidad de clase para cada clase, para cada muestra de entrenamiento (usando el código vectorizado) y etiquetaremos la clase de salida como la clase con la probabilidad más alta.

###在这里填入代码###
def predict_all(X, all_theta):
    rows = X.shape[0]
    params = X.shape[1]
    num_labels = all_theta.shape[0]
    
    # 与之前一样,需要插入一列确保矩阵形状
    X = np.insert(X, 0, values=np.ones(rows), axis=1)
    
    # 将其转换为矩阵
    X = np.matrix(X)
    all_theta = np.matrix(all_theta)
    
    # 计算每个训练样本所属每个类别的概率
    h = sigmoid(X * all_theta.T)
    
    # 创建具有最大概率的索引数组
    h_argmax = np.argmax(h, axis=1)
    
    # 因为我们的数组是零索引的,所以我们需要为真正的标签预测+1
    h_argmax = h_argmax + 1
    
    return h_argmax

Ahora podemos usar la función predict_all para generar predicciones de clase para cada instancia y ver cómo funciona nuestro clasificador.

###请运行并测试你的代码###
y_pred = predict_all(data['X'], all_theta)
correct = [1 if a == b else 0 for (a, b) in zip(y_pred, data['y'])]
accuracy = (sum(map(int, correct)) / float(len(correct)))
print ('accuracy = {0}%'.format(accuracy * 100))
accuracy = 94.46%

Resumir

El problema de clasificación múltiple es una tarea importante en el aprendizaje automático, que generalmente requiere el uso de algoritmos de clasificación para predecir y clasificar diferentes categorías de datos. En la práctica, podemos usar una variedad de diferentes algoritmos de clasificación múltiple, como árboles de decisión, redes neuronales, máquinas de vectores de soporte, etc. para resolver problemas prácticos. Al mismo tiempo, también es necesario prestar atención al preprocesamiento de datos, la selección de características y la evaluación del modelo para mejorar la precisión y confiabilidad del algoritmo. Finalmente, para aplicar mejor los algoritmos de clasificación múltiple, es necesario aprender y explorar continuamente nuevos algoritmos y técnicas para hacer frente a los datos y necesidades cambiantes.

Supongo que te gusta

Origin blog.csdn.net/weixin_53573350/article/details/131071183
Recomendado
Clasificación