facebookarchive / caffe2

Caffe2 is a lightweight, modular, and scalable deep learning framework.
https://caffe2.ai
Apache License 2.0
8.42k stars 1.95k forks source link

How to save model as init_net.pb and predict_net.pb #567

Open dongliya opened 7 years ago

dongliya commented 7 years ago

I want to know how to generate init_net.pb and predict_net.pb?

dongliya commented 7 years ago

看了好几天还是没有找到保存模型的方法

raininglixinyu commented 7 years ago

+1

tarunjainsagar commented 7 years ago

+1 @Yangqing @bwasti @aaronmarkham

jimmyoic commented 7 years ago

I try to use FetchBlob and FeedBlob for a temporarily weight saving. At least it works...

wannabehero commented 7 years ago

@jimmyoic do you have any sample code for that? Are you able to then use it with the predictor?

jimmyoic commented 7 years ago

I use pickle to serialize the weight, which is a dictionary of blobName-Weight pair, then dump it into files. Once I need to load the model, I can recover the weight by pickle, and call FeedBlob to put the weight into the model. It's a dumb way that I think somehow we may easily reload the model like what we did in Caffe later.

dongliya commented 7 years ago

@jimmyoic do you have sample code for that? +1

raininglixinyu commented 7 years ago

@jimmyoic wow! Could you share your code?

zhoushipin commented 7 years ago
def GetCheckpointParams(train_model):
    params = [str(p) for p in train_model.GetParams()]
    #params.extend([str(p) + "_momentum" for p in params])
    params.extend([str(p) for p in train_model.GetComputedParams()])
    assert len(params) > 0
    return params

def SaveModel(args, train_model, epoch):  
    predictor_export_meta = pred_exp.PredictorExportMeta(
        predict_net=train_model.net.Proto(),
        parameters=GetCheckpointParams(train_model),
        #inputs=["data"],
        inputs=[],
        #outputs=["softmax"],
        outputs=[],
        shapes={
            #"data": (args.num_channels, args.image_size, args.image_size)
            #"softmax": (1, args.num_labels)
        }
    )

    model_path = "%s/%s_%d.mdl" % (
        args.models_dir,
        train_model.net.Proto().name,
        epoch,
    )

    pred_exp.save_to_db(
        db_type="minidb",
        db_destination=model_path,
        predictor_export_meta=predictor_export_meta,
    )

def LoadModel(path, model):
    meta_net_def = pred_exp.load_from_db(path, 'minidb')
    init_net = core.Net(pred_utils.GetNet(
        meta_net_def, predictor_constants.GLOBAL_INIT_NET_TYPE))
    predict_init_net = core.Net(pred_utils.GetNet(
        meta_net_def, predictor_constants.PREDICT_INIT_NET_TYPE))

    predict_init_net.RunAllOnGPU()
    init_net.RunAllOnGPU()
    assert workspace.RunNetOnce(predict_init_net)
    assert workspace.RunNetOnce(init_net)
raininglixinyu commented 7 years ago

@jimmyoic Hi,did you save the model to init_net.pb and predict_init_net.pb ? I am trying to use the caffe2 model on mobilephone.

dongliya commented 7 years ago

@zhoushipin how to predict?

zhoushipin commented 7 years ago

@dongliya

from caffe2.python import workspace

predictor = workspace.Predictor(init_net, predict_init_net)
inputs = [np.zeros((1, 3, 32, 32), dtype='f')] #or load image use cv2.imread
outputs = predictor.run(inputs)
dongliya commented 7 years ago

@zhoushipin I know this method of use python, but do you know how to predict use C++ ?

zhoushipin commented 7 years ago

@dongliya


static bool read_binary_file(const std::string &filename,
                             std::vector<char> &buffer)
{
    std::ifstream file(filename, std::ios::binary | std::ios::ate);
    if (!file)
    {
        return false;
    }

    std::streamsize size = file.tellg();
    file.seekg(0, std::ios::beg);

    buffer.resize(size);
    return file.read(buffer.data(), size);
}

std::vector<char> init_net_buffer;
std::vector<char> predict_net_buffer;

