From e5a57a7ce446c5952845bc2e1bedf19f11675970 Mon Sep 17 00:00:00 2001 From: Philipp Moritz Date: Sun, 15 Oct 2017 22:13:36 -0700 Subject: [PATCH] Blog post on Serialization and Apache Arrow Integration (#1130) * Add initial blog post on serialization libraries. * Shrink PNGs. * Small rewording. * Link to pyarrow serialization documentation. * More rewordings and authors. * Undo accidental change. * Small fixes. * Add code and other minor fixes. * Add note. --- ...-serialization-with-ray-and-arrow.markdown | 281 ++++++++++++++++++ .../arrow_object.png | Bin 0 -> 12059 bytes .../python_object.png | Bin 0 -> 20784 bytes .../speedups0.png | Bin 0 -> 4050 bytes .../speedups1.png | Bin 0 -> 4502 bytes .../speedups2.png | Bin 0 -> 4276 bytes .../speedups3.png | Bin 0 -> 13637 bytes 7 files changed, 281 insertions(+) create mode 100644 site/_posts/2017-10-15-fast-python-serialization-with-ray-and-arrow.markdown create mode 100644 site/assets/fast_python_serialization_with_ray_and_arrow/arrow_object.png create mode 100644 site/assets/fast_python_serialization_with_ray_and_arrow/python_object.png create mode 100644 site/assets/fast_python_serialization_with_ray_and_arrow/speedups0.png create mode 100644 site/assets/fast_python_serialization_with_ray_and_arrow/speedups1.png create mode 100644 site/assets/fast_python_serialization_with_ray_and_arrow/speedups2.png create mode 100644 site/assets/fast_python_serialization_with_ray_and_arrow/speedups3.png diff --git a/site/_posts/2017-10-15-fast-python-serialization-with-ray-and-arrow.markdown b/site/_posts/2017-10-15-fast-python-serialization-with-ray-and-arrow.markdown new file mode 100644 index 000000000..f160294ec --- /dev/null +++ b/site/_posts/2017-10-15-fast-python-serialization-with-ray-and-arrow.markdown @@ -0,0 +1,281 @@ +--- +layout: post +title: "Fast Python Serialization with Ray and Apache Arrow" +excerpt: "This post describes How serialization works in Ray." +date: 2017-10-15 14:00:00 +author: Philipp Moritz, Robert Nishihara +--- + +This post elaborates on the integration between [Ray][1] and [Apache Arrow][2]. +The main problem this addresses is [data serialization][3]. + +From [Wikipedia][3], **serialization** is + +> ... the process of translating data structures or object state into a format +> that can be stored ... or transmitted ... and reconstructed later (possibly +> in a different computer environment). + +Why is any translation necessary? Well, when you create a Python object, it may +have pointers to other Python objects, and these objects are all allocated in +different regions of memory, and all of this has to make sense when unpacked by +another process on another machine. + +Serialization and deserialization are **bottlenecks in parallel and distributed +computing**, especially in machine learning applications with large objects and +large quantities of data. + +## Design Goals + +As Ray is optimized for machine learning and AI applications, we have focused a +lot on serialization and data handling, with the following design goals: + +1. It should be very efficient with **large numerical data** (this includes +NumPy arrays and Pandas DataFrames, as well as objects that recursively contain +Numpy arrays and Pandas DataFrames). +2. It should be about as fast as Pickle for **general Python types**. +3. It should be compatible with **shared memory**, allowing multiple processes +to use the same data without copying it. +4. **Deserialization** should be extremely fast (when possible, it should not +require reading the entire serialized object). +5. It should be **language independent** (eventually we'd like to enable Python +workers to use objects created by workers in Java or other languages and vice +versa). + +## Our Approach and Alternatives + +The go-to serialization approach in Python is the **pickle** module. Pickle is +very general, especially if you use variants like [cloudpickle][4]. However, it +does not satisfy requirements 1, 3, 4, or 5. Alternatives like **json** satisfy +5, but not 1-4. + +**Our Approach:** To satisfy requirements 1-5, we chose to use the +[Apache Arrow][2] format as our underlying data representation. In collaboration +with the Apache Arrow team, we built [libraries][7] for mapping general Python +objects to and from the Arrow format. Some properties of this approach: + +- The data layout is language independent (requirement 5). +- Offsets into a serialized data blob can be computed in constant time without +reading the full object (requirements 1 and 4). +- Arrow supports **zero-copy reads**, so objects can naturally be stored in +shared memory and used by multiple processes (requirements 1 and 3). +- We can naturally fall back to pickle for anything we can’t handle well +(requirement 2). + +**Alternatives to Arrow:** We could have built on top of +[**Protocol Buffers**][5], but protocol buffers really isn't designed for +numerical data, and that approach wouldn’t satisfy 1, 3, or 4. Building on top +of [**Flatbuffers**][6] actually could be made to work, but it would have +required implementing a lot of the facilities that Arrow already has and we +preferred a columnar data layout more optimized for big data. + +## Speedups + +Here we show some performance improvements over Python’s pickle module. The +experiments were done using `pickle.HIGHEST_PROTOCOL`. Code for generating these +plots is included at the end of the post. + +**With NumPy arrays:** In machine learning and AI applications, data (e.g., +images, neural network weights, text documents) are typically represented as +data structures containing NumPy arrays. When using NumPy arrays, the speedups +are impressive. + +The fact that the Ray bars for deserialization are barely visible is not a +mistake. This is a consequence of the support for zero-copy reads (the savings +largely come from the lack of memory movement). + +
+ + +
+ +Note that the biggest wins are with deserialization. The speedups here are +multiple orders of magnitude and get better as the NumPy arrays get larger +(thanks to design goals 1, 3, and 4). Making **deserialization** fast is +important for two reasons. First, an object may be serialized once and then +deserialized many times (e.g., an object that is broadcast to all workers). +Second, a common pattern is for many objects to be serialized in parallel and +then aggregated and deserialized one at a time on a single worker making +deserialization the bottleneck. + +**Without NumPy arrays:** When using regular Python objects, for which we +cannot take advantage of shared memory, the results are comparable to pickle. + +
+ + +
+ +These are just a few examples of interesting Python objects. The most important +case is the case where NumPy arrays are nested within other objects. Note that +our serialization library works with very general Python types including custom +Python classes and deeply nested objects. + +## Data Representation + +We use Apache Arrow as the underlying language-independent data layout. Objects +are stored in two parts: a **schema** and a **data blob**. At a high level, the +data blob is roughly a flattened concatenation of all of the data values +recursively contained in the object, and the schema defines the types and +nesting structure of the data blob. + +Python sequences (e.g., dictionaries, lists, tuples, sets) are encoded as +[UnionArrays][8] of other types (e.g., bools, ints, strings, bytes, floats, +doubles, date64s, tensors (i.e., NumPy arrays), lists, tuples, dicts and sets). +Nested sequences are encoded using [ListArrays][9]. All tensors are collected +and appended to the end of the serialized object, and the UnionArray contains +references to these tensors. + +To give a concrete example, consider the following object. + +```python +[(1, 2), 'hello', 3, 4, np.array([5.0, 6.0])] +``` + +It would be represented in Arrow with the following structure. + +``` +UnionArray(type_ids=[tuple, string, int, int, ndarray], + tuples=ListArray(offsets=[0, 2], + UnionArray(type_ids=[int, int], + ints=[1, 2])), + strings=['hello'], + ints=[3, 4], + ndarrays=[]) +``` + +Arrow uses Flatbuffers to encode serialized schemas. **Using only the schema, we +can compute the offsets of each value in the data blob without scanning through +the data blob.** This means that we can avoid copying or otherwise converting +large arrays and other values during deserialization. Tensors are appended at +the end of the UnionArray and can be efficiently shared and accessed using +shared memory. + +Note that the actual object would be laid out in memory as shown below. + +
+ +
+
The layout of a Python object in the heap. Each box is allocated in a +different memory region, and arrows between boxes represent pointers.
+
+ +The Arrow serialized representation would be as follows. + +
+ +
+
The memory layout of the Arrow-serialized object.
+
+ +## The API + +The serialization library can be used directly through pyarrow as follows. More +documentation is available [here][7]. + +```python +x = [(1, 2), 'hello', 3, 4, np.array([5.0, 6.0])] +serialized_x = pyarrow.serialize(x).to_buffer() +deserialized_x = pyarrow.deserialize(serialized_x) +``` + +It can be used directly through the Ray API as follows. + +```python +x = [(1, 2), 'hello', 3, 4, np.array([5.0, 6.0])] +x_id = ray.put(x) +deserialized_x = ray.get(x_id) +``` + +## Getting Involved + +We welcome contributions, especially in the following areas. + +- Use the C++ and Java implementations of Arrow to implement versions of this +for C++ and Java. +- Implement support for more Python types and better test coverage. + +## Reproducing the Figures Above + +For reference, the figures can be reproduced with the following code. +Benchmarking `ray.put` and `ray.get` instead of `pyarrow.serialize` and +`pyarrow.deserialize` gives similar figures. + +```python +import pickle +import pyarrow +import matplotlib.pyplot as plt +import numpy as np +import timeit + + +def benchmark_object(obj, number=10): + # Time serialization and deserialization for pickle. + pickle_serialize = timeit.timeit( + lambda: pickle.dumps(obj, protocol=pickle.HIGHEST_PROTOCOL), + number=number) + serialized_obj = pickle.dumps(obj, pickle.HIGHEST_PROTOCOL) + pickle_deserialize = timeit.timeit(lambda: pickle.loads(serialized_obj), + number=number) + + # Time serialization and deserialization for Ray. + ray_serialize = timeit.timeit( + lambda: pyarrow.serialize(obj).to_buffer(), number=number) + serialized_obj = pyarrow.serialize(obj).to_buffer() + ray_deserialize = timeit.timeit( + lambda: pyarrow.deserialize(serialized_obj), number=number) + + return [[pickle_serialize, pickle_deserialize], + [ray_serialize, ray_deserialize]] + + +def plot(pickle_times, ray_times, title, i): + fig, ax = plt.subplots() + fig.set_size_inches(3.8, 2.7) + + bar_width = 0.35 + index = np.arange(2) + opacity = 0.6 + + plt.bar(index, pickle_times, bar_width, + alpha=opacity, color='r', label='Pickle') + + plt.bar(index + bar_width, ray_times, bar_width, + alpha=opacity, color='c', label='Ray') + + plt.title(title, fontweight='bold') + plt.ylabel('Time (seconds)', fontsize=10) + labels = ['serialization', 'deserialization'] + plt.xticks(index + bar_width / 2, labels, fontsize=10) + plt.legend(fontsize=10, bbox_to_anchor=(1, 1)) + plt.tight_layout() + plt.yticks(fontsize=10) + plt.savefig('plot-' + str(i) + '.png', format='png') + + +test_objects = [ + [np.random.randn(50000) for i in range(100)], + {'weight-' + str(i): np.random.randn(50000) for i in range(100)}, + {i: set(['string1' + str(i), 'string2' + str(i)]) for i in range(100000)}, + [str(i) for i in range(200000)] +] + +titles = [ + 'List of large numpy arrays', + 'Dictionary of large numpy arrays', + 'Large dictionary of small sets', + 'Large list of strings' +] + +for i in range(len(test_objects)): + plot(*benchmark_object(test_objects[i]), titles[i], i) +``` + +[1]: http://ray.readthedocs.io/en/latest/index.html +[2]: https://arrow.apache.org/ +[3]: https://en.wikipedia.org/wiki/Serialization +[4]: https://github.com/cloudpipe/cloudpickle/ +[5]: https://developers.google.com/protocol-buffers/ +[6]: https://google.github.io/flatbuffers/ +[7]: https://arrow.apache.org/docs/python/ipc.html#arbitrary-object-serialization +[8]: http://arrow.apache.org/docs/memory_layout.html#dense-union-type +[9]: http://arrow.apache.org/docs/memory_layout.html#list-type diff --git a/site/assets/fast_python_serialization_with_ray_and_arrow/arrow_object.png b/site/assets/fast_python_serialization_with_ray_and_arrow/arrow_object.png new file mode 100644 index 0000000000000000000000000000000000000000..f0a1839d90382e833373cfdba2a91d66a0bd7c77 GIT binary patch literal 12059 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 F{{hK)MsWZD literal 0 HcmV?d00001 diff --git a/site/assets/fast_python_serialization_with_ray_and_arrow/speedups0.png b/site/assets/fast_python_serialization_with_ray_and_arrow/speedups0.png new file mode 100644 index 0000000000000000000000000000000000000000..31ab26be1b48a1d059111f90f379ef016da98922 GIT binary patch literal 4050 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 literal 0 HcmV?d00001 diff --git a/site/assets/fast_python_serialization_with_ray_and_arrow/speedups2.png b/site/assets/fast_python_serialization_with_ray_and_arrow/speedups2.png new file mode 100644 index 0000000000000000000000000000000000000000..0d68299d135c3215422a2a6b7dd31ad1ae40b7e5 GIT binary patch literal 4276 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 aV8ckkHON3bB3}aR4NEgSYPE^am45?-7Ep5l literal 0 HcmV?d00001 diff --git a/site/assets/fast_python_serialization_with_ray_and_arrow/speedups3.png b/site/assets/fast_python_serialization_with_ray_and_arrow/speedups3.png new file mode 100644 index 0000000000000000000000000000000000000000..8f1879750431ac474013c22807f5946752d8fa17 GIT binary patch literal 13637 zcmb_@2{e{_`|e}NJP(nKFCmExNkTG2hR9G98A?hdl_8lkMJZ)Y8A6644V27dp^}J7 znHnU8%tM^(*?WKA`p#P4`k%AbIeV@4w)1-5=lMPNecjh^yI{6kpOr~~i698pT?V@5 z1VI&yKdcON_#3+K_n+WDw5PRqSu)@se}=62T>PH+1- ztC9ZdTbejG?GA#IGhgsg0b6iXQ~@0~!5J6rL@i1&-(yVZ>dHhj21gm_DNu26=1WTw z6bf%6t(IF5G)J zBPVB7iZLBMePjU}uH&sU%@!=;LJ=he}8`&=e3rVo2WP{y}!1t zA%aUwy;Hga7N+u(wd`zdWj0bREls`}Ty$(}#Z`m3_Aus9q)z9DgIz=E=x*9fhY z)vMb(IzmfI6nZ~?^!&3hed^~v&j5lcoH{*VW{sP>d*-cMH2C@C>(>wU*M!W?eDI*+ z`9skRSU8jNzJ6tHh~4+>+1j=?mQzmzckbNDzsZ5fx^=5j@%HW;p?FBouSqqYeQ|wD zq_O0=Z||D6^!cBU722k4Z!dxiKH8DZXlrLz68OiDC{7JLte9fG{OjXWJqHmQf+%&g2kP4)FJgOpTuaD*jn*q8XY z_+z=(2J^n_@_c+rWldasd{UjL;2tk$#gy^sZhL0Dy_D%qSdxN9 zy@MluWyYh5Ni*ikl`Bpwu|(LFD;xtaZ)|J)b$Xz@&z3#d?DlS`aO& zqj#HeNKv8;p;zMK#FX87?ltsW7TLZ$LlZ))LbWFaMZ?M}pd1_*$9cxfD=sDF!rcR9 zgU{l`RnPvGaB^~Le{{T?@+0T=?L$LNm+n1!)Ocf?4?$E_RXuz0Vihqp(#4Fg4Gau8 zKHOsFrlq=h^QP~@)Oy009%{rpfi@bzoN z_cyo2<>iYzZ{?oot6~ib3Oe)SEvr$ITw{(=()j2*rO}U1`IKB<>IMdC0uw|Ts0oM9 z&*GBNx2Wrg;;MxLgMgBf65pv|PQsxrSs_`~lXCyTgNbI5p#IzGfuZH)e))su$E?zV z^HQZ-*VJ?s?hAi?OP?9H&8xh5bIj6jCN{R!t*bR@dP?1|n`?ak{(Vppr7k8eu4Aj> zH#JOgAue3FFsM#XPe0I>qBPk0?wyUT_ds2ES(AODQm~v|c~o`cp+kqlM@L7Ue#n03 z8~-37ArbW>IW?8(?Afz}_Xp}DV_K`0ej9mK#l*y@uArF4dUw`-%PTD0kf!RXJ-0Yk zZ6tf3cbQMxpU%P2QLMsuLi^a+V=oChc466l~B

UMyyi#6y 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