KBQA_多轮对话——模型源码解析(一)Pickle模块功能详解
KBQA_多輪對(duì)話——模型源碼解析(一)Pickle模塊功能詳解
- pickle --- Python 對(duì)象序列化的基本功能
- 1、pickle基本概念
- 2、pickle 與 json 模塊的比較
- 3、pickle應(yīng)用實(shí)例
- 4、pickle模塊解析CIFAR-10數(shù)據(jù)集
- 5、【對(duì)象持久性】的理解
pickle — Python 對(duì)象序列化的基本功能
1、pickle基本概念
模塊pickle實(shí)現(xiàn)了對(duì)一個(gè)Python對(duì)象結(jié)構(gòu)的二進(jìn)制序列化 “封存 (pickling)” 和 反序列化 “解封 (unpickling)”。
- pickling是將Python對(duì)象及其所擁有的層次結(jié)構(gòu)轉(zhuǎn)化為一個(gè)字節(jié)流的過(guò)程;
- unpickling是相反的操作,會(huì)將(來(lái)自一個(gè)binary file 或者 bytes-like object)的字節(jié)流轉(zhuǎn)化回一個(gè)對(duì)象層次結(jié)構(gòu)。
參考鏈接:pickle的官方開(kāi)發(fā)文檔——pickle — Python 對(duì)象序列化
- pickle模塊對(duì)于錯(cuò)誤或惡意構(gòu)造的數(shù)據(jù)是不安全的。
數(shù)據(jù)流格式: pickle 所使用的數(shù)據(jù)格式僅可用于 Python。
這樣做的好處是沒(méi)有外部標(biāo)準(zhǔn)給該格式強(qiáng)加限制,比如 JSON 或 XDR(不能表示共享指針)標(biāo)準(zhǔn);但這也意味著 非 Python 程序可能無(wú)法重新讀取 pickle 封存的 Python 對(duì)象 。
默認(rèn)情況下,pickle 格式使用相對(duì)緊湊的二進(jìn)制來(lái)存儲(chǔ)。如果需要讓文件更小,可以高效地 壓縮 由 pickle 封存的數(shù)據(jù)。
注解:序列化是一種比持久化更底層的概念,雖然 pickle 讀取和寫(xiě)入的是文件對(duì)象,但它不處理持久對(duì)象的命名問(wèn)題,也不處理對(duì)持久對(duì)象的并發(fā)訪問(wèn)(甚至更復(fù)雜)的問(wèn)題。pickle 模塊可以將復(fù)雜對(duì)象轉(zhuǎn)換為字節(jié)流,也可以將字節(jié)流轉(zhuǎn)換為具有相同內(nèi)部結(jié)構(gòu)的對(duì)象。處理這些字節(jié)流最常見(jiàn)的做法是將它們寫(xiě)入文件,但它們也可以通過(guò)網(wǎng)絡(luò)發(fā)送或存儲(chǔ)在數(shù)據(jù)庫(kù)中。shelve 模塊提供了一個(gè)簡(jiǎn)單的接口,用于在 DBM 類(lèi)型的數(shù)據(jù)庫(kù)文件上封存和解封對(duì)象。
模塊接口:
要序列化某個(gè)包含層次結(jié)構(gòu)的對(duì)象,只需調(diào)用 dumps() 函數(shù)即可。同樣,要反序列化數(shù)據(jù)流,可以調(diào)用 loads() 函數(shù)。但是,如果要對(duì)序列化和反序列化加以更多的控制,可以分別創(chuàng)建 Pickler 或 Unpickler 對(duì)象。
pickle 模塊的常用方法:
pickle 模塊提供了以下方法,讓封存過(guò)程更加方便:
將對(duì)象 obj 封存以后的對(duì)象寫(xiě)入已打開(kāi)的 file object file。它等同于 Pickler(file, protocol).dump(obj)。
備注:參數(shù) file、protocol、fix_imports 和 buffer_callback 的含義與它們?cè)?Pickler 的構(gòu)造函數(shù)中的含義相同。
將 obj 封存以后的對(duì)象作為 bytes 類(lèi)型直接返回,而不是將其寫(xiě)入到文件。
備注:參數(shù) protocol、fix_imports 和 buffer_callback 的含義與它們?cè)?Pickler 的構(gòu)造函數(shù)中的含義相同。
從已打開(kāi)的 file object 文件 中讀取封存后的對(duì)象,重建其中特定對(duì)象的層次結(jié)構(gòu)并返回。它相當(dāng)于 Unpickler(file).load()。
Pickle 協(xié)議版本是自動(dòng)檢測(cè)出來(lái)的,所以不需要參數(shù)來(lái)指定協(xié)議。封存對(duì)象以外的其他字節(jié)將被忽略。
備注:參數(shù) file、fix_imports、encoding、errors、strict 和 buffers 的含義與它們?cè)?Unpickler 的構(gòu)造函數(shù)中的含義相同。
重建并返回一個(gè)對(duì)象的封存表示形式 data 的對(duì)象層級(jí)結(jié)構(gòu)。 data 必須為 bytes-like object。
Pickle 協(xié)議版本是自動(dòng)檢測(cè)出來(lái)的,所以不需要參數(shù)來(lái)指定協(xié)議。封存對(duì)象以外的其他字節(jié)將被忽略。
備注:參數(shù) file、fix_imports、encoding、errors、strict 和 buffers 的含義與它們?cè)?Unpickler 的構(gòu)造函數(shù)中的含義相同。
pickle 模塊包含了 3 個(gè)類(lèi),Pickler、Unpickler 和 PickleBuffer:
class pickle.Pickler(file, protocol=None, *, fix_imports=True, buffer_callback=None)
它接受一個(gè)二進(jìn)制文件用于寫(xiě)入 pickle 數(shù)據(jù)流。
class pickle.Unpickler(file, *, fix_imports=True, encoding='ASCII', errors='strict', buffers=None)
它接受一個(gè)二進(jìn)制文件用于讀取 pickle 數(shù)據(jù)流。
class pickle.PickleBuffer(buffer)
緩沖區(qū)的包裝器 (wrapper),緩沖區(qū)中包含著可封存的數(shù)據(jù)。buffer 必須是一個(gè) buffer-providing 對(duì)象,比如 bytes-like object 或多維數(shù)組。
2、pickle 與 json 模塊的比較
json 模塊:是一個(gè)允許JSON序列化 和 反序列化的標(biāo)準(zhǔn)庫(kù)模塊。
Pickle 協(xié)議和 JSON (JavaScript Object Notation) 間有著本質(zhì)的不同:
\quad
3、pickle應(yīng)用實(shí)例
示例1:創(chuàng)建一個(gè)文件,通過(guò)pickle模塊編碼為二進(jìn)制流,再u(mài)npickle解碼為可讀數(shù)據(jù)。
import numpy as np import pickle import osif __name__=='__main__':path = r'/Users/zhang/Documents/my_daily/KBQA_for_Diagnosis_yangyang/nlu/bert_intent_recognition/test_picklefile'file = open(path, 'wb')data = {'a':123, 'b':'ads', 'c':[[1,2],[3,4]]}pickle.dump(data, file)print("file:", file)file.close()f1 = open(path, 'rb')print("file1:", f1)data1 = pickle.load(f1)print(data1)打印輸出: >>> file: <_io.BufferedWriter name='/Users/yangyang/Documents/my_daily/KBQA_for_Diagnosis_yangyang/nlu/bert_intent_recognition/test_picklefile'> file1: <_io.BufferedReader name='/Users/yangyang/Documents/my_daily/KBQA_for_Diagnosis_yangyang/nlu/bert_intent_recognition/test_picklefile'> {'a': 123, 'b': 'ads', 'c': [[1, 2], [3, 4]]}示例2:創(chuàng)建一個(gè)文件,通過(guò)pickle模塊編碼為二進(jìn)制流,再u(mài)npickle解碼為可讀數(shù)據(jù)。
import numpy as np import pickle import os import random import matplotlib.pyplot as plt from PIL import Imagepath1 = r'/Users/yangyang/Documents/學(xué)習(xí)資料/d2l-zh/data/cifar_10數(shù)據(jù)集/cifar-10-batches-py/data_batch_1'if __name__ == '__main__':with open(path1, 'rb') as fo:data_dict = pickle.load(fo, encoding='bytes')print("data_dict:", data_dict)print("data_dict包含的鍵:",data_dict.keys())print("data_dict[b'batch_label']:",data_dict[b'batch_label'])print("data_dict[b'labels']:",data_dict[b'labels'])print("data_dict[b'filenames']:",data_dict[b'filenames'])print("data_dict[b'data'].shape:",data_dict[b'data'].shape)images_batch = np.array(data_dict[b'data'])images = images_batch.reshape([-1, 3, 32, 32])print("images.shape:",images.shape)imgs = images[5,:,:,:].reshape([3,32,32]) # images的四個(gè)維度分別為[第N張圖像, 圖像channel, 圖像width, 圖像length]img = np.stack((imgs[0,:,:], imgs[1,:,:], imgs[2,:,:]), 2)print("img.shape:",img.shape)plt.imshow(img)plt.axis('off')plt.show()輸出結(jié)果: >>> data_dict: {b'batch_label': b'training batch 1 of 5', b'labels': [6, 9, 9, 4, 1,...,],b'data': array([[ 59, 43, 50, ..., 140, 84, 72],[154, 126, 105, ..., 139, 142, 144],[255, 253, 253, ..., 83, 83, 84],...,[ 71, 60, 74, ..., 68, 69, 68],[250, 254, 211, ..., 215, 255, 254],[ 62, 61, 60, ..., 130, 130, 131]], dtype=uint8), b'filenames': [b'leptodactylus_pentadactylus_s_000004.png', b'camion_s_000148.png', b'tipper_truck_s_001250.png',...]>>> data_dict包含的鍵: dict_keys([b'batch_label', b'labels', b'data', b'filenames']) >>> data_dict[b'batch_label']: b'training batch 1 of 5' >>> data_dict[b'labels']: [6, 9, 9, 4, 1, 1, 2, 7, 8, 3, 4, 7, 7, 2,...] >>> data_dict[b'filenames']: [b'leptodactylus_pentadactylus_s_000004.png', b'camion_s_000148.png',...] >>> data_dict[b'data'].shape: (10000, 3072) >>> images.shape: (10000, 3, 32, 32) >>> "img.shape:"(32, 32, 3)4、pickle模塊解析CIFAR-10數(shù)據(jù)集
CIFAR-10和CIFAR-100是來(lái)自于80 million張小型圖片的數(shù)據(jù)集,圖片收集者是Alex Krizhevsky, Vinod Nair, and Geoffrey Hinton。
官網(wǎng) http://www.cs.toronto.edu/~kriz/cifar.html
cifar-10 數(shù)據(jù)集說(shuō)明及下載:
飛機(jī)、汽車(chē)、鳥(niǎo)、貓、鹿、狗、青蛙、馬、船、貨車(chē)。其中,5萬(wàn)張作為訓(xùn)練集,1萬(wàn)張作為測(cè)試機(jī)。訓(xùn)練集被分為了5批訓(xùn)練和1批測(cè)試。每一批都是1萬(wàn)張。測(cè)試集是從每一種分類(lèi)中隨機(jī)抽取出來(lái)1000張組成。訓(xùn)練集從10個(gè)分類(lèi)中各自隨機(jī)抽取5000張,一共5萬(wàn)張。
說(shuō)明:
- 沒(méi)有后綴名的文件,如:data_batch_1,其實(shí)都是用python的cpickle庫(kù)打包好的,這個(gè)庫(kù)就是用來(lái)將python中的變量原封不動(dòng)地存到本地使用的,當(dāng)再次使用的時(shí)候,可以讀取出來(lái)。
備注:有經(jīng)驗(yàn)的朋友會(huì)自動(dòng)和json.dumps聯(lián)系起來(lái),其實(shí)json模塊只能保存一個(gè)字典到本地的json文件,而pickle模塊(或者cpickle)卻可以打包任何對(duì)象。
通過(guò)pickle在python3環(huán)境下讀取CIFAR-10數(shù)據(jù):
def unpickle(file):import picklewith open(file, 'rb') as fo:dict = pickle.load(fo, encoding='bytes')return dictdata = unpickle('test_batch') data.keys() # dict_keys([b'batch_label', b'labels', b'data', b'filenames']) data[b'data'][0] # array([158, 159, 165, ..., 124, 129, 110], dtype=uint8)每個(gè)字典如下表所示,每個(gè)batch文件轉(zhuǎn)換為dictonary,其中的內(nèi)容是:
| data | a 10000×3072 array(uint85),array的每行是一張32×32的彩色圖片,前1024是red channel的值,后面1024是green channel的值,最后1024是blue channel的值。圖片是以行主順序存儲(chǔ),所以,前數(shù)組中前32個(gè)數(shù)表示的是一張圖片第一行的red channel values。 |
| labels | 標(biāo)簽,長(zhǎng)度是10000,每個(gè)都是0-9的數(shù)字,是一個(gè)列表。其索引和data里面的索引相互對(duì)應(yīng)。 |
| batch_label | batch的名稱(chēng) |
| filenames | 數(shù)據(jù)集中data對(duì)應(yīng)的圖片名稱(chēng)數(shù)組 |
- 含后綴的文件batches.meta,這個(gè)文件保存的就是索引與名字之間的對(duì)應(yīng)。如:label_names[0] == “airplane”, label_names[1] == “automobile”,batches.meta文件包含了[b’num_cases_per_batch’, b’label_names’, b’num_vis’]。其中,label_names 對(duì)應(yīng) 十個(gè)類(lèi)別的英文名,cifar-10劃分為5個(gè)training batches。圖像也是彩色的,所以要給圖像的三個(gè)通道進(jìn)行管理。
參考鏈接:
讀取代碼參考:https://blog.csdn.net/DarrenXf/article/details/85471718,
cifar10數(shù)據(jù)格式以及讀取方式:https://blog.csdn.net/u014281392/article/details/74881967,
TensorFlow進(jìn)階:CNN對(duì)CIFAR10圖像分類(lèi)和python讀取,https://www.cnblogs.com/jimobuwu/p/9161531.html
將cifar的3個(gè)單通道數(shù)據(jù),轉(zhuǎn)化為三通道數(shù)據(jù),并保存:
p = './data/cifar-10-batches/data_batch_1' d = unpickle(p) #print(d) #print(d.keys()) #print(d[b'batch_label']) #print(d[b'labels']) #print(d[b'filenames'])e = d[b'data'] for i in range(100):image = e[i]red_image = image[:1024].reshape(32,32)green_image = image[1024:2048].reshape(32,32)blue_image = image[2048:].reshape(32,32)result_img = np.ones((32, 32, 3), dtype=np.uint8)result_img[:,:,0] = red_imageresult_img[:,:,1] = green_imageresult_img[:,:,2] = blue_imagecv2.imwrite('a\\'+str(i)+'.jpg',result_img)
參考鏈接:深度學(xué)習(xí):CIFAR-10數(shù)據(jù)集讀取實(shí)操
5、【對(duì)象持久性】的理解
什么是持久性?
持久性的基本思想很簡(jiǎn)單。假定有一個(gè) Python 程序,它可能是一個(gè)管理日常待辦事項(xiàng)的程序,您希望在多次執(zhí)行這個(gè)程序之間可以保存應(yīng)用程序?qū)ο?#xff08;待辦事項(xiàng))。換句話說(shuō),您希望將對(duì)象存儲(chǔ)在磁盤(pán)上,便于以后檢索。這就是持久性。要達(dá)到這個(gè)目的,有幾種方法,每一種方法都有其優(yōu)缺點(diǎn)。
例如,可以將對(duì)象數(shù)據(jù)存儲(chǔ)在某種格式的文本文件中,譬如 CSV 文件。或者可以用關(guān)系數(shù)據(jù)庫(kù),譬如 Gadfly、MySQL、PostgreSQL 或者 DB2。這些文件格式和數(shù)據(jù)庫(kù)都非常優(yōu)秀,對(duì)于所有這些存儲(chǔ)機(jī)制,Python 都有健壯的接口。
這些存儲(chǔ)機(jī)制都有一個(gè)共同點(diǎn): 存儲(chǔ)的數(shù)據(jù)是獨(dú)立于對(duì)這些數(shù)據(jù)進(jìn)行操作的對(duì)象和程序。這樣做的好處是,數(shù)據(jù)可以作為共享的資源,供其它應(yīng)用程序使用。缺點(diǎn)是,用這種方式,可以允許其它程序訪問(wèn)對(duì)象的數(shù)據(jù),這違背了面向?qū)ο蟮姆庋b性原則 — 即對(duì)象的數(shù)據(jù)只能通過(guò)這個(gè)對(duì)象自身的公共(public)接口來(lái)訪問(wèn)。
另外,對(duì)于某些應(yīng)用程序,關(guān)系數(shù)據(jù)庫(kù)方法可能不是很理想。尤其是,關(guān)系數(shù)據(jù)庫(kù)不理解對(duì)象。相反,關(guān)系數(shù)據(jù)庫(kù)會(huì)強(qiáng)行使用自己的類(lèi)型系統(tǒng)和關(guān)系數(shù)據(jù)模型(表),每張表包含一組元組(行),每行包含具有固定數(shù)目的靜態(tài)類(lèi)型字段(列)。如果應(yīng)用程序的對(duì)象模型不能夠方便地轉(zhuǎn)換到關(guān)系模型,那么在將對(duì)象映射到元組以及將元組映射回對(duì)象方面,會(huì)碰到一定難度。這種困難常被稱(chēng)為阻礙性不匹配(impedence-mismatch)問(wèn)題。
對(duì)象持久性
如果希望透明地存儲(chǔ) Python 對(duì)象,而不丟失其身份和類(lèi)型等信息,則需要某種形式的對(duì)象序列化:它是一個(gè)將任意復(fù)雜的對(duì)象轉(zhuǎn)成對(duì)象的文本或二進(jìn)制表示的過(guò)程。同樣,必須能夠?qū)?duì)象經(jīng)過(guò)序列化后的形式恢復(fù)到原有的對(duì)象。在 Python 中,這種序列化過(guò)程稱(chēng)為 pickle,可以將對(duì)象 pickle 成字符串、磁盤(pán)上的文件或者任何類(lèi)似于文件的對(duì)象,也可以將這些字符串、文件或任何類(lèi)似于文件的對(duì)象 unpickle 成原來(lái)的對(duì)象。我們將在本文后面詳細(xì)討論 pickle。
假定您喜歡將任何事物都保存成對(duì)象,而且希望避免將對(duì)象轉(zhuǎn)換成某種基于非對(duì)象存儲(chǔ)的開(kāi)銷(xiāo);那么 pickle 文件可以提供這些好處,但有時(shí)可能需要比這種簡(jiǎn)單的 pickle 文件更健壯以及更具有可伸縮性的事物。例如,只用 pickle 不能解決命名和查找 pickle 文件這樣的問(wèn)題,另外,它也不能支持并發(fā)地訪問(wèn)持久性對(duì)象。如果需要這些方面的功能,則要求助類(lèi)似于 ZODB(針對(duì) Python 的 Z 對(duì)象數(shù)據(jù)庫(kù))這類(lèi)數(shù)據(jù)庫(kù)。ZODB 是一個(gè)健壯的、多用戶的和面向?qū)ο蟮臄?shù)據(jù)庫(kù)系統(tǒng),它能夠存儲(chǔ)和管理任意復(fù)雜的 Python 對(duì)象,并支持事務(wù)操作和并發(fā)控制。(請(qǐng)參閱 參考資料,以下載 ZODB。)令人足夠感興趣的是,甚至 ZODB 也依靠 Python 的本機(jī)序列化能力,而且要有效地使用 ZODB,必須充分了解 pickle。
另一種令人感興趣的解決持久性問(wèn)題的方法是 Prevayler,它最初是用 Java 實(shí)現(xiàn)的(有關(guān) Prevaylor 方面的developerWorks 文章,請(qǐng)參閱 參考資料)。最近,一群 Python 程序員將 Prevayler 移植到了 Python 上,另起名為 PyPerSyst,由 SourceForge 托管(有關(guān)至 PyPerSyst 項(xiàng)目的鏈接,請(qǐng)參閱 參考資料)。Prevayler/PyPerSyst 概念也是建立在 Java 和 Python 語(yǔ)言的本機(jī)序列化能力之上。PyPerSyst 將整個(gè)對(duì)象系統(tǒng)保存在內(nèi)存中,并通過(guò)不時(shí)地將系統(tǒng)快照 pickle 到磁盤(pán)以及維護(hù)一個(gè)命令日志(通過(guò)此日志可以重新應(yīng)用最新的快照)來(lái)提供災(zāi)難恢復(fù)。所以,盡管使用 PyPerSyst 的應(yīng)用程序受到可用內(nèi)存的限制,但好處是本機(jī)對(duì)象系統(tǒng)可以完全裝入到內(nèi)存中,因而速度極快,而且實(shí)現(xiàn)起來(lái)要比如 ZODB 這樣的數(shù)據(jù)庫(kù)簡(jiǎn)單,ZODB 允許對(duì)象的數(shù)目比同時(shí)在能內(nèi)存中所保持的對(duì)象要多。
既然我們已經(jīng)簡(jiǎn)要討論了存儲(chǔ)持久對(duì)象的各種方法,那么現(xiàn)在該詳細(xì)探討 pickle 過(guò)程了。雖然我們主要感興趣的是探索以各種方式來(lái)保存 Python 對(duì)象,而不必將其轉(zhuǎn)換成某種其它格式,但我們?nèi)匀贿€有一些需要關(guān)注的地方,譬如:如何有效地 pickle 和 unpickle 簡(jiǎn)單對(duì)象以及復(fù)雜對(duì)象,包括定制類(lèi)的實(shí)例;如何維護(hù)對(duì)象的引用,包括循環(huán)引用和遞歸引用;以及如何處理類(lèi)定義發(fā)生的變化,從而使用以前經(jīng)過(guò) pickle 的實(shí)例時(shí)不會(huì)發(fā)生問(wèn)題。我們將在隨后關(guān)于 Python 的 pickle 能力探討中涉及所有這些問(wèn)題。
一些經(jīng)過(guò) pickle 的 Python
pickle 模塊及其同類(lèi)模塊 cPickle 向 Python 提供了 pickle 支持。后者是用 C 編碼的,它具有更好的性能,對(duì)于大多數(shù)應(yīng)用程序,推薦使用該模塊。我們將繼續(xù)討論 pickle ,但本文的示例實(shí)際是利用了 cPickle 。由于其中大多數(shù)示例要用 Python shell 來(lái)顯示,所以先展示一下如何導(dǎo)入 cPickle ,并可以作為 pickle 來(lái)引用它:
參考鏈接:Python pickle模塊學(xué)習(xí)(超級(jí)詳細(xì))
總結(jié)
以上是生活随笔為你收集整理的KBQA_多轮对话——模型源码解析(一)Pickle模块功能详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 彻底理解DDS(信号发生器)的fpga实
- 下一篇: Spring Boot(二)——项目热部