diff --git a/_static/custom.css b/_static/custom.css new file mode 100644 index 0000000..194630d --- /dev/null +++ b/_static/custom.css @@ -0,0 +1,3 @@ +html[data-theme="light"] { + --sbt-color-announcement: rgb(125, 125, 125); +} \ No newline at end of file diff --git a/ch-ray-core/ray-intro.md b/ch-ray-core/ray-intro.md index 7524281..f421817 100644 --- a/ch-ray-core/ray-intro.md +++ b/ch-ray-core/ray-intro.md @@ -17,12 +17,12 @@ Ray Core 提供的 API 将 Python 任务横向扩展到集群上,最关键的 * 行动者(Actor):面向类(Class)的接口,用于定义一个类,该类可以在集群中分布式地执行。 * 对象(Object):分布式的对象,对象不可变(Immutable),用于在 Task 和 Actor 之间传递数据。 +上层的各类生态均基于 Ray Core 的这些底层 API,结合各类人工智能应用编写而成。 + ```{figure} ../img/ch-ray-core/ray-apis.svg --- width: 800px name: ray-core-apis --- Ray Core 核心 API -``` - -上层的各类生态均基于 Ray Core 的这些底层 API,结合各类人工智能应用编写而成。 \ No newline at end of file +``` \ No newline at end of file diff --git a/ch-ray-core/remote-class.ipynb b/ch-ray-core/remote-class.ipynb index 64d3933..d5cf0cf 100644 --- a/ch-ray-core/remote-class.ipynb +++ b/ch-ray-core/remote-class.ipynb @@ -12,7 +12,7 @@ "\n", "{numref}`remote-function` 展示了如何将一个无状态的函数扩展到 Ray 集群上进行分布式计算,但实际的场景中,我们经常需要进行有状态的计算。最简单的有状态计算包括维护一个计数器,每遇到某种条件,计数器加一。这类有状态的计算对于给定的输入,不一定得到确定的输出。单机场景我们可以使用 Python 的类(Class)来实现,计数器可作为类的成员变量。Ray 可以将 Python 类拓展到集群上,即远程类(Remote Class),又被称为行动者(Actor)。Actor 的名字来自 Actor 编程模型 {cite}`hewitt1973Universal` ,这是一个典型的分布式计算编程模型,被广泛应用在大数据和人工智能领域,但 Actor 编程模型比较抽象,我们先从计数器的案例来入手。\n", "\n", - "## 案例1:分布式计数器\n" + "## 案例1:分布式计数器" ] }, { @@ -38,7 +38,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "c873d22011234552a5da4bb3bfc9f76f", + "model_id": "05fad1c7643f4f028f2ee9cb6097f749", "version_major": 2, "version_minor": 0 }, @@ -62,24 +62,20 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", - " \n", + " \n", " \n", - " \n", - " \n", - " \n", - "\n", - "\n", + " \n", "
Python version:3.10.133.11.7
Ray version:2.7.02.9.0
Dashboard:http://127.0.0.1:8265
\n", "\n", " \n", "\n" ], "text/plain": [ - "RayContext(dashboard_url='127.0.0.1:8265', python_version='3.10.13', ray_version='2.7.0', ray_commit='b4bba4717f5ba04ee25580fe8f88eed63ef0c5dc', protocol_version=None)" + "RayContext(dashboard_url='', python_version='3.11.7', ray_version='2.9.0', ray_commit='9be5a16e3ccad0710bba08d0f75e9ff774ae6880', protocol_version=None)" ] }, "execution_count": 1, @@ -104,7 +100,7 @@ "origin_pos": 2 }, "source": [ - "Ray 的 Remote Class 也使用 [`ray.remote()`](https://docs.ray.io/en/latest/ray-core/api/doc/ray.remote.html) 来装饰。\n" + "Ray 的 Remote Class 也使用 [`ray.remote()`](https://docs.ray.io/en/latest/ray-core/api/doc/ray.remote.html) 来装饰。" ] }, { @@ -145,7 +141,7 @@ "origin_pos": 4 }, "source": [ - "使用 Ray 创建一个类名为 `Counter` 的 Remote Class,需要在类名 `Counter` 后面加上 `remote()`。这样创建的类就是一个分布式的 Actor。\n" + "初始化一个实例,在类名 `Counter` 后面加上 `remote()`,即创建一个分布式的 Actor。" ] }, { @@ -176,7 +172,7 @@ "origin_pos": 6 }, "source": [ - "接下来我们要使用 `Counter` 类的计数功能:`increment()` 函数,我们也要在函数后面添加 `remote()` ,即 `对象实例.函数名.remote()`。\n" + "接下来我们要使用 `Counter` 类的计数功能:`increment()` 函数,我们也要在函数后面添加 `remote()` ,即 `对象实例.函数名.remote()`。" ] }, { @@ -216,7 +212,7 @@ "origin_pos": 8 }, "source": [ - "我们可以用同一个类创建不同的 Actor 实例,不同 Actor 之间的成员函数调用可以被并行化执行,但同一个 Actor 的成员函数调用是顺序执行的。\n" + "我们可以用同一个类创建不同的 Actor 实例,不同 Actor 之间的成员函数调用可以被并行化执行,但同一个 Actor 的成员函数调用是顺序执行的。" ] }, { @@ -236,13 +232,6 @@ ] }, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[2m\u001b[33m(raylet)\u001b[0m [2023-10-31 17:16:11,991 E 64054 59177832] (raylet) file_system_monitor.cc:111: /tmp/ray/session_2023-10-31_17-15-57_239394_63766 is over 95% full, available space: 49435729920; capacity: 1000240963584. Object creation will fail if spilling is required.\n" - ] - }, { "name": "stdout", "output_type": "stream", @@ -329,7 +318,7 @@ "\n", "## 案例2:排行榜\n", "\n", - "接下来我们基于 Actor 实现一个更加复杂的案例:成绩排行榜。这个排行榜的状态是一个键值对,名为 `self.board`,键是名字(`name`),是一个 `str` 类型,值是分数(`score`),是一个 `float` 类型。\n" + "接下来我们基于 Actor 实现一个更加复杂的案例:成绩排行榜。这个排行榜的状态是一个键值对,名为 `self.board`,键是名字(`name`),是一个 `str` 类型,值是分数(`score`),是一个 `float` 类型。" ] }, { @@ -397,7 +386,7 @@ "* `add()`:添加一条新记录,同时对输入进行解析,如果 `score` 不能转换成 `float` 会抛出异常;并对已有记录排序。\n", "* `pop()`:删除最大值的那条记录,如果 `self.board` 为空,会抛出异常。\n", "\n", - "使用 `.remote()` 函数来创建这个 Remote Class 对应的 Actor 实例。\n" + "使用 `.remote()` 函数来创建这个 Remote Class 对应的 Actor 实例。" ] }, { @@ -431,7 +420,7 @@ "source": [ "这里的 `ranking` 是一个 Actor 的引用(Actor Handle),有点像 `ObjectRef`,我们用 `ranking` 这个 Actor Handle 来管理这个 Actor。一旦 Actor Handle 被销毁,对应的 Actor 以及其状态也被销毁。\n", "\n", - "我们可以创建多个 Actor 实例,每个实例管理自己的状态。还可以用 [`ActorClass.options`](https://docs.ray.io/en/latest/ray-core/api/doc/ray.actor.ActorClass.options.html) 给这些 Actor 实例设置一些选项,起名字,设置 CPU、GPU 计算资源等。\n" + "我们可以创建多个 Actor 实例,每个实例管理自己的状态。还可以用 [`ActorClass.options`](https://docs.ray.io/en/latest/ray-core/api/doc/ray.actor.ActorClass.options.html) 给这些 Actor 实例设置一些选项,起名字,设置 CPU、GPU 计算资源等。" ] }, { @@ -468,7 +457,7 @@ "origin_pos": 18 }, "source": [ - "有了名字之后,就可以通过 [`ray.get_actor()`](https://docs.ray.io/en/latest/ray-core/api/doc/ray.get_actor.html) 来获取 Actor Handle,\n" + "有了名字之后,就可以通过 [`ray.get_actor()`](https://docs.ray.io/en/latest/ray-core/api/doc/ray.get_actor.html) 来获取 Actor Handle," ] }, { @@ -500,7 +489,7 @@ "origin_pos": 20 }, "source": [ - "向 `ranking` 排行榜内添加新记录,即调用 `add()` 函数。调用类成员函数,都要记得加上 `.remote()` ,否则会报错。\n" + "向 `ranking` 排行榜内添加新记录,即调用 `add()` 函数。调用类成员函数,都要记得加上 `.remote()` ,否则会报错。" ] }, { @@ -575,7 +564,7 @@ "origin_pos": 23 }, "source": [ - "在上面的案例中,有些调用会引发异常,比如插入一个字符串,Ray 通常会处理异常并打印出来,但是为了保险起见,你也可以在调用这些 Remote Class 的成员方法时手动做好 `try/except` 的异常捕获:\n" + "在上面的案例中,有些调用会引发异常,比如插入一个字符串,Ray 通常会处理异常并打印出来,但是为了保险起见,你也可以在调用这些 Remote Class 的成员方法时手动做好 `try/except` 的异常捕获:" ] }, { @@ -588,25 +577,11 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[2m\u001b[36m(Ranking pid=53871)\u001b[0m The data type of score should be float but we receive .\n", - "\u001b[36mray::Ranking.pop()\u001b[39m (pid=53871, ip=127.0.0.1, actor_id=b765fed53d3f5536b2056cd901000000, repr=<__main__.Ranking object at 0x7fcb041eb730>)\n", - " File \"/var/folders/4n/v40br47s46ggrjm9bdm64lwh0000gn/T/ipykernel_53185/1570506600.py\", line 29, in pop\n", - "Exception: The board is empty.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[2m\u001b[36m(Ranking pid=64481)\u001b[0m The data type of score should be float but we receive .\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[36mray::Ranking.pop()\u001b[39m (pid=64481, ip=127.0.0.1, actor_id=b0dd04160e75747cf6ebc7de01000000, repr=<__main__.Ranking object at 0x7fb6f9f92c20>)\n", - " File \"/var/folders/4n/v40br47s46ggrjm9bdm64lwh0000gn/T/ipykernel_63766/1570506600.py\", line 29, in pop\n", + "\u001b[36m(Ranking pid=94276)\u001b[0m The data type of score should be float but we receive .\n", + "\u001b[36mray::Ranking.pop()\u001b[39m (pid=94276, ip=127.0.0.1, actor_id=ad9e8acb97292b765b95c42501000000, repr=<__main__.Ranking object at 0x10348d690>)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/var/folders/4n/v40br47s46ggrjm9bdm64lwh0000gn/T/ipykernel_94239/1570506600.py\", line 29, in pop\n", "Exception: The board is empty.\n" ] } @@ -627,7 +602,7 @@ "source": [ "## 案例3:Actor Pool\n", "\n", - "实践上,经常创建一个 Actor 资源池(Actor Pool),[Actor Pool](https://docs.ray.io/en/latest/ray-core/api/doc/ray.util.ActorPool.html) 有点像 `multiprocessing.Pool`,Actor Pool 中有包含多个 Actor,每个 Actor 功能一样,而且可以分式地在多个计算节点上运行。" + "实践上,经常创建一个 Actor 资源池(Actor Pool),[`ActorPool`](https://docs.ray.io/en/latest/ray-core/api/doc/ray.util.ActorPool.html) 有点像 `multiprocessing.Pool`,Actor Pool 中有包含多个 Actor,每个 Actor 功能一样,而且可以分式地在多个计算节点上运行。" ] }, { @@ -672,9 +647,9 @@ "origin_pos": 25 }, "source": [ - "如果我们想调用加入到 ActorPool 中的 Actor,可以使用 [`map(fn, values)`](https://docs.ray.io/en/latest/ray-core/api/doc/ray.util.ActorPool.map.html) 和 [`submit(fn, value)`](https://docs.ray.io/en/latest/ray-core/api/doc/ray.util.ActorPool.submit.html) 方法。这两个方法非常相似,所接收的参数是一个函数 `fn` 和参数 `value` 或者参数列表 `values`。`map()` 的 `values` 是一个列表,让函数并行地分发给多个 Actor 去处理;`submit()` 的 `value` 是单个值,每次从 ActorPool 中选择一个 Actor 去执行。`fn` 是一个 Lambda 表达式,或者说是一个匿名函数。这个 Lambda 表达式有两个参数:`actor` 和 `value`,`actor` 就是我们定义的单个 Actor 的函数调用,`value` 是这个函数的参数。\n", + "如果我们想调用加入到 `ActorPool` 中的 Actor,可以使用 [`map(fn, values)`](https://docs.ray.io/en/latest/ray-core/api/doc/ray.util.ActorPool.map.html) 和 [`submit(fn, value)`](https://docs.ray.io/en/latest/ray-core/api/doc/ray.util.ActorPool.submit.html) 方法。这两个方法非常相似,所接收的参数是一个函数 `fn` 和参数 `value` 或者参数列表 `values`。`map()` 的 `values` 是一个列表,让函数并行地分发给多个 Actor 去处理;`submit()` 的 `value` 是单个值,每次从 `ActorPool` 中选择一个 Actor 去执行。`fn` 是一个 Lambda 表达式,或者说是一个匿名函数。这个 Lambda 表达式有两个参数:`actor` 和 `value`,`actor` 就是我们定义的单个 Actor 的函数调用,`value` 是这个函数的参数。\n", "\n", - "函数的第一个参数是 ActorPool 中的 Actor,第二个参数是函数的参数。\n" + "函数的第一个参数是 `ActorPool` 中的 Actor,第二个参数是函数的参数。" ] }, { @@ -708,7 +683,7 @@ "origin_pos": 27 }, "source": [ - "`map()` 和 `submit()` 将计算任务提交到了 ActorPool 中,ActorPool 并不是直接返回结果,而是异步地分发给后台不同的 Actor 去执行。需要使用 [`get_next()`](https://docs.ray.io/en/latest/ray-core/api/doc/ray.util.ActorPool.get_next.html) 阻塞地返回结果。\n" + "`map()` 和 `submit()` 将计算任务提交到了 `ActorPool` 中,`ActorPool` 并不是直接返回结果,而是异步地分发给后台不同的 Actor 去执行。需要使用 [`get_next()`](https://docs.ray.io/en/latest/ray-core/api/doc/ray.util.ActorPool.get_next.html) 阻塞地返回结果。" ] }, { @@ -756,7 +731,7 @@ "source": [ "当然,如果已经把所有结果都取回,仍然再去 `get_next()`,将会抛出异常。\n", "\n", - "在这里,`value` 只能是单个对象,不能是参数列表,如果想传入多个参数,可以把参数包裹成元组。比如 `add()` 方法对两个操作数做计算,我们把两个操作数包裹为一个元组,实现 `add()` 函数时使用 `(a, b) = operands` 解析这个元组。\n" + "在这里,`submit()` 的 `value` 参数只能是单个对象,不能是参数列表,如果想传入多个参数,可以把参数包裹成元组。比如 `add()` 方法对两个操作数做计算,我们把两个操作数包裹为一个元组,实现 `add()` 函数时使用 `(a, b) = operands` 解析这个元组。" ] }, { @@ -839,7 +814,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.11.7" }, "required_libs": [] }, diff --git a/ch-ray-core/remote-object.ipynb b/ch-ray-core/remote-object.ipynb index 30ec837..394951d 100644 --- a/ch-ray-core/remote-object.ipynb +++ b/ch-ray-core/remote-object.ipynb @@ -12,7 +12,7 @@ "\n", "Ray 分布式计算中涉及共享数据可被放在分布式对象存储(Distributed Ojbect Store)中,被放置在分布式对象存储中的数据被称为远程对象(Remote Object)中。我们可以使用 [`ray.get()`](https://docs.ray.io/en/latest/ray-core/api/doc/ray.get.html) 和 [`ray.put()`](https://docs.ray.io/en/latest/ray-core/api/doc/ray.put.html) 读写这些 Remote Object。与内存中的 Python 对象实例不同,Remote Object 是不可原地直接更改的(Immutable)。\n", "\n", - "## ray.put() 与 ray.get()\n" + "## `ray.put()` 与 `ray.get()`\n" ] }, { @@ -119,8 +119,8 @@ "width: 800px\n", "name: put-get-object-store\n", "---\n", - "RAY 分布式对象存储示意图\n", - "```\n" + "Ray 分布式对象存储示意图\n", + "```" ] }, { @@ -156,7 +156,7 @@ " return torch.randn(size=(size), dtype=torch.float)\n", "\n", "torch.manual_seed(42)\n", - "# 创建 16个 个机张量,每个张量大小为 (X, 8, 8)\n", + "# 创建 16 个张量,每个张量大小为 (X, 8, 8)\n", "tensor_obj_ref_list = [ray.put(create_rand_tensor((i, 8, 8))) for i in range(1, 16)]\n", "tensor_obj_ref_list[0], len(tensor_obj_ref_list)" ] @@ -227,7 +227,7 @@ "origin_pos": 6 }, "source": [ - "或者把存放 `ObjectRefIDs` 列表的所有对象都拉取过来:\n" + "或者把 `ObjectRefID` 列表的所有对象都拉取过来:" ] }, { @@ -286,9 +286,9 @@ "origin_pos": 8 }, "source": [ - "## 案例1:对数据进行转换\n", + "## Example 1: Transforming Data\n", "\n", - "Remote Object 的数据是不可原地更改的,比如下面的操作在单机的内存上可以,但是在 Remote Object 上,不可以直接在原地对 Remote Object 做更改。\n" + "The data of remote objects is immutable. For example, the following operation is common in the local memory but cannot be directly applied to a remote object." ] }, { @@ -339,7 +339,7 @@ "origin_pos": 10 }, "source": [ - "如果我们想使用新数据,应该使用 Remote Function 或者 Remote Class 对 Remote Object 进行转换操作,生成新的 Remote Object。\n" + "如果我们想使用新数据,应该使用 Remote Function 或者 Remote Class 对 Remote Object 进行转换操作,生成新的 Remote Object。" ] }, { @@ -392,7 +392,7 @@ "\n", "### 直接传递\n", "\n", - "直接在 Task 或者 Actor 的函数调用时将 `RefObjectID` 作为参数传递进去。在下面这个例子中,`x_obj_ref` 是一个 `RefObjectID` ,`echo()` 这个 Remote Function 将自动从 `x_obj_ref` 获取 `x` 的值。这个自动获取值的过程被称为自动反引用(De-referenced)。\n" + "直接在 Task 或者 Actor 的函数调用时将 `RefObjectID` 作为参数传递进去。在下面这个例子中,`x_obj_ref` 是一个 `RefObjectID` ,`echo()` 这个 Remote Function 将自动从 `x_obj_ref` 获取 `x` 的值。这个自动获取值的过程被称为自动反引用(De-referenced)。" ] }, { @@ -517,7 +517,7 @@ "如果 `RefObjectID` 被包裹在一个复杂的数据结构中,Ray 并不会自动获取 `RefObjectID` 对应的值,即 De-referenced 并不是自动的。复杂数据结构包括:\n", "\n", "* `RefObjectID` 被包裹在一个 `dict` 中,比如:`.remote({\"obj\": x_obj_ref})`\n", - "* `RefObjectID` 被包裹在一个 `list` 中,比如:`.remote([x_obj_ref])`\n" + "* `RefObjectID` 被包裹在一个 `list` 中,比如:`.remote([x_obj_ref])`" ] }, { @@ -639,7 +639,7 @@ "\n", "Ray 集群的每个计算节点都有一个基于共享内存的对象存储, Remote Object 的数据会存储在集群某个或者某些计算节点的对象存储中,所有计算节点的共享内存共同组成了分布式对象存储。\n", "\n", - "当某个 Remote Object 的数据量较小时(<= 100 KB),它会被存储在计算节点进程内存中;当数据量较大时,它会被存储在分布式的共享内存中;当集群的共享内存的空间不够时,数据会被外溢(Spill)到持久化的存储上,比如硬盘或者S3。\n" + "当某个 Remote Object 的数据量较小时(<= 100 KB),它会被存储在计算节点进程内存中;当数据量较大时,它会被存储在分布式的共享内存中;当集群的共享内存的空间不够时,数据会被外溢(Spill)到持久化的存储上,比如硬盘或者S3。" ] }, { diff --git a/ch-ray-data/data-load-inspect-save.ipynb b/ch-ray-data/data-load-inspect-save.ipynb index 3b657c8..34f2ae2 100644 --- a/ch-ray-data/data-load-inspect-save.ipynb +++ b/ch-ray-data/data-load-inspect-save.ipynb @@ -156,8 +156,6 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "使用 HDFS、S3 或者其他文件系统时,Ray Data 遵守 {numref}`uri-schemes` 中提及的 URI 和文件系统 Scheme 标准,应在 URI 中明确 Scheme 信息。\n", - "\n", "查看这份数据集的数据模式(Schema):" ] }, @@ -219,15 +217,10 @@ ":name: ray-data-read-files\n", "| \t| Parquet \t| Text \t| CSV \t| TFRecord \t| 二进制 \t|\n", "|:----:\t|:--------------:\t|:-----------:\t|:----------:\t|:----------------:\t|---------------------\t|\n", - "| 方法 \t| read_parquet() \t| [read_text()](https://docs.ray.io/en/latest/data/api/doc/ray.data.read_text.html) \t| [read_csv()](https://docs.ray.io/en/latest/data/api/doc/ray.data.read_csv.html) \t| [read_tfrecords()](https://docs.ray.io/en/latest/data/api/doc/ray.data.read_tfrecords.html) \t| [read_binary_files()](https://docs.ray.io/en/latest/data/api/doc/ray.data.read_binary_files.html) \t|\n", + "| 方法 \t| [`read_parquet()`](https://docs.ray.io/en/latest/data/api/doc/ray.data.read_parquet.html) \t| [`read_text()`](https://docs.ray.io/en/latest/data/api/doc/ray.data.read_text.html) \t| [`read_csv()`](https://docs.ray.io/en/latest/data/api/doc/ray.data.read_csv.html) \t| [`read_tfrecords()`](https://docs.ray.io/en/latest/data/api/doc/ray.data.read_tfrecords.html) \t| [`read_binary_files()`](https://docs.ray.io/en/latest/data/api/doc/ray.data.read_binary_files.html) \t|\n", "```" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [] - }, { "cell_type": "markdown", "metadata": {}, @@ -346,7 +339,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 并行调优\n", + "### 并行度\n", "\n", "{numref}`ray-data-intro` 我们提到,Ray Data 背后使用 Task 或 Actor 将数据处理过程并行化,在数据读取时,可以设置 `parallelism` 参数,以优化并行数据处理过程。包括 `read_parquet()`,Ray Data 提供的各类数据读取方法,都可以设置 `parallelism` 参数,来控制底层的并行执行的过程。如果不设置 `parallelism`,Ray Data 通过以下方式试探 `parallelism`:\n", "\n", @@ -652,13 +645,15 @@ "\n", "### 写入文件系统\n", "\n", + "使用 HDFS、S3 或者其他文件系统时,Ray Data 遵守 {numref}`uri-schemes` 中提及的 URI 和文件系统 Scheme 标准,应在 URI 中明确 Scheme 信息。\n", + "\n", "{numref}`ray-data-save` 列举了几个将 `Dataset` 保存为不同文件格式的 API。\n", "\n", "```{table} 将 Dataset 写入文件系统\n", ":name: ray-data-save\n", "| \t| Parquet \t| CSV \t| JSON \t| TFRecord \t|\n", "|:----:\t|:--------------:\t|:-----------:\t|:----------:\t|:----------------:\t|\n", - "| 方法 \t| [Dataset.write_parquet()](https://docs.ray.io/en/latest/data/api/doc/ray.data.Dataset.write_parquet.html) \t| [Dataset.write_csv()](https://docs.ray.io/en/latest/data/api/doc/ray.data.Dataset.write_csv.html) \t| [Dataset.write_json()](https://docs.ray.io/en/latest/data/api/doc/ray.data.Dataset.write_json.html) \t| [Dataset.write_tfrecords()](https://docs.ray.io/en/latest/data/api/doc/ray.data.Dataset.write_tfrecords.html) \t|\n", + "| 方法 \t| [`Dataset.write_parquet()`](https://docs.ray.io/en/latest/data/api/doc/ray.data.Dataset.write_parquet.html) \t| [`Dataset.write_csv()`](https://docs.ray.io/en/latest/data/api/doc/ray.data.Dataset.write_csv.html) \t| [`Dataset.write_json()`](https://docs.ray.io/en/latest/data/api/doc/ray.data.Dataset.write_json.html) \t| [`Dataset.write_tfrecords()`](https://docs.ray.io/en/latest/data/api/doc/ray.data.Dataset.write_tfrecords.html) \t|\n", "```\n", "\n", "将数据持久化到文件系统时,注意写明文件系统的 Scheme。比如,写入本地的 `/tmp/trip` 目录:" @@ -765,7 +760,7 @@ ":name: ray-data-convert-other-library\n", "| \t| pandas \t| Dask \t| Spark \t| \n", "|:----:\t|:--------------:\t|:-----------:\t|:----------:\t|\n", - "| 方法 \t| [Dataset.to_pandas()](https://docs.ray.io/en/latest/data/api/doc/ray.data.Dataset.to_pandas.html) \t| [Dataset.to_dask()](https://docs.ray.io/en/latest/data/api/doc/ray.data.Dataset.to_dask.html) \t| [Dataset.to_spark()](https://docs.ray.io/en/latest/data/api/doc/ray.data.Dataset.to_spark.html) \t|\n", + "| 方法 \t| [`Dataset.to_pandas()`](https://docs.ray.io/en/latest/data/api/doc/ray.data.Dataset.to_pandas.html) \t| [`Dataset.to_dask()`](https://docs.ray.io/en/latest/data/api/doc/ray.data.Dataset.to_dask.html) \t| [`Dataset.to_spark()`](https://docs.ray.io/en/latest/data/api/doc/ray.data.Dataset.to_spark.html) \t|\n", "```" ] } diff --git a/ch-ray-data/data-transform.ipynb b/ch-ray-data/data-transform.ipynb index 1aada1d..edb1872 100644 --- a/ch-ray-data/data-transform.ipynb +++ b/ch-ray-data/data-transform.ipynb @@ -308,8 +308,8 @@ } ], "source": [ - "filterd_dataset = dataset.map_batches(lambda df: df[df[\"trip_distance\"] > 4], batch_format=\"pandas\")\n", - "print(f\"过滤后的行数:{filterd_dataset.count()}\")" + "filtered_dataset = dataset.map_batches(lambda df: df[df[\"trip_distance\"] > 4], batch_format=\"pandas\")\n", + "print(f\"过滤后的行数:{filtered_dataset.count()}\")" ] }, { diff --git a/ch-ray-data/preprocessor.ipynb b/ch-ray-data/preprocessor.ipynb index 02dbaac..a66e57b 100644 --- a/ch-ray-data/preprocessor.ipynb +++ b/ch-ray-data/preprocessor.ipynb @@ -254,13 +254,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## 分类\n", - "\n", - "Ray Data 的 Preprocessor 可处理以下几类数据:\n", + "## 分类变量和数值变量\n", "\n", "### 分类变量\n", "\n", - "原始数据是分类(Categorical)变量,但机器学习模型无法接受分类变量,所以需要进行一些转换。{numref}`categorical-data-preprocessor` 是几个处理分类变量的 Preprocessor。\n", + "机器学习模型无法接受分类变量,所以需要进行一些转换。{numref}`categorical-data-preprocessor` 是几个处理分类变量的 Preprocessor。\n", "\n", "```{table} 用于处理分类变量的 Preprocessor\n", ":name: categorical-data-preprocessor\n", @@ -274,7 +272,7 @@ "\n", "### 数值变量\n", "\n", - "原始数据是数值变量,使用下面的转换将数据进行转换,以适应特定的机器学习模型,{numref}`numerical-data-preprocessor` 是几个处理数值变量的 Preprocessor。\n", + "使用下面的转换将数据进行转换,以适应特定的机器学习模型,{numref}`numerical-data-preprocessor` 是几个处理数值变量的 Preprocessor。\n", "\n", "```{table} 用于处理数值变量的 Preprocessor\n", ":name: numerical-data-preprocessor\n", diff --git a/conf.py b/conf.py index cc1a024..0b4d7e9 100644 --- a/conf.py +++ b/conf.py @@ -14,7 +14,13 @@ html_theme = 'sphinx_book_theme' html_theme_options = { 'search_bar_text': '搜索...', - 'launch_buttons': {'notebook_interface': 'classic', 'binderhub_url': '', 'jupyterhub_url': '', 'thebe': False, 'colab_url': ''}, + 'launch_buttons': { + 'notebook_interface': 'classic', + 'binderhub_url': '', + 'jupyterhub_url': '', + 'thebe': False, + 'colab_url': 'https://colab.research.google.com' + }, 'path_to_docs': 'docs', 'repository_url': 'https://github.com/godaai/distributed-python', 'repository_branch': 'main', @@ -41,6 +47,8 @@ 'use_issues_button': False, "toc_title": "本节目录", } +html_static_path = ["_static"] +html_css_files = ["custom.css"] html_title = 'Python 分布式编程' latex_engine = 'pdflatex' myst_enable_extensions = ['colon_fence', 'dollarmath', 'linkify', 'substitution', 'tasklist'] diff --git a/img/ch-ray-data/dataset-map.svg b/img/ch-ray-data/dataset-map.svg index 7a7c6a5..1d205e6 100644 --- a/img/ch-ray-data/dataset-map.svg +++ b/img/ch-ray-data/dataset-map.svg @@ -1,4 +1,4 @@ -
Map Task
Map Task
Map Task
Map Task
Map Task
Map Task
Map Task
Map Task
Block
Block
Block
Block
Block
Block
Block
Block
ds.map_batches(stateless_fn)
ds.map_batches(stateless_fn)
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Actor Pool
(min_size=10,
max_size=20)
Actor Pool...
ds.map_batches(callable_cls,
compute=ActorPoolstrategy(
min_size=10, max_size=20,
))
ds.map_batches(callable_cls,...
Text is not SVG - cannot display
\ No newline at end of file +
Map Task
Map Task
Map Task
Map Task
Map Task
Map Task
Map Task
Map Task
Block
Block
Block
Block
Block
Block
Block
Block
ds.map_batches(stateless_fn)
ds.map_batches(stateless_fn)
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
ActorPool
(min_size=10,
max_size=20)
ActorPool...
ds.map_batches(callable_cls,
compute=ActorPoolstrategy(
min_size=10, max_size=20,
))
ds.map_batches(callable_cls,...
Text is not SVG - cannot display
\ No newline at end of file diff --git a/img/ch-ray-data/dataset-read.svg b/img/ch-ray-data/dataset-read.svg index f3cb5c9..6821959 100644 --- a/img/ch-ray-data/dataset-read.svg +++ b/img/ch-ray-data/dataset-read.svg @@ -1,4 +1,4 @@ -
File 1
File 1
File 2
File 2
File 3
File 3
File 4
File 4
Read Task
Read Task
Read Task
Read Task
Read Task
Read Task
Read Task
Read Task
Block
Block
Block
Block
Block
Block
Block
Block
File 1
File 1
File 2
File 2
File 3
File 3
File 4
File 4
Read Task
Read Task
Read Task
Read Task
Block
Block
Block
Block
ray.data.read_csv(path)
ray.data.read_csv(path)
Manually specifying parallelism:
ray.data.read_csv(path, parallelism=2)
Manually specifying parallelism:...
Text is not SVG - cannot display
\ No newline at end of file +
File 1
File 1
File 2
File 2
File 3
File 3
File 4
File 4
Read Task
Read Task
Read Task
Read Task
Read Task
Read Task
Read Task
Read Task
Block
Block
Block
Block
Block
Block
Block
Block
File 1
File 1
File 2
File 2
File 3
File 3
File 4
File 4
Read Task
Read Task
Read Task
Read Task
Block
Block
Block
Block
ray.data.read_csv(path)
ray.data.read_csv(path)
Manually specifying parallelism:
ray.data.read_csv(path, parallelism=2)
Manually specifying parallelism:...
Text is not SVG - cannot display
\ No newline at end of file