본문으로 바로가기

대부분의 딥러닝 혹은 신경망 책, 동영상 강의등을 보면 이렇게 진행해 오다가 XOR라는 단어가 나타납니다. 저도 전자회로 이후에 이렇게 AND, XOR 등의 단어를 많이 본 건 참 오랜만이네요. 처음 AND를 학습[바로가기]했던 예제는 입력 노드에 가중치가 붙고 출력 노드로 이어지는 아주 심플한 구조였습니다. 이번에는 단일 신경망으로는 풀 수 없는 유명한 문제 XOR를 은닉층 하나 추가해서 간단히 풀어내는 예제를 볼려고 합니다~~~~

오늘도 언제나 그렇듯~ 김성훈 교수님의 유명한 딥러닝과 텐서플로우 공개 강좌[바로가기], 그 외에 엣지있게 설명한 텐서플로우[바로가기], 딥러닝 첫걸음[바로가기], 처음 배우는 머신러닝[바로가기]을 정말 단순히 따라가는 수준입니다.

뭐 아무튼... 처음 AND 예제[바로가기]에서 AND를 입력하던 부분만

# XOR
x_data = np.array([[0, 0],
                  [0, 1],
                  [1, 0],
                  [1, 1]], dtype=np.float32)
y_data = np.array([[0],
                  [1],
                  [1],
                  [0]], dtype=np.float32)

위 코드로 표현되는 XOR로 바꿔서 실행해 보면... 

이런 결과가 나타납니다. Hypothesis가 모두 0.5가 되어서 사실 못 맞춘거죠.. 1 두개, 0 두개 있으니 Accuracy야 0.5가 잡혔겠지만 말이죠~

출처 : Learn to Build an App to Find Similar Images using Deep Learning- Piotr Teterwak

그것은 위의 AND나...

출처 : Learn to Build an App to Find Similar Images using Deep Learning- Piotr Teterwak

OR는 모두 하나의 선으로 분리 가능(linear separable)한데요...

출처 : Learn to Build an App to Find Similar Images using Deep Learning- Piotr Teterwak

XOR는 그렇지 않기 때문입니다. 그래서 어마어마한 역사적 사실들 - 이것도 굉장히 재미있는데요. 딥러닝의 역사를 따로 구글에서 찾아보시길 권합니다. 엄청~~~ 재미난 역사이니까요... 뭐 아무튼 이 XOR문제를 해결하는 방법은 많은 위대한 분들의 작업결과를 바로 가져오면 은닉층(Hidden Layer)을 하나 추가해 주면 됩니다. 먼저...

import tensorflow as tf
import numpy as np
from tqdm import tqdm_notebook
import matplotlib.pyplot as plt
%matplotlib inline

# XOR
x_data = np.array([[0, 0],
                  [0, 1],
                  [1, 0],
                  [1, 1]], dtype=np.float32)
y_data = np.array([[0],
                  [1],
                  [1],
                  [0]], dtype=np.float32)

X = tf.placeholder(tf.float32, [None, 2], name='x-input')
Y = tf.placeholder(tf.float32, [None, 1], name='y-input')

with tf.name_scope("layer1") as scope:    
    W1 = tf.Variable(tf.random_normal([2, 2]), name='weight1')
    b1 = tf.Variable(tf.random_normal([2]), name='bias1')

    layer1 = tf.sigmoid(tf.matmul(X, W1) + b1)

with tf.name_scope("layer2") as scope:    
    W2 = tf.Variable(tf.random_normal([2, 1]), name='weight2')
    b2 = tf.Variable(tf.random_normal([1]), name='bias2')

    hypothesis = tf.sigmoid(tf.matmul(layer1, W2) + b2)

# cost/loss function
with tf.name_scope("cost") as scope:
    cost = -tf.reduce_mean(Y * tf.log(hypothesis) + (1 - Y) * tf.log(1 - hypothesis))
    cost_summ = tf.summary.scalar("cost", cost)

with tf.name_scope("train") as scope:
    train = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(cost)

# Accuracy computation
# True if hypothesis>0.5 else False
predicted = tf.cast(hypothesis > 0.5, dtype=tf.float32)
accuracy = tf.reduce_mean(tf.cast(tf.equal(predicted, Y), dtype=tf.float32))
accuracy_summ = tf.summary.scalar("accuracy", accuracy)

이렇게 XOR까지 넣고 준비를 하구요. with tf.name_scope('NAME') as scope는 [바로가기]에서 이야기한 텐서보드를 사용할 때 이쁘게 보이게 그룹핑할 용도이구요. 나머지는 AND 때와 동일한 코드입니다. 이제

# Launch graph
with tf.Session() as sess:
    # tensorboard --logdir=./logs
    merged_summary = tf.summary.merge_all()
    writer = tf.summary.FileWriter("./logs/XOR/HiddenLayer")
    writer.add_graph(sess.graph)  # Show the graph
    
    # Initialize TensorFlow variables
    sess.run(tf.global_variables_initializer())

    for step in tqdm_notebook(range(10001)):
        summary, _ = sess.run([merged_summary, train], feed_dict={X: x_data, Y: y_data})
        writer.add_summary(summary, global_step=step)

    # Accuracy report
    h, c, a = sess.run([hypothesis, predicted, accuracy], feed_dict={X: x_data, Y: y_data})
    print("\nHypothesis: ", h, "\nCorrect: ", c, "\nAccuracy: ", a)

