热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Ray:为人工智能而生的分布式执行框架

原文:Ray:ADistributedExecutionFrameworkforAIApplications作者:RobertNishihara翻译&#

原文:Ray: A Distributed Execution Framework for AI Applications
作者:Robert Nishihara
翻译:黑色巧克力


译者注:文章介绍了服务人工智能的开源框架Ray,并借助代码示例说明了它的特点和优势。

Ray,一个在集群和大型多核机器上高效运行Python代码的框架。可以查看相关代码和文档。

许多人工智能算法在计算上都非常密集,并且显示出复杂的通信模式。为此许多研究人员将大部分时间花在构建定制系统上,以高效地在集群中分发代码。

然而,定制的系统通常是基于特定的单一算法或算法类。因此我们构建了Ray来帮助消除一堆冗余的工程任务,这些任务目前在每个新算法中反复出现。我们希望能够重用一些基本的基础元素来实现并高效地执行各种算法和应用程序。


现有代码的简单并行化

Ray允许通过最少的修改来远程执行Python函数。

使用常规的Python时,在函数未执行完毕之前,如果调用函数,那么会被阻塞。下面这个例子的执行时间为8秒:

def f():time.sleep(1)# Calls to f executed serially.
results = []
for _ in range(8):result = f()results.append(result)

对于Ray,当调用远程函数时会立即返回一个future(称之为对象IDs)。接着创建一个任务,然后调度它,并在集群的某个地方去执行。下面的例子只需要1秒即可完成。

@ray.remote
def f():time.sleep(1)# Tasks executed in parallel.
results = []
for _ in range(8):result = f.remote()results.append(result)results = ray.get(results)

注意,惟一的变化是将@ray.remote装饰器添加到了函数定义中,通过f.remote调用该函数,并且在对象IDs列表中调用ray.get(记住对象IDs是未来),以便阻塞进程直到相应的任务执行完成。



image

这是描述任务和对象的图表。圆圈表示任务,而方框表示对象。8个单独的任务之间没有箭头,表示所有的任务可以并行执行。


任务依赖的灵活编码

与MapReduce或Apache Spark这样的批量同步并行框架相比,Ray的设计目的是支持需要细粒度任务依赖的人工智能应用程序。它与整个数据集的总统计量的计算不同,训练过程可以对一小部分数据进行操作,也可以对少数任务的输出进行操作。

依赖项可以通过将对象IDs(任务的输出)传递到其他任务来进行编码。

import numpy as np@ray.remote
def aggregate_data(x, y):return x + ydata = [np.random.normal(size=1000) for i in range(4)]while len(data) > 1:intermediate_result = aggregate_data.remote(data[0], data[1])data = data[2:] + [intermediate_result]result = ray.get(data[0])

通过将一些调用的输出传递给aggregate_data,随后调用aggregate_data,然后对这些任务之间的依赖进行编码,这些任务可以由系统使用,从而制定调度决策,并协调对象的传输。注意,当将对象IDs传递到远程函数调用时,实际的值将在函数执行之前被解压,因此当执行aggregate_data函数时,x和y将是numpy数组。



image

这是描述任务和对象的图表。圆圈表示任务,而方框表示对象。箭头表明从任务到它们产生的对象或者从对象到依赖于它们的任务。


与参与者共享可变状态

Ray使用参与者在任务之间共享可变状态。下面的例子中多个任务共享Atari模拟器状态。每个任务通过运行模拟器完成前面任务所遗留下的几个步骤。

import gym@ray.remote
class Simulator(object):def __init__(self):self.env = gym.make("Pong-v0")self.env.reset()def step(self, action):return self.env.step(action)# Create a simulator, this will start a new worker that will run all
# methods for this actor.
simulator = Simulator.remote()observations = []
for _ in range(4):# Take action 0 in the simulator.observations.append(simulator.step.remote(0))

每次调用simulator.step.remote生成一个在参与者上调度的任务。这些任务会改变模拟器对象的状态,并且每次执行一个。

与远程函数一样,参与者的方法返回对象IDs(也就是future),这些对象可以被传递到其他任务中,并且可以用ray.get来检索它们的值。



image

这是描述任务和对象的图表。圆圈表示任务,而方框表示对象。第一个任务是参与者的构造函数。粗箭头用于显示在这个参与者上调用的方法共享参与者的底层状态。


等待完成任务的子集

有时,当运行带有变量持续时间的任务时,不希望等待所有的任务完成。相反,可能希望等待一半的任务完成,或者使用完一秒后完成的任务。

@ray.remote
def f():time.sleep(np.random.uniform(0, 5))# Launch 10 tasks with variable durations.
results = [f.remote() for _ in range(10)]# Wait until either five tasks have completed or two seconds have passed and
# return a list of the object IDs whose tasks have finished.
ready_ids, remaining_ids = ray.wait(results, num_returns=5, timeout=2000)

在本例中,ready_ids是一个对象IDs列表,它对应的任务已完成执行,而remaining_ids是剩余的对象IDs列表。

这段原始代码使实现其他行为变得很容易,例如希望按照完成的顺序来处理某些任务。

# Launch 10 tasks with variable durations.
remaining_ids = [f.remote() for _ in range(10)]# Process the tasks in the order that they complete.
results = []
while len(remaining_ids) > 0:ready_ids, remaining_ids = ray.wait(remaining_ids, num_returns=1)results.append(ray.get(ready_ids[0]))

注意,可以简单的修改上面的示例,以便上一个任务完成时自适应地启动新任务。


