| @@ -1,12 +1,12 @@ | |||||
| set(glog_CXXFLAGS "-D_FORTIFY_SOURCE=2 -O2 ${SECURE_CXX_FLAGS} -D_GLIBCXX_USE_CXX11_ABI=0") | set(glog_CXXFLAGS "-D_FORTIFY_SOURCE=2 -O2 ${SECURE_CXX_FLAGS} -D_GLIBCXX_USE_CXX11_ABI=0") | ||||
| set(glog_CFLAGS "-D_FORTIFY_SOURCE=2 -O2") | set(glog_CFLAGS "-D_FORTIFY_SOURCE=2 -O2") | ||||
| if (ENABLE_GITEE) | |||||
| if(ENABLE_GITEE) | |||||
| set(REQ_URL "https://gitee.com/mirrors/glog/repository/archive/v0.4.0.tar.gz") | set(REQ_URL "https://gitee.com/mirrors/glog/repository/archive/v0.4.0.tar.gz") | ||||
| set(MD5 "22fe340ddc231e6c8e46bc295320f8ee") | set(MD5 "22fe340ddc231e6c8e46bc295320f8ee") | ||||
| else() | else() | ||||
| set(REQ_URL "https://github.com/google/glog/archive/v0.4.0.tar.gz") | set(REQ_URL "https://github.com/google/glog/archive/v0.4.0.tar.gz") | ||||
| set(MD5 "0daea8785e6df922d7887755c3d100d0") | set(MD5 "0daea8785e6df922d7887755c3d100d0") | ||||
| endif () | |||||
| endif() | |||||
| mindspore_add_pkg(glog | mindspore_add_pkg(glog | ||||
| VER 0.4.0 | VER 0.4.0 | ||||
| LIBS glog | LIBS glog | ||||
| @@ -14,4 +14,4 @@ mindspore_add_pkg(glog | |||||
| MD5 ${MD5} | MD5 ${MD5} | ||||
| CMAKE_OPTION -DBUILD_TESTING=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DBUILD_SHARED_LIBS=ON -DWITH_GFLAGS=OFF) | CMAKE_OPTION -DBUILD_TESTING=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DBUILD_SHARED_LIBS=ON -DWITH_GFLAGS=OFF) | ||||
| include_directories(${glog_INC}) | include_directories(${glog_INC}) | ||||
| add_library(mindspore::glog ALIAS glog::glog) | |||||
| add_library(mindspore_serving::glog ALIAS glog::glog) | |||||
| @@ -241,7 +241,7 @@ Status GrpcTensorHelper::CreateInstanceFromRequest(const proto::PredictRequest & | |||||
| MethodSignature method_signature; | MethodSignature method_signature; | ||||
| if (!servable_signature.GetMethodDeclare(request_spec->method_name, &method_signature)) { | if (!servable_signature.GetMethodDeclare(request_spec->method_name, &method_signature)) { | ||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) | return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) | ||||
| << "Method " << method_name << " is not registed for servable " << servable_name; | |||||
| << "Method " << method_name << " is not registered for servable " << servable_name; | |||||
| } | } | ||||
| if (request.instances_size() == 0) { | if (request.instances_size() == 0) { | ||||
| @@ -269,7 +269,7 @@ Status GrpcTensorHelper::CreateReplyFromInstances(const proto::PredictRequest &r | |||||
| MethodSignature method_signature; | MethodSignature method_signature; | ||||
| if (!servable_signature.GetMethodDeclare(method_name, &method_signature)) { | if (!servable_signature.GetMethodDeclare(method_name, &method_signature)) { | ||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) | return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) | ||||
| << "Method " << method_name << " is not registed for servable " << servable_name; | |||||
| << "Method " << method_name << " is not registered for servable " << servable_name; | |||||
| } | } | ||||
| *reply->mutable_servable_spec() = request.servable_spec(); | *reply->mutable_servable_spec() = request.servable_spec(); | ||||
| @@ -305,7 +305,7 @@ Status GrpcTensorHelper::CreateReplyFromInstances(const proto::PredictRequest &r | |||||
| auto &output_tensor = output_intance.data[i]; | auto &output_tensor = output_intance.data[i]; | ||||
| auto &proto_tensor = (*proto_items)[method_signature.outputs[i]]; | auto &proto_tensor = (*proto_items)[method_signature.outputs[i]]; | ||||
| ProtoTensor result_tensor(&proto_tensor); | ProtoTensor result_tensor(&proto_tensor); | ||||
| result_tensor.assgin(*output_tensor); | |||||
| result_tensor.assign(*output_tensor); | |||||
| } | } | ||||
| } | } | ||||
| return SUCCESS; | return SUCCESS; | ||||
| @@ -356,9 +356,15 @@ Status GrpcTensorHelper::CheckRequestTensor(const proto::Tensor &tensor) { | |||||
| } | } | ||||
| } else { | } else { | ||||
| size_t element_num = tensor_input.element_cnt(); | size_t element_num = tensor_input.element_cnt(); | ||||
| if (element_num == 0) { // shape dim invalid or element count > max element num | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "Tensor check failed: input " | |||||
| << " shape " << tensor_input.shape() << " invalid"; | |||||
| bool zero_dim = false; | |||||
| for (auto &shape_item : tensor_input.shape()) { | |||||
| if (shape_item < 0 || zero_dim) { | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "Tensor check failed: input " | |||||
| << " shape " << tensor_input.shape() << " invalid"; | |||||
| } | |||||
| if (shape_item == 0) { | |||||
| zero_dim = true; | |||||
| } | |||||
| } | } | ||||
| if (tensor_input.data_type() == kMSI_Unknown || tensor_input.itemsize() == 0) { | if (tensor_input.data_type() == kMSI_Unknown || tensor_input.itemsize() == 0) { | ||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "Tensor check failed: input " | return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "Tensor check failed: input " | ||||
| @@ -63,9 +63,6 @@ class Status { | |||||
| } | } | ||||
| #define INFER_STATUS(code) mindspore::serving::Status(code) < mindspore::serving::LogStream() | #define INFER_STATUS(code) mindspore::serving::Status(code) < mindspore::serving::LogStream() | ||||
| #define ERROR_INFER_STATUS(status, type, msg) \ | |||||
| MSI_LOG_ERROR << msg; \ | |||||
| status = mindspore::serving::Status(type, msg) | |||||
| #define INFER_STATUS_LOG_ERROR(code) mindspore::serving::Status(code) = MSILOG_NOIF(ERROR) | #define INFER_STATUS_LOG_ERROR(code) mindspore::serving::Status(code) = MSILOG_NOIF(ERROR) | ||||
| #define INFER_STATUS_LOG_WARNING(code) mindspore::serving::Status(code) = MSILOG_NOIF(WARNING) | #define INFER_STATUS_LOG_WARNING(code) mindspore::serving::Status(code) = MSILOG_NOIF(WARNING) | ||||
| @@ -68,7 +68,7 @@ size_t TensorBase::GetTypeSize(DataType type) { | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| void TensorBase::assgin(const TensorBase &other) { | |||||
| void TensorBase::assign(const TensorBase &other) { | |||||
| if (is_bytes_val_data()) { | if (is_bytes_val_data()) { | ||||
| clear_bytes_data(); | clear_bytes_data(); | ||||
| } | } | ||||
| @@ -51,7 +51,7 @@ enum DataType { | |||||
| class TensorBase; | class TensorBase; | ||||
| using TensorBasePtr = std::shared_ptr<TensorBase>; | using TensorBasePtr = std::shared_ptr<TensorBase>; | ||||
| class MS_API TensorBase { | |||||
| class MS_API TensorBase : public std::enable_shared_from_this<TensorBase> { | |||||
| public: | public: | ||||
| TensorBase() = default; | TensorBase() = default; | ||||
| virtual ~TensorBase() = default; | virtual ~TensorBase() = default; | ||||
| @@ -84,7 +84,7 @@ class MS_API TensorBase { | |||||
| // TensorBase(const TensorBase& other) = delete; | // TensorBase(const TensorBase& other) = delete; | ||||
| // TensorBase& operator=(const TensorBase& other) = delete; | // TensorBase& operator=(const TensorBase& other) = delete; | ||||
| void assgin(const TensorBase &other); | |||||
| void assign(const TensorBase &other); | |||||
| Status concat(const std::vector<TensorBasePtr> &inputs); | Status concat(const std::vector<TensorBasePtr> &inputs); | ||||
| bool is_bytes_val_data() const { return data_type() == kMSI_Bytes || data_type() == kMSI_String; } | bool is_bytes_val_data() const { return data_type() == kMSI_Bytes || data_type() == kMSI_String; } | ||||
| }; | }; | ||||
| @@ -120,18 +120,16 @@ size_t GetB64OriginSize(size_t target_len, size_t tail_size) { | |||||
| size_t GetTailEqualSize(const std::string &str) { | size_t GetTailEqualSize(const std::string &str) { | ||||
| size_t length = str.size(); | size_t length = str.size(); | ||||
| if (length == 0 || length % 4 != 0) { | |||||
| if (length % 4 != 0) { | |||||
| return UINT32_MAX; | return UINT32_MAX; | ||||
| } | } | ||||
| size_t count = 0; | size_t count = 0; | ||||
| if (str.at(str.size() - 1) == '=') { | |||||
| if (length >= 1 && str[length - 1] == '=') { | |||||
| count++; | count++; | ||||
| } | } | ||||
| if (str.at(str.size() - 2) == '=') { | |||||
| if (length >= 2 && str[length - 2] == '=') { | |||||
| count++; | count++; | ||||
| } | } | ||||
| return count; | return count; | ||||
| } | } | ||||
| @@ -148,8 +148,9 @@ bool RestfulService::JsonMatchDataType(const json &js, DataType type) { | |||||
| flag = true; | flag = true; | ||||
| } | } | ||||
| } else if (js.is_string()) { | } else if (js.is_string()) { | ||||
| // string value can express all kinds type | |||||
| flag = true; | |||||
| if (type == kMSI_String) { | |||||
| flag = true; | |||||
| } | |||||
| } else if (js.is_boolean()) { | } else if (js.is_boolean()) { | ||||
| if (type == kMSI_Bool) { | if (type == kMSI_Bool) { | ||||
| flag = true; | flag = true; | ||||
| @@ -162,12 +163,9 @@ bool RestfulService::JsonMatchDataType(const json &js, DataType type) { | |||||
| std::vector<int64_t> RestfulService::GetObjShape(const json &js) { | std::vector<int64_t> RestfulService::GetObjShape(const json &js) { | ||||
| std::vector<int64_t> shape; | std::vector<int64_t> shape; | ||||
| auto it = js.find(kShape); | auto it = js.find(kShape); | ||||
| if (it == js.end()) { | |||||
| shape.push_back(1); | |||||
| } else { | |||||
| if (it != js.end()) { | |||||
| shape = GetSpecifiedShape(it.value()); | shape = GetSpecifiedShape(it.value()); | ||||
| } | } | ||||
| return shape; | return shape; | ||||
| } | } | ||||
| @@ -330,17 +328,24 @@ Status RestfulService::CheckObj(const json &js) { | |||||
| if (!value.is_array()) { | if (!value.is_array()) { | ||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "json object, key is 'shape', value should be array type"; | return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "json object, key is 'shape', value should be array type"; | ||||
| } | } | ||||
| if (value.empty()) { | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "json object, key is 'shape', array value should no be empty"; | |||||
| } | |||||
| bool zero_dims_before = false; | |||||
| for (auto it = value.begin(); it != value.end(); ++it) { | for (auto it = value.begin(); it != value.end(); ++it) { | ||||
| if (!(it->is_number())) { | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "json object, key is 'shape', array value should be number"; | |||||
| if (zero_dims_before) { | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) | |||||
| << "json object, key is 'shape', invalid shape value " << value.dump(); | |||||
| } | |||||
| if (!(it->is_number_unsigned())) { | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) | |||||
| << "json object, key is 'shape', array value should be unsigned integer"; | |||||
| } | } | ||||
| auto number = it->get<int32_t>(); | auto number = it->get<int32_t>(); | ||||
| if (number <= 0) { | |||||
| if (number < 0) { | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) | return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) | ||||
| << "json object, key is 'shape', number value should be positive number"; | |||||
| << "json object, key is 'shape', number value should not be negative number, shape value: " | |||||
| << value.dump(); | |||||
| } | |||||
| if (number == 0) { | |||||
| zero_dims_before = true; | |||||
| } | } | ||||
| } | } | ||||
| shape_count++; | shape_count++; | ||||
| @@ -365,28 +370,29 @@ Status RestfulService::CheckObj(const json &js) { | |||||
| // 1. parse request common func | // 1. parse request common func | ||||
| Status RestfulService::ParseItem(const json &value, ProtoTensor *const pb_tensor) { | Status RestfulService::ParseItem(const json &value, ProtoTensor *const pb_tensor) { | ||||
| Status status(SUCCESS); | Status status(SUCCESS); | ||||
| std::vector<int64_t> scalar_shape = {}; | |||||
| if (value.is_number_integer()) { | if (value.is_number_integer()) { | ||||
| DataType type = kMSI_Int32; | DataType type = kMSI_Int32; | ||||
| pb_tensor->set_data_type(type); | pb_tensor->set_data_type(type); | ||||
| pb_tensor->set_shape({1}); | |||||
| pb_tensor->set_shape(scalar_shape); | |||||
| pb_tensor->resize_data(pb_tensor->GetTypeSize(type)); | pb_tensor->resize_data(pb_tensor->GetTypeSize(type)); | ||||
| status = GetScalarByType(type, value, 0, pb_tensor); | status = GetScalarByType(type, value, 0, pb_tensor); | ||||
| } else if (value.is_number_float()) { | } else if (value.is_number_float()) { | ||||
| DataType type = kMSI_Float32; | DataType type = kMSI_Float32; | ||||
| pb_tensor->set_data_type(type); | pb_tensor->set_data_type(type); | ||||
| pb_tensor->set_shape({1}); | |||||
| pb_tensor->set_shape(scalar_shape); | |||||
| pb_tensor->resize_data(pb_tensor->GetTypeSize(type)); | pb_tensor->resize_data(pb_tensor->GetTypeSize(type)); | ||||
| status = GetScalarByType(type, value, 0, pb_tensor); | status = GetScalarByType(type, value, 0, pb_tensor); | ||||
| } else if (value.is_boolean()) { | } else if (value.is_boolean()) { | ||||
| DataType type = kMSI_Bool; | DataType type = kMSI_Bool; | ||||
| pb_tensor->set_data_type(type); | pb_tensor->set_data_type(type); | ||||
| pb_tensor->set_shape({1}); | |||||
| pb_tensor->set_shape(scalar_shape); | |||||
| pb_tensor->resize_data(pb_tensor->GetTypeSize(type)); | pb_tensor->resize_data(pb_tensor->GetTypeSize(type)); | ||||
| status = GetScalarByType(type, value, 0, pb_tensor); | status = GetScalarByType(type, value, 0, pb_tensor); | ||||
| } else if (value.is_string()) { | } else if (value.is_string()) { | ||||
| DataType type = kMSI_String; | DataType type = kMSI_String; | ||||
| pb_tensor->set_data_type(type); | pb_tensor->set_data_type(type); | ||||
| pb_tensor->set_shape({1}); | |||||
| pb_tensor->set_shape(scalar_shape); | |||||
| status = GetScalarByType(type, value, 0, pb_tensor); | status = GetScalarByType(type, value, 0, pb_tensor); | ||||
| } else if (value.is_object()) { | } else if (value.is_object()) { | ||||
| status = CheckObj(value); | status = CheckObj(value); | ||||
| @@ -400,10 +406,6 @@ Status RestfulService::ParseItem(const json &value, ProtoTensor *const pb_tensor | |||||
| } | } | ||||
| std::vector<int64_t> shape = GetObjShape(value); | std::vector<int64_t> shape = GetObjShape(value); | ||||
| if (shape.empty()) { | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "object json, shape is empty"; | |||||
| } | |||||
| bool is_tensor = false; | bool is_tensor = false; | ||||
| if (type != kMSI_String && type != kMSI_Bytes) { | if (type != kMSI_String && type != kMSI_Bytes) { | ||||
| is_tensor = true; | is_tensor = true; | ||||
| @@ -437,7 +439,7 @@ Status RestfulService::ParseItem(const json &value, ProtoTensor *const pb_tensor | |||||
| is_tensor = true; | is_tensor = true; | ||||
| } | } | ||||
| // intances mode:only support one item | |||||
| // instances mode:only support one item | |||||
| if (request_type_ == kInstanceType) { | if (request_type_ == kInstanceType) { | ||||
| if (!is_tensor) { | if (!is_tensor) { | ||||
| size_t elements_nums = std::accumulate(shape.begin(), shape.end(), 1LL, std::multiplies<size_t>()); | size_t elements_nums = std::accumulate(shape.begin(), shape.end(), 1LL, std::multiplies<size_t>()); | ||||
| @@ -481,15 +483,15 @@ Status RestfulService::RecursiveGetArray(const json &json_data, size_t depth, si | |||||
| std::vector<int64_t> required_shape = request_tensor->shape(); | std::vector<int64_t> required_shape = request_tensor->shape(); | ||||
| if (depth >= required_shape.size()) { | if (depth >= required_shape.size()) { | ||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) | return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) | ||||
| << "current depth:" << depth << " is more than shape dims:" << required_shape.size(); | |||||
| << "invalid json array: current depth " << depth << " is more than shape dims " << required_shape.size(); | |||||
| } | } | ||||
| if (!json_data.is_array()) { | if (!json_data.is_array()) { | ||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "json type is not array"; | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "invalid json array: json type is not array"; | |||||
| } | } | ||||
| if (json_data.size() != static_cast<size_t>(required_shape[depth])) { | if (json_data.size() != static_cast<size_t>(required_shape[depth])) { | ||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) | return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) | ||||
| << "json size is:" << json_data.size() << "; the " << depth << " dim need" | |||||
| << " shape size:" << required_shape[depth]; | |||||
| << "invalid json array: json size is " << json_data.size() << ", the dim " << depth << " expected to be " | |||||
| << required_shape[depth]; | |||||
| } | } | ||||
| if (depth + 1 < required_shape.size()) { | if (depth + 1 < required_shape.size()) { | ||||
| size_t sub_element_cnt = | size_t sub_element_cnt = | ||||
| @@ -618,9 +620,7 @@ Status RestfulService::GetScalarData(const json &js, size_t index, bool is_bytes | |||||
| auto value = js.get<std::string>(); | auto value = js.get<std::string>(); | ||||
| if (is_bytes) { | if (is_bytes) { | ||||
| if (value.empty()) { | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "string value is empty"; | |||||
| } | |||||
| DataType real_type = request_tensor->data_type(); | |||||
| auto tail_equal_size = GetTailEqualSize(value); | auto tail_equal_size = GetTailEqualSize(value); | ||||
| if (tail_equal_size == UINT32_MAX) { | if (tail_equal_size == UINT32_MAX) { | ||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "'" << value << "' is illegal b64 encode string"; | return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "'" << value << "' is illegal b64 encode string"; | ||||
| @@ -631,7 +631,6 @@ Status RestfulService::GetScalarData(const json &js, size_t index, bool is_bytes | |||||
| if (target_size != origin_size) { | if (target_size != origin_size) { | ||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "decode base64 failed, size is not matched."; | return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "decode base64 failed, size is not matched."; | ||||
| } | } | ||||
| DataType real_type = request_tensor->data_type(); | |||||
| if (real_type == kMSI_Bytes || real_type == kMSI_String) { | if (real_type == kMSI_Bytes || real_type == kMSI_String) { | ||||
| request_tensor->add_bytes_data(buffer.data(), origin_size); | request_tensor->add_bytes_data(buffer.data(), origin_size); | ||||
| } else { | } else { | ||||
| @@ -643,9 +642,10 @@ Status RestfulService::GetScalarData(const json &js, size_t index, bool is_bytes | |||||
| << "; Given info: type:" << GetStringByDataType(real_type) << "; type size:" << type_size | << "; Given info: type:" << GetStringByDataType(real_type) << "; type size:" << type_size | ||||
| << "; element nums:" << element_cnt; | << "; element nums:" << element_cnt; | ||||
| } | } | ||||
| auto data = reinterpret_cast<T *>(request_tensor->mutable_data()) + index; | |||||
| memcpy_s(data, origin_size, buffer.data(), buffer.size()); | |||||
| if (origin_size > 0) { | |||||
| auto data = reinterpret_cast<T *>(request_tensor->mutable_data()) + index; | |||||
| memcpy_s(data, origin_size, buffer.data(), buffer.size()); | |||||
| } | |||||
| } | } | ||||
| } else { | } else { | ||||
| request_tensor->add_bytes_data(reinterpret_cast<uint8_t *>(value.data()), value.length()); | request_tensor->add_bytes_data(reinterpret_cast<uint8_t *>(value.data()), value.length()); | ||||
| @@ -680,7 +680,7 @@ Status RestfulService::RunRestful(const std::shared_ptr<RestfulRequest> &restful | |||||
| MSI_TIME_STAMP_END(ParseRequest) | MSI_TIME_STAMP_END(ParseRequest) | ||||
| if (status != SUCCESS) { | if (status != SUCCESS) { | ||||
| std::string error_msg = status.StatusMessage(); | std::string error_msg = status.StatusMessage(); | ||||
| std::string msg = "Parser reqeust failed, " + error_msg; | |||||
| std::string msg = "Parser request failed, " + error_msg; | |||||
| status = msg; | status = msg; | ||||
| return status; | return status; | ||||
| } | } | ||||
| @@ -730,7 +730,7 @@ Status RestfulService::ParseRequest(const std::shared_ptr<RestfulRequest> &restf | |||||
| status = ParseInstancesMsg(js_msg, request); | status = ParseInstancesMsg(js_msg, request); | ||||
| break; | break; | ||||
| default: | default: | ||||
| return INFER_STATUS_LOG_ERROR(FAILED) << "restful reqeust only support instances mode"; | |||||
| return INFER_STATUS_LOG_ERROR(FAILED) << "restful request only support instances mode"; | |||||
| } | } | ||||
| return status; | return status; | ||||
| @@ -741,8 +741,7 @@ Status RestfulService::ParseReqCommonMsg(const std::shared_ptr<RestfulRequest> & | |||||
| Status status(SUCCESS); | Status status(SUCCESS); | ||||
| auto request_ptr = restful_request->decompose_event_request(); | auto request_ptr = restful_request->decompose_event_request(); | ||||
| if (request_ptr == nullptr) { | if (request_ptr == nullptr) { | ||||
| ERROR_INFER_STATUS(status, INVALID_INPUTS, "Decompose event request is nullptr"); | |||||
| return status; | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "Decompose event request is nullptr"; | |||||
| } | } | ||||
| request->mutable_servable_spec()->set_name(request_ptr->model_name_); | request->mutable_servable_spec()->set_name(request_ptr->model_name_); | ||||
| request->mutable_servable_spec()->set_version_number(request_ptr->version_); | request->mutable_servable_spec()->set_version_number(request_ptr->version_); | ||||
| @@ -755,8 +754,7 @@ Status RestfulService::ParseInstancesMsg(const json &js_msg, PredictRequest *con | |||||
| auto type = GetReqTypeStr(request_type_); | auto type = GetReqTypeStr(request_type_); | ||||
| auto instances = js_msg.find(type); | auto instances = js_msg.find(type); | ||||
| if (instances == js_msg.end()) { | if (instances == js_msg.end()) { | ||||
| ERROR_INFER_STATUS(status, FAILED, "instances request json should have instances key word"); | |||||
| return status; | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "instances request json should have instances key word"; | |||||
| } | } | ||||
| // get instances way:{key, value} or {value} | // get instances way:{key, value} or {value} | ||||
| @@ -845,9 +843,7 @@ Status RestfulService::ParseReplyDetail(const proto::Tensor &tensor, json *const | |||||
| Status status(SUCCESS); | Status status(SUCCESS); | ||||
| const ProtoTensor pb_tensor(const_cast<proto::Tensor *>(&tensor)); | const ProtoTensor pb_tensor(const_cast<proto::Tensor *>(&tensor)); | ||||
| auto shape = pb_tensor.shape(); | auto shape = pb_tensor.shape(); | ||||
| size_t shape_size = std::accumulate(shape.begin(), shape.end(), 1LL, std::multiplies<size_t>()); | |||||
| if (shape_size == 1) { | |||||
| if (shape.empty()) { | |||||
| status = ParseScalar(pb_tensor, 0, js); | status = ParseScalar(pb_tensor, 0, js); | ||||
| if (status != SUCCESS) { | if (status != SUCCESS) { | ||||
| return status; | return status; | ||||
| @@ -900,7 +896,7 @@ Status RestfulService::ParseScalar(const ProtoTensor &pb_tensor, size_t index, j | |||||
| status = ParseScalarData<uint64_t>(pb_tensor, false, index, js); | status = ParseScalarData<uint64_t>(pb_tensor, false, index, js); | ||||
| break; | break; | ||||
| case kMSI_Float16: | case kMSI_Float16: | ||||
| ERROR_INFER_STATUS(status, FAILED, "fp16 reply is not supported"); | |||||
| status = INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "fp16 reply is not supported"; | |||||
| break; | break; | ||||
| case kMSI_Float32: | case kMSI_Float32: | ||||
| status = ParseScalarData<float>(pb_tensor, false, index, js); | status = ParseScalarData<float>(pb_tensor, false, index, js); | ||||
| @@ -915,7 +911,7 @@ Status RestfulService::ParseScalar(const ProtoTensor &pb_tensor, size_t index, j | |||||
| status = ParseScalarData<std::string>(pb_tensor, true, index, js); | status = ParseScalarData<std::string>(pb_tensor, true, index, js); | ||||
| break; | break; | ||||
| default: | default: | ||||
| ERROR_INFER_STATUS(status, FAILED, "reply data type is not supported"); | |||||
| status = INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "reply data type is not supported"; | |||||
| break; | break; | ||||
| } | } | ||||
| return status; | return status; | ||||
| @@ -981,10 +977,15 @@ Status RestfulService::RecursiveParseArray(const ProtoTensor &pb_tensor, size_t | |||||
| json *const out_json) { | json *const out_json) { | ||||
| Status status(SUCCESS); | Status status(SUCCESS); | ||||
| std::vector<int64_t> required_shape = pb_tensor.shape(); | std::vector<int64_t> required_shape = pb_tensor.shape(); | ||||
| if (depth >= 10) { | |||||
| return INFER_STATUS_LOG_ERROR(FAILED) << "result shape dims is larger than 10"; | |||||
| if (depth >= required_shape.size()) { | |||||
| return INFER_STATUS_LOG_ERROR(FAILED) | |||||
| << "result shape dims is larger than result shape size " << required_shape.size(); | |||||
| } | } | ||||
| if (depth == required_shape.size() - 1) { | if (depth == required_shape.size() - 1) { | ||||
| if (required_shape[depth] == 0) { // make empty array | |||||
| out_json->push_back(json()); | |||||
| out_json->clear(); | |||||
| } | |||||
| for (int i = 0; i < required_shape[depth]; i++) { | for (int i = 0; i < required_shape[depth]; i++) { | ||||
| out_json->push_back(json()); | out_json->push_back(json()); | ||||
| json &scalar_json = out_json->back(); | json &scalar_json = out_json->back(); | ||||
| @@ -21,10 +21,12 @@ | |||||
| #include <algorithm> | #include <algorithm> | ||||
| #include <utility> | #include <utility> | ||||
| static const char UrlKeyModel[] = "model"; | |||||
| static const char UrlKeyVersion[] = "version"; | |||||
| static const char UrlSplit[] = "/"; | |||||
| static const char UrlKeyEnd[] = ":"; | |||||
| namespace { | |||||
| const char kUrlKeyModel[] = "model"; | |||||
| const char kUrlKeyVersion[] = "version"; | |||||
| const char kUrlSplit[] = "/"; | |||||
| const char kUrlKeyEnd[] = ":"; | |||||
| } // namespace | |||||
| namespace mindspore { | namespace mindspore { | ||||
| namespace serving { | namespace serving { | ||||
| @@ -40,8 +42,8 @@ DecomposeEvRequest::~DecomposeEvRequest() { | |||||
| std::string DecomposeEvRequest::UrlQuery(const std::string &url, const std::string &key) { | std::string DecomposeEvRequest::UrlQuery(const std::string &url, const std::string &key) { | ||||
| std::string::size_type start_pos(0); | std::string::size_type start_pos(0); | ||||
| if (key == UrlKeyEnd) { | |||||
| if ((start_pos = url_.find(UrlKeyEnd)) != std::string::npos) { | |||||
| if (key == kUrlKeyEnd) { | |||||
| if ((start_pos = url_.find(kUrlKeyEnd)) != std::string::npos) { | |||||
| return url_.substr(start_pos + 1, url_.size()); | return url_.substr(start_pos + 1, url_.size()); | ||||
| } | } | ||||
| } | } | ||||
| @@ -49,10 +51,11 @@ std::string DecomposeEvRequest::UrlQuery(const std::string &url, const std::stri | |||||
| int key_size = key.size() + 1; | int key_size = key.size() + 1; | ||||
| std::string::size_type end_pos(0); | std::string::size_type end_pos(0); | ||||
| if ((start_pos = url.find(key)) != std::string::npos) { | if ((start_pos = url.find(key)) != std::string::npos) { | ||||
| end_pos = std::min(url.find(UrlSplit, start_pos + key_size), url.find(UrlKeyEnd, start_pos + key_size)); | |||||
| if (end_pos != std::string::npos) { | |||||
| return url.substr(start_pos + key_size, end_pos - start_pos - key_size); | |||||
| end_pos = std::min(url.find(kUrlSplit, start_pos + key_size), url.find(kUrlKeyEnd, start_pos + key_size)); | |||||
| if (end_pos == std::string::npos) { | |||||
| return url.substr(start_pos + key_size); | |||||
| } | } | ||||
| return url.substr(start_pos + key_size, end_pos - start_pos - key_size); | |||||
| } | } | ||||
| return ""; | return ""; | ||||
| } | } | ||||
| @@ -62,21 +65,17 @@ Status DecomposeEvRequest::GetPostMessageToJson() { | |||||
| std::string message; | std::string message; | ||||
| size_t input_size = evbuffer_get_length(event_request_->input_buffer); | size_t input_size = evbuffer_get_length(event_request_->input_buffer); | ||||
| if (input_size == 0) { | if (input_size == 0) { | ||||
| ERROR_INFER_STATUS(status, INVALID_INPUTS, "http message invalid"); | |||||
| return status; | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "http message invalid"; | |||||
| } else if (input_size > max_msg_size_) { | } else if (input_size > max_msg_size_) { | ||||
| ERROR_INFER_STATUS(status, INVALID_INPUTS, "http message is bigger than " + std::to_string(max_msg_size_)); | |||||
| return status; | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "http message is bigger than " << max_msg_size_; | |||||
| } else { | } else { | ||||
| message.resize(input_size); | message.resize(input_size); | ||||
| auto src_data = evbuffer_pullup(event_request_->input_buffer, -1); | auto src_data = evbuffer_pullup(event_request_->input_buffer, -1); | ||||
| if (src_data == nullptr) { | if (src_data == nullptr) { | ||||
| ERROR_INFER_STATUS(status, FAILED, "get http message failed."); | |||||
| return status; | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "get http message failed."; | |||||
| } | } | ||||
| if (memcpy_s(message.data(), input_size, src_data, input_size) != EOK) { | if (memcpy_s(message.data(), input_size, src_data, input_size) != EOK) { | ||||
| ERROR_INFER_STATUS(status, FAILED, "copy http message failed."); | |||||
| return status; | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "copy http message failed."; | |||||
| } | } | ||||
| } | } | ||||
| MSI_TIME_STAMP_START(ParseJson) | MSI_TIME_STAMP_START(ParseJson) | ||||
| @@ -84,9 +83,7 @@ Status DecomposeEvRequest::GetPostMessageToJson() { | |||||
| request_message_ = nlohmann::json::parse(message); | request_message_ = nlohmann::json::parse(message); | ||||
| } catch (nlohmann::json::exception &e) { | } catch (nlohmann::json::exception &e) { | ||||
| std::string json_exception = e.what(); | std::string json_exception = e.what(); | ||||
| std::string error_message = "Illegal JSON format." + json_exception; | |||||
| ERROR_INFER_STATUS(status, INVALID_INPUTS, error_message); | |||||
| return status; | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "Illegal JSON format." + json_exception; | |||||
| } | } | ||||
| MSI_TIME_STAMP_END(ParseJson) | MSI_TIME_STAMP_END(ParseJson) | ||||
| @@ -100,8 +97,7 @@ Status DecomposeEvRequest::CheckRequestMethodValid() { | |||||
| request_method_ = "POST"; | request_method_ = "POST"; | ||||
| return status; | return status; | ||||
| default: | default: | ||||
| ERROR_INFER_STATUS(status, INVALID_INPUTS, "http message only support POST right now"); | |||||
| return status; | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "http message only support POST right now"; | |||||
| } | } | ||||
| } | } | ||||
| @@ -120,35 +116,37 @@ Status DecomposeEvRequest::Decompose() { | |||||
| // eg: /model/resnet/version/1:predict | // eg: /model/resnet/version/1:predict | ||||
| url_ = evhttp_request_get_uri(event_request_); | url_ = evhttp_request_get_uri(event_request_); | ||||
| if (url_.empty()) { | if (url_.empty()) { | ||||
| ERROR_INFER_STATUS(status, INVALID_INPUTS, "evhttp url is empty."); | |||||
| return status; | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "evhttp url is empty."; | |||||
| } | } | ||||
| MSI_LOG_INFO << "url_: " << url_; | MSI_LOG_INFO << "url_: " << url_; | ||||
| model_name_ = UrlQuery(url_, UrlKeyModel); | |||||
| model_name_ = UrlQuery(url_, kUrlKeyModel); | |||||
| if (model_name_.empty()) { | if (model_name_.empty()) { | ||||
| ERROR_INFER_STATUS(status, INVALID_INPUTS, "please check url, the keyword:[model] must contain."); | |||||
| return status; | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "please check url, the keyword:[model] must contain."; | |||||
| } | } | ||||
| MSI_LOG_INFO << "model_name_: " << model_name_; | MSI_LOG_INFO << "model_name_: " << model_name_; | ||||
| if (url_.find(UrlKeyVersion) != std::string::npos) { | |||||
| auto version_str = UrlQuery(url_, UrlKeyVersion); | |||||
| if (url_.find(kUrlKeyVersion) != std::string::npos) { | |||||
| auto version_str = UrlQuery(url_, kUrlKeyVersion); | |||||
| try { | try { | ||||
| version_ = std::stol(version_str); | |||||
| auto version = std::stol(version_str); | |||||
| if (version < 0 || version >= UINT32_MAX) { | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) | |||||
| << "please check url, version number range failed, request version number " << version_str; | |||||
| } | |||||
| version_ = static_cast<uint32_t>(version); | |||||
| } catch (const std::invalid_argument &) { | } catch (const std::invalid_argument &) { | ||||
| ERROR_INFER_STATUS(status, INVALID_INPUTS, "please check url, the keyword:[version] must contain."); | |||||
| return status; | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) | |||||
| << "please check url, the keyword:[version] value invalid, request version number " << version_str; | |||||
| } catch (const std::out_of_range &) { | } catch (const std::out_of_range &) { | ||||
| ERROR_INFER_STATUS(status, INVALID_INPUTS, "please check url, the keyword:[version] out of range."); | |||||
| return status; | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) | |||||
| << "please check url, version number range failed, request version number " << version_str; | |||||
| } | } | ||||
| MSI_LOG_INFO << "version_: " << version_; | MSI_LOG_INFO << "version_: " << version_; | ||||
| } | } | ||||
| service_method_ = UrlQuery(url_, UrlKeyEnd); | |||||
| service_method_ = UrlQuery(url_, kUrlKeyEnd); | |||||
| if (service_method_.empty()) { | if (service_method_.empty()) { | ||||
| ERROR_INFER_STATUS(status, INVALID_INPUTS, "please check url, the keyword:[service method] must contain."); | |||||
| return status; | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "please check url, the keyword:[service method] must contain."; | |||||
| } | } | ||||
| MSI_LOG_INFO << "service_method_: " << service_method_; | MSI_LOG_INFO << "service_method_: " << service_method_; | ||||
| return status; | return status; | ||||
| @@ -164,37 +162,31 @@ RestfulRequest::~RestfulRequest() { | |||||
| } | } | ||||
| Status RestfulRequest::RestfulReplayBufferInit() { | Status RestfulRequest::RestfulReplayBufferInit() { | ||||
| Status status(SUCCESS); | |||||
| replay_buffer_ = evbuffer_new(); | replay_buffer_ = evbuffer_new(); | ||||
| if (replay_buffer_ == nullptr) { | if (replay_buffer_ == nullptr) { | ||||
| ERROR_INFER_STATUS(status, INVALID_INPUTS, "creat restful replay buffer fail"); | |||||
| return status; | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "create restful replay buffer fail"; | |||||
| } | } | ||||
| return status; | |||||
| return SUCCESS; | |||||
| } | } | ||||
| Status RestfulRequest::RestfulReplay(const std::string &replay) { | Status RestfulRequest::RestfulReplay(const std::string &replay) { | ||||
| Status status(SUCCESS); | |||||
| if (replay_buffer_ == nullptr) { | if (replay_buffer_ == nullptr) { | ||||
| ERROR_INFER_STATUS(status, INVALID_INPUTS, "replay_buffer_ is nullptr"); | |||||
| return status; | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "replay_buffer_ is nullptr"; | |||||
| } | } | ||||
| if (decompose_event_request_ == nullptr) { | if (decompose_event_request_ == nullptr) { | ||||
| ERROR_INFER_STATUS(status, INVALID_INPUTS, "replay_buffer_ is nullptr"); | |||||
| return status; | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "replay_buffer_ is nullptr"; | |||||
| } | } | ||||
| if (decompose_event_request_->event_request_ == nullptr) { | if (decompose_event_request_->event_request_ == nullptr) { | ||||
| ERROR_INFER_STATUS(status, INVALID_INPUTS, "replay_buffer_ is nullptr"); | |||||
| return status; | |||||
| return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "replay_buffer_ is nullptr"; | |||||
| } | } | ||||
| evbuffer_add(replay_buffer_, replay.data(), replay.size()); | evbuffer_add(replay_buffer_, replay.data(), replay.size()); | ||||
| evhttp_send_reply(decompose_event_request_->event_request_, HTTP_OK, "Client", replay_buffer_); | evhttp_send_reply(decompose_event_request_->event_request_, HTTP_OK, "Client", replay_buffer_); | ||||
| return status; | |||||
| return SUCCESS; | |||||
| } | } | ||||
| Status RestfulRequest::ErrorMessage(Status status) { | Status RestfulRequest::ErrorMessage(Status status) { | ||||
| Status error_status(SUCCESS); | Status error_status(SUCCESS); | ||||
| nlohmann::json error_json = {{"error_message", status.StatusMessage()}}; | |||||
| nlohmann::json error_json = {{"error_msg", status.StatusMessage()}}; | |||||
| std::string out_error_str = error_json.dump(); | std::string out_error_str = error_json.dump(); | ||||
| if ((error_status = RestfulReplay(out_error_str)) != SUCCESS) { | if ((error_status = RestfulReplay(out_error_str)) != SUCCESS) { | ||||
| return error_status; | return error_status; | ||||
| @@ -46,16 +46,8 @@ void RestfulServer::DispatchEvHttpRequest(evhttp_request *request) { | |||||
| Status status(SUCCESS); | Status status(SUCCESS); | ||||
| auto de_request = std::make_unique<DecomposeEvRequest>(request, max_msg_size_); | auto de_request = std::make_unique<DecomposeEvRequest>(request, max_msg_size_); | ||||
| if (de_request == nullptr) { | |||||
| ERROR_INFER_STATUS(status, INVALID_INPUTS, "de_request is nullptr."); | |||||
| return; | |||||
| } | |||||
| Status de_status = de_request->Decompose(); | Status de_status = de_request->Decompose(); | ||||
| auto restful_request = std::make_shared<RestfulRequest>(std::move(de_request)); | auto restful_request = std::make_shared<RestfulRequest>(std::move(de_request)); | ||||
| if (restful_request == nullptr) { | |||||
| ERROR_INFER_STATUS(status, INVALID_INPUTS, "restful_request is nullptr."); | |||||
| return; | |||||
| } | |||||
| status = restful_request->RestfulReplayBufferInit(); | status = restful_request->RestfulReplayBufferInit(); | ||||
| if (status != SUCCESS) { | if (status != SUCCESS) { | ||||
| if ((status = restful_request->ErrorMessage(status)) != SUCCESS) { | if ((status = restful_request->ErrorMessage(status)) != SUCCESS) { | ||||
| @@ -129,7 +121,7 @@ Status RestfulServer::StartRestfulServer() { | |||||
| if (listener == nullptr) { | if (listener == nullptr) { | ||||
| status = INFER_STATUS_LOG_ERROR(SYSTEM_ERROR) | status = INFER_STATUS_LOG_ERROR(SYSTEM_ERROR) | ||||
| << "Serving Error: RESTful server start failed, create http listener faild, port " << restful_port_; | |||||
| << "Serving Error: RESTful server start failed, create http listener failed, port " << restful_port_; | |||||
| free_event_base(); | free_event_base(); | ||||
| free_evhttp(); | free_evhttp(); | ||||
| return status; | return status; | ||||
| @@ -137,7 +129,7 @@ Status RestfulServer::StartRestfulServer() { | |||||
| auto bound = evhttp_bind_listener(event_http_, listener); | auto bound = evhttp_bind_listener(event_http_, listener); | ||||
| if (bound == nullptr) { | if (bound == nullptr) { | ||||
| status = INFER_STATUS_LOG_ERROR(SYSTEM_ERROR) | status = INFER_STATUS_LOG_ERROR(SYSTEM_ERROR) | ||||
| << "Serving Error: RESTful server start failed, bind http listener to server faild, port " | |||||
| << "Serving Error: RESTful server start failed, bind http listener to server failed, port " | |||||
| << restful_port_; | << restful_port_; | ||||
| evconnlistener_free(listener); | evconnlistener_free(listener); | ||||
| free_event_base(); | free_event_base(); | ||||
| @@ -27,6 +27,9 @@ | |||||
| namespace mindspore::serving { | namespace mindspore::serving { | ||||
| PYBIND11_MODULE(_mindspore_serving, m) { | PYBIND11_MODULE(_mindspore_serving, m) { | ||||
| // avoid as numpy object memory copy in PyTensor::AsPythonData | |||||
| py::class_<TensorBase, TensorBasePtr>(m, "Tensor_"); | |||||
| py::class_<PyPreprocessStorage, std::shared_ptr<PyPreprocessStorage>>(m, "PreprocessStorage_") | py::class_<PyPreprocessStorage, std::shared_ptr<PyPreprocessStorage>>(m, "PreprocessStorage_") | ||||
| .def(py::init<>()) | .def(py::init<>()) | ||||
| .def_static("get_instance", &PyPreprocessStorage::Instance) | .def_static("get_instance", &PyPreprocessStorage::Instance) | ||||
| @@ -196,7 +196,7 @@ py::object PyTensor::AsPythonData(TensorBasePtr tensor, bool copy) { | |||||
| py::buffer_info info(reinterpret_cast<void *>(const_cast<uint8_t *>(data)), sizeof(uint8_t), | py::buffer_info info(reinterpret_cast<void *>(const_cast<uint8_t *>(data)), sizeof(uint8_t), | ||||
| py::format_descriptor<uint8_t>::format(), 1, shape, strides); | py::format_descriptor<uint8_t>::format(), 1, shape, strides); | ||||
| if (!copy) { | if (!copy) { | ||||
| py::array self; | |||||
| py::object self = py::cast(tensor.get()); | |||||
| return py::array(py::dtype(info), info.shape, info.strides, info.ptr, self); | return py::array(py::dtype(info), info.shape, info.strides, info.ptr, self); | ||||
| } else { | } else { | ||||
| return py::array(py::dtype(info), info.shape, info.strides, info.ptr); | return py::array(py::dtype(info), info.shape, info.strides, info.ptr); | ||||
| @@ -210,7 +210,7 @@ py::object PyTensor::AsPythonData(TensorBasePtr tensor, bool copy) { | |||||
| static_cast<ssize_t>(tensor_shape.size()), shape, strides); | static_cast<ssize_t>(tensor_shape.size()), shape, strides); | ||||
| if (!copy) { | if (!copy) { | ||||
| py::array self; | |||||
| py::object self = py::cast(tensor.get()); | |||||
| return py::array(py::dtype(info), info.shape, info.strides, info.ptr, self); | return py::array(py::dtype(info), info.shape, info.strides, info.ptr, self); | ||||
| } else { | } else { | ||||
| return py::array(py::dtype(info), info.shape, info.strides, info.ptr); | return py::array(py::dtype(info), info.shape, info.strides, info.ptr); | ||||
| @@ -221,7 +221,7 @@ py::object PyTensor::AsPythonData(TensorBasePtr tensor, bool copy) { | |||||
| py::tuple PyTensor::AsNumpyTuple(const InstanceData &instance_data) { | py::tuple PyTensor::AsNumpyTuple(const InstanceData &instance_data) { | ||||
| py::tuple numpy_inputs_tuple(instance_data.size()); | py::tuple numpy_inputs_tuple(instance_data.size()); | ||||
| for (size_t i = 0; i < instance_data.size(); i++) { // inputs | for (size_t i = 0; i < instance_data.size(); i++) { // inputs | ||||
| numpy_inputs_tuple[i] = PyTensor::AsPythonData(instance_data[i]); | |||||
| numpy_inputs_tuple[i] = PyTensor::AsPythonData(instance_data[i], false); | |||||
| } | } | ||||
| return numpy_inputs_tuple; | return numpy_inputs_tuple; | ||||
| } | } | ||||
| @@ -126,17 +126,17 @@ def _check_str(arg_name, str_val): | |||||
| raise RuntimeError(f"Parameter '{arg_name}' should not be empty str") | raise RuntimeError(f"Parameter '{arg_name}' should not be empty str") | ||||
| def _check_int(arg_name, int_val, mininum=None, maximum=None): | |||||
| def _check_int(arg_name, int_val, minimum=None, maximum=None): | |||||
| """Check whether the input parameters are reasonable int input""" | """Check whether the input parameters are reasonable int input""" | ||||
| if not isinstance(int_val, int): | if not isinstance(int_val, int): | ||||
| raise RuntimeError(f"Parameter '{arg_name}' should be int, but actually {type(int_val)}") | raise RuntimeError(f"Parameter '{arg_name}' should be int, but actually {type(int_val)}") | ||||
| if mininum is not None and int_val < mininum: | |||||
| if minimum is not None and int_val < minimum: | |||||
| if maximum is not None: | if maximum is not None: | ||||
| raise RuntimeError(f"Parameter '{arg_name}' should be in range [{mininum},{maximum}]") | |||||
| raise RuntimeError(f"Parameter '{arg_name}' should be >= {mininum}") | |||||
| raise RuntimeError(f"Parameter '{arg_name}' should be in range [{minimum},{maximum}]") | |||||
| raise RuntimeError(f"Parameter '{arg_name}' should be >= {minimum}") | |||||
| if maximum is not None and int_val > maximum: | if maximum is not None and int_val > maximum: | ||||
| if mininum is not None: | |||||
| raise RuntimeError(f"Parameter '{arg_name}' should be in range [{mininum},{maximum}]") | |||||
| if minimum is not None: | |||||
| raise RuntimeError(f"Parameter '{arg_name}' should be in range [{minimum},{maximum}]") | |||||
| raise RuntimeError(f"Parameter '{arg_name}' should be <= {maximum}") | raise RuntimeError(f"Parameter '{arg_name}' should be <= {maximum}") | ||||
| @@ -259,29 +259,6 @@ class Client: | |||||
| print(status_code.value) | print(status_code.value) | ||||
| return ClientGrpcAsyncError({"error": "Grpc Error, " + str(status_code.value)}) | return ClientGrpcAsyncError({"error": "Grpc Error, " + str(status_code.value)}) | ||||
| def close(self): | |||||
| """ | |||||
| Used to release gRPC connection avoiding influence on the connection to the next restarted Serving server. | |||||
| Examples: | |||||
| >>> from mindspore_serving.client import Client | |||||
| >>> import numpy as np | |||||
| >>> instance = {"x1": np.ones((2, 2), np.int32), "x2": np.ones((2, 2), np.int32)} | |||||
| >>> client = Client("localhost", 5500, "add", "add_cast") | |||||
| >>> result = client.infer(instance) | |||||
| >>> client.close() | |||||
| >>> print(result) | |||||
| """ | |||||
| if self.stub: | |||||
| del self.stub | |||||
| self.stub = None | |||||
| def __enter__(self): | |||||
| return self | |||||
| def __exit__(self, exc_type, exc_val, exc_tb): | |||||
| self.close() | |||||
| def _create_request(self, instances): | def _create_request(self, instances): | ||||
| """Used to create request spec.""" | """Used to create request spec.""" | ||||
| if not isinstance(instances, (tuple, list)): | if not isinstance(instances, (tuple, list)): | ||||
| @@ -342,7 +319,7 @@ class Client: | |||||
| class ClientGrpcAsyncResult: | class ClientGrpcAsyncResult: | ||||
| """ | """ | ||||
| When Client.infer_async invoke sucessfully, a ClientGrpcAsyncResult object is returned. | |||||
| When Client.infer_async invoke successfully, a ClientGrpcAsyncResult object is returned. | |||||
| Examples: | Examples: | ||||
| >>> from mindspore_serving.client import Client | >>> from mindspore_serving.client import Client | ||||
| @@ -91,7 +91,7 @@ class _MultiCompatibleRotatingFileHandler(RotatingFileHandler): | |||||
| self.stream.close() | self.stream.close() | ||||
| self.stream = None | self.stream = None | ||||
| # Attain an exclusive lock with bloking mode by `fcntl` module. | |||||
| # Attain an exclusive lock with blocking mode by `fcntl` module. | |||||
| with open(self.baseFilename, 'a') as file_pointer: | with open(self.baseFilename, 'a') as file_pointer: | ||||
| if platform.system() != "Windows": | if platform.system() != "Windows": | ||||
| fcntl.lockf(file_pointer.fileno(), fcntl.LOCK_EX) | fcntl.lockf(file_pointer.fileno(), fcntl.LOCK_EX) | ||||
| @@ -396,7 +396,7 @@ def _clear_handler(logger): | |||||
| logger.removeHandler(handler) | logger.removeHandler(handler) | ||||
| def _find_caller(stack_info=False): | |||||
| def _find_caller(stack_info=False, _=1): | |||||
| """ | """ | ||||
| Find the stack frame of the caller. | Find the stack frame of the caller. | ||||
| @@ -432,13 +432,13 @@ def _find_caller(stack_info=False): | |||||
| def _get_stack_info(frame): | def _get_stack_info(frame): | ||||
| """ | """ | ||||
| Get the stack informations. | |||||
| Get the stack information. | |||||
| Args: | Args: | ||||
| frame(frame): the frame requiring informations. | |||||
| frame(frame): the frame requiring information. | |||||
| Returns: | Returns: | ||||
| str, the string of the stack informations. | |||||
| str, the string of the stack information. | |||||
| """ | """ | ||||
| sinfo = None | sinfo = None | ||||
| stack_prefix = 'Stack (most recent call last):\n' | stack_prefix = 'Stack (most recent call last):\n' | ||||
| @@ -14,7 +14,6 @@ | |||||
| # ============================================================================ | # ============================================================================ | ||||
| """MindSpore Serving Master""" | """MindSpore Serving Master""" | ||||
| from mindspore_serving.worker import _check_version | |||||
| from ._master import start_grpc_server, start_restful_server, start_master_server, stop | from ._master import start_grpc_server, start_restful_server, start_master_server, stop | ||||
| __all__ = [] | __all__ = [] | ||||
| @@ -1,2 +1,4 @@ | |||||
| numpy>=1.17.0 | numpy>=1.17.0 | ||||
| protobuf>=3.8.0 | protobuf>=3.8.0 | ||||
| grpcio>=1.27.3 | |||||
| requests>=2.22.0 | |||||
| @@ -3,11 +3,7 @@ add_library(protobuf::libprotobuf ALIAS protobuf::protobuf) | |||||
| add_executable(protobuf::libprotoc ALIAS protobuf::protoc) | add_executable(protobuf::libprotoc ALIAS protobuf::protoc) | ||||
| set(_PROTOBUF_LIBPROTOBUF protobuf::libprotobuf) | set(_PROTOBUF_LIBPROTOBUF protobuf::libprotobuf) | ||||
| if(CMAKE_CROSSCOMPILING) | |||||
| find_program(_PROTOBUF_PROTOC protoc) | |||||
| else() | |||||
| set(_PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>) | |||||
| endif() | |||||
| set(_PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>) | |||||
| # Find gRPC installation | # Find gRPC installation | ||||
| # Looks for gRPCConfig.cmake file installed by gRPC's cmake installation. | # Looks for gRPCConfig.cmake file installed by gRPC's cmake installation. | ||||
| @@ -24,13 +20,8 @@ message(STATUS "Using gRPC ${gRPC_VERSION}") | |||||
| set(_GRPC_GRPCPP gRPC::grpc++) | set(_GRPC_GRPCPP gRPC::grpc++) | ||||
| set(_REFLECTION gRPC::grpc++_reflection) | set(_REFLECTION gRPC::grpc++_reflection) | ||||
| if(CMAKE_CROSSCOMPILING) | |||||
| find_program(_GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin) | |||||
| find_program(_GRPC_PYTHON_PLUGIN_EXECUTABLE grpc_python_plugin) | |||||
| else() | |||||
| set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_cpp_plugin>) | |||||
| set(_GRPC_PYTHON_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_python_plugin>) | |||||
| endif() | |||||
| set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_cpp_plugin>) | |||||
| set(_GRPC_PYTHON_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_python_plugin>) | |||||
| # Proto file | # Proto file | ||||
| # Generated sources | # Generated sources | ||||
| @@ -96,7 +87,7 @@ add_library(serving_ut_common STATIC ${UT_SERVING_COMMON}) | |||||
| target_link_libraries(serving_ut_common PRIVATE ${_REFLECTION} ${_GRPC_GRPCPP} ${_PROTOBUF_LIBPROTOBUF}) | target_link_libraries(serving_ut_common PRIVATE ${_REFLECTION} ${_GRPC_GRPCPP} ${_PROTOBUF_LIBPROTOBUF}) | ||||
| target_link_libraries(serving_ut_common PRIVATE mindspore_serving::event mindspore_serving::event_pthreads) | target_link_libraries(serving_ut_common PRIVATE mindspore_serving::event mindspore_serving::event_pthreads) | ||||
| target_link_libraries(serving_ut_common PRIVATE pthread mindspore::glog) | |||||
| target_link_libraries(serving_ut_common PRIVATE pthread mindspore_serving::glog) | |||||
| target_link_libraries(serving_ut_common PRIVATE ${SECUREC_LIBRARY}) | target_link_libraries(serving_ut_common PRIVATE ${SECUREC_LIBRARY}) | ||||
| # copy libevent lib | # copy libevent lib | ||||
| @@ -14,9 +14,12 @@ | |||||
| # limitations under the License. | # limitations under the License. | ||||
| # ============================================================================ | # ============================================================================ | ||||
| set -e | set -e | ||||
| BASEPATH=$(cd "$(dirname "$0")"; pwd) | |||||
| BASEPATH=$( | |||||
| cd "$(dirname "$0")" | |||||
| pwd | |||||
| ) | |||||
| PROJECT_PATH=${BASEPATH}/../../.. | PROJECT_PATH=${BASEPATH}/../../.. | ||||
| if [ $BUILD_PATH ];then | |||||
| if [ $BUILD_PATH ]; then | |||||
| echo "BUILD_PATH = $BUILD_PATH" | echo "BUILD_PATH = $BUILD_PATH" | ||||
| else | else | ||||
| BUILD_PATH=${PROJECT_PATH}/build | BUILD_PATH=${PROJECT_PATH}/build | ||||
| @@ -859,15 +859,26 @@ TEST_F(TestParseReply, test_reply_SUCCESS) { | |||||
| std::cout << "===start====" << std::endl; | std::cout << "===start====" << std::endl; | ||||
| for (auto &it : element.items()) { | for (auto &it : element.items()) { | ||||
| if (it.key() == "key_int") { | if (it.key() == "key_int") { | ||||
| ASSERT_EQ(it.value(), 1); | |||||
| ASSERT_TRUE(it.value().is_array()); | |||||
| ASSERT_EQ(it.value().size(), 1); | |||||
| auto array_items = it.value().items(); | |||||
| auto int_val = *(array_items.begin()); | |||||
| ASSERT_TRUE(int_val.value().is_number_integer()); | |||||
| ASSERT_EQ(int_val.value(), 1); | |||||
| count++; | count++; | ||||
| } else if (it.key() == "key_bool") { | } else if (it.key() == "key_bool") { | ||||
| ASSERT_TRUE(it.value().is_boolean()); | |||||
| ASSERT_EQ(it.value(), false); | ASSERT_EQ(it.value(), false); | ||||
| count++; | count++; | ||||
| } else if (it.key() == "key_float") { | } else if (it.key() == "key_float") { | ||||
| ASSERT_FLOAT_EQ(it.value(), 2.3); | |||||
| ASSERT_TRUE(it.value().is_array()); | |||||
| ASSERT_EQ(it.value().size(), 1); | |||||
| auto array_items = it.value().items(); | |||||
| auto float_val = *(array_items.begin()); | |||||
| ASSERT_FLOAT_EQ(float_val.value(), 2.3); | |||||
| count++; | count++; | ||||
| } else if (it.key() == "key_str") { | } else if (it.key() == "key_str") { | ||||
| ASSERT_TRUE(it.value().is_string()); | |||||
| ASSERT_EQ(it.value(), "ut_test"); | ASSERT_EQ(it.value(), "ut_test"); | ||||
| count++; | count++; | ||||
| } else if (it.key() == "key_bytes") { | } else if (it.key() == "key_bytes") { | ||||
| @@ -44,10 +44,12 @@ echo "LD_LIBRARY_PATH=LD_LIBRARY_PATH" | |||||
| unset http_proxy | unset http_proxy | ||||
| unset https_proxy | unset https_proxy | ||||
| cd - | |||||
| cd ${PROJECT_PATH}/tests/ut/python/tests/ | |||||
| if [ $# -gt 0 ]; then | if [ $# -gt 0 ]; then | ||||
| pytest -v ${PROJECT_PATH}/tests/ut/python/tests/ -k $1 | |||||
| pytest -v . -k "$1" | |||||
| else | else | ||||
| pytest -v ${PROJECT_PATH}/tests/ut/python/tests | |||||
| pytest -v . | |||||
| fi | fi | ||||
| RET=$? | RET=$? | ||||
| @@ -79,5 +79,43 @@ def serving_test(func): | |||||
| finally: | finally: | ||||
| master.stop() | master.stop() | ||||
| worker.stop() | worker.stop() | ||||
| servable_dir = os.path.join(os.getcwd(), "serving_python_ut_servables") | |||||
| rmtree(servable_dir, True) | |||||
| return wrap_test | return wrap_test | ||||
| def release_client(client): | |||||
| del client.stub | |||||
| client.stub = None | |||||
| # test servable_config.py with client | |||||
| servable_config_import = r""" | |||||
| import numpy as np | |||||
| from mindspore_serving.worker import register | |||||
| """ | |||||
| servable_config_declare_servable = r""" | |||||
| register.declare_servable(servable_file="tensor_add.mindir", model_format="MindIR", with_batch_dim=False) | |||||
| """ | |||||
| servable_config_preprocess_cast = r""" | |||||
| def add_trans_datatype(x1, x2): | |||||
| return x1.astype(np.float32), x2.astype(np.float32) | |||||
| """ | |||||
| servable_config_method_add_common = r""" | |||||
| @register.register_method(output_names=["y"]) | |||||
| def add_common(x1, x2): # only support float32 inputs | |||||
| y = register.call_servable(x1, x2) | |||||
| return y | |||||
| """ | |||||
| servable_config_method_add_cast = r""" | |||||
| @register.register_method(output_names=["y"]) | |||||
| def add_cast(x1, x2): | |||||
| x1, x2 = register.call_preprocess(add_trans_datatype, x1, x2) # cast input to float32 | |||||
| y = register.call_servable(x1, x2) | |||||
| return y | |||||
| """ | |||||
| @@ -0,0 +1,75 @@ | |||||
| # Copyright 2020 Huawei Technologies Co., Ltd | |||||
| # | |||||
| # 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. | |||||
| # ============================================================================ | |||||
| """test Serving, Common""" | |||||
| import json | |||||
| import requests | |||||
| import numpy as np | |||||
| def compare_float_value(expect, result): | |||||
| expect = np.array(expect) | |||||
| result = np.array(result) | |||||
| assert (np.abs(expect - result) < 0.001).all() | |||||
| def create_multi_instances_fp32(instance_count): | |||||
| instances = [] | |||||
| # instance 1 | |||||
| y_data_list = [] | |||||
| for i in range(instance_count): | |||||
| x1 = np.asarray([[1.1, 2.2], [3.3, 4.4]]).astype(np.float32) * (i + 1) | |||||
| x2 = np.asarray([[5.5, 6.6], [7.7, 8.8]]).astype(np.float32) * (i + 1) | |||||
| y_data_list.append(x1 + x2) | |||||
| instances.append({"x1": x1.tolist(), "x2": x2.tolist()}) | |||||
| return instances, y_data_list | |||||
| def create_multi_instances_int32_input_fp32_output(instance_count): | |||||
| instances = [] | |||||
| # instance 1 | |||||
| y_data_list = [] | |||||
| for i in range(instance_count): | |||||
| x1 = np.asarray([[1.1, 2.2], [3.3, 4.4]]).astype(np.int32) * (i + 1) | |||||
| x2 = np.asarray([[5.5, 6.6], [7.7, 8.8]]).astype(np.int32) * (i + 1) | |||||
| y_data_list.append((x1 + x2).astype(np.float32)) | |||||
| instances.append({"x1": x1.tolist(), "x2": x2.tolist()}) | |||||
| return instances, y_data_list | |||||
| def check_result(result, y_data_list, output_name="y"): | |||||
| result = result["instances"] | |||||
| assert len(result) == len(y_data_list) | |||||
| for result_item, expected_item in zip(result, y_data_list): | |||||
| result_item = np.array(result_item[output_name]) | |||||
| print("result", result_item) | |||||
| print("expect:", expected_item) | |||||
| assert result_item.shape == expected_item.shape | |||||
| assert (np.abs(result_item - expected_item) < 0.001).all() | |||||
| def post_restful(ip, restful_port, servable_name, method_name, json_instances, version_number=None): | |||||
| instances_map = {"instances": json_instances} | |||||
| post_payload = json.dumps(instances_map) | |||||
| print("request:", post_payload) | |||||
| if version_number is not None: | |||||
| request_url = f"http://{ip}:{restful_port}/model/{servable_name}/version/{version_number}:{method_name}" | |||||
| result = requests.post(request_url, data=post_payload) | |||||
| else: | |||||
| request_url = f"http://{ip}:{restful_port}/model/{servable_name}:{method_name}" | |||||
| result = requests.post(request_url, data=post_payload) | |||||
| print("result", result.text) | |||||
| result = json.loads(result.text) | |||||
| return result | |||||
| @@ -18,7 +18,9 @@ import numpy as np | |||||
| from mindspore_serving import master | from mindspore_serving import master | ||||
| from mindspore_serving import worker | from mindspore_serving import worker | ||||
| from mindspore_serving.client import Client | from mindspore_serving.client import Client | ||||
| from common import ServingTestBase, serving_test | |||||
| from common import ServingTestBase, serving_test, release_client | |||||
| from common import servable_config_import, servable_config_declare_servable, servable_config_preprocess_cast | |||||
| from common import servable_config_method_add_common, servable_config_method_add_cast | |||||
| def create_multi_instances_fp32(instance_count): | def create_multi_instances_fp32(instance_count): | ||||
| @@ -50,7 +52,7 @@ def test_master_worker_client_success(): | |||||
| instance_count = 3 | instance_count = 3 | ||||
| instances, y_data_list = create_multi_instances_fp32(instance_count) | instances, y_data_list = create_multi_instances_fp32(instance_count) | ||||
| result = client.infer(instances) | result = client.infer(instances) | ||||
| client.close() # avoid affecting the next use case | |||||
| release_client(client) | |||||
| print(result) | print(result) | ||||
| check_result(result, y_data_list) | check_result(result, y_data_list) | ||||
| @@ -63,11 +65,12 @@ def test_master_worker_client_multi_times_success(): | |||||
| worker.start_servable_in_master(base.servable_dir, base.servable_name, 0) | worker.start_servable_in_master(base.servable_dir, base.servable_name, 0) | ||||
| master.start_grpc_server("0.0.0.0", 5500) | master.start_grpc_server("0.0.0.0", 5500) | ||||
| # Client, use with avoid affecting the next use case | # Client, use with avoid affecting the next use case | ||||
| with Client("localhost", 5500, base.servable_name, "add_common") as client: | |||||
| for instance_count in range(1, 5): | |||||
| instances, y_data_list = create_multi_instances_fp32(instance_count) | |||||
| result = client.infer(instances) | |||||
| check_result(result, y_data_list) | |||||
| client = Client("localhost", 5500, base.servable_name, "add_common") | |||||
| for instance_count in range(1, 5): | |||||
| instances, y_data_list = create_multi_instances_fp32(instance_count) | |||||
| result = client.infer(instances) | |||||
| check_result(result, y_data_list) | |||||
| release_client(client) | |||||
| @serving_test | @serving_test | ||||
| @@ -78,10 +81,11 @@ def test_master_worker_client_alone_success(): | |||||
| master.start_grpc_server("0.0.0.0", 5500) | master.start_grpc_server("0.0.0.0", 5500) | ||||
| worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600) | worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600) | ||||
| # Client | # Client | ||||
| with Client("localhost", 5500, base.servable_name, "add_common") as client: | |||||
| instance_count = 3 | |||||
| instances, y_data_list = create_multi_instances_fp32(instance_count) | |||||
| result = client.infer(instances) | |||||
| client = Client("localhost", 5500, base.servable_name, "add_common") | |||||
| instance_count = 3 | |||||
| instances, y_data_list = create_multi_instances_fp32(instance_count) | |||||
| result = client.infer(instances) | |||||
| release_client(client) | |||||
| check_result(result, y_data_list) | check_result(result, y_data_list) | ||||
| @@ -93,11 +97,12 @@ def test_master_worker_client_alone_multi_times_success(): | |||||
| master.start_grpc_server("0.0.0.0", 5500) | master.start_grpc_server("0.0.0.0", 5500) | ||||
| worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600) | worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600) | ||||
| # Client, use with avoid affecting the next use case | # Client, use with avoid affecting the next use case | ||||
| with Client("localhost", 5500, base.servable_name, "add_common") as client: | |||||
| for instance_count in range(1, 5): | |||||
| instances, y_data_list = create_multi_instances_fp32(instance_count) | |||||
| result = client.infer(instances) | |||||
| check_result(result, y_data_list) | |||||
| client = Client("localhost", 5500, base.servable_name, "add_common") | |||||
| for instance_count in range(1, 5): | |||||
| instances, y_data_list = create_multi_instances_fp32(instance_count) | |||||
| result = client.infer(instances) | |||||
| check_result(result, y_data_list) | |||||
| release_client(client) | |||||
| @serving_test | @serving_test | ||||
| @@ -112,7 +117,7 @@ def test_master_worker_client_async_success(): | |||||
| instances, y_data_list = create_multi_instances_fp32(instance_count) | instances, y_data_list = create_multi_instances_fp32(instance_count) | ||||
| result_future = client.infer_async(instances) | result_future = client.infer_async(instances) | ||||
| result = result_future.result() | result = result_future.result() | ||||
| client.close() # avoid affecting the next use case | |||||
| release_client(client) # avoid affecting the next use case | |||||
| print(result) | print(result) | ||||
| check_result(result, y_data_list) | check_result(result, y_data_list) | ||||
| @@ -125,12 +130,13 @@ def test_master_worker_client_async_multi_times_success(): | |||||
| worker.start_servable_in_master(base.servable_dir, base.servable_name, 0) | worker.start_servable_in_master(base.servable_dir, base.servable_name, 0) | ||||
| master.start_grpc_server("0.0.0.0", 5500) | master.start_grpc_server("0.0.0.0", 5500) | ||||
| # Client, use with avoid affecting the next use case | # Client, use with avoid affecting the next use case | ||||
| with Client("localhost", 5500, base.servable_name, "add_common") as client: | |||||
| for instance_count in range(1, 5): | |||||
| instances, y_data_list = create_multi_instances_fp32(instance_count) | |||||
| result_future = client.infer_async(instances) | |||||
| result = result_future.result() | |||||
| check_result(result, y_data_list) | |||||
| client = Client("localhost", 5500, base.servable_name, "add_common") | |||||
| for instance_count in range(1, 5): | |||||
| instances, y_data_list = create_multi_instances_fp32(instance_count) | |||||
| result_future = client.infer_async(instances) | |||||
| result = result_future.result() | |||||
| check_result(result, y_data_list) | |||||
| release_client(client) | |||||
| @serving_test | @serving_test | ||||
| @@ -231,7 +237,7 @@ def test_master_worker_client_alone_repeat_grpc_and_restful_port_failed(): | |||||
| master.start_restful_server("0.0.0.0", 7600) | master.start_restful_server("0.0.0.0", 7600) | ||||
| assert False | assert False | ||||
| except RuntimeError as e: | except RuntimeError as e: | ||||
| assert "Serving Error: RESTful server start failed, create http listener faild, port" in str(e) | |||||
| assert "Serving Error: RESTful server start failed, create http listener failed, port" in str(e) | |||||
| @serving_test | @serving_test | ||||
| @@ -246,37 +252,6 @@ def test_master_worker_client_alone_repeat_grpc_and_restful_port2_failed(): | |||||
| assert "Serving Error: Serving gRPC server start failed, create server failed, address" in str(e) | assert "Serving Error: Serving gRPC server start failed, create server failed, address" in str(e) | ||||
| # test servable_config.py with client | |||||
| servable_config_import = r""" | |||||
| import numpy as np | |||||
| from mindspore_serving.worker import register | |||||
| """ | |||||
| servable_config_declare_servable = r""" | |||||
| register.declare_servable(servable_file="tensor_add.mindir", model_format="MindIR", with_batch_dim=False) | |||||
| """ | |||||
| servable_config_preprocess_cast = r""" | |||||
| def add_trans_datatype(x1, x2): | |||||
| return x1.astype(np.float32), x2.astype(np.float32) | |||||
| """ | |||||
| servable_config_method_add_common = r""" | |||||
| @register.register_method(output_names=["y"]) | |||||
| def add_common(x1, x2): # only support float32 inputs | |||||
| y = register.call_servable(x1, x2) | |||||
| return y | |||||
| """ | |||||
| servable_config_method_add_cast = r""" | |||||
| @register.register_method(output_names=["y"]) | |||||
| def add_cast(x1, x2): | |||||
| x1, x2 = register.call_preprocess(add_trans_datatype, x1, x2) # cast input to float32 | |||||
| y = register.call_servable(x1, x2) | |||||
| return y | |||||
| """ | |||||
| @serving_test | @serving_test | ||||
| def test_master_worker_client_servable_content_success(): | def test_master_worker_client_servable_content_success(): | ||||
| base = ServingTestBase() | base = ServingTestBase() | ||||
| @@ -292,8 +267,9 @@ def test_master_worker_client_servable_content_success(): | |||||
| # Client | # Client | ||||
| instance_count = 3 | instance_count = 3 | ||||
| instances, y_data_list = create_multi_instances_fp32(instance_count) | instances, y_data_list = create_multi_instances_fp32(instance_count) | ||||
| with Client("localhost", 5500, base.servable_name, "add_common") as client: | |||||
| result = client.infer(instances) | |||||
| client = Client("localhost", 5500, base.servable_name, "add_common") | |||||
| result = client.infer(instances) | |||||
| release_client(client) | |||||
| print(result) | print(result) | ||||
| check_result(result, y_data_list) | check_result(result, y_data_list) | ||||
| @@ -320,9 +296,9 @@ def add_cast(x1, x2): | |||||
| # Client | # Client | ||||
| instance_count = 3 | instance_count = 3 | ||||
| instances, _ = create_multi_instances_fp32(instance_count) | instances, _ = create_multi_instances_fp32(instance_count) | ||||
| # Client, use with avoid affecting the next use case | |||||
| with Client("localhost", 5500, base.servable_name, "add_cast") as client: | |||||
| result = client.infer(instances) | |||||
| client = Client("localhost", 5500, base.servable_name, "add_cast") | |||||
| result = client.infer(instances) | |||||
| release_client(client) | |||||
| print(result) | print(result) | ||||
| assert "Preprocess Failed" in str(result[0]["error"]) | assert "Preprocess Failed" in str(result[0]["error"]) | ||||
| @@ -349,9 +325,9 @@ def add_cast(x1, x2): | |||||
| # Client | # Client | ||||
| instance_count = 3 | instance_count = 3 | ||||
| instances, _ = create_multi_instances_fp32(instance_count) | instances, _ = create_multi_instances_fp32(instance_count) | ||||
| # Client, use with avoid affecting the next use case | |||||
| with Client("localhost", 5500, base.servable_name, "add_cast") as client: | |||||
| result = client.infer(instances) | |||||
| client = Client("localhost", 5500, base.servable_name, "add_cast") | |||||
| result = client.infer(instances) | |||||
| release_client(client) | |||||
| print(result) | print(result) | ||||
| assert "Postprocess Failed" in str(result[0]["error"]) | assert "Postprocess Failed" in str(result[0]["error"]) | ||||
| @@ -387,9 +363,9 @@ def add_cast(x1, x2, label): | |||||
| for i, instance in enumerate(instances): | for i, instance in enumerate(instances): | ||||
| instance["label"] = list_str[i] | instance["label"] = list_str[i] | ||||
| # Client, use with avoid affecting the next use case | |||||
| with Client("localhost", 5500, base.servable_name, "add_cast") as client: | |||||
| result = client.infer(instances) | |||||
| client = Client("localhost", 5500, base.servable_name, "add_cast") | |||||
| result = client.infer(instances) | |||||
| release_client(client) | |||||
| assert result[0]["text"] == "ABC123" | assert result[0]["text"] == "ABC123" | ||||
| assert result[1]["text"] == "DEF456" | assert result[1]["text"] == "DEF456" | ||||
| assert result[2]["text"] == "HIJ789" | assert result[2]["text"] == "HIJ789" | ||||
| @@ -426,9 +402,9 @@ def add_cast(x1, x2, label): | |||||
| for i, instance in enumerate(instances): | for i, instance in enumerate(instances): | ||||
| instance["label"] = str.encode(list_str[i]) | instance["label"] = str.encode(list_str[i]) | ||||
| # Client, use with avoid affecting the next use case | |||||
| with Client("localhost", 5500, base.servable_name, "add_cast") as client: | |||||
| result = client.infer(instances) | |||||
| client = Client("localhost", 5500, base.servable_name, "add_cast") | |||||
| result = client.infer(instances) | |||||
| release_client(client) | |||||
| assert bytes.decode(result[0]["text"]) == "ABC123" | assert bytes.decode(result[0]["text"]) == "ABC123" | ||||
| assert bytes.decode(result[1]["text"]) == "DEF456" | assert bytes.decode(result[1]["text"]) == "DEF456" | ||||
| assert bytes.decode(result[2]["text"]) == "HIJ789" | assert bytes.decode(result[2]["text"]) == "HIJ789" | ||||
| @@ -458,9 +434,9 @@ def add_cast(x1, x2, bool_val): | |||||
| for i, instance in enumerate(instances): | for i, instance in enumerate(instances): | ||||
| instance["bool_val"] = (i % 2 == 0) | instance["bool_val"] = (i % 2 == 0) | ||||
| # Client, use with avoid affecting the next use case | |||||
| with Client("localhost", 5500, base.servable_name, "add_cast") as client: | |||||
| result = client.infer(instances) | |||||
| client = Client("localhost", 5500, base.servable_name, "add_cast") | |||||
| result = client.infer(instances) | |||||
| release_client(client) | |||||
| assert not result[0]["value"] | assert not result[0]["value"] | ||||
| assert result[1]["value"] | assert result[1]["value"] | ||||
| assert not result[2]["value"] | assert not result[2]["value"] | ||||
| @@ -490,9 +466,9 @@ def add_cast(x1, x2, int_val): | |||||
| for i, instance in enumerate(instances): | for i, instance in enumerate(instances): | ||||
| instance["int_val"] = i * 2 | instance["int_val"] = i * 2 | ||||
| # Client, use with avoid affecting the next use case | |||||
| with Client("localhost", 5500, base.servable_name, "add_cast") as client: | |||||
| result = client.infer(instances) | |||||
| client = Client("localhost", 5500, base.servable_name, "add_cast") | |||||
| result = client.infer(instances) | |||||
| release_client(client) | |||||
| assert result[0]["value"] == 1 | assert result[0]["value"] == 1 | ||||
| assert result[1]["value"] == 3 | assert result[1]["value"] == 3 | ||||
| assert result[2]["value"] == 5 | assert result[2]["value"] == 5 | ||||
| @@ -522,9 +498,53 @@ def add_cast(x1, x2, float_val): | |||||
| for i, instance in enumerate(instances): | for i, instance in enumerate(instances): | ||||
| instance["float_val"] = i * 2.2 | instance["float_val"] = i * 2.2 | ||||
| # Client, use with avoid affecting the next use case | |||||
| with Client("localhost", 5500, base.servable_name, "add_cast") as client: | |||||
| result = client.infer(instances) | |||||
| client = Client("localhost", 5500, base.servable_name, "add_cast") | |||||
| result = client.infer(instances) | |||||
| release_client(client) | |||||
| assert result[0]["value"] == 1 | assert result[0]["value"] == 1 | ||||
| assert result[1]["value"] == (2.2 + 1) | assert result[1]["value"] == (2.2 + 1) | ||||
| assert result[2]["value"] == (4.4 + 1) | assert result[2]["value"] == (4.4 + 1) | ||||
| @serving_test | |||||
| def test_master_worker_client_preprocess_update_numpy_success(): | |||||
| base = ServingTestBase() | |||||
| servable_content = servable_config_import | |||||
| servable_content += servable_config_declare_servable | |||||
| servable_content += r""" | |||||
| def preprocess(x3): | |||||
| x3[0] = 123 | |||||
| return x3 | |||||
| def postprocess(x3, x4): | |||||
| return x3 + 1, x4 + 2 | |||||
| @register.register_method(output_names=["x3", "x4"]) | |||||
| def add_cast(x1, x2, x3): | |||||
| x4 = register.call_preprocess(preprocess, x3) # [123, 1, 1], expect x3 is x4, same as python function call | |||||
| y = register.call_servable(x1, x2) | |||||
| x3, x4 = register.call_postprocess(postprocess, x3, x4) | |||||
| return x3, x4 | |||||
| """ | |||||
| base.init_servable_with_servable_config(1, servable_content) | |||||
| worker.start_servable_in_master(base.servable_dir, base.servable_name) | |||||
| master.start_grpc_server("0.0.0.0", 5500) | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| for instance in instances: | |||||
| instance["x3"] = np.ones([3]) | |||||
| # Client, use with avoid affecting the next use case | |||||
| client = Client("localhost", 5500, base.servable_name, "add_cast") | |||||
| result = client.infer(instances) | |||||
| release_client(client) | |||||
| x3 = np.array([123, 1, 1]) + 1 | |||||
| x4 = np.array([123, 1, 1]) + 2 | |||||
| assert (result[0]["x3"] == x3).all() | |||||
| assert (result[1]["x3"] == x3).all() | |||||
| assert (result[2]["x3"] == x3).all() | |||||
| assert (result[0]["x4"] == x4).all() | |||||
| assert (result[1]["x4"] == x4).all() | |||||
| assert (result[2]["x4"] == x4).all() | |||||
| @@ -0,0 +1,949 @@ | |||||
| # Copyright 2020 Huawei Technologies Co., Ltd | |||||
| # | |||||
| # 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. | |||||
| # ============================================================================ | |||||
| """test Serving RESTful, with master, worker and client""" | |||||
| import base64 | |||||
| import numpy as np | |||||
| from common import ServingTestBase, serving_test | |||||
| from common import servable_config_import, servable_config_declare_servable | |||||
| from common_restful import create_multi_instances_fp32, check_result, post_restful | |||||
| from mindspore_serving import master | |||||
| from mindspore_serving import worker | |||||
| def start_str_restful_server(): | |||||
| base = ServingTestBase() | |||||
| servable_content = servable_config_import | |||||
| servable_content += servable_config_declare_servable | |||||
| servable_content += r""" | |||||
| index = 0 | |||||
| list_str = ["123", "456", "789"] | |||||
| def postprocess(y, label): | |||||
| global index | |||||
| text = list_str[index] | |||||
| index = (index + 1) if index + 1 < len(list_str) else 0 | |||||
| return y.astype(np.int32), label + text | |||||
| @register.register_method(output_names=["y", "text"]) | |||||
| def add_common(x1, x2, label): | |||||
| y = register.call_servable(x1, x2) | |||||
| y, text = register.call_postprocess(postprocess, y, label) | |||||
| return y, text | |||||
| def empty_postprocess(y, label): | |||||
| global index | |||||
| if len(label) == 0: | |||||
| text = list_str[index] | |||||
| else: | |||||
| text = "" | |||||
| index = (index + 1) if index + 1 < len(list_str) else 0 | |||||
| return y.astype(np.int32), text | |||||
| @register.register_method(output_names=["y", "text"]) | |||||
| def add_empty(x1, x2, label): | |||||
| y = register.call_servable(x1, x2) | |||||
| y, text = register.call_postprocess(empty_postprocess, y, label) | |||||
| return y, text | |||||
| """ | |||||
| base.init_servable_with_servable_config(1, servable_content) | |||||
| worker.start_servable_in_master(base.servable_dir, base.servable_name) | |||||
| master.start_restful_server("0.0.0.0", 5500) | |||||
| return base | |||||
| def start_bytes_restful_server(): | |||||
| base = ServingTestBase() | |||||
| servable_content = servable_config_import | |||||
| servable_content += servable_config_declare_servable | |||||
| servable_content += r""" | |||||
| index = 0 | |||||
| list_str = ["123", "456", "789"] | |||||
| def postprocess(y, label): | |||||
| global index | |||||
| label = bytes.decode(label.tobytes()) # bytes decode to str | |||||
| text = list_str[index] | |||||
| index = (index + 1) if index + 1 < len(list_str) else 0 | |||||
| return y.astype(np.int32), str.encode(label + text) # str encode to bytes | |||||
| @register.register_method(output_names=["y", "text"]) | |||||
| def add_common(x1, x2, label): | |||||
| y = register.call_servable(x1, x2) | |||||
| y, text = register.call_postprocess(postprocess, y, label) | |||||
| return y, text | |||||
| def empty_postprocess(y, label): | |||||
| global index | |||||
| label = bytes.decode(label.tobytes()) # bytes decode to str | |||||
| if len(label) == 0: | |||||
| text = list_str[index] | |||||
| else: | |||||
| text = "" | |||||
| index = (index + 1) if index + 1 < len(list_str) else 0 | |||||
| return y.astype(np.int32), str.encode(text) # str encode to bytes | |||||
| @register.register_method(output_names=["y", "text"]) | |||||
| def add_empty(x1, x2, label): | |||||
| y = register.call_servable(x1, x2) | |||||
| y, text = register.call_postprocess(empty_postprocess, y, label) | |||||
| return y, text | |||||
| """ | |||||
| base.init_servable_with_servable_config(1, servable_content) | |||||
| worker.start_servable_in_master(base.servable_dir, base.servable_name) | |||||
| master.start_restful_server("0.0.0.0", 5500) | |||||
| return base | |||||
| def start_bool_int_float_restful_server(): | |||||
| base = ServingTestBase() | |||||
| servable_content = servable_config_import | |||||
| servable_content += servable_config_declare_servable | |||||
| servable_content += r""" | |||||
| def bool_postprocess(y, bool_val): | |||||
| return y.astype(np.int32), ~bool_val | |||||
| @register.register_method(output_names=["y", "value"]) | |||||
| def add_bool(x1, x2, bool_val): | |||||
| y = register.call_servable(x1, x2) | |||||
| y, value = register.call_postprocess(bool_postprocess, y, bool_val) | |||||
| return y, value | |||||
| def int_postprocess(y, int_val): | |||||
| return y.astype(np.int32), int_val + 1 | |||||
| @register.register_method(output_names=["y", "value"]) | |||||
| def add_int(x1, x2, int_val): | |||||
| y = register.call_servable(x1, x2) | |||||
| y, value = register.call_postprocess(int_postprocess, y, int_val) | |||||
| return y, value | |||||
| def float_postprocess(y, float_val): | |||||
| value = float_val + 1 | |||||
| if value.dtype == np.float16: | |||||
| value = value.astype(np.float32) | |||||
| return y, value | |||||
| @register.register_method(output_names=["y", "value"]) | |||||
| def add_float(x1, x2, float_val): | |||||
| y = register.call_servable(x1, x2) | |||||
| y, value = register.call_postprocess(float_postprocess, y, float_val) | |||||
| return y, value | |||||
| """ | |||||
| base.init_servable_with_servable_config(1, servable_content) | |||||
| worker.start_servable_in_master(base.servable_dir, base.servable_name) | |||||
| master.start_restful_server("0.0.0.0", 5500) | |||||
| return base | |||||
| def common_test_restful_base64_str_scalar_input_output_success(shape): | |||||
| base = start_str_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| list_str = ["ABC", "DEF", "HIJ"] | |||||
| for i, instance in enumerate(instances): | |||||
| if shape is None: | |||||
| instance["label"] = {"b64": base64.b64encode(str.encode(list_str[i])).decode(), "type": "str"} | |||||
| else: | |||||
| instance["label"] = {"b64": base64.b64encode(str.encode(list_str[i])).decode(), "type": "str", | |||||
| 'shape': shape} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_common", instances) | |||||
| result = result["instances"] | |||||
| assert result[0]["text"] == "ABC123" | |||||
| assert result[1]["text"] == "DEF456" | |||||
| assert result[2]["text"] == "HIJ789" | |||||
| @serving_test | |||||
| def test_restful_base64_str_scalar_input_output_success(): | |||||
| common_test_restful_base64_str_scalar_input_output_success(shape=None) | |||||
| @serving_test | |||||
| def test_restful_base64_str_scalar_shape1_input_output_success(): | |||||
| common_test_restful_base64_str_scalar_input_output_success(shape=[1]) | |||||
| @serving_test | |||||
| def test_restful_base64_str_scalar_shape_empty_input_output_success(): | |||||
| common_test_restful_base64_str_scalar_input_output_success(shape=[]) | |||||
| @serving_test | |||||
| def test_restful_base64_empty_str_input_output_success(): | |||||
| base = start_str_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| list_str = ["ABC", "", "HIJ"] | |||||
| for i, instance in enumerate(instances): | |||||
| instance["label"] = {"b64": base64.b64encode(str.encode(list_str[i])).decode(), "type": "str"} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_empty", instances) | |||||
| result = result["instances"] | |||||
| assert result[0]["text"] == "" | |||||
| assert result[1]["text"] == "456" | |||||
| assert result[2]["text"] == "" | |||||
| @serving_test | |||||
| def test_restful_base64_str_scalar_invalid_shape0_input_failed(): | |||||
| base = start_str_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| list_str = ["ABC", "DEF", "HIJ"] | |||||
| for i, instance in enumerate(instances): | |||||
| instance["label"] = {"b64": base64.b64encode(str.encode(list_str[i])).decode(), "type": "str", "shape": [0]} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_common", instances) | |||||
| assert "only support scalar when data type is string or bytes, please check 'type' or 'shape'" \ | |||||
| in str(result["error_msg"]) | |||||
| @serving_test | |||||
| def test_restful_base64_str_scalar_invalid_shape_input_failed(): | |||||
| base = start_str_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| list_str = ["ABC", "DEF", "HIJ"] | |||||
| for i, instance in enumerate(instances): | |||||
| instance["label"] = {"b64": base64.b64encode(str.encode(list_str[i])).decode(), "type": "str", 'shape': [2]} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_common", instances) | |||||
| assert "json object, only support scalar when data type is string or bytes, please check 'type' or 'shape'" \ | |||||
| in str(result["error_msg"]) | |||||
| @serving_test | |||||
| def test_restful_base64_str_1d_array_failed(): | |||||
| base = start_str_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| list_str = ["ABC", "DEF", "HIJ"] | |||||
| for i, instance in enumerate(instances): | |||||
| instance["label"] = [{"b64": base64.b64encode(str.encode(list_str[i])).decode(), "type": "str"}, | |||||
| {"b64": base64.b64encode(str.encode(list_str[i])).decode(), "type": "str"}] | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_cast", instances) | |||||
| assert "json array, string or bytes type only support one item" in str(result["error_msg"]) | |||||
| def common_test_restful_bytes_input_output_success(shape): | |||||
| base = start_bytes_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| list_str = ["ABC", "DEF", "HIJ"] | |||||
| for i, instance in enumerate(instances): | |||||
| if shape is not None: | |||||
| instance["label"] = {"b64": base64.b64encode(str.encode(list_str[i])).decode(), "shape": shape} | |||||
| else: | |||||
| instance["label"] = {"b64": base64.b64encode(str.encode(list_str[i])).decode()} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_common", instances) | |||||
| result = result["instances"] | |||||
| b64_decode_to_str = lambda a: bytes.decode(base64.b64decode(a["b64"])) | |||||
| assert b64_decode_to_str(result[0]["text"]) == "ABC123" | |||||
| assert b64_decode_to_str(result[1]["text"]) == "DEF456" | |||||
| assert b64_decode_to_str(result[2]["text"]) == "HIJ789" | |||||
| @serving_test | |||||
| def test_restful_bytes_input_output_success(): | |||||
| common_test_restful_bytes_input_output_success(None) | |||||
| @serving_test | |||||
| def test_restful_bytes_empty_shape_success(): | |||||
| common_test_restful_bytes_input_output_success([]) | |||||
| @serving_test | |||||
| def test_restful_bytes_shape1_success(): | |||||
| common_test_restful_bytes_input_output_success([1]) | |||||
| @serving_test | |||||
| def test_restful_empty_bytes_input_output_success(): | |||||
| base = start_bytes_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| list_str = ["ABC", "", "HIJ"] | |||||
| for i, instance in enumerate(instances): | |||||
| instance["label"] = {"b64": base64.b64encode(str.encode(list_str[i])).decode()} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_empty", instances) | |||||
| result = result["instances"] | |||||
| b64_decode_to_str = lambda a: bytes.decode(base64.b64decode(a["b64"])) | |||||
| assert b64_decode_to_str(result[0]["text"]) == "" | |||||
| assert b64_decode_to_str(result[1]["text"]) == "456" | |||||
| assert b64_decode_to_str(result[2]["text"]) == "" | |||||
| @serving_test | |||||
| def test_restful_bytes_1d_array_failed(): | |||||
| base = start_bytes_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| list_str = ["ABC", "DEF", "HIJ"] | |||||
| for i, instance in enumerate(instances): | |||||
| instance["label"] = [{"b64": base64.b64encode(str.encode(list_str[i])).decode()}, | |||||
| {"b64": base64.b64encode(str.encode(list_str[i])).decode()}] | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_cast", instances) | |||||
| assert "json array, string or bytes type only support one item" in str(result["error_msg"]) | |||||
| @serving_test | |||||
| def test_restful_bytes_invalid_shape_input_failed(): | |||||
| base = start_bytes_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| list_str = ["ABC", "DEF", "HIJ"] | |||||
| for i, instance in enumerate(instances): | |||||
| instance["label"] = {"b64": base64.b64encode(str.encode(list_str[i])).decode(), 'shape': [0]} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_cast", instances) | |||||
| assert "only support scalar when data type is string or bytes, please check 'type' or 'shape'" \ | |||||
| in result["error_msg"] | |||||
| @serving_test | |||||
| def test_restful_base64_bool_scalar_input_output_success(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| for i, instance in enumerate(instances): | |||||
| val = np.int8(i % 2 == 0) | |||||
| instance["bool_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "bool"} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_bool", instances) | |||||
| result = result["instances"] | |||||
| assert not result[0]["value"] | |||||
| assert result[1]["value"] | |||||
| assert not result[2]["value"] | |||||
| @serving_test | |||||
| def test_restful_base64_bool_1d_array_input_output_success(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| for i, instance in enumerate(instances): | |||||
| val = [(i % 2 == 0)] * (i + 1) | |||||
| val = np.array(val) | |||||
| instance["bool_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "bool", "shape": [i + 1]} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_bool", instances) | |||||
| result = result["instances"] | |||||
| assert result[0]["value"] == [False] | |||||
| assert result[1]["value"] == [True, True] | |||||
| assert result[2]["value"] == [False, False, False] | |||||
| @serving_test | |||||
| def test_restful_base64_bool_2d_array_input_output_success(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| for i, instance in enumerate(instances): | |||||
| val = (i % 2 == 0) | |||||
| val = [[val] * (i + 1)] * (i + 1) | |||||
| val = np.array(val) | |||||
| instance["bool_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "bool", | |||||
| "shape": [i + 1, i + 1]} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_bool", instances) | |||||
| result = result["instances"] | |||||
| assert result[0]["value"] == [[False]] | |||||
| assert result[1]["value"] == [[True, True], [True, True]] | |||||
| assert result[2]["value"] == [[False, False, False], [False, False, False], [False, False, False]] | |||||
| @serving_test | |||||
| def test_restful_base64_int_scalar_input_output_success(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| for i, instance in enumerate(instances): | |||||
| val = np.int32(i * 2) | |||||
| instance["int_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "int32"} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_int", instances) | |||||
| result = result["instances"] | |||||
| assert result[0]["value"] == 1 | |||||
| assert result[1]["value"] == 3 | |||||
| assert result[2]["value"] == 5 | |||||
| @serving_test | |||||
| def test_restful_base64_int_1d_empty_input_output_success(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| for i, instance in enumerate(instances): | |||||
| if i % 2 == 0: | |||||
| val = [] | |||||
| else: | |||||
| val = [i * 2] * (i + 1) | |||||
| val = np.array(val).astype(np.int32) | |||||
| instance["int_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "int32", "shape": val.shape} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_int", instances) | |||||
| result = result["instances"] | |||||
| assert result[0]["value"] == [] | |||||
| assert result[1]["value"] == [3, 3] | |||||
| assert result[2]["value"] == [] | |||||
| @serving_test | |||||
| def test_restful_base64_int_2d_empty_input_output_success(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| for i, instance in enumerate(instances): | |||||
| if i % 2 == 0: | |||||
| val = [[]] | |||||
| else: | |||||
| val = [i * 2] * (i + 1) | |||||
| val = np.array(val).astype(np.int32) | |||||
| instance["int_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "int32", "shape": val.shape} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_int", instances) | |||||
| result = result["instances"] | |||||
| assert result[0]["value"] == [[]] | |||||
| assert result[1]["value"] == [3, 3] | |||||
| assert result[2]["value"] == [[]] | |||||
| @serving_test | |||||
| def test_restful_base64_int_2d_empty_invalid_shape_failed(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| for _, instance in enumerate(instances): | |||||
| val = [[]] | |||||
| val = np.array(val).astype(np.int32) | |||||
| instance["int_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "int32", "shape": [1, 2, 0, 1]} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_int", instances) | |||||
| assert "json object, key is 'shape', invalid shape value" in result["error_msg"] | |||||
| @serving_test | |||||
| def test_restful_base64_int_1d_array_input_output_success(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| for i, instance in enumerate(instances): | |||||
| val = i * 2 | |||||
| val = [val] * (i + 1) | |||||
| val = np.array(val).astype(np.int32) | |||||
| instance["int_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "int32", "shape": val.shape} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_int", instances) | |||||
| result = result["instances"] | |||||
| assert result[0]["value"] == [1] | |||||
| assert result[1]["value"] == [3, 3] | |||||
| assert result[2]["value"] == [5, 5, 5] | |||||
| def common_test_restful_base64_int_type_2d_array_input_output_success(dtype): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| dtype_str_map = {np.int8: "int8", np.int16: "int16", np.int32: "int32", np.int64: "int64"} | |||||
| assert dtype in dtype_str_map | |||||
| for i, instance in enumerate(instances): | |||||
| val = (i + 1) * 2 * (-1 if i % 2 == 0 else 1) # -2, 4, -6 | |||||
| val = [[val] * (i + 1)] * (i + 1) | |||||
| val = np.array(val).astype(dtype) | |||||
| instance["int_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': dtype_str_map[dtype], | |||||
| "shape": val.shape} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_int", instances) | |||||
| result = result["instances"] | |||||
| assert result[0]["value"] == [[-1]] | |||||
| assert result[1]["value"] == [[5, 5], [5, 5]] | |||||
| assert result[2]["value"] == [[-5, -5, -5], [-5, -5, -5], [-5, -5, -5]] | |||||
| @serving_test | |||||
| def test_restful_base64_int8_2d_array_input_output_success(): | |||||
| common_test_restful_base64_int_type_2d_array_input_output_success(np.int8) | |||||
| @serving_test | |||||
| def test_restful_base64_int16_2d_array_input_output_success(): | |||||
| common_test_restful_base64_int_type_2d_array_input_output_success(np.int16) | |||||
| @serving_test | |||||
| def test_restful_base64_int32_2d_array_input_output_success(): | |||||
| common_test_restful_base64_int_type_2d_array_input_output_success(np.int32) | |||||
| @serving_test | |||||
| def test_restful_base64_int64_2d_array_input_output_success(): | |||||
| common_test_restful_base64_int_type_2d_array_input_output_success(np.int64) | |||||
| def common_test_restful_base64_uint_type_2d_array_input_output_success(dtype): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| dtype_str_map = {np.uint8: "uint8", np.uint16: "uint16", np.uint32: "uint32", np.uint64: "uint64"} | |||||
| assert dtype in dtype_str_map | |||||
| for i, instance in enumerate(instances): | |||||
| val = i * 2 | |||||
| val = [[val] * (i + 1)] * (i + 1) | |||||
| val = np.array(val).astype(dtype) | |||||
| instance["int_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': dtype_str_map[dtype], | |||||
| "shape": val.shape} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_int", instances) | |||||
| result = result["instances"] | |||||
| assert result[0]["value"] == [[1]] | |||||
| assert result[1]["value"] == [[3, 3], [3, 3]] | |||||
| assert result[2]["value"] == [[5, 5, 5], [5, 5, 5], [5, 5, 5]] | |||||
| @serving_test | |||||
| def test_restful_base64_uint8_2d_array_input_output_success(): | |||||
| common_test_restful_base64_uint_type_2d_array_input_output_success(np.uint8) | |||||
| @serving_test | |||||
| def test_restful_base64_uint16_2d_array_input_output_success(): | |||||
| common_test_restful_base64_uint_type_2d_array_input_output_success(np.uint16) | |||||
| @serving_test | |||||
| def test_restful_base64_uint32_2d_array_input_output_success(): | |||||
| common_test_restful_base64_uint_type_2d_array_input_output_success(np.uint32) | |||||
| @serving_test | |||||
| def test_restful_base64_uint64_2d_array_input_output_success(): | |||||
| common_test_restful_base64_uint_type_2d_array_input_output_success(np.uint64) | |||||
| @serving_test | |||||
| def test_restful_base64_float_scalar_input_output_success(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| for i, instance in enumerate(instances): | |||||
| val = np.float32(i * 2.2) | |||||
| instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "fp32"} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_float", instances) | |||||
| result = result["instances"] | |||||
| assert result[0]["value"] == 1.0 | |||||
| assert abs(result[1]["value"] - (2.2 + 1)) < 0.001 | |||||
| assert abs(result[2]["value"] - (4.4 + 1)) < 0.001 | |||||
| @serving_test | |||||
| def test_restful_base64_float_1d_array_input_output_success(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| y_data_list = [] | |||||
| for i, instance in enumerate(instances): | |||||
| val = [i * 2.2 * (-1 if i % 2 == 0 else 1)] * (i + 1) # [0], [2.2, 2.2], [-4.4, -4.4, -4.4] | |||||
| val = np.array(val).astype(np.float32) | |||||
| y_data_list.append(val + 1) | |||||
| instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "fp32", 'shape': [i + 1]} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_float", instances) | |||||
| check_result(result, y_data_list, "value") | |||||
| def common_test_restful_base64_float_type_2d_array_input_output_success(dtype): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| dtype_str_map = {np.float16: "fp16", np.float32: "fp32", np.float64: "fp64"} | |||||
| assert dtype in dtype_str_map | |||||
| y_data_list = [] | |||||
| for i, instance in enumerate(instances): | |||||
| val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4 | |||||
| val = [[val] * (i + 1)] * (i + 1) | |||||
| val = np.array(val).astype(dtype) | |||||
| y_data_list.append(val + 1) | |||||
| instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': dtype_str_map[dtype], | |||||
| 'shape': [i + 1, i + 1]} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_float", instances) | |||||
| check_result(result, y_data_list, "value") | |||||
| @serving_test | |||||
| def test_restful_base64_float16_2d_array_input_output_success(): | |||||
| common_test_restful_base64_float_type_2d_array_input_output_success(np.float16) | |||||
| @serving_test | |||||
| def test_restful_base64_float32_2d_array_input_output_success(): | |||||
| common_test_restful_base64_float_type_2d_array_input_output_success(np.float32) | |||||
| @serving_test | |||||
| def test_restful_base64_float64_2d_array_input_output_success(): | |||||
| common_test_restful_base64_float_type_2d_array_input_output_success(np.float64) | |||||
| @serving_test | |||||
| def test_restful_base64_float16_2d_array_not_support_fp16_output_failed(): | |||||
| base = ServingTestBase() | |||||
| servable_content = servable_config_import | |||||
| servable_content += servable_config_declare_servable | |||||
| servable_content += r""" | |||||
| def postprocess(y, float_val): | |||||
| return y, float_val + 1 | |||||
| @register.register_method(output_names=["y", "value"]) | |||||
| def add_cast(x1, x2, float_val): | |||||
| y = register.call_servable(x1, x2) | |||||
| y, value = register.call_postprocess(postprocess, y, float_val) | |||||
| return y, value | |||||
| """ | |||||
| base.init_servable_with_servable_config(1, servable_content) | |||||
| worker.start_servable_in_master(base.servable_dir, base.servable_name) | |||||
| master.start_restful_server("0.0.0.0", 5500) | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| dtype = np.float16 | |||||
| dtype_str_map = {np.float16: "fp16", np.float32: "fp32", np.float64: "fp64"} | |||||
| assert dtype in dtype_str_map | |||||
| y_data_list = [] | |||||
| for i, instance in enumerate(instances): | |||||
| val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4 | |||||
| val = [[val] * (i + 1)] * (i + 1) | |||||
| val = np.array(val).astype(dtype) | |||||
| y_data_list.append(val + 1) | |||||
| instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': dtype_str_map[dtype], | |||||
| 'shape': [i + 1, i + 1]} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_cast", instances) | |||||
| assert "fp16 reply is not supported" in result["error_msg"] | |||||
| @serving_test | |||||
| def test_restful_base64_dtype_unknow_failed(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| dtype = np.float16 | |||||
| dtype_str_map = {np.float16: "fp16", np.float32: "fp32", np.float64: "fp64"} | |||||
| assert dtype in dtype_str_map | |||||
| y_data_list = [] | |||||
| for i, instance in enumerate(instances): | |||||
| val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4 | |||||
| val = [[val] * (i + 1)] * (i + 1) | |||||
| val = np.array(val).astype(dtype) | |||||
| y_data_list.append(val + 1) | |||||
| instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "dtype_unknow", | |||||
| 'shape': [i + 1, i + 1]} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_float", instances) | |||||
| assert "Parser request failed, json object, specified type:'dtype_unknow' is illegal" in result["error_msg"] | |||||
| @serving_test | |||||
| def test_restful_base64_dtype_empty_failed(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| dtype = np.float16 | |||||
| dtype_str_map = {np.float16: "fp16", np.float32: "fp32", np.float64: "fp64"} | |||||
| assert dtype in dtype_str_map | |||||
| y_data_list = [] | |||||
| for i, instance in enumerate(instances): | |||||
| val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4 | |||||
| val = [[val] * (i + 1)] * (i + 1) | |||||
| val = np.array(val).astype(dtype) | |||||
| y_data_list.append(val + 1) | |||||
| instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "", | |||||
| 'shape': [i + 1, i + 1]} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_float", instances) | |||||
| assert "Parser request failed, json object, specified type:'' is illegal" in result["error_msg"] | |||||
| @serving_test | |||||
| def test_restful_base64_float16_2d_array_shape_not_match1_large_failed(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| dtype = np.float16 | |||||
| dtype_str_map = {np.float16: "fp16", np.float32: "fp32", np.float64: "fp64"} | |||||
| assert dtype in dtype_str_map | |||||
| y_data_list = [] | |||||
| for i, instance in enumerate(instances): | |||||
| val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4 | |||||
| val = [[val] * (i + 1)] * (i + 1) | |||||
| val = np.array(val).astype(dtype) | |||||
| y_data_list.append(val + 1) | |||||
| instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': dtype_str_map[dtype], | |||||
| 'shape': [i + 2, i + 2]} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_float", instances) | |||||
| assert "Parser request failed, size is not matched" in result["error_msg"] | |||||
| @serving_test | |||||
| def test_restful_base64_float16_2d_array_shape_not_match2_small_failed(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| dtype = np.float16 | |||||
| dtype_str_map = {np.float16: "fp16", np.float32: "fp32", np.float64: "fp64"} | |||||
| assert dtype in dtype_str_map | |||||
| y_data_list = [] | |||||
| for i, instance in enumerate(instances): | |||||
| val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4 | |||||
| val = [[val] * (i + 2)] * (i + 2) | |||||
| val = np.array(val).astype(dtype) | |||||
| y_data_list.append(val + 1) | |||||
| instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': dtype_str_map[dtype], | |||||
| 'shape': [i + 1, i + 1]} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_float", instances) | |||||
| assert "Parser request failed, size is not matched" in result["error_msg"] | |||||
| @serving_test | |||||
| def test_restful_base64_float16_2d_array_shape_not_match3_small_failed(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| dtype = np.float16 | |||||
| dtype_str_map = {np.float16: "fp16", np.float32: "fp32", np.float64: "fp64"} | |||||
| assert dtype in dtype_str_map | |||||
| y_data_list = [] | |||||
| for i, instance in enumerate(instances): | |||||
| val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4 | |||||
| val = [[val] * (i + 2)] * (i + 2) | |||||
| val = np.array(val).astype(dtype) | |||||
| y_data_list.append(val + 1) | |||||
| instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': dtype_str_map[dtype], | |||||
| 'shape': [i + 2, i]} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_float", instances) | |||||
| assert "Parser request failed, size is not matched" in result["error_msg"] | |||||
| @serving_test | |||||
| def test_restful_base64_float16_2d_array_dtype_not_match4_empty_data_failed(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| dtype = np.float16 | |||||
| y_data_list = [] | |||||
| for i, instance in enumerate(instances): | |||||
| val = [[]] | |||||
| val = np.array(val).astype(dtype) | |||||
| y_data_list.append(val + 1) | |||||
| instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "fp16", | |||||
| 'shape': [i + 1, i + 1]} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_float", instances) | |||||
| assert "Parser request failed, size is not matched" in result["error_msg"] | |||||
| @serving_test | |||||
| def test_restful_base64_float16_2d_array_dtype_not_match5_empty_shape_failed(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| dtype = np.float16 | |||||
| y_data_list = [] | |||||
| for i, instance in enumerate(instances): | |||||
| val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4 | |||||
| val = [[val] * (i + 2)] * (i + 2) | |||||
| val = np.array(val).astype(dtype) | |||||
| y_data_list.append(val + 1) | |||||
| instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "fp16", | |||||
| 'shape': []} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_float", instances) | |||||
| assert "Parser request failed, size is not matched" in result["error_msg"] | |||||
| @serving_test | |||||
| def test_restful_base64_float16_2d_array_dtype_not_match6_empty_shape3_failed(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| dtype = np.float16 | |||||
| y_data_list = [] | |||||
| for i, instance in enumerate(instances): | |||||
| val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4 | |||||
| val = [[val] * (i + 2)] * (i + 2) | |||||
| val = np.array(val).astype(dtype) | |||||
| y_data_list.append(val + 1) | |||||
| instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "fp16"} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_float", instances) | |||||
| assert "Parser request failed, size is not matched" in result["error_msg"] | |||||
| @serving_test | |||||
| def test_restful_base64_float16_2d_array_dtype_not_match_failed(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| dtype = np.float16 | |||||
| y_data_list = [] | |||||
| for i, instance in enumerate(instances): | |||||
| val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4 | |||||
| val = [[val] * (i + 2)] * (i + 2) | |||||
| val = np.array(val).astype(dtype) | |||||
| y_data_list.append(val + 1) | |||||
| instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "fp32", | |||||
| 'shape': [i + 2, i + 2]} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_float", instances) | |||||
| assert "Parser request failed, size is not matched" in result["error_msg"] | |||||
| @serving_test | |||||
| def test_restful_base64_float16_2d_array_invalid_shape_2d_shape_failed(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| dtype = np.float16 | |||||
| y_data_list = [] | |||||
| for i, instance in enumerate(instances): | |||||
| val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4 | |||||
| val = [[val] * (i + 2)] * (i + 2) | |||||
| val = np.array(val).astype(dtype) | |||||
| y_data_list.append(val + 1) | |||||
| instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "fp16", "shape": [[]]} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_float", instances) | |||||
| assert "json object, key is 'shape', array value should be unsigned integer" in result["error_msg"] | |||||
| @serving_test | |||||
| def test_restful_base64_float16_2d_array_invalid_shape2_str_shape_failed(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| dtype = np.float16 | |||||
| y_data_list = [] | |||||
| for i, instance in enumerate(instances): | |||||
| val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4 | |||||
| val = [[val] * (i + 2)] * (i + 2) | |||||
| val = np.array(val).astype(dtype) | |||||
| y_data_list.append(val + 1) | |||||
| instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "fp16", "shape": ["abc"]} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_float", instances) | |||||
| assert "json object, key is 'shape', array value should be unsigned integer" in result["error_msg"] | |||||
| @serving_test | |||||
| def test_restful_base64_float16_2d_array_invalid_shape3_float_shape_failed(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| dtype = np.float16 | |||||
| y_data_list = [] | |||||
| for i, instance in enumerate(instances): | |||||
| val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4 | |||||
| val = [[val] * (i + 2)] * (i + 2) | |||||
| val = np.array(val).astype(dtype) | |||||
| y_data_list.append(val + 1) | |||||
| instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "fp16", "shape": [1.1]} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_float", instances) | |||||
| assert "json object, key is 'shape', array value should be unsigned integer" in result["error_msg"] | |||||
| @serving_test | |||||
| def test_restful_base64_float16_2d_array_invalid_shape4_negative_shape_failed(): | |||||
| base = start_bool_int_float_restful_server() | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| dtype = np.float16 | |||||
| y_data_list = [] | |||||
| for i, instance in enumerate(instances): | |||||
| val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4 | |||||
| val = [[val] * (i + 2)] * (i + 2) | |||||
| val = np.array(val).astype(dtype) | |||||
| y_data_list.append(val + 1) | |||||
| instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "fp16", "shape": [-1]} | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_float", instances) | |||||
| assert "json object, key is 'shape', array value should be unsigned integer" in result["error_msg"] | |||||
| @@ -0,0 +1,335 @@ | |||||
| # Copyright 2020 Huawei Technologies Co., Ltd | |||||
| # | |||||
| # 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. | |||||
| # ============================================================================ | |||||
| """test Serving RESTful, with master, worker and client""" | |||||
| import json | |||||
| import requests | |||||
| from mindspore_serving import master | |||||
| from mindspore_serving import worker | |||||
| from common import ServingTestBase, serving_test | |||||
| from common import servable_config_import, servable_config_declare_servable | |||||
| from common_restful import create_multi_instances_fp32, check_result, post_restful | |||||
| from common_restful import create_multi_instances_int32_input_fp32_output | |||||
| @serving_test | |||||
| def test_restful_request_success(): | |||||
| base = ServingTestBase() | |||||
| base.init_servable(1, "add_servable_config.py") | |||||
| worker.start_servable_in_master(base.servable_dir, base.servable_name, 0) | |||||
| master.start_restful_server("0.0.0.0", 5500) | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, y_data_list = create_multi_instances_fp32(instance_count) | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_common", instances) | |||||
| check_result(result, y_data_list) | |||||
| @serving_test | |||||
| def test_restful_request_multi_times_success(): | |||||
| base = ServingTestBase() | |||||
| base.init_servable(1, "add_servable_config.py") | |||||
| worker.start_servable_in_master(base.servable_dir, base.servable_name, 0) | |||||
| master.start_restful_server("0.0.0.0", 5500) | |||||
| for instance_count in range(1, 5): | |||||
| instances, y_data_list = create_multi_instances_fp32(instance_count) | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_common", instances) | |||||
| check_result(result, y_data_list) | |||||
| @serving_test | |||||
| def test_restful_request_multi_times_int32_success(): | |||||
| base = ServingTestBase() | |||||
| base.init_servable(1, "add_servable_config.py") | |||||
| worker.start_servable_in_master(base.servable_dir, base.servable_name, 0) | |||||
| master.start_restful_server("0.0.0.0", 5500) | |||||
| for instance_count in range(1, 5): | |||||
| instances, y_data_list = create_multi_instances_int32_input_fp32_output(instance_count) | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_cast", instances) | |||||
| check_result(result, y_data_list) | |||||
| @serving_test | |||||
| def test_restful_request_worker_alone_success(): | |||||
| base = ServingTestBase() | |||||
| base.init_servable(1, "add_servable_config.py") | |||||
| master.start_master_server(master_port=7600) | |||||
| master.start_restful_server("0.0.0.0", 5500) | |||||
| worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600) | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, y_data_list = create_multi_instances_fp32(instance_count) | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_common", instances) | |||||
| check_result(result, y_data_list) | |||||
| @serving_test | |||||
| def test_restful_request_worker_alone_multi_times_success(): | |||||
| base = ServingTestBase() | |||||
| base.init_servable(1, "add_servable_config.py") | |||||
| master.start_master_server(master_port=7600) | |||||
| master.start_restful_server("0.0.0.0", 5500) | |||||
| worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600) | |||||
| # Client | |||||
| for instance_count in range(1, 5): | |||||
| instances, y_data_list = create_multi_instances_fp32(instance_count) | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_common", instances) | |||||
| check_result(result, y_data_list) | |||||
| @serving_test | |||||
| def test_restful_request_worker_alone_servable_invalid_failed(): | |||||
| base = ServingTestBase() | |||||
| base.init_servable(1, "add_servable_config.py") | |||||
| master.start_master_server(master_port=7600) | |||||
| master.start_restful_server("0.0.0.0", 5500) | |||||
| worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600) | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| result = post_restful("localhost", 5500, base.servable_name + "_error", "add_common", instances) | |||||
| assert "servable is not available" in str(result["error_msg"]) | |||||
| @serving_test | |||||
| def test_restful_request_worker_alone_method_invalid_failed(): | |||||
| base = ServingTestBase() | |||||
| base.init_servable(1, "add_servable_config.py") | |||||
| master.start_master_server(master_port=7600) | |||||
| master.start_restful_server("0.0.0.0", 5500) | |||||
| worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600) | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_common" + "_error", instances) | |||||
| assert "method is not available" in str(result["error_msg"]) | |||||
| @serving_test | |||||
| def test_restful_request_worker_alone_with_version_number_0_success(): | |||||
| base = ServingTestBase() | |||||
| base.init_servable(1, "add_servable_config.py") | |||||
| master.start_master_server(master_port=7600) | |||||
| master.start_restful_server("0.0.0.0", 5500) | |||||
| worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600) | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, y_data_list = create_multi_instances_fp32(instance_count) | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_common", instances, 0) | |||||
| check_result(result, y_data_list) | |||||
| @serving_test | |||||
| def test_restful_request_worker_alone_with_version_number_1_success(): | |||||
| base = ServingTestBase() | |||||
| base.init_servable(1, "add_servable_config.py") | |||||
| master.start_master_server(master_port=7600) | |||||
| master.start_restful_server("0.0.0.0", 5500) | |||||
| worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600) | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, y_data_list = create_multi_instances_fp32(instance_count) | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_common", instances, 1) | |||||
| check_result(result, y_data_list) | |||||
| @serving_test | |||||
| def test_restful_request_worker_alone_with_version_number_2_invalid_failed(): | |||||
| base = ServingTestBase() | |||||
| base.init_servable(1, "add_servable_config.py") | |||||
| master.start_master_server(master_port=7600) | |||||
| master.start_restful_server("0.0.0.0", 5500) | |||||
| worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600) | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_common", instances, 2) | |||||
| assert "servable is not available" in str(result["error_msg"]) | |||||
| @serving_test | |||||
| def test_restful_request_worker_alone_version_number_negative_failed(): | |||||
| base = ServingTestBase() | |||||
| base.init_servable(1, "add_servable_config.py") | |||||
| master.start_master_server(master_port=7600) | |||||
| master.start_restful_server("0.0.0.0", 5500) | |||||
| worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600) | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_common", instances, -1) | |||||
| assert "please check url, version number range failed" in str(result["error_msg"]) | |||||
| @serving_test | |||||
| def test_restful_request_worker_alone_without_model_invalid_failed(): | |||||
| base = ServingTestBase() | |||||
| base.init_servable(1, "add_servable_config.py") | |||||
| master.start_master_server(master_port=7600) | |||||
| master.start_restful_server("0.0.0.0", 5500) | |||||
| worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600) | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| instances_map = {"instances": instances} | |||||
| post_payload = json.dumps(instances_map) | |||||
| print("request:", post_payload) | |||||
| request_url = f"http://localhost:5500/x/:add_common" | |||||
| result = requests.post(request_url, data=post_payload) | |||||
| print("result", result.text) | |||||
| result = json.loads(result.text) | |||||
| assert "please check url, the keyword:[model] must contain" in str(result["error_msg"]) | |||||
| @serving_test | |||||
| def test_restful_request_worker_alone_without_method_invalid_failed(): | |||||
| base = ServingTestBase() | |||||
| base.init_servable(1, "add_servable_config.py") | |||||
| master.start_master_server(master_port=7600) | |||||
| master.start_restful_server("0.0.0.0", 5500) | |||||
| worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600) | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| instances_map = {"instances": instances} | |||||
| post_payload = json.dumps(instances_map) | |||||
| print("request:", post_payload) | |||||
| request_url = f"http://localhost:5500/model/{base.servable_name}" | |||||
| result = requests.post(request_url, data=post_payload) | |||||
| print("result", result.text) | |||||
| result = json.loads(result.text) | |||||
| assert "please check url, the keyword:[service method] must contain." in str(result["error_msg"]) | |||||
| @serving_test | |||||
| def test_restful_request_without_method_invalid_failed(): | |||||
| base = ServingTestBase() | |||||
| base.init_servable(1, "add_servable_config.py") | |||||
| master.start_master_server(master_port=7600) | |||||
| master.start_restful_server("0.0.0.0", 5500) | |||||
| worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600) | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| instances_map = {"instances": instances} | |||||
| post_payload = json.dumps(instances_map) | |||||
| print("request:", post_payload) | |||||
| request_url = f"http://localhost:5500/model/{base.servable_name}" | |||||
| result = requests.post(request_url, data=post_payload) | |||||
| print("result", result.text) | |||||
| result = json.loads(result.text) | |||||
| assert "please check url, the keyword:[service method] must contain." in str(result["error_msg"]) | |||||
| @serving_test | |||||
| def test_restful_request_worker_alone_servable_version_reverse_success(): | |||||
| base = ServingTestBase() | |||||
| base.init_servable(1, "add_servable_config.py") | |||||
| master.start_master_server(master_port=7600) | |||||
| master.start_restful_server("0.0.0.0", 5500) | |||||
| worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600) | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, y_data_list = create_multi_instances_fp32(instance_count) | |||||
| instances_map = {"instances": instances} | |||||
| post_payload = json.dumps(instances_map) | |||||
| print("request:", post_payload) | |||||
| request_url = f"http://localhost:5500/version/0/model/{base.servable_name}:add_common" | |||||
| result = requests.post(request_url, data=post_payload) | |||||
| print("result", result.text) | |||||
| result = json.loads(result.text) | |||||
| check_result(result, y_data_list) | |||||
| @serving_test | |||||
| def test_restful_request_preprocess_outputs_count_not_match_failed(): | |||||
| base = ServingTestBase() | |||||
| servable_content = servable_config_import | |||||
| servable_content += servable_config_declare_servable | |||||
| servable_content += r""" | |||||
| def add_trans_datatype(x1, x2): | |||||
| return x1.astype(np.float32) | |||||
| @register.register_method(output_names=["y"]) | |||||
| def add_cast(x1, x2): | |||||
| x1, x2 = register.call_preprocess(add_trans_datatype, x1, x2) # cast input to float32 | |||||
| y = register.call_servable(x1, x2) | |||||
| return y | |||||
| """ | |||||
| base.init_servable_with_servable_config(1, servable_content) | |||||
| worker.start_servable_in_master(base.servable_dir, base.servable_name) | |||||
| master.start_restful_server("0.0.0.0", 5500) | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_cast", instances) | |||||
| print(result) | |||||
| assert "Preprocess Failed" in str(result["instances"][0]["error_msg"]) | |||||
| @serving_test | |||||
| def test_restful_request_postprocess_outputs_count_not_match_failed(): | |||||
| base = ServingTestBase() | |||||
| servable_content = servable_config_import | |||||
| servable_content += servable_config_declare_servable | |||||
| servable_content += r""" | |||||
| def add_trans_datatype(x1, x2): | |||||
| return x1.astype(np.float32) | |||||
| @register.register_method(output_names=["y"]) | |||||
| def add_cast(x1, x2): | |||||
| y = register.call_servable(x1, x2) | |||||
| y, y2 = register.call_postprocess(add_trans_datatype, y, x2) | |||||
| return y | |||||
| """ | |||||
| base.init_servable_with_servable_config(1, servable_content) | |||||
| worker.start_servable_in_master(base.servable_dir, base.servable_name) | |||||
| master.start_restful_server("0.0.0.0", 5500) | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| result = post_restful("localhost", 5500, base.servable_name, "add_cast", instances) | |||||
| assert "Postprocess Failed" in str(result["instances"][0]["error_msg"]) | |||||
| @serving_test | |||||
| def test_restful_request_worker_alone_outputs_count_not_match_failed(): | |||||
| base = ServingTestBase() | |||||
| servable_content = servable_config_import | |||||
| servable_content += servable_config_declare_servable | |||||
| servable_content += r""" | |||||
| def add_trans_datatype(x1, x2): | |||||
| return x1.astype(np.float32) | |||||
| @register.register_method(output_names=["y"]) | |||||
| def add_cast(x1, x2): | |||||
| y = register.call_servable(x1, x2) | |||||
| y, y2 = register.call_postprocess(add_trans_datatype, y, x2) | |||||
| return y | |||||
| """ | |||||
| base.init_servable_with_servable_config(1, servable_content) | |||||
| master.start_master_server(master_port=7600) | |||||
| master.start_restful_server("0.0.0.0", 5500) | |||||
| worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600) | |||||
| # Client | |||||
| instance_count = 3 | |||||
| instances, _ = create_multi_instances_fp32(instance_count) | |||||
| result = post_restful("localhost", 5500, base.servable_name + "_error", "add_common", instances) | |||||
| assert "servable is not available" in str(result["error_msg"]) | |||||