Export tensorflow graph with batchnorm to opencv dnn - c++

First, build a network with batch_norm
net = tf.layers.conv2d(inputs = features, filters = 64, kernel_size = [3, 3], strides = (2, 2), padding = 'same')
training = tf.Variable(False, name = 'training')
net = tf.contrib.layers.batch_norm(net, is_training = training)
net = tf.nn.relu(net)
net = tf.reshape(net, [-1, 64 * 7 * 7]) #
net = tf.layers.dense(inputs = net, units = class_num, kernel_initializer = tf.contrib.layers.xavier_initializer(), name = 'regression_output')
#......
#after training, save the graph and weights
sess.run(loss, feed_dict={features : train_imgs, x : real_delta, training : False})
saver = tf.train.Saver()
saver.save(sess, 'reshape_final.ckpt')
tf.train.write_graph(sess.graph.as_graph_def(), "", 'graph_final.pb')
After that, I freeze the graph->optimize>transform
python3 ~/.keras2/lib/python3.5/site-packages/tensorflow/python/tools/freeze_graph.py --input_graph=graph_final.pb --input_checkpoint=reshape_final.ckpt --output_graph=frozen_graph.pb --output_node_names=regression_output/BiasAdd
python3 ~/.keras2/lib/python3.5/site-packages/tensorflow/python/tools/optimize_for_inference.py --input frozen_graph.pb --output opt_graph.pb --frozen_graph True --input_names input --output_names regression_output/BiasAdd
~/Qt/3rdLibs/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/transform_graph --in_graph=opt_graph.pb --out_graph=fused_graph.pb --inputs=input --outputs=regression_output/BiasAdd --transforms="fold_constants fold_batch_norms fold_old_batch_norms sort_by_execution_order"
Load the model
std::string const model("/home/ramsus/Qt/blogCodes2/deep_homography/cnn/tensorflow/fused_graph.pb");
dnn::Net net = dnn::readNetFromTensorflow(model);
if(net.empty()){
std::cerr<<"Can't load network by using the mode file:"<<std::endl;
std::cerr<<model<<std::endl;
throw std::runtime_error("net is empty");
}
it throw error messages:
BatchNorm/moments/mean:Mean(conv2d/convolution)(BatchNorm/moments/mean/reduction_indices)
keep_dims:[ ] Tidx:[ ] T:0 OpenCV Error: Unspecified error (Unknown
layer type Mean in op BatchNorm/moments/mean) in populateNet, file
/home/ramsus/Qt/3rdLibs/opencv/modules/dnn/src/tensorflow/tf_importer.cpp,
line 1077
/home/ramsus/Qt/3rdLibs/opencv/modules/dnn/src/tensorflow/tf_importer.cpp:1077:
error: (-2) Unknown layer type Mean in op BatchNorm/moments/mean in
function populateNet
How could I solve this issue?Thanks

Related

OpenVINO - Image classification

