ctr_prediction_op.cpp 8.1 KB
Newer Older
W
wangguibao 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "demo-serving/op/ctr_prediction_op.h"
#include <algorithm>
W
wangguibao 已提交
17
#include <string>
W
wangguibao 已提交
18 19 20 21 22 23 24 25 26 27 28 29 30
#include "predictor/framework/infer.h"
#include "predictor/framework/memory.h"

namespace baidu {
namespace paddle_serving {
namespace serving {

using baidu::paddle_serving::predictor::MempoolWrapper;
using baidu::paddle_serving::predictor::ctr_prediction::CTRResInstance;
using baidu::paddle_serving::predictor::ctr_prediction::Response;
using baidu::paddle_serving::predictor::ctr_prediction::CTRReqInstance;
using baidu::paddle_serving::predictor::ctr_prediction::Request;

W
wangguibao 已提交
31 32
const int VARIABLE_NAME_LEN = 256;

W
wangguibao 已提交
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
// Total 26 sparse input + 1 dense input
const int CTR_PREDICTION_INPUT_SLOTS = 27;

// First 26: sparse input
const int CTR_PREDICTION_SPARSE_SLOTS = 26;

// Last 1: dense input
const int CTR_PREDICTION_DENSE_SLOT_ID = 26;
const int CTR_PREDICTION_DENSE_DIM = 13;
const int CTR_PREDICTION_EMBEDDING_SIZE = 10;

#if 1
struct CubeValue {
  int error;
  std::string buff;
};
#endif
W
wangguibao 已提交
50

W
wangguibao 已提交
51 52 53 54 55 56 57 58 59 60 61 62
void fill_response_with_message(Response *response,
                                int err_code,
                                std::string err_msg) {
  if (response == NULL) {
    LOG(ERROR) << "response is NULL";
    return;
  }

  response->set_err_code(err_code);
  response->set_err_msg(err_msg);
  return;
}
W
wangguibao 已提交
63 64 65 66 67

int CTRPredictionOp::inference() {
  const Request *req = dynamic_cast<const Request *>(get_request_message());

  TensorVector *in = butil::get_object<TensorVector>();
W
wangguibao 已提交
68 69
  Response *res = mutable_data<Response>();

W
wangguibao 已提交
70 71 72
  uint32_t sample_size = req->instances_size();
  if (sample_size <= 0) {
    LOG(WARNING) << "No instances need to inference!";
W
wangguibao 已提交
73
    fill_response_with_message(res, -1, "Sample size invalid");
W
wangguibao 已提交
74
    return 0;
W
wangguibao 已提交
75 76 77
  }

  paddle::PaddleTensor lod_tensors[CTR_PREDICTION_INPUT_SLOTS];
W
wangguibao 已提交
78
  for (int i = 0; i < CTR_PREDICTION_INPUT_SLOTS; ++i) {
W
wangguibao 已提交
79 80 81 82 83 84
    lod_tensors[i].dtype = paddle::PaddleDType::FLOAT32;
    std::vector<std::vector<size_t>> &lod = lod_tensors[i].lod;
    lod.resize(1);
    lod[0].push_back(0);
  }

W
wangguibao 已提交
85 86 87 88 89 90
  // Query cube API for sparse embeddings
  std::vector<int64_t> keys;
  std::vector<CubeValue> values;

  for (uint32_t si = 0; si < sample_size; ++si) {
    const CTRReqInstance &req_instance = req->instances(si);
W
wangguibao 已提交
91
    if (req_instance.sparse_ids_size() != CTR_PREDICTION_SPARSE_SLOTS) {
W
wangguibao 已提交
92
      std::ostringstream iss;
W
wangguibao 已提交
93
      iss << "Sparse input size != " << CTR_PREDICTION_SPARSE_SLOTS;
W
wangguibao 已提交
94
      fill_response_with_message(res, -1, iss.str());
W
wangguibao 已提交
95
      return 0;
W
wangguibao 已提交
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
    }

    for (int i = 0; i < req_instance.sparse_ids_size(); ++i) {
      keys.push_back(req_instance.sparse_ids(i));
    }
  }

#if 0
  mCube::CubeAPI* cube = CubeAPI::instance();
  int ret = cube->seek(keys, values);
  if (ret != 0) {
    fill_response_with_message(res, -1, "Query cube for embeddings error");
    LOG(ERROR) << "Query cube for embeddings error";
    return -1;
  }
#else
  float buff[CTR_PREDICTION_EMBEDDING_SIZE] = {
      0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.00};
  for (int i = 0; i < keys.size(); ++i) {
W
wangguibao 已提交
115 116 117 118
    CubeValue value;
    value.error = 0;
    value.buff = std::string(reinterpret_cast<char *>(buff), sizeof(buff));
    values.push_back(value);
W
wangguibao 已提交
119 120
  }
#endif
W
wangguibao 已提交
121

W
wangguibao 已提交
122
  // Sparse embeddings
W
wangguibao 已提交
123
  for (int i = 0; i < CTR_PREDICTION_SPARSE_SLOTS; ++i) {
W
wangguibao 已提交
124
    paddle::PaddleTensor &lod_tensor = lod_tensors[i];
W
wangguibao 已提交
125 126
    std::vector<std::vector<size_t>> &lod = lod_tensor.lod;

W
wangguibao 已提交
127 128 129 130
    char name[VARIABLE_NAME_LEN];
    snprintf(name, VARIABLE_NAME_LEN, "embedding_%d.tmp_0", i);
    lod_tensor.name = std::string(name);

W
wangguibao 已提交
131 132 133 134 135
    for (uint32_t si = 0; si < sample_size; ++si) {
      const CTRReqInstance &req_instance = req->instances(si);
      lod[0].push_back(lod[0].back() + 1);
    }

W
wangguibao 已提交
136 137 138
    lod_tensor.shape = {lod[0].back(), CTR_PREDICTION_EMBEDDING_SIZE};
    lod_tensor.data.Resize(lod[0].back() * sizeof(float) *
                           CTR_PREDICTION_EMBEDDING_SIZE);
W
wangguibao 已提交
139 140 141

    int offset = 0;
    for (uint32_t si = 0; si < sample_size; ++si) {
W
wangguibao 已提交
142
      float *data_ptr = static_cast<float *>(lod_tensor.data.data()) + offset;
W
wangguibao 已提交
143
      const CTRReqInstance &req_instance = req->instances(si);
W
wangguibao 已提交
144 145 146 147 148 149 150

      int idx = si * CTR_PREDICTION_SPARSE_SLOTS + i;
      if (values[idx].buff.size() !=
          sizeof(float) * CTR_PREDICTION_EMBEDDING_SIZE) {
        LOG(ERROR) << "Embedding vector size not expected";
        fill_response_with_message(
            res, -1, "Embedding vector size not expected");
W
wangguibao 已提交
151
        return 0;
W
wangguibao 已提交
152 153 154 155
      }

      memcpy(data_ptr, values[idx].buff.data(), values[idx].buff.size());
      offset += CTR_PREDICTION_EMBEDDING_SIZE;
W
wangguibao 已提交
156 157 158 159 160
    }

    in->push_back(lod_tensor);
  }

W
wangguibao 已提交
161
  // Dense features
W
wangguibao 已提交
162 163
  paddle::PaddleTensor &lod_tensor = lod_tensors[CTR_PREDICTION_DENSE_SLOT_ID];
  lod_tensor.dtype = paddle::PaddleDType::FLOAT32;
W
wangguibao 已提交
164
  std::vector<std::vector<size_t>> &lod = lod_tensor.lod;
W
wangguibao 已提交
165
  lod_tensor.name = std::string("dense_input");
W
wangguibao 已提交
166 167 168

  for (uint32_t si = 0; si < sample_size; ++si) {
    const CTRReqInstance &req_instance = req->instances(si);
W
wangguibao 已提交
169 170 171 172
    if (req_instance.dense_ids_size() != CTR_PREDICTION_DENSE_DIM) {
      std::ostringstream iss;
      iss << "dense input size != " << CTR_PREDICTION_DENSE_DIM;
      fill_response_with_message(res, -1, iss.str());
W
wangguibao 已提交
173
      return 0;
W
wangguibao 已提交
174
    }
W
wangguibao 已提交
175 176 177
    lod[0].push_back(lod[0].back() + req_instance.dense_ids_size());
  }

W
wangguibao 已提交
178 179 180
  lod_tensor.shape = {lod[0].back() / CTR_PREDICTION_DENSE_DIM,
                      CTR_PREDICTION_DENSE_DIM};
  lod_tensor.data.Resize(lod[0].back() * sizeof(float));
W
wangguibao 已提交
181 182 183

  int offset = 0;
  for (uint32_t si = 0; si < sample_size; ++si) {
W
wangguibao 已提交
184
    float *data_ptr = static_cast<float *>(lod_tensor.data.data()) + offset;
W
wangguibao 已提交
185 186 187
    const CTRReqInstance &req_instance = req->instances(si);
    int id_count = req_instance.dense_ids_size();
    memcpy(data_ptr,
W
wangguibao 已提交
188
           req_instance.dense_ids().data(),
W
wangguibao 已提交
189
           sizeof(float) * req_instance.dense_ids_size());
W
wangguibao 已提交
190 191 192 193 194 195 196 197
    offset += req_instance.dense_ids_size();
  }

  in->push_back(lod_tensor);

  TensorVector *out = butil::get_object<TensorVector>();
  if (!out) {
    LOG(ERROR) << "Failed get tls output object";
W
wangguibao 已提交
198
    fill_response_with_message(res, -1, "Failed get thread local resource");
W
wangguibao 已提交
199
    return 0;
W
wangguibao 已提交
200 201 202 203 204 205 206
  }

  // call paddle fluid model for inferencing
  if (predictor::InferManager::instance().infer(
          CTR_PREDICTION_MODEL_NAME, in, out, sample_size)) {
    LOG(ERROR) << "Failed do infer in fluid model: "
               << CTR_PREDICTION_MODEL_NAME;
W
wangguibao 已提交
207
    fill_response_with_message(res, -1, "Failed do infer in fluid model");
W
wangguibao 已提交
208
    return 0;
W
wangguibao 已提交
209 210
  }

W
wangguibao 已提交
211
  if (out->size() != sample_size) {
W
wangguibao 已提交
212
    LOG(ERROR) << "Output tensor size not equal that of input";
W
wangguibao 已提交
213
    fill_response_with_message(res, -1, "Output size != input size");
W
wangguibao 已提交
214
    return 0;
W
wangguibao 已提交
215 216 217 218 219 220 221 222
  }

  for (size_t i = 0; i < out->size(); ++i) {
    int dim1 = out->at(i).shape[0];
    int dim2 = out->at(i).shape[1];

    if (out->at(i).dtype != paddle::PaddleDType::FLOAT32) {
      LOG(ERROR) << "Expected data type float";
W
wangguibao 已提交
223
      fill_response_with_message(res, -1, "Expected data type float");
W
wangguibao 已提交
224
      return 0;
W
wangguibao 已提交
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
    }

    float *data = static_cast<float *>(out->at(i).data.data());
    for (int j = 0; j < dim1; ++j) {
      CTRResInstance *res_instance = res->add_predictions();
      res_instance->set_prob0(data[j * dim2]);
      res_instance->set_prob1(data[j * dim2 + 1]);
    }
  }

  for (size_t i = 0; i < in->size(); ++i) {
    (*in)[i].shape.clear();
  }
  in->clear();
  butil::return_object<TensorVector>(in);

  for (size_t i = 0; i < out->size(); ++i) {
    (*out)[i].shape.clear();
  }
  out->clear();
  butil::return_object<TensorVector>(out);
W
wangguibao 已提交
246 247 248

  res->set_err_code(0);
  res->set_err_msg(std::string(""));
W
wangguibao 已提交
249 250 251 252 253 254 255 256
  return 0;
}

DEFINE_OP(CTRPredictionOp);

}  // namespace serving
}  // namespace paddle_serving
}  // namespace baidu