// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "paddle/fluid/framework/program_converter.h" #include #include #include #include #include "paddle/fluid/framework/block_desc.h" #include "paddle/fluid/framework/op_desc.h" #include "paddle/fluid/framework/op_version_proto.h" #include "paddle/fluid/framework/op_version_registry.h" #include "paddle/fluid/framework/program_desc.h" #include "paddle/fluid/framework/version.h" namespace paddle::framework { using paddle::experimental::ExtractPlainVector; using paddle::experimental::WrapAsScalars; static std::unordered_set needConvertedOperators = { "assign_value", "set_value", "set_value_grad"}; std::pair> DetectLegacyOps( ProgramDesc* program) { bool is_legacy_program = false; std::unordered_multimap legacy_op_map; std::unordered_map program_op_versions; std::unordered_map legacy_op_versions; // get *all kinds* of formats of op versions and op version map to a unified // representation before comparison can be done in a neat way legacy_op_versions = paddle::framework::compatible::pb::GetLegacyOpVersions(); const auto* _op_version_map = program->OpVersionMap(); for (int i = 0; i < _op_version_map->pair_size(); ++i) { auto pair = std::make_pair( _op_version_map->pair(i).op_name(), static_cast(_op_version_map->pair(i).op_version().version())); program_op_versions.insert(pair); } const size_t num_blocks = program->Size(); for (size_t i = 0; i < num_blocks; i++) { BlockDesc* block = program->MutableBlock(i); const size_t num_ops = block->OpSize(); for (size_t j = 0; j < num_ops; j++) { OpDesc* op = block->Op(static_cast(j)); const std::string& op_type = op->Type(); if (needConvertedOperators.find(op_type) != needConvertedOperators.end()) { // If an operator (program_op) is in the needConvertedOperators set, // it indicates that the operator may need to be converted. // Further judgement: if the operator does not exist in the // program_op_version_map, the operator needs to be converted. // Moreover, if the operator does exist and its program_op_version_ // is less than or equal legacy_op_version, the operator also needs to // be converted. if (!program_op_versions.count(op_type) || program_op_versions[op_type] <= legacy_op_versions[op_type]) { is_legacy_program = true; legacy_op_map.insert(std::make_pair(op_type, op)); } } } } return std::make_pair(is_legacy_program, legacy_op_map); } } // namespace paddle::framework namespace paddle::framework::no_scalar { void ConvertSetValueOp(OpDesc* op) { std::vector values = PADDLE_GET_CONST( std::vector, op->GetAttr("values", false)); op->RemoveAttr("values"); op->SetAttr("bool_values", std::vector()); op->SetAttr("fp32_values", std::vector()); op->SetAttr("int32_values", std::vector()); op->SetAttr("int64_values", std::vector()); op->SetAttr("fp64_values", std::vector()); op->SetAttr("fp16_values", std::vector()); DataType dtype = DataType::FLOAT32; if (!values.empty()) { dtype = values.at(0).dtype(); } switch (dtype) { case DataType::BOOL: op->SetAttr("bool_values", ExtractPlainVector(values)); break; case DataType::FLOAT32: op->SetAttr("fp32_values", ExtractPlainVector(values)); break; case DataType::INT32: op->SetAttr("int32_values", ExtractPlainVector(values)); break; case DataType::INT64: op->SetAttr("int64_values", ExtractPlainVector(values)); break; case DataType::FLOAT64: op->SetAttr("fp64_values", ExtractPlainVector(values)); break; case DataType::FLOAT16: op->SetAttr("fp16_values", ExtractPlainVector(values)); break; default: PD_THROW("Invalid data type `", dtype, "`."); } } void ConvertAssignValueOp(OpDesc* op) { std::vector values = PADDLE_GET_CONST( std::vector, op->GetAttr("values", false)); op->RemoveAttr("values"); op->SetAttr("bool_values", std::vector()); op->SetAttr("fp32_values", std::vector()); op->SetAttr("int32_values", std::vector()); op->SetAttr("int64_values", std::vector()); DataType dtype = DataType::FLOAT32; if (!values.empty()) { dtype = values.at(0).dtype(); } switch (dtype) { case DataType::BOOL: op->SetAttr("bool_values", ExtractPlainVector(values)); break; case DataType::FLOAT32: op->SetAttr("fp32_values", ExtractPlainVector(values)); break; case DataType::FLOAT64: op->SetAttr("fp32_values", ExtractPlainVector(values)); break; case DataType::INT32: op->SetAttr("int32_values", ExtractPlainVector(values)); break; case DataType::INT64: op->SetAttr("int64_values", ExtractPlainVector(values)); break; default: PD_THROW("Invalid data type `", dtype, "`."); } } void ConvertProgram(ProgramDesc* program) { PADDLE_ENFORCE_NOT_NULL( program, common::errors::InvalidArgument("program should not be null")); VLOG(3) << "Setting Program Version and OpVersionMap to Legacy " "settings(a.k.a 2.4.2)"; framework::compatible::pb::OpVersionMap op_version_map( program->OpVersionMap()); program->SetVersion(paddle::framework::kLegacyProgramVersion); paddle::framework::compatible::SaveOpVersions( paddle::framework::compatible::pb::GetLegacyOpVersions(), &op_version_map); VLOG(3) << "Converting program from new(with scalar attributes) to old(no " "scalar attributes)"; const size_t num_blocks = program->Size(); for (size_t i = 0; i < num_blocks; i++) { BlockDesc* block = program->MutableBlock(i); const size_t num_ops = block->OpSize(); for (size_t j = 0; j < num_ops; j++) { OpDesc* op = block->Op(static_cast(j)); const std::string op_type = op->Type(); if (op_type == "set_value" || op_type == "set_value_grad") { ConvertSetValueOp(op); } if (op_type == "assign_value") { ConvertAssignValueOp(op); } } } } } // namespace paddle::framework::no_scalar namespace paddle::framework::scalar { void ConvertSetValueOp(OpDesc* op) { std::vector values; if (op->HasAttr("bool_values")) { std::vector bool_values = PADDLE_GET_CONST(std::vector, op->GetAttr("bool_values", false)); if (!bool_values.empty()) { values = WrapAsScalars(bool_values); } op->RemoveAttr("bool_values"); } if (op->HasAttr("fp32_values")) { std::vector fp32_values = PADDLE_GET_CONST(std::vector, op->GetAttr("fp32_values", false)); if (!fp32_values.empty()) { values = WrapAsScalars(fp32_values); } op->RemoveAttr("fp32_values"); } if (op->HasAttr("int32_values")) { std::vector int32_values = PADDLE_GET_CONST(std::vector, op->GetAttr("int32_values", false)); if (!int32_values.empty()) { values = WrapAsScalars(int32_values); } op->RemoveAttr("int32_values"); } if (op->HasAttr("int64_values")) { std::vector int64_values = PADDLE_GET_CONST( std::vector, op->GetAttr("int64_values", false)); if (!int64_values.empty()) { values = WrapAsScalars(int64_values); } op->RemoveAttr("int64_values"); } if (op->HasAttr("fp64_values")) { std::vector fp64_values = PADDLE_GET_CONST( std::vector, op->GetAttr("fp64_values", false)); if (!fp64_values.empty()) { values = WrapAsScalars(fp64_values); } op->RemoveAttr("fp64_values"); } if (op->HasAttr("fp16_values")) { std::vector fp16_values = PADDLE_GET_CONST(std::vector, op->GetAttr("fp16_values", false)); if (!fp16_values.empty()) { values = WrapAsScalars(fp16_values); } op->RemoveAttr("fp16_values"); } op->SetAttr("values", values); } void ConvertAssignValueOp(OpDesc* op) { VLOG(3) << "convert old assign value op to new"; std::vector values; if (op->HasAttr("bool_values")) { std::vector bool_values = PADDLE_GET_CONST(std::vector, op->GetAttr("bool_values", false)); if (!bool_values.empty()) { values = WrapAsScalars(bool_values); } op->RemoveAttr("bool_values"); } if (op->HasAttr("fp32_values")) { std::vector fp32_values = PADDLE_GET_CONST(std::vector, op->GetAttr("fp32_values", false)); if (!fp32_values.empty()) { values = WrapAsScalars(fp32_values); } op->RemoveAttr("fp32_values"); } if (op->HasAttr("int32_values")) { std::vector int32_values = PADDLE_GET_CONST(std::vector, op->GetAttr("int32_values", false)); if (!int32_values.empty()) { values = WrapAsScalars(int32_values); } op->RemoveAttr("int32_values"); } if (op->HasAttr("int64_values")) { std::vector int64_values = PADDLE_GET_CONST( std::vector, op->GetAttr("int64_values", false)); if (!int64_values.empty()) { values = WrapAsScalars(int64_values); } op->RemoveAttr("int64_values"); } if (!values.empty()) op->SetAttr("values", values); } void ConvertProgram(ProgramDesc* program) { PADDLE_ENFORCE_NOT_NULL( program, common::errors::InvalidArgument("program should not be null")); auto legacy_op_results = DetectLegacyOps(program); bool is_legacy_program = legacy_op_results.first; const std::unordered_multimap& legacy_ops = legacy_op_results.second; VLOG(3) << "is_legacy_program : " << is_legacy_program; if (!is_legacy_program) return; VLOG(3) << "Updating Program Version and OpVersionMap"; program->SetVersion(paddle::framework::kCurProgramVersion); framework::compatible::pb::OpVersionMap op_version_map( program->OpVersionMap()); paddle::framework::compatible::SaveOpVersions( framework::compatible::get_op_version_map(), &op_version_map); VLOG(3) << "Converting program from old(no scalar attributes) to new(with " "scalar attributes)"; for (const auto& pair : legacy_ops) { const std::string op_type = pair.first; VLOG(3) << "Converting program from old to new, op_type=" << op_type; if (op_type == "set_value" || op_type == "set_value_grad") { ConvertSetValueOp(pair.second); } if (op_type == "assign_value") { ConvertAssignValueOp(pair.second); } } } } // namespace paddle::framework::scalar