Apache Ignite 上的 TensorFlow
2019 年 2 月 22 日
Anton DmitrievGridGain Systems 的软件工程师撰写。

任何深度学习都始于数据。这是一个关键点。没有数据,我们就无法训练模型,无法评估模型质量,也无法进行预测。因此,数据源非常重要。在进行研究、发明新的神经网络架构和进行实验时,我们习惯于使用最简单的本地数据源,通常是不同格式的文件。这种方法非常有效。但到了一定程度,我们需要更接近生产环境。简化和加速生产数据馈送变得非常重要,并且能够处理大数据。而此时,Apache Ignite 就派上了用场。

Apache Ignite 是一个以内存为中心的分布式数据库,缓存和处理平台,适用于事务性、分析性和流式工作负载,在 PB 级规模上提供内存速度。Apache Ignite 和 TensorFlow 之间现有的集成允许您使用 Apache Ignite 作为神经网络训练和推断的数据源,以及作为分布式训练的检查点存储和集群管理器。

分布式内存数据源

Apache Ignite 是一个以内存为中心的分布式数据库,提供快速的数据访问。它允许您避免硬盘驱动器限制,在分布式集群中存储和操作尽可能多的数据。您可以通过使用 Ignite Dataset 来利用 Apache Ignite 的这些优势。

请注意,Apache Ignite 不仅仅是数据库或数据仓库与 TensorFlow 之间的 ETL 管道步骤。Apache Ignite 是一个 HTAP(混合事务/分析处理)系统。选择 Apache Ignite 和 TensorFlow,您将获得一个用于事务处理和分析处理的单一系统,同时还能够使用您的运营和历史数据进行神经网络训练和推断。

以下基准测试结果表明,Apache Ignite 非常适合单节点数据存储用例。如果存储和客户端位于同一节点上,它允许您实现超过 850 MB/s 的吞吐量。如果存储相对于客户端位于远程节点上,则吞吐量约为 800 MB/s。
在单个本地 Apache Ignite 节点的情况下,Ignite Dataset 吞吐量。此基准测试是在配备 2x Xeon E5–2609 v4 1.7GHz、16Gb 内存和 10 Gb/s 网络的机器上进行的(1MB 行和 20MB 页面大小)。
另一个基准测试展示了 Ignite Dataset 如何与分布式 Apache Ignite 集群一起使用。这是 Apache Ignite 作为 HTAP 系统的默认用例,它允许您在 10 Gb/s 网络集群上为单个客户端实现超过 1 GB/s 的读取吞吐量。
在具有不同节点数(从 1 到 9)的分布式 Apache Ignite 集群的情况下,Ignite Dataset 吞吐量。此基准测试是在配备 2x Xeon E5–2609 v4 1.7GHz、16Gb 内存和 10 Gb/s 网络的机器上进行的(1MB 行和 20MB 页面大小)。
测试的用例如下:Apache Ignite 缓存(在第一组测试中具有不同的分区数量,在第二组测试中具有 2048 个分区)填充了 10K 行,每行 1MB,然后 TensorFlow 客户端使用 Ignite Dataset 读取所有数据。所有节点都由配备 2x Xeon E5–2609 v4 1.7GHz、16Gb 内存并通过 10Gb/s 网络连接的机器表示。每个节点都运行具有默认 配置 的 Apache Ignite。

将 Apache Ignite 同时用作具有 SQL 接口的经典数据库和 TensorFlow 数据源非常容易。
apache-ignite/bin/ignite.sh
apache-ignite/bin/sqlline.sh -u "jdbc:ignite:thin://localhost:10800/"
CREATE TABLE KITTEN_CACHE (ID LONG PRIMARY KEY, NAME VARCHAR);
INSERT INTO KITTEN_CACHE VALUES (1, 'WARM KITTY');
INSERT INTO KITTEN_CACHE VALUES (2, 'SOFT KITTY');
INSERT INTO KITTEN_CACHE VALUES (3, 'LITTLE BALL OF FUR');
import tensorflow as tf
from tensorflow.contrib.ignite import IgniteDataset
tf.enable_eager_execution()

