使用tf.estimator加载预训练InceptionV3遇张量匹配错误求助
解决tf.estimator加载InceptionV3预训练权重时的张量名不匹配问题
我之前踩过一模一样的坑!你遇到的Tensor name "model/InceptionV3/AuxLogits/Conv2d_1b_1x1/BatchNorm/beta" not found错误,核心原因是你的模型图里的变量命名和预训练checkpoint里的命名不匹配。
为什么会出现这个问题?
你下载的官方InceptionV3预训练权重里,变量名都是InceptionV3/xxx/xxx这种格式的,但从你的代码来看,你的模型应该是被包裹在了model/这个变量作用域里(可能是Estimator默认的作用域,或者你自己隐含添加的),导致图里的变量名变成了model/InceptionV3/xxx/xxx,自然找不到checkpoint里对应的张量。
具体解决步骤
1. 先确认checkpoint里的变量名
先跑一段小代码,看看预训练权重里的变量到底叫什么:
import tensorflow as tf # 替换成你的checkpoint实际路径 for var_name, shape in tf.train.list_variables("inception_v3.ckpt"): print(var_name)
你会发现输出里的变量都是InceptionV3/AuxLogits/Conv2d_1b_1x1/BatchNorm/beta这类,完全没有model/前缀。
2. 在Estimator的model_fn中添加权重加载逻辑
Estimator需要在model_fn里处理预训练权重的加载,用tf.train.init_from_checkpoint函数,它支持自定义变量名映射。你可以在构建完网络之后,添加这段代码:
# 构建变量名映射:去掉图中变量的"model/"前缀 def map_checkpoint_name(var): # var.name的格式是"model/InceptionV3/xxx:0",我们需要去掉"model/"和最后的":0" return var.name.replace("model/", "").split(":")[0] # 筛选出需要从预训练加载的变量:只保留InceptionV3相关的,排除你自己加的全连接层等 variables_to_restore = [ var for var in tf.global_variables() if "InceptionV3" in var.name and not "your_custom_layer" in var.name # 替换成你的自定义层名称 ] # 创建变量映射字典 var_map = {map_checkpoint_name(var): var for var in variables_to_restore} # 加载预训练权重 tf.train.init_from_checkpoint(params.checkpoint, var_map)
3. 另一种更简单的方式:调整变量作用域
如果你不想写映射逻辑,可以在构建网络的时候,把Slim的InceptionV3放在和预训练权重一致的作用域里,比如:
# 去掉默认的model作用域,直接用InceptionV3作为作用域 with tf.variable_scope("InceptionV3"): network_fn = nets_factory.get_network_fn( params.network_name, num_classes=1001, weight_decay=0.00004, is_training=is_training ) logits, end_points = network_fn(images)
这样图里的变量名就和预训练checkpoint里的完全一致,不需要额外映射,直接用tf.train.init_from_checkpoint加载即可:
tf.train.init_from_checkpoint(params.checkpoint, {"InceptionV3/": "InceptionV3/"})
额外注意点
- 你设置的
num_classes=1001是对的,因为官方预训练模型是针对ImageNet的1000类+背景类,如果你要做自定义分类,后面加的全连接层不要从预训练权重加载,所以筛选变量的时候要排除这些层。 - 确保你的Slim版本和预训练模型的版本匹配,你用的TensorFlow 1.6/1.8和Slim的InceptionV3是兼容的,这个不用太担心。
内容的提问来源于stack exchange,提问作者Pfaeff
相关产品推荐
相关产品推荐

