{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# CHAPTER 9. 텐서플로 시작하기" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.12.0\n", "Default Graph : \n", "Default Session: None\n" ] } ], "source": [ "import tensorflow as tf\n", "print(tf.__version__)\n", "print(\"Default Graph :\", tf.get_default_graph())\n", "print(\"Default Session:\", tf.get_default_session())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Tensorflow\n", " - 공개날짜: 2015년 11월\n", " - 수치 계산을 위한 오픈소스 라이브러리\n", " - 대규모 머신러닝에 특화 \n", " - Two Phase\n", " - 계산 그래프 정의\n", " - 최적화된 C++ 코드를 사용한 그래프 실행\n", " - 그래프를 여러 부분으로 나누어 CPU나 GPU에서 병렬로 실행가능\n", " - 분산 컴퓨팅 지원 --> 수백 대의 서버에 계산을 나누어 실행가능 " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Computation Graph (계산 그래프)\n", " - a form of directed graph where nodes describe operations, while edges represent data flowing between these operations." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Operation\n", " - An operation can have zero or more inputs and produce zero or more outputs.\n", " - Type of operation\n", " - source ops (소스 연산): 입력이 없는 연산 노드, 즉 항상 시작 노드\n", " - a constant, a variable, a placeholder\n", " - ops (연산)\n", " - a mathematical equation (e.g., 더하기, 곱셈)\n", " - 모델을 구성하는 요소들간의 의존 관계를 직관적으로 파악가능함" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.get_default_graph().get_operations()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Tensor \n", " - a symbolic handle to an input or output of operation.\n", " - A tensor provides only an interface for retrieving the values referenced by the tensor.\n", " - 데이터 타입, 크기를 가짐\n", " - 텐서를 평가한 결과는 ndarray (넘파이 배열)로 반환됨." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Session\n", " - Execution of operations (evaluation of tensors) is performed in a special environment referred to as session" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", " \n", " \n", " \n", " \n", "
\n", " \n", " \n", " \n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- 텐서플로우의 주요 기능 - 1\n", " - 윈도우, 리눅스, macOS, iOS, Android 지원\n", " - Scikit Learn과 호환되는 간결한 라이브러리 TF.Learn (tf.contrib.learn) 제공 \n", " - https://www.tensorflow.org/api_docs/python/tf/contrib/learn\n", " - tf.contrib.learn <-- deprecated. 대신 1.8버전부터는 tf.estimator로 깔끔하게 정리되어 이동됨\n", " - 참고: https://excelsior-cjh.tistory.com/157\n", " - 신경망의 구축, 훈련, 평가를 단순화한 TF-slim API 제공 \n", " - https://www.tensorflow.org/api_docs/python/tf/contrib/slim\n", " - Keras나 Preety Tensor와 같은 고수준 API가 텐서플로우 기반으로 독립적으로 구축\n", " - https://www.tensorflow.org/api_docs/python/tf/keras\n", " - 기본 파이썬 API는 복잡도가 높긴 하지만 매우 유연함 --> 다양한 신경망 구조 구현 가능\n", " - 속도가 중요한 연산은 내부적으로 C++로 구현됨\n", " - C++ API 제공\n", " - Loss 값을 최소화하는 모델 파라미터를 찾기 위한 고수준의 최적화 ***노드*** 제공\n", " - 자동 미분 (autodiff) 지원 \n", " - 사용자가 직접 정의한 그래디언트를 자동으로 계산\n", " - 텐서 보드 (TensorBoard) 시각화도구\n", " - 계산 그래프 출력\n", " - 학습 곡선 출력\n", " - 클라우드 서비스\n", " - https://cloud.google.com/ml-engine/\n", " - 오픈소스에 기여하는 커뮤니티\n", " - 풍부한 튜토리얼 및 리소스 \n", " - https://github.com/jtoy/awesome-tensorflow " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- 보스턴 housing price 데이터셋" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x_data.shape : (506, 13)\n", "y_data.shape : (506,)\n" ] } ], "source": [ "from sklearn import datasets, metrics, preprocessing\n", "\n", "boston = datasets.load_boston()\n", "x_data = preprocessing.StandardScaler().fit_transform(boston.data)\n", "y_data = boston.target\n", "\n", "print('x_data.shape :', x_data.shape)\n", "print('y_data.shape :', y_data.shape)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Linear Regression: Natvie TensorFlow" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Default Graph : \n", "Default Session: None\n", "\n", "Step: 40\t MSE: 494.40574\n", "Step: 80\t MSE: 418.47794\n", "Step: 120\t MSE: 357.52841\n", "Step: 160\t MSE: 307.04117\n", "Step: 200\t MSE: 264.59991\n", "Step: 240\t MSE: 228.68188\n", "Step: 280\t MSE: 198.19118\n", "\n", "MSE: 184.06053\n", "Default Graph : \n", "Default Session: \n", "\n", "Default Graph : \n", "Default Session: None\n", "\n" ] } ], "source": [ "print(\"Default Graph :\", tf.get_default_graph())\n", "print(\"Default Session:\", tf.get_default_session())\n", "print()\n", "\n", "x = tf.placeholder(tf.float64, shape=(None, 13))\n", "y_true = tf.placeholder(tf.float64, shape=(None))\n", "\n", "w = tf.Variable(initial_value=tf.zeros([1, 13], dtype=tf.float64, name='weights'))\n", "b = tf.Variable(initial_value=0, dtype=tf.float64, name='bias')\n", "y_pred = tf.matmul(w, tf.transpose(x)) + b\n", " \n", "loss = tf.reduce_mean(tf.square(y_true-y_pred)) # MSE\n", " \n", "learning_rate = 0.1\n", "optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001)\n", "train = optimizer.minimize(loss)\n", " \n", "init = tf.global_variables_initializer()\n", "with tf.Session() as sess:\n", " sess.run(init)\n", " for step in range(300):\n", " MSE, _ = sess.run([loss, train], feed_dict={x: x_data, y_true: y_data})\n", " if (step + 1) % 40 == 0:\n", " print('Step: {:2d}\\t MSE: {:.5f}'.format(step + 1, MSE))\n", " \n", " loss = sess.run(loss, feed_dict={x: x_data, y_true: y_data})\n", " print('\\nMSE: {0:.5f}'.format(loss))\n", " print(\"Default Graph :\", tf.get_default_graph())\n", " print(\"Default Session:\", tf.get_default_session())\n", " print()\n", " \n", "print(\"Default Graph :\", tf.get_default_graph())\n", "print(\"Default Session:\", tf.get_default_session())\n", "print()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Linear Regression: tf.estimator 사용" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "INFO:tensorflow:Using default config.\n", "WARNING:tensorflow:Using temporary folder as model directory: /var/folders/3t/087xhfzj6knbg91h3f4np1pr0000gn/T/tmphicguchu\n", "INFO:tensorflow:Using config: {'_model_dir': '/var/folders/3t/087xhfzj6knbg91h3f4np1pr0000gn/T/tmphicguchu', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': allow_soft_placement: true\n", "graph_options {\n", " rewrite_options {\n", " meta_optimizer_iterations: ONE\n", " }\n", "}\n", ", '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_device_fn': None, '_protocol': None, '_eval_distribute': None, '_experimental_distribute': None, '_service': None, '_cluster_spec': , '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}\n", "WARNING:tensorflow:From /Users/yhhan/anaconda3/lib/python3.6/site-packages/tensorflow/python/estimator/inputs/queues/feeding_queue_runner.py:62: QueueRunner.__init__ (from tensorflow.python.training.queue_runner_impl) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "To construct input pipelines, use the `tf.data` module.\n", "WARNING:tensorflow:From /Users/yhhan/anaconda3/lib/python3.6/site-packages/tensorflow/python/estimator/inputs/queues/feeding_functions.py:500: add_queue_runner (from tensorflow.python.training.queue_runner_impl) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "To construct input pipelines, use the `tf.data` module.\n", "INFO:tensorflow:Calling model_fn.\n", "INFO:tensorflow:Done calling model_fn.\n", "INFO:tensorflow:Create CheckpointSaverHook.\n", "INFO:tensorflow:Graph was finalized.\n", "INFO:tensorflow:Running local_init_op.\n", "INFO:tensorflow:Done running local_init_op.\n", "WARNING:tensorflow:From /Users/yhhan/anaconda3/lib/python3.6/site-packages/tensorflow/python/training/monitored_session.py:804: start_queue_runners (from tensorflow.python.training.queue_runner_impl) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "To construct input pipelines, use the `tf.data` module.\n", "INFO:tensorflow:Saving checkpoints for 0 into /var/folders/3t/087xhfzj6knbg91h3f4np1pr0000gn/T/tmphicguchu/model.ckpt.\n", "INFO:tensorflow:loss = 583.40393, step = 1\n", "INFO:tensorflow:global_step/sec: 134.283\n", "INFO:tensorflow:loss = 392.1066, step = 101 (0.746 sec)\n", "INFO:tensorflow:global_step/sec: 164.817\n", "INFO:tensorflow:loss = 259.70663, step = 201 (0.607 sec)\n", "INFO:tensorflow:Saving checkpoints for 300 into /var/folders/3t/087xhfzj6knbg91h3f4np1pr0000gn/T/tmphicguchu/model.ckpt.\n", "INFO:tensorflow:Loss for final step: 177.97446.\n", "INFO:tensorflow:Calling model_fn.\n", "INFO:tensorflow:Done calling model_fn.\n", "INFO:tensorflow:Starting evaluation at 2019-03-11-14:54:59\n", "INFO:tensorflow:Graph was finalized.\n", "INFO:tensorflow:Restoring parameters from /var/folders/3t/087xhfzj6knbg91h3f4np1pr0000gn/T/tmphicguchu/model.ckpt-300\n", "INFO:tensorflow:Running local_init_op.\n", "INFO:tensorflow:Done running local_init_op.\n", "INFO:tensorflow:Finished evaluation at 2019-03-11-14:54:59\n", "INFO:tensorflow:Saving dict for global step 300: average_loss = 184.05464, global_step = 300, label/mean = 22.53281, loss = 184.05464, prediction/mean = 10.174241\n", "INFO:tensorflow:Saving 'checkpoint_path' summary for global step 300: /var/folders/3t/087xhfzj6knbg91h3f4np1pr0000gn/T/tmphicguchu/model.ckpt-300\n", "{'average_loss': 184.05464, 'label/mean': 22.53281, 'loss': 184.05464, 'prediction/mean': 10.174241, 'global_step': 300}\n", "Default Graph : \n", "Default Session: None\n" ] } ], "source": [ "feature_column = [tf.feature_column.numeric_column(key='x', shape=13)]\n", "\n", "train_input_fn = tf.estimator.inputs.numpy_input_fn(\n", " {'x': x_data}, y_data, shuffle=True, batch_size=506, num_epochs=300\n", ")\n", "\n", "eval_input_fn = tf.estimator.inputs.numpy_input_fn(\n", " {'x': x_data}, y_data, shuffle=True, batch_size=506, num_epochs=1\n", ")\n", "\n", "reg = tf.estimator.LinearRegressor(\n", " feature_columns=feature_column,\n", " optimizer=tf.train.GradientDescentOptimizer(learning_rate=0.001),\n", " loss_reduction=tf.losses.Reduction.MEAN\n", ")\n", "\n", "reg.train(input_fn=train_input_fn)\n", "\n", "MSE = reg.evaluate(input_fn=eval_input_fn)\n", "\n", "print(MSE)\n", "\n", "print(\"Default Graph :\", tf.get_default_graph())\n", "print(\"Default Session:\", tf.get_default_session())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 9.1 설치" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```\n", "cd $ML_PATH\n", "source env/bin/activate\n", "\n", "pip3 install --upgrade tensorflow\n", "\n", "python3 -c 'import tensorflow; print(tensorflow.__version__)'\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 9.2 첫 번째 계산 그래프를 만들어 세션에서 실행하기" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Default Graph : \n", "Default Session: None\n" ] } ], "source": [ "print(\"Default Graph :\", tf.get_default_graph())\n", "print(\"Default Session:\", tf.get_default_session())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- 계산 그래프 생성\n", " - 아래 코드는 계산 그래프만 생성\n", " - 어떠한 계산도 수행되지 않음\n", " - 변수조차도 실제로 초기화되지 않음" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Default Graph : \n", "Default Session: None\n", "Default Graph : \n", "Default Session: None\n", "Tensor(\"add_1:0\", shape=(), dtype=int32)\n" ] } ], "source": [ "tf.reset_default_graph()\n", "print(\"Default Graph :\", tf.get_default_graph())\n", "print(\"Default Session:\", tf.get_default_session())\n", "\n", "x = tf.Variable(3, name=\"x\")\n", "y = tf.Variable(4, name=\"y\")\n", "f = x*x*y + y + 2\n", "\n", "print(\"Default Graph :\", tf.get_default_graph())\n", "print(\"Default Session:\", tf.get_default_session())\n", "print(f)" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ]" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.get_default_graph().get_operations()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- 세션 생성 후 개별적인 변수 노드 초기화 및 연산 노드 실행 (평가)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "42\n", "Default Graph : \n", "Default Session: None\n" ] } ], "source": [ "sess = tf.Session()\n", "\n", "sess.run(x.initializer)\n", "sess.run(y.initializer)\n", "result = sess.run(f)\n", "print(result)\n", "print(\"Default Graph :\", tf.get_default_graph())\n", "print(\"Default Session:\", tf.get_default_session())\n", "\n", "sess.close()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- with 블록을 활용한 default session 지정\n", " - with 블록 내부의 sess는 default session\n", " - with 블록이 끝나면 sess는 자동 종료\n", " \n", "- default session이 생성된 상황에서는 run() 호출 가능\n", " - x.initializer.run() == tf.get_default_session().run(x.initializer)\n", " - f.eval() == tf.get_default_session().run(f)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Default Graph : \n", "Default Session: None\n", "\n", "Default Graph : \n", "Default Session: \n", "True\n", "\n", "42\n", "Default Graph : \n", "Default Session: None\n" ] } ], "source": [ "print(\"Default Graph :\", tf.get_default_graph())\n", "print(\"Default Session:\", tf.get_default_session())\n", "print()\n", "\n", "with tf.Session() as sess:\n", " x.initializer.run()\n", " y.initializer.run()\n", " result = f.eval()\n", " print(\"Default Graph :\", tf.get_default_graph())\n", " print(\"Default Session:\", tf.get_default_session())\n", " print(sess is tf.get_default_session()) \n", " print()\n", "\n", "print(result)\n", "print(\"Default Graph :\", tf.get_default_graph())\n", "print(\"Default Session:\", tf.get_default_session())" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Default Graph : \n", "Default Session: None\n", "\n", "Default Graph : \n", "Default Session: \n", "True\n", "\n", "42\n", "Default Graph : \n", "Default Session: None\n" ] } ], "source": [ "print(\"Default Graph :\", tf.get_default_graph())\n", "print(\"Default Session:\", tf.get_default_session())\n", "print()\n", "\n", "with tf.Session() as sess:\n", " tf.get_default_session().run(x.initializer)\n", " tf.get_default_session().run(y.initializer)\n", " result = tf.get_default_session().run(f)\n", " print(\"Default Graph :\", tf.get_default_graph())\n", " print(\"Default Session:\", tf.get_default_session())\n", " print(sess is tf.get_default_session()) \n", " print()\n", "\n", "print(result)\n", "print(\"Default Graph :\", tf.get_default_graph())\n", "print(\"Default Session:\", tf.get_default_session())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- 각 변수를 개별적으로 초기화하는 대신 global_variables_initialzer() 함수 사용" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "42\n", "Default Graph : \n", "Default Session: None\n" ] } ], "source": [ "init = tf.global_variables_initializer()\n", "\n", "with tf.Session():\n", " init.run() # 실제 모든 변수 초기화\n", " result = f.eval()\n", "\n", "print(result)\n", "print(\"Default Graph :\", tf.get_default_graph())\n", "print(\"Default Session:\", tf.get_default_session())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- InteractiveSession 사용\n", " - InteractiveSession이 생성되면 생성된 session 이 default session 으로 지정됨" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Default Graph : \n", "Default Session: None\n", "\n", "Default Graph : \n", "Default Session: \n", "\n", "42\n", "Default Graph : \n", "Default Session: None\n" ] } ], "source": [ "print(\"Default Graph :\", tf.get_default_graph())\n", "print(\"Default Session:\", tf.get_default_session())\n", "print()\n", "init = tf.global_variables_initializer()\n", "\n", "sess = tf.InteractiveSession()\n", "print(\"Default Graph :\", tf.get_default_graph())\n", "print(\"Default Session:\", tf.get_default_session())\n", "print()\n", "\n", "init.run()\n", "result = f.eval()\n", "sess.close()\n", "\n", "print(result)\n", "print(\"Default Graph :\", tf.get_default_graph())\n", "print(\"Default Session:\", tf.get_default_session())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 9.3 계산 그래프 관리" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- 노드를 만들면 자동으로 default graph에 추가" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Default Graph : \n", "Default Session: None\n", "\n", "Default Graph : \n", "Default Session: None\n", "\n", "True\n" ] } ], "source": [ "print(\"Default Graph :\", tf.get_default_graph())\n", "print(\"Default Session:\", tf.get_default_session())\n", "print()\n", "\n", "tf.reset_default_graph()\n", "print(\"Default Graph :\", tf.get_default_graph())\n", "print(\"Default Session:\", tf.get_default_session())\n", "print()\n", "\n", "x1 = tf.Variable(1)\n", "print(x1.graph is tf.get_default_graph())" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Default Graph : \n", "Default Session: None\n", "\n", "False\n", "True\n", "True\n", "False\n", "True\n" ] } ], "source": [ "print(\"Default Graph :\", tf.get_default_graph())\n", "print(\"Default Session:\", tf.get_default_session())\n", "print()\n", "\n", "graph = tf.Graph()\n", "print(graph is tf.get_default_graph())\n", "\n", "with graph.as_default():\n", " x2 = tf.Variable(2)\n", " print(graph is tf.get_default_graph()) \n", " print(x2.graph is tf.get_default_graph())\n", " \n", "print(x2.graph is tf.get_default_graph()) # graph (== x2.graph)는 디폴트 그래프에서 분리된 다른 그래프\n", "print(x2.graph is graph)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- ***[주의]***\n", " - Tensorflow 코딩을 하는 동안 default graph에 중복되거나 불필요한 노드가 포함될 수 있음\n", " - 그러므로, 코드 시작시에 tf.reset_default_graph()로 default graph를 초기화하는 습관 필요" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 9.4 노드 값의 생애주기" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- 임의의 노드 평가 --> 이 노드가 의존하고 있는 다른 노드들을 자동으로 먼저 찾아 평가" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tensor(\"Const:0\", shape=(), dtype=int32)\n", "Tensor(\"add:0\", shape=(), dtype=int32)\n", "Tensor(\"add_1:0\", shape=(), dtype=int32)\n", "Tensor(\"mul:0\", shape=(), dtype=int32)\n", "\n", "10\n", "15\n" ] } ], "source": [ "w = tf.constant(3)\n", "x = w + 2\n", "y = x + 5\n", "z = x * 3\n", "\n", "print(w)\n", "print(x)\n", "print(y)\n", "print(z)\n", "print()\n", "with tf.Session() as sess:\n", " print(y.eval()) # 10\n", " print(z.eval()) # 15" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- 위 코드의 단점\n", " - w와 x가 두번 평가됨\n", " - 즉, 상수 노드에 대해서는 평가된 노드의 값은 한번의 eval() 실행이후 세션 내에서 사라짐\n", "- 아래 코드는 개선된 코드\n", " - sess.run()을 통해서 한번 그래프 실행으로 w와 x는 한번만 평가됨" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "10\n", "15\n" ] } ], "source": [ "with tf.Session() as sess:\n", " y_val, z_val = sess.run([y, z])\n", " print(y_val) # 10\n", " print(z_val) # 15" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- 변수 노드에 대해서는 eval() 이후에도 세션 내에 유지됨\n", "- 변수의 일생\n", " - 변수가 초기화될 때 시작\n", " - 세션이 종료가 되면 내용이 사라짐" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- 단일 프로세스 텐서플로우에서는 여러 세션에서 동일한 그래프를 재사용하더라도 어떤 상태도 공유하지 않음" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 9.5 텐서플로우를 이용한 선형 회귀" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(20640, 8)\n", "(20640, 9)\n", "\n", "(20640,)\n", "(20640, 1)\n" ] } ], "source": [ "import numpy as np\n", "from sklearn.datasets import fetch_california_housing\n", "import tensorflow as tf\n", "\n", "housing = fetch_california_housing()\n", "print(housing.data.shape)\n", "\n", "m = housing.data.shape[0]\n", "\n", "# 각 훈련 샘플에 편향 특성(x_0 = 1) 추가\n", "housing_data_plus_bias = np.c_[np.ones(shape=(m, 1)), housing.data]\n", "print(housing_data_plus_bias.shape)\n", "\n", "print()\n", "\n", "print(housing.target.shape)\n", "housing_target = housing.target.reshape(-1, 1)\n", "print(housing_target.shape)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- np.c_\n", " - 두 개의 배열을 열 방향 (두번째 축)으로 합침" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- 선형회귀 (Linear Regression)\n", " - https://nbviewer.jupyter.org/github/bluebibi/LINK_ML_BIG_DATA/blob/master/linear_regression.ipynb\n", " - 본 교재의 Ch. 4.1 ~ 4.5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- $X$: (20640, 9) <-- housing_data_plus_bias\n", "- $y$: (20640, 1) <-- housing_target\n", "- $\\theta$: (9, 1) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- $X$, $\\theta$, $y$를 사용한 Linear Equation\n", " - $y = X\\cdot\\theta$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- $\\theta$를 도출하는 정규방정식 (Ch. 4.1 ~ 4.5 참조)\n", " - $\\theta = (X^T \\cdot X)^{-1} \\cdot X^T \\cdot y$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- $X^T$: (9, 20640)\n", "- $X^T \\cdot X$: (9, 9)\n", "- $(X^T \\cdot X)^{-1}$: (9, 9)\n", "- $(X^T \\cdot X)^{-1} \\cdot X^T$: (9, 20640)\n", "- $(X^T \\cdot X)^{-1} \\cdot X^T \\cdot y$: (9, 1)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[-3.69419202e+01]\n", " [ 4.36693293e-01]\n", " [ 9.43577803e-03]\n", " [-1.07322041e-01]\n", " [ 6.45065694e-01]\n", " [-3.97638942e-06]\n", " [-3.78654265e-03]\n", " [-4.21314378e-01]\n", " [-4.34513755e-01]]\n" ] } ], "source": [ "tf.reset_default_graph()\n", "\n", "X = tf.constant(housing_data_plus_bias, dtype=tf.float64, name=\"X\")\n", "y = tf.constant(housing_target, dtype=tf.float64, name=\"y\")\n", "XT = tf.transpose(X)\n", "theta = tf.matmul(tf.matmul(tf.matrix_inverse(tf.matmul(XT, X)), XT), y)\n", "\n", "with tf.Session() as sess:\n", " result = theta.eval()\n", "\n", "print(result)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Numpy 또는 Scipy 라이브러리 대신 위 Tensorflow 라이브러리를 이용할 때의 장점\n", " - GPU 사용 가능 (12장 참조)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 9.6 경사 하강법 구현\n", "- 정규 방정식 대신 경사 하강법을 활용하여 $\\theta$를 구하기\n", "- 경사 하강법 구현 방법\n", " - 1) 직접 gradient 계산\n", " - 2) Tensorflow의 자동 미분 (autodiff) 사용\n", " - 3) Tensorflow의 내장 optimizer 사용" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- 경사 하강법 사용시에는 입력 특성 정규화 중요\n", " - scikit-learn의 StandardScaler 사용" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "from sklearn.preprocessing import StandardScaler\n", "scaler = StandardScaler()\n", "scaled_housing_data = scaler.fit_transform(housing.data)\n", "scaled_housing_data_plus_bias = np.c_[np.ones((m, 1)), scaled_housing_data]" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 1.00000000e+00 6.60969987e-17 5.50808322e-18 6.60969987e-17\n", " -1.06030602e-16 -1.10161664e-17 3.44255201e-18 -1.07958431e-15\n", " -8.52651283e-15]\n", "(20640, 9)\n" ] } ], "source": [ "print(scaled_housing_data_plus_bias.mean(axis=0))\n", "print(scaled_housing_data_plus_bias.shape)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 9.6.1 직접 gradient 계산" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Mean Sqaure Error (MSE)\n", "$$J(\\theta)= \\frac{1}{m} \\sum(X \\cdot \\theta - y)^2$$\n", "- Gradient of MSE \n", "$$J'(\\theta) = \\frac{2}{m} X^T \\cdot (X \\cdot \\theta - y)$$\n", " - $X^T$: (9, 20640)\n", " - $X$: (20640, 9) <-- scaled_housing_data_plus_bias\n", " - $\\theta$: (9, 1) \n", " - $X \\cdot \\theta$: (20640, 1)\n", " - $y$: (20640, 1) <-- housing_target\n", " \n", " \n", "- Gradient descent for getting $\\theta$\n", " - $$\\theta = \\theta - \\alpha J'(\\theta)$$" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number of samples: 20640, Number of features: 9\n", "\n", "Epoch 0 MSE = 2.7544272\n", "Epoch 100 MSE = 0.6322218\n", "Epoch 200 MSE = 0.57277966\n", "Epoch 300 MSE = 0.5585006\n", "Epoch 400 MSE = 0.5490694\n", "Epoch 500 MSE = 0.5422878\n", "Epoch 600 MSE = 0.5373788\n", "Epoch 700 MSE = 0.5338218\n", "Epoch 800 MSE = 0.5312427\n", "Epoch 900 MSE = 0.5293706\n", "Best theta: \n", "[[ 2.0685523e+00]\n", " [ 7.7407807e-01]\n", " [ 1.3119239e-01]\n", " [-1.1784514e-01]\n", " [ 1.6477820e-01]\n", " [ 7.4408232e-04]\n", " [-3.9194513e-02]\n", " [-8.6135650e-01]\n", " [-8.2347965e-01]]\n" ] } ], "source": [ "tf.reset_default_graph()\n", "\n", "learning_rate = 0.01\n", "\n", "m, n = scaled_housing_data_plus_bias.shape\n", "print(\"Number of samples: {0}, Number of features: {1}\".format(m, n))\n", "print()\n", "\n", "X = tf.constant(scaled_housing_data_plus_bias, dtype=tf.float32, name=\"X\")\n", "y = tf.constant(housing_target, dtype=tf.float32, name=\"y\")\n", "\n", "theta = tf.Variable(\n", " tf.random_uniform(shape=[n, 1], minval=-1.0, maxval=1.0, seed=42), \n", " name=\"theta\"\n", ")\n", "\n", "y_pred = tf.matmul(X, theta, name=\"predictions\")\n", "error = y_pred - y\n", "mse = tf.reduce_mean(tf.square(error), name=\"mse\")\n", "\n", "gradients = 2/m * tf.matmul(tf.transpose(X), error)\n", "training_op = tf.assign(theta, theta - learning_rate * gradients)\n", "\n", "init = tf.global_variables_initializer()\n", "\n", "n_epochs = 1000\n", "\n", "with tf.Session() as sess:\n", " sess.run(init)\n", "\n", " for epoch in range(n_epochs):\n", " if epoch % 100 == 0:\n", " print(\"Epoch\", epoch, \"MSE =\", mse.eval())\n", " sess.run(training_op)\n", " \n", " best_theta = theta.eval()\n", "\n", "print(\"Best theta: \\n{0}\".format(best_theta))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 9.6.2 직접 gradient 계산\n", "- 후진 모드 자동 미분 (Backword Propagation - Autodiff)\n", "- ***gradients = tf.gradients(mse, [theta])[0]***" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[5.0]\n" ] } ], "source": [ "x = tf.constant(2.0)\n", "y = x**2 + x - 1\n", "\n", "grad = tf.gradients(y, x)\n", "\n", "init = tf.global_variables_initializer()\n", "\n", "with tf.Session() as sess:\n", " sess.run(init)\n", " grad_value = sess.run(grad)\n", " print(grad_value)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number of samples: 20640, Number of features: 9\n", "\n", "Epoch 0 MSE = 2.7544272\n", "Epoch 100 MSE = 0.6322219\n", "Epoch 200 MSE = 0.57277966\n", "Epoch 300 MSE = 0.5585006\n", "Epoch 400 MSE = 0.54906934\n", "Epoch 500 MSE = 0.54228777\n", "Epoch 600 MSE = 0.5373788\n", "Epoch 700 MSE = 0.5338219\n", "Epoch 800 MSE = 0.5312427\n", "Epoch 900 MSE = 0.5293704\n", "Best theta: \n", "[[ 2.0685525e+00]\n", " [ 7.7407807e-01]\n", " [ 1.3119237e-01]\n", " [-1.1784511e-01]\n", " [ 1.6477817e-01]\n", " [ 7.4407971e-04]\n", " [-3.9194521e-02]\n", " [-8.6135668e-01]\n", " [-8.2347977e-01]]\n" ] } ], "source": [ "tf.reset_default_graph()\n", "\n", "learning_rate = 0.01\n", "\n", "m, n = scaled_housing_data_plus_bias.shape\n", "print(\"Number of samples: {0}, Number of features: {1}\".format(m, n))\n", "print()\n", "\n", "X = tf.constant(scaled_housing_data_plus_bias, dtype=tf.float32, name=\"X\")\n", "y = tf.constant(housing_target, dtype=tf.float32, name=\"y\")\n", "\n", "theta = tf.Variable(\n", " tf.random_uniform(shape=[n, 1], minval=-1.0, maxval=1.0, seed=42), \n", " name=\"theta\"\n", ")\n", "\n", "y_pred = tf.matmul(X, theta, name=\"predictions\")\n", "error = y_pred - y\n", "mse = tf.reduce_mean(tf.square(error), name=\"mse\")\n", "\n", "###\n", "gradients = tf.gradients(mse, theta)[0]\n", "###\n", "training_op = tf.assign(theta, theta - learning_rate * gradients)\n", "\n", "init = tf.global_variables_initializer()\n", "\n", "n_epochs = 1000\n", "\n", "with tf.Session() as sess:\n", " sess.run(init)\n", "\n", " for epoch in range(n_epochs):\n", " if epoch % 100 == 0:\n", " print(\"Epoch\", epoch, \"MSE =\", mse.eval())\n", " sess.run(training_op)\n", " \n", " best_theta = theta.eval()\n", "\n", "print(\"Best theta: \\n{0}\".format(best_theta))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 9.6.3 Optimizer 사용\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- GradientDescentOptimizer 사용" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number of samples: 20640, Number of features: 9\n", "\n", "Epoch 0 MSE = 2.7544272\n", "Epoch 100 MSE = 0.6322219\n", "Epoch 200 MSE = 0.57277966\n", "Epoch 300 MSE = 0.5585006\n", "Epoch 400 MSE = 0.54906934\n", "Epoch 500 MSE = 0.54228777\n", "Epoch 600 MSE = 0.5373788\n", "Epoch 700 MSE = 0.5338219\n", "Epoch 800 MSE = 0.5312427\n", "Epoch 900 MSE = 0.5293704\n", "Best theta: \n", "[[ 2.0685525e+00]\n", " [ 7.7407807e-01]\n", " [ 1.3119237e-01]\n", " [-1.1784511e-01]\n", " [ 1.6477817e-01]\n", " [ 7.4407971e-04]\n", " [-3.9194521e-02]\n", " [-8.6135668e-01]\n", " [-8.2347977e-01]]\n" ] } ], "source": [ "tf.reset_default_graph()\n", "\n", "learning_rate = 0.01\n", "\n", "m, n = scaled_housing_data_plus_bias.shape\n", "print(\"Number of samples: {0}, Number of features: {1}\".format(m, n))\n", "print()\n", "\n", "X = tf.constant(scaled_housing_data_plus_bias, dtype=tf.float32, name=\"X\")\n", "y = tf.constant(housing_target, dtype=tf.float32, name=\"y\")\n", "\n", "theta = tf.Variable(\n", " tf.random_uniform(shape=[n, 1], minval=-1.0, maxval=1.0, seed=42), \n", " name=\"theta\"\n", ")\n", "\n", "y_pred = tf.matmul(X, theta, name=\"predictions\")\n", "error = y_pred - y\n", "mse = tf.reduce_mean(tf.square(error), name=\"mse\")\n", "\n", "###\n", "optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)\n", "training_op = optimizer.minimize(mse)\n", "###\n", "\n", "init = tf.global_variables_initializer()\n", "\n", "n_epochs = 1000\n", "\n", "with tf.Session() as sess:\n", " sess.run(init)\n", "\n", " for epoch in range(n_epochs):\n", " if epoch % 100 == 0:\n", " print(\"Epoch\", epoch, \"MSE =\", mse.eval())\n", " sess.run(training_op)\n", " \n", " best_theta = theta.eval()\n", "\n", "print(\"Best theta: \\n{0}\".format(best_theta))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- MomentumOptimizer 사용" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number of samples: 20640, Number of features: 9\n", "\n", "Epoch 0 MSE = 2.7544272\n", "Epoch 100 MSE = 0.5273161\n", "Epoch 200 MSE = 0.52441406\n", "Epoch 300 MSE = 0.5243281\n", "Epoch 400 MSE = 0.52432173\n", "Epoch 500 MSE = 0.524321\n", "Epoch 600 MSE = 0.52432096\n", "Epoch 700 MSE = 0.5243204\n", "Epoch 800 MSE = 0.52432066\n", "Epoch 900 MSE = 0.5243207\n", "Best theta: \n", "[[ 2.068558 ]\n", " [ 0.82961667]\n", " [ 0.11875105]\n", " [-0.26552197]\n", " [ 0.30569217]\n", " [-0.00450318]\n", " [-0.03932618]\n", " [-0.8998918 ]\n", " [-0.87054694]]\n" ] } ], "source": [ "tf.reset_default_graph()\n", "\n", "learning_rate = 0.01\n", "\n", "m, n = scaled_housing_data_plus_bias.shape\n", "print(\"Number of samples: {0}, Number of features: {1}\".format(m, n))\n", "print()\n", "\n", "X = tf.constant(scaled_housing_data_plus_bias, dtype=tf.float32, name=\"X\")\n", "y = tf.constant(housing_target, dtype=tf.float32, name=\"y\")\n", "\n", "theta = tf.Variable(\n", " tf.random_uniform(shape=[n, 1], minval=-1.0, maxval=1.0, seed=42), \n", " name=\"theta\"\n", ")\n", "\n", "y_pred = tf.matmul(X, theta, name=\"predictions\")\n", "error = y_pred - y\n", "mse = tf.reduce_mean(tf.square(error), name=\"mse\")\n", "\n", "###\n", "optimizer = tf.train.MomentumOptimizer(learning_rate=learning_rate, momentum=0.9)\n", "training_op = optimizer.minimize(mse)\n", "###\n", "\n", "init = tf.global_variables_initializer()\n", "\n", "n_epochs = 1000\n", "\n", "with tf.Session() as sess:\n", " sess.run(init)\n", "\n", " for epoch in range(n_epochs):\n", " if epoch % 100 == 0:\n", " print(\"Epoch\", epoch, \"MSE =\", mse.eval())\n", " sess.run(training_op)\n", " \n", " best_theta = theta.eval()\n", "\n", "print(\"Best theta: \\n{0}\".format(best_theta))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 9.7 훈련 알고리즘에 데이터 주입\n", "- 미니배치 경사 하강법\n", " - 매 반복 마다 $X$와 $y$를 다음번 미니배치로 변경해야 함\n", " - Placeholder 사용\n", " - 실행시에 데이터 주입\n", " - 일반적으로 계산 그래프에 훈련 데이터 또는 테스트 데이터를 전달하기 위해 사용" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[6. 7. 8.]]\n", "\n", "[[ 9. 10. 11.]\n", " [12. 13. 14.]]\n", "\n", "[[ 6. 7. 8.]\n", " [ 9. 10. 11.]\n", " [12. 13. 14.]\n", " [15. 16. 17.]]\n" ] } ], "source": [ "tf.reset_default_graph()\n", "\n", "A = tf.placeholder(tf.float32, shape=(None, 3))\n", "B = A + 5\n", "\n", "with tf.Session() as sess:\n", " B_val_1 = B.eval(feed_dict={A: [[1, 2, 3]]})\n", " B_val_2 = B.eval(feed_dict={A: [[4, 5, 6], [7, 8, 9]]})\n", " B_val_3 = B.eval(feed_dict={A: [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]})\n", "\n", "print(B_val_1, end=\"\\n\\n\")\n", "print(B_val_2, end=\"\\n\\n\")\n", "print(B_val_3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- 위 Placeholder A에는 반드시 rank가 2이고, 두번째 차원에는 3개의 원소가 있어야 함.\n", " - rank: number of dimensions (rank = len(A.shape))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- 미니배치 경사 하강법 사용 코드" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number of samples: 20640, Number of features: 9\n", "\n", "Epoch 0 MSE = 2.7544272\n", "Epoch 1 MSE = 7.1942964\n", "Epoch 2 MSE = 0.6038717\n", "Epoch 3 MSE = 0.5658047\n", "Epoch 4 MSE = 0.5324455\n", "Epoch 5 MSE = 0.5322575\n", "Epoch 6 MSE = 0.5278092\n", "Epoch 7 MSE = 0.5279042\n", "Epoch 8 MSE = 0.64588606\n", "Epoch 9 MSE = 0.6614312\n", "Best theta: \n", "[[ 2.0692444 ]\n", " [ 0.8011928 ]\n", " [ 0.11612897]\n", " [-0.25423694]\n", " [ 0.15042946]\n", " [ 0.00301097]\n", " [-0.09266656]\n", " [-0.898888 ]\n", " [-0.86405325]]\n" ] } ], "source": [ "import numpy.random as rnd\n", "\n", "tf.reset_default_graph()\n", "\n", "learning_rate = 0.01\n", "\n", "m, n = scaled_housing_data_plus_bias.shape\n", "print(\"Number of samples: {0}, Number of features: {1}\".format(m, n))\n", "print()\n", "\n", "X = tf.placeholder(tf.float32, shape=(None, n), name=\"X\")\n", "y = tf.placeholder(tf.float32, shape=(None, 1), name=\"y\")\n", "\n", "theta = tf.Variable(\n", " tf.random_uniform(shape=[n, 1], minval=-1.0, maxval=1.0, seed=42), \n", " name=\"theta\"\n", ")\n", "\n", "y_pred = tf.matmul(X, theta, name=\"predictions\")\n", "error = y_pred - y\n", "mse = tf.reduce_mean(tf.square(error), name=\"mse\")\n", "\n", "optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)\n", "training_op = optimizer.minimize(mse)\n", "\n", "\n", "def fetch_batch(epoch, batch_index, batch_size):\n", " indices = rnd.randint(m, size=batch_size)\n", " X_batch = scaled_housing_data_plus_bias[indices]\n", " y_batch = housing_target[indices]\n", " return X_batch, y_batch\n", "\n", "def fetch_batch2(epoch, batch_index, batch_size):\n", " start_idx = batch_index * batch_size\n", " end_idx = min(m, (batch_index + 1) * batch_size)\n", " X_batch = scaled_housing_data_plus_bias[start_idx: end_idx]\n", " y_batch = housing_target[start_idx: end_idx]\n", " return X_batch, y_batch\n", "\n", "n_epochs = 10\n", "batch_size = 100\n", "n_batches = int(np.ceil(m / batch_size))\n", "\n", "init = tf.global_variables_initializer()\n", "\n", "with tf.Session() as sess:\n", " sess.run(init)\n", "\n", " for epoch in range(n_epochs):\n", " print(\"Epoch\", epoch, \"MSE =\", mse.eval(\n", " feed_dict={X: scaled_housing_data_plus_bias, y: housing_target})\n", " )\n", " for batch_index in range(n_batches):\n", " X_batch, y_batch = fetch_batch(epoch, batch_index, batch_size)\n", " sess.run(training_op, feed_dict={X: X_batch, y: y_batch})\n", " \n", " best_theta = theta.eval()\n", " \n", "print(\"Best theta: \\n{0}\".format(best_theta))" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.8" } }, "nbformat": 4, "nbformat_minor": 2 }