Rescale에서 다중 GPU를 사용한 딥 러닝: Torch

모델병렬
데이터 병렬

성화봉
오늘 우리는 여러 GPU를 사용하여 단일 신경망을 훈련시키는 방법에 대해 논의할 것입니다. 토치 머신러닝 라이브러리. 이는 다중 GPU 및 다중 노드를 사용하도록 심층 신경망(DNN) 훈련 워크로드를 확장하는 기술에 대한 일련의 기사 중 첫 번째입니다.
이 시리즈에서는 단일 네트워크의 훈련을 병렬화하는 데 중점을 둘 것입니다. 구성 매개변수를 최적화하기 위해 여러 네트워크를 효율적으로 교육하는 당혹스러운 병렬 문제에 대한 자세한 내용은 다음을 참조하세요. 하이퍼 매개변수 최적화에 대한 이전 게시물.
토치 소개
Torch는 Lua 프로그래밍 언어를 기반으로 구축된 가볍고 유연한 텐서 라이브러리입니다. Torch는 기계 학습 연구자들에게 인기가 높기 때문에 많은 새로운 심층 신경망 아이디어가 Torch에서 처음 구현되어 오픈 소스 확장으로 제공됩니다. 따라서 딥 러닝의 최첨단 기능을 Torch에서 처음으로 사용할 수 있는 경우가 많습니다.
단점은 Torch 문서가 종종 구현에 뒤처진다는 것입니다. 따라서 정확히 수행하려는 작업에 대한 예제를 github에서 찾지 않는 한 어떤 Torch 모듈을 사용해야 하고 어떻게 사용하는지 파악하는 것이 어려울 수 있습니다.
이에 대한 한 가지 예는 Torch가 여러 GPU를 사용하여 신경망을 훈련하도록 하는 방법입니다. 인터넷에서 '멀티 GPU 토치'를 검색하면 나옵니다. 이 github 문제 최고의 결과 중 하나로. 이를 통해 우리는 토치 환경에서 둘 이상의 GPU에 액세스할 수 있다는 것을 알고 있습니다. 하지만 이 하위 수준 구성을 사용하여 복잡한 네트워크를 훈련하려면 어떻게 해야 할까요?
데이터 대 모델 병렬성
단일 신경망을 훈련하기 위해 작업을 병렬화할 때 작업을 분할하는 방법에 대해 모델 병렬성과 데이터 병렬성이라는 두 가지 선택 사항이 있습니다.

모델 병렬성을 사용하면 각 GPU는 주어진 데이터 배치에 대해 네트워크의 노드 덩어리를 실행합니다.

데이터 병렬성을 사용하면 각 GPU가 다양한 데이터 배치에 대해 전체 네트워크를 실행합니다.
이 차이점은 자세히 논의됩니다. 이 논문에서, 그러나 둘 중 하나를 사용하는 선택은 GPU 간에 필요한 동기화 종류에 영향을 미칩니다. 데이터 병렬 처리에는 모델 매개변수의 동기화가 필요하고, 모델 병렬 처리에는 청크 간의 입력 및 출력 값 동기화가 필요합니다.
간단한 토치 예제
이제 다음을 기반으로 컨볼루셔널 신경망을 훈련하는 간단한 예를 살펴보겠습니다. Torch 자체의 단위 테스트. 이 네트워크에는 2개의 컨볼루션 레이어와 2개의 정류기 레이어가 있습니다. 우리는 네트워크를 통해 간단한 정방향 및 역방향 전달을 수행합니다. 훈련을 위해 실제로 오류 기울기를 계산하는 대신 작업을 단순하게 유지하기 위해 이를 임의의 벡터로 설정했습니다.

'nn' 필요 모델 = nn.Sequential() 모델:add(nn.SpatialConvolution(3, 3, 3, 5)) 모델:add(nn.ReLU(true)) 모델:add(nn.SpatialConvolution(3, 3) , 3, 5)) 모델:add(nn.ReLU(true)) 입력 = torch.round(torch.Tensor(16, 3, 10, 10):uniform(0, 255)) 출력 = 모델:forward(입력 ) fakeGradients = 출력:clone():uniform(-0.1, 0.1) 모델:backward(input, fakeGradients)

이제 GPU에서 실행되도록 변환해 보겠습니다(이 예제는 CUDA 호환 GPU가 있는 경우에만 실행됩니다).

'cutorch' 필요 'cunn' 필요 cutorch.setDevice(1) model = nn.Sequential() model:add(nn.SpatialConvolution(3, 3, 3, 5)) model:add(nn.ReLU(true)) model :add(nn.SpatialConvolution(3, 3, 3, 5)) 모델:add(nn.ReLU(true)) 모델:cuda() 입력 = torch.round(torch.CudaTensor(16, 3, 10, 10) :uniform(0, 255)) 출력 = 모델:forward(input) fakeGradients = 출력:clone():uniform(-0.1, 0.1) 모델:backward(input, fakeGradients)

