我(未成功)尝试使用 Aiy Vision Kit Compiler 编译模型,以便可以在 Google Vision Kit 上使用它,但我总是收到有关冻结图的错误。我正在使用带有 Tensorflow 1.15 的 Keras。
根据编译器的要求,我冻结并将我的图形保存在 .pb 文件中。起初我使用的是 Tensorflow 2(正如我在另一个问题中报告的那样,我问Tensorflow 2.1/Keras - “output_node is not in graph” error when trying to freeze graph,其中还有我用于冻结的代码),但编译器保留给我一个“output_node/Softmax is not in the graph”错误,所以我切换到 TensorFlow 1.15,现在错误如下:
2020-01-30 07:48:20.826925: F convert_tensorflow_graph.cc:83] Check failed: graph_def.ParseFromString(frozen_graph_contents) Could not parse GraphDef in "./frozen_graph.pb"
在我运行以下命令后:
--frozen_graph_path=./frozen_graph.pb \
--output_graph_path=./frozen_graph.binaryproto \
--input_tensor_name=input_node \
--output_tensor_names=output_node/Softmax\
--input_tensor_size=256 \
--debug
从我在 .pbtxt 文件中看到的冻结图来看,它看起来像我用 Keras 创建的模型,并且输入和输出名称是正确的,所以我不确定我犯了什么错误。
我按照建议在 Linux 虚拟机上运行编译器。从 Aiy Vision Kit 网站下载的预训练模型已成功编译,所以我猜测问题出在我的 .pb 文件上,而不是环境上。
这是我用来创建和训练模型的代码:
input_layer=layers.Input(shape = (16,16,1), name = "input_node")
conv1=layers.Conv2D(64, kernel_size=(3, 3), activation='relu')(input_layer)
pool1=layers.MaxPooling2D((2, 2))(conv1)
conv2=(layers.Conv2D(128, kernel_size=(3, 3), activation='relu'))(pool1)
pool2=(layers.MaxPooling2D((2, 2), strides=1))(conv2)
conv3=(layers.Conv2D(256, kernel_size=(3, 3), activation='relu'))(pool2)
pool3=(layers.MaxPooling2D((2, 2), strides=1))(conv3)
flat=(layers.Flatten())(pool3)
dense1=(layers.Dense(128, activation='relu'))(flat)
dense2=(layers.Dense(units=num_classes))(dense1)
output=(layers.Softmax(name="output_node"))(dense2)
model = models.Model(input_layer, output)
model.compile(loss=keras.losses.categorical_crossentropy,
optimizer=keras.optimizers.Adadelta(),
metrics=['accuracy'])
return model
model=create_model()
model.summary()
history = model.fit(X_train, Y_train, epochs=25,
validation_data=(X_test, Y_test))
我检查了 Tensorflow 是否可以使用此代码解析 graph_def,它似乎可以工作,并且我得到了具有正确名称的节点和所有节点。
f = gfile.FastGFile("./frozen_graph.pb", 'rb')
graph_def = tf.GraphDef()
graph_def.ParseFromString(f.read())
f.close()
我还尝试使用带有以下代码的 Sequential 创建模型。
model=models.Sequential()
model.add(layers.Input(shape = (16,16,1), name = "input_node"))
model.add(layers.Conv2D(64, kernel_size=(3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, kernel_size=(3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2), strides=1))
model.add(layers.Conv2D(256, kernel_size=(3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2), strides=1))
model.add(layers.Flatten())
model.add(layers.Dense(128, activation='relu'))
model.add(layers.Dense(units=num_classes))
model.add(layers.Softmax(name="output_node"))
model.compile(loss=krs.losses.categorical_crossentropy,
optimizer=krs.optimizers.Adadelta(),
metrics=['accuracy'])
model.summary()
history = model.fit(X_train, Y_train, epochs=25,
validation_data=(X_test, Y_test))
而且我在训练时得到了相同数量的参数和相同的准确性/损失,所以我认为它们几乎是等价的。相反,在将其保存为 .h5 文件后,如果我加载模型并打印输入节点名称,它会给我 conv2d_input,就好像它合并了输入层和第一个卷积层一样。在这种情况下,我使用 Vision Kit 编译器得到另一个错误:
./bonnet_model_compiler.par \
--frozen_graph_path=./frozen_graph2.pb \
--output_graph_path=./frozen_graph2.binaryproto \
--input_tensor_name=conv2d_input \
--output_tensor_names=output_node/Softmax\
--input_tensor_size=256 \
--debug
Errorr = 2020-01-31 01:30:27.240900: I external/org_tensorflow/tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.cc:39] Before Removing unused ops: 35 operators, 50 arrays (0 quantized)
2020-01-31 01:30:27.241337: I external/org_tensorflow/tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.cc:39] Before general graph transformations: 35 operators, 50 arrays (0 quantized)
2020-01-31 01:30:27.241414: F external/org_tensorflow/tensorflow/contrib/lite/toco/graph_transformations/propagate_fixed_sizes.cc:347] Check failed: output_depth == input_depth * op->depth_multiplier (64 vs. 192)input/output depths and depth_multiplier don't match
这两个模型都是使用 TF 1.15 中的 Keras 类创建的,并且都已使用 freeze_session 冻结(如此处https://www.dlology.com/blog/how-to-convert-trained-keras-model-to-tensorflow-和-做出-预测/)。检查 pbtxt 文件并解析 graph_def 后,节点名称应该是正确的。
任何有关如何解决此问题的帮助将不胜感激。