У меня есть прямоугольник в двухмерном пространстве и набор точек внутри прямоугольника. Прямоугольник перемещается следующим образом: центр перемещается на значение u
по оси X, v
по оси Y, и все масштабируется с коэффициентом sx
и sy
соответственно. Я получаю расположение точек только после движения. Моя цель — оценить вектор (u, v, sx, sy)
.
У меня есть следующие данные во время выполнения:
Уравнение для расчета положения точки в текущем кадре с учетом вектора (u, v, sx, sy)
имеет вид:
x_currentFrameCalaulated = sx * px + u + x0 * (1 - sx)
y_currentFrameCalaulated = sy * py + v + y0 * (1 - sy)
Обратите внимание, что оси не являются зависимыми. Я определил следующую функцию, которую нужно минимизировать:
def estimateCurr(vec, previous, current, center):
return np.abs(current - (vec[1]* previous + vec[0]+ center * (1 - vec[1])))
Здесь vec[0] представляет движение относительно оси, а vec[1] представляет масштаб. Я устанавливаю границу в соответствии с моей проблемой следующим образом:
h = 270
w = 480
boundsX = Bounds([-w, -1], [w, w - 1])
boundsY = Bounds([-h, -1], [h, h - 1])
Инициализация предположения для [0, 0]
:
init = np.zeros((2 , ))
Я возобновляю попытку найти оптимальное решение:
res = minimize(estimateCurr, x0 = init, args=(px, cx, centerX), method='trust-constr', bounds=boundsX, options = {'verbose': 1})
print(res)
res = minimize(estimateCurr, x0 = init, args=(py, cy, centerY), method='trust-constr', bounds=boundsY, options = {'verbose': 1})
print(res)
Я получаю:
ValueError: все входные массивы должны иметь одинаковое количество измерений, но массив с индексом 0 имеет 2 измерения, а массив с индексом 1 имеет 1 измерение(я)
Это очевидно, так как у меня 17 точек, а размеры печати: печать(px.shape) печать (cx.shape) печать (centerX.shape) печать (init.shape)
(17,) (17,) (17,) (2,)
Однако я не уверен, как установить правильные размеры для задачи и даже использую ли я правильный решатель. Я попытался умножить (u, v, sx, sy)
, чтобы подогнать размер данных, чтобы не было зла. Как мне подойти к этой проблеме?
Мой формальный вопрос: с учетом набора измеренных точек данных, как мне подобрать многомерное решение, которое минимизирует ошибку с помощью Python?
Добавляем фиктивный пример запроса комментариев. Я сократил набор данных до 6 пунктов:
from scipy.optimize import Bounds
from scipy.optimize import minimize
import numpy as np
def estimateCurr(vec, previous, current, center):
# np.full(())
return np.abs(current - (vec[1] * previous + vec[0] + center * (1 - vec[1])))
h = 270
w = 480
x0 = 90.8021
y0 = -20.8282
px = np.array([86.7581, 74.5433, 85.0012, 84.348, 83.704, 91.6176])
py = np.array([-19.5163, -17.3714, -3.39899, -4.83069, -1.97073, -2.20099])
cx = np.array([89.7436, 75.8955, 87.5827, 87.1492, 86.0817, 92.6683])
cy = np.array([-19.2132, -16.3913, -2.9177, -4.81898, -1.49321, -2.43572])
numPoints = px.shape[0]
boundsX = Bounds([-w, -1], [w, w - 1])
boundsY = Bounds([-h, -1], [h, h - 1])
centerX = np.full((numPoints,), x0)
centerY = np.full((numPoints,), y0)
init = np.zeros((2 ,))
print(px.shape)
print(cx.shape)
print(centerX.shape)
print(init.shape)
res = minimize(estimateCurr, x0 = init, args=(px, cx, centerX), method='trust-constr', bounds=boundsX, options = {'verbose': 1})
print(res)
res = minimize(estimateCurr, x0 = init, args=(py, cy, centerY), method='trust-constr', bounds=boundsY, options = {'verbose': 1})
print(res)
Добавление полной трассировки:
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) /tmp/ipykernel_6249/3484902536.py in <module>
25 print(centerX.shape)
26 print(init.shape)
---> 27 res = minimize(estimateCurr, x0 = init, args=(px, cx, centerX), method='trust-constr', bounds=boundsX, options = {'verbose': 1})
28 print(res)
29 res = minimize(estimateCurr, x0 = init, args=(py, cy, centerY), method='trust-constr', bounds=boundsY, options = {'verbose': 1})
~/.conda/envs/oxip-new6/lib/python3.7/site-packages/scipy/optimize/_minimize.py in minimize(fun, x0, args, method, jac, hess, hessp, bounds, constraints, tol, callback, options)
634 return _minimize_trustregion_constr(fun, x0, args, jac, hess, hessp,
635 bounds, constraints,
--> 636 callback=callback, **options)
637 elif meth == 'dogleg':
638 return _minimize_dogleg(fun, x0, args, jac, hess,
~/.conda/envs/oxip-new6/lib/python3.7/site-packages/scipy/optimize/_trustregion_constr/minimize_trustregion_constr.py in _minimize_trustregion_constr(fun, x0, args, grad, hess, hessp, bounds, constraints, xtol, gtol, barrier_tol, sparse_jacobian, callback, maxiter, verbose, finite_diff_rel_step, initial_constr_penalty, initial_tr_radius, initial_barrier_parameter, initial_barrier_tolerance, factorization_method, disp)
518 initial_barrier_tolerance,
519 initial_constr_penalty, initial_tr_radius,
--> 520 factorization_method)
521
522 # Status 3 occurs when the callback function requests termination,
~/.conda/envs/oxip-new6/lib/python3.7/site-packages/scipy/optimize/_trustregion_constr/tr_interior_point.py in tr_interior_point(fun, grad, lagr_hess, n_vars, n_ineq, n_eq, constr, jac, x0, fun0, grad0, constr_ineq0, jac_ineq0, constr_eq0, jac_eq0, stop_criteria, enforce_feasibility, xtol, state, initial_barrier_parameter, initial_tolerance, initial_penalty, initial_trust_radius, factorization_method)
306 barrier_parameter, tolerance, enforce_feasibility, ...
347
<__array_function__ internals> in concatenate(*args, **kwargs)
ValueError: all the input arrays must have same number of dimensions, but the array at index 0 has 2 dimension(s) and the array at index 1 has 1 dimension(s)
Стоит отметить, что эта проблема является линейной, поэтому вы можете использовать линейную регрессию для ее решения, если minimize()
и ее нелинейные решатели вам не подходят.
Можете ли вы предоставить достаточно кода и данных, чтобы кто-то другой мог скопировать и вставить ваш пример кода и запустить его на своем компьютере? Я попробовал настроить массивы так, как вы описываете, и не смог получить описанную вами ошибку.
Что дает тестовый вызовestimateCurr(init, *args)
? Это должно быть одно значение, которое необходимо минимизировать. Я предполагаю, что вместо этого будет массив (17).
Пожалуйста, найдите время, чтобы написать минимально воспроизводимый пример, невозможно воспроизвести вашу проблему просто потому, что отсутствует часть кода и данных. В это время NameError: name 'Bounds' is not defined
.
@jlandercy Bound — это импорт from scipy.optimize import Bounds
. Обычно импорт не включается в минимальные примеры AFAIK. Я добавлю их в любом случае.
Минимально воспроизводимый пример включает в себя все необходимое для воспроизведения проблемы. Включите импорт, данные и т. д. Пожалуйста, прочитайте ссылку.
Целевая функция должна быть скалярной функцией. В вашем определении функция возвращает массив. Поэтому вам нужно как-то агрегировать это. Наиболее очевидным выбором обычно является сумма.
Например, следующая целевая функция работает и сходится:
def estimateCurr(vec, previous, current, center):
return np.sum(np.power(current - (vec[1] * previous + vec[0] + center * (1 - vec[1])), 2))
# message: `xtol` termination condition is satisfied.
# success: True
# status: 2
# fun: 3.1694871819514345
# x: [ 2.274e+00 1.013e+00]
# ...
Можете ли вы опубликовать полную обратную трассировку, включая ту часть, которая показывает, какая строка вызвала ошибку?