我是TensorFlow和机器学习的新手。我想要做的是加载一些图像分类器,在我的应用程序中使用它们并比较结果。然后将结果用于嵌入,但是我现在遇到的主要问题是我无法设法找到一种可靠的方式来加载go中的TensorFlow模型。
到目前为止,我已经尝试过:
我从https://github.com/hybridgroup/gocv/blob/master/cmd/tf-classifier/main.go得到了示例,然后可以得到前k个结果。但是起初我不知道如何为模型获取.pb文件,因为TensorFlow .tar.gz文件中提供的全部是.ckpt文件。
后来我回到这种方法并弄清楚如何生成.pb文件,但是现在我遇到了一个问题,例如InceptionV3使用了OpenCV尚未实现的层:https://github.com/hybridgroup/gocv/issues/474
由于我不想在C ++中实现此功能,因此我认为这种方法无效。
因此有https://www.tensorflow.org/hub个用于共享模型。作为一个完整的新手,这似乎是我的标准方式,所以我尝试了一下。但是,没有可供使用的语言绑定,因此我在Python中实现了一个小的poc。我可以运行它,但是后来我意识到集线器提供的模型数量很少,并且我需要的模型不可用。
加分点:即使可用的模型很少,但已经有2种不同且不兼容的模型版本。
这是最直接的方法。既然我已经学到了很多关于不同文件格式的知识,我意识到这实际上是最简单的方法,因此我使用了https://github.com/nilsmagnus/tensorflow-with-go/blob/master/custom.go中的示例代码并对其进行了一些修改:
$ cat main.go
package main
import (
"fmt"
tf "github.com/tensorflow/tensorflow/tensorflow/go"
)
const input_folder = "./inceptionv3/"
const input_tag = "input"
const output_tag = "InceptionV3/Predictions/Reshape_1"
func main() {
model, err := tf.LoadSavedModel(input_folder, []string{input_tag}, nil)
if err != nil {
fmt.Printf("Error loading saved model: %s\n", err.Error())
return
}
defer model.Session.Close()
tensor, terr := dummyInputTensor(299 * 299) // replace this with your own data
if terr != nil {
fmt.Printf("Error creating input tensor: %s\n", terr.Error())
return
}
result, runErr := model.Session.Run(
map[tf.Output]*tf.Tensor{
model.Graph.Operation(input_tag).Output(0): tensor,
},
[]tf.Output{
model.Graph.Operation(output_tag).Output(0),
},
nil,
)
if runErr != nil {
fmt.Printf("Error running the session with input, err: %s\n", runErr.Error())
return
}
fmt.Printf("Most likely number in input is %v \n", result[0].Value())
}
func dummyInputTensor(size int) (*tf.Tensor, error) {
imageData := [][]float32{make([]float32, size)}
return tf.NewTensor(imageData)
}
但是在godoc中它声明了以下内容:
导出的模型包含一组图形和(可选)变量值。模型中的标记标识单个图。 LoadSavedModel使用已识别的图形和变量从磁盘上的检查点初始化为初始化会话。
确保运行代码足够会导致以下错误
$ go run main.go
2019-06-26 16:07:46.741248: I tensorflow/cc/saved_model/reader.cc:31] Reading SavedModel from: ./inceptionv3/
2019-06-26 16:07:47.098472: I tensorflow/cc/saved_model/reader.cc:54] Reading meta graph with tags { input }
2019-06-26 16:07:47.108505: I tensorflow/cc/saved_model/loader.cc:285] SavedModel load for tags { input }; Status: fail. Took 367263 microseconds.
Error loading saved model: Could not find meta graph def matching supplied tags: { input }. To inspect available tag-sets in the SavedModel, please use the SavedModel CLI: `saved_model_cli`
所以我怀疑该图缺少需要识别的标签。
I then modified the last few lines of https://github.com/tensorflow/models/blob/master/research/slim/export_inference_graph.py
using the information from the example at https://github.com/nilsmagnus/tensorflow-with-go/blob/master/mnist.py
to use `saved_model.Builder` instead of `tf.io.write_graph`.
我替换了以下内容:
graph_def = graph.as_graph_def()
if FLAGS.write_text_graphdef:
tf.io.write_graph(
graph_def,
os.path.dirname(FLAGS.output_file),
os.path.basename(FLAGS.output_file),
as_text=True)
else:
with gfile.GFile(FLAGS.output_file, 'wb') as f:
f.write(graph_def.SerializeToString())
与此:
builder = tf.compat.v1.saved_model.Builder(FLAGS.output_file)
with tf.compat.v1.Session(graph=graph) as sess:
tf.global_variables_initializer().run()
builder.add_meta_graph_and_variables(sess,
["serve"])
builder.save(FLAGS.write_text_graphdef)
然后我写了一个文件。但是,在此文件上,freeze_graph
和summarize_graph
都不对创建的.pb
文件起作用。但是我偶然发现另一个名为“ saved_model_cli”的程序可以打开文件,但是输出为空
$ saved_model_cli show --dir inception_v3_new/ --all
MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:
我怀疑即使它们的结尾相同,它们还是两种不同的文件格式。
我认为文件为空的原因是因为我缺少两个参数
signature_def_map=
assets_collection=
对于功能add_meta_graph_and_variables
的,但是我不知道在那添加什么。就记录这些参数应包含的内容(在https://www.tensorflow.org/api_docs/python/tf/saved_model/Builder)而言,此位置的文档非常差。
.pb
文件:$ python3 export_inference_graph.py
--alsologtostderr
--model_name=inception_v3
--output_file=inception_v3.pb
然后使用检查点冻结图形
$ freeze_graph
--input_graph=inception_v3.pb
--input_checkpoint=inception_v3.ckpt
--input_binary=true
--output_graph=frozen_inception_v3.pb
--output_node_names=InceptionV3/Predictions/Reshape_1
$ bazel-bin/tensorflow/tools/graph_transforms/summarize_graph --in_graph="../frozen_inception_v3.pb"
Found 1 possible inputs: (name=input, type=float(1), shape=[?,299,299,3])
No variables spotted.
Found 1 possible outputs: (name=InceptionV3/Predictions/Reshape_1, op=Reshape)
Found 23871066 (23.87M) const parameters, 0 (0) variable parameters, and 0 control_edges
Op types used: 488 Const, 379 Identity, 95 Conv2D, 94 FusedBatchNormV3, 94 Relu, 15 ConcatV2, 10 AvgPool, 4 MaxPool, 2 Reshape, 1 BiasAdd, 1 Placeholder, 1 Shape, 1 Softmax, 1 Squeeze
To use with tensorflow/tools/benchmark:benchmark_model try these arguments:
bazel run tensorflow/tools/benchmark:benchmark_model -- --graph=../frozen_inception_v3.pb --show_flops --input_layer=input --input_layer_type=float --input_layer_shape=-1,299,299,3 --output_layer=InceptionV3/Predictions/Reshape_1
在这一点上,我没有其他办法了。
如何以最少的工作量使预训练的模型继续运行?
我可以通过一些小的更改使TensorFlow导出适当的文件吗?
例如,使用tf.io.write_graph
编写标签还是使用saved_model.Builder
正确地导出.pb
文件?
这个问题不是重复的,因为另一个问题专门询问TensorFlow-hub,但是这个问题不是关于TensorFlow-hub,而是关于预训练的TensorFlow模型的一般用法。关于TensorFlow-hub的部分仅用于解释我已经尝试过的内容,它与另一个问题重叠。