Notizen im Python Pickle-Format

Hintergrund

Ich möchte Binärdaten zwischen Python und C / C ++ für maschinelles Lernen und spätes Rennen austauschen. Ich möchte nur die Standardfunktionen von Python verwenden. Für Text gibt es JSON und Numpy Text Format (CSV), aber Binärdateien sind auf der C ++ - Seite nicht einfach zu verwenden.

Betrachten Sie die Pickle-Serialisierung.

https://docs.python.org/ja/3/library/pickle.html

Es scheint, dass auch Endianness berücksichtigt wird.

Information

Die Seite, auf der Pickles Serialisierungsformat selbst kurz erklärt wurde, war ebenfalls nicht in englischer Sprache: Cry: (Sobald Sie es wissen, ist es nicht das komplizierte Format, daher reicht es möglicherweise nicht aus, es zu erklären ...)

Zum Glück unterstützt PyTorch JIT die Serialisierung mit einem eigenen C ++ - Pickle-Loader für die Implementierung von TorchScript (Python-ähnliche Skriptsprache), und der Code ist hilfreich.

https://github.com/pytorch/pytorch/blob/master/torch/csrc/jit/docs/serialization.md

https://github.com/pytorch/pytorch/blob/master/torch/csrc/jit/serialization/pickler.h

Sie können die Daten auch mit Pickletools in Python analysieren.

https://docs.python.org/ja/3.6/library/pickletools.html

Format

Protokollversion

Es gibt mehrere Protokollversionen von Pickle. In Python3 ist 3 die Standardeinstellung, aber wenn sie in Python3 mit Proto 3 serialisiert wird, kann sie in Python2 nicht gelesen werden.

Wenn Sie hauptsächlich numerische Daten verwenden und keine Daten verarbeiten, die nicht sehr seltsam sind, wird Proto 2 empfohlen? (TorchScript unterstützt nur Proto 2)

Der Header besteht aus 2 Bytes "0x80" (PROTO, 1 Byte) und der Versionsnummer (1 Byte).

Versuchen wir, 1 zu serialisieren.

import pickle
import io

a = 1 

f = io.BytesIO()
b = pickle.dump(a, f)

w = open("bora.p", "wb")
w.write(f.getbuffer())
$ od -tx1c bora.p
0000000  80  03  4b  01  2e
        200 003   K 001   .
0000005

"K" ist "BININT1" . (2e) ist STOP. Datenende.

Mit Blick auf unpicker.cpp in pytorch jit,

    case PickleOpCode::BININT1: {
      uint8_t value = read<uint8_t>();
      stack_.emplace_back(int64_t(value));
    } break;

Da dies der Fall ist, können Sie sehen, dass BININT1 ein Wert vom Typ int ist, der mit 1 Byte serialisiert werden kann.

Probieren Sie die Array-Daten aus.

import pickle
import io

a = [1, 2] 

f = io.BytesIO()
b = pickle.dump(a, f, protocol=2)

w = open("bora.p", "wb")
w.write(f.getbuffer())

Lassen Sie es uns jetzt mit Pickletools entsorgen.

