-
Notifications
You must be signed in to change notification settings - Fork 19.6k
OpenVINO: linspace #21209
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
OpenVINO: linspace #21209
Changes from 55 commits
a9ba69a
e95aba3
2933a49
94c678e
47cc458
54ecce1
00ef089
b449b7f
f1bc6f3
c11347e
831ceee
6744166
9683006
51cd940
01188fc
9368989
5aa98c0
98c9e04
6df399e
647c69e
93e481e
92d384f
dc1e1e9
25fc834
d8aa091
5e3c537
2df8827
998a35b
7d30d96
2a9ec53
cdc91d9
004fce9
dc8081f
43f0125
fae2a81
3cf5427
a62795d
3c60459
d65d92c
37e96c1
af33c76
a26d3a6
5dc78bf
280be55
f982384
6a5fb1b
536b11a
abe68e4
0a39e5f
7d43dbf
fb5649f
e3fdbfa
96d17ff
209daf0
724b143
e60d708
9c7fbee
c6991f9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -910,9 +910,156 @@ def less_equal(x1, x2): | |
def linspace( | ||
start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0 | ||
): | ||
raise NotImplementedError( | ||
"`linspace` is not supported with openvino backend" | ||
) | ||
""" | ||
Return evenly spaced numbers over a specified interval. | ||
|
||
Returns `num` evenly spaced samples, calculated over the | ||
interval [`start`, `stop`]. | ||
|
||
The endpoint of the interval can optionally be excluded. | ||
|
||
Parameters | ||
---------- | ||
start : array_like | ||
The starting value of the sequence. | ||
stop : array_like | ||
The end value of the sequence, unless `endpoint` is set to False. | ||
In that case, the sequence consists of all but the last of ``num + 1`` | ||
evenly spaced samples, so that `stop` is excluded. Note that the step | ||
size changes when `endpoint` is False. | ||
num : int, optional | ||
Number of samples to generate. Default is 50. Must be non-negative. | ||
endpoint : bool, optional | ||
If True, `stop` is the last sample. Otherwise, it is not included. | ||
Default is True. | ||
retstep : bool, optional | ||
If True, return (`samples`, `step`), where `step` is the spacing | ||
between samples. | ||
dtype : dtype, optional | ||
The type of the output array. If `dtype` is not given, the data type | ||
is inferred from `start` and `stop`. The inferred dtype will never be | ||
an integer; `float` is chosen even if the arguments would produce an | ||
array of integers. | ||
axis : int, optional | ||
The axis in the result to store the samples. Relevant only if start | ||
or stop are array-like. By default (0), the samples will be along a | ||
new axis inserted at the beginning. Use -1 to get an axis at the end. | ||
|
||
Returns | ||
------- | ||
samples : ndarray | ||
There are `num` equally spaced samples in the closed interval | ||
``[start, stop]`` or the half-open interval ``[start, stop)`` | ||
(depending on whether `endpoint` is True or False). | ||
step : float, optional | ||
Only returned if `retstep` is True | ||
|
||
Size of spacing between samples. | ||
""" | ||
|
||
dtype = standardize_dtype(dtype) or config.floatx() | ||
out_dtype = OPENVINO_DTYPES[dtype] | ||
dtype = OPENVINO_DTYPES[config.floatx()] | ||
|
||
start = get_ov_output(start, dtype) | ||
stop = get_ov_output(stop, dtype) | ||
start = ov_opset.convert(start, dtype).output(0) | ||
stop = ov_opset.convert(stop, dtype).output(0) | ||
|
||
if isinstance(num, OpenVINOKerasTensor): | ||
num = get_ov_output(num, Type.i32) | ||
elif isinstance(num, int): | ||
num = ov_opset.constant(num, Type.i32).output(0) | ||
else: | ||
raise TypeError("`num` must be an int or OpenVINOKerasTensor.") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think |
||
num = ov_opset.convert(num, Type.i32).output(0) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not needed |
||
|
||
zero_i = ov_opset.constant(0, Type.i32).output(0) | ||
one_i = ov_opset.constant(1, Type.i32).output(0) | ||
axis_i = ov_opset.constant(axis, Type.i32).output(0) | ||
|
||
div = ov_opset.subtract(num, one_i).output(0) if endpoint else num | ||
div = ov_opset.convert(div, dtype).output(0) | ||
|
||
zero = ov_opset.constant(0.0, dtype).output(0) | ||
one = ov_opset.constant(1.0, dtype).output(0) | ||
num_f = ov_opset.convert(num, dtype).output(0) | ||
seq = ov_opset.range(zero, num_f, one, dtype).output(0) | ||
|
||
ndim = len(start.shape) | ||
dims = ov_opset.concat( | ||
[ | ||
ov_opset.constant([-1], Type.i32), | ||
ov_opset.constant([1] * ndim, Type.i32), | ||
], | ||
0, | ||
).output(0) | ||
seq = ov_opset.reshape(seq, dims, False).output(0) | ||
|
||
delta = ov_opset.subtract(stop, start).output(0) | ||
|
||
cond = ov_opset.greater(div, zero).output(0) | ||
nan_const = ov_opset.constant(float("nan"), dtype).output(0) | ||
step_val = ov_opset.divide(delta, div).output(0) | ||
step = ov_opset.select(cond, step_val, nan_const).output(0) | ||
|
||
target_shape = ov_opset.concat( | ||
[ | ||
ov_opset.constant([1], Type.i64), | ||
ov_opset.shape_of(start).output(0), | ||
], | ||
0, | ||
).output(0) | ||
step = ov_opset.reshape(step, target_shape, False).output(0) | ||
|
||
eq_zero = ov_opset.equal(step, zero).output(0) | ||
any_zero = ov_opset.reduce_logical_or( | ||
eq_zero, ov_opset.constant([0], Type.i32), False | ||
).output(0) | ||
|
||
y_norm = ov_opset.multiply(seq, step).output(0) | ||
y_denorm = ov_opset.multiply( | ||
ov_opset.divide(seq, div).output(0), | ||
delta, | ||
).output(0) | ||
y_pos = ov_opset.convert( | ||
ov_opset.select(any_zero, y_denorm, y_norm).output(0), dtype | ||
).output(0) | ||
|
||
y_zero = ov_opset.convert( | ||
ov_opset.multiply(seq, delta).output(0), dtype | ||
).output(0) | ||
y = ov_opset.add( | ||
ov_opset.convert(ov_opset.select(cond, y_pos, y_zero).output(0), dtype), | ||
start, | ||
).output(0) | ||
|
||
if endpoint: | ||
idx = ov_opset.subtract(num, one_i).output(0) | ||
idx = ov_opset.convert(idx, Type.i32).output(0) | ||
idx_tensor = ov_opset.broadcast(idx, target_shape).output(0) | ||
stop_tensor = ov_opset.broadcast(stop, target_shape).output(0) | ||
y = ov_opset.scatter_elements_update( | ||
y, idx_tensor, stop_tensor, 0 | ||
).output(0) | ||
|
||
if axis != 0: | ||
rank = ov_opset.rank(y).output(0) | ||
axis_p1 = ov_opset.add(axis_i, one_i).output(0) | ||
pre = ov_opset.range(one_i, axis_p1, one_i).output(0) | ||
post = ov_opset.range(axis_p1, rank, one_i).output(0) | ||
zero_i = ov_opset.reshape( | ||
zero_i, ov_opset.constant([1], Type.i32), False | ||
).output(0) | ||
perm = ov_opset.concat([pre, zero_i, post], 0).output(0) | ||
y = ov_opset.transpose(y, perm).output(0) | ||
|
||
y = ov_opset.convert(y, out_dtype).output(0) | ||
if retstep: | ||
return OpenVINOKerasTensor(y), ov_opset.convert(step, out_dtype).output( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. create |
||
0 | ||
) | ||
return OpenVINOKerasTensor(y) | ||
|
||
|
||
def log(x): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not needed because
get_ov_output
already performsconvert
. So please removeThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your review, @rkazants.
I've incorporated the rest of the changes but removing this seems to cause type errors.