赞
踩
在keras和tensorflow2中,模型或者模型的权重以h5文件保存。怎么单独读取保存模型或者模型中的权重值呢?这是这篇文章中讨论的问题。
首先我们从网上下载vgg16的模型文件,重命名为‘vgg16’。下载地址为:VGG16权重
首先简单介绍一下h5文件:
h5文件即HDF5文件(Hierarchical Data Format Version 5( HDF5): 层次性数据格式第五版),是一种存储相同类型数值的大数组的机制,适用于可被层次性组织且数据集需要被元数据标记的数据模型,在python中常用的接口模块为 h5py。
HDF5 三大要素:
hdf5 files:能够存储两类数据对象 dataset 和 group 的容器,其操作类似 python 标准的文件操作;File 实例对象本身就是一个组,以 / 为名,是遍历文件的入口。
dataset(array-like):可类比为 Numpy 数组,每个数据集都有一个名字(name)、形状(shape) 和类型(dtype),支持切片操作。
group(folder-like):可以类比为 字典,它是一种像文件夹一样的容器,group 中可以存放 dataset 或者其他的 group,键就是组成员的名称,值就是组成员对象本身(组或者数据集)。HDF5 group在组织数据上像文件的目录,但在操作上HDF5 group为字典
总之,一个HDF5文件是一种存放两类对象的容器:dataset和group。
Dataset是类似于数组的数据集,而group是类似文件夹一样的容器,存放dataset和其他group。在使用h5py的时候需要牢记一句话:groups类比词典,dataset类比Numpy中的数组。HDF5的dataset虽然与Numpy的数组在接口上很相近,但是支持更多对外透明的存储特征,如数据压缩,误差检测,分块传输。因为h5文件类似python的词典对象,因此我们可以查看所有的键值,示例如下:
- import h5py
- f = h5py.File('vgg16.h5', 'r')
- print('f.keys():', f.keys())
- print('f.values():', f.values())
- print('f.items():', f.items())
- print('f.attrs:', f.attrs)
- print('f.attrs.items():', f.attrs.items())
- print('f.attrs.keys():', f.attrs.keys())
- print("f.attrs['layer_names']:", f.attrs['layer_names'])
- print("f['block1_conv1'].attrs.keys():", f['block1_conv1'].attrs.keys())
- print("f['block1_conv1'].attrs['weight_names']:", f['block1_conv1'].attrs['weight_names'])
- print("f['block1_conv1/block1_conv1_W_1:0']:", f['block1_conv1/block1_conv1_W_1:0'])
输出如下:
- f.keys(): <KeysViewHDF5 ['block1_conv1', 'block1_conv2', 'block1_pool', 'block2_conv1', 'block2_conv2', 'block2_pool', 'block3_conv1', 'block3_conv2', 'block3_conv3', 'block3_pool', 'block4_conv1', 'block4_conv2', 'block4_conv3', 'block4_pool', 'block5_conv1', 'block5_conv2', 'block5_conv3', 'block5_pool', 'fc1', 'fc2', 'flatten', 'predictions']>
- f.values(): ValuesViewHDF5(<HDF5 file "vgg16.h5" (mode r)>)
- f.items(): ItemsViewHDF5(<HDF5 file "vgg16.h5" (mode r)>)
- f.attrs: <Attributes of HDF5 object at 140703882956288>
- f.attrs.items(): ItemsViewHDF5(<Attributes of HDF5 object at 140703882956288>)
- f.attrs.keys(): <KeysViewHDF5 ['layer_names']>
- f.attrs['layer_names']: [b'block1_conv1' b'block1_conv2' b'block1_pool' b'block2_conv1'
- b'block2_conv2' b'block2_pool' b'block3_conv1' b'block3_conv2'
- b'block3_conv3' b'block3_pool' b'block4_conv1' b'block4_conv2'
- b'block4_conv3' b'block4_pool' b'block5_conv1' b'block5_conv2'
- b'block5_conv3' b'block5_pool' b'flatten' b'fc1' b'fc2' b'predictions']
- f['block1_conv1'].attrs.keys(): <KeysViewHDF5 ['weight_names']>
- f['block1_conv1'].attrs['weight_names']: [b'block1_conv1_W_1:0' b'block1_conv1_b_1:0']
- f['block1_conv1/block1_conv1_W_1:0']: <HDF5 dataset "block1_conv1_W_1:0": shape (3, 3, 3, 64), type "<f4">
h5文件中的权重保存在HDF5 dataset中,怎么读取呢?正如上面所讲,因为h5文件中的dataset是类似于数组的数据集,那我们就可以用读取数组的方法进行读取了!
- print(f['block1_conv1/block1_conv1_W_1:0'][:])
- print(f['block1_conv1/block1_conv1_W_1:0'].value) #会报错
输出如下:
- [[[[ 4.29470569e-01 1.17273867e-01 3.40129584e-02 ... -1.32241577e-01
- -5.33475243e-02 7.57738389e-03]
- [ 5.50379455e-01 2.08774377e-02 9.88311544e-02 ... -8.48205537e-02
- -5.11389151e-02 3.74943428e-02]
- [ 4.80015397e-01 -1.72696680e-01 3.75577137e-02 ... -1.27135560e-01
- -5.02991639e-02 3.48965675e-02]]
- ......
- [[-3.50096762e-01 1.38710454e-01 -1.25339806e-01 ... -1.53092295e-01
- -1.39917329e-01 -2.65075237e-01]
- [-4.85030204e-01 4.23195846e-02 -1.12076312e-01 ... -1.18306056e-01
- -1.67058021e-01 -3.22241962e-01]
- [-4.18516338e-01 -1.57048807e-01 -1.49133086e-01 ... -1.56839803e-01
- -1.42874300e-01 -2.69694626e-01]]]]
-
- Traceback (most recent call last):
- File "/home/t.py", line 14, in <module>
- print(f['block1_conv1/block1_conv1_W_1:0'].value)
- AttributeError: 'Dataset' object has no attribute 'value'
网上的教程有用.value的方法读取dataset中的值的,但是在我这行不通,不知道是不是我的问题。。。所以我只能用[:]像读取数组的值一样读取dataset中的值了。
既然现在我们知道了h5文件中的数据存放形式以及读取方法,那就开始读取vgg16.h5中的权重值吧!先查看一下上代码:
- import h5py
- f = h5py.File('vgg16.h5','r')
- for k, v in f.attrs.items():
- print('k:', k)
- print('v:', v)
- for k1, v1 in f.items():
- print('k1:', k1)
- print('v1:', v1)
输出:
- k: layer_names
- v: [b'block1_conv1' b'block1_conv2' b'block1_pool' b'block2_conv1'
- b'block2_conv2' b'block2_pool' b'block3_conv1' b'block3_conv2'
- b'block3_conv3' b'block3_pool' b'block4_conv1' b'block4_conv2'
- b'block4_conv3' b'block4_pool' b'block5_conv1' b'block5_conv2'
- b'block5_conv3' b'block5_pool' b'flatten' b'fc1' b'fc2' b'predictions']
- k1: block1_conv1
- v1: <HDF5 group "/block1_conv1" (2 members)>
- k1: block1_conv2
- v1: <HDF5 group "/block1_conv2" (2 members)>
- k1: block1_pool
- v1: <HDF5 group "/block1_pool" (0 members)>
- k1: block2_conv1
- v1: <HDF5 group "/block2_conv1" (2 members)>
- ......(省略)
从上可以看出从f.attrs.items()只能读出模型中各个层或者各个模块的名称,所以要从f.items()中才可以继续读到模型的权重值!
- for k1, v1 in f.items():
- print('k1:', k1)
- print('v1:', v1)
- for k2, v2 in v1.items():
- print('k2:', k2)
- print('v2:', v2)
- print('v2:', v2[:].shape)
- print('v2:', v2[:])
输出:
- k1: block1_conv1
- v1: <HDF5 group "/block1_conv1" (2 members)>
- k2: block1_conv1_W_1:0
- v2: <HDF5 dataset "block1_conv1_W_1:0": shape (3, 3, 3, 64), type "<f4">
- v2: (3, 3, 3, 64)
- v2: [[[[ 4.29470569e-01 1.17273867e-01 3.40129584e-02 ... -1.32241577e-01
- -5.33475243e-02 7.57738389e-03]
- [ 5.50379455e-01 2.08774377e-02 9.88311544e-02 ... -8.48205537e-02
- -5.11389151e-02 3.74943428e-02]
- [ 4.80015397e-01 -1.72696680e-01 3.75577137e-02 ... -1.27135560e-01
- -5.02991639e-02 3.48965675e-02]
- (。。。省略)
从上可以看出,先遍历字典f.items(),得到h5文件中的group(v1),然后在遍历group字典v1.items(),就可以得到group中的dataset(v2),最后就可以通过v2[:]读取其权重值了!如果在遍历group字典v1.attrs.items(),就可以得到group中的weight_names,如下所示:
- for k1, v1 in f.items():
- print('k1:', k1)
- print('v1:', v1)
- for k2, v2 in v1.attrs.items():
- print('k2:', k2)
- print('v2:', v2)
- print('v2:', v2[:].shape)
- print('v2:', v2[:])
输出:
- k1: block1_conv1
- v1: <HDF5 group "/block1_conv1" (2 members)>
- k2: weight_names
- v2: [b'block1_conv1_W_1:0' b'block1_conv1_b_1:0']
- v2: (2,)
- v2: [b'block1_conv1_W_1:0' b'block1_conv1_b_1:0']
- ......(省略)
所以为了读取权重值,要用.items(),而不是.attrs.items()!因为这样得到的时权重值的名字!
但是有时候为了得到权重值的名字和其值,则需要如下代码:
- for k1, v1 in f.items():
- print('k1:', k1)
- print('v1:', v1)
- for k2, v2 in v1.attrs.items():
- print('k2:', k2)
- print('v2:', v2)
- for i in v2:
- name = k1+'/'+str(i, encoding="utf-8")
- print('name:', name)
- print('f[name]:', f[name])
- print('f[name].shap:', f[name].shape)
- print('f[name][:]:', f[name][:])
输出:
- k1: block1_conv1
- v1: <HDF5 group "/block1_conv1" (2 members)>
- k2: weight_names
- v2: [b'block1_conv1_W_1:0' b'block1_conv1_b_1:0']
- name: block1_conv1/block1_conv1_W_1:0
- f[name]: <HDF5 dataset "block1_conv1_W_1:0": shape (3, 3, 3, 64), type "<f4">
- f[name].shap: (3, 3, 3, 64)
- f[name][:]: [[[[ 4.29470569e-01 1.17273867e-01 3.40129584e-02 ... -1.32241577e-01
- -5.33475243e-02 7.57738389e-03]
- [ 5.50379455e-01 2.08774377e-02 9.88311544e-02 ... -8.48205537e-02
- -5.11389151e-02 3.74943428e-02]
- [ 4.80015397e-01 -1.72696680e-01 3.75577137e-02 ... -1.27135560e-01
- -5.02991639e-02 3.48965675e-02]]
- (。。。。省略)
再介绍另一个可以读取h5文件的deepdish模块,还是用‘vgg16.h'文件为例。代码示例如下:
- import deepdish as dd
- p = dd.io.load('vgg16.h5')
- print(type(p))
- for k,v in p.items():
- print('k:', k)
- print('v:', v)
输出:
- <class 'dict'>
- k: block1_conv1
- v: {'block1_conv1_W_1:0': array([[[[ 4.29470569e-01, 1.17273867e-01, 3.40129584e-02, ...,
- -1.32241577e-01, -5.33475243e-02, 7.57738389e-03],
- [ 5.50379455e-01, 2.08774377e-02, 9.88311544e-02, ...,
- -8.48205537e-02, -5.11389151e-02, 3.74943428e-02],
- [ 4.80015397e-01, -1.72696680e-01, 3.75577137e-02, ...,
- -1.27135560e-01, -5.02991639e-02, 3.48965675e-02]],
- ............}
- ......(省略)
从以上代码可以看出通过deepdish.io.load()方法读取’vgg16.h'文件后,就直接j将vgg16.h文件的内容以字典的形式返回!
那返回的字典中的值又是什么类型呢?
- import deepdish as dd
- p = dd.io.load('vgg16.h5')
- print(type(p))
- for k,v in p.items():
- print('k:', k)
- print('type(v):', type(v))
输出:
- <class 'dict'>
- k: block1_conv1
- type(v): <class 'dict'>
- k: block1_conv2
- type(v): <class 'dict'>
- k: block1_pool
- type(v): <class 'dict'>
- ......(省略)
- k: predictions
- type(v): <class 'dict'>
- k: layer_names
- type(v): <class 'numpy.ndarray'>
通过以上代码可以得知,除了最后一个k(layer_names)对应的v的类型不是字典(dict)外,其余全是字典(dict),那么我们还可以通过遍历v这个字典(dict),直接得到每一个权重值!
- import deepdish as dd
- p = dd.io.load('vgg16.h5')
- for k1, v1 in p.items():
- print('k1:', k1)
- print('v1:', v1)
- if k1 != 'layer_names':
- for k2, v2 in v1.items():
- print('k2:', k2)
- print('v2:', v2)
- print('name:', k1+'/'+k2)
输出:
- k1: block1_conv1
- v1: {'block1_conv1_W_1:0': array([[[[ 4.29470569e-01, 1.17273867e-01, 3.40129584e-02, ...,
- -1.32241577e-01, -5.33475243e-02, 7.57738389e-03],
- [ 5.50379455e-01, 2.08774377e-02, 9.88311544e-02, ...,
- -8.48205537e-02, -5.11389151e-02, 3.74943428e-02],
- [ 4.80015397e-01, -1.72696680e-01, 3.75577137e-02, ...,
- -1.27135560e-01, -5.02991639e-02, 3.48965675e-02]],
- [-4.18516338e-01, -1.57048807e-01, -1.49133086e-01, ...,
- -1.56839803e-01, -1.42874300e-01, -2.69694626e-01]]]],
- dtype=float32), 'block1_conv1_b_1:0': array([ 0.73429835, 0.09340367, 0.06775674, 0.8862966 , 0.25994542,
- 0.66426694, -0.01582893, 0.3249065 , 0.68600726, 0.06247932,
- 0.58156496, 0.2361475 , 0.69694996, 0.19451167, 0.4858922 ,
- 0.09850298, 0.3803252 , 0.66880196, 0.4015123 , 0.90510356,
- 0.43166816, 1.302014 , 0.5306885 , 0.48993504], dtype=float32),
- ......(省略)
通过以上代码的示例,deepdish模块也可以获取h5文件中模型的权重值以及对应的名字,好像还比使用h5py模块简单!
至此,我们已经可以将h5文件中的权重名称和权重值完全读取出来了!
更多内容可以关注个人做着玩的微信公众号。。。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。