Por que as GPUs são adequadas para o aprendizado profundo?
Como muitos já disseram, as GPUs são tão rápidas porque são tão eficientes para multiplicação e convolução de matrizes, mas ninguém deu uma explicação real para isso. A verdadeira razão para isso é a largura de banda de memória e não necessariamente o paralelismo.
Primeiro de tudo, você tem que entender que as CPUs são otimizadas para latência enquanto as GPUs são otimizadas para largura de banda. Você pode visualizar isso como uma CPU sendo uma Ferrari e uma GPU sendo um grande caminhão. A tarefa de ambos é pegar pacotes de uma localização aleatória A e transportar esses pacotes para outra localização aleatória B. A CPU (Ferrari) pode pegar algumas memórias (pacotes) na sua RAM rapidamente enquanto a GPU (grande caminhão) é mais lenta em fazer isso (latência muito maior). Entretanto, a CPU (Ferrari) precisa ir e voltar muitas vezes para fazer seu trabalho (local A $\rightarrow$ pegar 2 pacotes $\rightarrow$ local B ... repeat) enquanto a GPU pode pegar muito mais memória de uma vez (local A $\rightarrow$ pegar 100 pacotes $\rightarrow$ local B .... repeat).
Então, em outras palavras, a CPU é boa em buscar pequenas quantidades de memória rapidamente (5 * 3 * 7) enquanto a GPU é boa em buscar grandes quantidades de memória (multiplicação de Matrix: (A*B)*C). As melhores CPUs têm cerca de 50GB/s, enquanto as melhores GPUs têm 750GB/s de largura de banda de memória. Portanto, quanto mais memória suas operações computacionais exigirem, mais significativa será a vantagem das GPUs em relação às CPUs. Mas ainda há a latência que pode prejudicar a performance no caso da GPU. Um grande caminhão pode ser capaz de pegar muitos pacotes com cada tour, mas o problema é que você está esperando muito tempo até que o próximo conjunto de pacotes chegue. Sem resolver este problema, as GPUs seriam muito lentas mesmo para grandes quantidades de dados. Então como isso é resolvido?
Se você pedir a um grande caminhão para fazer muitas excursões para pegar os pacotes, você sempre esperará muito tempo pela próxima carga de pacotes uma vez que o caminhão tenha partido para fazer a próxima excursão - o caminhão está apenas lento. Entretanto, se você agora usa uma frota de Ferraris e caminhões grandes (paralelismo de linha), e você tem um trabalho grande com muitos pacotes (grandes pedaços de memória como matrizes) então você vai esperar um pouco pelo primeiro caminhão, mas depois disso você não terá tempo de espera - descarregar os pacotes leva tanto tempo que todos os caminhões vão fazer fila no local de descarga B para que você sempre tenha acesso direto aos seus pacotes (memória). Isto esconde eficazmente a latência para que as GPUs ofereçam alta largura de banda enquanto escondem sua latência sob o paralelismo de threads - assim, para grandes pedaços de GPUs de memória, as GPUs fornecem a melhor largura de banda de memória enquanto não têm quase nenhum inconveniente devido à latência via paralelismo de threads. Esta é a segunda razão pela qual as GPUs são mais rápidas do que as CPUs para um aprendizado profundo. Como nota lateral, você também verá porque mais threads não fazem sentido para as CPUs: Uma frota de Ferraris não tem benefício real em nenhum cenário.
Mas as vantagens para a GPU não terminam aqui. Este é o primeiro passo onde a memória é buscada da memória principal (RAM) para a memória local no chip (cache L1 e registros). Este segundo passo é menos crítico para a performance, mas ainda assim aumenta a vantagem para as GPUs. Todos os cálculos que são executados acontecem em registros que estão diretamente ligados à unidade de execução (um núcleo para CPUs, um processador de fluxo para GPUs). Normalmente, você tem a memória rápida L1 e de registro muito próxima ao mecanismo de execução, e você quer manter essas memórias pequenas para que o acesso seja rápido. O aumento da distância para o motor de execução reduz drasticamente a velocidade de acesso à memória, portanto, quanto maior a distância para acessá-la, mais lenta ela fica. Se você tornar sua memória cada vez maior, então, por sua vez, ela fica mais lenta para acessar sua memória (em média, encontrar o que você quer comprar em uma loja pequena é mais rápido do que encontrar o que você quer comprar em uma loja enorme, mesmo se você souber onde esse item está). Então o tamanho é limitado para arquivos de registro - estamos apenas nos limites da física aqui e cada nanômetro conta, queremos mantê-los pequenos.
A vantagem da GPU é que ela pode ter um pequeno pacote de registros para cada unidade de processamento (processador de fluxo, ou SM), dos quais ela tem muitos. Assim podemos ter no total muita memória de registro, que é muito pequena e, portanto, muito rápida. Isso faz com que o tamanho agregado dos registros da GPU seja mais de 30 vezes maior em relação às CPUs e ainda duas vezes mais rápido, o que se traduz em até 14MB de memória de registro que opera em 80TB/s. Como comparação, o cache L1 da CPU só opera a cerca de 5TB/s, que é bastante lento e tem o tamanho de aproximadamente 1MB; os registros da CPU normalmente têm tamanhos de cerca de 64-128KB e operam a 10-20TB/s. É claro que essa comparação de números é um pouco imperfeita porque os registros operam um pouco diferente dos registros da GPU (um pouco como maçãs e laranjas), mas a diferença de tamanho aqui é mais crucial do que a diferença de velocidade, e faz uma diferença.
Como nota lateral, a utilização total dos registros nas GPUs parece ser difícil de conseguir no início porque é a menor unidade de computação que precisa ser afinada manualmente para uma boa performance. No entanto, a NVIDIA desenvolveu ferramentas de compilação úteis que indicam quando você está usando muito ou muito poucos registros por processador de fluxo. É fácil ajustar o código da sua GPU para fazer uso da quantidade certa de registros e cache L1 para uma performance rápida. Isso dá às GPUs uma vantagem sobre outras arquiteturas como o Xeon Phis onde essa utilização é complicada e dolorosa para depuração, o que no final torna difícil maximizar a performance em um Xeon Phi.
O que isso significa, no final, é que você pode armazenar muitos dados em seus caches L1 e arquivos de registro em GPUs para reutilizar tiles de multiplicação convolucional e matricial. Por exemplo, os melhores algoritmos de multiplicação de matrizes usam 2 tiles de números 64x32 a 96x64 para 2 matrizes em cache L1, e um tile de registro de números 16x16 a 32x32 para as somas de saída por bloco de thread (1 bloco de thread = até 1024 threads; você tem 8 blocos de thread por processador de stream, há 60 processadores de stream no total para toda a GPU). Se você tiver uma matriz de 100MB, você pode dividi-la em matrizes menores que cabem no seu cache e registros, e então fazer multiplicação de matriz com três tiles de matriz a velocidades de 10-80TB/s - isso é rápido! Esta é a terceira razão pela qual as GPUs são muito mais rápidas que as CPUs, e porque elas são tão adequadas para o aprendizado profundo.
Cutem em mente que a memória mais lenta sempre domina os gargalos de performance. Se 95% dos seus movimentos de memória ocorrem em registros (80TB/s), e 5% em sua memória principal (0.75TB/s), então você ainda gasta a maior parte do tempo no acesso à memória principal (cerca de seis vezes mais).
Thus em ordem de importância: (1) memória principal de alta largura de banda, (2) ocultar a latência de acesso à memória sob paralelismo de threads, e (3) registro grande e rápido e memória L1 facilmente programável são os componentes que fazem com que as GPUs sejam tão bem adequadas para o aprendizado profundo.
Artigos semelhantes
- Qual é melhor, as GPUs AMD Radeon série RX 6000 ou as GPUs Nvidia série RTX 3000?
- Como construir um PC para jogos e para um aprendizado profundo
- Qual é o melhor laptop para se comprar em 2021 para um aprendizado profundo?
- Quais são alguns avanços recentes e potencialmente futuros no aprendizado profundo?