Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
P
pytensor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
testgroup
pytensor
Commits
e2cb1e2d
提交
e2cb1e2d
authored
12月 10, 2025
作者:
Ricardo Vieira
提交者:
Ricardo Vieira
12月 13, 2025
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Optimize: Enforce input types, and stop appeasing mypy
上级
10d225dd
隐藏空白字符变更
内嵌
并排
正在显示
2 个修改的文件
包含
71 行增加
和
88 行删除
+71
-88
optimize.py
pytensor/tensor/optimize.py
+70
-88
mypy-failing.txt
scripts/mypy-failing.txt
+1
-0
没有找到文件。
pytensor/tensor/optimize.py
浏览文件 @
e2cb1e2d
import
logging
import
logging
from
collections.abc
import
Sequence
from
collections.abc
import
Sequence
from
copy
import
copy
from
copy
import
copy
from
typing
import
cast
import
numpy
as
np
import
numpy
as
np
...
@@ -126,7 +125,9 @@ class LRUCache1:
...
@@ -126,7 +125,9 @@ class LRUCache1:
self
.
hess_calls
=
0
self
.
hess_calls
=
0
def
_find_optimization_parameters
(
objective
:
TensorVariable
,
x
:
TensorVariable
):
def
_find_optimization_parameters
(
objective
:
TensorVariable
,
x
:
TensorVariable
)
->
list
[
Variable
]:
"""
"""
Find the parameters of the optimization problem that are not the variable `x`.
Find the parameters of the optimization problem that are not the variable `x`.
...
@@ -140,23 +141,19 @@ def _find_optimization_parameters(objective: TensorVariable, x: TensorVariable):
...
@@ -140,23 +141,19 @@ def _find_optimization_parameters(objective: TensorVariable, x: TensorVariable):
def
_get_parameter_grads_from_vector
(
def
_get_parameter_grads_from_vector
(
grad_wrt_args_vector
:
Variable
,
grad_wrt_args_vector
:
Tensor
Variable
,
x_star
:
Variable
,
x_star
:
Tensor
Variable
,
args
:
Sequence
[
Variable
],
args
:
Sequence
[
Variable
],
output_grad
:
Variable
,
output_grad
:
Tensor
Variable
,
):
)
->
list
[
TensorVariable
]
:
"""
"""
Given a single concatenated vector of objective function gradients with respect to raveled optimization parameters,
Given a single concatenated vector of objective function gradients with respect to raveled optimization parameters,
returns the contribution of each parameter to the total loss function, with the unraveled shape of the parameter.
returns the contribution of each parameter to the total loss function, with the unraveled shape of the parameter.
"""
"""
grad_wrt_args_vector
=
cast
(
TensorVariable
,
grad_wrt_args_vector
)
x_star
=
cast
(
TensorVariable
,
x_star
)
cursor
=
0
cursor
=
0
grad_wrt_args
=
[]
grad_wrt_args
=
[]
for
arg
in
args
:
for
arg
in
args
:
arg
=
cast
(
TensorVariable
,
arg
)
arg_shape
=
arg
.
shape
arg_shape
=
arg
.
shape
arg_size
=
arg_shape
.
prod
()
arg_size
=
arg_shape
.
prod
()
arg_grad
=
grad_wrt_args_vector
[:,
cursor
:
cursor
+
arg_size
]
.
reshape
(
arg_grad
=
grad_wrt_args_vector
[:,
cursor
:
cursor
+
arg_size
]
.
reshape
(
...
@@ -268,17 +265,16 @@ class ScipyVectorWrapperOp(ScipyWrapperOp):
...
@@ -268,17 +265,16 @@ class ScipyVectorWrapperOp(ScipyWrapperOp):
def
scalar_implict_optimization_grads
(
def
scalar_implict_optimization_grads
(
inner_fx
:
Variable
,
inner_fx
:
Tensor
Variable
,
inner_x
:
Variable
,
inner_x
:
Tensor
Variable
,
inner_args
:
Sequence
[
Variable
],
inner_args
:
Sequence
[
Variable
],
args
:
Sequence
[
Variable
],
args
:
Sequence
[
Variable
],
x_star
:
Variable
,
x_star
:
Tensor
Variable
,
output_grad
:
Variable
,
output_grad
:
Tensor
Variable
,
fgraph
:
FunctionGraph
,
fgraph
:
FunctionGraph
,
)
->
list
[
Variable
]:
)
->
list
[
Variable
]:
df_dx
,
*
df_dthetas
=
cast
(
df_dx
,
*
df_dthetas
=
grad
(
list
[
Variable
],
inner_fx
,
[
inner_x
,
*
inner_args
],
disconnected_inputs
=
"ignore"
grad
(
inner_fx
,
[
inner_x
,
*
inner_args
],
disconnected_inputs
=
"ignore"
),
)
)
replace
=
dict
(
zip
(
fgraph
.
inputs
,
(
x_star
,
*
args
),
strict
=
True
))
replace
=
dict
(
zip
(
fgraph
.
inputs
,
(
x_star
,
*
args
),
strict
=
True
))
...
@@ -286,20 +282,20 @@ def scalar_implict_optimization_grads(
...
@@ -286,20 +282,20 @@ def scalar_implict_optimization_grads(
grad_wrt_args
=
[
grad_wrt_args
=
[
(
-
df_dtheta_star
/
df_dx_star
)
*
output_grad
(
-
df_dtheta_star
/
df_dx_star
)
*
output_grad
for
df_dtheta_star
in
cast
(
list
[
TensorVariable
],
df_dthetas_stars
)
for
df_dtheta_star
in
df_dthetas_stars
]
]
return
grad_wrt_args
return
grad_wrt_args
def
implict_optimization_grads
(
def
implict_optimization_grads
(
df_dx
:
Variable
,
df_dx
:
Tensor
Variable
,
df_dtheta_columns
:
Sequence
[
Variable
],
df_dtheta_columns
:
Sequence
[
Tensor
Variable
],
args
:
Sequence
[
Variable
],
args
:
Sequence
[
Variable
],
x_star
:
Variable
,
x_star
:
Tensor
Variable
,
output_grad
:
Variable
,
output_grad
:
Tensor
Variable
,
fgraph
:
FunctionGraph
,
fgraph
:
FunctionGraph
,
):
)
->
list
[
TensorVariable
]
:
r"""
r"""
Compute gradients of an optimization problem with respect to its parameters.
Compute gradients of an optimization problem with respect to its parameters.
...
@@ -341,21 +337,15 @@ def implict_optimization_grads(
...
@@ -341,21 +337,15 @@ def implict_optimization_grads(
fgraph : FunctionGraph
fgraph : FunctionGraph
The function graph that contains the inputs and outputs of the optimization problem.
The function graph that contains the inputs and outputs of the optimization problem.
"""
"""
df_dx
=
cast
(
TensorVariable
,
df_dx
)
df_dtheta
=
concatenate
(
df_dtheta
=
concatenate
(
[
[
atleast_2d
(
jac_col
,
left
=
False
)
for
jac_col
in
df_dtheta_columns
],
atleast_2d
(
jac_col
,
left
=
False
)
for
jac_col
in
cast
(
list
[
TensorVariable
],
df_dtheta_columns
)
],
axis
=-
1
,
axis
=-
1
,
)
)
replace
=
dict
(
zip
(
fgraph
.
inputs
,
(
x_star
,
*
args
),
strict
=
True
))
replace
=
dict
(
zip
(
fgraph
.
inputs
,
(
x_star
,
*
args
),
strict
=
True
))
df_dx_star
,
df_dtheta_star
=
cast
(
df_dx_star
,
df_dtheta_star
=
graph_replace
(
list
[
TensorVariable
],
[
atleast_2d
(
df_dx
),
df_dtheta
],
replace
=
replace
graph_replace
([
atleast_2d
(
df_dx
),
df_dtheta
],
replace
=
replace
),
)
)
grad_wrt_args_vector
=
solve
(
-
df_dx_star
,
df_dtheta_star
)
grad_wrt_args_vector
=
solve
(
-
df_dx_star
,
df_dtheta_star
)
...
@@ -369,20 +359,24 @@ def implict_optimization_grads(
...
@@ -369,20 +359,24 @@ def implict_optimization_grads(
class
MinimizeScalarOp
(
ScipyScalarWrapperOp
):
class
MinimizeScalarOp
(
ScipyScalarWrapperOp
):
def
__init__
(
def
__init__
(
self
,
self
,
x
:
Variable
,
x
:
Tensor
Variable
,
*
args
:
Variable
,
*
args
:
Variable
,
objective
:
Variable
,
objective
:
Tensor
Variable
,
method
:
str
=
"brent"
,
method
:
str
,
optimizer_kwargs
:
dict
|
None
=
None
,
optimizer_kwargs
:
dict
|
None
=
None
,
):
):
if
not
cast
(
TensorVariable
,
x
)
.
ndim
==
0
:
if
not
(
isinstance
(
x
,
TensorVariable
)
and
x
.
ndim
==
0
)
:
raise
ValueError
(
raise
ValueError
(
"The variable `x` must be a scalar (0-dimensional) tensor for minimize_scalar."
"The variable `x` must be a scalar (0-dimensional) tensor for minimize_scalar."
)
)
if
not
cast
(
TensorVariable
,
objective
)
.
ndim
==
0
:
if
not
(
isinstance
(
objective
,
TensorVariable
)
and
objective
.
ndim
==
0
)
:
raise
ValueError
(
raise
ValueError
(
"The objective function must be a scalar (0-dimensional) tensor for minimize_scalar."
"The objective function must be a scalar (0-dimensional) tensor for minimize_scalar."
)
)
if
x
not
in
ancestors
([
objective
]):
raise
ValueError
(
"The variable `x` must be an input to the computational graph of the objective function."
)
self
.
fgraph
=
FunctionGraph
([
x
,
*
args
],
[
objective
])
self
.
fgraph
=
FunctionGraph
([
x
,
*
args
],
[
objective
])
self
.
method
=
method
self
.
method
=
method
...
@@ -468,7 +462,6 @@ def minimize_scalar(
...
@@ -468,7 +462,6 @@ def minimize_scalar(
Symbolic boolean flag indicating whether the minimization routine reported convergence to a minimum
Symbolic boolean flag indicating whether the minimization routine reported convergence to a minimum
value, based on the requested convergence criteria.
value, based on the requested convergence criteria.
"""
"""
args
=
_find_optimization_parameters
(
objective
,
x
)
args
=
_find_optimization_parameters
(
objective
,
x
)
minimize_scalar_op
=
MinimizeScalarOp
(
minimize_scalar_op
=
MinimizeScalarOp
(
...
@@ -479,9 +472,7 @@ def minimize_scalar(
...
@@ -479,9 +472,7 @@ def minimize_scalar(
optimizer_kwargs
=
optimizer_kwargs
,
optimizer_kwargs
=
optimizer_kwargs
,
)
)
solution
,
success
=
cast
(
solution
,
success
=
minimize_scalar_op
(
x
,
*
args
)
tuple
[
TensorVariable
,
TensorVariable
],
minimize_scalar_op
(
x
,
*
args
)
)
return
solution
,
success
return
solution
,
success
...
@@ -489,17 +480,21 @@ def minimize_scalar(
...
@@ -489,17 +480,21 @@ def minimize_scalar(
class
MinimizeOp
(
ScipyVectorWrapperOp
):
class
MinimizeOp
(
ScipyVectorWrapperOp
):
def
__init__
(
def
__init__
(
self
,
self
,
x
:
Variable
,
x
:
Tensor
Variable
,
*
args
:
Variable
,
*
args
:
Variable
,
objective
:
Variable
,
objective
:
Tensor
Variable
,
method
:
str
=
"BFGS"
,
method
:
str
,
jac
:
bool
=
True
,
jac
:
bool
=
True
,
hess
:
bool
=
False
,
hess
:
bool
=
False
,
hessp
:
bool
=
False
,
hessp
:
bool
=
False
,
use_vectorized_jac
:
bool
=
False
,
use_vectorized_jac
:
bool
=
False
,
optimizer_kwargs
:
dict
|
None
=
None
,
optimizer_kwargs
:
dict
|
None
=
None
,
):
):
if
not
cast
(
TensorVariable
,
objective
)
.
ndim
==
0
:
if
not
(
isinstance
(
x
,
TensorVariable
)
and
x
.
ndim
in
(
0
,
1
)):
raise
ValueError
(
"The variable `x` must be a scalar or vector (0-or-1-dimensional) tensor for minimize."
)
if
not
(
isinstance
(
objective
,
TensorVariable
)
and
objective
.
ndim
==
0
):
raise
ValueError
(
raise
ValueError
(
"The objective function must be a scalar (0-dimensional) tensor for minimize."
"The objective function must be a scalar (0-dimensional) tensor for minimize."
)
)
...
@@ -512,19 +507,14 @@ class MinimizeOp(ScipyVectorWrapperOp):
...
@@ -512,19 +507,14 @@ class MinimizeOp(ScipyVectorWrapperOp):
self
.
use_vectorized_jac
=
use_vectorized_jac
self
.
use_vectorized_jac
=
use_vectorized_jac
if
jac
:
if
jac
:
grad_wrt_x
=
cast
(
grad_wrt_x
=
grad
(
self
.
fgraph
.
outputs
[
0
],
self
.
fgraph
.
inputs
[
0
])
Variable
,
grad
(
self
.
fgraph
.
outputs
[
0
],
self
.
fgraph
.
inputs
[
0
])
)
self
.
fgraph
.
add_output
(
grad_wrt_x
)
self
.
fgraph
.
add_output
(
grad_wrt_x
)
if
hess
:
if
hess
:
hess_wrt_x
=
cast
(
hess_wrt_x
=
jacobian
(
Variable
,
self
.
fgraph
.
outputs
[
-
1
],
jacobian
(
self
.
fgraph
.
inputs
[
0
],
self
.
fgraph
.
outputs
[
-
1
],
vectorize
=
use_vectorized_jac
,
self
.
fgraph
.
inputs
[
0
],
vectorize
=
use_vectorized_jac
,
),
)
)
self
.
fgraph
.
add_output
(
hess_wrt_x
)
self
.
fgraph
.
add_output
(
hess_wrt_x
)
...
@@ -654,9 +644,7 @@ def minimize(
...
@@ -654,9 +644,7 @@ def minimize(
optimizer_kwargs
=
optimizer_kwargs
,
optimizer_kwargs
=
optimizer_kwargs
,
)
)
solution
,
success
=
cast
(
solution
,
success
=
minimize_op
(
x
,
*
args
)
tuple
[
TensorVariable
,
TensorVariable
],
minimize_op
(
x
,
*
args
)
)
return
solution
,
success
return
solution
,
success
...
@@ -664,21 +652,23 @@ def minimize(
...
@@ -664,21 +652,23 @@ def minimize(
class
RootScalarOp
(
ScipyScalarWrapperOp
):
class
RootScalarOp
(
ScipyScalarWrapperOp
):
def
__init__
(
def
__init__
(
self
,
self
,
variables
,
variables
:
TensorVariable
,
*
args
,
*
args
:
Variable
,
equation
,
equation
:
TensorVariable
,
method
,
method
:
str
,
jac
:
bool
=
False
,
jac
:
bool
=
False
,
hess
:
bool
=
False
,
hess
:
bool
=
False
,
optimizer_kwargs
=
None
,
optimizer_kwargs
=
None
,
):
):
if
not
equation
.
ndim
==
0
:
if
not
(
isinstance
(
variables
,
TensorVariable
)
and
variables
.
ndim
==
0
):
raise
ValueError
(
"The variable `x` must be a scalar (0-dimensional) tensor for root_scalar."
)
if
not
(
isinstance
(
equation
,
TensorVariable
)
and
equation
.
ndim
==
0
):
raise
ValueError
(
raise
ValueError
(
"The equation must be a scalar (0-dimensional) tensor for root_scalar."
"The equation must be a scalar (0-dimensional) tensor for root_scalar."
)
)
if
not
isinstance
(
variables
,
Variable
)
or
variables
not
in
ancestors
(
if
variables
not
in
ancestors
([
equation
]):
[
equation
]
):
raise
ValueError
(
raise
ValueError
(
"The variable `variables` must be an input to the computational graph of the equation."
"The variable `variables` must be an input to the computational graph of the equation."
)
)
...
@@ -686,9 +676,7 @@ class RootScalarOp(ScipyScalarWrapperOp):
...
@@ -686,9 +676,7 @@ class RootScalarOp(ScipyScalarWrapperOp):
self
.
fgraph
=
FunctionGraph
([
variables
,
*
args
],
[
equation
])
self
.
fgraph
=
FunctionGraph
([
variables
,
*
args
],
[
equation
])
if
jac
:
if
jac
:
f_prime
=
cast
(
f_prime
=
grad
(
self
.
fgraph
.
outputs
[
0
],
self
.
fgraph
.
inputs
[
0
])
Variable
,
grad
(
self
.
fgraph
.
outputs
[
0
],
self
.
fgraph
.
inputs
[
0
])
)
self
.
fgraph
.
add_output
(
f_prime
)
self
.
fgraph
.
add_output
(
f_prime
)
if
hess
:
if
hess
:
...
@@ -697,9 +685,7 @@ class RootScalarOp(ScipyScalarWrapperOp):
...
@@ -697,9 +685,7 @@ class RootScalarOp(ScipyScalarWrapperOp):
"Cannot set `hess=True` without `jac=True`. No methods use second derivatives without also"
"Cannot set `hess=True` without `jac=True`. No methods use second derivatives without also"
" using first derivatives."
" using first derivatives."
)
)
f_double_prime
=
cast
(
f_double_prime
=
grad
(
self
.
fgraph
.
outputs
[
-
1
],
self
.
fgraph
.
inputs
[
0
])
Variable
,
grad
(
self
.
fgraph
.
outputs
[
-
1
],
self
.
fgraph
.
inputs
[
0
])
)
self
.
fgraph
.
add_output
(
f_double_prime
)
self
.
fgraph
.
add_output
(
f_double_prime
)
self
.
method
=
method
self
.
method
=
method
...
@@ -813,9 +799,7 @@ def root_scalar(
...
@@ -813,9 +799,7 @@ def root_scalar(
optimizer_kwargs
=
optimizer_kwargs
,
optimizer_kwargs
=
optimizer_kwargs
,
)
)
solution
,
success
=
cast
(
solution
,
success
=
root_scalar_op
(
variable
,
*
args
)
tuple
[
TensorVariable
,
TensorVariable
],
root_scalar_op
(
variable
,
*
args
)
)
return
solution
,
success
return
solution
,
success
...
@@ -825,15 +809,19 @@ class RootOp(ScipyVectorWrapperOp):
...
@@ -825,15 +809,19 @@ class RootOp(ScipyVectorWrapperOp):
def
__init__
(
def
__init__
(
self
,
self
,
variables
:
Variable
,
variables
:
Tensor
Variable
,
*
args
:
Variable
,
*
args
:
Variable
,
equations
:
Variable
,
equations
:
Tensor
Variable
,
method
:
str
=
"hybr"
,
method
:
str
,
jac
:
bool
=
True
,
jac
:
bool
=
True
,
optimizer_kwargs
:
dict
|
None
=
None
,
optimizer_kwargs
:
dict
|
None
=
None
,
use_vectorized_jac
:
bool
=
False
,
use_vectorized_jac
:
bool
=
False
,
):
):
if
cast
(
TensorVariable
,
variables
)
.
ndim
!=
cast
(
TensorVariable
,
equations
)
.
ndim
:
if
not
isinstance
(
variables
,
TensorVariable
):
raise
ValueError
(
"The variable `variables` must be a tensor for root."
)
if
not
isinstance
(
equations
,
TensorVariable
):
raise
ValueError
(
"The equations must be a tensor for root."
)
if
variables
.
ndim
!=
equations
.
ndim
:
raise
ValueError
(
raise
ValueError
(
"The variable `variables` must have the same number of dimensions as the equations."
"The variable `variables` must have the same number of dimensions as the equations."
)
)
...
@@ -916,12 +904,8 @@ class RootOp(ScipyVectorWrapperOp):
...
@@ -916,12 +904,8 @@ class RootOp(ScipyVectorWrapperOp):
outputs
[
0
][
0
]
=
res
.
x
.
reshape
(
variables
.
shape
)
.
astype
(
variables
.
dtype
)
outputs
[
0
][
0
]
=
res
.
x
.
reshape
(
variables
.
shape
)
.
astype
(
variables
.
dtype
)
outputs
[
1
][
0
]
=
np
.
bool_
(
res
.
success
)
outputs
[
1
][
0
]
=
np
.
bool_
(
res
.
success
)
def
L_op
(
def
L_op
(
self
,
inputs
,
outputs
,
output_grads
):
self
,
# TODO: Handle disconnected inputs
inputs
:
Sequence
[
Variable
],
outputs
:
Sequence
[
Variable
],
output_grads
:
Sequence
[
Variable
],
)
->
list
[
Variable
]:
x
,
*
args
=
inputs
x
,
*
args
=
inputs
x_star
,
_
=
outputs
x_star
,
_
=
outputs
output_grad
,
_
=
output_grads
output_grad
,
_
=
output_grads
...
@@ -1004,9 +988,7 @@ def root(
...
@@ -1004,9 +988,7 @@ def root(
use_vectorized_jac
=
use_vectorized_jac
,
use_vectorized_jac
=
use_vectorized_jac
,
)
)
solution
,
success
=
cast
(
solution
,
success
=
root_op
(
variables
,
*
args
)
tuple
[
TensorVariable
,
TensorVariable
],
root_op
(
variables
,
*
args
)
)
return
solution
,
success
return
solution
,
success
...
...
scripts/mypy-failing.txt
浏览文件 @
e2cb1e2d
...
@@ -15,6 +15,7 @@ pytensor/tensor/blas_headers.py
...
@@ -15,6 +15,7 @@ pytensor/tensor/blas_headers.py
pytensor/tensor/elemwise.py
pytensor/tensor/elemwise.py
pytensor/tensor/extra_ops.py
pytensor/tensor/extra_ops.py
pytensor/tensor/math.py
pytensor/tensor/math.py
pytensor/tensor/optimize.py
pytensor/tensor/random/basic.py
pytensor/tensor/random/basic.py
pytensor/tensor/random/op.py
pytensor/tensor/random/op.py
pytensor/tensor/random/utils.py
pytensor/tensor/random/utils.py
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论