Aprendizado de Máquina

Prof. Ronaldo Cristiano Prati
ronaldo.prati@ufabc.edu.br
Bloco A, Sala 513-2

Tópicos da Aula

  • Implementações do algoritmo da descida do gradiente para regressão linear
    • Direta
    • Vetorizada (numpy)
    • Algebra Linear
  • Regressão linear multivariada

Função de custo

  • Vamos definir a função de custo (em python). As variáveis x e y são listas de tamanho mm, e theta é uma lista de tamanho 2.
def costFunction(x,y,theta):
    error = 0
    m = len(x)
    for i in range(m):
        error += ((theta[0] + theta[1]*x[i]) - y[i])**2
    return error / (2*m)

Descida do Gradiente (1 passo)

  • Calcula o gradiente em cada ponto e calcula o novo valor de θ\theta.
def step_gradient(x,y,theta,alpha):

    new_theta = [0,0]
    m = len(x)

    theta_0_grad = []
    theta_1_grad = []

    for i in range(m):
        theta_0_grad.append((theta[0] + theta[1]*x[i]) - y[i])
        theta_1_grad.append(((theta[0] + theta[1]*x[i]) - y[i])* x[i])

    new_theta[0] = theta[0] - (alpha * sum(theta_0_grad)/m)
    new_theta[1] = theta[1] - (alpha * sum(theta_1_grad)/m)
    return(new_theta)

Descida do Gradiente (iterando)

  • Chama o método step_gradient iterativamente para atualizar o valor de θ\theta. Armazena os valores intermediários para plotar
theta = [0,0]
theta_logs = [theta] # para plotar
cost_logs = [costFunction(x,y,theta)] # para plotar
n_iter=200
alpha = 0.001
for i in range(n_iter):
    theta = step_gradient(x,y,theta,alpha)
    theta_logs.append(theta) # para plotar
    cost_logs.append(costFunction(x,y,theta)) # para plotar

Alpha = 0.03

Alpha = 0.02

Alpha = 0.01

Alpha = 0.001

Alpha = 0.0001

Vetorização

  • Algumas linguagens (como matlab e R) permite o uso de técnicas de vetorização. Nessas linguagens, algumas operacoes são transparentemente aplicadas a vetores ou matrizes.

  • Em python, a biblioteca numpy provê várias funcionalidades para explorar vetorização

Função de custo - vetorizada

  • Uma versão da função de custo vetorizada é mostrada a seguir. Observe que não é utilizado o laço.

  • As variáveis x, y e theta devem ser numpy.array

import numpy as np

def costFunction(x,y,theta):
    error = np.sum(((theta[0] + theta[1]*x) - y)**2)
    return error / (2*m)  

Descida do Gradiente (1 passo)

def step_gradient(x,y,theta,alpha):

    theta_gradient = np.zeros(2)
    theta_gradient[0] = np.mean((theta[0] + theta[1]*x) - y)
    theta_gradient[1] = np.mean(((theta[0] + theta[1]*x) - y)*x)

    new_theta = theta - (alpha * theta_gradient)

    return(new_theta)

Algebra linear

  • Suponha que nosso modelo seja

hθ(x)=40+0.25xh_\theta(x) = -40 + 0.25x

  • Queremos aplicá-la em uma base de dados com 4 casas
Tamanho
2104
1416
1534
852

Algebra linear

  • Podemos calcular o valor predito pelo modelo acrescentando uma coluna de 1's ao conjunto de dados, e multiplicando pela "matriz" de coeficientes.

[1210411416115341852]×[400.25]=[486.0314.0343.5173.0]\begin{bmatrix} 1 & 2104 \\ 1 & 1416 \\ 1 & 1534 \\ 1 & 852 \\\end{bmatrix} \times \begin{bmatrix} -40 \\ 0.25\end{bmatrix} =\begin{bmatrix} 486.0 \\ 314.0 \\ 343.5 \\ 173.0 \end{bmatrix}

  • Isso pode ser muito mais eficiente computacionalmente que usar laços, e também facilita a codificação (se tivermos uma biblioteca de algegra linear)

