Descida de gradiente estocástico com base em operações vetoriais?

10

Vamos supor que eu queira treinar um algoritmo de regressão descendente de gradiente estocástico usando um conjunto de dados que possui N amostras. Como o tamanho do conjunto de dados é fixo, reutilizarei os dados T vezes. Em cada iteração ou "época", eu uso cada amostra de treinamento exatamente uma vez após reordenar aleatoriamente todo o conjunto de treinamento.

Minha implementação é baseada em Python e Numpy. Portanto, o uso de operações vetoriais pode diminuir notavelmente o tempo de computação. Criar uma implementação vetorizada de descida em gradiente de lote é bastante simples. No entanto, no caso da descida do gradiente estocástico, não consigo descobrir como evitar o loop externo que itera através de todas as amostras em cada época.

Alguém conhece alguma implementação vetorizada de descida de gradiente estocástico?

EDIT : Me perguntaram por que gostaria de usar a descida gradiente on-line se o tamanho do meu conjunto de dados é fixo.

De [1], pode-se ver que a descida do gradiente online converge mais lentamente que a descida do gradiente em lote para o mínimo do custo empírico. No entanto, converge mais rapidamente para o mínimo do custo esperado, que mede o desempenho da generalização. Eu gostaria de testar o impacto desses resultados teóricos no meu problema específico, por meio da validação cruzada. Sem uma implementação vetorizada, meu código de descida de gradiente online é muito mais lento que o de descida de gradiente em lote. Isso aumenta notavelmente o tempo necessário para que o processo de validação cruzada seja concluído.

EDIT : eu incluo aqui o pseudocódigo da minha implementação de descida de gradiente on-line, conforme solicitado pelo ffriend. Estou resolvendo um problema de regressão.

Method: on-line gradient descent (regression)
Input: X (nxp matrix; each line contains a training sample, represented as a length-p vector), Y (length-n vector; output of the training samples)
Output: A (length-p+1 vector of coefficients)

Initialize coefficients (assign value 0 to all coefficients)
Calculate outputs F
prev_error = inf
error = sum((F-Y)^2)/n
it = 0
while abs(error - prev_error)>ERROR_THRESHOLD and it<=MAX_ITERATIONS:
    Randomly shuffle training samples
    for each training sample i:
        Compute error for training sample i
        Update coefficients based on the error above
    prev_error = error
    Calculate outputs F
    error = sum((F-Y)^2)/n
    it = it + 1

[1] "Aprendizagem on-line em larga escala", L. Bottou, Y. Le Cunn, NIPS 2003.

Pablo Suau
fonte
2
Divida o conjunto de dados em minilotes e ajuste o modelo a cada minilote sequencialmente.
ffriend
Obrigado @ffriend. No entanto, isso não seria uma pura implementação on-line.
Pablo Suau 10/10
11
Qual é o motivo para usar a implementação "pura online" se seu conjunto de dados for corrigido? O SGD diz apenas que você não precisa iterar todo o conjunto de dados de uma só vez, mas pode dividi-lo em um número arbitrário de peças (minilotes) e processá-los um por um. O minilote de tamanho 1 só faz sentido quando você tem uma fonte de dados contínua e possivelmente infinita (como feed do twitter, por exemplo) e deseja atualizar o modelo após cada nova observação. Mas esse é um caso muito raro e definitivamente não é para conjuntos de dados fixos.
ffriend
Desculpas pela minha resposta muito tardia. Por favor, verifique o texto que eu adicionei à pergunta original.
Pablo Suau
11
Você pode mostrar sua implementação? Vejo mal-entendidos, mas sem um exemplo de código, será difícil explicá-lo.
ffriend

Respostas:

10

Antes de tudo, a palavra "amostra" é normalmente usada para descrever um subconjunto da população , por isso vou me referir à mesma coisa que "exemplo".

Sua implementação do SGD é lenta devido a esta linha:

for each training example i:

Aqui você usa explicitamente exatamente um exemplo para cada atualização dos parâmetros do modelo. Por definição, a vetorização é uma técnica para converter operações em um elemento em operações em um vetor desses elementos. Portanto, não, você não pode processar exemplos um por um e ainda usar a vetorização.

Você pode, no entanto, aproximar o SGD verdadeiro usando minilotes . Mini-lote é um pequeno subconjunto do conjunto de dados original (digamos, 100 exemplos). Você calcula atualizações de erros e parâmetros com base em minilotes, mas ainda itera muitos deles sem otimização global, tornando o processo estocástico. Portanto, para tornar sua implementação muito mais rápida, basta alterar a linha anterior para:

batches = split dataset into mini-batches
for batch in batches: 

e calcule o erro do lote, não de um único exemplo.

Embora bastante óbvio, também devo mencionar a vetorização no nível por exemplo. Ou seja, em vez de algo como isto:

theta = np.array([...])  # parameter vector
x = np.array([...])      # example
y = 0                    # predicted response
for i in range(len(example)):
    y += x[i] * theta[i]
error = (true_y - y) ** 2  # true_y - true value of response

você definitivamente deveria fazer algo assim:

error = (true_y - sum(np.dot(x, theta))) ** 2

que, novamente, fácil de generalizar para mini-lotes:

true_y = np.array([...])     # vector of response values
X = np.array([[...], [...]]) # mini-batch
errors = true_y - sum(np.dot(X, theta), 1)
error = sum(e ** 2 for e in errors)
amiga
fonte
11
Eu acho que este é o caminho a percorrer. Mini-lotes com um tamanho bem escolhido podem realmente convergir mais rapidamente do que a versão em lote ou on-line (o antigo atualiza apenas os pesos uma vez por conjunto inteiro e o último não pode ser vetorizado, além de ter etapas adicionais de atualização de peso com mais frequência)
Neil Slater
Obrigado a ambos. Desculpas por teimosamente rejeitar mini lotes antes, mas eu não tinha certeza das implicações desse método na taxa de convergência. Neil, sua afirmação vem de sua própria experiência ou existem resultados publicados teóricos / empíricos?
precisa
11
@PabloSuau Você pode conferir a aula de Machine Learning de Andrew Ng no Coursera, semana 10, ele explica por que a convergência pode ser mais rápida que o SGD e o lote GD. Para ser mais preciso: deve ser sempre tão rápido quanto o SGD, mas às vezes deve ser ainda mais rápido na prática.
gaborous 7/08/16
1

Confira o método paragraph_fit do classificador SGD do scikit . Você tem controle sobre o que chama: com o aprendizado on-line "verdadeiro", passando uma instância de cada vez, ou pode agrupar instâncias em minilotes, se todos os seus dados estiverem disponíveis em uma matriz. Se estiverem, você pode dividir a matriz para fornecer os minibatches.

Ben Allison
fonte