Skip to content

Commit

Permalink
Fixed passing of generation config params to VLM generate. (#1180)
Browse files Browse the repository at this point in the history
- Fixed passing of generation config params to VLM generate().
- Updated generation config params params list in
`update_config_from_kwargs()` method.

Ticket: CVS-157050

---------

Co-authored-by: Ilya Lavrenov <[email protected]>
  • Loading branch information
popovaan and ilya-lavrenov authored Nov 20, 2024
1 parent 6cd66d0 commit cd05c8e
Show file tree
Hide file tree
Showing 13 changed files with 220 additions and 282 deletions.
2 changes: 1 addition & 1 deletion src/cpp/include/openvino/genai/generation_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ static constexpr ov::Property<bool> ignore_eos{"ignore_eos"};
static constexpr ov::Property<size_t> min_new_tokens{"min_new_tokens"};
static constexpr ov::Property<std::vector<std::string>> stop_strings{"stop_strings"};
static constexpr ov::Property<bool> include_stop_str_in_output{"include_stop_str_in_output"};
static constexpr ov::Property<std::vector<std::vector<int64_t>>> stop_token_ids{"stop_token_ids"};
static constexpr ov::Property<std::set<int64_t>> stop_token_ids{"stop_token_ids"};

static constexpr ov::Property<size_t> num_beam_groups{"num_beam_groups"};
static constexpr ov::Property<size_t> num_beams{"num_beams"};
Expand Down
7 changes: 7 additions & 0 deletions src/cpp/src/llm_pipeline_static.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,13 @@ template <typename T>
T pop_or_default(ov::AnyMap& config, const std::string& key, const T& default_value) {
auto anyopt = pop_option(config, key);
if (anyopt.has_value()) {
if (anyopt.value().empty()) {
if (ov::genai::utils::is_container<T>)
return T{};
else {
OPENVINO_THROW("Got empty ov::Any for key: " + key);
}
}
return anyopt.value().as<T>();
}
return default_value;
Expand Down
22 changes: 21 additions & 1 deletion src/cpp/src/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

#pragma once
#include <type_traits>

#include "openvino/genai/llm_pipeline.hpp"
#include "openvino/runtime/core.hpp"
Expand All @@ -12,6 +13,16 @@ namespace ov {
namespace genai {
namespace utils {

// Variable template that checks if a type has begin() and end() member functions
template<typename, typename = void>
constexpr bool is_container = false;

template<typename T>
constexpr bool is_container<T,
std::void_t<decltype(std::declval<T>().begin()),
decltype(std::declval<T>().end())>> = true;


Tensor init_attention_mask(const Tensor& position_ids);

void print_tensor(const ov::Tensor& tensor);
Expand All @@ -31,7 +42,16 @@ template <typename T>
void read_anymap_param(const ov::AnyMap& config_map, const std::string& name, T& param) {
auto it = config_map.find(name);
if (it != config_map.end()) {
param = it->second.as<typename OmitOptional<T>::value>();
if (it->second.empty()) {
if (ov::genai::utils::is_container<T>)
param = T{};
else {
OPENVINO_THROW("Got empty ov::Any for parameter name: " + name);
}
}
else {
param = it->second.as<typename OmitOptional<T>::value>();
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/python/openvino_genai/py_openvino_genai.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -1296,7 +1296,7 @@ class Tokenizer:
openvino_genai.Tokenizer object is used to initialize Tokenizer
if it's located in a different path than the main model.
"""
def __init__(self, tokenizer_path: os.PathLike, properties: dict[str, typing.Any] = {}) -> None:
def __init__(self, tokenizer_path: os.PathLike, properties: dict[str, typing.Any] = {}, **kwargs) -> None:
...
def apply_chat_template(self, history: list[dict[str, str]], add_generation_prompt: bool, chat_template: str = '') -> str:
"""
Expand Down
108 changes: 3 additions & 105 deletions src/python/py_image_generation_pipelines.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,108 +67,6 @@ auto text2image_generate_docstring = R"(
)";


void update_image_generation_config_from_kwargs(
ov::genai::ImageGenerationConfig& config,
const py::kwargs& kwargs) {
for (const auto& item : kwargs) {
std::string key = py::cast<std::string>(item.first);
py::object value = py::cast<py::object>(item.second);

if (key == "prompt_2") {
config.prompt_2 = py::cast<std::string>(value);
} else if (key == "prompt_3") {
config.prompt_3 = py::cast<std::string>(value);
} else if (key == "negative_prompt") {
config.negative_prompt = py::cast<std::string>(value);
} else if (key == "negative_prompt_2") {
config.negative_prompt_2 = py::cast<std::string>(value);
} else if (key == "negative_prompt_3") {
config.negative_prompt_3 = py::cast<std::string>(value);
} else if (key == "num_images_per_prompt") {
config.num_images_per_prompt = py::cast<size_t>(value);
} else if (key == "guidance_scale") {
config.guidance_scale = py::cast<float>(value);
} else if (key == "height") {
config.height = py::cast<int64_t>(value);
} else if (key == "width") {
config.width = py::cast<int64_t>(value);
} else if (key == "num_inference_steps") {
config.num_inference_steps = py::cast<size_t>(value);
} else if (key == "generator") {
auto py_generator = py::cast<std::shared_ptr<ov::genai::Generator>>(value);
config.generator = py_generator;
} else if (key == "adapters") {
config.adapters = py::cast<ov::genai::AdapterConfig>(value);
} else if (key == "strength") {
config.strength = py::cast<float>(value);
} else if (key == "max_sequence_length") {
config.max_sequence_length = py::cast<size_t>(value);
} else {
throw(std::invalid_argument("'" + key + "' is unexpected parameter name. "
"Use help(openvino_genai.ImageGenerationConfig) to get list of acceptable parameters."));
}
}
}

ov::AnyMap text2image_kwargs_to_any_map(const py::kwargs& kwargs, bool allow_compile_properties=true) {
ov::AnyMap params = {};

for (const auto& item : kwargs) {
std::string key = py::cast<std::string>(item.first);
py::object value = py::cast<py::object>(item.second);

if (key == "prompt_2") {
params.insert({ov::genai::prompt_2(std::move(py::cast<std::string>(value)))});
} else if (key == "prompt_3") {
params.insert({ov::genai::prompt_3(std::move(py::cast<std::string>(value)))});
} else if (key == "negative_prompt") {
params.insert({ov::genai::negative_prompt(std::move(py::cast<std::string>(value)))});
} else if (key == "negative_prompt_2") {
params.insert({ov::genai::negative_prompt_2(std::move(py::cast<std::string>(value)))});
} else if (key == "negative_prompt_3") {
params.insert({ov::genai::negative_prompt_3(std::move(py::cast<std::string>(value)))});
} else if (key == "num_images_per_prompt") {
params.insert({ov::genai::num_images_per_prompt(std::move(py::cast<size_t>(value)))});
} else if (key == "guidance_scale") {
params.insert({ov::genai::guidance_scale(std::move(py::cast<float>(value)))});
} else if (key == "height") {
params.insert({ov::genai::height(std::move(py::cast<int64_t>(value)))});
} else if (key == "width") {
params.insert({ov::genai::width(std::move(py::cast<int64_t>(value)))});
} else if (key == "num_inference_steps") {
params.insert({ov::genai::num_inference_steps(std::move(py::cast<size_t>(value)))});
} else if (key == "generator") {
auto py_generator =py::cast<std::shared_ptr<ov::genai::Generator>>(value);
params.insert({ov::genai::generator(std::move(py_generator))});
} else if (key == "adapters") {
params.insert({ov::genai::adapters(std::move(py::cast<ov::genai::AdapterConfig>(value)))});
} else if (key == "strength") {
params.insert({ov::genai::strength(std::move(py::cast<float>(value)))});
} else if (key == "max_sequence_length") {
params.insert({ov::genai::max_sequence_length(std::move(py::cast<size_t>(value)))});
} else if (key == "callback") {
params.insert({ov::genai::callback(std::move(py::cast<std::function<bool(size_t, ov::Tensor&)>>(value)))});
}
else {
if (allow_compile_properties) {
// convert arbitrary objects to ov::Any
// not supported properties are not checked, as these properties are passed to compile(), which will throw exception in case of unsupported property
if (pyutils::py_object_is_any_map(value)) {
auto map = pyutils::py_object_to_any_map(value);
params.insert(map.begin(), map.end());
} else {
params[key] = pyutils::py_object_to_any(value);
}
}
else {
// generate doesn't run compile(), so only Text2ImagePipeline specific properties are allowed
throw(std::invalid_argument("'" + key + "' is unexpected parameter name. "
"Use help(openvino_genai.Text2ImagePipeline.generate) to get list of acceptable parameters."));
}
}
}
return params;
}

} // namespace

Expand Down Expand Up @@ -230,7 +128,7 @@ void init_image_generation_pipelines(py::module_& m) {
.def("update_generation_config", [](
ov::genai::ImageGenerationConfig config,
const py::kwargs& kwargs) {
update_image_generation_config_from_kwargs(config, kwargs);
config.update_generation_config(pyutils::kwargs_to_any_map(kwargs));
});

auto text2image_pipeline = py::class_<ov::genai::Text2ImagePipeline>(m, "Text2ImagePipeline", "This class is used for generation with text-to-image models.")
Expand All @@ -252,7 +150,7 @@ void init_image_generation_pipelines(py::module_& m) {
const py::kwargs& kwargs
) {
ScopedVar env_manager(pyutils::ov_tokenizers_module_path());
return std::make_unique<ov::genai::Text2ImagePipeline>(models_path, device, text2image_kwargs_to_any_map(kwargs, true));
return std::make_unique<ov::genai::Text2ImagePipeline>(models_path, device, pyutils::kwargs_to_any_map(kwargs));
}),
py::arg("models_path"), "folder with exported model files.",
py::arg("device"), "device on which inference will be done",
Expand Down Expand Up @@ -289,7 +187,7 @@ void init_image_generation_pipelines(py::module_& m) {
const std::string& prompt,
const py::kwargs& kwargs
) -> py::typing::Union<ov::Tensor> {
ov::AnyMap params = text2image_kwargs_to_any_map(kwargs, false);
ov::AnyMap params = pyutils::kwargs_to_any_map(kwargs);
return py::cast(pipe.generate(prompt, params));
},
py::arg("prompt"), "Input string",
Expand Down
13 changes: 11 additions & 2 deletions src/python/py_tokenizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,18 @@ void init_tokenizer(py::module_& m) {
R"(openvino_genai.Tokenizer object is used to initialize Tokenizer
if it's located in a different path than the main model.)")

.def(py::init([](const std::filesystem::path& tokenizer_path, const std::map<std::string, py::object>& properties) {
.def(py::init([](const std::filesystem::path& tokenizer_path, const std::map<std::string, py::object>& properties, const py::kwargs& kwargs) {
ScopedVar env_manager(pyutils::ov_tokenizers_module_path());
return std::make_unique<ov::genai::Tokenizer>(tokenizer_path, pyutils::properties_to_any_map(properties));
auto kwargs_properties = pyutils::kwargs_to_any_map(kwargs);
if (properties.size()) {
PyErr_WarnEx(PyExc_DeprecationWarning,
"'properties' parameters is deprecated, please use kwargs to pass config properties instead.",
1);
auto map_properties = pyutils::properties_to_any_map(properties);
kwargs_properties.insert(map_properties.begin(), map_properties.end());
}

return std::make_unique<ov::genai::Tokenizer>(tokenizer_path, kwargs_properties);
}), py::arg("tokenizer_path"), py::arg("properties") = ov::AnyMap({}))

.def("encode", [](Tokenizer& tok, std::vector<std::string>& prompts, bool add_special_tokens) {
Expand Down
Loading

0 comments on commit cd05c8e

Please sign in to comment.