KBQA_多轮对话——模型源码解析(一)Pickle模块功能详解

  • pickle --- Python 对象序列化的基本功能
    • 1、pickle基本概念
    • 2、pickle 与 json 模块的比较
    • 3、pickle应用实例
    • 4、pickle模块解析CIFAR-10数据集
    • 5、【对象持久性】的理解

pickle — Python 对象序列化的基本功能

1、pickle基本概念

模块pickle实现了对一个Python对象结构的二进制序列化 “封存 (pickling)”反序列化 “解封 (unpickling)”

  • pickling是将Python对象及其所拥有的层次结构转化为一个字节流的过程;
  • unpickling是相反的操作,会将(来自一个binary file 或者 bytes-like object)的字节流转化回一个对象层次结构。

参考链接:pickle的官方开发文档——pickle — Python 对象序列化

  • pickle模块对于错误或恶意构造的数据是不安全的。

数据流格式: pickle 所使用的数据格式仅可用于 Python。

这样做的好处是没有外部标准给该格式强加限制,比如 JSON 或 XDR(不能表示共享指针)标准;但这也意味着 非 Python 程序可能无法重新读取 pickle 封存的 Python 对象

默认情况下,pickle 格式使用相对紧凑的二进制来存储。如果需要让文件更小,可以高效地 压缩 由 pickle 封存的数据。

注解:序列化是一种比持久化更底层的概念,虽然 pickle 读取和写入的是文件对象,但它不处理持久对象的命名问题,也不处理对持久对象的并发访问(甚至更复杂)的问题。pickle 模块可以将复杂对象转换为字节流,也可以将字节流转换为具有相同内部结构的对象。处理这些字节流最常见的做法是将它们写入文件,但它们也可以通过网络发送或存储在数据库中。shelve 模块提供了一个简单的接口,用于在 DBM 类型的数据库文件上封存和解封对象。

模块接口:

要序列化某个包含层次结构的对象,只需调用 dumps() 函数即可。同样,要反序列化数据流,可以调用 loads() 函数。但是,如果要对序列化和反序列化加以更多的控制,可以分别创建 Pickler 或 Unpickler 对象。

pickle 模块的常用方法:

pickle 模块提供了以下方法,让封存过程更加方便:

  1. pickle.dump(obj, file, protocol=None, *, fix_imports=True, buffer_callback=None)
    将对象 obj 封存以后的对象写入已打开的 file object file。它等同于 Pickler(file, protocol).dump(obj)。

备注:参数 file、protocol、fix_imports 和 buffer_callback 的含义与它们在 Pickler 的构造函数中的含义相同。

  1. pickle.dumps(obj, protocol=None, *, fix_imports=True, buffer_callback=None)
    将 obj 封存以后的对象作为 bytes 类型直接返回,而不是将其写入到文件

备注:参数 protocol、fix_imports 和 buffer_callback 的含义与它们在 Pickler 的构造函数中的含义相同。

  1. pickle.load(file, *, fix_imports=True, encoding='ASCII', errors='strict', buffers=None)
    从已打开的 file object 文件 中读取封存后的对象,重建其中特定对象的层次结构并返回。它相当于 Unpickler(file).load()。

Pickle 协议版本是自动检测出来的,所以不需要参数来指定协议。封存对象以外的其他字节将被忽略。

备注:参数 file、fix_imports、encoding、errors、strict 和 buffers 的含义与它们在 Unpickler 的构造函数中的含义相同。

  1. pickle.loads(data, /, *, fix_imports=True, encoding="ASCII", errors="strict", buffers=None)
    重建并返回一个对象的封存表示形式 data 的对象层级结构。 data 必须为 bytes-like object。

Pickle 协议版本是自动检测出来的,所以不需要参数来指定协议。封存对象以外的其他字节将被忽略。

备注:参数 file、fix_imports、encoding、errors、strict 和 buffers 的含义与它们在 Unpickler 的构造函数中的含义相同。

pickle 模块包含了 3 个类,Pickler、Unpickler 和 PickleBuffer:

  1. class pickle.Pickler(file, protocol=None, *, fix_imports=True, buffer_callback=None)
    它接受一个二进制文件用于写入 pickle 数据流。

  2. class pickle.Unpickler(file, *, fix_imports=True, encoding='ASCII', errors='strict', buffers=None)
    它接受一个二进制文件用于读取 pickle 数据流。

  3. class pickle.PickleBuffer(buffer)
    缓冲区的包装器 (wrapper),缓冲区中包含着可封存的数据。buffer 必须是一个 buffer-providing 对象,比如 bytes-like object 或多维数组。