이렇게 학습하고 결과를 보죠~

앗 ~ 잘 잡았네요^^

텐서보드로 구조를 보면 Layer1과 Layer2로 입력층에서 은닉층을 거치는 것이 보입니다. 이렇게 하면 XOR 문제도 해결을 할 수 있다는 것과... 은닉층을 추가하는 것도 텐서플로우에서는 꽤 쉽다는 것도 함께 알 수 있네용^^


댓글을 달아 주세요

  1. BlogIcon 공수래공수거 2018.02.19 08:25 신고

    즑웠던 설 연휴를 보내고
    한주 활기차게 시작하시기 바랍니다^^

    • BlogIcon PinkWink 2018.02.19 16:48 신고

      왠지 즑웠던 이라는 단어가 오타이시겠지만..
      전.. 즐겁지만 또한 피곤함과 뭔가 모를 공허함과 우울함이 느껴지는 뭐 그런 느낌의 단어입니다. ㅎㅎㅎ

  2. BlogIcon 휴식같은 친구 2018.02.19 15:29 신고

    exclusive OR...오랜만에 들어보네요.
    잘 보고 갑니다.
    즐거운 한 주 시작하세요.

  3. BlogIcon 『방쌤』 2018.02.19 16:06 신고

    설 연휴는 잘 보내셨나요?
    이번 주는 날씨가 많이 풀렸네요^^
    즐거운 한 주 보내세요!

  4. BlogIcon 귀요미디지 2018.02.19 17:45 신고

    즐거운 명절 보내시고 다시 일상이네요~
    앞으로의 일상도 항상 즐거운 나날되세요 ^^

  5. 2018.02.19 19:10

    비밀댓글입니다

  6. BlogIcon peterjun 2018.02.20 00:45 신고

    딥러닝 역사 한 번 찾아봐야겠습니다. ^^

  7. BlogIcon Bliss :) 2018.02.20 08:38 신고

    아....집중해서 읽으려고 했으나..집중력을 분산케 하는 제 무지함이 느껴지네요ㅎㅎㅎ 연휴의 후유증 잘 극복하시고 행복한 한 주 보내시길요^^

  8. dnWNsdl 2018.08.18 21:20 신고

    저는 왜 이렇게 나올까요?
    Hypothesis: [[0.01035854]
    [0.49691284]
    [0.98676515]
    [0.50558954]]
    Correct: [[0.]
    [0.]
    [1.]
    [1.]]
    Accuracy: 0.5
    이상하네요....

  9. dnWNsdl 2018.08.18 21:40 신고

    다시 해보니까 이번엔 이상한 메세지가 뜨네요... 어렵습니다.
    InvalidArgumentError Traceback (most recent call last)
    ~\AppData\Local\conda\conda\envs\venv\lib\site-packages\tensorflow\python\client\session.py in _do_call(self, fn, *args)
    1360 try:
    -> 1361 return fn(*args)
    1362 except errors.OpError as e:

    ~\AppData\Local\conda\conda\envs\venv\lib\site-packages\tensorflow\python\client\session.py in _run_fn(session, feed_dict, fetch_list, target_list, options, run_metadata)
    1339 return tf_session.TF_Run(session, options, feed_dict, fetch_list,
    -> 1340 target_list, status, run_metadata)
    1341

    ~\AppData\Local\conda\conda\envs\venv\lib\site-packages\tensorflow\python\framework\errors_impl.py in __exit__(self, type_arg, value_arg, traceback_arg)
    515 compat.as_text(c_api.TF_Message(self.status.status)),
    --> 516 c_api.TF_GetCode(self.status.status))
    517 # Delete the underlying status object from memory otherwise it stays alive

    InvalidArgumentError: You must feed a value for placeholder tensor 'x-input' with dtype float and shape [?,2]
    [[Node: x-input = Placeholder[dtype=DT_FLOAT, shape=[?,2], _device="/job:localhost/replica:0/task:0/device:CPU:0"]()]]

    During handling of the above exception, another exception occurred:

    InvalidArgumentError Traceback (most recent call last)
    <ipython-input-17-39cfc11dc289> in <module>()
    10
    11 for step in tqdm_notebook(range(10001)):
    ---> 12 summary, _ = sess.run([merged_summary, train], feed_dict={X: x_data, Y: y_data})
    13 writer.add_summary(summary, global_step=step)
    14

    ~\AppData\Local\conda\conda\envs\venv\lib\site-packages\tensorflow\python\client\session.py in run(self, fetches, feed_dict, options, run_metadata)
    903 try:
    904 result = self._run(None, fetches, feed_dict, options_ptr,
    --> 905 run_metadata_ptr)
    906 if run_metadata:
    907 proto_data = tf_session.TF_GetBuffer(run_metadata_ptr)

    ~\AppData\Local\conda\conda\envs\venv\lib\site-packages\tensorflow\python\client\session.py in _run(self, handle, fetches, feed_dict, options, run_metadata)
    1135 if final_fetches or final_targets or (handle and feed_dict_tensor):
    1136 results = self._do_run(handle, final_targets, final_fetches,
    -> 1137 feed_dict_tensor, options, run_metadata)
    1138 else:
    1139 results = []

    ~\AppData\Local\conda\conda\envs\venv\lib\site-packages\tensorflow\python\client\session.py in _do_run(self, handle, target_list, fetch_list, feed_dict, options, run_metadata)
    1353 if handle is None:
    1354 return self._do_call(_run_fn, self._session, feeds, fetches, targets,
    -> 1355 options, run_metadata)
    1356 else:
    1357 return self._do_call(_prun_fn, self._session, handle, feeds, fetches)

    ~\AppData\Local\conda\conda\envs\venv\lib\site-packages\tensorflow\python\client\session.py in _do_call(self, fn, *args)
    1372 except KeyError:
    1373 pass
    -> 1374 raise type(e)(node_def, op, message)
    1375
    1376 def _extend_graph(self):

    InvalidArgumentError: You must feed a value for placeholder tensor 'x-input' with dtype float and shape [?,2]
    [[Node: x-input = Placeholder[dtype=DT_FLOAT, shape=[?,2], _device="/job:localhost/replica:0/task:0/device:CPU:0"]()]]

    Caused by op 'x-input', defined at:
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\ipykernel_launcher.py", line 16, in <module>
    app.launch_new_instance()
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\traitlets\config\application.py", line 658, in launch_instance
    app.start()
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\ipykernel\kernelapp.py", line 486, in start
    self.io_loop.start()
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\tornado\platform\asyncio.py", line 127, in start
    self.asyncio_loop.run_forever()
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\asyncio\base_events.py", line 422, in run_forever
    self._run_once()
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\asyncio\base_events.py", line 1432, in _run_once
    handle._run()
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\asyncio\events.py", line 145, in _run
    self._callback(*self._args)
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\tornado\platform\asyncio.py", line 117, in _handle_events
    handler_func(fileobj, events)
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\tornado\stack_context.py", line 276, in null_wrapper
    return fn(*args, **kwargs)
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\zmq\eventloop\zmqstream.py", line 450, in _handle_events
    self._handle_recv()
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\zmq\eventloop\zmqstream.py", line 480, in _handle_recv
    self._run_callback(callback, msg)
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\zmq\eventloop\zmqstream.py", line 432, in _run_callback
    callback(*args, **kwargs)
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\tornado\stack_context.py", line 276, in null_wrapper
    return fn(*args, **kwargs)
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\ipykernel\kernelbase.py", line 283, in dispatcher
    return self.dispatch_shell(stream, msg)
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\ipykernel\kernelbase.py", line 233, in dispatch_shell
    handler(stream, idents, msg)
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\ipykernel\kernelbase.py", line 399, in execute_request
    user_expressions, allow_stdin)
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\ipykernel\ipkernel.py", line 208, in do_execute
    res = shell.run_cell(code, store_history=store_history, silent=silent)
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\ipykernel\zmqshell.py", line 537, in run_cell
    return super(ZMQInteractiveShell, self).run_cell(*args, **kwargs)
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\IPython\core\interactiveshell.py", line 2662, in run_cell
    raw_cell, store_history, silent, shell_futures)
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\IPython\core\interactiveshell.py", line 2785, in _run_cell
    interactivity=interactivity, compiler=compiler, result=result)
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\IPython\core\interactiveshell.py", line 2903, in run_ast_nodes
    if self.run_code(code, result):
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\IPython\core\interactiveshell.py", line 2963, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
    File "<ipython-input-1-718ee9d9fec5>", line 17, in <module>
    X = tf.placeholder(tf.float32, [None, 2], name='x-input')
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\tensorflow\python\ops\array_ops.py", line 1746, in placeholder
    return gen_array_ops._placeholder(dtype=dtype, shape=shape, name=name)
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\tensorflow\python\ops\gen_array_ops.py", line 4026, in _placeholder
    "Placeholder", dtype=dtype, shape=shape, name=name)
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\tensorflow\python\framework\op_def_library.py", line 787, in _apply_op_helper
    op_def=op_def)
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\tensorflow\python\framework\ops.py", line 3271, in create_op
    op_def=op_def)
    File "C:\Users\lss9566\AppData\Local\conda\conda\envs\venv\lib\site-packages\tensorflow\python\framework\ops.py", line 1650, in __init__
    self._traceback = self._graph._extract_stack() # pylint: disable=protected-access

    InvalidArgumentError (see above for traceback): You must feed a value for placeholder tensor 'x-input' with dtype float and shape [?,2]
    [[Node: x-input = Placeholder[dtype=DT_FLOAT, shape=[?,2], _device="/job:localhost/replica:0/task:0/device:CPU:0"]()]]