Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
P
pytensor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
testgroup
pytensor
Commits
9adfd678
提交
9adfd678
authored
10月 16, 2009
作者:
James Bergstra
浏览文件
操作
浏览文件
下载
差异文件
merge
上级
4b7f6f87
e568c558
全部展开
显示空白字符变更
内嵌
并排
正在显示
7 个修改的文件
包含
136 行增加
和
20 行删除
+136
-20
__init__.py
theano/compile/sandbox/__init__.py
+2
-2
cc.py
theano/gof/cc.py
+19
-9
cmodule.py
theano/gof/cmodule.py
+2
-1
debug.py
theano/sandbox/debug.py
+1
-1
basic.py
theano/scalar/basic.py
+50
-7
opt.py
theano/tensor/opt.py
+62
-0
test_opt.py
theano/tensor/tests/test_opt.py
+0
-0
没有找到文件。
theano/compile/sandbox/__init__.py
浏览文件 @
9adfd678
from
.sharedvalue
import
shared
,
shared_constructor
from
theano.compile.sandbox
.sharedvalue
import
shared
,
shared_constructor
from
.pfunc
import
pfunc
from
theano.compile.sandbox
.pfunc
import
pfunc
theano/gof/cc.py
浏览文件 @
9adfd678
...
@@ -792,14 +792,24 @@ class CLinker(link.Linker):
...
@@ -792,14 +792,24 @@ class CLinker(link.Linker):
function raises a KeyError exception.
function raises a KeyError exception.
"""
"""
order
=
list
(
self
.
env
.
toposort
())
return
self
.
cmodule_key_
(
self
.
env
,
self
.
no_recycling
,
env_inputs_dict
=
dict
((
i
,
[
-
1
,
pos
])
for
pos
,
i
in
enumerate
(
self
.
env
.
inputs
))
compile_args
=
self
.
compile_args
(),
libraries
=
self
.
libraries
()
)
@staticmethod
def
cmodule_key_
(
env
,
no_recycling
,
compile_args
=
None
,
libraries
=
None
):
"""
Do the actual computation of cmodule_key in a static method
to allow it to be reused in scalar.Composite.__eq__
"""
order
=
list
(
env
.
toposort
())
env_computed_set
=
set
()
env_computed_set
=
set
()
env_inputs_dict
=
dict
((
i
,
[
-
1
,
pos
])
for
pos
,
i
in
enumerate
(
env
.
inputs
))
constant_ids
=
dict
()
constant_ids
=
dict
()
op_pos
=
{}
# Apply -> topological position
op_pos
=
{}
# Apply -> topological position
rval
=
[
'CLinker.cmodule_key'
]
# will be cast to tuple on return
rval
=
[
'CLinker.cmodule_key'
]
# will be cast to tuple on return
rval
.
append
(
tuple
(
self
.
compile_args
()
))
if
compile_args
is
not
None
:
rval
.
append
(
tuple
(
compile_args
))
rval
.
append
(
tuple
(
self
.
libraries
()
))
if
libraries
is
not
None
:
rval
.
append
(
tuple
(
libraries
))
version
=
[]
version
=
[]
# assert that every input to every node is one of'
# assert that every input to every node is one of'
...
@@ -822,16 +832,16 @@ class CLinker(link.Linker):
...
@@ -822,16 +832,16 @@ class CLinker(link.Linker):
else
:
else
:
if
i
.
owner
is
None
:
if
i
.
owner
is
None
:
assert
all
(
all
(
out
is
not
None
for
out
in
o
.
outputs
)
for
o
in
order
)
assert
all
(
all
(
out
is
not
None
for
out
in
o
.
outputs
)
for
o
in
order
)
assert
all
(
input
.
owner
is
None
for
input
in
self
.
env
.
inputs
)
assert
all
(
input
.
owner
is
None
for
input
in
env
.
inputs
)
raise
Exception
(
'what is this?'
,
(
i
,
type
(
i
),
i
.
clients
,
self
.
env
))
raise
Exception
(
'what is this?'
,
(
i
,
type
(
i
),
i
.
clients
,
env
))
if
i
in
self
.
env
.
outputs
:
if
i
in
env
.
outputs
:
rval
+=
[
op_pos
[
i
.
owner
],
# outputs
rval
+=
[
op_pos
[
i
.
owner
],
# outputs
i
.
owner
.
outputs
.
index
(
i
),
i
.
owner
.
outputs
.
index
(
i
),
self
.
env
.
outputs
.
index
(
i
)]
env
.
outputs
.
index
(
i
)]
else
:
else
:
rval
+=
[
op_pos
[
i
.
owner
],
i
.
owner
.
outputs
.
index
(
i
)]
# temps
rval
+=
[
op_pos
[
i
.
owner
],
i
.
owner
.
outputs
.
index
(
i
)]
# temps
assert
rval
assert
rval
rval
.
append
(
i
in
self
.
no_recycling
)
rval
.
append
(
i
in
no_recycling
)
return
tuple
(
rval
)
return
tuple
(
rval
)
for
node_pos
,
node
in
enumerate
(
order
):
for
node_pos
,
node
in
enumerate
(
order
):
...
...
theano/gof/cmodule.py
浏览文件 @
9adfd678
...
@@ -386,7 +386,7 @@ class ModuleCache(object):
...
@@ -386,7 +386,7 @@ class ModuleCache(object):
try
:
try
:
module
=
fn
(
location
=
location
)
# WILL FAIL FOR BAD C CODE
module
=
fn
(
location
=
location
)
# WILL FAIL FOR BAD C CODE
except
Exception
,
e
:
except
Exception
,
e
:
shutil
.
rmtree
(
location
)
_
rmtree
(
location
)
#try:
#try:
#except Exception, ee:
#except Exception, ee:
#error('failed to cleanup location', location, ee)
#error('failed to cleanup location', location, ee)
...
@@ -515,6 +515,7 @@ class ModuleCache(object):
...
@@ -515,6 +515,7 @@ class ModuleCache(object):
def
_rmtree
(
parent
):
def
_rmtree
(
parent
):
try
:
try
:
if
not
os
.
getenv
(
'THEANO_NOCLEANUP'
,
0
):
shutil
.
rmtree
(
parent
)
shutil
.
rmtree
(
parent
)
except
Exception
,
e
:
except
Exception
,
e
:
try
:
try
:
...
...
theano/sandbox/debug.py
浏览文件 @
9adfd678
from
..
import
gof
from
theano
import
gof
import
sys
import
sys
...
...
theano/scalar/basic.py
浏览文件 @
9adfd678
...
@@ -348,6 +348,9 @@ def int_out(*types):
...
@@ -348,6 +348,9 @@ def int_out(*types):
def
float_out
(
*
types
):
def
float_out
(
*
types
):
return
float64
,
return
float64
,
def
upgrade_to_float
(
*
types
):
def
upgrade_to_float
(
*
types
):
"""
This upgrade the types to float32 or float64 to don't loose any precision.
"""
conv
=
{
int8
:
float32
,
conv
=
{
int8
:
float32
,
int16
:
float32
,
int16
:
float32
,
int32
:
float64
,
int32
:
float64
,
...
@@ -370,8 +373,8 @@ class ScalarOp(Op):
...
@@ -370,8 +373,8 @@ class ScalarOp(Op):
def
make_node
(
self
,
*
inputs
):
def
make_node
(
self
,
*
inputs
):
if
self
.
nin
>=
0
:
if
self
.
nin
>=
0
:
if
len
(
inputs
)
!=
self
.
nin
:
if
len
(
inputs
)
!=
self
.
nin
:
raise
TypeError
(
"Wrong number of inputs for
%
s.make_node (got
%
i, expected
%
i)"
\
raise
TypeError
(
"Wrong number of inputs for
%
s.make_node (got
%
i
(
%
s)
, expected
%
i)"
\
%
(
self
,
len
(
inputs
),
self
.
nin
))
%
(
self
,
len
(
inputs
),
s
tr
(
inputs
),
s
elf
.
nin
))
inputs
=
[
as_scalar
(
input
)
for
input
in
inputs
]
inputs
=
[
as_scalar
(
input
)
for
input
in
inputs
]
outputs
=
[
t
()
for
t
in
self
.
output_types
([
input
.
type
for
input
in
inputs
])]
outputs
=
[
t
()
for
t
in
self
.
output_types
([
input
.
type
for
input
in
inputs
])]
if
len
(
outputs
)
!=
self
.
nout
:
if
len
(
outputs
)
!=
self
.
nout
:
...
@@ -977,6 +980,7 @@ class Inv(UnaryScalarOp):
...
@@ -977,6 +980,7 @@ class Inv(UnaryScalarOp):
inv
=
Inv
(
upgrade_to_float
,
name
=
'inv'
)
inv
=
Inv
(
upgrade_to_float
,
name
=
'inv'
)
class
Log
(
UnaryScalarOp
):
class
Log
(
UnaryScalarOp
):
""" log base e """
def
impl
(
self
,
x
):
def
impl
(
self
,
x
):
return
math
.
log
(
x
)
return
math
.
log
(
x
)
def
grad
(
self
,
(
x
,
),
(
gz
,
)):
def
grad
(
self
,
(
x
,
),
(
gz
,
)):
...
@@ -994,6 +998,7 @@ class Log(UnaryScalarOp):
...
@@ -994,6 +998,7 @@ class Log(UnaryScalarOp):
log
=
Log
(
upgrade_to_float
,
name
=
'log'
)
log
=
Log
(
upgrade_to_float
,
name
=
'log'
)
class
Log2
(
UnaryScalarOp
):
class
Log2
(
UnaryScalarOp
):
""" log base 2 """
def
impl
(
self
,
x
):
def
impl
(
self
,
x
):
return
numpy
.
log2
(
x
)
return
numpy
.
log2
(
x
)
def
grad
(
self
,
(
x
,
),
(
gz
,
)):
def
grad
(
self
,
(
x
,
),
(
gz
,
)):
...
@@ -1009,6 +1014,7 @@ class Log2(UnaryScalarOp):
...
@@ -1009,6 +1014,7 @@ class Log2(UnaryScalarOp):
log2
=
Log2
(
upgrade_to_float
,
name
=
'log2'
)
log2
=
Log2
(
upgrade_to_float
,
name
=
'log2'
)
class
Log10
(
UnaryScalarOp
):
class
Log10
(
UnaryScalarOp
):
""" log base 10 """
def
impl
(
self
,
x
):
def
impl
(
self
,
x
):
return
numpy
.
log10
(
x
)
return
numpy
.
log10
(
x
)
def
grad
(
self
,
(
x
,
),
(
gz
,
)):
def
grad
(
self
,
(
x
,
),
(
gz
,
)):
...
@@ -1170,6 +1176,14 @@ class Composite(ScalarOp):
...
@@ -1170,6 +1176,14 @@ class Composite(ScalarOp):
implement the loop fusion optimizer (which I have yet to do
implement the loop fusion optimizer (which I have yet to do
someday...)
someday...)
"""
"""
def
__str__
(
self
):
if
hasattr
(
self
,
'name'
)
and
self
.
name
:
return
self
.
name
else
:
return
"
%
s{
%
s}"
%
(
self
.
__class__
.
__name__
,
", "
.
join
(
"
%
s=
%
s"
%
(
k
,
v
)
for
k
,
v
in
self
.
__dict__
.
items
()
if
k
not
in
[
"name"
,
"env"
,
"_c_code"
]
))
def
__init__
(
self
,
inputs
,
outputs
):
def
__init__
(
self
,
inputs
,
outputs
):
env
=
Env
(
*
gof
.
graph
.
clone
(
inputs
,
outputs
))
env
=
Env
(
*
gof
.
graph
.
clone
(
inputs
,
outputs
))
gof
.
MergeOptimizer
()
.
optimize
(
env
)
gof
.
MergeOptimizer
()
.
optimize
(
env
)
...
@@ -1233,12 +1247,15 @@ class Composite(ScalarOp):
...
@@ -1233,12 +1247,15 @@ class Composite(ScalarOp):
self
.
nin
=
len
(
inputs
)
self
.
nin
=
len
(
inputs
)
self
.
nout
=
len
(
outputs
)
self
.
nout
=
len
(
outputs
)
self
.
env
=
env
self
.
env
=
env
self
.
inputs_type
=
tuple
([
input
.
type
for
input
in
self
.
env
.
inputs
])
self
.
outputs_type
=
tuple
([
output
.
type
for
output
in
self
.
env
.
outputs
])
self
.
_rehash
()
def
output_types
(
self
,
input_types
):
def
output_types
(
self
,
input_types
):
if
tuple
(
input_types
)
!=
tuple
([
input
.
type
for
input
in
self
.
env
.
inputs
])
:
if
tuple
(
input_types
)
!=
self
.
inputs_type
:
raise
TypeError
(
"Wrong types for Composite. Expected
%
s, got
%
s."
raise
TypeError
(
"Wrong types for Composite. Expected
%
s, got
%
s."
%
(
tuple
([
input
.
type
for
input
in
self
.
env
.
inputs
])
,
tuple
(
input_types
)))
%
(
self
.
inputs_type
,
tuple
(
input_types
)))
return
[
output
.
type
for
output
in
self
.
env
.
outputs
]
return
self
.
outputs_type
def
perform
(
self
,
node
,
inputs
,
output_storage
):
def
perform
(
self
,
node
,
inputs
,
output_storage
):
for
storage
,
impl
in
zip
(
output_storage
,
self
.
_impls
):
for
storage
,
impl
in
zip
(
output_storage
,
self
.
_impls
):
...
@@ -1259,10 +1276,36 @@ class Composite(ScalarOp):
...
@@ -1259,10 +1276,36 @@ class Composite(ScalarOp):
onames
),
onames
),
**
sub
)
**
sub
)
d
[
'name'
]
=
name
d
[
'name'
]
=
name
if
not
sub
.
has_key
(
'id'
):
#The use of a dummy id is safe as the code is in a separate block.
#It won't generate conflicting variable name.
d
[
'id'
]
=
'_DUMMY_ID_'
return
self
.
_c_code
%
d
return
self
.
_c_code
%
d
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
return
self
is
other
if
self
is
other
:
return
True
if
not
isinstance
(
other
,
self
.
__class__
):
return
False
if
self
.
nin
!=
other
.
nin
or
self
.
nout
!=
other
.
nout
:
return
False
return
self
.
_hashval
==
other
.
_hashval
return
self
.
_cmodule_key
==
other
.
_cmodule_key
def
_rehash
(
self
):
#TODO: What no_recycling is used for? What I need to put their?
# no_recycling = []
self
.
_cmodule_key
=
gof
.
CLinker
.
cmodule_key_
(
self
.
env
,
[])
self
.
_hashval
=
hash
(
self
.
_cmodule_key
)
def
__hash__
(
self
):
def
__hash__
(
self
):
return
id
(
self
)
return
self
.
_hashval
# def __getstate__(self):
# d = copy(self.__dict__)
# d.pop('env')
# d.pop('_impls')
# #TODO: the self._impls must be restored to allow the perform to work.(c version continue to work.
# return d
# def __setstate__(self, d):
# self.__dict__.update(d)
# #TODO: how to restore the _impls?
theano/tensor/opt.py
浏览文件 @
9adfd678
...
@@ -1227,6 +1227,68 @@ register_canonicalize(local_transposed_dot, name='local_transposed_dot')
...
@@ -1227,6 +1227,68 @@ register_canonicalize(local_transposed_dot, name='local_transposed_dot')
# # Loop fusion #
# # Loop fusion #
# ###############
# ###############
@gof.local_optimizer
([
T
.
Elemwise
,
T
.
Elemwise
])
def
local_elemwise_fusion
(
node
):
"""
As part of specialisation, we fusion two consecutif elemwise op of the same shape.
For mixed dtype, we let the Compise op do the cast. It let the C compile do the cast.
The number of dimension is validated at call time by theano itself.
TODO:The broadcast flag?
"""
# TODO:implement Composite.__eq__ by using CLinker.cmodule_key() to compare the graph.
#TODO: Merge when nb_clients>1? When this optimisation could introduce duplication of computation? When this will be faster?
if
not
isinstance
(
node
.
op
,
T
.
Elemwise
):
return
False
nb_elemwise
=
0
inputs
=
[]
#inputs of the new Elemwise op.
s_inputs
=
[]
#inputs of the new scalar op.
s_g
=
[]
#graph of scalar, what will by done in the inner loop.
for
i
in
node
.
inputs
:
if
i
.
owner
and
isinstance
(
i
.
owner
.
op
,
T
.
Elemwise
)
and
len
(
i
.
clients
)
<=
1
:
if
len
(
i
.
clients
)
>
1
:
#should we put this in the first if, then we would go to the elif to don't fuse it?
#if one of the inputs have more then 1 clients and it is an intermediate result. We don't fuse.
print
"local_elemwise_fusion: Elemwise inputs have more then 1 client. Don't optimise for now"
return
False
nb_elemwise
+=
1
inputs
.
extend
(
i
.
owner
.
inputs
)
s_input
=
[
scalar
.
Scalar
(
x
.
dtype
)
.
make_variable
()
for
x
in
i
.
owner
.
inputs
]
s_inputs
.
extend
(
s_input
)
s_op
=
i
.
owner
.
op
.
scalar_op
(
*
s_input
)
s_g
.
append
(
s_op
)
else
:
if
i
.
owner
and
isinstance
(
i
.
owner
.
op
,
T
.
Elemwise
)
and
len
(
i
.
clients
)
>
1
:
#should we put this in the first if, then we would go to the elif to don't fuse it?
print
"local_elemwise_fusion: inputs have more then 1 client. Don't fuse it for now.!"
return
False
inputs
.
append
(
i
)
s
=
scalar
.
Scalar
(
i
.
dtype
)
.
make_variable
()
s_inputs
.
append
(
s
)
s_g
.
append
(
s
)
#if no inputs have are an elemwise, their is nothing to fuse.
if
nb_elemwise
==
0
:
# print "local_elemwise_fusion: no elemwise in inputs. Nothing to fuse."
return
False
otype
=
node
.
outputs
[
0
]
.
type
s_new_out
=
node
.
op
.
scalar_op
(
*
s_g
)
#create the composite op.
C
=
scalar
.
Composite
(
s_inputs
,[
s_new_out
])
#create the new node.
n
=
T
.
Elemwise
(
C
)
.
make_node
(
*
inputs
)
assert
len
(
n
.
outputs
)
==
1
assert
node
.
outputs
[
0
]
.
dtype
==
n
.
outputs
[
0
]
.
dtype
# print "local_elemwise_fusion: FUSED",nb_elemwise+1,"elemwise!"
return
n
.
outputs
#register_specialize(local_elemwise_fusion)
# def make_composite(inputs, outputs):
# def make_composite(inputs, outputs):
# scalar_inputs = [scalar.Scalar(dtype = i.type.dtype)() for i in inputs]
# scalar_inputs = [scalar.Scalar(dtype = i.type.dtype)() for i in inputs]
# def transform(r):
# def transform(r):
...
...
theano/tensor/tests/test_opt.py
浏览文件 @
9adfd678
差异被折叠。
点击展开。
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论