2、pickle 与 json 模块的比较

json 模块:是一个允许JSON序列化反序列化的标准库模块。

Pickle 协议和 JSON (JavaScript Object Notation) 间有着本质的不同:
\quad

  1. JSON 是一个文本序列化格式(它输出 unicode 文本,尽管在大多数时候它会接着以 utf-8 编码),而 pickle 是一个二进制序列化格式;
  2. JSON 是我们可以直观阅读的,而 pickle 不是;
  3. JSON是可互操作的,在Python系统之外广泛使用,而pickle则是Python专用的;
  4. 默认情况下,JSON 只能表示 Python 内置类型的子集,不能表示自定义的类;但 pickle 可以表示大量的 Python 数据类型(可以合理使用 Python 的对象内省功能自动地表示大多数类型,复杂情况可以通过实现 specific object APIs 来解决)。
  5. 不像pickle,对一个不信任的JSON进行反序列化的操作本身不会造成任意代码执行漏洞。

3、pickle应用实例

示例1:创建一个文件,通过pickle模块编码为二进制流,再unpickle解码为可读数据。

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:创建一个文件,通过pickle模块编码为二进制流,再unpickle解码为可读数据。

import numpy as np
import pickle
import os
import random
import matplotlib.pyplot as plt
from PIL import Imagepath1 = r'/Users/yangyang/Documents/学习资料/d2l-zh/data/cifar_10数据集/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的四个维度分别为[第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()输出结果:
>>>
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数据集

CIFAR-10和CIFAR-100是来自于80 million张小型图片的数据集,图片收集者是Alex Krizhevsky, Vinod Nair, and Geoffrey Hinton。

官网 http://www.cs.toronto.edu/~kriz/cifar.html

cifar-10 数据集说明及下载:

  1. 数据集组成:本数据及包含了6万张分辨率为32x32的图片,一共分为了10类,分别为:
    飞机、汽车、鸟、猫、鹿、狗、青蛙、马、船、货车。其中,5万张作为训练集,1万张作为测试机。训练集被分为了5批训练和1批测试。每一批都是1万张。测试集是从每一种分类中随机抽取出来1000张组成。训练集从10个分类中各自随机抽取5000张,一共5万张。
  2. 数据结构:数据集解压之后的样子如下图所示:

说明:

  • 没有后缀名的文件,如:data_batch_1,其实都是用python的cpickle库打包好的,这个库就是用来将python中的变量原封不动地存到本地使用的,当再次使用的时候,可以读取出来。

备注:有经验的朋友会自动和json.dumps联系起来,其实json模块只能保存一个字典到本地的json文件,而pickle模块(或者cpickle)却可以打包任何对象。

通过pickle在python3环境下读取CIFAR-10数据:

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)

每个字典如下表所示,每个batch文件转换为dictonary,其中的内容是:

data a 10000×3072 array(uint85),array的每行是一张32×32的彩色图片,前1024是red channel的值,后面1024是green channel的值,最后1024是blue channel的值。图片是以行主顺序存储,所以,前数组中前32个数表示的是一张图片第一行的red channel values。
labels 标签,长度是10000,每个都是0-9的数字,是一个列表。其索引和data里面的索引相互对应。
batch_label batch的名称
filenames 数据集中data对应的图片名称数组
  • 含后缀的文件batches.meta,这个文件保存的就是索引与名字之间的对应。如:label_names[0] == “airplane”, label_names[1] == “automobile”,batches.meta文件包含了[b’num_cases_per_batch’, b’label_names’, b’num_vis’]。其中,label_names 对应 十个类别的英文名,cifar-10划分为5个training batches。图像也是彩色的,所以要给图像的三个通道进行管理。

参考链接:
读取代码参考:https://blog.csdn.net/DarrenXf/article/details/85471718,
cifar10数据格式以及读取方式:https://blog.csdn.net/u014281392/article/details/74881967,
TensorFlow进阶:CNN对CIFAR10图像分类和python读取,https://www.cnblogs.com/jimobuwu/p/9161531.html

将cifar的3个单通道数据,转化为三通道数据,并保存:

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)


参考链接:深度学习:CIFAR-10数据集读取实操

5、【对象持久性】的理解

什么是持久性?

持久性的基本思想很简单。假定有一个 Python 程序,它可能是一个管理日常待办事项的程序,您希望在多次执行这个程序之间可以保存应用程序对象(待办事项)。换句话说,您希望将对象存储在磁盘上,便于以后检索。这就是持久性。要达到这个目的,有几种方法,每一种方法都有其优缺点。
例如,可以将对象数据存储在某种格式的文本文件中,譬如 CSV 文件。或者可以用关系数据库,譬如 Gadfly、MySQL、PostgreSQL 或者 DB2。这些文件格式和数据库都非常优秀,对于所有这些存储机制,Python 都有健壮的接口。

