目录html
tf.keras 的预训练模型都放在了'tensorflow.python.keras.applications' 目录下,在 tensorflow 1.10 版本中,预训练好的模型有:python
DenseNet121, DenseNet169, DenseNet201, InceptionResNetV2, InceptionV3, MobileNet, NASNetLarge, NASNetMobile, ResNet50, VGG16, VGG19, Xception.
git
找了半天,发现 keras 没有预训练好的 AlexNet。。。github
因此本文提供一种从其它框架(如 PyTorch)导入预训练模型的方法,下面以 AlexNet 为例。shell
首先明白一点,当模型的结构同样时,咱们只须要导入模型的参数便可复现模型,因此咱们要作的就是从 PyTorch 中导出预训练好的模型参数,并用 keras 加载。json
这里要介绍一个微软的项目:MMdnn。MMdnn 使咱们能够在不一样深度学习框架之间转换模型,这里我也使用 MMdnn 来转换 AlexNet(PyTorch to Keras)。markdown
必须一致配置: - PyTorch: 0.4.0 (若是其它版本出现了问题,请退回到 0.4.0 版) 非必须一致配置: - numpy: 1.14.5 - Keras: 2.1.3 (非 tensorflow 中的 keras)
$ pip3 install mmdnn
我安装的 mmdnn 版本为 0.2.5。架构
其它安装方式请参考 github。app
PyTorch 保存模型时,能够保存整个模型,也能够仅保存模型的参数,都是存放到 pth 文件中。框架
mmdnn 操做的 pth 文件是要求含有模型结构的,具体参见 FAQ,而在 PyTorch 中预训练 AlexNet 仅保存了参数。
经过如下程序获得包含有模型结构和权重的 AlexNet 预训练模型(pth 文件):
import torch import torchvision m = torchvision.models.alexnet(pretrained=True) torch.save(m, './alexnet.pth')
对于其它模型,如 resnet101,能够经过如下指令直接获得含有结构和权重的预训练模型:
$ mmdownload -f pytorch -n resnet101 -o ./
(不要经过上述指令获得 alexnet.pth,由于其仅仅包含权重,而不含结构,故后面一步会出现错误 "AttributeError: 'collections.OrderedDict' object has no attribute 'state_dict'"。)
依次执行如下三条指令,最后会获得一个 'keras_alexnet.h5' 文件,这就是咱们想要的 keras 能加载的预训练权重文件。
$ mmtoir -f pytorch -d alexnet --inputShape 3,227,227 -n alexnet.pth IR network structure is saved as [alexnet.json]. IR network structure is saved as [alexnet.pb]. IR weights are saved as [alexnet.npy]. $ mmtocode -f keras --IRModelPath alexnet.pb --IRWeightPath alexnet.npy --dstModelPath keras_alexnet.py Using TensorFlow backend. Parse file [alexnet.pb] with binary format successfully. Target network code snippet is saved as [keras_alexnet.py]. $ python3 -m mmdnn.conversion.examples.keras.imagenet_test -n keras_alexnet.py -w alexnet.npy --dump keras_alexnet.h5 Using TensorFlow backend. Keras model file is saved as [keras_alexnet.h5], generated by [keras_alexnet.py.py] and [alexnet.npy].
Solution:PyTorch 版本问题,1.1.0 版会出现这个问题,回退到 0.4.0 版本便可。
$ pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --upgrade torch==0.4.0 torchvision==0.2.0
Solution:请更改 numpy 版本。
Solution:pth 文件仅含模型参数而不含模型结构,在 PyTorch 中加载一下而后保存含有模型结构和参数的 pth 文件。
测试用的几张图片、代码以及生成的 keras_alexnet.h5 文件都存放到了 wuliytTaotao · Github。
import torch import torchvision import cv2 import numpy as np from torch.autograd import Variable import tensorflow as tf from tensorflow.keras import layers,regularizers filename_test = 'data/dog2.png' img = cv2.imread(filename_test) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 数据预处理 img = cv2.resize(img, (227, 227)) img = img / 255.0 img = np.reshape(img, (1, 227, 227, 3)) # 标准化,这是 PyTorch 预训练 AlexNet 模型的预处理方式,详情请见 https://pytorch.org/docs/stable/torchvision/models.html mean = np.array([0.485, 0.456, 0.406]).reshape([1, 1, 1, 3]) std = np.array([0.229, 0.224, 0.225]).reshape([1, 1, 1, 3]) img = (img - mean) / std # PyTorch # PyTorch 数据输入 channel 排列和 Keras 不一致 img_tmp = np.transpose(img, (0, 3, 1, 2)) model = torchvision.models.alexnet(pretrained=True) # torch.save(model, './model/alexnet.pth') model = model.double() model.eval() y = model(Variable(torch.tensor(img_tmp))) # 预测的类别 print(np.argmax(y.detach().numpy())) # Keras def get_AlexNet(num_classes=1000, drop_rate=0.5, regularizer_rate=0.01): """ PyTorch 中实现的 AlexNet 预训练模型结构,filter 的深度分别为:(64,192,384,256,256)。 返回 AlexNet 的 inputs 和 outputs """ inputs = layers.Input(shape=[227, 227, 3]) conv1 = layers.Conv2D(64, (11, 11), strides=(4, 4), padding='valid', activation='relu')(inputs) pool1 = layers.MaxPooling2D(pool_size=(3, 3), strides=(2, 2))(conv1) conv2 = layers.Conv2D(192, (5, 5), strides=(1, 1), padding='same', activation='relu')(pool1) pool2 = layers.MaxPooling2D(pool_size=(3, 3), strides=(2, 2))(conv2) conv3 = layers.Conv2D(384, (3, 3), strides=(1, 1), padding='same', activation='relu')(pool2) conv4 = layers.Conv2D(256, (3, 3), strides=(1, 1), padding='same', activation='relu')(conv3) conv5 = layers.Conv2D(256, (3, 3), strides=(1, 1), padding='same', activation='relu')(conv4) pool3 = layers.MaxPooling2D(pool_size=(3, 3), strides=(2, 2))(conv5) flat = layers.Flatten()(pool3) dense1 = layers.Dense(4096, activation='relu', kernel_regularizer=regularizers.l2(regularizer_rate))(flat) dense1 = layers.Dropout(drop_rate)(dense1) dense2 = layers.Dense(4096, activation='relu', kernel_regularizer=regularizers.l2(regularizer_rate))(dense1) dense2 = layers.Dropout(drop_rate)(dense2) outputs = layers.Dense(num_classes, activation='softmax', kernel_regularizer=regularizers.l2(regularizer_rate))(dense2) return inputs, outputs inputs, outputs = get_AlexNet() model2 = tf.keras.Model(inputs, outputs) model2.load_weights('./keras_alexnet.h5') # 预测的类别 print(np.argmax(model2.predict(img)))
预测结果表明的类别请看博客 ImageNet图像库1000个类别名称(中文注释不断更新)。
PyTorch 中的预训练 AlexNet 模型卷积层 filter 的个数和原论文不一致,filter 的个数分别 \(64,192,384,256,256\)。具体参见 GitHub - pytorch: vision/torchvision/models/alexnet.py
PyTorch 给出的解释是,它的预训练 AlexNet 模型用的是论文 Krizhevsky, A. (2014). One weird trick for parallelizing convolutional neural networks. arXiv preprint arXiv:1404.5997. 给出的架构,但 PyTorch 的模型架构和这篇论文仍是有区别,这篇论文中第四个卷积层 filter 个数为 384,而 PyTorch 为 256。
而 caffe 中实现的 AlexNet 含有原始的 LRN 层,去掉 LRN 层后,我的感受预训练的权重就不能直接拿来用了。
PyTorch
GitHub - microsoft/MMdnn
GitHub - pytorch: vision/torchvision/models/alexnet.py
ImageNet图像库1000个类别名称(中文注释不断更新)-- 徐小妹