Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
P
pytensor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
testgroup
pytensor
Commits
d5d90999
提交
d5d90999
authored
7月 23, 2012
作者:
Nicolas Bouchard
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
pep8
上级
60bf2afe
隐藏空白字符变更
内嵌
并排
正在显示
1 个修改的文件
包含
587 行增加
和
254 行删除
+587
-254
basic.py
theano/sparse/basic.py
+587
-254
没有找到文件。
theano/sparse/basic.py
浏览文件 @
d5d90999
"""
"""Classes for handling sparse matrices.
Classes for handling sparse matrices.
To read about different sparse formats, see
To read about different sparse formats, see
U{http://www-users.cs.umn.edu/~saad/software/SPARSKIT/paper.ps}.
http://www-users.cs.umn.edu/~saad/software/SPARSKIT/paper.ps
@todo: Automatic methods for determining best sparse format?
"""
"""
# TODO
# Automatic methods for determining best sparse format?
from
itertools
import
izip
from
itertools
import
izip
import
sys
import
sys
...
@@ -103,15 +104,19 @@ def _kmap_hash(a):
...
@@ -103,15 +104,19 @@ def _kmap_hash(a):
# Wrapper type
# Wrapper type
def
as_sparse_variable
(
x
,
name
=
None
):
def
as_sparse_variable
(
x
,
name
=
None
):
"""
"""Wrapper around SparseVariable constructor to construct
Wrapper around SparseVariable constructor.
a Variable with a sparse matrix with the same dtype and
@param x: A sparse matrix. as_sparse_variable reads dtype and format
format.
properties out of this sparse matrix.
@return: SparseVariable version of sp.
@todo Verify that sp is sufficiently sparse, and raise a warning if it is
:param x: A sparse matrix.
not
:return: SparseVariable version of `x`.
"""
"""
# TODO
# Verify that sp is sufficiently sparse, and raise a
# warning if it is not
if
isinstance
(
x
,
gof
.
Apply
):
if
isinstance
(
x
,
gof
.
Apply
):
if
len
(
x
.
outputs
)
!=
1
:
if
len
(
x
.
outputs
)
!=
1
:
raise
ValueError
(
"It is ambiguous which output of a "
raise
ValueError
(
"It is ambiguous which output of a "
...
@@ -131,9 +136,15 @@ as_sparse = as_sparse_variable
...
@@ -131,9 +136,15 @@ as_sparse = as_sparse_variable
def
as_sparse_or_tensor_variable
(
x
,
name
=
None
):
def
as_sparse_or_tensor_variable
(
x
,
name
=
None
):
"""Same as `as_sparse_variable` but If we can't make a
sparse variable, we try to make a tensor variable.
format.
:param x: A sparse matrix.
:return: SparseVariable or TensorVariable version of `x`.
"""
"""
If we can't make a sparse variable, we try to make a tensor variable.
"""
try
:
try
:
return
as_sparse_variable
(
x
,
name
)
return
as_sparse_variable
(
x
,
name
)
except
(
ValueError
,
TypeError
):
except
(
ValueError
,
TypeError
):
...
@@ -141,10 +152,20 @@ def as_sparse_or_tensor_variable(x, name=None):
...
@@ -141,10 +152,20 @@ def as_sparse_or_tensor_variable(x, name=None):
def
verify_grad_sparse
(
op
,
pt
,
structured
=
False
,
*
args
,
**
kwargs
):
def
verify_grad_sparse
(
op
,
pt
,
structured
=
False
,
*
args
,
**
kwargs
):
"""Wrapper for theano.test.unittest_tools.py:verify_grad wich
converts sparse variables back and forth.
:param op: Op to check.
:param pt: List of inputs to realize the tests.
:param structured: True to tests with a structured grad,
False otherwise.
:param *args: Other `verify_grad` parameter if any.
:param **kwargs: Other `verify_grad` key word parameter
if any.
:return: None
"""
"""
Wrapper for theano.test.unittest_tools.py:verify_grad
Converts sparse variables back and forth.
"""
conv_none
=
lambda
x
:
x
conv_none
=
lambda
x
:
x
def
conv_csr
(
ind
,
indptr
,
shp
):
def
conv_csr
(
ind
,
indptr
,
shp
):
...
@@ -510,28 +531,44 @@ discrete_dtypes = int_dtypes + uint_dtypes
...
@@ -510,28 +531,44 @@ discrete_dtypes = int_dtypes + uint_dtypes
# CONSTRUCTION
# CONSTRUCTION
class
CSMProperties
(
gof
.
Op
):
class
CSMProperties
(
gof
.
Op
):
"""Extract all of .data .indices and .indptr
"""Extract all of .data, .indices, .indptr and .shape.
:note: We won't implement infer_shape for this op now. This will
For specific field, `csm_data`, `csm_indices`, `csm_indptr`
ask that we implement an GetNNZ op, and this op will keep
and `csm_shape` are provided. Also, `kmap` could be
the dependence on the input of this op. So this won't help
set through to constructor to specified the parts
to remove computations in the graph. To remove computation,
of the parameter `data` the op should return.Fancy indexing
we will need to make an infer_sparse_pattern feature to
with numpy.ndarray should be used for this purpose.
remove computations. Doing this is trickier then the
infer_shape feature. For example, how do we handle the case
:param csm: Sparse matrix in CSR or CSC format.
when some op create some 0 values? So there is dependence
on the values themselves. We could write an infer_shape for
:return: (data, indices, indptr, shape), the properties
the last output that is the shape, but I dough this will
of `csm`.
get used.
:note:
- The grad implemented is regular, i.e. not structured.
- `infer_shape` method is not available for this op.
"""
"""
# NOTE
# We won't implement infer_shape for this op now. This will
# ask that we implement an GetNNZ op, and this op will keep
# the dependence on the input of this op. So this won't help
# to remove computations in the graph. To remove computation,
# we will need to make an infer_sparse_pattern feature to
# remove computations. Doing this is trickier then the
# infer_shape feature. For example, how do we handle the case
# when some op create some 0 values? So there is dependence
# on the values themselves. We could write an infer_shape for
# the last output that is the shape, but I dough this will
# get used.
# we don't return a view of the shape, we create a new ndarray from the
# we don't return a view of the shape, we create a new ndarray from the
# shape tuple.
# shape tuple.
view_map
=
{
0
:
[
0
],
1
:
[
0
],
2
:
[
0
]}
view_map
=
{
0
:
[
0
],
1
:
[
0
],
2
:
[
0
]}
kmap
=
None
kmap
=
None
""" WRITEME """
"""Indexing to speficied what part of the data parameter
should be use to construct the sparse matrix."""
def
__init__
(
self
,
kmap
=
None
):
def
__init__
(
self
,
kmap
=
None
):
self
.
kmap
=
kmap
self
.
kmap
=
kmap
...
@@ -592,16 +629,43 @@ def csm_shape(csm):
...
@@ -592,16 +629,43 @@ def csm_shape(csm):
class
CSM
(
gof
.
Op
):
class
CSM
(
gof
.
Op
):
"""Construct a CSC or CSR matrix from the internal representation """
"""Construct a CSC or CSR matrix from the internal
representation.
The format for the sparse array can be specified
through the constructor. Also, `kmap` could be
set through to constructor to specified the parts
of the parameter `data` the op should use to construct
the sparse matrix. Fancy indexing with numpy.ndarray
should be used for this purpose.
:param data: One dimensionnal tensor representing
the data of the sparse to construct.
:param indices: One dimensionnal tensor of integers
representing the indices of the sparse
matrix to construct.
:param indptr: One dimensionnal tensor of integers
representing the indice pointer for
the sparse matrix to construct.
:param shape: One dimensionnal tensor of integers
representing the shape of the sparse
matrix to construct.
:return: A sparse matrix having the properties
speficied by the inputs.
:note:
- The grad method returns a dense vector, so it provide
a regular grad.
"""
# should view the other inputs too, but viewing multiple inputs is not
# should view the other inputs too, but viewing multiple inputs is not
view_map
=
{
0
:
[
0
]}
view_map
=
{
0
:
[
0
]}
#currently supported by the destroyhandler
#currently supported by the destroyhandler
format
=
None
"""WRITEME"""
kmap
=
None
kmap
=
None
"""WRITEME"""
"""Indexing to speficied what part of the data parameter
should be use to construct the sparse matrix."""
_hashval
=
None
_hashval
=
None
"""Pre-computed hash value, defined by __init__"""
"""Pre-computed hash value, defined by __init__"""
...
@@ -628,16 +692,6 @@ class CSM(gof.Op):
...
@@ -628,16 +692,6 @@ class CSM(gof.Op):
return
self
.
_hashval
return
self
.
_hashval
def
make_node
(
self
,
data
,
indices
,
indptr
,
shape
):
def
make_node
(
self
,
data
,
indices
,
indptr
,
shape
):
"""Build a SparseVariable from the internal parametrization
:param data:
:param indices:
:param indptr:
:type data: 1-d tensor
:type indices: 1-d tensor of ints
:type indptr: 1-d tensor of ints
"""
data
=
tensor
.
as_tensor_variable
(
data
)
data
=
tensor
.
as_tensor_variable
(
data
)
if
not
isinstance
(
indices
,
tensor
.
TensorVariable
):
if
not
isinstance
(
indices
,
tensor
.
TensorVariable
):
...
@@ -653,13 +707,13 @@ class CSM(gof.Op):
...
@@ -653,13 +707,13 @@ class CSM(gof.Op):
if
data
.
type
.
ndim
!=
1
:
if
data
.
type
.
ndim
!=
1
:
raise
TypeError
(
'data argument must be a vector'
,
data
.
type
,
raise
TypeError
(
'data argument must be a vector'
,
data
.
type
,
data
.
type
.
ndim
)
data
.
type
.
ndim
)
if
indices
.
type
.
ndim
!=
1
or
indices
.
type
.
dtype
!=
'int32'
:
if
indices
.
type
.
ndim
!=
1
or
indices
.
type
.
dtype
not
in
discrete_dtypes
:
raise
TypeError
(
'indices must be vector of integers'
,
indices
,
raise
TypeError
(
'indices must be vector of integers'
,
indices
,
indices
.
type
)
indices
.
type
)
if
indptr
.
type
.
ndim
!=
1
or
indptr
.
type
.
dtype
!=
'int32'
:
if
indptr
.
type
.
ndim
!=
1
or
indptr
.
type
.
dtype
not
in
discrete_dtypes
:
raise
TypeError
(
'indices must be vector of integers'
,
indptr
,
raise
TypeError
(
'indices must be vector of integers'
,
indptr
,
indptr
.
type
)
indptr
.
type
)
if
shape
.
type
.
ndim
!=
1
or
shape
.
type
.
dtype
!=
'int32'
:
if
shape
.
type
.
ndim
!=
1
or
shape
.
type
.
dtype
not
in
discrete_dtypes
:
raise
TypeError
(
'n_rows must be integer type'
,
shape
,
shape
.
type
)
raise
TypeError
(
'n_rows must be integer type'
,
shape
,
shape
.
type
)
return
gof
.
Apply
(
self
,
return
gof
.
Apply
(
self
,
...
@@ -668,7 +722,6 @@ class CSM(gof.Op):
...
@@ -668,7 +722,6 @@ class CSM(gof.Op):
format
=
self
.
format
)
.
make_variable
()])
format
=
self
.
format
)
.
make_variable
()])
def
perform
(
self
,
node
,
(
data
,
indices
,
indptr
,
shape
),
(
out
,)):
def
perform
(
self
,
node
,
(
data
,
indices
,
indptr
,
shape
),
(
out
,)):
"""Build a csc_matrix"""
# for efficiency, if remap does nothing, then do not apply it
# for efficiency, if remap does nothing, then do not apply it
if
self
.
kmap
is
not
None
:
if
self
.
kmap
is
not
None
:
data
=
data
[
self
.
kmap
]
data
=
data
[
self
.
kmap
]
...
@@ -694,7 +747,6 @@ class CSM(gof.Op):
...
@@ -694,7 +747,6 @@ class CSM(gof.Op):
copy
=
False
)
copy
=
False
)
def
grad
(
self
,
(
x_data
,
x_indices
,
x_indptr
,
x_shape
),
(
g_out
,)):
def
grad
(
self
,
(
x_data
,
x_indices
,
x_indptr
,
x_shape
),
(
g_out
,)):
"""Return a gradient on the data vector"""
g_data
,
g_indices
,
g_indptr
,
g_shape
=
csm_properties
(
g_out
)
g_data
,
g_indices
,
g_indptr
,
g_shape
=
csm_properties
(
g_out
)
#unpack the data vector and wrap it as a 1d TensorType
#unpack the data vector and wrap it as a 1d TensorType
g_data
=
csm_grad
(
self
.
kmap
)(
x_data
,
x_indices
,
x_indptr
,
x_shape
,
g_data
=
csm_grad
(
self
.
kmap
)(
x_data
,
x_indices
,
x_indptr
,
x_shape
,
...
@@ -714,20 +766,20 @@ CSR = CSM('csr')
...
@@ -714,20 +766,20 @@ CSR = CSM('csr')
class
CSMGrad
(
gof
.
op
.
Op
):
class
CSMGrad
(
gof
.
op
.
Op
):
"""
# Note
This Op computes the gradient of the CSM Op. CSM creates a matrix from
#
This Op computes the gradient of the CSM Op. CSM creates a matrix from
data, indices, and ind_
ptr vectors; it's gradient is the gradient of
# data, indices, and ind
ptr vectors; it's gradient is the gradient of
the data vector only. There are two complexities to calculate this
#
the data vector only. There are two complexities to calculate this
gradient:
#
gradient:
1. The gradient may be sparser than the input matrix defined by (data,
#
1. The gradient may be sparser than the input matrix defined by (data,
indices, ind_
ptr). In this case, the data vector of the gradient will have
# indices, ind
ptr). In this case, the data vector of the gradient will have
less elements than the data vector of the input because sparse formats
#
less elements than the data vector of the input because sparse formats
remove 0s. Since we are only returning the gradient of the data vector, the
# remove 0s. Since we are only returning the gradient of the data vector,
relevant 0s need to be added back.
# the
relevant 0s need to be added back.
2. The elements in the sparse dimension are not guaranteed to be sorted.
#
2. The elements in the sparse dimension are not guaranteed to be sorted.
Therefore, the input data vector may have a different order than the
#
Therefore, the input data vector may have a different order than the
gradient data vector.
#
gradient data vector.
"""
def
__init__
(
self
,
kmap
=
None
):
def
__init__
(
self
,
kmap
=
None
):
self
.
kmap
=
kmap
self
.
kmap
=
kmap
if
self
.
kmap
is
None
:
if
self
.
kmap
is
None
:
...
@@ -969,9 +1021,20 @@ zcast = Cast('complex128')
...
@@ -969,9 +1021,20 @@ zcast = Cast('complex128')
class
DenseFromSparse
(
gof
.
op
.
Op
):
class
DenseFromSparse
(
gof
.
op
.
Op
):
"""Convert a sparse matrix to a dense one.
:param x: A sparse matrix.
:return: A dense matrix, the same as `x`.
:note:
- The grad implementation can be controlled
through the constructor via the `structured`
parameter. `True` will provide a structured
grad while `False` will provide a regular
grad. By default, the grad is structured.
"""
"""
Convert a sparse matrix to an `ndarray`.
"""
def
__init__
(
self
,
structured
=
True
):
def
__init__
(
self
,
structured
=
True
):
self
.
sparse_grad
=
structured
self
.
sparse_grad
=
structured
...
@@ -1018,9 +1081,23 @@ dense_from_sparse = DenseFromSparse()
...
@@ -1018,9 +1081,23 @@ dense_from_sparse = DenseFromSparse()
class
SparseFromDense
(
gof
.
op
.
Op
):
class
SparseFromDense
(
gof
.
op
.
Op
):
"""Convert a dense matrix to a sparse matrix.
To convert in CSR format, use `csr_from_dense`
and to convert in CSC format, use `csc_from_dense`.
:param x: A dense matrix.
:return: The same as `x` in a sparse matrix
format.
:note:
- The grad implementation is regular, i.e.
not structured.
- The output sparse format can also be controlled
via the `format` parameter in the constructor.
"""
"""
Convert an `ndarray` matrix to a sparse matrix.
"""
def
__init__
(
self
,
format
):
def
__init__
(
self
,
format
):
self
.
format
=
format
self
.
format
=
format
...
@@ -1071,22 +1148,32 @@ csc_from_dense = SparseFromDense('csc')
...
@@ -1071,22 +1148,32 @@ csc_from_dense = SparseFromDense('csc')
# Indexing
# Indexing
class
GetItem2d
(
gof
.
op
.
Op
):
class
GetItem2d
(
gof
.
op
.
Op
):
"""
"""Implement a subtensor of sparse variable and that return a
Implement a subtensor of sparse variable and that return a sparse matrix.
sparse matrix.
If you want to take only one element of a sparse matrix see
`GetItemScalar` that return a tensor scalar.
If you want to take only one element of a sparse matrix see the
.. note::
class GetItemScalar that return a tensor scalar.
:note: that subtensor selection always returns a matrix so
Subtensor selection always returns a matrix, so indexing
indexing with [a:b, c:d] is forced. If one index is a scalar,
with [a:b, c:d] is forced. If one index is a scalar. For
e.g. x[a:b, c] and x[a, b:c], generate an error. Use instead
instance, x[a:b, c] and x[a, b:c], generate an error. Use
x[a:b, c:c+1] and x[a:a+1, b:c].
instead
x[a:b, c:c+1] and x[a:a+1, b:c].
The above indexing methods are not supported because the r
val
The above indexing methods are not supported because the r
eturn value
would be a sparse matrix rather than a sparse vector, which is a
would be a sparse matrix rather than a sparse vector, which is a
deviation from numpy indexing rule. This decision is made largely
deviation from numpy indexing rule. This decision is made largely
for keeping the consistency between numpy and theano.
Subjected
for keeping the consistency between numpy and theano. Subjected
to modification when sparse vector is supported.
to modification when sparse vector is supported.
:param x: Sparse matrix.
:param index: Tuple of slice object.
:return: The slice corresponding in `x`.
:note:
- The grad is not implemented for this op.
"""
"""
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
...
@@ -1096,7 +1183,7 @@ class GetItem2d(gof.op.Op):
...
@@ -1096,7 +1183,7 @@ class GetItem2d(gof.op.Op):
return
hash
(
type
(
self
))
return
hash
(
type
(
self
))
# Fred:Too complicated for now. If you need it, look at
# Fred:Too complicated for now. If you need it, look at
#
the Subtensor.infer_shape.
# the Subtensor.infer_shape.
# def infer_shape(self, node, i0_shapes):
# def infer_shape(self, node, i0_shapes):
# return i0_shapes
# return i0_shapes
...
@@ -1172,12 +1259,21 @@ get_item_2d = GetItem2d()
...
@@ -1172,12 +1259,21 @@ get_item_2d = GetItem2d()
class
GetItemScalar
(
gof
.
op
.
Op
):
class
GetItemScalar
(
gof
.
op
.
Op
):
"""
"""Implement a subtensor of a sparse variable that take
Implement a subtensor of a sparse variable that take two scalar as
two scalar as index and return a scalar.
index and return a scalar
:see: GetItem2d to return more than one element.
If you want to take a slice of a sparse matrix see
`GetItem2d` that return a sparse matrix.
:param x: Sparse matrix.
:param index: Tuple of scalar..
:return: The item corresponding in `x`.
:note:
- The grad is not implemented for this op.
"""
"""
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
return
(
type
(
self
)
==
type
(
other
))
return
(
type
(
self
)
==
type
(
other
))
...
@@ -1220,10 +1316,22 @@ class GetItemScalar(gof.op.Op):
...
@@ -1220,10 +1316,22 @@ class GetItemScalar(gof.op.Op):
get_item_scalar
=
GetItemScalar
()
get_item_scalar
=
GetItemScalar
()
# Linear Algebra
# Linear Algebra
class
Transpose
(
gof
.
op
.
Op
):
"""Return the transpose of the sparse matrix.
:param x: Sparse matrix.
:return: `x` transposed.
:note:
- The returned matrix will not be in the same format. `csc`
matrix will be changed in `csr` matrix and `csr` matrix in
`csc` matrix.
- The grad is regular, i.e. not structured.
"""
class
Transpose
(
gof
.
op
.
Op
):
format_map
=
{
'csr'
:
'csc'
,
format_map
=
{
'csr'
:
'csc'
,
'csc'
:
'csr'
}
'csc'
:
'csr'
}
...
@@ -1242,7 +1350,7 @@ class Transpose(gof.op.Op):
...
@@ -1242,7 +1350,7 @@ class Transpose(gof.op.Op):
[
x
],
[
x
],
[
SparseType
(
dtype
=
x
.
type
.
dtype
,
[
SparseType
(
dtype
=
x
.
type
.
dtype
,
format
=
self
.
format_map
[
x
.
type
.
format
]
format
=
self
.
format_map
[
x
.
type
.
format
]
)
.
make_variable
()])
)
.
make_variable
()])
def
perform
(
self
,
node
,
(
x
,
),
(
out
,
)):
def
perform
(
self
,
node
,
(
x
,
),
(
out
,
)):
assert
_is_sparse
(
x
)
assert
_is_sparse
(
x
)
...
@@ -1254,11 +1362,20 @@ class Transpose(gof.op.Op):
...
@@ -1254,11 +1362,20 @@ class Transpose(gof.op.Op):
def
infer_shape
(
self
,
node
,
shapes
):
def
infer_shape
(
self
,
node
,
shapes
):
return
[
shapes
[
0
][::
-
1
]]
return
[
shapes
[
0
][::
-
1
]]
transpose
=
Transpose
()
transpose
=
Transpose
()
class
Neg
(
gof
.
op
.
Op
):
class
Neg
(
gof
.
op
.
Op
):
"""Return the negation of the sparse matrix.
:param x: Sparse matrix.
:return: -`x`.
:note:
- The grad is regular, i.e. not structured.
"""
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
return
(
type
(
self
)
==
type
(
other
))
return
(
type
(
self
)
==
type
(
other
))
...
@@ -1282,25 +1399,23 @@ class Neg(gof.op.Op):
...
@@ -1282,25 +1399,23 @@ class Neg(gof.op.Op):
def
infer_shape
(
self
,
node
,
shapes
):
def
infer_shape
(
self
,
node
,
shapes
):
return
[
shapes
[
0
]]
return
[
shapes
[
0
]]
neg
=
Neg
()
neg
=
Neg
()
class
ColScaleCSC
(
gof
.
op
.
Op
):
class
ColScaleCSC
(
gof
.
op
.
Op
):
"""
Scale each columns of a sparse matrix by the corresponding
#
Scale each columns of a sparse matrix by the corresponding
element of a dense vector
#
element of a dense vector
:param x: A sparse matrix.
#
:param x: A sparse matrix.
:param s: A dense vector with length equal to the number
#
:param s: A dense vector with length equal to the number
of columns of `x`.
#
of columns of `x`.
:return: A sparse matrix in the same format as `x` which
#
:return: A sparse matrix in the same format as `x` which
each column had been multiply by the corresponding
#
each column had been multiply by the corresponding
element of `s`.
#
element of `s`.
:note:
# :note:
- The grad implemented is structured.
# - The grad implemented is structured.
"""
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
return
type
(
self
)
==
type
(
other
)
return
type
(
self
)
==
type
(
other
)
...
@@ -1336,20 +1451,19 @@ class ColScaleCSC(gof.op.Op):
...
@@ -1336,20 +1451,19 @@ class ColScaleCSC(gof.op.Op):
class
RowScaleCSC
(
gof
.
op
.
Op
):
class
RowScaleCSC
(
gof
.
op
.
Op
):
"""
Scale each row of a sparse matrix by the corresponding element of
#
Scale each row of a sparse matrix by the corresponding element of
a dense vector
#
a dense vector
:param x: A sparse matrix.
#
:param x: A sparse matrix.
:param s: A dense vector with length equal to the number
#
:param s: A dense vector with length equal to the number
of rows of `x`.
#
of rows of `x`.
:return: A sparse matrix in the same format as `x` which
#
:return: A sparse matrix in the same format as `x` which
each row had been multiply by the corresponding
#
each row had been multiply by the corresponding
element of `s`.
#
element of `s`.
:note:
# :note:
- The grad implemented is structured.
# - The grad implemented is structured.
"""
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
return
type
(
self
)
==
type
(
other
)
return
type
(
self
)
==
type
(
other
)
...
@@ -1387,6 +1501,21 @@ class RowScaleCSC(gof.op.Op):
...
@@ -1387,6 +1501,21 @@ class RowScaleCSC(gof.op.Op):
def
col_scale
(
x
,
s
):
def
col_scale
(
x
,
s
):
"""Scale each columns of a sparse matrix by the corresponding
element of a dense vector
:param x: A sparse matrix.
:param s: A dense vector with length equal to the number
of columns of `x`.
:return: A sparse matrix in the same format as `x` which
each column had been multiply by the corresponding
element of `s`.
:note:
- The grad implemented is structured.
"""
if
x
.
format
==
'csc'
:
if
x
.
format
==
'csc'
:
return
ColScaleCSC
()(
x
,
s
)
return
ColScaleCSC
()(
x
,
s
)
elif
x
.
format
==
'csr'
:
elif
x
.
format
==
'csr'
:
...
@@ -1396,6 +1525,20 @@ def col_scale(x, s):
...
@@ -1396,6 +1525,20 @@ def col_scale(x, s):
def
row_scale
(
x
,
s
):
def
row_scale
(
x
,
s
):
"""Scale each row of a sparse matrix by the corresponding element of
a dense vector
:param x: A sparse matrix.
:param s: A dense vector with length equal to the number
of rows of `x`.
:return: A sparse matrix in the same format as `x` which
each row had been multiply by the corresponding
element of `s`.
:note:
- The grad implemented is structured.
"""
return
col_scale
(
x
.
T
,
s
)
.
T
return
col_scale
(
x
.
T
,
s
)
.
T
...
@@ -1667,7 +1810,17 @@ def clean(x):
...
@@ -1667,7 +1810,17 @@ def clean(x):
class
AddSS
(
gof
.
op
.
Op
):
class
AddSS
(
gof
.
op
.
Op
):
'''Add two sparse matrices '''
"""Add tw sparse matrix.
:param x: A sparse matrix.
:param y: A sparse matrix
:return: `x`+`y`
:note:
- The grad implemented is regular, i.e. not structured.
"""
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
return
(
type
(
self
)
==
type
(
other
))
return
(
type
(
self
)
==
type
(
other
))
...
@@ -1758,7 +1911,17 @@ add_s_s_data = AddSSData()
...
@@ -1758,7 +1911,17 @@ add_s_s_data = AddSSData()
class
AddSD
(
gof
.
op
.
Op
):
class
AddSD
(
gof
.
op
.
Op
):
''' Add a sparse and a dense matrix '''
"""Add a sparse and a dense matrix.
:param x: A sparse matrix.
:param y: A dense matrix
:return: `x`+`y`
:note:
- The grad implemented is structured on `x`.
"""
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
return
(
type
(
self
)
==
type
(
other
))
return
(
type
(
self
)
==
type
(
other
))
...
@@ -1851,24 +2014,23 @@ structured_add_s_v = StructuredAddSV()
...
@@ -1851,24 +2014,23 @@ structured_add_s_v = StructuredAddSV()
class
StructuredAddSVCSR
(
gof
.
Op
):
class
StructuredAddSVCSR
(
gof
.
Op
):
"""
Structured addition of a sparse matrix and a dense vector.
#
Structured addition of a sparse matrix and a dense vector.
The elements of the vector are are only added to the corresponding
#
The elements of the vector are are only added to the corresponding
non-zero elements. Therefore, this operation outputs another sparse
#
non-zero elements. Therefore, this operation outputs another sparse
matrix.
#
matrix.
:param a_data: Sparse matrix data.
#
:param a_data: Sparse matrix data.
:param a_indices: Sparse matrix indices.
#
:param a_indices: Sparse matrix indices.
:param a_indptr: Sparse matrix indptr.
#
:param a_indptr: Sparse matrix indptr.
:param b: Tensor type vector.
#
:param b: Tensor type vector.
:return: A sparse matrix containing the addition of the vector to
#
:return: A sparse matrix containing the addition of the vector to
the data of the sparse matrix.
#
the data of the sparse matrix.
:note:
# :note:
- The a_* are the properties of a sparse matrix in csr
# - The a_* are the properties of a sparse matrix in csr
format.
# format.
- This op is used as an optimization for StructuredAddSV.
# - This op is used as an optimization for StructuredAddSV.
"""
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
return
(
type
(
self
)
==
type
(
other
))
return
(
type
(
self
)
==
type
(
other
))
...
@@ -1974,9 +2136,22 @@ structured_add_s_v_csr = StructuredAddSVCSR()
...
@@ -1974,9 +2136,22 @@ structured_add_s_v_csr = StructuredAddSVCSR()
def
add
(
x
,
y
):
def
add
(
x
,
y
):
"""Add two matrices, at least one of which is sparse.
This method will provide the right op according
to the inputs.
:param x: A matrix variable.
:param y: A matrix variable.
:return: `x` + `y`
:note:
- At least one of `x` and `y` must be a sparse matrix.
- The grad will be structured only when one of the variable
will be a dense matrix.
"""
"""
Add two matrices, at least one of which is sparse.
"""
if
hasattr
(
x
,
'getnnz'
):
if
hasattr
(
x
,
'getnnz'
):
x
=
as_sparse_variable
(
x
)
x
=
as_sparse_variable
(
x
)
if
hasattr
(
y
,
'getnnz'
):
if
hasattr
(
y
,
'getnnz'
):
...
@@ -1997,11 +2172,37 @@ def add(x, y):
...
@@ -1997,11 +2172,37 @@ def add(x, y):
def
sub
(
x
,
y
):
def
sub
(
x
,
y
):
"""Substact two matrices, at least one of which is sparse.
This method will provide the right op according
to the inputs.
:param x: A matrix variable.
:param y: A matrix variable.
:return: `x` - `y`
:note:
- At least one of `x` and `y` must be a sparse matrix.
- The grad will be structured only when one of the variable
will be a dense matrix.
"""
return
x
+
(
-
y
)
return
x
+
(
-
y
)
class
MulSS
(
gof
.
op
.
Op
):
class
MulSS
(
gof
.
op
.
Op
):
''' Elementwise multiply a sparse and a sparse '''
"""Elementwise multiply a sparse and a sparse.
:param x: A sparse matrix.
:param y: A sparse matrix.
:return: `x` * `y`
:note:
- At least one of `x` and `y` must be a sparse matrix.
"""
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
return
(
type
(
self
)
==
type
(
other
))
return
(
type
(
self
)
==
type
(
other
))
...
@@ -2035,7 +2236,17 @@ mul_s_s = MulSS()
...
@@ -2035,7 +2236,17 @@ mul_s_s = MulSS()
class
MulSD
(
gof
.
op
.
Op
):
class
MulSD
(
gof
.
op
.
Op
):
''' Elementwise multiply a sparse and a ndarray '''
"""Elementwise multiply a sparse and a dense matrix.
:param x: A sparse matrix.
:param y: A dense matrix.
:return: `x` * `y`
:note:
- The grad is regular, i.e. not structured..
"""
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
return
(
type
(
self
)
==
type
(
other
))
return
(
type
(
self
)
==
type
(
other
))
...
@@ -2112,28 +2323,26 @@ class MulSD(gof.op.Op):
...
@@ -2112,28 +2323,26 @@ class MulSD(gof.op.Op):
def
infer_shape
(
self
,
node
,
shapes
):
def
infer_shape
(
self
,
node
,
shapes
):
return
[
shapes
[
0
]]
return
[
shapes
[
0
]]
mul_s_d
=
MulSD
()
mul_s_d
=
MulSD
()
class
MulSDCSC
(
gof
.
Op
):
class
MulSDCSC
(
gof
.
Op
):
"""
Multiplication of sparse matrix by a broadcasted dense vector
#
Multiplication of sparse matrix by a broadcasted dense vector
element wise.
#
element wise.
:param a_data: Sparse matrix data.
#
:param a_data: Sparse matrix data.
:param a_indices: Sparse matrix indices.
#
:param a_indices: Sparse matrix indices.
:param a_indptr: Sparse matrix indptr.
#
:param a_indptr: Sparse matrix indptr.
:param b: Tensor type matrix.
#
:param b: Tensor type matrix.
:return: The multiplication of the two matrix element wise.
#
:return: The multiplication of the two matrix element wise.
:note:
# :note:
- `a_data`, `a_indices` and `a_indptr` must be the properties
# - `a_data`, `a_indices` and `a_indptr` must be the properties
of a sparse matrix in csc format.
# of a sparse matrix in csc format.
- The dtype of `a_data`, i.e. the dtype of the sparse matrix,
# - The dtype of `a_data`, i.e. the dtype of the sparse matrix,
cannot be a complex type.
# cannot be a complex type.
- This op is used as an optimization of mul_s_d.
# - This op is used as an optimization of mul_s_d.
"""
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
return
(
type
(
self
)
==
type
(
other
))
return
(
type
(
self
)
==
type
(
other
))
...
@@ -2232,23 +2441,22 @@ mul_s_d_csc = MulSDCSC()
...
@@ -2232,23 +2441,22 @@ mul_s_d_csc = MulSDCSC()
class
MulSDCSR
(
gof
.
Op
):
class
MulSDCSR
(
gof
.
Op
):
"""
Multiplication of sparse matrix by a broadcasted dense vector
#
Multiplication of sparse matrix by a broadcasted dense vector
element wise.
#
element wise.
:param a_data: Sparse matrix data.
#
:param a_data: Sparse matrix data.
:param a_indices: Sparse matrix indices.
#
:param a_indices: Sparse matrix indices.
:param a_indptr: Sparse matrix indptr.
#
:param a_indptr: Sparse matrix indptr.
:param b: Tensor type matrix.
#
:param b: Tensor type matrix.
:return: The multiplication of the two matrix element wise.
#
:return: The multiplication of the two matrix element wise.
:note:
# :note:
- `a_data`, `a_indices` and `a_indptr` must be the properties
# - `a_data`, `a_indices` and `a_indptr` must be the properties
of a sparse matrix in csr format.
# of a sparse matrix in csr format.
- The dtype of `a_data`, i.e. the dtype of the sparse matrix,
# - The dtype of `a_data`, i.e. the dtype of the sparse matrix,
cannot be a complex type.
# cannot be a complex type.
- This op is used as an optimization of mul_s_d.
# - This op is used as an optimization of mul_s_d.
"""
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
return
(
type
(
self
)
==
type
(
other
))
return
(
type
(
self
)
==
type
(
other
))
...
@@ -2397,23 +2605,22 @@ mul_s_v = MulSV()
...
@@ -2397,23 +2605,22 @@ mul_s_v = MulSV()
class
MulSVCSR
(
gof
.
Op
):
class
MulSVCSR
(
gof
.
Op
):
"""
Multiplication of sparse matrix by a broadcasted dense vector
#
Multiplication of sparse matrix by a broadcasted dense vector
element wise.
#
element wise.
:param a_data: Sparse matrix data.
#
:param a_data: Sparse matrix data.
:param a_indices: Sparse matrix indices.
#
:param a_indices: Sparse matrix indices.
:param a_indptr: Sparse matrix indptr.
#
:param a_indptr: Sparse matrix indptr.
:param b: Tensor type matrix.
#
:param b: Tensor type matrix.
:return: The multiplication of the two matrix element wise.
#
:return: The multiplication of the two matrix element wise.
:note:
# :note:
- `a_data`, `a_indices` and `a_indptr` must be the properties
# - `a_data`, `a_indices` and `a_indptr` must be the properties
of a sparse matrix in csr format.
# of a sparse matrix in csr format.
- The dtype of `a_data`, i.e. the dtype of the sparse matrix,
# - The dtype of `a_data`, i.e. the dtype of the sparse matrix,
cannot be a complex type.
# cannot be a complex type.
- This op is used as an optimization of MulSV.
# - This op is used as an optimization of MulSV.
"""
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
return
(
type
(
self
)
==
type
(
other
))
return
(
type
(
self
)
==
type
(
other
))
...
@@ -2507,9 +2714,22 @@ mul_s_v_csr = MulSVCSR()
...
@@ -2507,9 +2714,22 @@ mul_s_v_csr = MulSVCSR()
def
mul
(
x
,
y
):
def
mul
(
x
,
y
):
"""Multiply elementwise two matrices, at least one
of which is sparse.
This method will provide the right op according
to the inputs.
:param x: A matrix variable.
:param y: A matrix variable.
:return: `x` + `y`
:note:
- At least one of `x` and `y` must be a sparse matrix.
- The grad is regular, i.e. not structured.
"""
"""
Multiply (elementwise) two matrices, at least one of which is sparse.
"""
x
=
as_sparse_or_tensor_variable
(
x
)
x
=
as_sparse_or_tensor_variable
(
x
)
y
=
as_sparse_or_tensor_variable
(
y
)
y
=
as_sparse_or_tensor_variable
(
y
)
...
@@ -2848,12 +3068,12 @@ multinomial = Multinomial()
...
@@ -2848,12 +3068,12 @@ multinomial = Multinomial()
# Structured monoid
# Structured monoid
def
structured_monoid
(
tensor_op
):
def
structured_monoid
(
tensor_op
):
"""Generic operation to perform many kinds of monoid element-wise
# Generic operation to perform many kinds of monoid element-wise
operations on the non-zeros of a sparse matrix.
# operations on the non-zeros of a sparse matrix.
# The first parameter must always be a sparse matrix. The other parameters
# must be scalars which will be passed as argument to the tensor_op.
The first parameter must always be a sparse matrix. The other parameters
must be scalars which will be passed as argument to the tensor_op.
"""
def
decorator
(
f
):
def
decorator
(
f
):
def
wrapper
(
*
args
):
def
wrapper
(
*
args
):
x
=
as_sparse_variable
(
args
[
0
])
x
=
as_sparse_variable
(
args
[
0
])
...
@@ -2924,12 +3144,22 @@ def structured_add(x):
...
@@ -2924,12 +3144,22 @@ def structured_add(x):
# Dot
# Dot
class
StructuredDot
(
gof
.
Op
):
class
StructuredDot
(
gof
.
Op
):
"""Structured Dot is like dot, except that only the gradient wrt non-zero
"""Structured Dot is like dot, except that only the
elements of the sparse matrix A are calculated and propagated.
gradient wrt non-zero elements of the sparse matrix
`a` are calculated and propagated.
The output is presumed to be a dense matrix, and is represented by a
The output is presumed to be a dense matrix, and is represented by a
TensorType instance.
TensorType instance.
:param a: A sparse matrix.
:param b: A sparse or dense matrix.
:return: The dot product of `a` and `b`.
:note:
- The grad implemented is structured.
"""
"""
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
return
(
type
(
self
)
==
type
(
other
))
return
(
type
(
self
)
==
type
(
other
))
...
@@ -3010,12 +3240,27 @@ _structured_dot = StructuredDot()
...
@@ -3010,12 +3240,27 @@ _structured_dot = StructuredDot()
def
structured_dot
(
x
,
y
):
def
structured_dot
(
x
,
y
):
"""Structured Dot is like dot, except that only the
gradient wrt non-zero elements of the sparse matrix
`a` are calculated and propagated.
The output is presumed to be a dense matrix, and is represented by a
TensorType instance.
:param a: A sparse matrix.
:param b: A sparse or dense matrix.
:return: The dot product of `a` and `b`.
:note:
- The grad implemented is structured.
"""
"""
@todo: Maybe the triple-transposition formulation (when x is dense)
is slow. See if there is a direct way to do this.
# @todo: Maybe the triple-transposition formulation (when x is dense)
(JB 20090528: Transposing tensors and sparse matrices is constant-time,
# is slow. See if there is a direct way to do this.
inplace, and fast.)
# (JB 20090528: Transposing tensors and sparse matrices is constant-time,
"""
# inplace, and fast.)
if
hasattr
(
x
,
'getnnz'
):
if
hasattr
(
x
,
'getnnz'
):
x
=
as_sparse_variable
(
x
)
x
=
as_sparse_variable
(
x
)
if
hasattr
(
y
,
'getnnz'
):
if
hasattr
(
y
,
'getnnz'
):
...
@@ -3034,6 +3279,22 @@ def structured_dot(x, y):
...
@@ -3034,6 +3279,22 @@ def structured_dot(x, y):
class
StructuredDotCSC
(
gof
.
Op
):
class
StructuredDotCSC
(
gof
.
Op
):
# Structured Dot CSC is like dot, except that only the
# gradient wrt non-zero elements of the sparse matrix
# `a` are calculated and propagated.
# The output is presumed to be a dense matrix, and is represented by a
# TensorType instance.
# :param a: A sparse matrix in csc format.
# :param b: A sparse or dense matrix.
# :return: The dot product of `a` and `b`.
# :note:
# - The grad implemented is structured.
# - This op is used as an optimization for StructuredDot.
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
return
(
type
(
self
)
==
type
(
other
))
return
(
type
(
self
)
==
type
(
other
))
...
@@ -3058,19 +3319,18 @@ class StructuredDotCSC(gof.Op):
...
@@ -3058,19 +3319,18 @@ class StructuredDotCSC(gof.Op):
assert
_is_dense
(
out
[
0
])
# scipy 0.7 automatically converts to dense
assert
_is_dense
(
out
[
0
])
# scipy 0.7 automatically converts to dense
def
c_code
(
self
,
node
,
name
,
(
a_val
,
a_ind
,
a_ptr
,
a_nrows
,
b
),
(
z
,),
sub
):
def
c_code
(
self
,
node
,
name
,
(
a_val
,
a_ind
,
a_ptr
,
a_nrows
,
b
),
(
z
,),
sub
):
"""
# C-implementation of the dot product of the sparse matrix A and matrix
C-implementation of the dot product of the sparse matrix A and matrix
# B.
B.
# @param a_val: non-zero values of the sparse matrix
@param a_val: non-zero values of the sparse matrix
# @param a_ind: column indices of the non-null values (.indices of a
@param a_ind: column indices of the non-null values (.indices of a
# scipy.csc_matrix)
scipy.csc_matrix)
# @param a_ptr: a_ptr indicates col indices for col. i are in the range
@param a_ptr: a_ptr indicates col indices for col. i are in the range
# a_ptr[i]:a_ptr[i+1]
a_ptr[i]:a_ptr[i+1]
# @param n_rows: number of rows of sparse matrix
@param n_rows: number of rows of sparse matrix
# @param b: dense matrix to perform dot product with, as in dot(a, b)
@param b: dense matrix to perform dot product with, as in dot(a, b)
# @param z: return value
@param z: return value
# @param sub: TODO, not too sure, something to do with weave probably
@param sub: TODO, not too sure, something to do with weave probably
"""
if
node
.
inputs
[
0
]
.
type
.
dtype
in
(
'complex64'
,
'complex128'
):
if
node
.
inputs
[
0
]
.
type
.
dtype
in
(
'complex64'
,
'complex128'
):
raise
NotImplementedError
(
'Complex types are not supported for a_val'
)
raise
NotImplementedError
(
'Complex types are not supported for a_val'
)
...
@@ -3209,6 +3469,22 @@ sd_csc = StructuredDotCSC()
...
@@ -3209,6 +3469,22 @@ sd_csc = StructuredDotCSC()
class
StructuredDotCSR
(
gof
.
Op
):
class
StructuredDotCSR
(
gof
.
Op
):
# Structured Dot CSR is like dot, except that only the
# gradient wrt non-zero elements of the sparse matrix
# `a` are calculated and propagated.
# The output is presumed to be a dense matrix, and is represented by a
# TensorType instance.
# :param a: A sparse matrix in csr format.
# :param b: A sparse or dense matrix.
# :return: The dot product of `a` and `b`.
# :note:
# - The grad implemented is structured.
# - This op is used as an optimization for StructuredDot.
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
return
(
type
(
self
)
==
type
(
other
))
return
(
type
(
self
)
==
type
(
other
))
...
@@ -3430,39 +3706,38 @@ sampling_dot = SamplingDot()
...
@@ -3430,39 +3706,38 @@ sampling_dot = SamplingDot()
class
SamplingDotCSR
(
gof
.
Op
):
class
SamplingDotCSR
(
gof
.
Op
):
"""Operand optimized for calculating the dot product dot(`x`, `y`.T) = `z`
# Operand optimized for calculating the dot product dot(`x`, `y`.T) = `z`
when you only want to calculate a subset of `z`.
# when you only want to calculate a subset of `z`.
It is equivalent to `p` o (`x` . `y`.T) where o is the element-wise
# It is equivalent to `p` o (`x` . `y`.T) where o is the element-wise
product, `x` and `y` operands of the dot product and `p` is a matrix
# product, `x` and `y` operands of the dot product and `p` is a matrix
that contains 1 when the corresponding element of `z` should be calculated
# that contains 1 when the corresponding element of `z` should be
and 0 when it shouldn't. Note that SamplingDot has a different interface
# calculated and 0 when it shouldn't. Note that SamplingDot has a different
than `dot` because SamplingDot requires `x` to be a `m`x`k` matrix while
# interface than `dot` because SamplingDot requires `x` to be a `m`x`k`
`y` is a `n`x`k` matrix instead of the usual `k`x`n` matrix.
# matrix while `y` is a `n`x`k` matrix instead of the usual `k`x`n` matrix.
.. note::
# .. note::
It will work if the pattern is not binary value, but if the
# It will work if the pattern is not binary value, but if the
pattern doesn't have a high sparsity proportion it will be slower
# pattern doesn't have a high sparsity proportion it will be slower
then a more optimized dot followed by a normal elemwise
# then a more optimized dot followed by a normal elemwise
multiplication.
# multiplication.
:param x: Tensor matrix.
# :param x: Tensor matrix.
:param y: Tensor matrix.
# :param y: Tensor matrix.
:param p_data: Sparse matrix data.
# :param p_data: Sparse matrix data.
:param p_ind: Sparse matrix indices.
# :param p_ind: Sparse matrix indices.
:param p_ptr: Sparse matric indptr.
# :param p_ptr: Sparse matric indptr.
:param p_ncols: Sparse matrix number of columns.
# :param p_ncols: Sparse matrix number of columns.
:return: A dense matrix containing the dot product of `x` by `y`.T only
# :return: A dense matrix containing the dot product of `x` by `y`.T only
where `p` is 1.
# where `p` is 1.
:note:
# :note:
- If we have the input of mixed dtype, we insert cast elemwise
# - If we have the input of mixed dtype, we insert cast elemwise
in the graph to be able to call blas function as they don't
# in the graph to be able to call blas function as they don't
allow mixed dtype.
# allow mixed dtype.
- This op is used as an optimization for SamplingDot.
# - This op is used as an optimization for SamplingDot.
"""
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
return
type
(
self
)
==
type
(
other
)
return
type
(
self
)
==
type
(
other
)
...
@@ -3692,6 +3967,21 @@ def structured_dot_grad(sparse_A, dense_B, ga):
...
@@ -3692,6 +3967,21 @@ def structured_dot_grad(sparse_A, dense_B, ga):
class
StructuredDotGradCSC
(
gof
.
Op
):
class
StructuredDotGradCSC
(
gof
.
Op
):
# Op that produces the grad of StructuredDot.
# :param a_indices: Matrix indicies
# :param a_indptr: Matrix indptr
# :param b: Right operand
# :param g_ab: Accumulated gradient.
# :return: The grad of `a`.`b` for `a` accumulated
# with g_ab.
# :note:
# - The grad implemented is structured.
# - a_* are the corresponding properties of a sparse
# matrix in csc format.
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
return
(
type
(
self
)
==
type
(
other
))
return
(
type
(
self
)
==
type
(
other
))
...
@@ -3813,6 +4103,21 @@ sdg_csc = StructuredDotGradCSC()
...
@@ -3813,6 +4103,21 @@ sdg_csc = StructuredDotGradCSC()
class
StructuredDotGradCSR
(
gof
.
Op
):
class
StructuredDotGradCSR
(
gof
.
Op
):
# Op that produces the grad of StructuredDot.
# :param a_indices: Matrix indicies
# :param a_indptr: Matrix indptr
# :param b: Right operand
# :param g_ab: Accumulated gradient.
# :return: The grad of `a`.`b` for `a` accumulated
# with g_ab.
# :note:
# - The grad implemented is structured.
# - a_* are the corresponding properties of a sparse
# matrix in csr format.
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
return
(
type
(
self
)
==
type
(
other
))
return
(
type
(
self
)
==
type
(
other
))
...
@@ -3937,11 +4242,20 @@ sdg_csr = StructuredDotGradCSR()
...
@@ -3937,11 +4242,20 @@ sdg_csr = StructuredDotGradCSR()
class
Dot
(
gof
.
op
.
Op
):
class
Dot
(
gof
.
op
.
Op
):
"""
"""Operation for efficiently calculating the dot product when
Operation for efficiently calculating the dot product when
one or all operands is sparse. Supported format are CSC and CSR.
one or all operands is sparse. Supported format are CSC and CSR.
The output of the operation is dense.
The output of the operation is dense.
:param x: Matrix variable.
:param y: Matrix variable.
:return: The dot product `x`.`y` in a dense format.
:note:
- The grad implemented is regular, i.e. not structured.
- At least one of `x` or `y` must be a sparse matrix.
"""
"""
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
return
type
(
self
)
==
type
(
other
)
return
type
(
self
)
==
type
(
other
)
...
@@ -4007,11 +4321,20 @@ _dot = Dot()
...
@@ -4007,11 +4321,20 @@ _dot = Dot()
def
dot
(
x
,
y
):
def
dot
(
x
,
y
):
"""
"""Operation for efficiently calculating the dot product when
Operation for efficiently calculating the dot product when
one or all operands is sparse. Supported format are CSC and CSR.
one or all operands is sparse. Supported format are CSC and CSR.
The output of the operation is dense.
The output of the operation is dense.
:param x: Matrix variable.
:param y: Matrix variable.
:return: The dot product `x`.`y` in a dense format.
:note:
- The grad implemented is regular, i.e. not structured.
- At least one of `x` or `y` must be a sparse matrix.
"""
"""
if
hasattr
(
x
,
'getnnz'
):
if
hasattr
(
x
,
'getnnz'
):
x
=
as_sparse_variable
(
x
)
x
=
as_sparse_variable
(
x
)
if
hasattr
(
y
,
'getnnz'
):
if
hasattr
(
y
,
'getnnz'
):
...
@@ -4027,16 +4350,23 @@ def dot(x, y):
...
@@ -4027,16 +4350,23 @@ def dot(x, y):
class
Usmm
(
gof
.
op
.
Op
):
class
Usmm
(
gof
.
op
.
Op
):
"""
"""Performs the expression is `alpha` * `x` `y` + `z`.
Performs the expression is alpha * x y + z
:param x: Matrix variable.
:param y: Matrix variable.
:param z: Dense matrix.
:param alpha: A tensor scalar.
x or y are sparse matrix(the other can be sparse or dense)
:return: The dense matrix resulting from `alpha` * `x` `y` + `z`.
z is a dense matrix
alpha is a scalar
:note: We don't implement the infer_shape as it is inserted by optimization
:note:
only
- The grad is not implemented for this op.
- At least one of `x` or `y` must be a sparse matrix.
"""
"""
# We don't implement the infer_shape as it is
# inserted by optimization only.
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
return
type
(
self
)
==
type
(
other
)
return
type
(
self
)
==
type
(
other
)
...
@@ -4094,17 +4424,20 @@ usmm = Usmm()
...
@@ -4094,17 +4424,20 @@ usmm = Usmm()
class
UsmmCscDense
(
gof
.
Op
):
class
UsmmCscDense
(
gof
.
Op
):
"""
# Performs the expression is `alpha` * `x` `y` + `z`.
Performs the expression is alpha * x y + z
This is an optimized operation for the case when x is in CSC format.
x are sparse matrix
# :param x: Matrix variable.
y, z is a dense matrix
# :param y: Matrix variable.
alpha is a scalar
# :param z: Dense matrix.
# :param alpha: A tensor scalar.
# :return: The dense matrix resulting from `alpha` * `x` `y` + `z`.
# :note:
# - The grad is not implemented for this op.
# - Optimized version os Usmm when `x` is in csc format and
# `y` is dense.
:note: We don't implement the infer_shape as it is inserted by optimization
only
"""
def
__init__
(
self
,
inplace
):
def
__init__
(
self
,
inplace
):
self
.
inplace
=
inplace
self
.
inplace
=
inplace
if
inplace
:
if
inplace
:
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论