I tried to use OpenVINO Inference Engine to accelerate my DL inference. It works with one image. But I want to create a batch of two images and then do a inference.
This is my code:
InferenceEngine::Core core;
InferenceEngine::CNNNetwork network = core.ReadNetwork("path/to/model.xml");
InferenceEngine::InputInfo::Ptr input_info = network.getInputsInfo().begin()->second;
std::string input_name = network.getInputsInfo().begin()->first;
InferenceEngine::DataPtr output_info = network.getOutputsInfo().begin()->second;
std::string output_name = network.getOutputsInfo().begin()->first;
InferenceEngine::ExecutableNetwork executableNetwork = core.LoadNetwork(network, "CPU");
InferenceEngine::InferRequest inferRequest = executableNetwork.CreateInferRequest();
std::string input_image_01 = "path/to/image_01.png";
cv::Mat image_01 = cv::imread(input_image_01 );
InferenceEngine::Blob::Ptr imgBlob_01 = wrapMat2Blob(image_01);
std::string input_image_02 = "path/to/image_02.png";
cv::Mat image_02 = cv::imread(input_image_02 );
InferenceEngine::Blob::Ptr imgBlob_02 = wrapMat2Blob(image_02);
InferenceEngine::BlobMap imgBlobMap;
std::pair<std::string, InferenceEngine::Blob::Ptr> pair01(input_image_01, imgBlob_01);
imgBlobMap.insert(pair01);
std::pair<std::string, InferenceEngine::Blob::Ptr> pair02(input_image_02, imgBlob_02);
imgBlobMap.insert(pair02);
inferRequest.SetInput(imgBlobMap);
inferRequest.StartAsync();
inferRequest.Wait(InferenceEngine::IInferRequest::WaitMode::RESULT_READY);
InferenceEngine::Blob::Ptr output = inferRequest.GetBlob(output_name);
std::vector<unsigned> class_results;
ClassificationResult cls(output, {"x", "y"}, 2, 3);
class_results = cls.getResults();
Unfortunately, I received the following error message from the command
inferRequest.SetInput(imgBlobMap);
[NOT_FOUND] Failed to find input or output with name: 'path/to/image_02.png'
C:\j\workspace\private-ci\ie\build-windows-vs2019#2\b\repos\openvino\inference-engine\src\plugin_api\cpp_interfaces/impl/ie_infer_request_internal.hpp:303
C:\Program Files (x86)\Intel\openvino_2021.3.394\inference_engine\include\details/ie_exception_conversion.hpp:66
How can I create a batch of more than image, do a inference and get the information for classification class and confidence? Is the confidence and class located in the received variable of GetBlob()? Should I need the call of ClassificationResult cls(output, {"x", "y"}, 2, 3);?
I'd recommend you to review Using Shape Inference article from OpenVINO online documentation to be aware of the limitations of using batches. It also refers to Open Model Zoo smart_classroom_demo, where dynamic batching is used in processing multiple previously detected faces. Basically, when you have batch enabled in the model, the memory buffer of your input blob will be allocated to have a room for all batch of images, and your responsibility is to fill data in input blob for each image in batch from your data. You may take a look at function CnnDLSDKBase::InferBatch, of smart_classroom_demo, which is located at file smart_classroom_demo/cpp/src/cnn.cpp, line 51. As you can see, in the loop over num_imgs an auxiliary function matU8ToBlob fills the input blob with data for current_batch_size of images, then set batch size for infer request and run inference.
for (size_t batch_i = 0; batch_i < num_imgs; batch_i += batch_size) {
const size_t current_batch_size = std::min(batch_size, num_imgs - batch_i);
for (size_t b = 0; b < current_batch_size; b++) {
matU8ToBlob<uint8_t>(frames[batch_i + b], input, b);
}
if (config_.max_batch_size != 1)
infer_request_.SetBatch(current_batch_size);
infer_request_.Infer();
there is a similar sample using the batch inputs as input into model within the OpenVINO. You can refer to below link.
https://github.com/openvinotoolkit/openvino/blob/ae2913d3b5970ce0d3112cc880d03be1708f13eb/inference-engine/samples/hello_nv12_input_classification/main.cpp#L236

Error exchanging list of floats in a topic

I think that the issue is silly.
I'd like to run the code on two computers and I need to use a list. I followed this Tutorials
I used my PC as a talker and computer of the robot as a listener.
when running the code on my PC, the output is good as I needed.
[INFO] [1574230834.705510]: [3.0, 2.1]
[INFO] [1574230834.805443]: [3.0, 2.1]
but once running the code on the computer of the robot, the output is:
Traceback (most recent call last):
File "/home/redhwan/learn.py", line 28, in <module>
talker()
File "/home/redhwan/learn.py", line 23, in talker
pub.publish(position.data)
File "/opt/ros/kinetic/lib/python2.7/dist-packages/rospy/topics.py", line 886, in publish
raise ROSSerializationException(str(e))
rospy.exceptions.ROSSerializationException: <class 'struct.error'>: 'required argument is not a float' when writing 'data: [3.0, 2.1]'
full code on PC:
#!/usr/bin/env python
import rospy
from std_msgs.msg import Float32
x = 3.0
y = 2.1
def talker():
# if a == None:
pub = rospy.Publisher('position', Float32, queue_size=10)
rospy.init_node('talker', anonymous=True)
# rospy.init_node('talker')
rate = rospy.Rate(10) # 10hz
while not rospy.is_shutdown():
position = Float32()
a = [x,y]
# a = x
position.data = list(a)
# position.data = a
# hello_str = [5.0 , 6.1]
rospy.loginfo(position.data)
pub.publish(position.data)
rate.sleep()
if __name__ == '__main__':
try:
talker()
except rospy.ROSInterruptException:
pass
full code on the computer of the robot:
#!/usr/bin/env python
import rospy
from std_msgs.msg import Float32
def callback(data):
# a = list(data)
a = data.data
print a
def listener():
rospy.init_node('listener', anonymous=True)
rospy.Subscriber("position", Float32, callback)
# spin() simply keeps python from exiting until this node is stopped
rospy.spin()
if __name__ == '__main__':
listener()
when using one number as float everything is OK.
I understand how to publish and subscribe to them separately as the float but I'd like to do it as list
Any ideas or suggestion, it would be appreciated.
When you exchange messages in ROS is preferred to adopt standard messages if there is something relatively simple. Of course, when you develop more sophisticated systems (or modules), you can implement your own custom messages.
So in the case of float array, Float32MultiArray is your friend.
Populating the message in one side will look like that (just an example using a 2 elements float32 array) in C++:
.
.
.
while (ros::ok())
{
std_msgs::Float32MultiArray velocities;
velocities.layout.dim.push_back(std_msgs::MultiArrayDimension());
velocities.layout.dim[0].label = "velocities";
velocities.layout.dim[0].size = 2;
velocities.layout.dim[0].stride = 1;
velocities.data.clear();
velocities.data.push_back(count % 255);
velocities.data.push_back(-(count % 255));
velocities_demo_pub.publish(velocities);
ros::spinOnce();
loop_rate.sleep();
++count;
}
.
.
.
in Python for 8 elements array an example will look like:
.
.
.
while not rospy.is_shutdown():
# compose the multiarray message
pwmVelocities = Float32MultiArray()
myLayout = MultiArrayLayout()
myMultiArrayDimension = MultiArrayDimension()
myMultiArrayDimension.label = "motion_cmd"
myMultiArrayDimension.size = 1
myMultiArrayDimension.stride = 8
myLayout.dim = [myMultiArrayDimension]
myLayout.data_offset = 0
pwmVelocities.layout = myLayout
pwmVelocities.data = [0, 10.0, 0, 10.0, 0, 10.0, 0, 10.0]
# publish the message and log in terminal
pub.publish(pwmVelocities)
rospy.loginfo("I'm publishing: [%f, %f, %f, %f, %f, %f, %f, %f]" % (pwmVelocities.data[0], pwmVelocities.data[1],
pwmVelocities.data[2], pwmVelocities.data[3], pwmVelocities.data[4], pwmVelocities.data[5],
pwmVelocities.data[6], pwmVelocities.data[7]))
# repeat
r.sleep()
.
.
.
and on the other side your callback (in C++), will look like:
.
.
.
void hardware_interface::velocity_callback(const std_msgs::Float32MultiArray::ConstPtr &msg) {
//velocities.clear();
if (velocities.size() == 0) {
velocities.push_back(msg->data[0]);
velocities.push_back(msg->data[1]);
} else {
velocities[0] = msg->data[0];
velocities[1] = msg->data[1];
}
vel1 = msg->data[0];
vel2 = msg->data[1];
//ROS_INFO("Vel_left: [%f] - Vel_right: [%f]", vel1 , vel2);
}
.
.
.
Hope that you got an idea...if you need something more drop me a line!

tensorflow and tflearn c++ API

At first I am new on both tensorflow and python to start with.
I have a python code that contains a TFlearn DNN network. I need to convert that code to C++ to later on convert it into a library to be used in mobile application development.
I read about the C++ API for tensorflow (of which documentations are real vague and not clear). so I took the code line by line to try converting it.
The first step was loading the saved model that was was previously trained and saved in python (I don't need training to be done in c++ so just loading the tflearn model is enough)
The python code to save the file was as follows:
network = input_data(shape=[None, 100, 100, 1], name='input')
network = conv_2d(network, 32, 5, activation='relu')
network = avg_pool_2d(network, 2)
network = conv_2d(network, 64, 5, activation='relu')
network = avg_pool_2d(network, 2)
network = fully_connected(network, 128, activation='relu')
network = fully_connected(network, 64, activation='relu')
network = fully_connected(network, 2, activation='softmax',restore=False)
network = regression(network, optimizer='adam', learning_rate=0.0001,
loss='categorical_crossentropy', name='target')
model = tflearn.DNN(network, tensorboard_verbose=0)
model.fit(X, y.toarray(), n_epoch=3, validation_set=0.1, shuffle=True,
show_metric=True, batch_size=32, snapshot_step=100,
snapshot_epoch=False, run_id='model_finetuning')
model.save('model/my_model.tflearn')
To load the model python code was:
network = input_data(shape=[None, 100, 100, 1], name='input')
network = conv_2d(network, 32, 5, activation='relu')
network = avg_pool_2d(network, 2)
network = conv_2d(network, 64, 5, activation='relu')
network = avg_pool_2d(network, 2)
network = fully_connected(network, 128, activation='relu')
network = fully_connected(network, 64, activation='relu')
network = fully_connected(network, 2, activation='softmax')
network = regression(network, optimizer='adam', learning_rate=0.001,
loss='categorical_crossentropy', name='target')
model = tflearn.DNN(network, tensorboard_verbose=0)
model.load('model/my_model.tflearn')
and this code worked like a charm in python, yet the model save file was actually 4 files inside the model folder as follows:
model
|------------checkpoint
|------------my_model.tflearn.data-00000-of-00001
|------------my_model.tflearn.index
|------------my_model.tflearn.meta
now I come to the c++ part of it. After a lot of research I came up with the following code:
#include "tensorflow/core/public/session.h"
#include "tensorflow/core/platform/env.h"
#include <iostream>
using namespace tensorflow;
using namespace std;
int main()
{
Session* session;
Status status = NewSession(SessionOptions(), &session);
if (!status.ok())
{
cerr << status.ToString() << "\n";
return 1;
}
else
{
cout << "Session created successfully" << endl;
}
tensorflow::Tensor input_tensor(tensorflow::DT_FLOAT, tensorflow::TensorShape({1,100,100,1}));
GraphDef graph_def;
status = ReadBinaryProto(Env::Default(), "/home/user/PycharmProjects/untitled/model/my_model.tflearn", &graph_def);
if (!status.ok())
{
cerr << status.ToString() << "\n";
return 1;
}
else
{
cout << "Read Model File" << endl;
}
return 0;
}
And now for my questions, the code compile correctly (with no faults) using the bazel build (as described in the "Short" explanation of tensorflow C++ API. but when I tried to run it the model file is not found.
Is what I did in c++ correct? Is this the correct way to load the saved model (which I don't know why 4 files are generated during save)? or is there another approach to do it?
Is there any "Full and descent" manual for the tensorflow c++ API?
If you just want to load an already trained model, a c++ loader already exists. Directly on tensorflow look here and here
Patwie also got a really good example for loading a saved model Code from Patwie.
tensorflow::Status LoadModel(tensorflow::Session *sess, std::string graph_fn, std::string checkpoint_fn = "") {
tensorflow::Status status;
// Read in the protobuf graph we exported
tensorflow::MetaGraphDef graph_def;
status = ReadBinaryProto(tensorflow::Env::Default(), graph_fn, &graph_def);
if (status != tensorflow::Status::OK())
return status;
// create the graph in the current session
status = sess->Create(graph_def.graph_def());
if (status != tensorflow::Status::OK())
return status;
// restore model from checkpoint, iff checkpoint is given
if (checkpoint_fn != "") {
const std::string restore_op_name = graph_def.saver_def().restore_op_name();
const std::string filename_tensor_name = graph_def.saver_def().filename_tensor_name();
tensorflow::Tensor filename_tensor(tensorflow::DT_STRING, tensorflow::TensorShape());
filename_tensor.scalar<std::string>()() = checkpoint_fn;
tensor_dict feed_dict = {{filename_tensor_name, filename_tensor}};
status = sess->Run(feed_dict,
{},
{restore_op_name},
nullptr);
if (status != tensorflow::Status::OK())
return status;
} else {
// virtual Status Run(const std::vector<std::pair<string, Tensor> >& inputs,
// const std::vector<string>& output_tensor_names,
// const std::vector<string>& target_node_names,
// std::vector<Tensor>* outputs) = 0;
status = sess->Run({}, {}, {"init"}, nullptr);
if (status != tensorflow::Status::OK())
return status;
}
Unfortunatly there isn't a "full and descent" manual for tensorflow c++ API yet (AFAIK)
I wrote the steps how to save a TFLearn checkpoint correctly:
...
model = tflearn.DNN(network)
class MonitorCallback(tflearn.callbacks.Callback):
# Create an other session to clone the model and avoid effecting the training process
with tf.Session() as second_sess:
# Clone the current model
model2 = model
# Delete the training ops
del tf.get_collection_ref(tf.GraphKeys.TRAIN_OPS)[:]
# Save the checkpoint
model2.save('checkpoint_'+str(training_state.step)+".ckpt")
# Write a text protobuf to have a human-readable form of the model
tf.train.write_graph(second_sess.graph_def, '.', 'checkpoint_'+str(training_state.step)+".pbtxt", as_text = True)
return
mycb = MonitorCallback()
model.fit({'input': X}, {'target': Y}, n_epoch=500, run_id="mymodel", callbacks=mycb)
...
After you have the checkpoint, you can load in C++:
https://github.com/kecsap/tensorflow_cpp_packaging#load-a-checkpoint-in-c
...and you it for inference:
https://github.com/kecsap/tensorflow_cpp_packaging#inference-in-c
You can also find example code for C and how to freeze a model then load in C++.

How to save and restore a model using tf.data.dataset to import data?

I use tf.data.dataset to import data into model. I have created a simple reproducible code to show the idea. I save the trained model (please refer to the code below), and once I restore the model to run it on the test data I get to error that the iterator has not been initialized. Please see the error below for more details:
FailedPreconditionError (see above for traceback): GetNext() failed
because the iterator has not been initialized. Ensure that you have
run the initializer operation for this iterator before getting the
next element.
[[Node: IteratorGetNext = IteratorGetNext[output_shapes=[[?,10],
[?,1]], output_types=[DT_FLOAT, DT_FLOAT],
_device="/job:localhost/replica:0/task:0/device:CPU:0"](Iterator)]]
[[Node: IteratorGetNext/_39 = _Recv[client_terminated=false,
recv_device="/job:localhost/replica:0/task:0/device:GPU:0",
send_device="/job:localhost/replica:0/task:0/device:CPU:0",
send_device_incarnation=1, tensor_name="edge_7_IteratorGetNext",
tensor_type=DT_FLOAT,
_device="/job:localhost/replica:0/task:0/device:GPU:0"]()]]
How can I address this issue? Here's the reproducible code:
import tensorflow as tf
import os
import numpy as np
import math
features=np.random.randn(100,10)
features_test=np.random.randn(10,10)
y=np.random.randn(100,1)
y_test=np.random.randn(10,1)
feature_size=features.shape[1]
state_size=5
learning_rate=0.001
graph = tf.Graph()
with graph.as_default():
batch_size_tensor = tf.placeholder(tf.int64,name="Batch_tensor")
X,Y = tf.placeholder(tf.float32,
[None,feature_size],"X"),tf.placeholder(tf.float32,[None,1],name="Y")
dataset =tf.data.Dataset.from_tensor_slices((X,Y)).batch(batch_size_tensor).repeat()
iter = dataset.make_initializable_iterator()
x_inputs,y_outputs = iter.get_next()
Wx = tf.Variable(tf.truncated_normal([feature_size, state_size], stddev=2.0 / math.sqrt(state_size)),name="Visual_weights_layer1")
bx= tf.Variable(tf.zeros([state_size]),name="Visual_bias_layer1")
x_hidden_state=tf.matmul(x_inputs, Wx)+bx
x_hidden_state = tf.contrib.layers.batch_norm(x_hidden_state, epsilon=1e-5)
vx=tf.nn.relu(x_hidden_state)
W_final = tf.Variable(tf.truncated_normal([state_size, 1], stddev=2.0 / math.sqrt(state_size)),name="FinalLayer_weights")
by=tf.Variable(tf.zeros([1]),name="FinalLayer_bias")
predictions = tf.add(tf.matmul(vx, W_final), by,name="preds")
loss = tf.losses.mean_squared_error(y_outputs,predictions)
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(loss)
init = tf.global_variables_initializer()
saver = tf.train.Saver()
num_steps=100
batch_size=1
saver_path_model='tmp/testmodel'
export_path_model='tmp/testmodel.meta'
with tf.Session(graph=graph) as sess:
sess.run(init)
sess.run(iter.initializer, feed_dict={X: features, Y: y,
batch_size_tensor: batch_size})
print('initialized.')
for step in range(num_steps):
_, loss_val = sess.run([optimizer, loss])
print (loss_val)
saver.save(sess, saver_path_model)
saver.export_meta_graph(filename=export_path_model)
sess = tf.Session()
new_saver = tf.train.import_meta_graph(export_path_model)
new_saver.restore(sess, saver_path_model)
graph = tf.get_default_graph()
feed = {"X:0": features_test,"Y:0": y_test}
predictions_test = sess.run(["preds:0"], feed_dict=feed)
I saved my model as follows
saver = tf.train.Saver()
with tf.Session() as session:
session.run(tf.global_variables_initializer())
...
# after all training
save_path = saver.save(session, "logs/trained_model.ckpt")
print("Model saved: {}".format(save_path))
Then to load it
saver = tf.train.Saver()
# Initialize a session so that we can run TensorFlow operations
with tf.Session() as session:
# here is important, you need to load weights not initialize
saver.restore(session, "logs/trained_model.ckpt")
# then evaluate
official doc has more examples
https://www.tensorflow.org/api_docs/python/tf/train/Saver

Python lightgbm feature_importance() error?

1.Environment info
Operating System: Windows
Python version: Python 2.7.13
2.Error Message:
ValueError: No JSON object could be decoded
lgb_train = lgb.Dataset(X_train, y_train)
lgb_eval = lgb.Dataset(X_test, y_test, reference=lgb_train)
params = {
'task':'train',
'boosting':'gbdt',
'objective':'binary',
'metric':{'l2', 'auc'},
'num_leaves': 62,
'learning_rate': 0.05,
'feature_fraction': 0.9,
'bagging_fraction': 0.8,
'bagging_freq': 5,
'verbose': 20
}
gbm = lgb.train(params,
lgb_train,
num_boost_round=250,
valid_sets=lgb_eval)
print('Start predicting...')
y_pred = gbm.predict(X_test, num_iteration=gbm.best_iteration)
y_pred = np.round(y_pred)
print gbm.feature_importance()
Follow this link: https://github.com/Microsoft/LightGBM/issues/615. According to the contributor, this is a small bug: The infinite number cannot be handled by json.