这些存储机制都有一个共同点: 存储的数据是独立于对这些数据进行操作的对象和程序。这样做的好处是,数据可以作为共享的资源,供其它应用程序使用。缺点是,用这种方式,可以允许其它程序访问对象的数据,这违背了面向对象的封装性原则 — 即对象的数据只能通过这个对象自身的公共(public)接口来访问。
另外,对于某些应用程序,关系数据库方法可能不是很理想。尤其是,关系数据库不理解对象。相反,关系数据库会强行使用自己的类型系统和关系数据模型(表),每张表包含一组元组(行),每行包含具有固定数目的静态类型字段(列)。如果应用程序的对象模型不能够方便地转换到关系模型,那么在将对象映射到元组以及将元组映射回对象方面,会碰到一定难度。这种困难常被称为阻碍性不匹配(impedence-mismatch)问题。

对象持久性

如果希望透明地存储 Python 对象,而不丢失其身份和类型等信息,则需要某种形式的对象序列化:它是一个将任意复杂的对象转成对象的文本或二进制表示的过程。同样,必须能够将对象经过序列化后的形式恢复到原有的对象。在 Python 中,这种序列化过程称为 pickle,可以将对象 pickle 成字符串、磁盘上的文件或者任何类似于文件的对象,也可以将这些字符串、文件或任何类似于文件的对象 unpickle 成原来的对象。我们将在本文后面详细讨论 pickle。

假定您喜欢将任何事物都保存成对象,而且希望避免将对象转换成某种基于非对象存储的开销;那么 pickle 文件可以提供这些好处,但有时可能需要比这种简单的 pickle 文件更健壮以及更具有可伸缩性的事物。例如,只用 pickle 不能解决命名和查找 pickle 文件这样的问题,另外,它也不能支持并发地访问持久性对象。如果需要这些方面的功能,则要求助类似于 ZODB(针对 Python 的 Z 对象数据库)这类数据库。ZODB 是一个健壮的、多用户的和面向对象的数据库系统,它能够存储和管理任意复杂的 Python 对象,并支持事务操作和并发控制。(请参阅 参考资料,以下载 ZODB。)令人足够感兴趣的是,甚至 ZODB 也依靠 Python 的本机序列化能力,而且要有效地使用 ZODB,必须充分了解 pickle。

另一种令人感兴趣的解决持久性问题的方法是 Prevayler,它最初是用 Java 实现的(有关 Prevaylor 方面的developerWorks 文章,请参阅 参考资料)。最近,一群 Python 程序员将 Prevayler 移植到了 Python 上,另起名为 PyPerSyst,由 SourceForge 托管(有关至 PyPerSyst 项目的链接,请参阅 参考资料)。Prevayler/PyPerSyst 概念也是建立在 Java 和 Python 语言的本机序列化能力之上。PyPerSyst 将整个对象系统保存在内存中,并通过不时地将系统快照 pickle 到磁盘以及维护一个命令日志(通过此日志可以重新应用最新的快照)来提供灾难恢复。所以,尽管使用 PyPerSyst 的应用程序受到可用内存的限制,但好处是本机对象系统可以完全装入到内存中,因而速度极快,而且实现起来要比如 ZODB 这样的数据库简单,ZODB 允许对象的数目比同时在能内存中所保持的对象要多。

既然我们已经简要讨论了存储持久对象的各种方法,那么现在该详细探讨 pickle 过程了。虽然我们主要感兴趣的是探索以各种方式来保存 Python 对象,而不必将其转换成某种其它格式,但我们仍然还有一些需要关注的地方,譬如:如何有效地 pickle 和 unpickle 简单对象以及复杂对象,包括定制类的实例;如何维护对象的引用,包括循环引用和递归引用;以及如何处理类定义发生的变化,从而使用以前经过 pickle 的实例时不会发生问题。我们将在随后关于 Python 的 pickle 能力探讨中涉及所有这些问题。
一些经过 pickle 的 Python

pickle 模块及其同类模块 cPickle 向 Python 提供了 pickle 支持。后者是用 C 编码的,它具有更好的性能,对于大多数应用程序,推荐使用该模块。我们将继续讨论 pickle ,但本文的示例实际是利用了 cPickle 。由于其中大多数示例要用 Python shell 来显示,所以先展示一下如何导入 cPickle ,并可以作为 pickle 来引用它:

