@@ -76,25 +76,81 @@ def multiply(x1, x2):
7676
7777
7878def mean (x , axis = None , keepdims = False ):
79- x = get_ov_output (x )
80- if axis is None :
81- flatten_shape = ov_opset .constant ([- 1 ], Type .i32 ).output (0 )
82- x = ov_opset .reshape (x , flatten_shape , False ).output (0 )
83- axis = 0
84- axis_const = ov_opset .constant (axis , dtype = Type .i32 ).output (0 )
85- mean_ops = ov_opset .reduce_mean (x , axis_const , keepdims )
86- return OpenVINOKerasTensor (mean_ops .output (0 ))
79+ x_ov = get_ov_output (x )
80+ x_shape = x_ov .get_partial_shape ().to_shape ()
81+ x_type = x_ov .get_element_type ()
82+
83+ was_axis_none = axis is None
84+ x_resolved , axis_resolved = _resolve_axis (x_ov , axis )
85+
86+ if axis_resolved is None :
87+ return OpenVINOKerasTensor (x_ov )
88+
89+ if x_type .is_integral ():
90+ ov_type = OPENVINO_DTYPES [config .floatx ()]
91+ x_resolved = ov_opset .convert (x_resolved , ov_type ).output (0 )
92+
93+ result = ov_opset .reduce_mean (x_resolved , axis_resolved , keepdims ).output (0 )
94+
95+ if keepdims and was_axis_none :
96+ result_shape = [1 ] * len (x_shape )
97+ result = ov_opset .reshape (
98+ result ,
99+ ov_opset .constant (result_shape , Type .i32 ).output (0 ),
100+ False ,
101+ ).output (0 )
102+
103+ return OpenVINOKerasTensor (result )
87104
88105
89106def max (x , axis = None , keepdims = False , initial = None ):
90- assert initial is None , (
91- "`max` with not None initial is not supported by openvino backend"
92- )
107+ return _compute_extrema (x , "max" , axis , keepdims , initial )
108+
109+
110+ def _compute_extrema (x , operation , axis = None , keepdims = False , initial = None ):
111+ if operation == "min" :
112+ reduction_op = ov_opset .reduce_min
113+ elementwise_op = ov_opset .minimum
114+ elif operation == "max" :
115+ reduction_op = ov_opset .reduce_max
116+ elementwise_op = ov_opset .maximum
117+ else :
118+ raise ValueError (
119+ f"Operation must be 'min' or 'max', received { operation } "
120+ )
121+
93122 x = get_ov_output (x )
94- reduce_axis = ov_opset .constant (axis , Type .i32 ).output (0 )
95- return OpenVINOKerasTensor (
96- ov_opset .reduce_max (x , reduce_axis , keepdims ).output (0 )
97- )
123+ x_type = x .get_element_type ()
124+ x_for_rank = x
125+
126+ is_bool = x_type == Type .boolean
127+ if is_bool :
128+ x = ov_opset .convert (x , Type .i32 ).output (0 )
129+ x_type = Type .i32
130+
131+ if isinstance (axis , tuple ) and len (axis ) == 0 :
132+ return OpenVINOKerasTensor (x )
133+
134+ was_axis_none = axis is None
135+ x , axis = _resolve_axis (x , axis )
136+
137+ result = reduction_op (x , axis , keepdims ).output (0 )
138+
139+ if initial is not None :
140+ initial_tensor = ov_opset .constant (initial , x_type ).output (0 )
141+ result = elementwise_op (result , initial_tensor ).output (0 )
142+
143+ if keepdims and was_axis_none :
144+ orig_shape = ov_opset .shape_of (x_for_rank , Type .i32 ).output (0 )
145+ orig_rank_shape = ov_opset .shape_of (orig_shape , Type .i32 ).output (0 )
146+ one = ov_opset .constant (1 , Type .i32 ).output (0 )
147+ result_shape = ov_opset .broadcast (one , orig_rank_shape ).output (0 )
148+ result = ov_opset .reshape (result , result_shape , False ).output (0 )
149+
150+ if is_bool :
151+ result = ov_opset .convert (result , Type .boolean ).output (0 )
152+
153+ return OpenVINOKerasTensor (result )
98154
99155
100156def ones (shape , dtype = None ):
@@ -162,17 +218,11 @@ def any(x, axis=None, keepdims=False):
162218
163219
164220def amax (x , axis = None , keepdims = False ):
165- if axis == () or axis == []:
166- return x
167221 x = get_ov_output (x )
168222 x_type = x .get_element_type ()
223+ x , axis = _resolve_axis (x , axis )
169224 if axis is None :
170- flatten_shape = ov_opset .constant ([- 1 ], Type .i32 ).output (0 )
171- x = ov_opset .reshape (x , flatten_shape , False ).output (0 )
172- axis = 0
173- if isinstance (axis , tuple ):
174- axis = list (axis )
175- axis = ov_opset .constant (axis , Type .i32 ).output (0 )
225+ return OpenVINOKerasTensor (x )
176226 if x_type == Type .boolean :
177227 return OpenVINOKerasTensor (
178228 ov_opset .reduce_logical_or (x , axis , keepdims ).output (0 )
@@ -181,22 +231,29 @@ def amax(x, axis=None, keepdims=False):
181231
182232
183233def amin (x , axis = None , keepdims = False ):
184- if axis == () or axis == []:
185- return x
186234 x = get_ov_output (x )
187235 x_type = x .get_element_type ()
236+ x , axis = _resolve_axis (x , axis )
237+ if axis is None :
238+ return OpenVINOKerasTensor (x )
239+ if x_type == Type .boolean :
240+ return OpenVINOKerasTensor (
241+ ov_opset .reduce_logical_and (x , axis , keepdims ).output (0 )
242+ )
243+ return OpenVINOKerasTensor (ov_opset .reduce_min (x , axis , keepdims ).output (0 ))
244+
245+
246+ def _resolve_axis (x , axis ):
247+ if axis == () or axis == []:
248+ return x , None
188249 if axis is None :
189250 flatten_shape = ov_opset .constant ([- 1 ], Type .i32 ).output (0 )
190251 x = ov_opset .reshape (x , flatten_shape , False ).output (0 )
191252 axis = 0
192253 if isinstance (axis , tuple ):
193254 axis = list (axis )
194255 axis = ov_opset .constant (axis , Type .i32 ).output (0 )
195- if x_type == Type .boolean :
196- return OpenVINOKerasTensor (
197- ov_opset .reduce_logical_and (x , axis , keepdims ).output (0 )
198- )
199- return OpenVINOKerasTensor (ov_opset .reduce_min (x , axis , keepdims ).output (0 ))
256+ return x , axis
200257
201258
202259def append (x1 , x2 , axis = None ):
@@ -651,6 +708,8 @@ def cumsum(x, axis=None, dtype=None):
651708 x = ov_opset .reshape (x , flatten_shape , False ).output (0 )
652709 axis = 0
653710 axis = ov_opset .constant (axis , Type .i32 ).output (0 )
711+ if x .get_element_type () == Type .boolean :
712+ x = ov_opset .convert (x , Type .i32 ).output (0 )
654713 return OpenVINOKerasTensor (ov_opset .cumsum (x , axis ).output (0 ))
655714
656715
@@ -838,6 +897,9 @@ def flip(x, axis=None):
838897
839898def floor (x ):
840899 x = get_ov_output (x )
900+ x_type = x .get_element_type ()
901+ if x_type .is_integral ():
902+ x = ov_opset .convert (x , OPENVINO_DTYPES [config .floatx ()])
841903 return OpenVINOKerasTensor (ov_opset .floor (x ).output (0 ))
842904
843905
@@ -1509,46 +1571,7 @@ def meshgrid(*x, indexing="xy"):
15091571
15101572
15111573def min (x , axis = None , keepdims = False , initial = None ):
1512- x = get_ov_output (x )
1513- original_type = x .get_element_type ()
1514- x_type = original_type
1515- x_shape = x .get_partial_shape ().to_shape ()
1516-
1517- is_bool = x_type == Type .boolean
1518- if is_bool :
1519- x = ov_opset .convert (x , Type .i32 ).output (0 )
1520- x_type = Type .i32
1521-
1522- if isinstance (axis , tuple ) and len (axis ) == 0 :
1523- return OpenVINOKerasTensor (x )
1524-
1525- if axis is None :
1526- flatten_shape = ov_opset .constant ([- 1 ], Type .i32 ).output (0 )
1527- x = ov_opset .reshape (x , flatten_shape , False ).output (0 )
1528- axis = 0
1529-
1530- if isinstance (axis , tuple ):
1531- axis = list (axis )
1532-
1533- axis_const = ov_opset .constant (axis , Type .i32 ).output (0 )
1534- min_result = ov_opset .reduce_min (x , axis_const , keepdims ).output (0 )
1535-
1536- if initial is not None :
1537- initial_tensor = ov_opset .constant (initial , x_type ).output (0 )
1538- min_result = ov_opset .minimum (min_result , initial_tensor ).output (0 )
1539-
1540- if keepdims :
1541- result_shape = [1 ] * len (x_shape )
1542- min_result = ov_opset .reshape (
1543- min_result ,
1544- ov_opset .constant (result_shape , Type .i32 ).output (0 ),
1545- False ,
1546- ).output (0 )
1547-
1548- if is_bool :
1549- min_result = ov_opset .convert (min_result , Type .boolean ).output (0 )
1550-
1551- return OpenVINOKerasTensor (min_result )
1574+ return _compute_extrema (x , "min" , axis , keepdims , initial )
15521575
15531576
15541577def minimum (x1 , x2 ):
0 commit comments