머신러닝에 대한 책을 5권에서 6권정도 읽고 있는데 잘 이해가 안되는 부분이 참 많습니다. 그래서 내용을 필사하면서 직접 코드를 입력하면서 반복해서 보고 있습니다. 작년에 보았던 내용들 보다 더 많이 이해가 되고 점점 쉽게 느껴지는 부분도 생기네요. ^^
아래와 같은 순서로 책을 보시면됩니다. 파이썬 언어를 공부해야 합니다. => 판다스를 사용할 수 있어야 합니다. => 머신러닝, 딥러닝을 공부할 수 있습니다. 제가 정리한 글에 있습니다. 이런 순서로 공부하고 선형대수나 미분에 대한 내용을 개발자를 위한 수학책으로 따로 정리하면 될 것 같습니다. 좌절과 희열을 반복하면서 보고 있는데 점점 좌절보다는 희망을 보고 있습니다. 기계학습과 강화 학습을 공부하시는 모든 분들 화이팅입니다. ~~~~
https://steemit.com/kr/@papasmf1/73cj22
핸즈온 머신러닝 책의 소스는 아래의 깃허브에 있습니다. 참고하실 수 있습니다.
https://github.com/rickiepark/handson-ml
제가 테스트하고 실습하는 환경은 맥에 아나콘다 최근 패키지를 설치해서 주피터랩으로 실행하고 있습니다. 아나콘다 패키지를 사용하는 경우에 텐서플로는 쉽게 설치할 수 있습니다. ^^
12장부터는 많이 어렵네요. 맥이 별도의 그래픽칩을 가지고 있지 않아서 테스트가 안되네요. 스크립트만 돌려보고 정리해 보았습니다.
12장 다중 머선과 장치를 위한 분산 텐서플로 입니다. ^^
앞 장에서는 더 나은 가중치 초기화, 배치 정규화, 정교한 옵티마이저 등 훈련 속도를 높일 수 있는 여러 기술을 살펴봤습니다. 그러나 이런 기법들을 모두 사용하더라도 대규모 신경망을 CPU가 하나인 컴퓨터 한 대에서 훈련시키려면 며칠 혹은 몇 주가 걸릴 수 있습니다.
이 장에서는 텐서플로를 사용해 연산을 여러 개의 장치에 분산시켜서 병렬로 실행시키는 방법을 알아보겠습니다.
텐서플로의 분산 컴퓨팅 기능은 다른 신경망 프레임워크와 비교되는 주요한 장점입니다. 계산 그래프를 여러 장치와 머신에 어떻게 분할(또는 복제)시킬지 완전히 제어할 수 있고 연산을 다양한 방식으로 병렬화하고 동기화할 수 있어서 모든 종류의 병렬화 방식이 사용될 수 있습니다.
12.1 단일 머신의 다중 장치
한 대의 머신으로 간단하게 성능을 올릴 수 있는 방법은 GPU카드를 추가하는 것입니다. 사실 많은 경우에 이것으로 충분합니다. 즉, 여러 대의 컴퓨터를 사용할 필요가 전혀 없습니다. 예를 들어 어떤 신경망을 훈련시키는 데 여러 대의 컴퓨터로 나뉜 16개의 GPU보다 한 대의 컴퓨터에 설치된 8개의 GPU를 사용하는 편이 더 빠를 수 있습니다(다중 머신 환경에서 네트워크 통신으로 발생되는 지연이 더해지기 때문).
12.1.1 설치
텐서플로를 여러 개의 GPU카드에서 실행하기 위해서는 설치된 GPU카드가 엔비디아 계산능력을 가지고 있는지 확인해야 합니다.
GPU카드가 없다면 아마존 AWS 같이 GPU를 제공하는 호스팅 서비스를 사용할 수 있습니다. 또한 구글이 텐서플로 그래프를 실행시킬 수 있는 클라우드 머신러닝(https://cloud.google.com/ml)서비스를 시작했습니다. 2016년 5월에는 머신러닝에 최적화되어 있어서 많은 머신러닝 작업에서 범용 GPU보다 훨씬 빠른 프로세서인 텐서 프로세싱 유닛을 장착한 머신이 클라우드에 포함되었다고 발표했습니다.
엔비디아의 CUDA Compute Unified Device Architecture라이브러리를 사용하면 CUDA지원 GPU카드에서 (그래픽 가속뿐만 아니라) 어떤 계산도 수행할 수 있습니다. 엔비디아의 cuDNN CUDA Depp Neural Network라이브러리는 DNN을 위한 기초적인 GPU 가속 라이브러리입니다.
적절한 버전의 GPU용 텐서플로를 설치합니다.
pip3 install –upgrade tensorflow-gpu
12.1.2 GPU RAM관리
기본적으로 텐서플로는 계산 그래프가 처음 실행될 때 가용한 모든 GPU의 RAM을 자동으로 확보합니다.
12.1.3 장치에 연산 배치하기
텐서플로 백서에는 가용한 모든 장치에 연산을 완전히 자동으로 분산하는 동적 배치자 알고리즘이 소개되어 있습니다. 이 알고리즘에는 이전에 실행한 그래프의 계산 시간, 각 연산의 입출력 텐서 크기 추정, 장치마다 가용한 RAM용량, 장치에 데이터를 입출력할 때 발생하는 통신 지연, 사용자가 지정한 힌트나 제약사항 등이 고려됩니다.
단순 배치
계산 그래프를 실행할 때 텐서플로가 아직 디바이스에 배치되지 않은 노드를 평가해야 한다면 다른 노드들과 마찬가지로 배치를 위해 단순 배치자를 사용합니다.
동적 배치 함수
장치 블록을 생성할 때 장치 이름 대신 함수를 지정할 수 있습니다. 텐서플로는 장치 블록 안에서 배치가 필요한 모든 연산에 대해 이 함수를 호출합니다.
연산과 커널
텐서플로 연산을 장치에서 실행하려면 그 장치에 맞는 구현이 있어야 합니다. 이를 커널이라고 부릅니다.
간접 배치
기본적으로 커널이 없는 장치에 연산을 할당하면 텐서플로가 그 장치에 연산을 배치할 때 앞서 본 것처럼 에러를 발생시킵니다. 에러를 발생시키는 대신 텐서플로가 CPU를 사용하도록 하려면 Allow_soft_placement환경 설정을 True로 지정합니다.
12.1.4 병렬 실행
텐서플로는 계산 그래프를 실행할 때 먼저 평가해야 할 연산을 찾고, 각 연산이 다른 연산에 얼마나 많이 의존하는지 카운트합니다. 그런 다음 의존성이 전혀 없는 노드(즉, 소스 노드)를 연산이 할당된 장치의 평가 큐에 추가합니다.
CPU의 평가 큐에 있는 연산은 inter-op스레드 풀로 보내집니다. CPU가 여러 개의 코어를 사용한다면 이 연산들은 병렬화되어 효율적으로 평가될 것입니다.
GPU의 경우는 좀 더 단순합니다. GPU의 평가 큐에 있는 연산은 그냥 순서대로 평가됩니다. 그러나 많은 연산이 텐서플로가 사용하는 CUDA와 cuDNN같은 라이브러리로 구현된 멀티스레드 GPU커널을 가지고 있습니다. 이런 구현은 자체 스레드 풀을 가지고 있고 가능한 한 많은 GPU쓰레드를 활용합니다.
12.1.5 제어 의존성
어떤 경우에는 의존하는 모든 연산이 실행되었음에도 불구하고 연산의 평가를 미루는 것이 나을 때도 있습니다. 예를 들어 메모리를 많이 사용하는 연산이지만 그 값이 그래프의 후반에서야 필요하다면, 다른 연산에 필요한 메모리를 불필요하게 점유하는 것을 피하기 위해 마지막 순간에 평가하는 것이 최선입니다.
12.2 다중 머신의 다중 장치
여러 대의 머신에서 그래프를 실행하려면 먼저 클러스터를 정의해야 합니다. 클러스터는 태스크라고 하는 하나 이상의 텐서플로 서버로 구성되며 보통 여러 대의 머신에 나뉘어 있습니다. 각 태스크는 하나의 잡에 속해 있습니다. 하나의 잡은 그냥 이름이 부여된 태스크의 그룹이며 모델 파라미터를 저장하거나(이런 잡을 일반적으로 파라미터 서버를 나타내는 “ps”라고 이름 붙입니다) 계산을 수행하는(이런 잡을 일반적으로 “worker”라고 이름을 붙입니다) 공통된 역할을 가집니다.
다음의 클러스터 명세는 각각 한 개와 두 개의 태스크를 가지는 잡 “ps”와 “worker”를 정의합니다. 이 예제에서 머신 A는 두 개의 텐서플로 서버(즉, 태스크)를 다른 포트로 서비스하고 있습니다. 하나는 “ps”잡이고 다른 하나는 “worker”잡의 일부분입니다. 머신 B는 하나의 텐서플로 서버에서 “worker”잡의 일부분을 서비스하고 있습니다.
12.2.1 세션 열기
모든 태스크가 시작되면(아직은 아무것도 안 하지만) 어떤 머신의 프로세스에 있는 클라이언트에서도(심지어 태스크를 실행 중인 프로세스에서도) 다른 모든 서버에 대해 세션을 열 수 있습니다. 그리고 이 세션은 보통의 로컬 세션처럼 사용할 수 있습니다.
12.2.2마스터와 워커 서비스
클라이언트는 gRPC프로토콜(구글 원격 프로시져 호출)을 사용하여 서버와 통신합니다. 이 프로토콜은 다양한 플랫폼과 언어에서 원격 함수를 호출하고 그 출력을 받는 데 효율적인 오픈소스 프레임워크입니다.
모든 텐서플로 서버는 마스터 서비스와 워커 서비스 두 개의 서비스를 제공합니다. 마스터 서비스는 클라이언트가 세션을 열고 그래프를 실행할 수 있게 도와줍니다. 여러 태스크의 계산을 조율하고 워커 서비스를 통해 실제로 로컬 장치에서 계산을 실행하고 결과를 받습니다.
12.2.3 여러 태스크에 연산 할당하기
장치 블록을 사용하여 어떤 태스크에서 관리하는 장치에 잡 이름, 태스크 번호, 장치 유형, 장치 번호를 지정하여 연산을 할당할 수 있습니다.
12.2.4 여러 대의 파라미터 서버에 변수를 나누어 분산하기
잠시 후에 보겠지만 분산 환경에서 신경망을 훈련시킬 때 일반적인 패턴은 모델 파라미터를 일련의 파라미터 서버(즉, “ps”잡에 있는 태스크)에 저장하는 것입니다. 반면 다른 태스크(즉, “worker”잡에 있는 태스크)는 연산에 집중합니다. 수백만 개의 파라미터가 있는 대규모 모델의 경우, 파라미터 서버 한 대의 네트워크 카드가 포화되는 것을 피하기 위해 파라미터들을 여러 대의 파라미터 서버에 나누는 것이 좋습니다.
다행히 텐서플로는 모든 “ps”태스크에 라운드 로빈 방식으로 변수들을 분산시켜주는 replica_device_setter()함수를 제공합니다.
12.2.5 리소스 컨테이너를 사용해 여러 세션에서 상태 공유하기
평범한(분산 환경이 아닌) 로켈 세션을 사용할 때 각 변수의 상태는 세션 자체에서 관리합니다. 세션이 종료되면 모든 변수가 사라집니다. 더군다나 여러 개의 로컬 세션은 같은 그래프를 실행하더라도 어떤 상태로 공유할 수 없습니다. 즉, 각 세션은 각자 자신만의 변수에 대한 사본을 가집니다. 반대로 분산 세션을 사용할 때는 변수의 상태가 세션이 아니라 클러스터 자체에 있는 리소스 컨테이너에 의해 관리됩니다.
리소스 컨테이너는 큐나 리더같이 상태를 갖는 연산의 상태값을 유지하기도 합니다. 먼저 큐를 살펴보죠.
12.2.6 텐서플로 큐를 사용한 비동기 통신
큐는 여러 세션 사이에 데이터를 교환하기 위한 아주 좋은 또 다른 방법입니다. 예를 들어 한 클라이언트는 훈련 데이터를 로드하여 큐에 저장하는 그래프를 만들고, 다른 클라이언트는 큐에서 데이터를 추출하여 모델을 훈련시키는 그래프를 만드는 것입니다. 이렇게 하면 훈련 연산이 매 스텝마다 다음번 미니배치를 기다리지 않아도 되기 때문에 훈련 속도가 상당히 빨라집니다.
12.3 텐서플로 클러스터에서 신경망 병렬화하기
이 절에서는 먼저 여러 개의 신경망을 각기 다른 장치에 할당해 병렬화하는 간단한 방법을 살펴보겠습니다.
12.3.1 장치마다 하나의 신경망
텐서플로 클러스터에서 신경망을 훈련하고 실행시키는 가장 간단한 방법은 하나의 머신에 있는 하나의 장치를 사용하는 것과 똑같은 방식으로 코드를 작성하는 것입니다. 그러고 나서 세션을 만들 때 마스터 서버의 주소를 지정합니다. 이것이 전부입니다! 코드는 서버의 기본 장치에서 실행될 것입니다.
12.3.2 그래프 내 복제와 그래프 간 복제
여러 신경망을 다른 장치에 배치하여 신경망의 댁퓨모 앙상블 훈련을 쉽게 병렬화할 수 도 있습니다. 그러나 앙상블을 실행할 때는 각 신경망이 만든 개개의 예측을 모아서 앙상블의 예측을 만들어야 합니다.
12.3.3 모델 병렬화
지금까지는 하나의 장치에서 하나의 신경망을 실행했습니다. 하나의 신경망을 여러 개의 장치에서 실행하려면 어떻게 해야 할까요? 그렇게 하려면 모델을 여러 부분으로 나누어 각 부분을 다른 장치에서 실행시켜야 합니다. 이를 모델 병렬화라고 합니다.
또한 14장에서 보게 될 심층 순환 신경망 deep recurrent neural network(deep RNN)은 메모리 셀의 층으로 이루어져 있습니다. 시간 t에서 한 셀의 출력은 시간 t + 1의 입력으로 재사용됩니다.
12.3.4 데이터 병렬화
신경망의 훈련을 병렬화하는 또 다른 방법은 각 장치에 모델을 복제해서 각각 다른 미니배치를 사용해 모든 모델이 동시에 훈련 스텝을 실행하고 그래디언트를 취합하여 모델 파라미터를 업데이트하는 것입니다. 이를 데이터 병렬화라고 합니다.
이 방식에는 동기 업데이트와 비동기 업데이트 두 부류가 있습니다.