$ python -m pickletools bora.p 
    0: \x80 PROTO      2
    2: ]    EMPTY_LIST
    3: q    BINPUT     0
    5: (    MARK
    6: K        BININT1    1
    8: K        BININT1    2
   10: e        APPENDS    (MARK at 5)
   11: .    STOP
highest protocol among opcodes = 2

Grundsätzlich handelt es sich um eine Kombination aus Präfix und tatsächlichen Daten. Danach sollten Sie verschiedene Dinge ausprobieren, indem Sie auf pickler.cpp, unpickler.cpp und pickletools.py von pytorch jit verweisen und diese analysieren!

numpy array

Lassen Sie uns das numpy-Array (ndarray) serialisieren.

a = numpy.array([1.0, 2.2, 3.3, 4, 5, 6, 7, 8, 9, 10], dtype=numpy.float32)

f = io.BytesIO()
b = pickle.dump(a, f, protocol=2)

w = open("bora.p", "wb")
w.write(f.getbuffer())
    0: \x80 PROTO      2
    2: c    GLOBAL     'numpy.core.multiarray _reconstruct'
   38: q    BINPUT     0
   40: c    GLOBAL     'numpy ndarray'
   55: q    BINPUT     1
   57: K    BININT1    0
   59: \x85 TUPLE1
   60: q    BINPUT     2
   62: c    GLOBAL     '_codecs encode'
   78: q    BINPUT     3
   80: X    BINUNICODE 'b'
   86: q    BINPUT     4
   88: X    BINUNICODE 'latin1'
   99: q    BINPUT     5
  101: \x86 TUPLE2
  102: q    BINPUT     6
  104: R    REDUCE
  105: q    BINPUT     7
  107: \x87 TUPLE3
  108: q    BINPUT     8
  110: R    REDUCE
  111: q    BINPUT     9
  113: (    MARK
  114: K        BININT1    1
  116: K        BININT1    10
  118: \x85     TUPLE1
  119: q        BINPUT     10
  121: c        GLOBAL     'numpy dtype'
  134: q        BINPUT     11
  136: X        BINUNICODE 'f4'
  143: q        BINPUT     12
  145: K        BININT1    0
  147: K        BININT1    1
  149: \x87     TUPLE3
  150: q        BINPUT     13
  152: R        REDUCE
  153: q        BINPUT     14
  155: (        MARK
  156: K            BININT1    3
  158: X            BINUNICODE '<'
  164: q            BINPUT     15
  166: N            NONE
  167: N            NONE
  168: N            NONE
  169: J            BININT     -1
  174: J            BININT     -1
  179: K            BININT1    0
  181: t            TUPLE      (MARK at 155)
  182: q        BINPUT     16
  184: b        BUILD
  185: \x89     NEWFALSE
  186: h        BINGET     3
  188: X        BINUNICODE '\x00\x00\x80?ÍÌ\x0c@33S@\x00\x00\x80@\x00\x00\xa0@\x00\x00À@\x00\x00à@\x00\x00\x00A\x00\x00\x10A\x00\x00 A'
  240: q        BINPUT     17
  242: h        BINGET     5
  244: \x86     TUPLE2
  245: q        BINPUT     18
  247: R        REDUCE
  248: q        BINPUT     19
  250: t        TUPLE      (MARK at 113)
  251: q    BINPUT     20
  253: b    BUILD
  254: .    STOP
highest protocol among opcodes = 2

Sie können sehen, dass die Array-Daten als Byte-String um BINUNICODE gespeichert sind. Nach der Analyse des Quellcodes von numpy können Sie die Pickle-Version von numpy array und pytorch tensor (Sie können sich vorstellen, dass es eine ähnliche Struktur wie numpy hat) mit Ihrem eigenen C ++ - Loader laden! (numpy native? NPY / NPZ hat ein etwas prägnantes Format, zum Beispiel kann cnpy https://github.com/rogersce/cnpy lesen und schreiben)

TODO

Recommended Posts

Notizen im Python Pickle-Format
Python-Scraping-Memo
Python lernen note_000
Python-Lernnotizen
Python lernen note_006
Python C ++ Notizen
Python lernen note_005
Python-Grammatiknotizen
Python Library Hinweis
Python-String-Format
Python persönliche Notizen
Format in Python
Python Pandas Memo
Python lernen note_001
Python-Lernnotizen
Installationshinweise zu Python3.4
Python-Variablenerweiterung, Format
fehlende Ganzzahlen Python persönliche Notizen
Hinweise zur Entwicklung von Python-Paketen
Verwendungshinweise für Python Decorator
Python-IP-Adresse Paket Memo
Bildformat in Python
Methodische Verwendung im [Python] -Format
Erstes Python-Memo
Matlab => Python-Migrationsnotizen
Hinweise zur Python3-Zuweisung
Hinweise zur Verwendung von Python-Unterprozessen
Python versuchen / außer Memo
Hinweise zur Python-Framework-Flasche
Python-Memo mit perl-ternärem Operator
Einfaches Formatieren von JSON mit Python
Python-Einzug und String-Format
O'Reilly python3 Primer Lernnotiz
Hinweise zur Verwendung des Python-Standards unittest
Python-Notizen, die Sie bald vergessen sollten
python * args, ** kwargs Verwendungshinweise
Python-Notizen zur Verwendung von Perl-Spezialvariablen
Python-Theorie regulärer Ausdruck Anmerkungen
Python Tkinter Memo (für mich)
Lernnotizen zur Python-Datenanalyse
Hinweise zur Installation von Python auf Ihrem Mac
[Python 2/3] Analysiert die Formatzeichenfolge
Beispiel für die Verwendung von Python Pickle
Formatieren Sie json mit Vim (mit Python)
Holen Sie sich Evernote-Notizen in Python
String-Format mit Python% -Operator
Hinweise zur Installation von Python unter CentOS
Hinweise zu Python- und Wörterbuchtypen
Python
Python-Anwendung: Datenverarbeitung # 3: Datenformat
Minimale Grammatiknotizen zum Schreiben von Python
Hinweise zur Verwendung von MeCab aus Python
Formatieren Sie Python-Code automatisch mit Vim
Behandeln Sie Daten im NetCDF-Format mit Python
Behandeln Sie das GDS II-Format mit Python
Über Python Pickle (cPickle) und Marschall
Persönliche Notizen für die Python-Bildverarbeitung
Persönliche Notizen zur Vorverarbeitung von Python Pandas-Daten