Posit AI Weblog: Treinando imagenet com r



Posit AI Weblog: Treinando imagenet com r

Imagenet (Deng et al. 2009) é um banco de dados de imagem organizado de acordo com o WordNet (Miller 1995) Hierarquia que, historicamente, tem sido usada em benchmarks e pesquisas de visão computacional. No entanto, não foi até Alexnet (Krizhevsky, Sutskever e Hinton 2012) demonstraram a eficiência do aprendizado profundo usando redes neurais convolucionais nas GPUs de que a disciplina de visão de computador se transformou em um aprendizado profundo para alcançar modelos de ponta que revolucionavam seu campo. Dada a importância do ImageNet e AlexNet, este publish apresenta ferramentas e técnicas a serem consideradas ao treinar ImageNet e outros conjuntos de dados em larga escala com R.

Agora, para processar o imagenet, teremos que primeiro teremos que dividir e conquistarparticionando o conjunto de dados em vários subconjuntos gerenciáveis. Posteriormente, treinaremos o ImageNet usando o Alexnet em várias GPUs e calcular instâncias. Imagenet de pré -processamento e treinamento distribuído são os dois tópicos que este publish apresentará e discutirão, começando com o pré -processamento da imagem.

Imagenet de pré -processamento

Ao lidar com conjuntos de dados grandes, mesmo tarefas simples, como baixar ou ler um conjunto de dados, podem ser muito mais difíceis do que você esperaria. Por exemplo, como o ImageNet tem cerca de 300 GB de tamanho, você precisará ter pelo menos 600 GB de espaço livre para deixar espaço para obtain e descompressão. Mas não se preocupe, você sempre pode emprestar computadores com enormes unidades de disco do seu provedor de nuvem favorito. Enquanto você estiver nisso, você também deve solicitar instâncias de computação com várias GPUs, unidades de estado sólido (SSDs) e uma quantidade razoável de CPUs e memória. Se você quiser usar a configuração exata que usamos, dê uma olhada no mlverse/imagenet repo, que contém uma imagem do docker e comandos de configuração necessários para provisionar recursos de computação razoável para esta tarefa. Em resumo, verifique se você tem acesso a recursos de computação suficientes.

Agora que temos recursos capazes de trabalhar com o ImageNet, precisamos encontrar um lugar para baixar o ImageNet. A maneira mais fácil é usar uma variação de imagenet usada no Desafio de reconhecimento visible em larga escala ImageNet (ILSVRC)que contém um subconjunto de cerca de 250 GB de dados e pode ser facilmente baixado de muitos Kaggle competições, como o Desafio de localização de objetos ImageNet.

Se você leu algumas de nossas postagens anteriores, você já está pensando em usar o pinos Pacote, para o qual você pode usar: cache, descubra e compartilhe recursos de muitos serviços, incluindo Kaggle. Você pode aprender mais sobre a recuperação de dados de Kaggle no Usando placas Kaggle artigo; Enquanto isso, vamos supor que você já esteja familiarizado com este pacote.

Tudo o que precisamos fazer agora é registrar a placa Kaggle, recuperar o imagenet como um pino e descomprimir esse arquivo. Aviso, o código a seguir exige que você olhe para uma barra de progresso por, potencialmente, mais de uma hora.

library(pins)
board_register("kaggle", token = "kaggle.json")

pin_get("c/imagenet-object-localization-challenge", board = "kaggle")(1) %>%
  untar(exdir = "/localssd/imagenet/")

Se vamos treinar esse modelo repetidamente usando várias GPUs e até várias instâncias de computação, queremos ter certeza de que não perdemos muito tempo baixando o ImageNet todas as vezes.

A primeira melhoria a considerar é obter um disco rígido mais rápido. No nosso caso, montamos localmente uma variedade de SSDs no /localssd caminho. Nós então usamos /localssd Para extrair o ImageNet e configurar o caminho da temperatura e o cache de pinos de R para usar os SSDs também. Consulte a documentação do seu provedor de nuvem para configurar SSDs ou dê uma olhada mlverse/imagenet.

Em seguida, uma abordagem bem conhecida que podemos seguir é dividir o ImageNet em pedaços que podem ser baixados individualmente para executar o treinamento distribuído posteriormente.

