From e168f9941edbb1b4ea699f965d9832c81d08e895 Mon Sep 17 00:00:00 2001 From: rickiepark Date: Sat, 19 May 2018 17:03:53 +0900 Subject: [PATCH] =?UTF-8?q?Data=20API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 12_distributed_tensorflow.ipynb | 296 +++++++++++++++++++++++++++++++- 1 file changed, 294 insertions(+), 2 deletions(-) diff --git a/12_distributed_tensorflow.ipynb b/12_distributed_tensorflow.ipynb index b2a3552..073fc39 100644 --- a/12_distributed_tensorflow.ipynb +++ b/12_distributed_tensorflow.ipynb @@ -249,7 +249,24 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# 리더" + "# 리더 (Reader) - 예전 방법" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "reset_graph()\n", + "\n", + "default1 = tf.constant([5.])\n", + "default2 = tf.constant([6])\n", + "default3 = tf.constant([7])\n", + "dec = tf.decode_csv(tf.constant(\"1.,,44\"),\n", + " record_defaults=[default1, default2, default3])\n", + "with tf.Session() as sess:\n", + " print(sess.run(dec))" ] }, { @@ -274,7 +291,7 @@ "\n", "test_csv = open(\"my_test.csv\", \"w\")\n", "test_csv.write(\"x1, x2 , target\\n\")\n", - "test_csv.write(\"1., , 0\\n\")\n", + "test_csv.write(\"1.,, 0\\n\")\n", "test_csv.write(\"4., 5. , 1\\n\")\n", "test_csv.write(\"7., 8. , 0\\n\")\n", "test_csv.close()\n", @@ -493,6 +510,281 @@ " print(\"dequeue 타임 아웃\")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Data API" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "텐서플로 1.4에서 소개된 Data API를 사용하면 손쉽게 데이터를 효율적으로 읽을 수 있습니다." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tf.reset_default_graph()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "0에서 9까지 정수를 세 번 반복한 간단한 데이터셋을 일곱 개씩 배치로 만들어 시작해 보죠:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "dataset = tf.data.Dataset.from_tensor_slices(np.arange(10))\n", + "dataset = dataset.repeat(3).batch(7)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "첫 번째 줄은 0에서 9까지 정수를 담은 데이터셋을 만듭니다. 두 번째 줄은 이 데이터셋의 원소를 세 번 반복하고 일곱 개씩 담은 새로운 데이터셋을 만듭니다. 위에서 볼 수 있듯이 원본 데이터셋에서 여러 변환 메서드를 연결하여 호출하여 적용했습니다." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "그다음, 데이터셋을 한 번 순회하는 원-샷-이터레이터(one-shot-iterator)를 만들고, 다음 원소를 지칭하는 텐서를 얻기 위해 `get_next()` 메서드를 호출합니다." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "iterator = dataset.make_one_shot_iterator()\n", + "next_element = iterator.get_next()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`next_element`를 반복적으로 평가해서 데이터셋을 순회해 보죠. 원소가 별로 없기 때문에 `OutOfRangeError`가 발생합니다:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "with tf.Session() as sess:\n", + " try:\n", + " while True:\n", + " print(next_element.eval())\n", + " except tf.errors.OutOfRangeError:\n", + " print(\"완료\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "좋네요! 잘 작동합니다." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "늘 그렇듯이 텐서는 그래프를 실행(`sess.run()`)할 때마다 한 번만 평가된다는 것을 기억하세요. `next_element`에 의존하는 텐서를 여러개 평가하더라도 한 번만 평가됩니다. 또한 `next_element`를 동시에 두 번 실행해도 마찬가지입니다:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "with tf.Session() as sess:\n", + " try:\n", + " while True:\n", + " print(sess.run([next_element, next_element]))\n", + " except tf.errors.OutOfRangeError:\n", + " print(\"완료\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`interleave()` 메서드는 강력하지만 처음에는 이해하기 좀 어렵습니다. 예제를 통해 이해하는 것이 가장 좋습니다:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tf.reset_default_graph()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "dataset = tf.data.Dataset.from_tensor_slices(np.arange(10))\n", + "dataset = dataset.repeat(3).batch(7)\n", + "dataset = dataset.interleave(\n", + " lambda v: tf.data.Dataset.from_tensor_slices(v),\n", + " cycle_length=3,\n", + " block_length=2)\n", + "iterator = dataset.make_one_shot_iterator()\n", + "next_element = iterator.get_next()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "with tf.Session() as sess:\n", + " try:\n", + " while True:\n", + " print(next_element.eval(), end=\",\")\n", + " except tf.errors.OutOfRangeError:\n", + " print(\"완료\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`cycle_length=3`이므로 새로운 데이터셋은 이전 데이터셋에서 세 개의 원소를 추출합니다. 즉 `[0,1,2,3,4,5,6]`, `[7,8,9,0,1,2,3]`, `[4,5,6,7,8,9,0]` 입니다. 그다음 원소마다 하나의 데이터셋을 만들기 위해 람다(lambda) 함수를 호출합니다. `Dataset.from_tensor_slices()`를 사용했기 때문에 각 데이터셋은 차례대로 원소를 반환합니다. 다음 이 세 개의 데이터셋에서 각각 두 개의 아이템(`block_length=2`이므로)을 추출합니다. 세 개의 데이터셋의 아이템이 모두 소진될 때까지 반복됩니다. 즉 0,1 (첫 번째에서), 7,8 (두 번째에서), 4,5 (세 번째에서), 2,3 (첫 번째에서), 9,0 (두 번째에서) 등과 같은 식으로 8,9 (세 번째에서), 6 (첫 번째에서), 3 (두 번째에서), 0 (세 번째에서)까지 진행됩니다. 그다음에 원본 데이터셋에서 다음 번 세 개의 원소를 추출하려고 합니다. 하지만 두 개만 남아 있습니다. `[1,2,3,4,5,6,7]`와 `[8,9]` 입니다. 다시 이 원소로부터 데이터셋을 만들고 이 데이텃세의 아이템이 모두 소진될 때까지 두 개의 아이템을 추출합니다. 1,2 (첫 번째에서), 8,9 (두 번째에서), 3,4 (첫 번째에서), 5,6 (첫 번째에서), 7 (첫 번째에서)가 됩니다. 배열의 길이가 다르기 때문에 마지막에는 교대로 배치되지 않았습니다." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 리더 (Reader) - 새로운 방법" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`from_tensor_slices()`나 `from_tensor()`를 기반으로 한 원본 데이터셋을 사용하는 대신 리더 데이터셋을 사용할 수 있습니다. 복잡한 일들을 대부분 대신 처리해 줍니다(예를 들면, 스레드):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tf.reset_default_graph()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "filenames = [\"my_test.csv\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "dataset = tf.data.TextLineDataset(filenames)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "각 줄을 어떻게 디코드해야 하는지는 알려 주어야 합니다:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def decode_csv_line(line):\n", + " x1, x2, y = tf.decode_csv(\n", + " line, record_defaults=[[-1.], [-1.], [-1.]])\n", + " X = tf.stack([x1, x2])\n", + " return X, y" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "그다음, 이 디코딩 함수를 `map()`을 사용하여 데이터셋에 있는 각 원소에 적용할 수 있습니다:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "dataset = dataset.skip(1).map(decode_csv_line)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "마지막으로 원-샷-이터레이터를 만들어 보죠:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "it = dataset.make_one_shot_iterator()\n", + "X, y = it.get_next()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "with tf.Session() as sess:\n", + " try:\n", + " while True:\n", + " X_val, y_val = sess.run([X, y])\n", + " print(X_val, y_val)\n", + " except tf.errors.OutOfRangeError as ex:\n", + " print(\"완료\")" + ] + }, { "cell_type": "markdown", "metadata": {