提交 0ba28a79 编写于 作者: M MRXLT

Merge remote-tracking branch 'upstream/develop' into develop

......@@ -50,6 +50,7 @@ option(WITH_AVX "Compile Paddle Serving with AVX intrinsics" ${AVX_FOUND}
option(WITH_MKL "Compile Paddle Serving with MKL support." ${AVX_FOUND})
option(WITH_GPU "Compile Paddle Serving with NVIDIA GPU" ${CUDA_FOUND})
option(CLIENT_ONLY "Compile client libraries and demos only" FALSE)
option(WITH_ELASTIC_CTR "Compile ELASITC-CTR solution" FALSE)
set(WITH_MKLML ${WITH_MKL})
if (NOT DEFINED WITH_MKLDNN)
......@@ -123,3 +124,8 @@ add_subdirectory(inferencer-fluid-gpu)
endif()
add_subdirectory(demo-serving)
endif()
# Paddle Serving Solutions
if (WITH_ELASTIC_CTR)
add_subdirectory(elastic-ctr)
endif()
/home/work/image-class/bin/image_class --workflow_path=/home/work/image-class/conf/ --inferservice_path=/home/work/image-class/conf/ --logger_path=/home/work/image-class/conf/ --resource_path=/home/work/image-class/conf/
......@@ -20,10 +20,12 @@ bzip2-devel
## 编译
推荐使用Docker编译Paddle Serving, [Docker编译使用说明](./DOCKER.md)
推荐使用Docker准备Paddle Serving编译环境. [Docker编译使用说明](./DOCKER.md)
以下命令将会下载Paddle Serving最新代码,并执行编译
```shell
$ git clone https://github.com/PaddlePaddle/serving.git
$ git clone https://github.com/PaddlePaddle/Serving.git
$ cd serving
$ mkdir build
$ cd build
......@@ -32,39 +34,31 @@ $ make -j4
$ make install
```
`make install`将把目标产出放在/path/to/paddle-serving/build/output/目录下,目录结构:
`make install`将把目标产出放在/path/to/Paddle-Serving/build/output/目录下,目录结构:
```
.
|-- bin # Paddle Serving protobuf编译插件pdcodegen所在目录
|-- bin # Paddle Serving工具和protobuf编译插件pdcodegen所在目录
|-- conf
|-- demo # demo总目录
| |-- client
| |-- client # Demo client端
| | |-- bert # bert模型客户端
| | |-- ctr_prediction # CTR prediction模型客户端
| | |-- dense_format # dense_format客户端
| | | |-- bin # bin/dense_format是dense_format客户端bin
| | | `-- conf
| | |-- echo # echo服务客户端
| | | |-- bin # bin/echo是echo客户端bin
| | | \-- conf
| | |-- image_classification # image_classification服务客户端
| | | |-- bin # bin/ximage是image_classification客户端bin
| | | |-- conf
| | | |-- data
| | | `-- images
| | |-- int64tensor_format # int64tensor_format服务客户端
| | | |-- bin # bin/int64tensor_format是客户端bin
| | | `-- conf
| | `-- sparse_format # sparse_format客户端
| | |-- bin # bin/sparse_format是客户端bin
| | `-- conf
| `-- serving # serving端,同时提供echo/dense_format/sparse_format/int64tensor_format/image_class等5种服务
| |-- bin # bin/serving是serving端可执行bin
| |-- conf # 配置文件目录
| |-- data
| | `-- model
| | `-- paddle
| | `-- fluid
| | `-- SE_ResNeXt50_32x4d # image_classification模型
`-- lib # Paddle Serving产出的静态库文件: libpdseving.a, libsdk-cpp.a, libconfigure.a, libfluid_cpu_engine.a
| | |-- echo # 最简单的echo service客户端
| | |-- echo_kvdb # local KV读取demo客户端
| | |-- image_classification # 图像分类任务客户端
| | |-- int64tensor_format # int64tensor_format示例客户端
| | |-- sparse_format # sparse_format示例客户端
| | `-- text_classification # 文本分类任务示例客户端
| |-- db_func
| |-- db_thread
| |-- kvdb_test
| `-- serving # Demo serving端;该serving可同时响应所有demo client请求
|-- include # Paddle Serving发布的头文件
|-- lib # Paddle Serving发布的libs
`-- tool # Paddle Serving发布的工具目录
```
如要编写新的预测服务,请参考[从零开始写一个预测服务](CREATING.md)
......
add_subdirectory(client)
add_subdirectory(serving)
include(proto/CMakeLists.txt)
file(GLOB sdk_cpp_srcs ${CMAKE_SOURCE_DIR}/sdk-cpp/src/*.cpp)
list(APPEND elasticctr_srcs ${elastic_ctr_cpp_srcs})
list(APPEND elasticctr_srcs ${sdk_cpp_srcs})
list(APPEND elasticctr_srcs
${CMAKE_CURRENT_LIST_DIR}/api/elastic_ctr_api.cpp)
add_library(elasticctr SHARED ${elasticctr_srcs})
target_link_libraries(elasticctr brpc configure protobuf leveldb -lcrypto
-lssl -lz -lrt)
set_target_properties(elasticctr PROPERTIES INTERFACE_LINK_LIBRARIES "")
add_executable(elastic_ctr_demo ${CMAKE_CURRENT_LIST_DIR}/demo/demo.cpp)
set_target_properties(elastic_ctr_demo PROPERTIES LINK_LIBRARIES "")
target_link_libraries(elastic_ctr_demo elasticctr -lpthread -lcrypto -lm -lrt
-lssl -ldl -lz)
# install
install(TARGETS elasticctr elastic_ctr_demo
RUNTIME DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/elastic_ctr/client/bin
LIBRARY DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/elastic_ctr/client/bin)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/demo/conf DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/elastic_ctr/client/)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/demo/data/ctr_prediction DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/elastic_ctr/client/data)
install(TARGETS elasticctr
LIBRARY DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/elastic_ctr/api/lib)
install(FILES ${CMAKE_CURRENT_LIST_DIR}/api/elastic_ctr_api.h
DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/elastic_ctr/api/include/elastic-ctr/client/api/)
install(FILES
${CMAKE_BINARY_DIR}/elastic-ctr/client/elastic_ctr_prediction.pb.h
${CMAKE_BINARY_DIR}/elastic-ctr/client/pds_option.pb.h
${CMAKE_BINARY_DIR}/elastic-ctr/client/builtin_format.pb.h
DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/elastic_ctr/api/include/elastic-ctr/client/)
install(DIRECTORY
${CMAKE_SOURCE_DIR}/sdk-cpp/include
DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/elastic_ctr/api/include/sdk-cpp/)
install(DIRECTORY
${CMAKE_SOURCE_DIR}/configure/include
DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/elastic_ctr/api/include/configure)
install(FILES
${CMAKE_BINARY_DIR}/configure/sdk_configure.pb.h
DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/elastic_ctr/api/include/configure)
install(DIRECTORY
${CMAKE_BINARY_DIR}/third_party/install/protobuf/include/google
${CMAKE_BINARY_DIR}/third_party/install/brpc/include/brpc
${CMAKE_BINARY_DIR}/third_party/install/brpc/include/butil
${CMAKE_BINARY_DIR}/third_party/install/brpc/include/bthread
${CMAKE_BINARY_DIR}/third_party/install/brpc/include/bvar
${CMAKE_BINARY_DIR}/third_party/install/brpc/include/json2pb
${CMAKE_BINARY_DIR}/third_party/install/gflags/include/gflags
${CMAKE_BINARY_DIR}/third_party/install/glog/include/glog
DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/elastic_ctr/api/include)
# Python client API
install(FILES ${CMAKE_CURRENT_LIST_DIR}/api/python/elasticctr/elastic_ctr_api.py
DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/elastic_ctr/api/lib)
install(FILES ${CMAKE_CURRENT_LIST_DIR}/api/python/elasticctr/elastic_ctr_api.py
DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/elastic_ctr/client/bin)
install(FILES ${CMAKE_CURRENT_LIST_DIR}/demo/elastic_ctr.py
DESTINATION ${PADDLE_SERVING_INSTALL_DIR}/elastic_ctr/client/bin)
// 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 "elastic-ctr/client/api/elastic_ctr_api.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fstream>
#include <vector>
namespace baidu {
namespace paddle_serving {
namespace elastic_ctr {
const int VARIABLE_NAME_LEN = 256;
static void thread_resource_delete(void *d) {
#if 1
LOG(INFO) << "thread_resource_delete on " << bthread_self();
#endif
delete static_cast<ThreadResource *>(d);
}
std::set<std::string> ElasticCTRPredictorApi::slot_names_;
int ThreadResource::clear() {
request_.clear_instances();
response_.clear_predictions();
for (auto it : instance_map_) {
delete it.second;
}
return 0;
}
ReqInstance *ThreadResource::add_instance() {
ReqInstance *instance = request_.add_instances();
InstanceInfo *instance_info = new InstanceInfo();
instance_map_[instance] = instance_info;
return instance;
}
int ThreadResource::add_slot(ReqInstance *instance,
const std::string &slot_name,
uint64_t value) {
auto instance_it = instance_map_.find(instance);
if (instance_it == instance_map_.end()) {
return -1;
}
InstanceInfo *instance_info = instance_it->second;
auto slot_it = instance_info->slot_map_.find(slot_name);
Slot *slot = NULL;
if (slot_it == instance_info->slot_map_.end()) {
slot = instance->add_slots();
instance_info->slot_map_[slot_name] = slot;
} else {
slot = slot_it->second;
}
slot->set_slot_name(slot_name);
slot->add_feasigns(value);
return 0;
}
void ThreadResource::validate_request(const std::set<std::string> &slot_names) {
for (auto it : instance_map_) {
ReqInstance *req_instance = it.first;
InstanceInfo *instance_info = it.second;
for (auto slot_name : slot_names) {
if (instance_info->slot_map_.find(slot_name) ==
instance_info->slot_map_.end()) {
LOG(INFO) << "Missing values for slot " << slot_name.c_str();
add_slot(req_instance, slot_name, 0);
}
}
}
}
int ElasticCTRPredictorApi::read_slot_conf(const char *path,
const char *slot_conf_file) {
struct stat stat_buf;
char name[VARIABLE_NAME_LEN];
snprintf(name, VARIABLE_NAME_LEN, "%s/%s", path, slot_conf_file);
if (stat(name, &stat_buf) != 0) {
LOG(ERROR) << "Error stating file" << name;
return -1;
}
std::ifstream fs(name);
for (std::string line; std::getline(fs, line);) {
slot_names_.insert(line);
}
#if 1
for (auto x : slot_names_) {
LOG(INFO) << "slot: " << x.c_str();
}
#endif
return 0;
}
int ElasticCTRPredictorApi::init(const char *path,
const char *slot_conf_file,
const char *serving_conf_file) {
int ret = api_.create(path, serving_conf_file);
if (ret != 0) {
return ret;
}
ret = read_slot_conf(path, slot_conf_file);
if (ret != 0) {
return ret;
}
// Thread-local storage
if (pthread_key_create(&tls_bspec_key_, thread_resource_delete) != 0) {
LOG(ERROR) << "unable to create tls_bthread_key of thrd_data";
return -1;
}
return 0;
}
int ElasticCTRPredictorApi::thrd_initialize() {
api_.thrd_initialize();
ThreadResource *thread_resource =
reinterpret_cast<ThreadResource *>(pthread_getspecific(tls_bspec_key_));
if (thread_resource == NULL) {
thread_resource = new (std::nothrow) ThreadResource;
if (thread_resource == NULL) {
LOG(ERROR) << "failed to create thread local resource";
return -1;
}
if (pthread_setspecific(tls_bspec_key_, thread_resource) != 0) {
LOG(ERROR) << "unable to set tls thread local resource";
delete thread_resource;
thread_resource = NULL;
return -1;
}
}
return 0;
}
int ElasticCTRPredictorApi::thrd_clear() {
api_.thrd_clear();
ThreadResource *thread_resource =
reinterpret_cast<ThreadResource *>(pthread_getspecific(tls_bspec_key_));
if (thread_resource == NULL) {
if (thread_resource == NULL) {
LOG(ERROR) << "ERROR: thread local resource is null";
return -1;
}
}
if (thread_resource->clear() != 0) {
LOG(ERROR) << "ElasticCTRPredictorApi: thrd_clear() fail";
}
return 0;
}
int ElasticCTRPredictorApi::thrd_finalize() {
api_.thrd_finalize();
return 0;
}
void ElasticCTRPredictorApi::destroy() {
pthread_key_delete(tls_bspec_key_);
return;
}
ReqInstance *ElasticCTRPredictorApi::add_instance() {
ThreadResource *thread_resource =
reinterpret_cast<ThreadResource *>(pthread_getspecific(tls_bspec_key_));
if (thread_resource == NULL) {
if (thread_resource == NULL) {
LOG(ERROR) << "ERROR: thread local resource is null";
return NULL;
}
}
ReqInstance *instance = thread_resource->add_instance();
return instance;
}
int ElasticCTRPredictorApi::add_slot(ReqInstance *instance,
const std::string slot_name,
int64_t value) {
ThreadResource *thread_resource =
reinterpret_cast<ThreadResource *>(pthread_getspecific(tls_bspec_key_));
if (thread_resource == NULL) {
if (thread_resource == NULL) {
LOG(ERROR) << "ERROR: thread local resource is null";
return -1;
}
}
if (slot_names_.find(slot_name) == slot_names_.end()) {
LOG(ERROR) << "Slot name not match with those in slot.conf: "
<< slot_name.c_str();
return -1;
}
return thread_resource->add_slot(instance, slot_name, value);
}
void ElasticCTRPredictorApi::validate_request() {
ThreadResource *thread_resource =
reinterpret_cast<ThreadResource *>(pthread_getspecific(tls_bspec_key_));
if (thread_resource == NULL) {
if (thread_resource == NULL) {
LOG(ERROR) << "ERROR: thread local resource is null";
return;
}
}
thread_resource->validate_request(slot_names_);
}
int ElasticCTRPredictorApi::inference(
std::vector<std::vector<float>> &results_vec) {
ThreadResource *thread_resource =
reinterpret_cast<ThreadResource *>(pthread_getspecific(tls_bspec_key_));
if (thread_resource == NULL) {
if (thread_resource == NULL) {
LOG(ERROR) << "ERROR: thread local resource is null";
return -1;
}
}
Predictor *predictor = api_.fetch_predictor("ctr_prediction_service");
if (!predictor) {
LOG(ERROR) << "Failed fetch predictor: ctr_prediction_service";
return -1;
}
validate_request();
int ret = predictor->inference(thread_resource->get_request(),
thread_resource->get_response());
if (ret != 0) {
LOG(ERROR) << "Failed call predictor with req "
<< thread_resource->get_request()->ShortDebugString();
return ret;
}
Response *response = thread_resource->get_response();
for (int i = 0; i < response->predictions_size(); ++i) {
const ResInstance &res_instance = response->predictions(i);
std::vector<float> res;
res.push_back(res_instance.prob0());
res.push_back(res_instance.prob1());
results_vec.push_back(res);
}
return 0;
}
} // namespace elastic_ctr
} // namespace paddle_serving
} // namespace baidu
// 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.
#pragma once
#define BRPC_WITH_GLOG 1 // To make sure prpoer glog inclusion
#include <map>
#include <set>
#include <string>
#include <vector>
#include "elastic-ctr/client/elastic_ctr_prediction.pb.h"
#include "sdk-cpp/include/predictor_sdk.h"
using baidu::paddle_serving::sdk_cpp::Predictor;
using baidu::paddle_serving::sdk_cpp::PredictorApi;
using baidu::paddle_serving::predictor::elastic_ctr::Slot;
using baidu::paddle_serving::predictor::elastic_ctr::Request;
using baidu::paddle_serving::predictor::elastic_ctr::ReqInstance;
using baidu::paddle_serving::predictor::elastic_ctr::Response;
using baidu::paddle_serving::predictor::elastic_ctr::ResInstance;
namespace baidu {
namespace paddle_serving {
namespace elastic_ctr {
struct InstanceInfo {
std::map<std::string, Slot *> slot_map_;
};
class ThreadResource {
public:
int clear();
Request *get_request() { return &request_; }
Response *get_response() { return &response_; }
ReqInstance *add_instance();
int add_slot(ReqInstance *instance,
const std::string &slot_name,
uint64_t value);
void validate_request(const std::set<std::string> &slot_names);
private:
Request request_;
Response response_;
std::map<ReqInstance *, InstanceInfo *> instance_map_;
};
struct Prediction {
float prob0;
float prob1;
};
class ElasticCTRPredictorApi {
public:
ElasticCTRPredictorApi() {}
int init(const char *path,
const char *slot_conf_file,
const char *serving_conf_file);
int thrd_initialize();
int thrd_clear();
int thrd_finalize();
void destroy();
static ElasticCTRPredictorApi &instance() {
static ElasticCTRPredictorApi api;
return api;
}
public:
ReqInstance *add_instance();
int add_slot(ReqInstance *instance,
const std::string slot_name,
int64_t value);
int inference(std::vector<std::vector<float>> &results_vec); // NOLINT
private:
static int read_slot_conf(const char *path, const char *slot_conf_file);
void validate_request();
private:
PredictorApi api_;
pthread_key_t tls_bspec_key_;
static std::set<std::string> slot_names_;
};
} // namespace elastic_ctr
} // namespace paddle_serving
} // namespace baidu
# 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.
from __future__ import print_function
import json
import sys
import os
if sys.version_info[0] == 2:
import httplib
elif sys.version_info[0] == 3:
import http.client
class ElasticCTRAPI(object):
def __init__(self, serving_ip, serving_port):
self._instances = []
self._slots = []
self._conn = self.conn(serving_ip, serving_port)
def read_slots_conf(self, slots_conf_file):
if not os.path.exists(slots_conf_file):
print("Path %s not exist" % sltos_conf_file)
return -1
with open(slots_conf_file, "r") as f:
for line in f:
self._slots.append(line.rstrip('\n'))
return 0
def conn(self, ip, port):
if sys.version_info[0] == 2:
return httplib.HTTPConnection(ip, port)
elif sys.version_info[0] == 3:
return http.client.HTTPConnection(ip, port)
def add_instance(self):
feature_slots = []
instance = [{"slots": feature_slots}]
self._instances += instance
return instance
def clear(self):
self._instances = []
def add_slot(self, instance, slot, feasigns):
if not isinstance(instance, list):
print("add slot: parameter invalid: instance should be list")
return -1
if not isinstance(feasigns, list):
print("add slot: value format invalid: feasigns should be list")
return -1
kv = [{"slot_name": slot, "feasigns": feasigns}]
instance[0]["slots"] += kv
def inference(self):
for instance in self._instances:
feature_slots = instance["slots"]
keys = []
for x in feature_slots:
keys += [x["slot_name"]]
for slot in self._slots:
if not slot in keys:
feature_slots += [{"slot_name": slot, "feasigns": [0]}]
req = {"instances": self._instances}
request_json = json.dumps(req)
if sys.version_info[0] == 2:
try:
self._conn.request(
'POST', "/ElasticCTRPredictionService/inference",
request_json, {"Content-Type": "application/json"})
response = self._conn.getresponse()
return response.read()
except httplib.HTTPException as e:
print(e.reason)
elif sys.version_info[0] == 3:
try:
self._conn.request(
'POST', "/ElasticCTRPredictionService/inference",
request_json, {"Content-Type": "application/json"})
response = self._conn.getresponse()
return response.read()
except http.clinet.HTTPException as e:
print(e.reason)
default_variant_conf {
tag: "default"
connection_conf {
connect_timeout_ms: 2000
rpc_timeout_ms: 20000
connect_retry_count: 2
max_connection_per_host: 100
hedge_request_timeout_ms: -1
hedge_fetch_retry_count: 2
connection_type: "pooled"
}
naming_conf {
cluster_filter_strategy: "Default"
load_balance_strategy: "la"
}
rpc_parameter {
compress_type: 0
package_size: 20
protocol: "baidu_std"
max_channel_per_request: 3
}
}
predictors {
name: "ctr_prediction_service"
service_name: "baidu.paddle_serving.predictor.elastic_ctr.ElasticCTRPredictionService"
endpoint_router: "WeightedRandomRender"
weighted_random_render_conf {
variant_weight_list: "50"
}
variants {
tag: "var1"
naming_conf {
cluster: "list://127.0.0.1:8010"
}
}
}
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
1 0 6927017134761466251:0 6718470718629228516:1 13269072425766530826:2 4716523811429044439:3 13082382022140897056:4 15218982276382079900:5 11163313789190369446:6 2862867910291820749:7 11053760986033849339:8 10502870772583566854:9 2124556436191220259:10 9785506636498967227:11 11192516382072790924:12 8807115620238838348:13 17995078462363758872:14 10382497101983282355:15 16754133082265779776:16 304257334858494316:17 15720168260628638326:18 6674055552811657342:19 8243359970626135167:20 15787226800440587041:21 17241709254077376921:22 9596905073876765726:23 2790018448824600319:24 3613283134603402626:25 6397718522477982172:26
1 0 10464417414901951369:0 6718470718629228516:1 9179429492816205016:2 13676622477856975702:3 3286191063564561647:4 15218982276382079900:5 12219910503415112001:6 5844921059192075884:7 16705280652459417397:8 10502870772583566854:9 13175866100369809054:10 9263190458225192516:11 4266371886186239285:12 11945162612181776727:13 17063534181803794493:14 4354228603469696964:15 12148918327299807724:16 7214965342802508003:17 673372825355324337:18 6674055552811657342:19 17448608490400648307:20 3349135020277955702:21 17241709254077376921:22 9596905073876765726:23 11768418306406963895:24 3613283134603402626:25 18046364706790889106:26
1 0 18259870924294394882:0 7926934355403741575:1 1778885384708968565:2 10047289093984926440:3 8904989556311027751:4 15218982276382079900:5 11163313789190369446:6 15481040064803050827:7 16705280652459417397:8 10502870772583566854:9 9116963774439914137:10 2024160023045377795:11 10053031071814030523:12 15703750054742521685:13 14643263989734319679:14 9919260370661433660:15 15203515116826900154:16 5923634413866883174:17 16749168151358928664:18 17241709254077376921:19 17241709254077376921:20 14140506767829083971:21 5666677101597231609:22 9596905073876765726:23 3767297468498765274:24
1 0 17241709254077376921:0 6718470718629228516:1 6907281343774280101:2 11759673712270006187:3 4118309569338760275:4 15218982276382079900:5 12219910503415112001:6 16943826576216803194:7 16705280652459417397:8 10502870772583566854:9 13713908212120537905:10 700492901176585495:11 6059397185486721393:12 888592242675254215:13 14643263989734319679:14 9661584506590972764:15 18205506194066348403:16 11455583154613207504:17 14802349586823085503:18 17241709254077376921:19 17241709254077376921:20 13531621461153817732:21 17241709254077376921:22 9596905073876765726:23 2496960796842971748:24
1 0 7148434200721666028:0 17433040772822544485:1 1107762186306793885:2 18163012018653214493:3 15294713434719486333:4 15218982276382079900:5 9630582567144824550:6 15183274508769830484:7 16705280652459417397:8 10502870772583566854:9 1223989198202660467:10 13016347094912498810:11 1501638003805635312:12 15368041789475197909:13 17995078462363758872:14 18389378052457170731:15 16201993636138692864:16 11455583154613207504:17 4186049538830404914:18 17241709254077376921:19 17241709254077376921:20 10946611799884353646:21 17241709254077376921:22 11162666878533603762:23 9008292542607610184:24
1 0 17241709254077376921:0 132683728328325035:1 9878834515792997342:2 11380942336101970490:3 1783733297169330482:4 14669113407484985090:5 16604931673559730414:6 1151521833841701280:7 16705280652459417397:8 10502870772583566854:9 9116963774439914137:10 11471538872319732880:11 6159851880783390255:12 8345868733258616845:13 14643263989734319679:14 9825544215843793104:15 11057739430758424260:16 6932058406762394060:17 5802476668582561065:18 17241709254077376921:19 17241709254077376921:20 2589136076946269828:21 15225822399263889742:22 10610591363390850070:23 17344032937842889734:24
1 0 17241709254077376921:0 15209504892615885284:1 15700428036256333758:2 11861876803960528482:3 13982612809544027114:4 14669113407484985090:5 12219910503415112001:6 1917311332865131635:7 16705280652459417397:8 10502870772583566854:9 9116963774439914137:10 7557811442566408881:11 2660233397818919068:12 5883618680467675950:13 14643263989734319679:14 7618795044156816860:15 11907467542688733617:16 6932058406762394060:17 3017257153289738061:18 17241709254077376921:19 17241709254077376921:20 10288183625953528372:21 17241709254077376921:22 3737242667984714764:23 3441016006405463335:24
1 1 7148434200721666028:0 6718470718629228516:1 6907281343774280101:2 3053743611132167362:3 14555014367769717036:4 6609445196442839881:5 9630582567144824550:6 12824208005498741289:7 11053760986033849339:8 10502870772583566854:9 6597088772170499071:10 7856412937977050057:11 1891095274901020120:12 12618002768285189399:13 14643263989734319679:14 9661584506590972764:15 17855570972874293332:16 304257334858494316:17 14802349586823085503:18 17241709254077376921:19 17241709254077376921:20 12806982889865979921:21 17241709254077376921:22 11162666878533603762:23 2496960796842971748:24
1 0 12485775574321252452:0 132683728328325035:1 16661495110910303502:2 3074368415590455844:3 8904989556311027751:4 15218982276382079900:5 11163313789190369446:6 11923057388420984245:7 16705280652459417397:8 10502870772583566854:9 7171076840194666165:10 2094933755936510892:11 5461414925766068262:12 3465889447608886364:13 17063534181803794493:14 18271887029749773133:15 1101066663604879927:16 304257334858494316:17 11361347596796230131:18 17241709254077376921:19 17241709254077376921:20 16228061434981101242:21 17241709254077376921:22 11162666878533603762:23 3767297468498765274:24
1 0 13237225503670494420:0 132683728328325035:1 12379855725162006335:2 6074644261212226397:3 4596341914073759138:4 15218982276382079900:5 17241709254077376921:6 7497940997956148496:7 16705280652459417397:8 10502870772583566854:9 3021779155663915969:10 700492901176585495:11 4298977842768597523:12 888592242675254215:13 14643263989734319679:14 16023222668447088896:15 3371375212725266231:16 1187841073466173462:17 11941593174888892430:18 17241709254077376921:19 17241709254077376921:20 11692050119657422863:21 17241709254077376921:22 11162666878533603762:23 8839615097223058291:24
1 0 6927017134761466251:0 132683728328325035:1 10347279397112858233:2 14839005752061317576:3 11643462142079559806:4 15218982276382079900:5 11163313789190369446:6 9915797641434557402:7 16705280652459417397:8 5275575326790214142:9 9116963774439914137:10 2489870094069298004:11 16691266054645198741:12 11385501165283893086:13 17063534181803794493:14 12702100553493906816:15 9868549944644069825:16 6932058406762394060:17 7176777661971465827:18 6674055552811657342:19 17448608490400648307:20 16671638717570212599:21 17241709254077376921:22 9596905073876765726:23 8654884481043531114:24 9026989529823845647:25 15841982015093426084:26
1 0 1310192797669293303:0 132683728328325035:1 4525871349710877017:2 17241709254077376921:3 17241709254077376921:4 7239340616520487435:5 17241709254077376921:6 3679002119163610755:7 16705280652459417397:8 10502870772583566854:9 9116963774439914137:10 11218057536677162506:11 17241709254077376921:12 16350770227650797371:13 14643263989734319679:14 7652545525870866588:15 17241709254077376921:16 1187841073466173462:17 3917691649488249040:18 17241709254077376921:19 17241709254077376921:20 17241709254077376921:21 17241709254077376921:22 11162666878533603762:23
1 1 17241709254077376921:0 5886642295555720176:1 2302007180625858651:2 3522395746448527778:3 2805783828848712657:4 15218982276382079900:5 12219910503415112001:6 1268285911768541945:7 11053760986033849339:8 10502870772583566854:9 6143237717931161494:10 9637316102620415512:11 14196558684519731586:12 1225582077137166504:13 14643263989734319679:14 13112879913003496586:15 7545078501456903577:16 304257334858494316:17 16747724740464524161:18 17241709254077376921:19 17241709254077376921:20 347598151995767353:21 17241709254077376921:22 11162666878533603762:23 9008292542607610184:24
1 1 7674613650421074157:0 7324272953288436219:1 11725014094608043127:2 8803639408734925858:3 1220362653046102507:4 15218982276382079900:5 17241709254077376921:6 3878571312485518757:7 1920186525784302087:8 10502870772583566854:9 11648837483459045015:10 16964067792457588528:11 11139776027905272755:12 10931274492845838224:13 17995078462363758872:14 2882784002226225948:15 10592424308493458658:16 7214965342802508003:17 6489109027974645363:18 14824971285521433284:19 13903136866082777265:20 6209214591281588946:21 17241709254077376921:22 11162666878533603762:23 3864802563280438997:24 16289510092137203187:25 1143328503493968665:26
1 0 10464417414901951369:0 2725392301144350401:1 13269072425766530826:2 9340936592426343633:3 11607812542444855181:4 13061831759115026268:5 9630582567144824550:6 11684333772387618712:7 16705280652459417397:8 10502870772583566854:9 858103900590211222:10 2405475863815797309:11 10117123305461389642:12 1866649320189135820:13 17995078462363758872:14 18231693188453206193:15 7670149246223096137:16 12702162550489317753:17 3760431104103189667:18 6674055552811657342:19 8243359970626135167:20 5810191645665591538:21 17241709254077376921:22 11419070899087401463:23 11940139939806103414:24 3613283134603402626:25 11488888525484967944:26
1 0 18421644133257438848:0 132683728328325035:1 15296625554996690440:2 6460096976460959722:3 5151100674755853378:4 7239340616520487435:5 11163313789190369446:6 16238191574805953955:7 118720139541262076:8 10502870772583566854:9 9116963774439914137:10 16457356537362114607:11 6318549872891452918:12 2269348080352524802:13 11725792966931771710:14 16598043686953869187:15 8523338795451265391:16 6932058406762394060:17 17303720831352440113:18 17241709254077376921:19 17241709254077376921:20 14407037351922272955:21 17241709254077376921:22 9596905073876765726:23 15777325756826686259:24
1 1 6927017134761466251:0 6718470718629228516:1 13812071245874841815:2 8369163560705844602:3 801357380150787769:4 14669113407484985090:5 11163313789190369446:6 17793779049215302883:7 16705280652459417397:8 10502870772583566854:9 9116963774439914137:10 14718017702897407632:11 3209425260585266535:12 2492063417888556224:13 14643263989734319679:14 10966027886771057503:15 17295743869407193057:16 1187841073466173462:17 6734693422874215969:18 6674055552811657342:19 8243359970626135167:20 139482499327938777:21 17241709254077376921:22 11162666878533603762:23 8986115834532843425:24 1212354230547063649:25 11921475662408304750:26
1 0 13237225503670494420:0 17433040772822544485:1 1249352555698790157:2 6598874905195514554:3 3851538550409232565:4 7239340616520487435:5 8545055878216481300:6 5396822049332454302:7 16705280652459417397:8 10502870772583566854:9 6363466516423560187:10 11742149585588302477:11 1472616606809977294:12 13262001584124104287:13 17063534181803794493:14 17386800219881813582:15 1184590423286429205:16 304257334858494316:17 11746042240980974055:18 17241709254077376921:19 17241709254077376921:20 13624892508265615348:21 5666677101597231609:22 11162666878533603762:23 11847417109351225181:24
1 0 6927017134761466251:0 132683728328325035:1 9179429492816205016:2 12419927172070481052:3 16671678693872619409:4 17756465370064782659:5 8545055878216481300:6 2045728908485389207:7 4138847090351627078:8 10502870772583566854:9 624423715505587893:10 12718524099270024168:11 3882570943592267952:12 10781054518172359479:13 17995078462363758872:14 1390991494269790816:15 10983444501041401410:16 304257334858494316:17 673372825355324337:18 6674055552811657342:19 8243359970626135167:20 2189564446769495792:21 17241709254077376921:22 11162666878533603762:23 13220987151312695470:24 9026989529823845647:25 3034715851719530798:26
1 0 2744517546871237796:0 556544228763852288:1 8481262454092976260:2 4285960921148380086:3 13539253269495735736:4 7239340616520487435:5 9630582567144824550:6 12592895141281845869:7 16705280652459417397:8 10502870772583566854:9 17613298579766747861:10 16294710391255798824:11 17119319932275946669:12 16099645876152503593:13 14989216248460247009:14 1669199932227554795:15 773390050937845162:16 304257334858494316:17 11636838557479375654:18 17241709254077376921:19 17241709254077376921:20 15199286621432794054:21 17241709254077376921:22 12431040719102188135:23 11285526042152906113:24
1 1 1310192797669293303:0 15010597255987710479:1 2302007180625858651:2 1251912094623613011:3 8522350885443931925:4 15218982276382079900:5 11163313789190369446:6 2047382364755587755:7 991491529160202440:8 10502870772583566854:9 9116963774439914137:10 7146496797683784011:11 1624394027251615434:12 1468720105145813976:13 17995078462363758872:14 14610776272202945736:15 2051660839140268666:16 304257334858494316:17 8703513102941686805:18 17241709254077376921:19 17241709254077376921:20 16353039357050006708:21 17241709254077376921:22 11162666878533603762:23 1662435709620374852:24
1 0 10464417414901951369:0 132683728328325035:1 7761720401600392176:2 18114723123959769805:3 13390725149381271337:4 15218982276382079900:5 11163313789190369446:6 15410654408295982340:7 16705280652459417397:8 10502870772583566854:9 9116963774439914137:10 11893228565340993044:11 16811862145746373167:12 15906580571062931567:13 14643263989734319679:14 17417746869860111491:15 6820615658552164193:16 1187841073466173462:17 11710860182646955307:18 5687057810081340784:19 13903136866082777265:20 16744507119825703441:21 17241709254077376921:22 11162666878533603762:23 14943488082984001954:24 3613283134603402626:25 7604332626579472805:26
1 0 1310192797669293303:0 132683728328325035:1 2302007180625858651:2 10897719044254269746:3 5925846051782389161:4 15218982276382079900:5 8545055878216481300:6 13714358487444275641:7 991491529160202440:8 10502870772583566854:9 7778077206090334959:10 7388416915218585967:11 4591077158912775099:12 7506644265205420368:13 17063534181803794493:14 3705801579907156743:15 17085522217548379788:16 7214965342802508003:17 18154360331214990224:18 17241709254077376921:19 17241709254077376921:20 10963044268547670158:21 17241709254077376921:22 9596905073876765726:23 17414791962410575054:24
1 0 4515155089025077856:0 132683728328325035:1 11405409102603512372:2 8251945709297840525:3 7543223253778120235:4 15218982276382079900:5 11163313789190369446:6 2246324634435112644:7 16705280652459417397:8 10502870772583566854:9 9377127350574299749:10 8139166123436103210:11 13689654574437186097:12 11294956118538932177:13 14643263989734319679:14 8919898324792675572:15 2378680629806545058:16 11455583154613207504:17 6931488981881357525:18 17241709254077376921:19 17241709254077376921:20 16169389805558479250:21 17241709254077376921:22 14895502180141653390:23 9380115577475751377:24
1 0 17241709254077376921:0 2725392301144350401:1 10121931627885813714:2 3074368415590455844:3 8904989556311027751:4 15218982276382079900:5 11163313789190369446:6 17382075769804193277:7 16705280652459417397:8 10502870772583566854:9 12627544959104597769:10 1263308814507219723:11 5461414925766068262:12 3581508654345215642:13 14643263989734319679:14 9943212798300089479:15 1101066663604879927:16 1187841073466173462:17 12228204936486541205:18 17241709254077376921:19 17241709254077376921:20 16228061434981101242:21 14702504267520853429:22 9596905073876765726:23 3767297468498765274:24
1 0 17241709254077376921:0 2725392301144350401:1 7761720401600392176:2 11564561306807028662:3 15613298054424122150:4 15218982276382079900:5 17241709254077376921:6 10574792713779585457:7 16705280652459417397:8 10502870772583566854:9 6835349046682511653:10 11450198402057045659:11 7939464828829647706:12 6249927819966478852:13 7830116631536757802:14 5291175334204734932:15 14168143301350297163:16 7214965342802508003:17 11710860182646955307:18 1904009232434063178:19 13903136866082777265:20 15218713873994451489:21 17241709254077376921:22 11162666878533603762:23 5075464188083089464:24 3613283134603402626:25 6420753415704873062:26
1 1 12522305586339984642:0 17433040772822544485:1 11610205181468921922:2 12495413138988957243:3 14514583139797418816:4 15218982276382079900:5 11163313789190369446:6 1024676000316375047:7 11053760986033849339:8 10502870772583566854:9 16615750646632226979:10 8918896465005633300:11 9604668264211240048:12 10101989200715543075:13 14643263989734319679:14 3316745331177704448:15 13068263067076303846:16 11990012572963238042:17 10571811563118485420:18 6674055552811657342:19 13903136866082777265:20 5452194489244847065:21 17241709254077376921:22 11162666878533603762:23 8554804225766097854:24 13073481964273803881:25 3011175035015983684:26
1 1 6927017134761466251:0 6718470718629228516:1 2302007180625858651:2 16646566645713148609:3 8842147488328088793:4 7239340616520487435:5 11163313789190369446:6 7308362630242429461:7 16705280652459417397:8 10502870772583566854:9 11981115407209600669:10 16019080599479355057:11 7534128559857757061:12 8524159296168860913:13 14643263989734319679:14 18318827611950119257:15 3926699863293873238:16 12702162550489317753:17 4145364840174650918:18 17241709254077376921:19 17241709254077376921:20 7049434558429390848:21 17241709254077376921:22 9596905073876765726:23 14035356172170531840:24
1 1 17181926294437511708:0 6718470718629228516:1 5532134615375792653:2 5982899062617373488:3 8574179624883972242:4 7239340616520487435:5 16604931673559730414:6 9957622867904136669:7 16705280652459417397:8 10502870772583566854:9 7288041857773198145:10 12867563715192712027:11 15668081095363425709:12 15634626493901516249:13 17063534181803794493:14 6595409912005001338:15 16246751017073483244:16 304257334858494316:17 12114569828945163324:18 17241709254077376921:19 17241709254077376921:20 13214684022665073004:21 17241709254077376921:22 11162666878533603762:23 2836226778862690321:24
1 1 2515344368701119404:0 132683728328325035:1 16022881555416999883:2 14905174545263472017:3 14514404294664920713:4 15218982276382079900:5 9630582567144824550:6 14473553880688237330:7 16705280652459417397:8 10502870772583566854:9 7909506806877050790:10 700492901176585495:11 3239561746203967292:12 888592242675254215:13 7830116631536757802:14 14437248923152261292:15 7346608955167379841:16 304257334858494316:17 13739989172691280302:18 17241709254077376921:19 17241709254077376921:20 7850582845043555360:21 17241709254077376921:22 9596905073876765726:23 14282093253411701637:24
1 1 2744517546871237796:0 17433040772822544485:1 1325795336450945050:2 1273041429893930252:3 7496206612731460364:4 7239340616520487435:5 12219910503415112001:6 12331751569608134940:7 16705280652459417397:8 10502870772583566854:9 9116963774439914137:10 8033853962316844090:11 16745769382145216455:12 7876683170645847226:13 14643263989734319679:14 17376323974655968040:15 11742382316912349910:16 304257334858494316:17 11402365575022235878:18 17241709254077376921:19 17241709254077376921:20 13804780290152816225:21 17241709254077376921:22 9596905073876765726:23 12625173738661007962:24
1 0 17241709254077376921:0 7324272953288436219:1 13638147752706036569:2 3074368415590455844:3 8904989556311027751:4 15218982276382079900:5 12219910503415112001:6 384139667903776154:7 16705280652459417397:8 10502870772583566854:9 9116963774439914137:10 16598510211540031812:11 5461414925766068262:12 5718563564474677932:13 10635807090093424908:14 3922542365398847669:15 1101066663604879927:16 6932058406762394060:17 523783748084120554:18 17241709254077376921:19 17241709254077376921:20 16228061434981101242:21 17241709254077376921:22 9516923928322464298:23 3767297468498765274:24
1 0 17241709254077376921:0 132683728328325035:1 6959743776458474126:2 14424470049749894883:3 8005244996750823827:4 7239340616520487435:5 11163313789190369446:6 1024676000316375047:7 16705280652459417397:8 10502870772583566854:9 16881259423969557990:10 8918896465005633300:11 1061055799094912692:12 10101989200715543075:13 14643263989734319679:14 1383314317141920805:15 7793114640966478292:16 12702162550489317753:17 7209367094585708084:18 17241709254077376921:19 17241709254077376921:20 909388936747680086:21 17241709254077376921:22 11162666878533603762:23 16991424487007093566:24
1 0 12485775574321252452:0 132683728328325035:1 7756736608808612461:2 11577167303561283088:3 11607812542444855181:4 15218982276382079900:5 17241709254077376921:6 15410654408295982340:7 16705280652459417397:8 10502870772583566854:9 9116963774439914137:10 5392140113819433218:11 6997068159145122057:12 15906580571062931567:13 17485091878519158637:14 9555789384938451448:15 7670149246223096137:16 6932058406762394060:17 11266289668075112357:18 6674055552811657342:19 13903136866082777265:20 10091184306909033270:21 17241709254077376921:22 11162666878533603762:23 11940139939806103414:24 3613283134603402626:25 4560520958389071443:26
1 1 13237225503670494420:0 132683728328325035:1 7869373560102816254:2 10656729542438180977:3 16660288238169217524:4 15218982276382079900:5 17241709254077376921:6 7078992212226069630:7 16705280652459417397:8 10502870772583566854:9 2917400784138383462:10 13766608908513013628:11 4140848663537918691:12 3505527365334819935:13 17063534181803794493:14 80851017785285077:15 15531219999041518193:16 304257334858494316:17 10223771578267841980:18 17241709254077376921:19 17241709254077376921:20 379885792831848099:21 17241709254077376921:22 11162666878533603762:23 13507591849647755113:24
1 1 2744517546871237796:0 132683728328325035:1 2568470288720291233:2 7194489148694036722:3 6604426708968873079:4 7239340616520487435:5 8545055878216481300:6 17690669239570722078:7 16705280652459417397:8 10502870772583566854:9 1317134747613085835:10 5129648633975577085:11 10615548322336250981:12 13288734802378361721:13 14643263989734319679:14 3666714016737623396:15 15553709248581595649:16 5923634413866883174:17 11252861524791023509:18 2539435020450717756:19 13903136866082777265:20 7627118189590369514:21 5666677101597231609:22 14895502180141653390:23 5075464188083089464:24 9545123730527789043:25 6420753415704873062:26
1 0 17241709254077376921:0 16707040802038577899:1 16661495110910303502:2 5417495491599040800:3 3851538550409232565:4 15218982276382079900:5 11163313789190369446:6 10662314431050571660:7 11053760986033849339:8 10502870772583566854:9 9116963774439914137:10 8765734899149507447:11 10476933088170757261:12 9314838448007602968:13 17063534181803794493:14 12708386797627152534:15 1319185336447062834:16 6932058406762394060:17 1868988231257466985:18 17241709254077376921:19 17241709254077376921:20 1685454248563167127:21 17241709254077376921:22 11162666878533603762:23 11847417109351225181:24
1 0 17241709254077376921:0 14155721711170412399:1 17142147528445973487:2 309337549254456223:3 15650484392488235370:4 15218982276382079900:5 8545055878216481300:6 311225110694346085:7 16705280652459417397:8 10502870772583566854:9 7512753248695961857:10 789011181240346650:11 4689488607513039466:12 14329525652244951778:13 17063534181803794493:14 3114316559132996799:15 3493914413622711205:16 304257334858494316:17 2685465578393107277:18 6674055552811657342:19 13903136866082777265:20 183903379593608337:21 14702504267520853429:22 9419421512119490042:23 15707147566107585215:24 1212354230547063649:25 16322571623044823521:26
1 0 6080128442901703586:0 6718470718629228516:1 1325795336450945050:2 5081130028485875212:3 16183188853307284423:4 7239340616520487435:5 11163313789190369446:6 13588677844043420585:7 16705280652459417397:8 10502870772583566854:9 4653293388811748114:10 16372184753895583572:11 9970377938399320317:12 12474407437585636151:13 17995078462363758872:14 2154498555344425901:15 2514726800494388784:16 304257334858494316:17 13396841265939349009:18 17241709254077376921:19 17241709254077376921:20 2577543406825224159:21 17241709254077376921:22 11162666878533603762:23 12625173738661007962:24
1 0 18421644133257438848:0 2725392301144350401:1 6974293052959110895:2 15433061552422749716:3 7645359936682228524:4 15218982276382079900:5 17241709254077376921:6 18010627938646841509:7 16705280652459417397:8 10502870772583566854:9 9325814154323450115:10 10732935658775168222:11 14218201933603660697:12 13820288385413778690:13 17995078462363758872:14 18000658703715585342:15 9346827588225243975:16 5923634413866883174:17 10580802880289134283:18 6674055552811657342:19 8243359970626135167:20 8081392395287237696:21 17241709254077376921:22 11162666878533603762:23 16132620102982681109:24 9545123730527789043:25 3253737704730139202:26
1 0 10464417414901951369:0 132683728328325035:1 6959743776458474126:2 3074368415590455844:3 8904989556311027751:4 7239340616520487435:5 8545055878216481300:6 1024676000316375047:7 11053760986033849339:8 10502870772583566854:9 16615750646632226979:10 8918896465005633300:11 5461414925766068262:12 10101989200715543075:13 14643263989734319679:14 17679098502651198491:15 1101066663604879927:16 5923634413866883174:17 14978393120498354338:18 17241709254077376921:19 17241709254077376921:20 16228061434981101242:21 17241709254077376921:22 11162666878533603762:23 3767297468498765274:24
1 1 10464417414901951369:0 132683728328325035:1 11405409102603512372:2 17521105332861035085:3 15696811749211935437:4 15218982276382079900:5 8545055878216481300:6 7995709161350464776:7 16705280652459417397:8 10502870772583566854:9 8972257840302114602:10 2277686576113039246:11 3581840317011793591:12 12204173254688087823:13 17063534181803794493:14 3454666637371315104:15 5755484633992816039:16 5923634413866883174:17 12442700095681125561:18 17241709254077376921:19 17241709254077376921:20 5235658467977583426:21 17241709254077376921:22 11162666878533603762:23 13216860939962807533:24
1 0 7674613650421074157:0 132683728328325035:1 7761720401600392176:2 8469104618800065557:3 14648424205675448851:4 15218982276382079900:5 17241709254077376921:6 18162361451095511218:7 16705280652459417397:8 10502870772583566854:9 7859210876267311457:10 936474412636531367:11 172138924868194437:12 833956697717950326:13 17995078462363758872:14 8926080012733512439:15 883905295314056489:16 12702162550489317753:17 8117304531237350068:18 8819009507283715567:19 13903136866082777265:20 4574862061147892267:21 17241709254077376921:22 11162666878533603762:23 17414791962410575054:24 3613283134603402626:25 18333160135461364208:26
1 0 17241709254077376921:0 2725392301144350401:1 2302007180625858651:2 11497197735685607883:3 14678136854556310063:4 15218982276382079900:5 11163313789190369446:6 4540976613599653853:7 991491529160202440:8 5275575326790214142:9 9116963774439914137:10 3559315722260084772:11 14845566131754782335:12 10695095974431628238:13 14643263989734319679:14 10593381915738125194:15 2901804296254959117:16 1187841073466173462:17 10783949422666782912:18 17241709254077376921:19 17241709254077376921:20 7157991049882411293:21 17241709254077376921:22 9596905073876765726:23 11177134726796456344:24
1 0 17241709254077376921:0 132683728328325035:1 13638147752706036569:2 3074368415590455844:3 8904989556311027751:4 14669113407484985090:5 11163313789190369446:6 8556504194464356700:7 16705280652459417397:8 10502870772583566854:9 17834893318925711613:10 10314616971867983483:11 5461414925766068262:12 1172247109089069239:13 10635807090093424908:14 3922542365398847669:15 1101066663604879927:16 7214965342802508003:17 523783748084120554:18 17241709254077376921:19 17241709254077376921:20 16228061434981101242:21 14702504267520853429:22 9596905073876765726:23 3767297468498765274:24
1 0 13237225503670494420:0 132683728328325035:1 16661495110910303502:2 1896203452519532245:3 3851538550409232565:4 15218982276382079900:5 11163313789190369446:6 12807306182975078013:7 991491529160202440:8 10502870772583566854:9 9116963774439914137:10 17245004084799800418:11 1357724897190789423:12 16928674665660501381:13 17063534181803794493:14 12708386797627152534:15 403578019026461591:16 12702162550489317753:17 1868988231257466985:18 17241709254077376921:19 17241709254077376921:20 12694187641533714018:21 17241709254077376921:22 11162666878533603762:23 11847417109351225181:24
1 0 7885493856155582604:0 132683728328325035:1 10778118909304089744:2 3074368415590455844:3 8904989556311027751:4 7239340616520487435:5 11163313789190369446:6 14070589390653787841:7 6278115880124280497:8 10502870772583566854:9 9116963774439914137:10 16457356537362114607:11 5461414925766068262:12 2269348080352524802:13 17995078462363758872:14 2904196646018580026:15 1101066663604879927:16 304257334858494316:17 12412539170032122490:18 17241709254077376921:19 17241709254077376921:20 16228061434981101242:21 17241709254077376921:22 11162666878533603762:23 3767297468498765274:24
1 0 2489716146917121730:0 132683728328325035:1 17142147528445973487:2 11731712469714370552:3 16068800663921896502:4 15218982276382079900:5 8545055878216481300:6 2721940599734264845:7 16705280652459417397:8 10502870772583566854:9 15569061900063125436:10 10128672630056248315:11 18196391687378076903:12 9397555878993963837:13 14643263989734319679:14 4207359405239731256:15 13930716292907012619:16 304257334858494316:17 2685465578393107277:18 13884179104666065155:19 13903136866082777265:20 10518581636251048878:21 15641088087303452745:22 2889020552648910850:23 15041414959391718373:24 1212354230547063649:25 13996985142559576937:26
1 0 10464417414901951369:0 132683728328325035:1 2302007180625858651:2 14520649193439426780:3 15838390496681904262:4 15218982276382079900:5 12219910503415112001:6 1019471316359140639:7 11053760986033849339:8 10502870772583566854:9 16852185604723469529:10 11714595700715893218:11 2919821707309641602:12 6451082234801926718:13 17063534181803794493:14 6532587202758115977:15 7392598919204943076:16 304257334858494316:17 930413416427421657:18 17241709254077376921:19 17241709254077376921:20 254411386241374525:21 17241709254077376921:22 14895502180141653390:23 16019062971771971394:24
1 0 17241709254077376921:0 6718470718629228516:1 15793601865269415752:2 4415549998256817150:3 13862888586835434227:4 15218982276382079900:5 17241709254077376921:6 3874040758317561930:7 16705280652459417397:8 10502870772583566854:9 16537231773771350523:10 16620497602680476516:11 14290328798218203616:12 299766009414260151:13 17063534181803794493:14 16254155403319323417:15 3033065783430161494:16 304257334858494316:17 5885659819938670107:18 17241709254077376921:19 17241709254077376921:20 7608683087502877813:21 17241709254077376921:22 11162666878533603762:23 4447435252162465088:24
1 0 2104849252515447450:0 132683728328325035:1 2568470288720291233:2 9220353264788412283:3 11961315514967285277:4 1270111884358453186:5 11163313789190369446:6 12828435744279702426:7 6278115880124280497:8 10502870772583566854:9 9116963774439914137:10 7543252018161894567:11 2620322913300808617:12 14286354118342488235:13 17063534181803794493:14 2080111411455573937:15 17857733346223087027:16 5923634413866883174:17 11252861524791023509:18 7633813901422151913:19 13903136866082777265:20 13204446223212041104:21 17241709254077376921:22 9419421512119490042:23 5232670654339416318:24 9545123730527789043:25 13595181148984071975:26
1 1 2744517546871237796:0 2725392301144350401:1 2302007180625858651:2 249368224523449598:3 16737671921008133548:4 15218982276382079900:5 8545055878216481300:6 6166217781917718354:7 16705280652459417397:8 10502870772583566854:9 9116963774439914137:10 11575803860721327984:11 6488483739913062335:12 14891795159246543839:13 14643263989734319679:14 3713619133079082266:15 12118325671211587077:16 1187841073466173462:17 4413643969382843884:18 17241709254077376921:19 17241709254077376921:20 17849614474163407466:21 5666677101597231609:22 9596905073876765726:23 12271817899803072298:24
1 0 2744517546871237796:0 2556070921675172938:1 9831410514477038641:2 14409896190396645695:3 16435981311880596528:4 17756465370064782659:5 17241709254077376921:6 1418067059371300333:7 16705280652459417397:8 10502870772583566854:9 9116963774439914137:10 12402666635098576898:11 8779903365955772183:12 2701229318996507578:13 17995078462363758872:14 1880891991909007115:15 10785715091001021530:16 5923634413866883174:17 14211833462300942432:18 6674055552811657342:19 17448608490400648307:20 17197118316423679236:21 17241709254077376921:22 9516923928322464298:23 3767297468498765274:24 7968176428150426131:25 5909423592700275632:26
1 0 2744517546871237796:0 132683728328325035:1 11725014094608043127:2 6726966574958754102:3 16458791879951329218:4 15218982276382079900:5 9630582567144824550:6 17293010697459386247:7 4138847090351627078:8 10502870772583566854:9 2665116241244973724:10 2977282149199928954:11 2961072396289871319:12 14698203746985923458:13 17063534181803794493:14 15130080775503074076:15 8017149473582916519:16 5923634413866883174:17 6489109027974645363:18 2621219481720594487:19 8243359970626135167:20 3837798764716463050:21 17241709254077376921:22 9596905073876765726:23 1353937445816974199:24 3613283134603402626:25 5819539240603206806:26
1 0 1750302349509622455:0 1399035476613128213:1 17229753468900380177:2 7043770294042418930:3 10566002751857054807:4 15218982276382079900:5 11163313789190369446:6 5740590945386362916:7 991491529160202440:8 10502870772583566854:9 17091716463194279034:10 7886110891812946531:11 15659163698846131538:12 1992204986776921674:13 17995078462363758872:14 5846085299175120524:15 15544525090671103642:16 304257334858494316:17 12372331349497572863:18 17933444987208371535:19 13903136866082777265:20 11940518710504691557:21 17241709254077376921:22 2889020552648910850:23 16707091133635332751:24 15247174146344178271:25 9893080987624171859:26
1 0 7148434200721666028:0 17433040772822544485:1 11725014094608043127:2 11620790130793768247:3 13143543288151247360:4 15218982276382079900:5 11163313789190369446:6 9242147045642447424:7 15351441355156184373:8 10502870772583566854:9 12509085737619438205:10 11194098499946258502:11 4164599856737299371:12 8147856953322073385:13 14643263989734319679:14 8715524256750344983:15 18244293659739398429:16 304257334858494316:17 6489109027974645363:18 10731979616508713592:19 17448608490400648307:20 4762820616795212702:21 17241709254077376921:22 14895502180141653390:23 17414791962410575054:24 3613283134603402626:25 7418222241202479616:26
1 0 2744517546871237796:0 7324272953288436219:1 7761720401600392176:2 7616194583075143326:3 13656423230124312275:4 15218982276382079900:5 11163313789190369446:6 16893141893281011546:7 13022504441432371752:8 10502870772583566854:9 2665116241244973724:10 5502979128277945668:11 608927956349318034:12 7278718362455314919:13 14643263989734319679:14 17417746869860111491:15 14722425693660425498:16 5923634413866883174:17 11710860182646955307:18 6674055552811657342:19 13903136866082777265:20 12574198784123194788:21 17241709254077376921:22 9596905073876765726:23 5075464188083089464:24 4164242000176313026:25 6420753415704873062:26
1 0 12485775574321252452:0 132683728328325035:1 14974255340142203411:2 13377067912027368632:3 716915617347112283:4 10169647874801131836:5 17241709254077376921:6 9171950032060297506:7 16705280652459417397:8 10502870772583566854:9 17676350714988466998:10 80880752506730415:11 10485267817975729682:12 16717872495103086821:13 17063534181803794493:14 5046868444379245870:15 4891860215039680349:16 7214965342802508003:17 1270486826908984041:18 14410197339552347946:19 8243359970626135167:20 4135348783020685250:21 17241709254077376921:22 11162666878533603762:23 15528981002398622203:24 11407693399809036763:25 9289715309199872261:26
1 0 13237225503670494420:0 5323223840226363228:1 2466867873114963287:2 12508842808485958116:3 13294771143862183618:4 15218982276382079900:5 11163313789190369446:6 5758609254184218890:7 17800761078682202115:8 5275575326790214142:9 7028886165996453002:10 4783829069681126648:11 8627622133409266852:12 6352573541654064750:13 14643263989734319679:14 15151267823035334295:15 4063389965279697996:16 304257334858494316:17 11462684987225336497:18 6674055552811657342:19 8243359970626135167:20 7622620960530016907:21 17241709254077376921:22 9596905073876765726:23 10578268012249422077:24 1212354230547063649:25 9906784755286772302:26
1 0 7674613650421074157:0 132683728328325035:1 18118575695108702441:2 17870723487728888346:3 6051353402763117205:4 15218982276382079900:5 11163313789190369446:6 2657982605007273743:7 16705280652459417397:8 10502870772583566854:9 801225010036599221:10 13389528138579273588:11 9444119813502811919:12 16584709323650129467:13 14643263989734319679:14 17699869981965015733:15 9689085085025960584:16 1187841073466173462:17 6143817112501550397:18 10981353452324818237:19 8243359970626135167:20 4306915228772435959:21 17241709254077376921:22 14895502180141653390:23 15365807293045474131:24 16289510092137203187:25 6215821982819220266:26
1 0 17241709254077376921:0 2725392301144350401:1 11806389861194829656:2 10047289093984926440:3 8904989556311027751:4 15218982276382079900:5 8545055878216481300:6 2264132778128398737:7 991491529160202440:8 5275575326790214142:9 9116963774439914137:10 4066270391623260703:11 10053031071814030523:12 15706636664096529694:13 17063534181803794493:14 10112199529490531606:15 15203515116826900154:16 14420458785251292117:17 8426463912967849489:18 17241709254077376921:19 17241709254077376921:20 14140506767829083971:21 17241709254077376921:22 10610591363390850070:23 3767297468498765274:24
1 0 17241709254077376921:0 6718470718629228516:1 11725014094608043127:2 7180501115911047871:3 50577678532249152:4 15218982276382079900:5 11163313789190369446:6 1297539762829889239:7 16705280652459417397:8 5275575326790214142:9 13696153240998294823:10 14315004402354702865:11 728623140706371361:12 15472813378402936260:13 14643263989734319679:14 8715524256750344983:15 11741677503292249699:16 12702162550489317753:17 6489109027974645363:18 6674055552811657342:19 17448608490400648307:20 10461271632826393502:21 17241709254077376921:22 14895502180141653390:23 11343452967512485516:24 9026989529823845647:25 18411746252820545969:26
1 0 13502581747159608329:0 132683728328325035:1 17402298575104256725:2 1199794993295631561:3 16727454980856778451:4 7239340616520487435:5 11163313789190369446:6 11894650094606280030:7 5309180186429543442:8 10502870772583566854:9 9116963774439914137:10 13096552226142886957:11 14450942906612809792:12 1589578729598937869:13 17995078462363758872:14 14677332338842706407:15 9971292664384749376:16 304257334858494316:17 6442100751087523915:18 6674055552811657342:19 17448608490400648307:20 9526599691994542147:21 17241709254077376921:22 11162666878533603762:23 3044705928769459271:24 9026989529823845647:25 9758373975411238298:26
1 1 7674613650421074157:0 132683728328325035:1 7761720401600392176:2 1292685001554764182:3 14796365443935494402:4 15218982276382079900:5 11163313789190369446:6 3456464600341375816:7 16705280652459417397:8 5275575326790214142:9 6352440304741952019:10 6661130404281083290:11 8107169145060874815:12 6440170955840433752:13 7830116631536757802:14 5291175334204734932:15 15442972206696868777:16 304257334858494316:17 11710860182646955307:18 9516923928322464298:19 17448608490400648307:20 8473700175986405275:21 17241709254077376921:22 9596905073876765726:23 5075464188083089464:24 3613283134603402626:25 3907931301678453009:26
1 0 12485775574321252452:0 132683728328325035:1 1576968520803882157:2 17241709254077376921:3 17241709254077376921:4 15218982276382079900:5 9630582567144824550:6 9510110403709908673:7 4213013683184994876:8 10502870772583566854:9 14213800323646090430:10 11854946685387400574:11 17241709254077376921:12 2642876139876797206:13 14643263989734319679:14 7833066576263021265:15 17241709254077376921:16 1187841073466173462:17 11362728554186900248:18 17241709254077376921:19 17241709254077376921:20 17241709254077376921:21 17241709254077376921:22 9596905073876765726:23
1 1 2744517546871237796:0 132683728328325035:1 14974255340142203411:2 5280162267361520113:3 10835326980553883460:4 15218982276382079900:5 9630582567144824550:6 14378129877604253715:7 7983294729707680427:8 10502870772583566854:9 17662846678829858094:10 3635099069814814390:11 1930175532629274928:12 10640210903656608664:13 14643263989734319679:14 4151041093059368577:15 15656625461489990278:16 304257334858494316:17 1270486826908984041:18 11947010392505993133:19 17448608490400648307:20 6870538487473709226:21 17241709254077376921:22 9596905073876765726:23 17414791962410575054:24 3613283134603402626:25 7178132097474487233:26
1 0 17241709254077376921:0 6718470718629228516:1 13269072425766530826:2 1395163352158263842:3 14648424205675448851:4 15218982276382079900:5 11163313789190369446:6 5658718796175039254:7 16341758872098761751:8 10502870772583566854:9 9116963774439914137:10 8182142699941220847:11 7646715363715996367:12 4121498275813634865:13 17063534181803794493:14 5487039979342708444:15 506441678635694603:16 304257334858494316:17 11487055308647903360:18 6674055552811657342:19 17448608490400648307:20 2203634787932175703:21 17241709254077376921:22 11162666878533603762:23 17414791962410575054:24 3613283134603402626:25 7140162492810714387:26
1 0 6927017134761466251:0 7324272953288436219:1 7756736608808612461:2 9071747527450988064:3 16847758086157631864:4 15218982276382079900:5 9630582567144824550:6 6937632795904720388:7 991491529160202440:8 10502870772583566854:9 9116963774439914137:10 4191138115126463527:11 6631179764405548968:12 10850130783794118172:13 14643263989734319679:14 12563625388453916341:15 14590181483463994230:16 6932058406762394060:17 11266289668075112357:18 6674055552811657342:19 8243359970626135167:20 15803635232853491676:21 17241709254077376921:22 11162666878533603762:23 14582518184021979285:24 3613283134603402626:25 15171962259945101721:26
1 0 7674613650421074157:0 8307575886820000061:1 6832149244291977250:2 4828044233854946899:3 6231861218167722999:4 15218982276382079900:5 11163313789190369446:6 1164950462972037251:7 16705280652459417397:8 10502870772583566854:9 624423715505587893:10 12718524099270024168:11 16075274640427798475:12 10781054518172359479:13 14643263989734319679:14 502422259278661079:15 6389945652329230419:16 12702162550489317753:17 16082873749429812321:18 2831866874659088171:19 13903136866082777265:20 3641918716505547940:21 5666677101597231609:22 14895502180141653390:23 9449052154607698195:24 9026989529823845647:25 13137340396808512530:26
1 0 16165765826633870759:0 132683728328325035:1 1778885384708968565:2 10047289093984926440:3 8904989556311027751:4 15218982276382079900:5 11163313789190369446:6 13618674763255378568:7 16705280652459417397:8 10502870772583566854:9 13641010552752080966:10 13771837509339570707:11 10053031071814030523:12 17578796369335553211:13 14643263989734319679:14 5967065745499582085:15 15203515116826900154:16 1187841073466173462:17 16962405167368546489:18 17241709254077376921:19 17241709254077376921:20 14140506767829083971:21 17241709254077376921:22 3737242667984714764:23 3767297468498765274:24
1 0 2744517546871237796:0 17433040772822544485:1 2466867873114963287:2 4696662055267481940:3 6914357846170958885:4 17756465370064782659:5 12219910503415112001:6 1517397597806723283:7 991491529160202440:8 10502870772583566854:9 12685532390119019197:10 6118978426529077903:11 10188272821748722262:12 15060520146375100587:13 17063534181803794493:14 672067804737030601:15 16381144673291763394:16 304257334858494316:17 4457562282959834066:18 6674055552811657342:19 13903136866082777265:20 18317918161877220099:21 17241709254077376921:22 11162666878533603762:23 15415232719988304698:24 1212354230547063649:25 12437855719361950508:26
1 0 10464417414901951369:0 132683728328325035:1 2568470288720291233:2 7353149597890168493:3 3415974251850056442:4 14669113407484985090:5 11163313789190369446:6 16928786756096626718:7 15468584758257870698:8 10502870772583566854:9 18351367845515181951:10 13161858962265644485:11 1026205338118059637:12 2114436741547958504:13 17995078462363758872:14 13588026454452555230:15 10152652251931920111:16 1187841073466173462:17 11252861524791023509:18 7034290778595812200:19 13903136866082777265:20 8400999747568180310:21 17241709254077376921:22 9419421512119490042:23 6027051460244190386:24 3613283134603402626:25 12018654587113426299:26
1 1 13237225503670494420:0 132683728328325035:1 5932022704695318284:2 15338726294620142906:3 7008849814068303796:4 1270111884358453186:5 12219910503415112001:6 3364076609796475041:7 991491529160202440:8 10502870772583566854:9 4645044546999593874:10 16112702416248776197:11 16949756502384858239:12 12027372293967910024:13 17063534181803794493:14 3502613326304026218:15 15387726488145974818:16 304257334858494316:17 5307420297479553628:18 17241709254077376921:19 17241709254077376921:20 10992697529523616075:21 5666677101597231609:22 9596905073876765726:23 45394345549210920:24
1 0 6927017134761466251:0 6718470718629228516:1 11725014094608043127:2 7761350506110750551:3 13869542625789249208:4 17756465370064782659:5 9630582567144824550:6 6879105878256856368:7 15351441355156184373:8 10502870772583566854:9 3707395226754083209:10 3015442190685524539:11 13283098451516033670:12 3580010520686773783:13 17063534181803794493:14 15130080775503074076:15 4102433882877379022:16 12702162550489317753:17 6489109027974645363:18 6522591285950556830:19 17448608490400648307:20 11677689939317426763:21 17241709254077376921:22 11162666878533603762:23 16905424653322530816:24 9026989529823845647:25 11938823204540837359:26
1 0 17241709254077376921:0 17433040772822544485:1 13638147752706036569:2 3074368415590455844:3 8904989556311027751:4 15218982276382079900:5 8545055878216481300:6 12666300008347941267:7 16705280652459417397:8 5275575326790214142:9 6004785798427717350:10 9529269963964830945:11 5461414925766068262:12 7896428522860688413:13 10635807090093424908:14 3922542365398847669:15 1101066663604879927:16 7214965342802508003:17 523783748084120554:18 17241709254077376921:19 17241709254077376921:20 16228061434981101242:21 17241709254077376921:22 9596905073876765726:23 3767297468498765274:24
1 1 2744517546871237796:0 132683728328325035:1 9179429492816205016:2 13676622477856975702:3 3286191063564561647:4 15218982276382079900:5 17241709254077376921:6 8271641783481038513:7 16705280652459417397:8 10502870772583566854:9 11504631205878159170:10 10905155235958484624:11 4266371886186239285:12 18211955286933215227:13 17063534181803794493:14 4354228603469696964:15 12148918327299807724:16 7214965342802508003:17 673372825355324337:18 6674055552811657342:19 17448608490400648307:20 3349135020277955702:21 17241709254077376921:22 11162666878533603762:23 11768418306406963895:24 9026989529823845647:25 18046364706790889106:26
1 0 6927017134761466251:0 1399035476613128213:1 2302007180625858651:2 17241709254077376921:3 17241709254077376921:4 15218982276382079900:5 11163313789190369446:6 17628281450774980356:7 118720139541262076:8 5275575326790214142:9 9116963774439914137:10 15286906736036235427:11 17241709254077376921:12 12474407437585636151:13 14643263989734319679:14 13411286546173046030:15 17241709254077376921:16 14420458785251292117:17 3564255790878271039:18 17241709254077376921:19 17241709254077376921:20 17241709254077376921:21 5666677101597231609:22 11162666878533603762:23
1 0 1750302349509622455:0 556544228763852288:1 2302007180625858651:2 5222147763739822057:3 11160309835392871911:4 14669113407484985090:5 8545055878216481300:6 158843167301945739:7 16705280652459417397:8 10502870772583566854:9 13820913050860618742:10 15890621597037366531:11 7540237752362850982:12 15835536966732180213:13 17063534181803794493:14 12262937348670547054:15 13470973610771554304:16 5923634413866883174:17 11942720253262047320:18 17241709254077376921:19 17241709254077376921:20 13273297550853785901:21 17241709254077376921:22 11162666878533603762:23 8239366509781549266:24
1 1 16720874773084141888:0 132683728328325035:1 11610205181468921922:2 14815259582660166791:3 7741748769461086:4 7239340616520487435:5 11163313789190369446:6 1024676000316375047:7 16705280652459417397:8 10502870772583566854:9 16615750646632226979:10 8918896465005633300:11 15711120967935245452:12 10101989200715543075:13 17995078462363758872:14 14901153342134929630:15 7651583244965785325:16 5923634413866883174:17 10571811563118485420:18 7107665592721051702:19 13903136866082777265:20 6953765994808807944:21 17241709254077376921:22 9419421512119490042:23 5075464188083089464:24 13073481964273803881:25 6420753415704873062:26
1 0 7919287270473417401:0 132683728328325035:1 6907281343774280101:2 14597193782547881073:3 16594469583671977279:4 15218982276382079900:5 17241709254077376921:6 13829687067688901029:7 991491529160202440:8 10502870772583566854:9 2874105284374992107:10 14025102470145611417:11 15971037547368253528:12 12209057626933818569:13 17063534181803794493:14 6383130323232768411:15 17782866767648588701:16 304257334858494316:17 6547881841675310326:18 17241709254077376921:19 17241709254077376921:20 8135927885760076416:21 17241709254077376921:22 11162666878533603762:23 2496960796842971748:24
1 0 17241709254077376921:0 132683728328325035:1 13638147752706036569:2 3074368415590455844:3 8904989556311027751:4 17756465370064782659:5 12219910503415112001:6 18102164505069627973:7 118720139541262076:8 10502870772583566854:9 9116963774439914137:10 3545838982158047583:11 5461414925766068262:12 5020602360612712927:13 10635807090093424908:14 3922542365398847669:15 1101066663604879927:16 11455583154613207504:17 523783748084120554:18 17241709254077376921:19 17241709254077376921:20 16228061434981101242:21 17241709254077376921:22 9596905073876765726:23 3767297468498765274:24
1 0 13237225503670494420:0 6718470718629228516:1 1107762186306793885:2 10272705063907639836:3 15294713434719486333:4 7239340616520487435:5 8545055878216481300:6 2525361608634214349:7 16705280652459417397:8 10502870772583566854:9 7668041901685895197:10 14711812896288403100:11 13727223093358058013:12 14541195072869641051:13 10635807090093424908:14 2312215631457552335:15 15975511992187702157:16 1187841073466173462:17 14430508837400541970:18 17241709254077376921:19 17241709254077376921:20 12089347766744514758:21 17241709254077376921:22 9516923928322464298:23 9008292542607610184:24
1 0 7257727411320405062:0 2725392301144350401:1 17142147528445973487:2 16106155864716345900:3 3107479524066090589:4 15218982276382079900:5 11163313789190369446:6 13402960549627629483:7 16705280652459417397:8 10502870772583566854:9 7540202334272243846:10 10725535261626137590:11 18088433734111540314:12 17128735678207281795:13 10635807090093424908:14 16673262170570482650:15 16045358100534419239:16 304257334858494316:17 12990093021150865413:18 15764142131713189694:19 17448608490400648307:20 2654336549919000075:21 5666677101597231609:22 11162666878533603762:23 16974399985483225991:24 1212354230547063649:25 6316577074117164822:26
1 0 10464417414901951369:0 132683728328325035:1 18118575695108702441:2 1956175051945281541:3 5033632780235688047:4 7239340616520487435:5 11163313789190369446:6 1097546976239385393:7 4138847090351627078:8 10502870772583566854:9 5086843973960666202:10 4850247641092899286:11 10225428296035378596:12 11699327217983376859:13 17995078462363758872:14 733372832589336138:15 11997318947514300189:16 11990012572963238042:17 6143817112501550397:18 6674055552811657342:19 13903136866082777265:20 5195076967538993364:21 17241709254077376921:22 2889020552648910850:23 11311118934595296456:24 16289510092137203187:25 13723928875114193756:26
1 0 17241709254077376921:0 132683728328325035:1 7761720401600392176:2 15806312004458499178:3 3833211328834912524:4 14669113407484985090:5 8545055878216481300:6 5780088464155013567:7 11053760986033849339:8 10502870772583566854:9 13463820798879422386:10 7214577557421996743:11 3713811935587769057:12 8598220869698531116:13 14643263989734319679:14 17417746869860111491:15 10671158401465245444:16 12702162550489317753:17 11710860182646955307:18 8807673727521545548:19 13903136866082777265:20 10652030633986194442:21 17241709254077376921:22 11162666878533603762:23 17796640343097536367:24 13073481964273803881:25 14408626082386998136:26
1 0 5424679272531918615:0 132683728328325035:1 2466867873114963287:2 4909779727030499274:3 7825834245353241169:4 15218982276382079900:5 16604931673559730414:6 2090573799971559719:7 16705280652459417397:8 10502870772583566854:9 9116963774439914137:10 14718017702897407632:11 15564585302896094665:12 2492063417888556224:13 14643263989734319679:14 15151267823035334295:15 2476910834974969203:16 304257334858494316:17 11462684987225336497:18 6674055552811657342:19 8243359970626135167:20 12443816753509496829:21 17241709254077376921:22 11162666878533603762:23 12296019248434685433:24 1212354230547063649:25 14516232280245646272:26
1 1 7148434200721666028:0 132683728328325035:1 7761720401600392176:2 6478641606093460331:3 13354423438281543465:4 15218982276382079900:5 11163313789190369446:6 8745984515037464789:7 991491529160202440:8 10502870772583566854:9 10132068100858439007:10 6661130404281083290:11 6614533895548380348:12 6440170955840433752:13 14643263989734319679:14 17417746869860111491:15 16668761583331094378:16 304257334858494316:17 11710860182646955307:18 4125162040286893714:19 13903136866082777265:20 2610767721428036499:21 17241709254077376921:22 9596905073876765726:23 5075464188083089464:24 3613283134603402626:25 6420753415704873062:26
1 1 2744517546871237796:0 132683728328325035:1 10198864999521895765:2 14283694510759628225:3 2475795949097338748:4 15218982276382079900:5 17241709254077376921:6 8182508895590474658:7 11053760986033849339:8 10502870772583566854:9 1703925832953300463:10 7784648955879333569:11 15859859550692373464:12 9957688304180513910:13 14643263989734319679:14 16208220921135040219:15 12721390130629769734:16 11455583154613207504:17 1546438911232186867:18 17241709254077376921:19 17241709254077376921:20 1022042687804050137:21 17241709254077376921:22 11162666878533603762:23 3119876655139837962:24
1 0 17181926294437511708:0 7324272953288436219:1 2302007180625858651:2 17241709254077376921:3 17241709254077376921:4 15218982276382079900:5 17241709254077376921:6 7815158906760658264:7 16705280652459417397:8 10502870772583566854:9 12135733045742782117:10 10172095931249584156:11 17241709254077376921:12 6750732004941059120:13 14643263989734319679:14 10773596562833364693:15 17241709254077376921:16 304257334858494316:17 4986364358089708342:18 17241709254077376921:19 17241709254077376921:20 17241709254077376921:21 17241709254077376921:22 11162666878533603762:23
1 0 1884361412985708340:0 1399035476613128213:1 7761720401600392176:2 8469104618800065557:3 14648424205675448851:4 7239340616520487435:5 17241709254077376921:6 16447247161022698326:7 991491529160202440:8 10502870772583566854:9 3041898498511578252:10 9023709591144843013:11 172138924868194437:12 15415852953478515155:13 10635807090093424908:14 16268454291327340268:15 883905295314056489:16 7214965342802508003:17 8117304531237350068:18 8819009507283715567:19 17448608490400648307:20 4574862061147892267:21 17241709254077376921:22 11162666878533603762:23 17414791962410575054:24 3613283134603402626:25 18333160135461364208:26
1 1 5841576283076759122:0 6718470718629228516:1 13736117138133016446:2 1529185287032455422:3 10289645275367710598:4 15218982276382079900:5 12219910503415112001:6 476551412373857478:7 16705280652459417397:8 10502870772583566854:9 7709944093920699848:10 6625192222420878491:11 8367636140724141923:12 2576394315108315074:13 14643263989734319679:14 4847192240487161615:15 11752122932856338617:16 304257334858494316:17 15841159443225760662:18 1450301568544842084:19 17448608490400648307:20 3310681076380009974:21 17241709254077376921:22 14895502180141653390:23 16227083810990001366:24 1212354230547063649:25 6046005918922891339:26
1 0 17241709254077376921:0 6718470718629228516:1 13638147752706036569:2 3074368415590455844:3 8904989556311027751:4 15218982276382079900:5 12219910503415112001:6 14114057567039215395:7 16705280652459417397:8 10502870772583566854:9 16041267730365020418:10 13215171499502271015:11 5461414925766068262:12 16759783342728243176:13 17995078462363758872:14 15896137188699604196:15 1101066663604879927:16 5923634413866883174:17 13293834139238633019:18 17241709254077376921:19 17241709254077376921:20 16228061434981101242:21 17241709254077376921:22 2889020552648910850:23 3767297468498765274:24
1 0 17241709254077376921:0 132683728328325035:1 13638147752706036569:2 3074368415590455844:3 8904989556311027751:4 14669113407484985090:5 11163313789190369446:6 12591978802007535941:7 16705280652459417397:8 5275575326790214142:9 13771838652852816030:10 8885450730259554296:11 5461414925766068262:12 15118869621319575296:13 10635807090093424908:14 3922542365398847669:15 1101066663604879927:16 304257334858494316:17 523783748084120554:18 17241709254077376921:19 17241709254077376921:20 16228061434981101242:21 14702504267520853429:22 9596905073876765726:23 3767297468498765274:24
1 0 2489716146917121730:0 132683728328325035:1 12875455536576904474:2 12861242875098225016:3 5455576107295117382:4 15218982276382079900:5 11163313789190369446:6 13498795872817025468:7 16705280652459417397:8 10502870772583566854:9 4416853476367033701:10 17256037306092196196:11 1551193749783651897:12 16821634134493805625:13 14643263989734319679:14 1565199297719275733:15 6489730728852370287:16 304257334858494316:17 6702151720359481043:18 6674055552811657342:19 17448608490400648307:20 5381079020795095159:21 17241709254077376921:22 11162666878533603762:23 2407064251793561829:24 4164242000176313026:25 18352595854979698789:26
1 0 17241709254077376921:0 132683728328325035:1 13269072425766530826:2 8469104618800065557:3 14648424205675448851:4 14669113407484985090:5 8545055878216481300:6 10446853368944622849:7 16705280652459417397:8 10502870772583566854:9 9116963774439914137:10 14153401105953999066:11 172138924868194437:12 6020000510654702509:13 17995078462363758872:14 9391627788929346347:15 883905295314056489:16 7214965342802508003:17 11487055308647903360:18 6674055552811657342:19 17448608490400648307:20 4574862061147892267:21 17241709254077376921:22 9596905073876765726:23 17414791962410575054:24 3613283134603402626:25 7953251115798210533:26
1 0 13237225503670494420:0 132683728328325035:1 2302007180625858651:2 12427473243524142178:3 3789112372305922230:4 7239340616520487435:5 11163313789190369446:6 3075631905248506434:7 991491529160202440:8 5275575326790214142:9 2325886750190784890:10 3557854724473529018:11 17920882885284333207:12 10123798490811782077:13 17995078462363758872:14 11153225875822172166:15 4852996870923404678:16 7214965342802508003:17 10783949422666782912:18 17241709254077376921:19 17241709254077376921:20 17321253496113904093:21 17241709254077376921:22 2889020552648910850:23 2078387580204111440:24
1 0 7674613650421074157:0 132683728328325035:1 15330267725134755020:2 9452782523589518213:3 1725984468018631238:4 15218982276382079900:5 11163313789190369446:6 7207525335161733398:7 11053760986033849339:8 10502870772583566854:9 9579728145720788731:10 9676201557854305978:11 4731896413009015131:12 17905522760209459181:13 17063534181803794493:14 15285744035704368662:15 2265596674932911774:16 304257334858494316:17 1819108601587180398:18 5421479283559898697:19 8243359970626135167:20 13861143137683308479:21 17241709254077376921:22 14895502180141653390:23 5075464188083089464:24 9026989529823845647:25 6420753415704873062:26
1 0 13237225503670494420:0 132683728328325035:1 7761720401600392176:2 21002485849992795:3 336066712337470945:4 15218982276382079900:5 12219910503415112001:6 11866590129284196737:7 16705280652459417397:8 10502870772583566854:9 15238859373895068969:10 6231104288589860189:11 4018849280330685703:12 7518366351727709627:13 14643263989734319679:14 17417746869860111491:15 11704298043170297190:16 1187841073466173462:17 11710860182646955307:18 15858993896876398499:19 8243359970626135167:20 921766065305888747:21 17241709254077376921:22 9596905073876765726:23 17414791962410575054:24 3613283134603402626:25 6094626736077278091:26
1 0 13237225503670494420:0 2725392301144350401:1 600209798659007675:2 12315698492775170686:3 15406357556071787535:4 15218982276382079900:5 11163313789190369446:6 16783842240295458777:7 11053760986033849339:8 10502870772583566854:9 14213800323646090430:10 7853636003697589375:11 4009361900010953351:12 11227204779996682625:13 674564578780542685:14 4933751362251299983:15 14454615856887199705:16 12702162550489317753:17 15427010206990513389:18 17241709254077376921:19 17241709254077376921:20 2511008134917666536:21 17241709254077376921:22 9596905073876765726:23 10985039445557659498:24
1 0 6927017134761466251:0 132683728328325035:1 7761720401600392176:2 15524966656850654451:3 10182599171524437980:4 14669113407484985090:5 17241709254077376921:6 6024319228525808624:7 16705280652459417397:8 10502870772583566854:9 10490984741403024606:10 7686854714387873540:11 6064609207185952215:12 14643529896603192270:13 17063534181803794493:14 2639330246974301517:15 16974669170000599636:16 304257334858494316:17 11710860182646955307:18 6674055552811657342:19 8243359970626135167:20 5135288735729027677:21 17241709254077376921:22 11162666878533603762:23 12286428220600479687:24 3613283134603402626:25 88402684023886513:26
// 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 <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstdlib>
#include <fstream>
#include <sstream>
#include <string>
#include <thread> // NOLINT
#include "elastic-ctr/client/api/elastic_ctr_api.h"
using baidu::paddle_serving::elastic_ctr::ElasticCTRPredictorApi;
using baidu::paddle_serving::elastic_ctr::Prediction;
DEFINE_int32(batch_size, 10, "Infernce batch_size");
DEFINE_string(test_file, "", "test file");
const int VARIABLE_NAME_LEN = 256;
const int CTR_EMBEDDING_TABLE_SIZE = 100000001;
struct Sample {
std::map<std::string, std::vector<uint64_t>> slots;
};
std::vector<Sample> samples;
int read_samples(const char* file) {
std::ifstream fs(file);
for (std::string line; std::getline(fs, line);) {
std::vector<std::string> tokens;
std::stringstream ss(line);
std::string token;
Sample sample;
while (std::getline(ss, token, ' ')) {
tokens.push_back(token);
}
if (tokens.size() <= 3) {
continue;
}
for (std::size_t i = 2; i < tokens.size(); ++i) {
std::size_t pos = tokens[i].find(':');
if (pos == std::string::npos) {
continue;
}
uint64_t x = std::strtoull(tokens[i].substr(0, pos).c_str(), NULL, 10);
std::string slot_name = tokens[i].substr(pos + 1);
if (sample.slots.find(slot_name) == sample.slots.end()) {
std::vector<uint64_t> values;
values.push_back(x % CTR_EMBEDDING_TABLE_SIZE);
sample.slots[slot_name] = values;
} else {
auto it = sample.slots.find(slot_name);
it->second.push_back(x);
}
}
samples.push_back(sample);
}
LOG(INFO) << "Samples size = " << samples.size();
#if 1
for (std::size_t i = 0; i < samples.size(); ++i) {
LOG(INFO) << "=============Sample " << i << "=========";
for (auto slot : samples[i].slots) {
LOG(INFO) << "slot_name: " << slot.first.c_str();
for (auto x : slot.second) {
LOG(INFO) << x;
}
}
LOG(INFO) << "========================================";
}
#endif
return 0;
}
int main(int argc, char** argv) {
google::ParseCommandLineFlags(&argc, &argv, true);
ElasticCTRPredictorApi api;
#ifdef BCLOUD
logging::LoggingSettings settings;
settings.logging_dest = logging::LOG_TO_FILE;
std::string log_filename(argv[0]);
log_filename = log_filename.substr(log_filename.find_last_of('/') + 1);
settings.log_file = (std::string("./log/") + log_filename + ".log").c_str();
settings.delete_old = logging::DELETE_OLD_LOG_FILE;
logging::InitLogging(settings);
logging::ComlogSinkOptions cso;
cso.process_name = log_filename;
cso.enable_wf_device = true;
logging::ComlogSink::GetInstance()->Setup(&cso);
#else
struct stat st_buf;
int ret = 0;
if ((ret = stat("./log", &st_buf)) != 0) {
mkdir("./log", 0777);
ret = stat("./log", &st_buf);
if (ret != 0) {
LOG(WARNING) << "Log path ./log not exist, and create fail";
return -1;
}
}
FLAGS_log_dir = "./log";
google::InitGoogleLogging(strdup(argv[0]));
FLAGS_logbufsecs = 0;
FLAGS_logbuflevel = -1;
#endif
// predictor conf
if (api.init("./conf", "slot.conf", "predictors.prototxt") != 0) {
LOG(ERROR) << "Failed create predictors api!";
return -1;
}
api.thrd_initialize();
ret = read_samples(FLAGS_test_file.c_str());
std::size_t index = 0;
while (index < samples.size()) {
api.thrd_clear();
for (int i = 0; i < FLAGS_batch_size && index < samples.size(); ++i) {
ReqInstance* ins = api.add_instance();
if (!ins) {
LOG(ERROR) << "Failed create req instance";
return -1;
}
for (auto slot : samples[index].slots) {
for (auto x : slot.second) {
api.add_slot(ins, slot.first.c_str(), x);
}
}
++index;
}
std::vector<std::vector<float>> results_vec;
if (api.inference(results_vec) != 0) {
LOG(ERROR) << "failed call predictor";
return -1;
}
#if 1
for (std::size_t i = 0; i < results_vec.size(); ++i) {
LOG(INFO) << "sample " << i << ": [" << results_vec[i].at(0) << ", "
<< results_vec[i].at(1) << "]";
}
#endif
} // end while
api.thrd_finalize();
api.destroy();
return 0;
}
# 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.
from __future__ import print_function
import json
import sys
import os
from elastic_ctr_api import ElasticCTRAPI
BATCH_SIZE = 3
SERVING_IP = "127.0.0.1"
SLOT_CONF_FILE = "./conf/slot.conf"
CTR_EMBEDDING_TABLE_SIZE = 100000001
SLOTS = []
def str2long(str):
if sys.version_info[0] == 2:
return long(str)
elif sys.version_info[0] == 3:
return int(str)
def data_reader(data_file, samples, labels):
if not os.path.exists(data_file):
print("Path %s not exist" % data_file)
return -1
with open(data_file, "r") as f:
for line in f:
sample = {}
line = line.rstrip('\n')
feature_slots = line.split(' ')
labels.append(int(feature_slots[1]))
feature_slots = feature_slots[2:]
feature_slot_maps = [x.split(':') for x in feature_slots]
features = [x[0] for x in feature_slot_maps]
slots = [x[1] for x in feature_slot_maps]
for i in range(0, len(features)):
if slots[i] in sample:
sample[slots[i]] = [
sample[slots[i]] + str2long(features[i]) %
CTR_EMBEDDING_TABLE_SIZE
]
else:
sample[slots[i]] = [
str2long(features[i]) % CTR_EMBEDDING_TABLE_SIZE
]
for x in SLOTS:
if not x in sample:
sample[x] = [0]
samples.append(sample)
if __name__ == "__main__":
""" main
"""
if len(sys.argv) != 5:
print(
"Usage: python elastic_ctr.py SERVING_IP SERVING_PORT SLOT_CONF_FILE DATA_FILE"
)
sys.exit(-1)
samples = []
labels = []
SERVING_IP = sys.argv[1]
SERVING_PORT = sys.argv[2]
SLOT_CONF_FILE = sys.argv[3]
api = ElasticCTRAPI(SERVING_IP, SERVING_PORT)
ret = api.read_slots_conf(SLOT_CONF_FILE)
if ret != 0:
sys.exit(-1)
ret = data_reader(sys.argv[4], samples, labels)
correct = 0
for i in range(0, len(samples) - BATCH_SIZE, BATCH_SIZE):
api.clear()
batch = samples[i:i + BATCH_SIZE]
instances = []
for sample in batch:
instance = api.add_instance()
if sys.version_info[0] == 2:
for k, v in sample.iteritems():
api.add_slot(instance, k, v)
elif sys.version_info[0] == 3:
for k, v in sample.items():
api.add_slot(instance, k, v)
ret = api.inference()
ret = json.loads(ret)
predictions = ret["predictions"]
idx = 0
for x in predictions:
if x["prob0"] >= x["prob1"]:
pred = 0
else:
pred = 1
if labels[i + idx] == pred:
correct += 1
else:
print("id=%d predict incorrect: pred=%d label=%d (%f %f)" %
(i + idx, pred, labels[i + idx], x["prob0"], x["prob1"]))
idx = idx + 1
print("Acc=%f" % (float(correct) / len(samples)))
FILE(GLOB protos ${CMAKE_CURRENT_LIST_DIR}/*.proto)
list(APPEND protos ${CMAKE_SOURCE_DIR}/predictor/proto/pds_option.proto
${CMAKE_SOURCE_DIR}/predictor/proto/builtin_format.proto)
PROTOBUF_GENERATE_SERVING_CPP(FALSE PROTO_SRCS PROTO_HDRS ${protos})
LIST(APPEND elastic_ctr_cpp_srcs ${PROTO_SRCS})
// 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.
syntax = "proto2";
import "pds_option.proto";
import "builtin_format.proto";
package baidu.paddle_serving.predictor.elastic_ctr;
option cc_generic_services = true;
message Slot {
required string slot_name = 1;
repeated int64 feasigns = 2;
};
message ReqInstance { repeated Slot slots = 1; };
message Request { repeated ReqInstance instances = 1; };
message ResInstance {
required float prob0 = 1;
required float prob1 = 2;
};
message Response {
repeated ResInstance predictions = 1;
required int64 err_code = 2;
optional string err_msg = 3;
};
service ElasticCTRPredictionService {
rpc inference(Request) returns (Response);
rpc debug(Request) returns (Response);
option (pds.options).generate_stub = true;
};
if (NOT EXISTS
${CMAKE_CURRENT_LIST_DIR}/data/model/paddle/fluid/ctr_prediction)
execute_process(COMMAND wget --no-check-certificate
https://paddle-serving.bj.bcebos.com/data/ctr_prediction/elastic_ctr_model.tar.gz
--output-document
${CMAKE_CURRENT_LIST_DIR}/data/model/paddle/fluid/elastic_ctr_model.tar.gz)
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf
"${CMAKE_CURRENT_LIST_DIR}/data/model/paddle/fluid/elastic_ctr_model.tar.gz"
WORKING_DIRECTORY
${CMAKE_CURRENT_LIST_DIR}/data/model/paddle/fluid)
execute_process(COMMAND ${CMAKE_COMMAND} -E rename inference_only ctr_prediction
WORKING_DIRECTORY
${CMAKE_CURRENT_LIST_DIR}/data/model/paddle/fluid)
endif()
include_directories(SYSTEM ${CMAKE_CURRENT_LIST_DIR}/../kvdb/include)
include(op/CMakeLists.txt)
include(proto/CMakeLists.txt)
add_executable(elastic_serving ${serving_srcs})
add_dependencies(elastic_serving pdcodegen fluid_cpu_engine pdserving paddle_fluid cube-api)
target_include_directories(elastic_serving PUBLIC
${CMAKE_CURRENT_BINARY_DIR}/../../predictor
)
target_link_libraries(elastic_serving -Wl,--whole-archive fluid_cpu_engine
-Wl,--no-whole-archive)
target_link_libraries(elastic_serving paddle_fluid ${paddle_depend_libs})
target_link_libraries(elastic_serving pdserving)
target_link_libraries(elastic_serving cube-api)
target_link_libraries(elastic_serving kvdb rocksdb)
target_link_libraries(elastic_serving -liomp5 -lmklml_intel -lmkldnn -lpthread
-lcrypto -lm -lrt -lssl -ldl -lz -lbz2)
install(TARGETS elastic_serving
RUNTIME DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/elastic_ctr/serving/bin)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/conf DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/elastic_ctr/serving/)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/data DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/elastic_ctr/serving/)
FILE(GLOB inc ${CMAKE_CURRENT_BINARY_DIR}/*.pb.h)
install(FILES ${inc}
DESTINATION ${PADDLE_SERVING_INSTALL_DIR}/include/serving)
if (${WITH_MKL})
install(FILES
${CMAKE_BINARY_DIR}/third_party/install/Paddle/third_party/install/mklml/lib/libmklml_intel.so
${CMAKE_BINARY_DIR}/third_party/install/Paddle/third_party/install/mklml/lib/libiomp5.so
${CMAKE_BINARY_DIR}/third_party/install/Paddle/third_party/install/mkldnn/lib/libmkldnn.so.0
DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/elastic_ctr/serving/bin)
endif()
[{
"dict_name": "test_dict",
"shard": 2,
"dup": 1,
"timeout": 200,
"retry": 3,
"backup_request": 100,
"type": "ipport_list",
"load_balancer": "rr",
"nodes": [{
"ipport_list": "list://xxx.xxx.xxx.xxx:8000"
},{
"ipport_list": "list://xxx.xxx.xxx.xxx:8000"
}]
}]
--enable_model_toolkit
--enable_cube=true
engines {
name: "elastic_ctr_prediction"
type: "FLUID_CPU_ANALYSIS_DIR"
reloadable_meta: "./data/model/paddle/fluid_time_file"
reloadable_type: "timestamp_ne"
model_data_path: "./data/model/paddle/fluid/ctr_prediction"
runtime_thread_num: 0
batch_infer_size: 0
enable_batch_align: 0
sparse_param_service_type: REMOTE
sparse_param_service_table_name: "test_dict"
}
model_toolkit_path: "./conf/"
model_toolkit_file: "model_toolkit.prototxt"
cube_config_file: "./conf/cube.conf"
services {
name: "ElasticCTRPredictionService"
workflows: "workflow1"
}
workflows {
name: "workflow1"
workflow_type: "Sequence"
nodes {
name: "elastic_ctr_prediction_op"
type: "ElasticCTRPredictionOp"
}
}
FILE(GLOB op_srcs ${CMAKE_CURRENT_LIST_DIR}/*.cpp)
LIST(APPEND serving_srcs ${op_srcs})
// 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 "elastic-ctr/serving/op/elastic_ctr_prediction_op.h"
#include <algorithm>
#include <string>
#include "cube/cube-api/include/cube_api.h"
#include "predictor/framework/infer.h"
#include "predictor/framework/kv_manager.h"
#include "predictor/framework/memory.h"
// Flag where enable profiling mode
DECLARE_bool(enable_ctr_profiling);
namespace baidu {
namespace paddle_serving {
namespace serving {
using baidu::paddle_serving::predictor::MempoolWrapper;
using baidu::paddle_serving::predictor::elastic_ctr::Slot;
using baidu::paddle_serving::predictor::elastic_ctr::ResInstance;
using baidu::paddle_serving::predictor::elastic_ctr::Response;
using baidu::paddle_serving::predictor::elastic_ctr::ReqInstance;
using baidu::paddle_serving::predictor::elastic_ctr::Request;
const int VARIABLE_NAME_LEN = 256;
const int CTR_PREDICTION_DENSE_DIM = 13;
const int CTR_PREDICTION_EMBEDDING_SIZE = 9;
bthread::Mutex ElasticCTRPredictionOp::mutex_;
int64_t ElasticCTRPredictionOp::cube_time_us_ = 0;
int32_t ElasticCTRPredictionOp::cube_req_num_ = 0;
int32_t ElasticCTRPredictionOp::cube_req_key_num_ = 0;
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;
}
int ElasticCTRPredictionOp::inference() {
const Request *req = dynamic_cast<const Request *>(get_request_message());
TensorVector *in = butil::get_object<TensorVector>();
Response *res = mutable_data<Response>();
uint32_t sample_size = req->instances_size();
if (sample_size <= 0) {
LOG(WARNING) << "No instances need to inference!";
fill_response_with_message(res, -1, "Sample size invalid");
return 0;
}
// Verify all request instances have same slots
int slot_num = req->instances(0).slots_size();
#if 1
LOG(INFO) << "slot_num =" << slot_num;
#endif
for (int i = 1; i < req->instances_size(); ++i) {
if (req->instances(i).slots_size() != slot_num) {
LOG(WARNING) << "Req " << i
<< " has different slot num with that of req 0";
fill_response_with_message(
res, -1, "Req intance has varying slot numbers");
}
}
// Query cube API for sparse embeddings
std::vector<uint64_t> keys;
std::vector<rec::mcube::CubeValue> values;
// How to organize feasigns in the above `keys` vector:
//
// Assuming N instances, each instance having M feature slots:
//
// ins1:
// slot_1: ins1_slot1_1|ins1_slot1_2 slot2: ins1_slot2_1|ins1_slot2_2
//
// ins2:
// slot_1: ins2_slot1_1 slot2: ins2_slot2_1|ins2_slot2_2
//
// ...
//
// insN:
// slot_1: insN_slot1_1|insN_slot1_2 slot2: insN_slot2_1
//
// We organize the features in such a way that all slot_1 features are before
// slot_2 features:
//
// ins1_slot1_1|ins1_slot1_2|ins2_slot1_1|...|insN_slot1_1|insN_slot1_2
// ins1_slot2_1|ins1_slot2_2|ins2_slot2_1|ins2_slot2_2|...|insN_slot2_1
//
// With this placement, after querying KV service, we can retrieve the
// embeddings for each feature slot from the returned `values` vector easily,
// as they are grouped togegher.
// Level of details of each feature slot
std::vector<std::vector<size_t>> feature_slot_lods;
feature_slot_lods.resize(slot_num);
// Number of feature signs in each slot
std::vector<int> feature_slot_sizes;
feature_slot_sizes.resize(slot_num);
// Iterate over each feature slot
for (int i = 0; i < slot_num; ++i) {
feature_slot_lods[i].push_back(0);
feature_slot_sizes[i] = 0;
// Extract feature i values from each instance si
for (int si = 0; si < sample_size; ++si) {
#if 1
LOG(INFO) << "slot " << i << " sample " << si;
#endif
const ReqInstance &req_instance = req->instances(si);
const Slot &slot = req_instance.slots(i);
feature_slot_lods[i].push_back(feature_slot_lods[i].back() +
slot.feasigns_size());
feature_slot_sizes[i] += slot.feasigns_size();
for (int j = 0; j < slot.feasigns_size(); ++j) {
keys.push_back(slot.feasigns(j));
}
}
}
#if 1
rec::mcube::CubeAPI *cube = rec::mcube::CubeAPI::instance();
predictor::KVManager &kv_manager = predictor::KVManager::instance();
const predictor::KVInfo *kvinfo =
kv_manager.get_kv_info(CTR_PREDICTION_MODEL_NAME);
if (kvinfo == NULL) {
LOG(ERROR) << "Sparse param service info not found for model "
<< CTR_PREDICTION_MODEL_NAME
<< ". Maybe forgot to specify sparse_param_service_type and "
<< "sparse_param_service_table_name in "
<< "conf/model_toolkit.prototxt";
fill_response_with_message(res, -1, "Sparse param service info not found");
return 0;
}
std::string table_name;
if (kvinfo->sparse_param_service_type != configure::EngineDesc::NONE) {
table_name = kvinfo->sparse_param_service_table_name;
if (table_name.empty()) {
LOG(ERROR) << "sparse_param_service_table_name not specified. "
<< "Please specify it in conf/model_toolkit.protxt for model "
<< CTR_PREDICTION_MODEL_NAME;
fill_response_with_message(
res, -1, "sparse_param_service_table_name not specified");
return 0;
}
}
if (kvinfo->sparse_param_service_type == configure::EngineDesc::LOCAL) {
// Query local KV service
LOG(ERROR) << "Local kv service not supported for model "
<< CTR_PREDICTION_MODEL_NAME;
fill_response_with_message(
res, -1, "Local kv service not supported for this model");
return 0;
} else if (kvinfo->sparse_param_service_type ==
configure::EngineDesc::REMOTE) {
struct timeval start;
struct timeval end;
int ret;
gettimeofday(&start, NULL);
ret = cube->seek(table_name, keys, &values);
gettimeofday(&end, NULL);
uint64_t usec =
end.tv_sec * 1e6 + end.tv_usec - start.tv_sec * 1e6 - start.tv_usec;
// Statistics
mutex_.lock();
cube_time_us_ += usec;
++cube_req_num_;
cube_req_key_num_ += keys.size();
if (cube_req_num_ >= 1000) {
LOG(INFO) << "Cube request count: " << cube_req_num_;
LOG(INFO) << "Cube request key count: " << cube_req_key_num_;
LOG(INFO) << "Cube request total time: " << cube_time_us_ << "us";
LOG(INFO) << "Average "
<< static_cast<float>(cube_time_us_) / cube_req_num_
<< "us/req";
LOG(INFO) << "Average "
<< static_cast<float>(cube_time_us_) / cube_req_key_num_
<< "us/key";
cube_time_us_ = 0;
cube_req_num_ = 0;
cube_req_key_num_ = 0;
}
mutex_.unlock();
// Statistics end
if (ret != 0) {
fill_response_with_message(res, -1, "Query cube for embeddings error");
LOG(ERROR) << "Query cube for embeddings error";
return 0;
}
}
if (values.size() != keys.size()) {
LOG(ERROR) << "Sparse embeddings not ready; "
<< "maybe forgot to set sparse_param_service_type and "
<< "sparse_param_sevice_table_name for "
<< CTR_PREDICTION_MODEL_NAME
<< " in conf/model_toolkit.prototxt";
fill_response_with_message(
res, -1, "Sparse param service not configured properly");
return 0;
}
for (int i = 0; i < keys.size(); ++i) {
std::ostringstream oss;
oss << keys[i] << ": ";
const char *value = (values[i].buff.data());
if (values[i].buff.size() !=
sizeof(float) * CTR_PREDICTION_EMBEDDING_SIZE) {
LOG(WARNING) << "Key " << keys[i] << " has values less than "
<< CTR_PREDICTION_EMBEDDING_SIZE;
}
#if 0
for (int j = 0; j < values[i].buff.size(); ++j) {
oss << std::hex << std::uppercase << std::setw(2) << std::setfill('0')
<< (static_cast<int>(value[j]) & 0xff);
}
LOG(INFO) << oss.str().c_str();
#endif
}
// Fill feature embedding into feed tensors
std::vector<paddle::PaddleTensor> lod_tensors;
lod_tensors.resize(slot_num);
const ReqInstance &instance = req->instances(0);
for (int i = 0; i < slot_num; ++i) {
paddle::PaddleTensor &lod_tensor = lod_tensors[i];
char name[VARIABLE_NAME_LEN];
snprintf(name,
VARIABLE_NAME_LEN,
"embedding_%s.tmp_0",
instance.slots(i).slot_name().c_str());
lod_tensor.name = std::string(name);
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);
}
int base = 0;
// Iterate over all slots
for (int i = 0; i < slot_num; ++i) {
paddle::PaddleTensor &lod_tensor = lod_tensors[i];
std::vector<std::vector<size_t>> &lod = lod_tensor.lod;
lod[0] = feature_slot_lods[i];
lod_tensor.shape = {lod[0].back(), CTR_PREDICTION_EMBEDDING_SIZE};
lod_tensor.data.Resize(lod[0].back() * sizeof(float) *
CTR_PREDICTION_EMBEDDING_SIZE);
int offset = 0;
// Copy all slot i feature embeddings to lod_tensor[i]
for (uint32_t j = 0; j < feature_slot_sizes[i]; ++j) {
float *data_ptr = static_cast<float *>(lod_tensor.data.data()) + offset;
int idx = base + j;
if (values[idx].buff.size() !=
sizeof(float) * CTR_PREDICTION_EMBEDDING_SIZE) {
#if 0
LOG(ERROR) << "Embedding vector size not expected";
fill_response_with_message(
res, -1, "Embedding vector size not expected");
return 0;
#else
// sizeof(float) * CTR_PREDICTION_EMBEDDING_SIZE = 36
values[idx].buff.append(36, '0');
#endif
}
memcpy(data_ptr, values[idx].buff.data(), values[idx].buff.size());
offset += CTR_PREDICTION_EMBEDDING_SIZE;
}
in->push_back(lod_tensor);
// Bump base counter
base += feature_slot_sizes[i];
}
#else
// Fill all tensors
std::vector<paddle::PaddleTensor> lod_tensors;
lod_tensors.resize(slot_num);
const ReqInstance &instance = req->instances(0);
for (int i = 0; i < slot_num; ++i) {
paddle::PaddleTensor &lod_tensor = lod_tensors[i];
lod_tensor.name = instance.slots(i).slot_name();
LOG(INFO) << "slot " << i << "name: " << lod_tensor.name.c_str();
lod_tensors[i].dtype = paddle::PaddleDType::INT64;
}
// Iterate over all slots
for (int i = 0; i < slot_num; ++i) {
paddle::PaddleTensor &lod_tensor = lod_tensors[i];
std::vector<std::vector<size_t>> &lod = lod_tensor.lod;
lod.push_back(feature_slot_lods[i]);
lod_tensor.shape = {lod[0].back(), 1};
lod_tensor.data.Resize(lod[0].back() * sizeof(uint64_t));
int offset = 0;
// Copy all slot i features to lod_tensor[i]
uint64_t *keys_block = keys.data();
uint64_t *data_ptr = static_cast<uint64_t *>(lod_tensor.data.data());
memcpy(data_ptr,
keys_block + offset,
feature_slot_sizes[i] * sizeof(uint64_t));
offset += feature_slot_sizes[i];
in->push_back(lod_tensor);
// Bump base counter
offset += feature_slot_sizes[i];
}
#endif
TensorVector *out = butil::get_object<TensorVector>();
if (!out) {
LOG(ERROR) << "Failed get tls output object";
fill_response_with_message(res, -1, "Failed get thread local resource");
return 0;
}
// call paddle fluid model for inference
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;
fill_response_with_message(res, -1, "Failed do infer in fluid model");
return 0;
}
if (out->size() != 1) {
LOG(ERROR) << "Model returned number of fetch tensor more than 1";
fill_response_with_message(
res, -1, "Model returned number of fetch tensor more than 1");
return 0;
}
int output_shape_dim = out->at(0).shape.size();
if (output_shape_dim != 2) {
LOG(ERROR) << "Fetch LoDTensor should be shape of [sample_size, 2]";
fill_response_with_message(
res, -1, "Fetch LoDTensor should be shape of [sample_size, 2]");
return 0;
}
if (out->at(0).dtype != paddle::PaddleDType::FLOAT32) {
LOG(ERROR) << "Fetch LoDTensor data type should be FLOAT32";
fill_response_with_message(
res, -1, "Fetch LoDTensor data type should be FLOAT32");
return 0;
}
int dim1 = out->at(0).shape[0];
int dim2 = out->at(0).shape[1];
if (dim1 != sample_size) {
LOG(ERROR) << "Returned result count not equal to sample_size";
fill_response_with_message(
res, -1, "Returned result count not equal to sample size");
return 0;
}
if (dim2 != 2) {
LOG(ERROR) << "Returned result is not expected, should be 2 floats for "
"each sample";
fill_response_with_message(
res, -1, "Retunred result is not 2 floats for each sample");
return 0;
}
float *data = static_cast<float *>(out->at(0).data.data());
for (int i = 0; i < dim1; ++i) {
ResInstance *res_instance = res->add_predictions();
res_instance->set_prob0(data[i * dim2]);
res_instance->set_prob1(data[i * 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);
res->set_err_code(0);
res->set_err_msg(std::string(""));
return 0;
}
DEFINE_OP(ElasticCTRPredictionOp);
} // namespace serving
} // namespace paddle_serving
} // namespace baidu
// 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.
#pragma once
#include <vector>
#ifdef BCLOUD
#ifdef WITH_GPU
#include "paddle/paddle_inference_api.h"
#else
#include "paddle/fluid/inference/api/paddle_inference_api.h"
#endif
#else
#include "paddle_inference_api.h" // NOLINT
#endif
#include "elastic-ctr/serving/elastic_ctr_prediction.pb.h"
namespace baidu {
namespace paddle_serving {
namespace serving {
static const char* CTR_PREDICTION_MODEL_NAME = "elastic_ctr_prediction";
/**
* ElasticCTRPredictionOp: Serve CTR prediction requests.
*
*/
class ElasticCTRPredictionOp
: public baidu::paddle_serving::predictor::OpWithChannel<
baidu::paddle_serving::predictor::elastic_ctr::Response> {
public:
typedef std::vector<paddle::PaddleTensor> TensorVector;
DECLARE_OP(ElasticCTRPredictionOp);
int inference();
private:
static bthread::Mutex mutex_;
static int64_t cube_time_us_;
static int32_t cube_req_num_;
static int32_t cube_req_key_num_;
};
} // namespace serving
} // namespace paddle_serving
} // namespace baidu
LIST(APPEND protofiles
${CMAKE_CURRENT_LIST_DIR}/elastic_ctr_prediction.proto
)
PROTOBUF_GENERATE_SERVING_CPP(TRUE PROTO_SRCS PROTO_HDRS ${protofiles})
LIST(APPEND serving_srcs ${PROTO_SRCS})
// 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.
syntax = "proto2";
import "pds_option.proto";
import "builtin_format.proto";
package baidu.paddle_serving.predictor.elastic_ctr;
option cc_generic_services = true;
message Slot {
required string slot_name = 1;
repeated int64 feasigns = 2;
};
message ReqInstance { repeated Slot slots = 1; };
message Request { repeated ReqInstance instances = 1; };
message ResInstance {
required float prob0 = 1;
required float prob1 = 2;
};
message Response {
repeated ResInstance predictions = 1;
required int64 err_code = 2;
optional string err_msg = 3;
};
service ElasticCTRPredictionService {
rpc inference(Request) returns (Response);
rpc debug(Request) returns (Response);
option (pds.options).generate_impl = true;
};
......@@ -23,7 +23,6 @@
#include <unistd.h>
#include <exception>
#include "boost/unordered_map.hpp"
#include "gflags/gflags.h"
#include "google/protobuf/message.h"
......@@ -35,7 +34,7 @@
#include "base/logging.h"
#include "base/object_pool.h"
#include "base/time.h"
#include "bthread.h"
#include "bthread.h" // NOLINT
#else
#include "brpc/channel.h"
#include "brpc/parallel_channel.h"
......@@ -49,7 +48,7 @@
#include "bvar/bvar.h"
#ifdef BCLOUD
#include "json_to_pb.h"
#include "json_to_pb.h" // NOLINT
#else
#include "json2pb/json_to_pb.h"
#endif
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册