Além disso, também é mais rápido baixar o ImageNet de um native próximo, idealmente de um URL armazenado no mesmo information heart em que nossa instância em nuvem está localizada. Para isso, também podemos usar pinos para registrar uma placa com nosso provedor de nuvem e depois re-applar cada partição. Como o ImageNet já é particionado por categoria, podemos facilmente dividir o ImageNet em vários arquivos ZIP e reaparecer ao nosso information heart mais próximo da seguinte forma. Verifique se o balde de armazenamento é criado na mesma região que suas instâncias de computação.

board_register("", identify = "imagenet", bucket = "r-imagenet")

train_path <- "/localssd/imagenet/ILSVRC/Knowledge/CLS-LOC/practice/"
for (path in dir(train_path, full.names = TRUE)) {
  dir(path, full.names = TRUE) %>%
    pin(identify = basename(path), board = "imagenet", zip = TRUE)
}

Agora podemos recuperar um subconjunto de imagenet com bastante eficiência. Se você estiver motivado para fazê -lo e tem cerca de um gigabyte de sobra, fique à vontade para seguir a execução deste código. Observe que o imagenet contém muito de imagens JPEG para cada categoria WordNet.

board_register("https://storage.googleapis.com/r-imagenet/", "imagenet")

classes <- pin_get("classes", board = "imagenet")
pin_get(classes$id(1), board = "imagenet", extract = TRUE) %>%
  tibble::as_tibble()
# A tibble: 1,300 x 1
   worth                                                           
                                                              
 1 /localssd/pins/storage/n01440764/n01440764_10026.JPEG
 2 /localssd/pins/storage/n01440764/n01440764_10027.JPEG
 3 /localssd/pins/storage/n01440764/n01440764_10029.JPEG
 4 /localssd/pins/storage/n01440764/n01440764_10040.JPEG
 5 /localssd/pins/storage/n01440764/n01440764_10042.JPEG
 6 /localssd/pins/storage/n01440764/n01440764_10043.JPEG
 7 /localssd/pins/storage/n01440764/n01440764_10048.JPEG
 8 /localssd/pins/storage/n01440764/n01440764_10066.JPEG
 9 /localssd/pins/storage/n01440764/n01440764_10074.JPEG
10 /localssd/pins/storage/n01440764/n01440764_1009.JPEG 
# … with 1,290 extra rows

Ao fazer treinamento distribuído no ImageNet, agora podemos deixar uma única instância de computação processar uma partição do ImageNet com facilidade. Digamos, 1/16 do imagenet pode ser recuperado e extraído, em menos de um minuto, usando downloads paralelos com o Callr pacote:

classes <- pin_get("classes", board = "imagenet")
classes <- classes$id(1:(size(classes$id) / 16))

procs <- lapply(classes, operate(cat)
  callr::r_bg(operate(cat) {
    library(pins)
    board_register("https://storage.googleapis.com/r-imagenet/", "imagenet")
    
    pin_get(cat, board = "imagenet", extract = TRUE)
  }, args = listing(cat))
)
  
whereas (any(sapply(procs, operate(p) p$is_alive()))) Sys.sleep(1)

Podemos encerrar essa partição em uma lista contendo um mapa de imagens e categorias, que mais tarde usaremos em nosso modelo Alexnet através tfdatasets.

information <- listing(
    picture = unlist(lapply(classes, operate(cat) {
        pin_get(cat, board = "imagenet", obtain = FALSE)
    })),
    class = unlist(lapply(classes, operate(cat) {
        rep(cat, size(pin_get(cat, board = "imagenet", obtain = FALSE)))
    })),
    classes = classes
)

Ótimo! Estamos no meio do caminho para treinar imagenet. A próxima seção se concentrará na introdução de treinamento distribuído usando várias GPUs.

Treinamento distribuído

Agora que quebramos o ImageNet em peças gerenciáveis, podemos esquecer um segundo sobre o tamanho do ImageNet e focar no treinamento de um modelo de aprendizado profundo para esse conjunto de dados. No entanto, qualquer modelo que escolhemos provavelmente exigirá uma GPU, mesmo para um subconjunto de 1/16 do ImageNet. Portanto, verifique se suas GPUs estão configuradas corretamente executando is_gpu_available(). Se você precisar de ajuda para configurar uma GPU, o Usando GPUs com Tensorflow e Docker O vídeo pode ajudá -lo a acelerar.