dataset = IgniteDataset(cache_name="SQL_PUBLIC_KITTEN_CACHE")

for element in dataset:
  print(element)
{'key': 1, 'val': {'NAME': b'WARM KITTY'}}
{'key': 2, 'val': {'NAME': b'SOFT KITTY'}}
{'key': 3, 'val': {'NAME': b'LITTLE BALL OF FUR'}}

结构化对象

Apache Ignite 允许您存储任何类型的对象。这些对象可以具有任何层次结构。Ignite Dataset 提供了一种处理此类对象的能力。
import tensorflow as tf
from tensorflow.contrib.ignite import IgniteDataset
tf.enable_eager_execution()

dataset = IgniteDataset(cache_name="IMAGES")

for element in dataset.take(1):
  print(element)
{
    'key': 'kitten.png',
    'val': {
        'metadata': {
            'file_name': b'kitten.png',
            'label': b'little ball of fur',
            width: 800,
            height: 600
        },
        'pixels': [0, 0, 0, 0, ..., 0]
    }
}
神经网络训练和其他计算需要转换,如果您使用 Ignite Dataset,这些转换可以在 tf.data 管道的一部分中完成。
import tensorflow as tf
from tensorflow.contrib.ignite import IgniteDataset
tf.enable_eager_execution()

dataset = IgniteDataset(cache_name="IMAGES").map(lambda obj: obj['val']['pixels'])

for element in dataset:
  print(element)
[0, 0, 0, 0, ..., 0]

分布式训练

TensorFlow 是一个机器学习框架,它 原生支持 分布式神经网络训练、推断和其他计算。分布式神经网络训练背后的主要思想是能够在数据的每个分区(就横向分区而言)上计算损失函数的梯度(例如,误差的平方),然后将它们加起来以获得整个数据集的损失函数梯度。利用这种能力,我们可以在存储数据的节点上计算梯度,减少它们,然后最终更新模型参数。它允许您避免节点之间的数据传输,从而避免网络瓶颈。

Apache Ignite 使用横向分区将数据存储在分布式集群中。当我们创建 Apache Ignite 缓存(或 SQL 意义上的表)时,我们可以指定数据将要分区的分区数量。例如,如果一个 Apache Ignite 集群由 100 台机器组成,并且我们创建一个具有 1000 个分区的缓存,那么每台机器将维护大约 10 个数据分区。

Ignite Dataset 允许使用分布式神经网络训练(使用 TensorFlow)和 Apache Ignite 分区的这两个方面。Ignite Dataset 是可以在远程工作器上执行的计算图操作。远程工作器可以通过为工作器进程设置相应的环境变量(例如 IGNITE_DATASET_HOST, IGNITE_DATASET_PORTIGNITE_DATASET_PART)来覆盖 Ignite Dataset 参数(例如 hostportpart)。使用这种覆盖方法,我们可以为每个工作器分配一个特定分区,以便一个工作器处理一个分区,同时透明地使用单个数据集。
import tensorflow as tf
from tensorflow.contrib.ignite import IgniteDataset

dataset = IgniteDataset("IMAGES")

# Compute gradients locally on every worker node.
gradients = []
for i in range(5):
  with tf.device("/job:WORKER/task:%d" % i):
    device_iterator = tf.compat.v1.data.make_one_shot_iterator(dataset)
    device_next_obj = device_iterator.get_next()
    gradient = compute_gradient(device_next_obj)
    gradients.append(gradient)

# Aggregate them on master node.
result_gradient = tf.reduce_sum(gradients)

with tf.Session("grpc://localhost:10000") as sess:
  print(sess.run(result_gradient))
Apache Ignite 还允许您使用 TensorFlow 高级 Estimator API 运行分布式训练。此功能基于 TensorFlow 分布式训练的所谓 独立客户端 模式,Apache Ignite 充当数据源和集群管理器。下一篇文章将专门讨论这个主题。

检查点存储