이를 GPU에서 실행하려면 다음을 호출합니다. 쿠다()네트워크에 연결한 다음 입력을 CudaTensor.
이제 2개의 GPU에 모델을 배포해 보겠습니다(모델 병렬 패러다임의 예). GPU 장치 ID를 반복하고 컷토치.위드디바이스 각 레이어를 특정 GPU에 배치합니다.

'cutorch' 필요 'cunn' 필요 cutorch.setDevice(1) model = nn.Sequential() for i=1, math.min(2, cutorch.getDeviceCount()) do cutorch.withDevice(i, function() 모델: add(nn.SpatialConvolution(3, 3, 3, 5)) end) cutorch.withDevice(i, function() 모델:add(nn.ReLU(true)) end) end 모델:cuda() 입력 = torch.round (torch.CudaTensor(16, 3, 10, 10):uniform(0, 255)) 출력 = 모델:forward(input) fakeGradients = 출력:clone():uniform(-0.1, 0.1) 모델:backward(input, 가짜그라디언트)
데이터병렬 가능

이는 각 GPU에 컨볼루셔널 레이어와 ReLU 레이어를 배치합니다. 정방향 및 역방향 패스는 GPU 1과 GPU 2 간에 출력을 전파해야 합니다.
다음으로 우리는 nn.DataParallelTable 여러 GPU에서 실행되는 전체 네트워크의 복사본에 데이터 배치를 배포합니다. DataParallelTable은 여러 컨테이너를 래핑하고 여기에 입력을 배포하는 Torch 컨테이너입니다.

'cutorch' 필요 'cunn' 필요 cutorch.setDevice(1) model = nn.Sequential() model:add(nn.SpatialConvolution(3, 3, 3, 5)) model:add(nn.ReLU(true)) model :add(nn.SpatialConvolution(3, 3, 3, 5)) 모델:add(nn.ReLU(true)) 모델:cuda() gpus = torch.range(1, cutorch.getDeviceCount()):totable() dpt = nn.DataParallelTable(1):add(model, gpus):cuda() 입력 = torch.round(torch.CudaTensor(16, 3, 10, 10):uniform(0, 255)) 출력 = dpt:forward (입력) fakeGradients = 출력:clone():uniform(-0.1, 0.1) dpt:backward(입력, fakeGradients)

따라서 원래 Sequential 컨테이너를 통해 정방향 및 역방향 패스를 실행하는 대신 이제 DataParallelTable 컨테이너에서 이를 실행하고 데이터는 각 GPU의 네트워크 복사본에 배포됩니다.
Rescale에 대한 작업은 다음과 같습니다. 위의 모든 코드를 사용하여 직접 복제하고 실행할 수 있습니다.
더 큰 예
이제 실제 DNN을 교육할 때 실제로 DataParallelTable을 사용하는 방법을 살펴보겠습니다. 우리는 Sergey Zagoruyko의 구현을 사용할 것입니다. CIFAR10의 넓은 잔여 네트워크 github에서.
In 기차.루아, 기본 신경망의 모든 병렬화가 도우미 함수에 의해 적용되는 것을 볼 수 있습니다.

모델:추가(utils.makeDataParallelTable(net, opt.nGPU))

탐구 makeDataParallelTable, 다음을 사용하여 위의 마지막 예와 유사한 구조를 볼 수 있습니다. nn.DataParallelTable:추가

함수 utils.makeDataParallelTable(model, nGPU) nGPU > 1이면 로컬 gpus = torch.range(1, nGPU):totable() 로컬 가장 빠르며 벤치마크 = cudnn.fastest, cudnn.benchmark 로컬 dpt = nn.DataParallelTable(1, true, true) :add(모델, gpus) :threads(function() local cudnn = 'cudnn' 필요 cudnn.fastest, cudnn.benchmark = 가장 빠른, 벤치마크 종료) dpt.gradInput = nil model = dpt:cuda() end 반품 모델 종료

이러한 작업을 복제하고 Rescale에서 직접 교육을 실행할 수 있습니다.

10개의 에포크 동안 훈련을 실행한 후 4개의 GPU 작업이 단일 GPU 작업보다 약 3.33배 빠르게 실행되는 것을 볼 수 있습니다. 꽤 괜찮은 스케일업!
이 기사에서는 Torch를 사용한 모델 및 데이터 병렬 DNN 교육 구현의 예를 제공했습니다. 향후 게시물에서는 다중 노드 확장뿐만 아니라 다른 신경망 라이브러리를 사용한 다중 GPU 훈련 사용법을 다룰 것입니다.

저자

  • 마크 휘트니

    Mark Whitney는 Rescale의 엔지니어링 이사입니다. 그의 전문 분야에는 고성능 컴퓨팅 아키텍처, 양자 정보 연구, 클라우드 컴퓨팅이 포함됩니다. 그는 캘리포니아 대학교 버클리 캠퍼스에서 컴퓨터 과학 박사 학위를 취득했습니다.

비슷한 게시물