“Aprendizado semi-supervisionado” - isso é super adequado?

21

Eu estava lendo o relatório da solução vencedora de uma competição Kaggle ( Classificação de malware ). O relatório pode ser encontrado nesta postagem do fórum . O problema era um problema de classificação (nove classes, a métrica era a perda logarítmica) com 10.000 elementos no conjunto de trens e 10.000 elementos no conjunto de testes.

Durante a competição, os modelos foram avaliados contra 30% do conjunto de testes. Outro elemento importante é que os modelos tiveram um desempenho muito bom (precisão quase 100%)

Os autores usaram a seguinte técnica:

Outra técnica importante que surgimos é o aprendizado semissupervisionado. Primeiro, geramos pseudo-rótulos do conjunto de testes escolhendo a probabilidade máxima de nosso melhor modelo. Em seguida, prevemos o conjunto de testes novamente com validação cruzada, com dados de trem e dados de teste. Por exemplo, o conjunto de dados de teste é dividido em 4 partes A, B, C e D. Usamos todos os dados de treinamento e dados de teste A, B, C com seus pseudo rótulos, juntos como o novo conjunto de treinamento e prevemos o teste conjunto D.

O mesmo método é usado para prever A, B e C. Essa abordagem, inventada por Xiaozhou, funciona surpreendentemente bem e reduz a perda de validação cruzada local, a perda de LB pública e a perda de LB privada. O melhor modelo de aprendizado semissupervisionado pode atingir 0,0023 na perda de log LB privada, que é a melhor pontuação em todas as nossas soluções.

Realmente não vejo como isso pode melhorar os resultados. É porque 30% do conjunto de teste "vazou" e foi uma maneira de usar essas informações?

Ou existe alguma razão teórica para explicar por que funciona?

RUser4512
fonte

Respostas:

8

Não parece estar se adaptando demais. Intuitivamente, o ajuste excessivo implica treinamento nas peculiaridades (ruído) do conjunto de treinamento e, portanto, piora em um conjunto de teste independente que não compartilha essas peculiaridades. Se eu entendo o que aconteceu, eles não se saíram inesperadamente mal nos dados de teste retidos e, portanto, isso exclui empiricamente o sobreajuste. (Eles têm outro problema, que mencionarei no final, mas não é excessivamente adequado.)

Portanto, você está certo de que aproveita os dados de teste disponíveis (30%?). A questão é: como?

Se os dados de teste disponíveis tiverem rótulos associados, você poderá simplesmente agrupá-los nos dados de treinamento e aumentá-los, o que, em geral, produziria melhores resultados de maneira óbvia. Nenhuma realização real lá.

Observe que os rótulos não precisariam ser listados explicitamente se você tiver acesso a uma pontuação de precisão. Você pode simplesmente escalar o gradiente de precisão enviando repetidas pontuações, que é o que as pessoas fizeram no passado com competições mal projetadas.

Dado que os dados de teste disponíveis não possuem rótulos associados a ela - direta ou indiretamente -, há pelo menos duas outras possibilidades:

Primeiro, esse pode ser um método de aumento indireto, no qual você se concentra nos casos em que suas previsões apenas com os dados de treinamento discordam de suas previsões com os dados de teste pseudo-rotulados incluídos.