参考链接:Python pickle模块学习(超级详细)

KBQA_多轮对话——模型源码解析(一)Pickle模块功能详解相关推荐

  1. php manual 反射,Laravel框架源码解析之反射的使用详解

    本文实例讲述了Laravel框架源码解析之反射的使用.分享给大家供大家参考,具体如下: 前言 PHP的反射类与实例化对象作用相反,实例化是调用封装类中的方法.成员,而反射类则是拆封类中的所有方法.成员 ...

  2. 【THREE源码解析篇】THREE.Sprite详解

    THREE.Sprite详解 问题背景 1.sprite_vert.glsl解析 问题背景 因为之前想修改sprite使得可以不面向屏幕,正常立起来和3D文字一样,对此研究了下THREE对这块的实现原 ...

  3. php5模块怎么下载,centos源码编译php5 mcrypt模块步骤详解

    步骤: 1.从php.net上面下载php5.3.x版本的源码; 2.centos安装相应的扩展包: 代码如下: yum install libmcrypt libmcrypt-devel mcryp ...

  4. Spring源码解析之 Bean与BeanDefinition详解

    文章目录 Spring解决的核心问题 Bean与BeanDefinition 代码验证BeanDefinition 代码运行测试 Spring容器主要流程 与BeanDefinition相关的类 At ...

  5. AngularJS源码解析2:注入器的详解

    上一课,没有讲createInjector方法,只是讲了它的主要作用,这一课,详细来讲一下这个方法.此方法,最终返回的注册器实例对象有以下几个方法: invoke, instantiate, get, ...

  6. Android xUtils3源码解析之图片模块

    本文已授权微信公众号<非著名程序员>原创首发,转载请务必注明出处. xUtils3源码解析系列 一. Android xUtils3源码解析之网络模块 二. Android xUtils3 ...

  7. Android xUtils3源码解析之注解模块

    本文已授权微信公众号<非著名程序员>原创首发,转载请务必注明出处. xUtils3源码解析系列 一. Android xUtils3源码解析之网络模块 二. Android xUtils3 ...

  8. Android xUtils3源码解析之数据库模块

    本文已授权微信公众号<非著名程序员>原创首发,转载请务必注明出处. xUtils3源码解析系列 一. Android xUtils3源码解析之网络模块 二. Android xUtils3 ...

  9. Caddy源码阅读(一)Run详解

    Caddy源码阅读(一)Run详解 前言 本次系列会讲解 caddy 整个生命周期涉及到的源码. 平时我们使用 caddy 都是使用 它的 二进制 分发文件,现在来分析 caddy 的 Run 函数. ...

最新文章

  1. 广州新房都智能成这样了???
  2. ztree 自定义参数_zTree树插件使用方法及自定义控件实践_蓝戒的博客
  3. axios + router4 + mobx:对于全局登录的思考
  4. SAP Fiori :why my filter for category does not work
  5. python如何实现办公自动化培训_基于python实现自动化办公学习笔记(CSV、word、Excel、PPT)...
  6. Shell运算符及条件判断
  7. mulitpartfile怎么接收不到值_GNSS接收机设计杂谈(射频前端+捕获)
  8. 百度SEO尊诺网络移动端百度发包程序3.0
  9. 解决微信商户号无法开通企业付款到零钱
  10. Acwing 1299. 五指山
  11. vi删除选中内容_vi 删除指令的使用
  12. TCP/IP(3)——IPV6
  13. 抗战史上知名的戚家刀PK日本真三武士刀刀型
  14. COLVERN LM10/3M29电位计春天,宛若初见!
  15. BASNet: Boundary-Aware Salient Object Detection论文学习
  16. Hadoop数据迁移工具DistCp
  17. python图片修改过、有原图、怎么得到改动的地方_Python-根据照片信息获取用户详细信息(微信发原图或泄露位置信息)...
  18. win7上安装DDK,SDK。。
  19. UML类图以及常用集合
  20. Microsoft Offfice 2010 测试版下载

热门文章

  1. 云原生项目正确的数据库选择
  2. HEVC/H265帧类型判断及NALU TYPE介绍
  3. 车辆协同定位论文review
  4. ROS移动机器人——ROS基础知识与编程
  5. IEEE 标准 802.1Qav™-2009翻译
  6. c# https请求忽略证书验证_c# https绕过证书
  7. Excel VBA选择文件、高容错性地打开文件
  8. c语言字符串用for语句去重,python简介、第一个python程序、变量、字符编码、用户交互程序、if...else、while、for...
  9. MOE定量构效关系(QSAR)
  10. 初学爬虫-翻译软件爬虫