A história da mais completa coleção de truques para melhorar a GPU

prefácio

Primeiro, se você já está familiarizado com tf.data + estimador, você pode tirar o artigo x ╮ (¯ ▽ ¯ "") ╭

Mas! Se agora ou durante session.run (..) as palavras! Particularmente angustiado na memória GPU estão cheios, mas não aumentar a utilização de calçados infantis, este artigo pode ser capaz de dar-lhe abrir a porta para um mundo novo Oh (∇)

Se você achar que após uma série de maior eficiência melhorou muito após o treinamento, lembre-se de voltar para os pequenos envelopes noite (∇)

No entanto, este não é um monte de pasta de raiva a palavra de código (c) Jane (Introdução) Italiano (dois) Gai (idioma) no final de artigos de estilo CSDN. . . Então, chegar à parte que pode X fora ╮ (¯ ▽ ¯ "") ╭

origem

Em pouco tempo no início da noite, quando o pouco novo para tensorflow e uso de GPU acelerada computação, surgir uma dúvida sobre. Por que está quase cheio de memória gráfica, a utilização da GPU também mostrou tão baixo? Boa desperdiçá-la, mas eles não fazem nada. taxa de utilização GPU foi de 100% da situação de base, só é encontrada em um significativamente menores tarefas compotas 4,5 da memória não custa.

Em casos mais extremos, mesmo a taxa de utilização da GPU será reduzida para ou menos, 10% da seguinte forma:

 

v2-09e10589505de7a161415b60e365e83c_b.jpg

E depois de escrever o trem código na maioria dos casos é a seguinte:

 

v2-77c8ae3aa2b468d2682c62a26f063c3c_b.jpg

Pode ser visto, embora a memória gráfica são preenchidos, mas o poder gráfico (extrema esquerda da coluna, 114W e 69W) e utilização (coluna mais à direita do que, 35% e 38%) está longe de ser o limite. A maioria das pessoas pensam que bem Bem, não importa, eu experimentar adeus wei [Risos]

No entanto! Se você estiver fazendo experimento em grande escala, treinar alguns dias para executá-lo? Este detalhe irá afectar significativamente a eficiência de sua experiência e do número de experimentos antes da chegada DDL! Pense sobre exatamente o mesmo modelo e configurações, seu código deve treinar uma semana, mas no próximo necessidade porta só treinar três dias Faraó ╮ (¯ ▽ ¯ "") ╭

Transeunte: Eu tenho 256 cartões
pequeno noite: Bem, este artigo puder X fora

Bem, nós não poderia ter sido isso acontecer:

 

v2-fada8f09717f3847f8eae736eb0258e1_b.jpg

Não é parece incrível potência e eficiência! Não duvido que este é o PS Figura! Este é apenas um pequeno noite diária tiros! Bom uso de truques de utilização da GPU não cair 99%, e em seguida, escrever o ganso código bastante estúpido, você também pode ir até 5%!

Então a questão é, qual é a diferença no resultado final nele?