Gradiente descendente - AlgLin

  • Podemos reescrever a função de custo como:
    Jθ(x)=12m(xθy)2J_\theta(x) = \frac{1}{2m} \sum\left(x {\theta} - {y} \right)^2
  • e o seu gradiente como:
    θJθ(x)=1m((xθy)x)=1m(x×(xθy))\begin{aligned} \frac{\partial}{\partial_\theta}J_\theta(x) & = \frac{1}{m} \left((x{\theta} - {y})^\intercal x \right)^\intercal \\ & = \frac{1}{m} \left(x^\intercal \times (x{\theta} - {y})\right) \end{aligned}
  • Para derivação do gradiente, veja aqui

Gradiente descendente - AlgLin

def costFunction(X, y, theta):
    error = np.dot(X, theta) - y
    return np.mean(error) / 2

def step_gradient(x,y,theta,alpha):
    m = len(x)
    theta = theta - (alpha/m) * np.dot(x.T, np.dot(x, theta) - y)
    return(theta)

x = np.column_stack((np.ones(len(x)),x))
theta = [0,0]
n_iter=200
alpha = 0.001
for i in range(n_iter):
    theta = step_gradient(x,y,theta,alpha)

Regressão linear multivariada

  • Múltiplas variáveis = múltiplos atributos
  • No problema anterior, tinhamos
    • xx = tamanho da casa (em ft2ft^2)
    • yy = preço da casa
  • Mas podemos adicionar novas variáveis, tais como
    • x1,x2,x3,x4x_1, x_2, x_3, x4 são quatro atributos:
      x1x_1 = tamanho (ft2ft^2)
      x2x_2 = número de quartos
      x3x_3 = number de andares
      x4x_4 = idade da casa (anos)
      yy = preço das casas

Mais notação

  • nn = número de atributos (n=4)(n = 4)
  • mm = número de exemplos
  • xix^i = vetor de entrada para um exemplo. ii é o índice do conjunto de treinamento, então x3x^3 é, por exemplo a 3a3^{a} casa. xx é um vetor nn-dimensional
  • xjix_j^i é o valor do atributo jj do ii-ésimo exemplo de treino. Por exemplo, x23x_2^3 é o número de quartos da terceira casa.

Forma da hipótese

  • Anteriormente nossa hipótese era da forma:
    hθ(x)=θ0+θ1xh_\theta(x) = \theta_0 + \theta_1 x

  • Agora que temos multiplos atributos:
    hθ(x)=θ0+θ1x+θ2x+θ3x+θ4xh_\theta(x) = \theta_0 + \theta_1 x + \theta_2 x + \theta_3 x + \theta_4 x

  • Se adicionarmos uma feature adicional x0=1x_0 = 1, em notação vetorial temos:

hθ(x)=θxh_\theta(x) = \overrightarrow{\theta}x

Descida do Gradiente

  • Os parâmetros ainda podem ser determinados pela função de custo

  • Atualizamos cada parâmetro θj\theta_j fazendo
    θj:=θjαθjJ(θ)\theta_j := \theta_j - \alpha \frac{\partial}{\partial\theta_j} J(\theta)

  • em que
    θjJ(θ)=1mim(hθ(xi)yi)xji\frac{\partial}{\partial\theta_j} J(\theta) = \frac{1}{m} \sum_i^m (h_\theta(x^i) - y^i) x^i_j

  • A forma vetorial se ajusta ao número de variáveis

Diferença de escala

  • Atributos em diferentes escalas podem atrapalhar a descida do Gradiente. Por exemplo, se tivermos
    x1x_1 = Tamanho (0 - 2000 ft2ft^2)
    x2x_2 = número de quartos (1-5)
    Os contornos gerados pelo plot de θ1\theta_1 \emph{vs} θ2\theta_2 será alongado em um dos eixos e estreito no outro