(1) TRUE

Agora podemos decidir qual modelo de aprendizado profundo seria melhor adequado para tarefas de classificação do ImageNet. Em vez disso, para este publish, voltaremos no tempo aos dias de glória de Alexnet e usaremos o R-TensorFlow/AlexNet repo. Este repo contém uma porta de Alexnet para R, mas observe que esta porta não foi testada e não está pronta para nenhum caso de uso actual. De fato, apreciaríamos o PRS para melhorá -lo se alguém se sentir inclinado a fazê -lo. Independentemente disso, o foco desta postagem está nos fluxos de trabalho e ferramentas, não sobre a obtenção de pontuações de classificação de imagem de última geração. Portanto, por todos os meios, sinta -se à vontade para usar modelos mais apropriados.

Depois de escolhermos um modelo, vamos querer garantir que ele treine corretamente em um subconjunto de imagenet:

remotes::install_github("r-tensorflow/alexnet")
alexnet::alexnet_train(information = information)
Epoch 1/2
 103/2269 (>...............) - ETA: 5:52 - loss: 72306.4531 - accuracy: 0.9748

Até agora tudo bem! No entanto, este publish é sobre o treinamento em larga escala em várias GPUs, por isso queremos garantir que estamos usando o máximo possível. Infelizmente, correndo nvidia-smi mostrará que apenas uma GPU está sendo usada atualmente:

+-----------------------------------------------------------------------------+
| NVIDIA-SMI 418.152.00   Driver Model: 418.152.00   CUDA Model: 10.1     |
|-------------------------------+----------------------+----------------------+
| GPU  Title        Persistence-M| Bus-Id        Disp.A | Unstable Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Utilization/Cap|         Reminiscence-Utilization | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla K80           Off  | 00000000:00:05.0 Off |                    0 |
| N/A   48C    P0    89W / 149W |  10935MiB / 11441MiB |     28%      Default |
+-------------------------------+----------------------+----------------------+
|   1  Tesla K80           Off  | 00000000:00:06.0 Off |                    0 |
| N/A   74C    P0    74W / 149W |     71MiB / 11441MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Reminiscence |
|  GPU       PID   Kind   Course of identify                             Utilization      |
|=============================================================================|
+-----------------------------------------------------------------------------+

Para treinar várias GPUs, precisamos definir uma estratégia de processamento distribuído. Se este é um novo conceito, pode ser um bom momento para dar uma olhada no Treinamento distribuído com Keras tutorial e o Treinamento distribuído com tensorflow documentos. Ou, se você nos permitir simplificar demais o processo, tudo o que você precisa fazer é definir e compilar seu modelo no escopo certo. Uma explicação passo a passo está disponível no Aprendizado profundo distribuído com tensorflow e r vídeo. Nesse caso, o alexnet modelo já suporta Um parâmetro de estratégia, então tudo o que precisamos fazer é transmiti -lo.

library(tensorflow)
technique <- tf$distribute$MirroredStrategy(
  cross_device_ops = tf$distribute$ReductionToOneDevice())

alexnet::alexnet_train(information = information, technique = technique, parallel = 6)

Observe também parallel = 6 que configura tfdatasets Para fazer uso de várias CPUs ao carregar dados em nossas GPUs, consulte Mapeamento paralelo Para detalhes.

Agora podemos voltar novamente nvidia-smi Para validar todas as nossas GPUs, estão sendo usadas:

+-----------------------------------------------------------------------------+
| NVIDIA-SMI 418.152.00   Driver Model: 418.152.00   CUDA Model: 10.1     |
|-------------------------------+----------------------+----------------------+
| GPU  Title        Persistence-M| Bus-Id        Disp.A | Unstable Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Utilization/Cap|         Reminiscence-Utilization | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla K80           Off  | 00000000:00:05.0 Off |                    0 |
| N/A   49C    P0    94W / 149W |  10936MiB / 11441MiB |     53%      Default |
+-------------------------------+----------------------+----------------------+
|   1  Tesla K80           Off  | 00000000:00:06.0 Off |                    0 |
| N/A   76C    P0   114W / 149W |  10936MiB / 11441MiB |     26%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Reminiscence |
|  GPU       PID   Kind   Course of identify                             Utilization      |
|=============================================================================|
+-----------------------------------------------------------------------------+