使用Apache Arrow高效共享内存和序列化

序列化和反序列化数据常常是分布式计算的瓶颈。Ray让同一机器上的工作进程通过共享内存访问相同的对象。为了达到这一目的,Ray把内存中的对象存储在每台机器上为对象服务。

为了说明问题,假设我们创建了一些神经网络权重,并希望将它们从一个Python进程传送到另一个Python进程。

import numpy as npweights = {"Variable{}".format(i): np.random.normal(size=5000000)for i in range(10)} # 2.68s

为了将神经网络的权重传输到周围,首先需要将它们序列化成一个连续的字节块。这可以通过像pickle这样的标准序列化库来完成。

import pickle# Serialize the weights with pickle. Then deserialize them.
pickled_weights = pickle.dumps(weights) # 0.986s
new_weights = pickle.loads(pickled_weights) # 0.241s

反序列化所需的时间尤为重要,因为机器学习最常见的一种模式是在单一的过程中聚集大量的值(例如神经网络权重,转出,或其他值),因此连续的反序列化步骤可能发生数百次。

为了减少在共享内存中对象进行反序列化所需要的时间,我们使用Apache Arrow数据布局。这使我们能够在不扫描整个blob的情况下,计算对序列化的blob的偏移量。在实践中还可以转换成反序列化,达到几个数量级的速度。

# Serialize the weights and copy them into the object store. Then deserialize
# them.
weights_id = ray.put(weights) # 0.525s
new_weights = ray.get(weights_id) # 0.000622s

使用Arrow调用ray.put序列化权重,并将结果复制到对象存储的内存中。然后调用ray.get对序列化的对象进行反序列化,并构造一个新的numpy字典数组。然而支持numpy数组的底层数组仍然存在于共享内存中,并且不会被复制到Python进程的堆中。

注意如果一台不同的机器调用ray.get,那么相关的序列化对象将从一台常用机器上复制到另一台需要的机器上。

这个例子中,我们指明调用ray.put。然而通常情况下,只有当将Python对象传递到远程函数或从远程函数返回时,这个调用才会发生。


期待您的反馈

该项目处于早期阶段,如果你愿意尝试运用,我们非常乐意听到你的想法和建议。


推荐阅读
  • 颜色迁移(reinhard VS welsh)
    不要谈什么天分,运气,你需要的是一个截稿日,以及一个不交稿就能打爆你狗头的人,然后你就会被自己的才华吓到。------ ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
  • 十大经典排序算法动图演示+Python实现
    本文介绍了十大经典排序算法的原理、演示和Python实现。排序算法分为内部排序和外部排序,常见的内部排序算法有插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。文章还解释了时间复杂度和稳定性的概念,并提供了相关的名词解释。 ... [详细]
  • STL迭代器的种类及其功能介绍
    本文介绍了标准模板库(STL)定义的五种迭代器的种类和功能。通过图表展示了这几种迭代器之间的关系,并详细描述了各个迭代器的功能和使用方法。其中,输入迭代器用于从容器中读取元素,输出迭代器用于向容器中写入元素,正向迭代器是输入迭代器和输出迭代器的组合。本文的目的是帮助读者更好地理解STL迭代器的使用方法和特点。 ... [详细]
  • Python教学练习二Python1-12练习二一、判断季节用户输入月份,判断这个月是哪个季节?3,4,5月----春 ... [详细]
  • 学习SLAM的女生,很酷
    本文介绍了学习SLAM的女生的故事,她们选择SLAM作为研究方向,面临各种学习挑战,但坚持不懈,最终获得成功。文章鼓励未来想走科研道路的女生勇敢追求自己的梦想,同时提到了一位正在英国攻读硕士学位的女生与SLAM结缘的经历。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • Python瓦片图下载、合并、绘图、标记的代码示例
    本文提供了Python瓦片图下载、合并、绘图、标记的代码示例,包括下载代码、多线程下载、图像处理等功能。通过参考geoserver,使用PIL、cv2、numpy、gdal、osr等库实现了瓦片图的下载、合并、绘图和标记功能。代码示例详细介绍了各个功能的实现方法,供读者参考使用。 ... [详细]
  • 这是一个愚蠢的问题,但我只是对此感到好奇.假设我在Pythonshell,我有一些我查询的数据库对象.我做:db.query(的queryString)该查询在0xffdf842c ... [详细]
  • Python使用Pillow包生成验证码图片的方法
    本文介绍了使用Python中的Pillow包生成验证码图片的方法。通过随机生成数字和符号,并添加干扰象素,生成一幅验证码图片。需要配置好Python环境,并安装Pillow库。代码实现包括导入Pillow包和随机模块,定义随机生成字母、数字和字体颜色的函数。 ... [详细]
  • 超级简单加解密工具的方案和功能
    本文介绍了一个超级简单的加解密工具的方案和功能。该工具可以读取文件头,并根据特定长度进行加密,加密后将加密部分写入源文件。同时,该工具也支持解密操作。加密和解密过程是可逆的。本文还提到了一些相关的功能和使用方法,并给出了Python代码示例。 ... [详细]
  • 本文介绍了贝叶斯垃圾邮件分类的机器学习代码,代码来源于https://www.cnblogs.com/huangyc/p/10327209.html,并对代码进行了简介。朴素贝叶斯分类器训练函数包括求p(Ci)和基于词汇表的p(w|Ci)。 ... [详细]
author-avatar
w3812127
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有