【Python】データのシリアライズ概要と関係モジュール

プログラミング

本記事はPythonのシリアライズと、関係モジュールについての個人的な備忘録的なものです。想定読者は以下です。

  • 機械学習やってたら○○.pickleとかいうファイル出てきたけどこいつ何者?ってなった人
  • 直列化とかシリアライズとか言われてもイマイチピンとこない人
  • この記事を書く前の自分 ←

ということで、早速本題に入っていきましょう。

シリアライズ(直列化)とは?

みんな大好きWikipediaさんによると

「ある環境において存在しているオブジェクトを、バイト列やXMLフォーマットに変換することをいう」

wikipedia/シリアライズ

とのことです。Wikiのユーザーなら誰もが思う「で、結局何?」って声が聞こえてきそうな説明文ですね。例えばPythonでいうと、以下のような感じかと思います。

  • オブジェクト:Pythonの文字列とか、数値データ、自作のクラスなど。
  • バイト列: 2進数・16進数などのデータ。”0″と”1″で表現されているもの。通信可能。
  • XML:マークアップ言語の一種。ASCIIによるテキストデータ形式なので通信可能。

要は、プログラムの中に出てくる「意味を持ったデータの塊」を、通信したり、ファイル書き込みできる形状に変換するということが「シリアライズ(直列化)」ということです。

【使いどころ】

Python(というよりは機械学習)に触れていると、Pickleによりシリアライズして学習途中のデータを保存したり、それを読み込んで処理の続きを行ったりということが割と頻繁に行われています。処理途中のデータをバイト列に変形して保存するので読み出しが早いなどのメリットがあると言われています(未検証)。

さて、シリアライズについてザックリ説明はしたものの、これだけではイマイチ理解できないという人の方が多いかと思います。次の章では、Pythonを用いた具体的なオブジェクトの変換例を見て理解を深めてみましょう。

Pythonによるデータのシリアライズ例

例えば、Pythonで”65535″という数値データ(int型)を、シリアライズすると次のようになります。

import struct

binary = struct.pack(">L", 65535)
print(binary)

# 出力結果: b'\x00\x00\xff\xff'

65535という数値データが、16進数で”0000FFFF”となっていることが見て取れます。つまり、4Byteのデータとして、”00000000″、”00000000″、”11111111″、”11111111″となっているということです。

ちなみに、上記のコードの解説をしておくと、

  • struct:Pythonの標準ライブラリ。
  • pack:structの関数。”>”は「ビッグエンディアン」、”L”は符号なし4Byte整数を表す。

というところです。「ビッグエンディアン」などのバイトオーダーは、計算機・通信の挙動を理解する上で重要な概念ですがここでは深くは触れないことにします。

※ 自分の理解確認も兼ねて、別の記事で説明しようかとは思います。概要だけ言っておくと、計算機がメモリ上のデータを前から読むか、後ろから読むか、というルールを表しているとだけ認識していればOKかと思います。

上記はただの整数データだったので、もう一つシリアライズの例を出してみようと思います。

import pickle 

class SampleClass:
    def __init__(self, data):
        self.data = data

    def increment(self):
        self.data += 1

sample = SampleClass(100)
serialized = pickle.dumps(sample)
print(serialized)

# 出力結果:
# b'\x80\x03c__main__\nSampleClass\nq\x00)\x81q\x01}q\x02X\x04\x00\x00\x00dataq\x03Kdsb.'

保持しているデータをインクリメントするという機能を持った、単純なSampleClassのインスタンスを作成し、それをpickleというモジュールでシリアライズするコードです。出力結果をみると、一部”__main__” や、”SampleClass”など、人間がみて理解できる部分を含みますが、基本的に16進数+ASCIIデータ(参考) に変換されていることが分かります。

※このことは pickle.dumps() の返り値がbytesオブジェクトというところから判断しているので、間違っていたら教えていただけると助かります(参考:pickle & bytesオブジェクト ← dumps と bytes でページ内検索をかけてください)

シリアライズに関係するモジュール例

シリアライズの際によく出てくるモジュールは以下のようなものがあります。

  • struct
  • pickle
  • joblib
  • etc…(ほかにも色々あります)

structとpickleについては上記でも紹介しました。structはC言語で扱うデータとの互換性を意識したものになっており、変換の際に書式として「符号なし2Byte整数」「符号あり4Byte整数」「倍精度浮動小数点」などを指定するところが特徴として挙げられます。一方pickleはPythonオブジェクトを直接ファイル化したい時などに用いる印象が強いです。

上記に挙げているjoblibについては、pickleと同じ感覚で使えます。dumpするときに、引数で”compress=3″などと指定することで、圧縮されたシリアルデータとして保存できる部分が大きな違いになります。

また、シリアライズのモジュールではありませんが、ディープラーニングのフレームワークであるtensorflowにも、「tf.Example」「TFRocord」というデータのシリアライズメソッド・保存形式が存在します。これは学習の計算におけるI/Oバウンドな部分を削るのに威力を発揮します。大規模データを扱う際、ストレージと学習実行のマシンが別だったりすることがあるのですが、データの読み込みを待ってから学習を開始するのでは通信時間の無駄が生じます。そこで、データをストリーミングで読みだして、学習しながらデータも取得するということを行うわけです。その際に、シリアライズしておかないと効率的な通信ができないので、このようなメソッドが用意されているという訳です。

まとめ

本記事では、「シリアライズ」の概要、Pythonでのシリアライズ実装例、Pythonにおけるシリアライズ関係モジュールについて解説しました。モジュール例のところでも触れましたが、大容量のデータ(オブジェクト)を一時保存・通信するときにこの「シリアライズ」関係のモジュールは威力を発揮します。時間効率などを考えるときには視野に入ってくる技術だと思いますので、しっかり理解しておきたいところですね。今回は以上となります。最後までお読みいただき、ありがとうございました!

コメント

タイトルとURLをコピーしました