O MirroredStrategy pode nos ajudar a escalar até cerca de 8 GPUs por instância de computação; No entanto, é provável que precisemos de 16 instâncias com 8 GPUs cada para treinar Imagenet em um tempo razoável (consulte a postagem de Jeremy Howard no Treinando imagenet em 18 minutos). Então, para onde vamos daqui?

Bem -vindo a MultiWorkerMirroredStrategy: Essa estratégia pode usar não apenas várias GPUs, mas também várias GPUs em vários computadores. Para configurá -los, tudo o que precisamos fazer é definir um TF_CONFIG Variável de ambiente com os endereços corretos e execute exatamente o mesmo código em cada instância de computação.

library(tensorflow)

partition <- 0
Sys.setenv(TF_CONFIG = jsonlite::toJSON(listing(
    cluster = listing(
        employee = c("10.100.10.100:10090", "10.100.10.101:10090")
    ),
    activity = listing(sort = 'employee', index = partition)
), auto_unbox = TRUE))

technique <- tf$distribute$MultiWorkerMirroredStrategy(
  cross_device_ops = tf$distribute$ReductionToOneDevice())

alexnet::imagenet_partition(partition = partition) %>%
  alexnet::alexnet_train(technique = technique, parallel = 6)

Observe isso partition Deve mudar para cada instância de computação para identificá -la exclusiva e que os endereços IP também precisam ser ajustados. Além disso, information deve apontar para uma partição diferente do imagenet, com a qual podemos recuperar pins; Embora, por conveniência, alexnet contém código semelhante em alexnet::imagenet_partition(). Fora isso, o código que você precisa executar em cada instância de computação é exatamente o mesmo.

No entanto, se usássemos 16 máquinas com 8 GPUs cada para treinar o Imagenet, seria bastante demorado e propenso a erros para executar manualmente o código em cada sessão R. Então, em vez disso, devemos pensar em fazer uso de estruturas de computação em cluster, como o Apache Spark com execução da barreira. Se você é novo no Spark, há muitos recursos disponíveis em Sparklyr.ai. Para aprender a executar o Spark e o Tensorflow juntos, assista ao nosso Aprendizado profundo com faísca, tensorflow e r vídeo.

Juntando tudo, treinando ImageNet em r com tensorflow e faísca parece:

library(sparklyr)
sc <- spark_connect("yarn|mesos|and many others", config = listing("sparklyr.shell.num-executors" = 16))

sdf_len(sc, 16, repartition = 16) %>%
  spark_apply(operate(df, barrier) {
      library(tensorflow)

      Sys.setenv(TF_CONFIG = jsonlite::toJSON(listing(
        cluster = listing(
          employee = paste(
            gsub(":(0-9)+$", "", barrier$deal with),
            8000 + seq_along(barrier$deal with), sep = ":")),
        activity = listing(sort = 'employee', index = barrier$partition)
      ), auto_unbox = TRUE))
      
      if (is.null(tf_version())) install_tensorflow()
      
      technique <- tf$distribute$MultiWorkerMirroredStrategy()
    
      consequence <- alexnet::imagenet_partition(partition = barrier$partition) %>%
        alexnet::alexnet_train(technique = technique, epochs = 10, parallel = 6)
      
      consequence$metrics$accuracy
  }, barrier = TRUE, columns = c(accuracy = "numeric"))

Esperamos que este publish tenha dado a você uma visão geral razoável de como é o treinamento de grandes dados em R-obrigado por ler junto!

Deng, Jia, Wei Dong, Richard Socher, Li-Jia Li, Kai Li e Li Fei-Fei. 2009. “Imagenet: um banco de dados de imagem hierárquica em larga escala.” Em 2009 Conferência IEEE sobre visão computacional e reconhecimento de padrões248-55. IEEE.

Krizhevsky, Alex, Ilya Sutskever e Geoffrey E Hinton. 2012. “Classificação do ImageNet com profundas redes neurais convolucionais”. Em Avanços nos sistemas de processamento de informações neurais1097-1105.

Miller, George A. 1995. “WordNet: um banco de dados lexical para o inglês.” Comunicações do ACM 38 (11): 39–41.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *