머신러닝

텐서플로우 코딩을 제대로 하기 위해 어레이 구조를 이해해 보자

coding art 2019. 1. 21. 14:07
728x90

파이선 코딩을 배우는 초보자도 머신 러닝에 한번 도전해 보자.

머신 러닝을 배우려는 초보자들이 가지게 될 의문점들을 하나하나 찾아내어

실제 풀어보고 결과를 확인해볼 수 있도록  완전히 뒷문으로 들어가 시작하는 머신 러닝!


우선 아래 url 을 방문하여 url 로 구성된 본 서의 목차 파일을 다운로드 받아 살펴보시기 바랍니다.

파이선 코딩 초보자를 위한 톈서플로우∙OpenCV 머신러닝 머리말과 url 목차 파일 다운로드
https://steemit.com/kr/@codingart/pryx1-opencv

noname03.png

_____________________________________________________________________________________________________




텐서플로우에서 자유롭게 array  사용을 할수있도록 예제코드를 연습해보자.  이미 Numpy 라이브러리 모듈 지원하에서도 array  사용법은 그 다양성으로 인해  만만치 않다. 머신 러닝의 목표가 특정 API의 다양한 문법적인 특징을 섭렵하는 것이 아니라 학습에 의한 결과를 얻어내야 하기 때문에 이미 잘 짜여진 프레임 형태의 코드를 중심으로 소폭 수정하는 방법에 집착할 필요는 없다. 결국은 스스로 새롭게 코딩을 하든지 아니면 잘못된 코드를 제대로 마음대로 코딩할 수 있는 안목이 있어야 한다.




Numpy 에서는 일종의 규칙적인 구조를  어레이를 생각하지만 텐서플로우 머신 러닝에 들어와서는 어레이란 용어 대신에 아예 용어를 바꿔 텐서란 오브젝트를 주로 다루게 된다.


rank 0은 하나의 스칼라 상수나 변수를 뜻하며 rank 1은 1차원 어레이와 비슷하나 텐서플로우에서의 데이터는 주로 리스트 형태임을 상기하면 1차원 리스트에 해당하며 주로 1차원 입력 벡터로 많이 사용한다. rank 2는 2차원 리스트 데이터 구조 그런 방식으로 생각하자.

아주 간단한 rank가 3으로서 크기가 batchsizex2x3인 텐서를 생성하여 reshape 해 보도록 하자. batchsize 의 크기는 Session 단계에서 batch  샘플 묶음을 정의할 때 크기가 결정되며 Graph 단계에서는 placeholder로 사전 설정이 되어 있어야 한다. reshaping이란 2차원이나 3차원 구조의 데이터를 어떤 규칙에 따라 차원을 변화시키는 작업이다. 대표적으로 2차원 텐서로 표현이 되는 28X28 MNIST  이미지 데이타는 위 그림에서처럼 한줄 한줄 찢어서 연결하여 784개의 요소를 갖는 1차원으로 reshaping이 가능하다.

이 텐서를 대상으로 텐서플로우의 최적화된 표현기법을 사용하여 컬럼별로 합을 계산하는 연습을 하기로 한다. 컬럼별 합 계산을 할 줄 몰라서가 아니라 텐서플로우 틀을 사용하여 이해 증진 차원에서 해 보자는 것이다.



헤더 영역에서 tesnsorflow 와 numpy를 불러 들인다. 아무리 텐서플로우가 텐서를 다룬다 하더라도 그 근본은 numpy와 연관되어 잇다는 점이다.

Graph 설정 영역으로 넘어가서 2개의 placeholder를 설정하자. x는 batchsizex2x3에 해당하는 텐서인데 실제로 Session에서 계산을 위한 데이터를 입력해야 한다. batchsize는 Graph 영역에서 None 으로 처리하는데 Session 단계에서 구체적으로 크기를 결정하여 feed_dict{} 에서 입력된다.

    x = tf.placeholder(dtype=tf.float32, shape=(None, 2, 3), name='input_x')
    x2 = tf.reshape(x, shape=(-1, 6), name='x2')

이 rank 3인 텐서 x를 2x3=6인 rank 2인 텐서 x2로 reshaping 해보자. 아무리 모양을 바꾸어도 요소의 숫자는 일정하게 유지되어야 한다. 하지만 현재 위치에서 아직은 batchsize 가 결정이 안되어 있기 때문에 텐서 x의 전체적인 크기를 모르는 상태다. shape(-1,6)에서 첫 번째 디멘션 값 –1은 Session에서 batchsize 가 정해지고 텐서의 전체 크기가 결정되면 reshaping 되는 나머지 디멘션 값인 6으로 나누면 결정이 된다.
 
텐서 x3는 한줄에 수평으로 6개 크기의 데이터를 가지며 수직 방향으로의 줄 수는 Session에서 3으로 확정될 예정이다. 컬럼의 합을 계산해 보자.
    xsum = tf.reduce_sum(x2, axis=0, name='col_sum')
    xmean = tf.reduce_mean(x2, axis=0, name='col_mean')
axis  값에 따라 합산 결과가 크게 바뀐다. axis=None 이면 모조리 합하는 경우고, axis=1 이면 줄(raw)별로 합산한 결과를 준다.
reduce_mean에 의한 평균 값 계산도 reduce_sum 과 비슷하다. 각 axis 값을 None, 0, 1 로 바꾸면서 결과를 비교 검토해 보기 바란다. 즉 텐서플로우 명령인 sum과 mean으로 계산한 결과는 파이선 변수인 xsum 과 xmean 에 저장한다는 의미이다.



Session에서 우선 reshaping을 하되 Numpy 방식으로 데이터를 입력하자. 즉 arrang(18) 명령을 사용하여 1.0부터 18.0까지 1.0 간격으로 데이터를 생성하여 (3,2,3)으로 reshape 한 x_array 에 저장한다. 이 x_array 는 텐서플로우 변수가 아니며 Numpy 어레이 데이터 상태이며 feed_dict{c: x_array}을 통해 텐서로 입력된다. 이 부분이 결국 텐서플로우의 데이터 입출력 구조를 의미한다고 봐야 할 것이다. 다음과 같이 코드의 구조를 관찰해 보면 어디서 어디까지가 Numpy 이고 TensorFlow 영역인지 이해가 갈 것이다.

   
#tf.example_02.py

import tensorflow as tf
import numpy as np

g = tf.Graph()
with g.as_default():
    x = tf.placeholder(dtype=tf.float32,
                       shape=(None, 2, 3),
                       name='input_x')

    x2 = tf.reshape(x, shape=(-1, 6),
                    name='x2')

    ## calculate the sum of each column
    xsum = tf.reduce_sum(x2, axis=1, name='col_sum')
    ## calculate the mean of each column
    xmean = tf.reduce_mean(x2, axis=1, name='col_mean')
   
with tf.Session(graph=g) as sess:
    x_array = np.arange(18).reshape(3, 2, 3)
    print('input shape: ', x_array.shape)
    print('Reshaped:\n',
          sess.run(x2, feed_dict={x:x_array}))
    print('Column Sums:\n',
          sess.run(xsum, feed_dict={x:x_array}))
    print('Column Means:\n',
          sess.run(xmean, feed_dict={x:x_array}))