Diferença de escala

  • Colocar os atributos na mesma escala pode fazer o algoritmo covergir mais rapidamente
    • As linhas de contorno se parecerão mais com um círculo
  • Possíveis opções
    • Ajustar entre 0 e 1: xjimin(xj)max(xj)min(xj)\frac{x_j^i - \min(x_j)}{\max(x_j) - \min(x_j)}
    • Normalização: xjiμ(xj)σ(xj)\frac{x_j^i - \mu(x_j)}{\sigma(x_j)}

Criação de atributos

  • Suponha que tenhamos os atributos:
    • x1x_1 = Largura da frente to terreno
    • x2x_2 = Profundidade do terreno
  • Podemos criar um novo atributo x3x_3 = Área fazendo
    x3=x1x2x_3 = x_1 * x_2
  • Em muitos casos, a definição de novos atributos pode gerar modelos melhores!

Regressão Polinomial

Polinomial

Regressão Polinomial

  • Como podemos ajustar um polinômio de grau n>1n>1 aos dados?
  • Uma ideia simples é criar novos atribtos:

x1=xx2=x2x3=x3\begin{aligned} x_1 &= x \\ x_2 &= x^2 \\ x_3 &= x^3 \end{aligned}

  • Criarndo atributos como esses e aplicando o algoritmo de regressão linear podemos fazer regressão polinomial!

Regressão Polinomial

  • Reescalar os atributos se torna ainda mais importated nesse caso
  • Ao invés de um polinômio convencional, também podemos usar x1z,z{2,3,}x^{\frac{1}{z}}, z \in \{2,3,\dots\} (i.e., raiz quadrada, raiz cúbica, etc)
  • Podemos criar muitos atributos - posteriormente vamos ver algoritmos para selecionar os melhores atributos

Equação normal

  • Para alguns problemas de regressão linear, a equação normal provê uma melhor solução
    • Até agora estivemos usando a descida do Gradiente
    • Algoritmo iterativo que dá passos até convergir
  • A equação normal resolve θ\theta analiticamente
    • Resolve para o valor ótimo de θ\theta em um único passo
  • Tem vantagens e desvantagens

Equação normal

  • Vamos reescrever a função de custo Como

Jθ(x)=12m(xθy)(xθy)=12m((xθ)y)(xθy)=12m(xθ)(xθ)(xθ)yy(xθ)+yy=12mθxxθ2(xθ)+yy\begin{aligned} J_\theta(x) & = \frac{1}{2m} (x\theta - y)^{\intercal} (x\theta - y)\\ & = \frac{1}{2m} ((x\theta)^{\intercal} - y^{\intercal}) (x\theta - y) \\ & = \frac{1}{2m} (x\theta)^{\intercal}(x\theta) - (x\theta)^{\intercal}y - y^{\intercal}(x\theta) + y^\intercal y \\ & = \frac{1}{2m} \theta^\intercal x^\intercal x \theta - 2(x\theta)^\intercal + y^\intercal y \end{aligned}

Equação normal

  • Calculando a derivada

Jθ=2xxθ2xy\frac{\partial J}{\partial_\theta} = 2 x^\intercal x\theta - 2x^\intercal y

  • Igualando a zero (para achar o mínimo)

2xxθ2xy=02xxθ=2xyθ=(xx)1xy\begin{aligned} 2 x^\intercal x\theta - 2x^\intercal y & = 0 \\ 2 x^\intercal x\theta & = 2x^\intercal y \\ \theta & = (x^\intercal x)^{-1} x^\intercal y \end{aligned}

Quando usar?

  • Gradiente descendente:
    • Precisa escolher a taxa de aprendizado
    • Precisa de muitas iterações - pode ser demorado
    • Funciona bem quando nn é grande (adequado para Big Data)

Quando usar?

  • Equação Normaliza
    • não precisa escolher a taxa de aprendizado
    • não precida iterar, checar convergencia, etc.
    • Precisa inverter a matriz xxx^\intercal x (inverso de uma matrix n×nn \times n)
    • Devagar se nn é grande (pode ser bem lento)