Segundo, poderia ser um aprendizado semi-supervisionado direto. Intuitivamente: você pode usar a densidade de dados não rotulados para ajudar a moldar os limites de classificação de um método supervisionado. Veja a ilustração ( https://en.wikipedia.org/wiki/Semi-supervised_learning#/media/File:Example_of_unlabeled_data_in_semisupervised_learning.png ) na definição de aprendizado semi-supervisionado da Wikipedia para esclarecer.

Mas isso não significa que não há um truque aqui. E esse truque vem da definição de dados de treinamento e teste. Em princípio, os dados de treinamento representam dados que você poderia ter em mãos quando estiver pronto para implantar seu modelo. E os dados de teste representam dados futuros que entrarão no seu sistema quando estiver operacional.

Nesse caso, o treinamento em dados de teste é um vazamento do futuro , onde você está aproveitando os dados que ainda não teria visto. Essa é uma questão importante no mundo real, onde algumas variáveis ​​podem não existir até depois do fato (digamos, após a conclusão de uma investigação) ou podem ser atualizadas posteriormente.

Portanto, eles são meta-jogos aqui: o que eles fizeram é legítimo dentro das regras da competição, porque receberam acesso a alguns dos dados de teste. Mas não é legítimo no mundo real, onde o verdadeiro teste é o quão bem ele se sai no futuro, com novos dados.

Wayne
fonte
2

Não, não é super adequado.

Acho que sua preocupação aqui é que o modelo esteja ouvindo os dados em vez de modelá-los. Isso depende da complexidade do modelo (que permaneceu o mesmo) e do tamanho dos dados. Isso acontece quando o modelo é muito complexo e / ou quando os dados de treinamento são muito pequenos, nenhum dos quais é o caso aqui. O fato de o erro de teste (erro de validação cruzada) ser minimizado após o aprendizado semi-supervisionado deve implicar que ele não esteja excessivamente ajustado.

Por que essa abordagem está funcionando?
A abordagem usada aqui não é fora do mundo. Vi muitas pessoas fazendo isso em muitas competições de aprendizado de máquina (desculpe, tentei, mas não consigo me lembrar de onde vi isso).
Quando você prevê uma parte dos dados de teste e os inclui no treinamento, o modelo será exposto a novos recursos. Nesse caso, os dados de teste são tão grandes quanto os dados de treinamento, não é de admirar que eles estejam ganhando muito com o aprendizado semi-supervisionado.

Espero que isso explique
Obrigado

Vihari Piratla
fonte
Você precisa definir "o modelo" claramente. É muito parecido com toda a questão dos Graus Generalizados de Liberdade ( pegasus.cc.ucf.edu/~lni/sta6236/Ye1998.pdf ), em que alguém aponta para o "modelo final", que parece ser simples, mas que na verdade tem muita complexidade incorporada ao processo. Meu instinto é que você não pode simplesmente ignorar o restante do processo e apontar para o "modelo final", afirmar que não é mais complexo que o "modelo final" sem a etapa semi-supervisionada e depois prosseguir. A melhoria dos resultados fora da amostra é um bom indicador, como você diz.
Wayne
2

Não é muito grosseiro (dependendo da definição). As informações de destino do conjunto de testes são preservadas. Semi-supervisionado permite gerar um conjunto de dados sintético extra para treinar o modelo. Na abordagem descrita, os dados originais do treinamento são misturados sem ponderação com os sintéticos na proporção 4: 3. Assim, se a qualidade dos dados sintéticos for ruim, a abordagem seria desastrosa. Acho que, para qualquer problema em que as previsões sejam incertas, o conjunto de dados sintéticos seria de baixa precisão. Se a estrutura subjacente é muito complexa e o sistema possui baixo ruído, isso pode ajudar a gerar dados sintéticos, eu acho. Eu acho que o aprendizado semi-supervisionado é muito grande no aprendizado profundo (não é meu conhecimento), onde a representação de recursos também deve ser aprendida.

Tentei reproduzir maior precisão com o treinamento semi-supervisionado em vários conjuntos de dados com rf e xgboost sem nenhum resultado positivo. [Sinta-se à vontade para editar meu código.] Percebo que a melhoria real da precisão usando semi-supervisionada é bastante modesta no relatório do kaggle, talvez aleatória?

rm(list=ls())
#define a data structure
fy2 = function(nobs=2000,nclass=9) sample(1:nclass-1,nobs,replace=T)
fX2 = function(y,noise=.05,twist=8,min.width=.7) {
  x1 = runif(length(y)) * twist
  helixStart = seq(0,2*pi,le=length(unique(y))+1)[-1]
  x2 = sin(helixStart[y+1]+x1)*(abs(x1)+min.width) + rnorm(length(y))*noise
  x3 = cos(helixStart[y+1]+x1)*(abs(x1)+min.width) + rnorm(length(y))*noise
  cbind(x1,x2,x3)
}

#define a wrapper to predict n-1 folds of test set and retrain and predict last fold  
smartTrainPred = function(model,trainX,trainy,testX,nfold=4,...) {
  obj = model(trainX,trainy,...)
  folds = split(sample(1:dim(trainX)[1]),1:nfold)
  predDF = do.call(rbind,lapply(folds, function(fold) {
    bigX      = rbind(trainX ,testX[-fold,])
    bigy      = c(trainy,predict(obj,testX[-fold,]))
    if(is.factor(trainy)) bigy=factor(bigy-1)
    bigModel  = model(bigX,bigy,...)
    predFold  = predict(bigModel,testX[fold,])
    data.frame(sampleID=fold, pred=predFold)
  }))
  smartPreds = predDF[sort(predDF$sampleID,ind=T)$ix,2]
}

library(xgboost)
library(randomForest)

#complex but perfect separatable
trainy = fy2(); trainX = fX2(trainy)
testy  = fy2();  testX = fX2(testy )
pairs(trainX,col=trainy+1)

insira a descrição da imagem aqui

#try with randomForest
rf = randomForest(trainX,factor(trainy))
normPred = predict(rf,testX)
cat("\n supervised rf", mean(testy!=normPred))
smartPred = smartTrainPred(randomForest,trainX,factor(trainy),testX,nfold=4)
cat("\n semi-supervised rf",mean(testy!=smartPred))

#try with xgboost
xgb = xgboost(trainX,trainy,
              nrounds=35,verbose=F,objective="multi:softmax",num_class=9)
normPred = predict(xgb,testX)
cat("\n supervised xgboost",mean(testy!=normPred))

smartPred = smartTrainPred(xgboost,trainX,trainy,testX,nfold=4,
                           nrounds=35,verbose=F,objective="multi:softmax",num_class=9)
cat("\n semi-supervised xgboost",mean(testy!=smartPred))



printing prediction error:
 supervised rf 0.007
 semi-supervised rf 0.0085
 supervised xgboost 0.046
 semi-supervised xgboost 0.049
Soren Havelund Welling
fonte
1

Por esta definição: "O ajuste excessivo ocorre quando um modelo estatístico descreve erro ou ruído aleatório em vez do relacionamento subjacente" (wikipedia), a solução não está ajustando demais.

Mas nesta situação:
- Os dados de teste são um fluxo de itens e não um conjunto fixo de itens.
OU
- O processo de previsão não deve conter a fase de aprendizado (por exemplo, devido a problemas de desempenho).

A solução mencionada é sobreajustada. Porque a precisão da modelagem é mais do que situações reais.

parvij
fonte