Não se preocupe, nós temos que olhar para aqueles gpu ampliar a utilização de apenas 30% das alterações no código em alguns dos a utilização gpu durante o treinamento (parece um pouco longa sentença

        watch -n 0.1 nvidia-smi
      

 

v2-06ddcf4a0187d75ce5dffbbbac13f6d2_b.gif
ps :( quadro pode cair muito sério incoerente procurando ╮ (¯ ▽ ¯ "") ╭, é recomendado para tentar em suas máquinas, será multi intuitiva ~)

Olhe! Você não está de repente encontrar de errado comigo? Você pode ver que, de fato, não é a utilização de GPU tem sido a um nível relativamente baixo, mas Rose periódica muito regular para quase 100 dos 0 0 depois caiu, em seguida, subiu novamente caiu outros 100 de volta a 0. Se ambos abertos para imprimir a janela de log, você vai achar que este ciclo é exatamente consistentes com cada etapa de treinamento é muito tempo! Em outras palavras, em cada etapa, na verdade, nós temos algum tempo e não passar a GPU, é claro, é que ele é gasto na CPU.

Que o cpu em fazê-lo? Claro, é a próxima carga de um lote, este pré-processamento em lote e pós-impressão ficar sem resultados log na GPU, pós-processamento, o resumo de gravação até salvar modelos, esta série de despesas tem que confiar em cpu para ser concluído. Nós muitas vezes olhar para o código lê:

        create_graph()
create_model_saver()
create_summary_writer()
create_session()
do_init()
for i in range(num_train_steps):
    load_batch(...)                # cpu
    preprocess(...)                # cpu
    feed_dict = {...}              # cpu
    fetch_list = [...]             # cpu
    buf = session.run(fetch_list, feed_dict)    # gpu
    postprocess(buf)               # cpu
    print(...)                     # cpu
    if i % x == 0:
        summary_writer.write(...)  # cpu
    if i % xx == 0:
        model_saver.save(...)      # cpu
      

Olhar, especialmente preprocess (...) a tarefa é pesada, então é fácil de fazer com que o código na CPU também foi executado por algum tempo, a utilização da GPU irá, naturalmente, ir para cima e mudança cíclica-lo.

Existe alguma maneira de reduzir o tempo de CPU, melhorar o tempo de GPU?

Um muito auto (estúpido), então (estúpido) idéia é treinar todos os códigos reescrita não usar api tf mil milhões, e até mesmo a camada mais externa que for i in range(num_train_steps)realmente pode ser usado tf.while_loop reescrevê-lo. Ah, muito pequeno à noite, então eu tentei, e depois encontrado

 

v2-bde01235526089755e5a6895b1db83ec_b.jpg

TF api Este miado especial é o fantasma! python Numpy com uma variedade de funções internas e comportamento inconsistente com o mesmo nome mas que diabos! FML api menos este argumento como eu posso fazer? uma linha de código em python para ser capaz de conseguir as coisas porque eu escrevi algumas linhas? ?

 

v2-b347580774f2421578d25b1429cacbd4_b.jpg

Assim, além de programação funcional Daniel, pequeno noite fortemente não recomendado para repetir os mesmos erros! Especialmente aqueles de nós encontrar compilação grito, depois de ver 90 Lisp fadas acidente!

Portanto, não há maneira de descrever todo o ciclo de trem para o cálculo do mapa?

Não tenha medo, não tenha medo, boa notícia foi no pacote fato tensorflow tem um particularmente bom (e mais) com (pit) API para todo o ciclo de trem superior pode ser facilmente encapsulado no cálculo da figura, a fim de alcançar super-alta utilização e GPU eficiência do treinamento!

Estimador

Por que não ignorá-lo chamado Estimador, só precisa saber que nós só queremos fazer o básico deu um bom pacote na linha. A redacção deste clássico apenas passar

        1. create_model()
2. create_model_saver()
3. create_summary_writer()
4. create_session()
5. do_init()
6. for i in range(num_train_steps):
7.      load_batch(...)                # cpu
8.      preprocess(...)                # cpu
9.      feed_dict = {...}              # cpu
10.     fetch_list = [...]             # cpu
11.     buf = session.run(fetch_list, feed_dict)    # gpu
12.     postprocess(buf)               # cpu
13.     print(...)                     # cpu
14.     if i % x == 0:
15.         summary_writer.write(...)  # cpu
16.     if i % xx == 0:
17.         model_saver.save(...)      # cpu
      

1-5 são embalados estimador linha Bem, você acabou de colocar na configuração do estimador pode ser amigos ~ RunConfig

7-9 linha pacote também Bem, você só precisa carregar o código e o conjunto de dados associados em função do pré-tratamento do ~ sobrepor input_fn estimator.train

Linha 10 também encapsula Bem, você só precisa buscar a perda, train_op jogado EstimatorSpec estimador de ~

Linha 11 também encapsula Bem, você só precisa descrever o modelo de cálculo de sobreposição estimador da FIG model_fn ~

12-13 linhas não se preocupe sobre os detalhes, global_step e perda automaticamente, eo resto - jogou tf.Print e LoggingTensorHook

14-17 que você não escreve uma linha, a completa auto-

╮ (╯ ▽ ╰) ╭

Depois de uma refeição lance, descobrimos que ele melhora muito a utilização de GPU - quase igual a 80% ou mesmo 90%. Portanto, não há espaço para a imprensa é?

Na verdade, quando uma análise cuidadosa irá achar que, embora a maior parte do código escrito para o estimador para calcular Ituri, mas ainda é carregado e pré-processamento de dados da CPU, onde série conduta Sim, mas existe um tal lote de 128 amostras , então o estimaor interno executar cada etapa de tempo ou a esperar para as amostras de série 128 de trabalho processado. Isto, obviamente, é o último gargalo isso! Não há nenhuma maneira de eliminá-lo? · Claro, isso é

tf.data

TF conjunto de dados API pode ser dito de pessoas gostam de ódio, e ele não aparecer para fornecer um caminho para todo o quadro de pré-calculadas são movidos processamento paralelo, mas! Se você API realmente inteiramente tensorflow para fazer o pré-tratamento complexo, realmente vai fazer as pessoas loucas QAQ Então aqui antes com tf.data, pequeno noite fortemente recomendado como o primeiro conjunto de dados em um pré-transform olhar processados, incluindo fazendo palavra, não cortada, e assim fazer word2id, mas estofamento e input_mask pode ficar no TF que não , afinal, só precisa de uma linha.

Que após isso é feito o pré-processamento, armazenamento de dados como isso seria mais conveniente de leitura e acordo posterior com ele? De longe a forma mais recomendada é a utilização tf.recordsde armazenamento, disco, memória, IO e eficiência de armazenamento será mais rápido em comparação com os métodos tradicionais, x e y não se separam. Naturalmente, esta única desvantagem não é diretamente olhar aberto no conjunto de dados ╮ (¯ ▽ ¯ "") ╭ Afinal, o conjunto de dados foi feita em um arquivo binário.

Mas realmente não quer tf.record preguiçoso, então pequena noite é altamente recomendado que o x e y armazenados separadamente , e tentar fazer os acabamento tf.data necessário acima de dados pré-ler, quando para evitar difícil de uso corda API ea pressão operacional subjacente para reduzir a formação de CPU e memória.

tf.data há uma grande vantagem que podemos apoiar de uma forma muito natural para ler streaming de dados , esses dados não irá ocorrer em face de grandes conjuntos de dados após os gráficos de carga descoberta ocupada constrangimento de ╮ ( ¯ ▽ ¯ "") ╭

Como se estivesse falando por tanto tempo, não disse como ou com tf.data acelerar QAQ, Venha para o assunto.

Pense do Cazaquistão, tf.data inútil, podemos escrever o código realmente correr até é parecido com isto:

 

v2-1cc7ed94295fe3bb8ef66fb01a95233d_b.jpg

Este é também o início do pequeno noite artigo para explicar por que razões importantes não pode ir para cima e periodicamente alterar a utilização de GPU. Portanto, não podemos eliminar ocioso, assim tornar o processo de paralelo preparar e treiná-lo?

 

v2-989015918c2fa02d6d8e244fa81c6bf6_b.jpg

Claro que você pode! Isso é

pré-busca

Ele pode ser entendido a partir dos meios de pré-busca que PREFETCH o próximo passo de carregar o lote. Use tf.data que é chamado de pré-busca api mágico pode facilmente concluir que, este é o lugar onde a api argumento buffer_size está falando é quantas buscar adicionais, como buffer_size = 1, então temos de pré-busca de um lote, em seguida, cada modelo preparar um lote após tempos de conclusão e, em seguida, ele irá preparar automaticamente um lote de adicional, de modo a etapa de trem em seguida vem diretamente da memória pode ser removido nesta pré-preparar um amigos bom lote. (Para detalhes, ver mais adiante)

Espere, desenho palavras bonitas, não há madeira lá descobriram que, se um lote preparar muito curto demorado se de fato dois mundos, mas se você levou bastante tempo, especialmente uma vez que vários lote de pré-busca, então, uma vez que se preparar com mais de quando um trem com um passo, o desempenho de cada etapa no trem será limitado à eficiência prepará-lo. Se esta questão é ampliado como mostrado na FIG.

 

v2-807c180534fa39d9b4d8eccfc0aff9ab_b.jpg

Olhar, preparar por muito tempo quando usá-lo vai levar para o comboio completou um ocioso passo gpu para (embora, de facto, o próximo passo no lote já pode se preparar bem)

Não podemos garantir que o palco é menor do que o trem, quando a fase de preparação com o uso dele?

mapeamento paralelo

Uma ideia muito simples, claro, é para fazer amigos - se o tamanho de processamento em lote paralelo amostra é de 128, o tamanho de pré-busca = 1, em seguida, preparar um lote de série pré-tratamento run 128 * 2 = 256 vezes, mas se abrirmos quatro threads a prazo, não é rápido olhar muito mais atraente. Felizmente, não temos a soprar suas próprias mãos multithreading, tf.data.Dataset há um mapa parâmetro (pré-tratamento), em função num_parallel_calls, pode ser atribuído a este parâmetro paralelo analisá-lo. Como mostrado,

 

v2-2c2df2a40a1a57081d84314e1acc41f1_b.jpg

Então, enquanto BUFFER_SIZE e mapear a pré-busca de num_parrellel_calls obter adequado , basicamente trem ininterrupta pode alcançá-lo, o que é quase 100% de utilização da GPU!

Bem, eu pensei que para entender o código é fácil de entender. Não tf.record usado, decorre directamente do procedimento quando a conjuntos típicos texto simples carregamento de dados de dados pré-tratados

        def build_input(..):
    x = tf.data.XXDataset(..)
    x = x.map(..., num_parallel_calls=N)        # parellel

    y = tf.data.XXDataset(..)
    y = y.map(..., num_parallel_calls=N)

    dataset = tf.data.Dataset.zip((x, y))
    dataset = dataset.repeat(num_epochs)    
    if is_train:
        dataset = dataset.shuffle(..)
    dataset = dataset.batch(batch_size)
    dataset = dataset.prefetch(buffer_size=1)   # prefetch
    iterator = dataset.make_xx_iterator()
    return iterator.get_next()
      

Claro, se o uso de tf.recordapós, respectivamente, não ler dados de um arquivo em amigos ambos X e Y, interessados em calçados infantis pode ter que ir descobrir.

benefícios complementares

Naturalmente, apenas a migração de código tradicional para tf.data + estimador, ele pode não se adaptar, a coisa mais importante no modo de depuração, como session.run direto (debug_tensor), então como não fazer assim antes?

Em geral tensor nós impressão, existem dois casos, um é a necessidade de imprimir uma ou várias vezes para localizar o problema ao calcular o mapa errado, é como global_step, perda, etc necessidade de verificação periódica. Em ambos os casos, antes da session.run hábito quando você quiser imprimir o tensor também correr para fora, e agora esses dois casos podem ser distinguidos tratá-la.

Para o primeiro pequeno noite, sentir o mais eficiente ou conectado diretamente tf.Print (..), de fácil utilização, capacidade de depuração é muito poderoso no cálculo do Ituri! Se você precisa imprimir com a etapa global, além de um tf.cond para obtê-lo. Para o segundo depois, de fato, o passo global, em seguida, estimador de default e perda será impresso, se outro tensor requerem impressão periódica, em seguida, usar tf.train.LoggingTensorHook-embalados e depois jogado no hábito de realmente estimator.train nele ~ ainda sinto m muito conveniente (_ _ ) m

Finalmente, o mundo não está disposto a gráficos livres

Publicado 33 artigos originais · ganhou elogios 0 · Vistas 3284

Acho que você gosta

Origin blog.csdn.net/xixiaoyaoww/article/details/104553499
Recomendado
Clasificación