Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
P
pytensor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
testgroup
pytensor
Commits
d676edaf
提交
d676edaf
authored
3月 15, 2008
作者:
Olivier Breuleux
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
added base_tensor, some reorganizing, recovered some C support
上级
26d56c68
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
7 个修改的文件
包含
218 行增加
和
230 行删除
+218
-230
_test_tensor.py
_test_tensor.py
+8
-1
base_tensor.py
base_tensor.py
+171
-0
elemwise.py
elemwise.py
+3
-21
cc.py
gof/cc.py
+4
-0
gradient.py
gradient.py
+2
-0
tensor.py
tensor.py
+0
-0
tensor_ops.py
tensor_ops.py
+30
-208
没有找到文件。
_test_tensor.py
浏览文件 @
d676edaf
...
@@ -5,6 +5,8 @@ import unittest
...
@@ -5,6 +5,8 @@ import unittest
from
copy
import
copy
from
copy
import
copy
from
compile
import
Function
from
compile
import
Function
import
gradient
import
gradient
import
gof
#TODO: consider moving this function / functionality to gradient.py
#TODO: consider moving this function / functionality to gradient.py
# rationale: it's tricky, and necessary everytime you want to verify
# rationale: it's tricky, and necessary everytime you want to verify
...
@@ -57,7 +59,7 @@ class T_tensor(unittest.TestCase):
...
@@ -57,7 +59,7 @@ class T_tensor(unittest.TestCase):
def
test0_int
(
self
):
# allocate from a scalar float
def
test0_int
(
self
):
# allocate from a scalar float
t
=
tensor
(
1
)
t
=
tensor
(
1
)
self
.
failUnless
(
isinstance
(
t
,
Tensor
))
self
.
failUnless
(
isinstance
(
t
,
Tensor
))
self
.
failUnless
(
t
.
dtype
==
'int64'
)
self
.
failUnless
(
t
.
dtype
==
'int64'
or
t
.
dtype
==
'int32'
)
def
test1
(
self
):
# allocate from a vector of ints, not broadcastable
def
test1
(
self
):
# allocate from a vector of ints, not broadcastable
t
=
tensor
(
numpy
.
ones
(
5
,
dtype
=
'int32'
))
t
=
tensor
(
numpy
.
ones
(
5
,
dtype
=
'int32'
))
self
.
failUnless
(
isinstance
(
t
,
Tensor
))
self
.
failUnless
(
isinstance
(
t
,
Tensor
))
...
@@ -141,6 +143,11 @@ def check_eq2(self, inputs, output, args_in, arg_out):
...
@@ -141,6 +143,11 @@ def check_eq2(self, inputs, output, args_in, arg_out):
val
=
fn
(
*
args_in
)
val
=
fn
(
*
args_in
)
self
.
failUnless
(
numpy
.
all
(
val
==
arg_out
),
(
val
,
arg_out
))
self
.
failUnless
(
numpy
.
all
(
val
==
arg_out
),
(
val
,
arg_out
))
def
check_eq2
(
self
,
inputs
,
output
,
args_in
,
arg_out
):
fn
=
Function
(
inputs
,
[
output
],
linker_cls
=
gof
.
CLinker
)
val
=
fn
(
*
args_in
)
self
.
failUnless
(
numpy
.
all
(
val
==
arg_out
),
(
val
,
arg_out
))
class
T_abs
(
unittest
.
TestCase
):
class
T_abs
(
unittest
.
TestCase
):
def
test_impl
(
self
):
def
test_impl
(
self
):
...
...
base_tensor.py
0 → 100644
浏览文件 @
d676edaf
from
gof
import
ResultBase
import
numpy
from
copy
import
copy
###########################
# BaseTensor Class
###########################
class
BaseTensor
(
ResultBase
):
"""ResultBase to store numpy.ndarray or equivalent via .data
Attributes:
_dtype - numpy dtype string such as 'int64' or 'float64' (among others)
_broadcastable - tuple of ints in (0,1) saying which dimensions of this
tensor are guaranteed to be 1, and up for broadcasting
Properties:
dtype - read-only access to _dtype, which should not be changed
broadcastable - read-only access to _broadcastable, which should not be changed
This class does not implement python operators and has no dependencies
on the Ops that use it.
"""
def
__init__
(
self
,
dtype
,
broadcastable
,
role
=
None
,
name
=
None
):
"""Initialize a Tensor"""
# data is not given here. This may seem a bit strange, but when data was
# an argument, it made sense to use *either* the given dtype,
# broadcastable, or override them from the fields of data. This makes
# the function ugly, especially because it isn't obvious how to set
# broadcastable from data.
#
# The only clean option I could think of, when passing a data arg was to
# require the broadcastable field to be given. Since broadcastable is
# the argument that is awkward to construct, I decided to put all this
# into the tensor(data,...) function below, which is like a second
# constructor that works with an ndarray.
ResultBase
.
__init__
(
self
,
role
=
role
,
name
=
name
)
self
.
_dtype
=
str
(
dtype
)
self
.
_broadcastable
=
tuple
(
broadcastable
)
######################
# ResultBase interface
######################
#
# filter
#
def
filter
(
self
,
arr
):
if
not
isinstance
(
arr
,
numpy
.
ndarray
):
arr
=
numpy
.
asarray
(
arr
,
dtype
=
self
.
dtype
)
if
len
(
self
.
broadcastable
)
!=
len
(
arr
.
shape
):
raise
ValueError
(
BaseTensor
.
filter
.
E_rank
)
for
b
,
s
in
zip
(
self
.
broadcastable
,
arr
.
shape
):
if
b
and
(
s
!=
1
):
raise
ValueError
(
BaseTensor
.
filter
.
E_shape
)
return
arr
# these strings are here so that tests can use them
filter
.
E_rank
=
'wrong rank'
filter
.
E_shape
=
'non-unit size on broadcastable dimension'
#
# type information
#
def
dtype_specs
(
self
):
"""Return python - C type correspondance tuple for self.data
Return a tuple (python type, c type, numpy typenum) that corresponds to
self.dtype. It is for use in C code generation.
"""
#TODO: add more type correspondances for e.g. int32, int64, float32,
#complex64, etc.
return
{
'float64'
:
(
float
,
'double'
,
'NPY_DOUBLE'
)}[
self
.
dtype
]
#
# C codegen stubs
#
def
c_declare
(
self
):
return
"""
PyArrayObject*
%%(name)
s;
int type_num_
%%(name)
s;
typedef
%(dtype)
s dtype_
%%(name)
s;
"""
%
dict
(
dtype
=
self
.
dtype_specs
()[
1
])
def
c_init
(
self
):
return
"""
%%(name)
s = NULL;
type_num_
%%(name)
s =
%(type_num)
s;
"""
%
dict
(
type_num
=
self
.
dtype_specs
()[
2
])
def
c_extract
(
self
):
return
"""
%%(name)
s = NULL;
type_num_
%%(name)
s =
%(type_num)
s;
if (py_
%%(name)
s == Py_None) {
// We can either fail here or set
%%(name)
s to NULL and rely on Ops using
// tensors to handle the NULL case, but if they fail to do so they'll end up
// with nasty segfaults, so this is public service.
PyErr_SetString(PyExc_ValueError, "expected an ndarray, not None");
%%(fail)
s
//
%%(name)
s = NULL;
}
else if (!PyArray_Check(py_
%%(name)
s)) {
PyErr_SetString(PyExc_ValueError, "expected an ndarray");
%%(fail)
s
}
else if (((PyArrayObject*)py_
%%(name)
s)->descr->type_num !=
%(type_num)
s) {
PyErr_SetString(PyExc_ValueError, "expected
%(type_num)
s");
%%(fail)
s
}
else {
%%(name)
s = (PyArrayObject*)(py_
%%(name)
s);
Py_XINCREF(
%%(name)
s);
}
"""
%
dict
(
type_num
=
self
.
dtype_specs
()[
2
])
def
c_cleanup
(
self
):
return
"""
if (
%(name)
s) {
Py_XDECREF(
%(name)
s);
}
"""
def
c_sync
(
self
):
return
"""
if (!
%(name)
s) {
Py_XDECREF(py_
%(name)
s);
py_
%(name)
s = Py_None;
}
else if ((void*)py_
%(name)
s != (void*)
%(name)
s) {
Py_XDECREF(py_
%(name)
s);
py_
%(name)
s = (PyObject*)
%(name)
s;
Py_XINCREF(py_
%(name)
s);
}
"""
def
c_headers
(
self
):
return
[]
def
c_libraries
(
self
):
return
[]
############################
# Tensor specific attributes
############################
dtype
=
property
(
lambda
self
:
self
.
_dtype
)
broadcastable
=
property
(
lambda
self
:
self
.
_broadcastable
)
############################
# Cloning facilities
############################
def
__copy__
(
self
):
return
self
.
clone
(
True
)
def
clone
(
self
,
transfer_data
=
False
):
"""
Returns a copy of this Tensor. If there is data stored inside it, it is also copied.
"""
cpy
=
self
.
__class__
(
self
.
dtype
,
self
.
broadcastable
,
None
,
self
.
name
)
if
transfer_data
:
cpy
.
data
=
copy
(
self
.
data
)
return
cpy
elemwise.py
浏览文件 @
d676edaf
from
copy
import
copy
from
copy
import
copy
from
gof
import
Op
from
gof
import
Op
,
Destroyer
from
gof.utils
import
AbstractFunctionError
from
gof.utils
import
AbstractFunctionError
from
tensor
import
_Op
class
Elemwise
(
Op
):
class
Elemwise
(
_Op
):
def
var_desc
(
self
):
def
var_desc
(
self
):
raise
AbstractFunctionError
()
raise
AbstractFunctionError
()
...
@@ -20,22 +18,6 @@ class Elemwise(_Op):
...
@@ -20,22 +18,6 @@ class Elemwise(_Op):
return
[[
i
[
0
]
for
i
in
idesc
if
i
[
1
]],
return
[[
i
[
0
]
for
i
in
idesc
if
i
[
1
]],
[
o
[
0
]
for
o
in
odesc
if
o
[
1
]]]
[
o
[
0
]
for
o
in
odesc
if
o
[
1
]]]
def
propagate_broadcastable
(
self
,
*
inputs
):
idesc
,
odesc
=
self
.
var_desc
()
nonloop_o
=
[
o
[
0
]
for
o
in
odesc
if
not
o
[
1
]]
if
nonloop_o
:
raise
Exception
(
"Cannot infer broadcastable for non-loop variable(s)
%
s"
%
nonloop_o
)
all_bcast
=
[
broadcastable
for
broadcastable
,
i
in
zip
(
inputs
,
idesc
)
if
i
[
1
]]
if
reduce
(
lambda
x
,
y
:
x
is
not
False
and
x
==
y
and
y
,
[
len
(
x
)
for
x
in
all_bcast
])
is
False
:
raise
TypeError
(
"Inputs that are loop variables do not all have the same number of dimensions."
)
ret
=
[]
for
arr
in
zip
(
*
all_bcast
):
if
0
in
arr
:
ret
.
append
(
0
)
else
:
ret
.
append
(
1
)
return
[
ret
]
*
self
.
nout
def
c_code_init
(
self
):
def
c_code_init
(
self
):
raise
AbstractFunctionError
()
raise
AbstractFunctionError
()
...
@@ -76,7 +58,7 @@ class Elemwise(_Op):
...
@@ -76,7 +58,7 @@ class Elemwise(_Op):
[
"
%
("
+
v
+
")s"
for
v
in
input_loop_vars
],
[
"
%
("
+
v
+
")s"
for
v
in
input_loop_vars
],
[
"
%
("
+
v
+
")s"
for
v
in
output_loop_vars
],
[
"
%
("
+
v
+
")s"
for
v
in
output_loop_vars
],
aliases
)
aliases
)
return
ret
return
ret
def
c_validate_update
(
self
):
def
c_validate_update
(
self
):
...
...
gof/cc.py
浏览文件 @
d676edaf
...
@@ -234,7 +234,11 @@ class CLinker(Linker):
...
@@ -234,7 +234,11 @@ class CLinker(Linker):
env
=
self
.
env
env
=
self
.
env
self
.
inputs
=
env
.
inputs
self
.
inputs
=
env
.
inputs
if
len
(
set
(
self
.
inputs
))
!=
len
(
self
.
inputs
):
raise
Exception
(
"CLinker doesn't support duplicate inputs."
)
self
.
outputs
=
env
.
outputs
self
.
outputs
=
env
.
outputs
if
len
(
set
(
self
.
outputs
))
!=
len
(
self
.
outputs
):
raise
Exception
(
"CLinker doesn't support duplicate outputs."
)
try
:
self
.
results
=
list
(
env
.
results
())
try
:
self
.
results
=
list
(
env
.
results
())
except
AttributeError
:
self
.
results
=
self
.
inputs
+
self
.
outputs
except
AttributeError
:
self
.
results
=
self
.
inputs
+
self
.
outputs
...
...
gradient.py
浏览文件 @
d676edaf
import
gof
,
gof
.
result
import
gof
,
gof
.
result
import
numpy
#for numeric_grad
import
numpy
#for numeric_grad
from
gof.python25
import
all
_msg_retNone
=
'op.grad(...) returned None, consider returning [None]'
_msg_retNone
=
'op.grad(...) returned None, consider returning [None]'
_msg_badlen
=
'op.grad(...) returned wrong number of gradients'
_msg_badlen
=
'op.grad(...) returned wrong number of gradients'
...
...
tensor.py
浏览文件 @
d676edaf
差异被折叠。
点击展开。
tensor_ops.py
浏览文件 @
d676edaf
...
@@ -6,206 +6,6 @@ from tensor import *
...
@@ -6,206 +6,6 @@ from tensor import *
# # TensorOp is a convenient base class, permitting to factor the code for the
# # Ops in this file.
# # It is not necessary to inherit from TensorOp to make an Op that manipulates
# # Tensors.
# <<<<<<< /u/breuleuo/hg/new_theano/tensor_ops.py
# class TensorOp(Op):
# nin = -1
# nout = 1
# cast_method = lambda self, *args: _upcast(*args)
# def __init__(self, *inputs):
# inputs = map(_wrap_as_tensor, inputs)
# if self.nin >= 0:
# if len(inputs) != self.nin:
# raise TypeError("Wrong number of inputs for %s (got %i, expected %i)") \
# % (self, len(inputs), self.nin)
# i_broadcastables = [getattr(input, 'broadcastable', None) for input in inputs]
# i_dtypes = [getattr(input, 'dtype', None) for input in inputs]
# o_broadcastables = utils.from_return_values(self.propagate_broadcastable(*i_broadcastables))
# o_dtypes = utils.from_return_values(self.propagate_dtype(*i_dtypes))
# self.inputs = inputs
# self.outputs = [Tensor(dtype, broadcastable) for broadcastable, dtype in zip(o_broadcastables, o_dtypes)]
# def propagate_broadcastable(self, *inputs):
# raise AbstractFunctionError()
# def propagate_dtype(self, *i_dtypes):
# for dtype in i_dtypes:
# if dtype is None:
# raise TypeError("Expected a Tensor.")
# return self.cast_method(*i_dtypes)
# def impl(self, *inputs):
# raise AbstractFunctionError()
# def perform(self):
# res = self.impl(*[input.data for input in self.inputs])
# if self.nout == 1:
# self.outputs[0].data = res
# else:
# for output, value in zip(self.outputs, res):
# output.data = value
# def c_var_names(self):
# (self, inames, onames), _1, _2, _3 = inspect.getargspec(self.c_impl)
# inames = utils.from_return_values(inames)
# onames = utils.from_return_values(onames)
# return [inames, onames]
# def c_code(self):
# return self.c_impl(self.inputs, self.outputs)
# def c_impl(self, inputs, outputs):
# raise AbstractFunctionError()
# class UnaryTensorOp(TensorOp):
# nin = 1
# class BinaryTensorOp(TensorOp):
# nin = 2
# # class Transpose(UnaryTensorOp):
# # def propagate_broadcastable(self, x):
# # x2 = copy(x)
# # x2.reverse()
# # return [x2]
# # def impl(self, x):
# # return x.T
# # def c_impl(self, x, z):
# # return """
# # PyArrayObject* transposed = (PyArrayObject*)PyArray_Transpose(%(x)s, NULL);
# # //if (PyArray_REFCOUNT(transposed) == 1) {
# # // printf("lala\\n");
# # //}
# # //if (%(z)s) {
# # // Py_XDECREF(%(z)s);
# # //}
# # %(z)s = transposed;
# # Py_XINCREF(%(z)s);
# # """
# def scalar_switch(normal_f, scalar_f, scalar_f_reverse = None):
# def f(x, y):
# x, y = _wrap_as_tensor(x), _wrap_as_tensor(y)
# if 0 not in y.broadcastable:
# return scalar_f(x, y)
# if 0 not in x.broadcastable:
# if scalar_f_reverse:
# return scalar_f_reverse(y, x)
# else:
# raise TypeError("You cannot do this operation on a scalar.")
# return normal_f(x, y)
# return f
# # Wrapper to ensure that all inputs to the function impl have the same size (foils numpy's broadcasting)
# def assert_same_shapes(x, *rest):
# shape = x.shape
# for other in rest:
# if other.shape != shape:
# raise ValueError("The dimensions of the inputs do not match.")
# # Wrapper to ensure that the last input to impl is a scalar
# def assert_tensor_scalar(x, a):
# if numpy.product(a.shape) != 1:
# raise ValueError("The second argument must be a scalar.")
# class Elemwise(TensorOp):
# @staticmethod
# def extract_name(name):
# if name.endswith("_i"):
# return name[:-2]
# else:
# return name
# @staticmethod
# def is_loop_var(name):
# return name.endswith("_i")
# def c_var_names(self):
# cls = self.__class__
# (self, inames, onames), _1, _2, _3 = inspect.getargspec(self.c_foreach)
# spec = ([cls.extract_name(name) for name in inames],
# [cls.extract_name(name) for name in onames])
# return spec
# def loop_variables(self):
# cls = self.__class__
# (self, inames, onames), _1, _2, _3 = inspect.getargspec(cls.c_foreach)
# return ([cls.extract_name(name) for name in inames if cls.is_loop_var(name)],
# [cls.extract_name(name) for name in onames if cls.is_loop_var(name)])
# def propagate_broadcastable(self, *inputs):
# inames, onames = self.c_var_names()
# iloop, oloop = self.loop_variables()
# if oloop != onames:
# raise Exception("Cannot infer broadcastable for non-loop variable(s) %s" % set(onames).difference(oloop))
# all_bcast = [broadcastable for broadcastable, iname in zip(inputs, inames) if iname in iloop]
# ret = []
# for arr in zip(*all_bcast):
# if 0 in arr:
# ret.append(0)
# else:
# ret.append(1)
# return [ret] * self.nout
# @classmethod
# def inplace_version(cls):
# class Ret(cls, Destroyer):
# def destroy_list(self):
# return self.inputs[0]
# return Ret
# def c_init(self, inputs, outputs):
# pass
# def c_foreach(self, inputs, outputs):
# pass
# def c_finalize(self, inputs, outputs):
# pass
# class TensorScalarOp(Elemwise):
# def c_var_names(self):
# return (['x', '_a'], ['z', ])
# def loop_variables(self):
# return (['x', ], ['z', ])
# def c_init((x, _a), (z, )):
# return """
# if (PyArray_SIZE(_a) != 1) {
# PyErr_SetString(PyExc_ValueError, \"The size of the scalar argument is not 1.\");
# }
# _a_dtype a = ((_a_dtype*)PyArray_DATA(_a))[0];
# """
# def _c_foreach(self):
# return "z_i = %s;" % self.c_expr
# =======
# >>>>>>> /tmp/tensor_ops.py~other.fNA50a
###########################
###########################
#### Binary Operations ####
#### Binary Operations ####
###########################
###########################
...
@@ -214,6 +14,11 @@ from tensor import *
...
@@ -214,6 +14,11 @@ from tensor import *
## Dot ##
## Dot ##
#########
#########
class
Dot
(
TensorOp
):
class
Dot
(
TensorOp
):
@staticmethod
@staticmethod
def
_output_shape
(
xshape
,
yshape
):
def
_output_shape
(
xshape
,
yshape
):
...
@@ -258,20 +63,12 @@ class Dot(TensorOp):
...
@@ -258,20 +63,12 @@ class Dot(TensorOp):
class
Neg
(
Elemwise
):
def
impl
(
self
,
x
):
return
-
x
def
grad
(
self
,
x
,
gz
):
return
-
gz
def
c_foreach
(
self
,
(
x_i
,
),
(
z_i
,
)):
return
"z_i = -x_i;"
class
NegInplace
(
Neg
.
inplace_version
()):
class
NegInplace
(
Neg
.
inplace_version
()):
def
impl
(
self
,
x
):
def
impl
(
self
,
x
):
x
*=
-
1
x
*=
-
1
return
x
return
x
class
InvElemwise
(
Elemwise
):
class
InvElemwise
(
Elemwise
):
def
impl
(
self
,
x
):
def
impl
(
self
,
x
):
return
1
/
x
return
1
/
x
...
@@ -425,3 +222,28 @@ class MinMax:
...
@@ -425,3 +222,28 @@ class MinMax:
# # class Transpose(UnaryTensorOp):
# # def propagate_broadcastable(self, x):
# # x2 = copy(x)
# # x2.reverse()
# # return [x2]
# # def impl(self, x):
# # return x.T
# # def c_impl(self, x, z):
# # return """
# # PyArrayObject* transposed = (PyArrayObject*)PyArray_Transpose(%(x)s, NULL);
# # //if (PyArray_REFCOUNT(transposed) == 1) {
# # // printf("lala\\n");
# # //}
# # //if (%(z)s) {
# # // Py_XDECREF(%(z)s);
# # //}
# # %(z)s = transposed;
# # Py_XINCREF(%(z)s);
# # """
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论