read_binary_file("init_net.pb", init_net_buffer);
read_binary_file("predict_init_net.pb", predict_net_buffer);

caffe2::NetDef init_net;
caffe2::NetDef predict_net;

init_net.ParseFromArray(init_net_buffer.data(), init_net_buffer.size());
predict_net.ParseFromArray(predict_net_buffer.data(), predict_net_buffer.size());

std::unique_ptr<caffe2::Predictor> predictor =
    std::make_unique<caffe2::Predictor>(init_net, predict_net);

const int H = 32;
const int W = 32;
const int C = 3;

if (predictor)
{
    cv::Mat img = cv::imread("xxx.jpg");
    // preprocess the image
    // img = ...;

    caffe2::TensorCPU input(std::vector<int>({H, W, C}));
    memcpy(input.mutable_data<float>(), img.data, H * W * C * sizeof(float));
    caffe2::Predictor::TensorVector input_vec{&input};
    caffe2::Predictor::TensorVector output_vec;
    predictor->run(input_vec, &output_vec);

    // process the result in output_vec
    // ...
}
dongliya commented 7 years ago

@zhoushipin Thank you for your patience, but the problem still exists terminate called after throwing an instance of 'caffe2::EnforceNotMet' what(): [enforce fail at conv_op_impl.h:24] X.ndim() == filter.ndim(). 3 vs 4 Error from operator: input: "data" input: "conv1_w" input: "conv1_b" output: "conv1" type: "Conv" arg { name: "stride" i: 2 } arg { name: "pad" i: 0 } arg { name: "kernel" i: 3 } Aborted at 1495010251 (unix time) try "date -d @1495010251" if you are using GNU date PC: @ 0x7f03e2f3b428 gsignal SIGABRT (@0x3e800002542) received by PID 9538 (TID 0x7f03e63dc800) from PID 9538; stack trace: @ 0x7f03e2f3b4b0 (unknown) @ 0x7f03e2f3b428 gsignal @ 0x7f03e2f3d02a abort @ 0x7f03e335e84d gnu_cxx::verbose_terminate_handler() @ 0x7f03e335c6b6 (unknown) @ 0x7f03e335c701 std::terminate() @ 0x7f03e335c969 cxa_rethrow @ 0x7f03e5a4b594 caffe2::Operator<>::Run() @ 0x7f03e5a5d572 caffe2::SimpleNet::Run() @ 0x7f03e5aa9807 caffe2::Workspace::RunNet() @ 0x7f03e5a9e3a2 caffe2::Predictor::run() @ 0x40971a main @ 0x7f03e2f26830 libc_start_main @ 0x40a0c9 _start @ 0x0 (unknown) Aborted (core dumped)

zhoushipin commented 7 years ago

@dongliya

//caffe2::TensorCPU input(std::vector<int>({H, W, C}));
//memcpy(input.mutable_data<float>(), img.data, H * W * C * sizeof(float));

caffe2::TensorCPU input(std::vector<int>({1, C, H, W}));
to_tensorcpu(img, input);

static void to_tensorcpu(cv::Mat &img, caffe2::TensorCPU &tensor)
{
    const int num_channel = tensor.dim(1);
    const int height = tensor.dim(2);
    const int width = tensor.dim(3);

    assert(img.channels() == num_channel);
    assert(img.cols == width);
    assert(img.rows == height);
    assert(img.type() == CV_32F);

    float* tensor_data = tensor.mutable_data<float>();

    std::vector<cv::Mat> bgr;
    for (int i = 0; i < num_channel; ++i)
    {
        bgr.push_back(cv::Mat(height, width, CV_32FC1, tensor_data));
        tensor_data += width * height;
    }

    // HWC to CHW
    cv::split(img, bgr);
}
ShangxuanWu commented 7 years ago

This one might also help:

from caffe2.python.predictor import mobile_exporter

ghost commented 7 years ago

Anybody else who wants to save to a .pb file take a look at the unofficial C++ Caffe2 tutorial: https://github.com/leonardvandriel/caffe2_cpp_tutorial

The guy who created it has an example of writing to .PB files in the mnist tutorial and also has an example of reading it in through c++ in his pretrained tutorial.