텐서플로우(Tensorflow) - 간단한 신경망 만들기

    변수와 플레이스 홀더와 Weight 값 세팅하는 것만 배웠는데 무슨 벌써 신경망인가? 하실지 모르겠지만 사실 텐서플로우는 어느정도 익히고, 일반 개발에서 Hello World 찍거나 구구단 짜는 수준이 바로 간단한 신경망을 만드는 것이라 생각해도 된다. 파이썬만 어느정도 다룰 수 있다면, 다음부터는 진도를 쭉쭉 나갈 수 있다. 


    사실 텐서플로우에서 구현하는 신경망이라고 하는 것이 거의다 잘 짜여진 메소드 호출하고 하는 것인데 우리는 몇개의 Feature(특징)와 몇개의 노드, 그리고 몇개의 Output으로 되어 있는지, 회귀인지 분류인지 등등 정도만 정의하면 텐서플로우가 알아서 다 돌아간다. 그러니 만약에 여기서 텐서플로우 개발자는 대단해라고 생각한다면 그것은 큰 오산이다. 


    모든 연산을 텐서플로우가 거의다 해주며 텐서플로우 개발자 혹은 연구원은 정확률을 높히기 위해서 최적의 값으로 트레이닝을 하는 것이다. 물론 트레이닝 전단계인 수집 단계에서 상당한 공수가 소비될 수 있다. 예를 들어 비정형 텍스트 분석과 엄청나게 많은 데이터라고 한다면 빅데이터 수집 플랫폼이나 형태소 분석기같은 도구를 다룰 줄 알아야 되기 때문이다. 



    그렇지만, 텐서플로우 하나만 다루는 것은 크게 어렵지 않으며 심지어 이 세상에 존재하는 대다수의 텐서플로우의 소스를 보면 거기서 거기같은 느낌이 들 것이다. 그건 바로 구성이 같기 때문이기도 하고 텐서플로우의 역사가 얼마 되지 않았기 때문일 수도 있다.



    신경망 구조


    우리는 신경망 구조에 대해서 이미 어느정도 배운바 있지만 다시한번 우리가 만들어 볼 간단한 신경망에 대해서 모습을 보도록 해보자



    이 그림은 딥러닝(Deep Learning)형태의 신경망(Neural Network)으로 요즘은 히든노드가 2개 이상을 딥러닝이라고 부른다. 그림을 보면 3개의 Feature로 이루어진 input 값들을 2개의 히든노드를 거쳐서 최종적으로 한개의 값으로 출력되는 구조이다.


    3개의 값이 어떻게 4개의 값으로 변하는지 우선 깨달아야 하는데 그건 바로 중간에 연산을 추가하는 가중치(Weight)와 편향값(Bias)이 있기 때문이다. input layer의 값이 [1,2,3] 이 있는 배열이라고 가정할 때 첫번째 hidden layer의 각각의 값은 아래와 같다.


    ((1*w)+b) + ((2*w)+b) + ((3*w)+b)


    여기서 보통 b값은 스칼라값으로 되어 있어서 한쓰는 경우도 많고(ex: b의 값을 0으로 주면 사실상 안쓰는 구조), w의 값은 신경망을 학습하면서 최적의 값을 컴퓨터 스스로 찾는 것이다. 


    input값은 정해져 있는 FACT이고, output은 컴퓨터가 맞춰야 할 문제이기 때문에 컴퓨터가 핸들링해야 하는건 오로지 W값이라는 것이다. 즉 우리는 컴퓨터가 output의 정확도를 높히기 위해서 hidden 노드도 늘려보고 편향값을 바꾸기도 하고 등등의 실험을 통해서 가장 적절한 신경망 구조를 짜는 것이 핵심인 것이다.


    위의 공식을 보다시피, 매우 간단하다보니 사실상 간단한 신경망이라 함은 input값에 가중치를 곱하고 편향을 더하는 것 이상이하도 아니다. 이를 코드로 구현해보도록 해보자. 위의 딥러닝 구조는 예시일 뿐 우리가 구현해볼 것은 중간노드없이 input 노드에서 가중치와 편향값을 더해서 output 노드를 구하는 것이다.



    간단한 신경망 소스


    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    import tensorflow as tf
     
    # X라는 input 값을 placeholder로 세팅, 열만 3개
    = tf.placeholder(tf.float32, [None, 3])
    print(X)
     
    # X placeholder에 넣을 데이터 세팅
    input = [[1,2,3],[4,5,6]]
     
    # 가중치 변수에 [3,2] 구조로 랜덤값을 넣는다
    = tf.Variable(tf.random_normal([3,2]))
     
    # 편향변수에 [2,1] 구조로 랜덤값을 넣는다
    = tf.Variable(tf.random_normal([2,1]))
     
    # Input값과 가중치를 곱하고, 편향값을 더한값을 hypothesis
    hypothesis = tf.matmul(X,W) + b
     
    # 텐서플로우 시작
    sess = tf.Session()
     
    # 정의한 변수들 초기화
    sess.run(tf.global_variables_initializer())
     
    # input값 출력
    print("============== INPUT ==============")
    print(input)
     
    # 가충치값 출력
    print("============== W ==============")
    print(sess.run(W))
     
    # 편향값 출력
    print("============== b ==============")
    print(sess.run(b))
     
    # 최종결과
    print("============== hypothesis ==============")
    print(sess.run(hypothesis, feed_dict={X: input}))
    sess.close()
    cs


    소스에 주석을 달았고, 바로 전 포스팅에서 하나 추가된 것이 있는데 바로 matmul(행렬곱)을 하고, 편향값을 더한 것이다. 그리고 가중치(Weight)와 편향(Bias)를 랜덤으로 적용하였다. 여기서 값을 세팅할 때 꼭 기억해야 할 것은 배열을 곱할 때 앞단의 배열의 열과 뒷단의 배열의 행이 맞아야 한다는 것이다. 여기서는 X값에 행의 개수는 세팅이 되어 있지 않고, 열만 세팅이 되어 있는데 하나의 값을 트레이닝 하거나 분류할 때는 행이 하나인 것이 정상이기 때문이다.


    input값의 Feature가 3개로 되어 있기 때문에 가중치의 행렬 구조는 행 3개로 되어 있다. 그리고 가중치가 열 2개로 되어 있기 때문에 이 값은 input의 행 개수과 마지막 weight의 열 2개의 구조로 출력이 될 것이다.




    신경망 결과


    Tensor("Placeholder:0", shape=(?, 3), dtype=float32)

    2018-07-11 09:47:18.434000: I C:\tf_jenkins\home\workspace\rel-win\M\windows\PY\35\tensorflow\core\platform\cpu_feature_guard.cc:137] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX AVX2

    ============== INPUT ==============

    [[1, 2, 3], [4, 5, 6]]

    ============== W ==============

    [[ 2.22502518  0.79227114]

     [ 1.44572973  0.13895296]

     [ 0.57775867 -1.5595268 ]]

    ============== b ==============

    [[ 0.25380304]

     [ 0.63183624]]

    ============== hypothesis ==============

    [[  7.10356379  -3.35460019]

     [ 20.22713852  -4.86147451]]


    신경망 결과에서 볼드로 색을 진하게 한 것이 결과인데 예상처럼 2 X 2의 행렬구조로 출력이 되었다. 여기서 그럼 input값에 행을 하나 더 추가해보도록 하고, 3 X 2의 행렬구조로 나오는지 확인해보도록 하겠다.



    행 추가


    input = [[1,2,3],[4,5,6]]

    값에 행을 하나 더 추가해서


    input = [[1,2,3],[4,5,6],[7,8,9]]

    위와 같이 행을 하나 더 추가해서 [7,8,9] 값을 입력하였다. 위를 실행하면,


    Traceback (most recent call last):

      File "C:\Anaconda3\lib\site-packages\tensorflow\python\client\session.py", line 1323, in _do_call

        return fn(*args)

      File "C:\Anaconda3\lib\site-packages\tensorflow\python\client\session.py", line 1302, in _run_fn

        status, run_metadata)

      File "C:\Anaconda3\lib\site-packages\tensorflow\python\framework\errors_impl.py", line 473, in __exit__

        c_api.TF_GetCode(self.status.status))

    tensorflow.python.framework.errors_impl.InvalidArgumentError: Incompatible shapes: [3,2] vs. [2,1]

    [[Node: add = Add[T=DT_FLOAT, _device="/job:localhost/replica:0/task:0/device:CPU:0"](MatMul, Variable_1/read)]]


    During handling of the above exception, another exception occurred:


    Traceback (most recent call last):

      File "C:/Project/AI/SAI/02. PySource/Test/Exam.py", line 39, in <module>

        print(sess.run(hypothesis, feed_dict={X: input}))

      File "C:\Anaconda3\lib\site-packages\tensorflow\python\client\session.py", line 889, in run

        run_metadata_ptr)

      File "C:\Anaconda3\lib\site-packages\tensorflow\python\client\session.py", line 1120, in _run

        feed_dict_tensor, options, run_metadata)

      File "C:\Anaconda3\lib\site-packages\tensorflow\python\client\session.py", line 1317, in _do_run

        options, run_metadata)

      File "C:\Anaconda3\lib\site-packages\tensorflow\python\client\session.py", line 1336, in _do_call

        raise type(e)(node_def, op, message)

    tensorflow.python.framework.errors_impl.InvalidArgumentError: Incompatible shapes: [3,2] vs. [2,1]

    [[Node: add = Add[T=DT_FLOAT, _device="/job:localhost/replica:0/task:0/device:CPU:0"](MatMul, Variable_1/read)]]


    Caused by op 'add', defined at:

      File "C:/Project/AI/SAI/02. PySource/Test/Exam.py", line 17, in <module>

        hypothesis = tf.matmul(X,W) + b

      File "C:\Anaconda3\lib\site-packages\tensorflow\python\ops\math_ops.py", line 894, in binary_op_wrapper

        return func(x, y, name=name)

      File "C:\Anaconda3\lib\site-packages\tensorflow\python\ops\gen_math_ops.py", line 182, in add

        "Add", x=x, y=y, name=name)

      File "C:\Anaconda3\lib\site-packages\tensorflow\python\framework\op_def_library.py", line 787, in _apply_op_helper

        op_def=op_def)

      File "C:\Anaconda3\lib\site-packages\tensorflow\python\framework\ops.py", line 2956, in create_op

        op_def=op_def)

      File "C:\Anaconda3\lib\site-packages\tensorflow\python\framework\ops.py", line 1470, in __init__

        self._traceback = self._graph._extract_stack()  # pylint: disable=protected-access


    InvalidArgumentError (see above for traceback): Incompatible shapes: [3,2] vs. [2,1]

    [[Node: add = Add[T=DT_FLOAT, _device="/job:localhost/replica:0/task:0/device:CPU:0"](MatMul, Variable_1/read)]]


    실행하면 위와 같이 에러가 출력이 된다. 에러를 읽어보면 [3,2] vs [2,1]의 shape가 맞지 않아서 생기는 문제이다. 여기서 3,2의 모양은 Weight이고, 2,1의 모양은 bias인데 이 둘의 구조가 맞지 않아서 생기는 문제이다. Weight는 input의 구조에 맞게 변형했으니, bias의 구조도 [2,1] -> [3,1] 형태로 변경하면 이 문제는 해결이 된다.



    변경된 부분 및 결과


    변경소스

    1
    2
    3
    4
    5
    6
    7
    8
    # X placeholder에 넣을 데이터 세팅
    input = [[1,2,3],[4,5,6],[7,8,9]]
     
    # 가중치 변수에 [3,2] 구조로 랜덤값을 넣는다
    = tf.Variable(tf.random_normal([3,2]))
     
    # 편향변수에 [2,1] 구조로 랜덤값을 넣는다
    = tf.Variable(tf.random_normal([3,1]))
    cs


    최종결과

    Tensor("Placeholder:0", shape=(?, 3), dtype=float32)

    2018-07-11 10:38:36.373000: I C:\tf_jenkins\home\workspace\rel-win\M\windows\PY\35\tensorflow\core\platform\cpu_feature_guard.cc:137] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX AVX2

    ============== INPUT ==============

    [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

    ============== W ==============

    [[-0.72768003 -1.12832034]

     [-0.80668712 -0.7968179 ]

     [-0.61679399  0.32504284]]

    ============== b ==============

    [[-1.70346963]

     [ 0.10821879]

     [-0.90870345]]

    ============== hypothesis ==============

    [[ -5.89490604  -3.45029736]

     [-10.53670025  -6.43889475]

     [-18.00710487 -12.25610352]]



    이전 포스팅


    댓글

    Designed by JB FACTORY