• 텐서플로우 GPU병렬성

    2019. 2. 20. 20:23

    by. 위지원

    전체 코드는 https://github.com/tensorflow/tensorflow/blob/r0.7/tensorflow/models/image/cifar10/cifar10_multi_gpu_train.py


    텐서 플로우의 병렬성은

    - 모델 병렬성 : 주요 원칙은 모델 중의 다른 계산 노드를 서로 다른 하드웨어 리소스에 배치하여 연산

    - 데이터 병렬성 : 대규모 병렬 처리를 구현하기 위해 일반적으로 사용한다.

    으로 구분된다.


    아래의 명령어로 데이터를 미리 준비해두자.


    $ git clone https://github.com/tensorflow/models.git


    다운 받은 폴더에  models/tutorials/image/cifar10에 가면 cifar10_multi_gpu_train.py라는 파일이 있다. 이 파일을 실행 시켜주면 된다!


    (tensorEnv) weejiwon@weeserver:~/tensorEnv/exampleCode/models/tutorials/image/cifar10$ ls
    BUILD             cifar10_input_test.py       cifar10_train.py
    cifar10_eval.py   cifar10_multi_gpu_train.py  __init__.py
    cifar10_input.py  cifar10.py                  README.md
    (tensorEnv) weejiwon@weeserver:~/tensorEnv/exampleCode/models/tutorials/image/cifar10$ vi cifar10_multi_gpu_train.py
    (tensorEnv) weejiwon@weeserver:~/tensorEnv/exampleCode/models/tutorials/image/cifar10$ python3 cifar10_multi_gpu_train.py
    >> Downloading cifar-10-binary.tar.gz 100.0%
    Successfully downloaded cifar-10-binary.tar.gz 170052171 bytes.


    그럼 아래와 같이...훈련이 진행된다.


    2019-02-20 10:10:28.450461: step 1260, loss = 2.17 (151.4 examples/sec; 0.845 sec/batch)
    2019-02-20 10:10:36.809246: step 1270, loss = 2.16 (155.7 examples/sec; 0.822 sec/batch)
    2019-02-20 10:10:45.144759: step 1280, loss = 2.09 (154.3 examples/sec; 0.830 sec/batch)



    1. 손실을 계산하는 tower_loss 함수

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    def tower_loss(scope):
      images, labels = cifar10.distorted_inputs()
     
      logits = cifar10.inference(images)
     
      _ = cifar10.loss(logits, labels)
     
      losses = tf.get_collection('losses', scope)
     
      total_loss = tf.add_n(losses, name='total_loss')
     
      loss_averages = tf.train.ExponentialMovingAverage(0.9, name='avg')
      loss_averages_op = loss_averages.apply(losses + [total_loss])
     
      for l in losses + [total_loss]:
     
        loss_name = re.sub('%s_[0-9]*/' % cifar10.TOWER_NAME, '', l.op.name)
     
        tf.scalar_summary(loss_name +' (raw)', l)
        tf.scalar_summary(loss_name, loss_averages.average(l))
     
      with tf.control_dependencies([loss_averages_op]):
        total_loss = tf.identity(total_loss)
      return total_loss
     
    cs


    1) line2에서 distorted_inputs()을 사용하여 데이터가 왜곡된 이미지 및 레이블을 생성

    2) line4에서 컨벌루션 신경망을 생성한다.

    3) 손실함수를 계산하고 마지막에 total_loss를 tf.add_n 함수를 이용하여 모든 손실을 합한다.



    2. 서로 다른 GPU로 계산된 기울기를 합성하는 함수

    tower_grads는 기울기의 한쌍의 레이어 목록이다. tuple(기울기,변수)로 이루어짐 ex [[(grad0_gpu0,var_gpu0),(grad1_gpu1,var1_gpu0)]]이렇게


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    def average_gradients(tower_grads):
      average_grads = []
      for grad_and_vars in zip(*tower_grads):
        grads = []
        for g, _ in grad_and_vars:
          expanded_g = tf.expand_dims(g, 0)
     
          grads.append(expanded_g)
     
        grad = tf.concat(0, grads)
        grad = tf.reduce_mean(grad, 0)
     
        v = grad_and_vars[0][1]
        grad_and_var = (grad, v)
        average_grads.append(grad_and_var)
      return average_grads
     
    cs


    1) line3에서 zip을 수행하면 각 gpu에서 계산한 var끼리 뭉쳐진다 [[(gpu0,var1),(gpu1,var1)],[(gpu0,var0),(gpu1,var0)]] 요롷게

    2) line6에서 expand_dims 함수를 사용하면  기울기에 중복된 차원 0을 추가한다.

    3) line10에서 추가한 차원 0에 기울기를 병합한다음에

    4) line11에서 reduce_mean을 이용해 차원-0의 평균을 구한다. 

    5) 마지막에 평균 기울기를 Variable과 결합해서 원래 튜플 형식으로 변환한다. (..?흠...그냥 하나로 병합해서 평균구하고 다시 뿌리는 작업을 하는듯)



    3.학습하는 부분

    간단한 계산을 위해 기본 계산 장치는 cpu로 설정했다고 한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    def train():
      with tf.Graph().as_default(), tf.device('/cpu:0'):
        global_step = tf.get_variable('global_step', [],
                                      initializer=tf.constant_initializer(0), 
                                      trainable=False)
     
        num_batches_per_epoch = (cifar10.NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN /
                                 FLAGS.batch_size)
     
        decay_steps = int(num_batches_per_epoch * cifar10.NUM_EPOCHS_PER_DECAY)
     
        lr = tf.train.exponential_decay(cifar10.INITIAL_LEARNING_RATE,
                                        global_step,
                                        decay_steps,
                                        cifar10.LEARNING_RATE_DECAY_FACTOR,
                                        staircase=True)
     
        opt = tf.train.GradientDescentOptimizer(lr)

    cs


    아래의 4가지를 설정하는 부분이다.


    1) global_step : 훈련 단계 수를 기록한다.

    2) epoch : batch 수 설정

    3) decay : exponetial_decay(초기 학습속도, 전역 훈련의 단계, 각 감쇠에 필요한 단계, 감쇠율, True로 설정된것은 단계적 감쇠를 뜻함)

    4) opt : 최적화 알고리즘은 GradientDescent로 설정


    4. GPU 계산 결과 저장


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     tower_grads = []
     for i in xrange(FLAGS.num_gpus):
          with tf.device('/gpu:%d' % i):
            with tf.name_scope('%s_%d' % (cifar10.TOWER_NAME, i)) as scope:
              loss = tower_loss(scope)
              tf.get_variable_scope().reuse_variables()
              summaries = tf.get_collection(tf.GraphKeys.SUMMARIES, scope)
              grads = opt.compute_gradients(loss)
              tower_grads.append(grads)
    grads = average_gradients(tower_grads)
    apply_gradient_op = opt.apply_gradients(grads, global_step=global_step)
    cs


    1) GPU 개수만큼 loop를 돌게 한다

    2) tf.device로 gpu 선택한 뒤

    3) line 6에서 함수를 이용하여 모든 GPU가 하나의 모델 및 동일한 매개 변수를 공유토록 한다.

    4) line 8에서 단일 gpu의 기울기를 계산해서 line 1에 있는 변수에 추가한다.

    5) line 10에서 평균을 계산해서

    6) line 11에서 모델 매개변수를 업데이트 한다.

    '2019년' 카테고리의 다른 글

    텐서플로우 분산 병렬처리 동기/비동기 를 훌륭하게 설명한 블로그  (0) 2019.02.21
    텐서플로우 분산 병렬 처리  (0) 2019.02.21
    텐서보드  (0) 2019.02.20
    설치 메모  (0) 2019.02.19
    curl을 이용한 pip 설치  (0) 2019.02.19

    대화의 장 💬