diff --git a/src/frontends/pytorch/src/op/log.cpp b/src/frontends/pytorch/src/op/log.cpp new file mode 100644 index 00000000000..614c6813c6d --- /dev/null +++ b/src/frontends/pytorch/src/op/log.cpp @@ -0,0 +1,39 @@ +// Copyright (C) 2018-2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "openvino/op/log.hpp" + +#include "openvino/frontend/pytorch/node_context.hpp" +#include "openvino/op/constant.hpp" +#include "openvino/op/convert.hpp" +#include "openvino/op/divide.hpp" + +namespace ov { +namespace frontend { +namespace pytorch { +namespace op { + +OutputVector translate_log(NodeContext& context) { + // torch.log returns a tensor with the natural logarithm of the elements of input. + auto x = context.get_input(0); + x = context.mark_node(std::make_shared(x, element::f32)); + auto log = context.mark_node(std::make_shared(x)); + return {log}; +}; + +OutputVector translate_log2(NodeContext& context) { + // torch.log2 returns a tensor with the logarithm to the base 2 of the elements of input. + auto x = context.get_input(0); + auto two = context.mark_node(ov::op::v0::Constant::create(element::f32, Shape{}, {2})); + x = context.mark_node(std::make_shared(x, element::f32)); + auto log2 = context.mark_node(std::make_shared(two)); + auto log = context.mark_node(std::make_shared(x)); + auto res = context.mark_node(std::make_shared(log, log2)); + return {res}; +}; + +} // namespace op +} // namespace pytorch +} // namespace frontend +} // namespace ov \ No newline at end of file diff --git a/src/frontends/pytorch/src/op_table.cpp b/src/frontends/pytorch/src/op_table.cpp index 846a37aeb03..e771b2b9ca1 100644 --- a/src/frontends/pytorch/src/op_table.cpp +++ b/src/frontends/pytorch/src/op_table.cpp @@ -50,6 +50,8 @@ OP_CONVERTER(translate_layer_norm); OP_CONVERTER(translate_len); OP_CONVERTER(translate_linear); OP_CONVERTER(translate_list_construct); +OP_CONVERTER(translate_log); +OP_CONVERTER(translate_log2); OP_CONVERTER(translate_loop); OP_CONVERTER(translate_max_poolnd); OP_CONVERTER(translate_max); @@ -184,6 +186,10 @@ const std::map get_supported_ops() { {"aten::linear", op::translate_linear}, {"aten::le", op::translate_1to1_match_2_inputs}, {"aten::lt", op::translate_1to1_match_2_inputs}, + {"aten::log", op::translate_log}, + {"aten::log_", op::inplace_op}, + {"aten::log2", op::translate_log2}, + {"aten::log2_", op::inplace_op}, {"aten::matmul", op::translate_1to1_match_2_inputs}, {"aten::masked_fill", op::translate_masked_fill}, {"aten::masked_fill_", op::inplace_op}, diff --git a/tests/layer_tests/pytorch_tests/test_log.py b/tests/layer_tests/pytorch_tests/test_log.py new file mode 100644 index 00000000000..c354b50a316 --- /dev/null +++ b/tests/layer_tests/pytorch_tests/test_log.py @@ -0,0 +1,48 @@ +# Copyright (C) 2018-2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +import pytest +from pytorch_layer_test_class import PytorchLayerTest + + +class TestLog(PytorchLayerTest): + def _prepare_input(self, dtype): + import numpy as np + return (np.random.uniform(2, 16, (1, 10)).astype(dtype),) + + def create_model(self, op): + import torch + + ops = { + "log": torch.log, + "log_": torch.log_, + "log2": torch.log2, + "log2_": torch.log2_ + } + + op_fn = ops[op] + + class aten_log(torch.nn.Module): + def __init__(self, op): + super(aten_log, self).__init__() + self.op = op + + def forward(self, x): + return self.op(x) + + ref_net = None + + return aten_log(op_fn), ref_net, f"aten::{op}" + + @pytest.mark.nightly + @pytest.mark.precomit + @pytest.mark.parametrize(("op", "input_dtype"), + [["log", "float32"], + ["log", "int32"], + ["log_", "float32"], + ["log2", "float32"], + ["log2", "int32"], + ["log2_", "float32"]]) + def test_log(self, op, input_dtype, ie_device, precision, ir_version): + self._test(*self.create_model(op), ie_device, precision, + ir_version, kwargs_to_prepare_input={"dtype": input_dtype}) \ No newline at end of file