除了数据库功能外,Apache Ignite 还提供了一个名为 IGFS 的分布式文件系统。IGFS 提供与 Hadoop HDFS 相似的功能,但仅在内存中。事实上,除了自己的 API 外,IGFS 还实现了 Hadoop FileSystem API,可以透明地插入 Hadoop 或 Spark 部署中。Apache Ignite 上的 TensorFlow 提供了 IGFS 和 TensorFlow 之间的集成。集成基于 TensorFlow 端的 自定义文件系统插件 和 Apache Ignite 端的 IGFS 本机 API。它有许多用例,例如
  • 状态的检查点可以保存到 IGFS 以实现可靠性和容错性。
  • 训练过程通过将事件文件写入 TensorBoard 监视的目录来与 TensorBoard 通信。IGFS 允许这种通信即使在 TensorBoard 在不同的进程或机器上运行时也能正常工作。
此功能已在 TensorFlow 1.13 中发布,并将作为 tensorflow/io 的一部分在 TensorFlow 2.0 中发布。

SSL 连接

Apache Ignite 允许您通过 SSL 和身份验证来保护数据传输通道。Ignite Dataset 支持带有和不带有身份验证的 SSL 连接。有关更多信息,请参阅 Apache Ignite SSL/TLS 文档。
import tensorflow as tf
from tensorflow.contrib.ignite import IgniteDataset
tf.enable_eager_execution()

dataset = IgniteDataset(cache_name="IMAGES",
                        certfile="client.pem",
                        cert_password="password",
                        username="ignite",
                        password="ignite")

Windows 支持

Ignite Dataset 与 Windows 完全兼容。您可以在 Windows 工作站以及 Linux/MacOS 系统上将其用作 TensorFlow 的一部分。

试一试

以下示例将帮助您轻松地开始使用此模块。

Ignite Dataset

尝试 Ignite Dataset 的最简单方法是运行一个带有 Apache Ignite 和已加载的 MNIST 数据的 Docker 容器,并在启动后使用 Ignite Dataset 与其交互。此类容器在 Docker Hub 上可用:dmitrievanthony/ignite-with-mnist。您需要在您的机器上启动此容器
docker run -it -p 10800:10800 dmitrievanthony/ignite-with-mnist
之后,您将能够按照以下方式使用它:

IGFS

TensorFlow 对 IGFS 的支持已在 TensorFlow 1.13 中发布,并将作为 tensorflow/io 的一部分在 TensorFlow 2.0 中发布。尝试使用 TensorFlow 使用 IGFS 的最简单方法是运行一个带有 Apache Ignite + IGFS 的 Docker 容器,然后使用 TensorFlow tf.gfile 与其交互。此类容器在 Docker Hub 上可用:dmitrievanthony/ignite-with-igfs。您可以在您的机器上运行此容器
docker run -it -p 10500:10500 dmitrievanthony/ignite-with-igfs
之后,您将能够按照以下方式使用它
import tensorflow as tf
import tensorflow.contrib.ignite.python.ops.igfs_ops

with tf.gfile.Open("igfs:///hello.txt", mode='w') as w:
  w.write("Hello, world!")

with tf.gfile.Open("igfs:///hello.txt", mode='r') as r:
  print(r.read())
Hello, world!

限制

目前,Ignite Dataset 假设缓存中的所有对象都具有相同的结构(同构对象),并且缓存包含至少一个对象以检索模式。另一个限制涉及结构化对象,Ignite Dataset 不支持 UUID、Maps 和 Object 数组,这些数组可能是对象结构的一部分。所有这些限制都是进一步开发的主题。

即将推出的 TensorFlow 2.0

即将在 TensorFlow 2.0 中发布的更改将导致此功能分离到 tensorflow/io 模块中。这将使您能够更灵活地使用它。示例将略有更改,我们的文档和示例将反映这一点。
下一篇文章
TensorFlow on Apache Ignite

Anton DmitrievGridGain Systems 软件工程师)撰写的客座文章。

任何深度学习都始于数据。这是关键。没有数据,我们无法训练模型,也无法评估模型质量,更无法进行预测。因此,数据源非常重要。在进行研究、发明新的神经网络架构和进行实验时,我们习惯使用最简单的本地数据源……