Tensorflow ResNet 模型加载使用 **~5 GB 的 RAM** - 而从权重加载仅使用~200 MB

Mic*_*l S 5 keras tensorflow tensorflow2.0

我通过迁移学习使用 Tensorflow 2.0 训练了一个 ResNet50 模型。我稍微修改了架构(新的分类层)并在训练期间使用 ModelCheckpoint 回调https://keras.io/callbacks/#modelcheckpoint保存模型。训练很好。回调保存的模型在硬盘驱动器上占用约 206 MB。

为了使用我所做的模型进行预测:

  • 我创建了一个 Jupyter Lab 笔记本。我用于my_model = tf.keras.models.load_model('../models_using/my_model.hdf5')加载模型。(顺便说一句,使用 IPython 也会发生同样的情况)。

  • 我使用freelinux 命令行工具来测量加载之前和之后的可用 RAM。模型加载需要大约 5 GB 的 RAM

  • 我将模型和配置的权重保存为 json。这大约需要 105 MB。

  • 我从 json 配置和权重加载了模型。这需要大约 200 MB 的 RAM。

  • 比较了两种模型的预测。完全相同的。

  • 我用稍微不同的架构(以相同的方式训练)测试了相同的程序,结果是相同的。

谁能解释一下巨大的 RAM 使用量,以及硬盘驱动器上模型大小的差异?

顺便说一句,给定一个 Keras 模型,你能找出编译过程(优化器,..)吗?Model.summary() 没有帮助..

2019-12-07 - 编辑:感谢这个答案,我进行了一系列测试:

我使用!freeJupyterLab 中的命令来测量每次测试前后的可用内存。因为我get_weights返回一个列表,所以我曾经copy.deepcopy真正复制对象。请注意,下面的命令是单独的 Jupyter 单元,并且仅为此答案添加了内存注释。

!free

model = tf.keras.models.load_model('model.hdf5', compile=True)
# 25278624 - 21491888 = 3786.736 MB used

!free

weights = copy.deepcopy(model.get_weights())
# 21491888 - 21440272 = 51.616 MB used

!free


optimizer_weights = copy.deepcopy(model.optimizer.get_weights())
# 21440272 - 21339404 = 100.868 MB used

!free

model2 = tf.keras.models.load_model('model.hdf5', compile=False)
# 21339404 - 21140176 = 199.228 MB used

!free
Run Code Online (Sandbox Code Playgroud)

从 json 加载模型:

!free
# loading from json
with open('model_json.json') as f:
    model_json_weights = tf.keras.models.model_from_json(f.read())

model_json_weights.load_weights('model_weights.h5')
!free

# 21132664 - 20971616 = 161.048 MB used
Run Code Online (Sandbox Code Playgroud)

Dan*_*ler 4

checkpoint 和 JSON+Weights 的区别在于优化器:

  • 检查点或model.save()保存优化器及其权重(load_model编译模型)
  • JSON + 权重并不能节省优化器

除非您使用非常简单的优化器,否则它通常具有与模型相同数量的权重(例如,每个权重张量都有一个“动量”张量)。

某些优化器可能需要两倍于模型大小,因为每个模型权重张量都有两个优化器权重张量。

如果您想继续训练,保存和加载优化器非常重要。在没有适当权重的情况下使用新的优化器再次开始训练会在某种程度上破坏模型的性能(至少在开始时)。

现在,5GB对我来说并不是很清楚。但我认为:

  • 保存的权重应该有很大的压缩
  • 它可能与为所有梯度和反向传播操作分配内存有关

有趣的测试:

  • model.get_weights()压缩:检查和的结果使用了多少内存model.optimizer.get_weights()。这些权重将是 numpy 的,从原始张量复制而来
  • Grandient/Backpropagation:检查使用了多少内存:
    • load_model(name, compile=True)
    • load_model(name, compile=False)