Maybe sparse.py now works?

上级 2bbaeb62
...@@ -80,88 +80,86 @@ class _testCase_dot(unittest.TestCase): ...@@ -80,88 +80,86 @@ class _testCase_dot(unittest.TestCase):
def setUp(self): def setUp(self):
numpy.random.seed(44) numpy.random.seed(44)
def test(self): def test_basic0(self):
"""Bring back the tests for sparse dot""" for mtype in [sparse.csc_matrix, sparse.csr_matrix]:
raise NotImplementedError() x = assparse(mtype(sparse.speye(5,3)))
if 0: y = tensor.astensor(numpy.random.rand(3, 2))
def test_basic0(self):
for mtype in [sparse.csc_matrix, sparse.csr_matrix]: zop = dot(x,y)
x = assparse(mtype(sparse.speye(5,3))) z = compile.eval_outputs([zop])
y = astensor(numpy.random.rand(3, 2)) self.failUnless(z.shape == (5,2))
self.failUnless(type(z) is mtype)
z = dot(x,y)
self.failUnless(z.data.shape == (5,2)) # def test_basic1(self):
self.failUnless(type(z.data) is mtype) # """dot: sparse left"""
# a = numpy.asarray([[1, 0, 3, 0, 5], [0, 0, -2, 0, 0]],
def test_basic1(self): # dtype='float64')
"""dot: sparse left""" # b = numpy.random.rand(5, 3)
a = numpy.asarray([[1, 0, 3, 0, 5], [0, 0, -2, 0, 0]], # for mtype in [sparse.csr_matrix, sparse.csc_matrix, sparse.dok_matrix,
dtype='float64') # sparse.lil_matrix]:#, sparse.coo_matrix]:
b = numpy.random.rand(5, 3) # #print type(a), mtype
for mtype in [sparse.csr_matrix, sparse.csc_matrix, sparse.dok_matrix, # m = mtype(a)
sparse.lil_matrix]:#, sparse.coo_matrix]: # ab = m.dot(b)
#print type(a), mtype # try:
m = mtype(a) # z = dot(assparse(m), gof.Result(data=b))
ab = m.dot(b) # self.failUnless(z.data.shape == ab.shape)
try: # self.failUnless(type(z.data) == type(ab))
z = dot(SparseR(m),core.Result(data=b)) # except Exception, e:
self.failUnless(z.data.shape == ab.shape) # print 'cccc', mtype, e, str(e)
self.failUnless(type(z.data) == type(ab)) # raise
except Exception, e: #
print 'cccc', mtype, e, str(e) # def test_basic2(self):
raise # """dot: sparse right"""
# a = numpy.random.rand(2, 5)
def test_basic2(self): # b = numpy.asarray([[1, 0, 3, 0, 5], [0, 0, -2, 0, 0]],
"""dot: sparse right""" # dtype='float64').transpose()
a = numpy.random.rand(2, 5) #
b = numpy.asarray([[1, 0, 3, 0, 5], [0, 0, -2, 0, 0]], # for mtype in [sparse.csr_matrix, sparse.csc_matrix, sparse.dok_matrix,
dtype='float64').transpose() # sparse.lil_matrix]:#, sparse.coo_matrix]:
# m = mtype(b)
for mtype in [sparse.csr_matrix, sparse.csc_matrix, sparse.dok_matrix, # ab = m.transpose().dot(a.transpose()).transpose()
sparse.lil_matrix]:#, sparse.coo_matrix]: # z = dot(gof.Result(data=a),assparse(mtype(b)))
m = mtype(b) # self.failUnless(z.data.shape == ab.shape)
ab = m.transpose().dot(a.transpose()).transpose() # self.failUnless(type(z.data) == type(ab))
z = dot(core.Result(data=a),SparseR(mtype(b))) #
self.failUnless(z.data.shape == ab.shape) # def test_graph_bprop0(self):
self.failUnless(type(z.data) == type(ab)) # x = tensor.astensor(numpy.random.rand(10,2))
# w = assparse(sparse.csr_matrix(
def test_graph_bprop0(self): # numpy.asarray([[1, 0, 3, 0, 5], [0, 0, -2, 0,0]],dtype='float64')
x = core.wrap(numpy.random.rand(10,2)) # ))
w = SparseR(sparse.csr_matrix(numpy.asarray([[1, 0, 3, 0, 5], [0, 0, -2, 0, #
0]],dtype='float64'))) # for epoch in xrange(50):
# xw = dense_from_sparse(dot(x, w))
for epoch in xrange(50): # y = dense_from_sparse(dot(xw, transpose(w)))
xw = sparse2dense(dot(x, w)) # loss = core.sum(core.sqr(x-y))
y = sparse2dense(dot(xw, transpose(w))) # gy = y-x
loss = core.sum(core.sqr(x-y)) # g = grad.Grad({y:gy})
gy = y-x # g.bprop()
g = grad.Grad({y:gy}) # lr = 0.002
g.bprop() # g(w).data[1,0] = 0
lr = 0.002 # g(w).data[1,4] = 0
g(w).data[1,0] = 0 # w.data = -lr * g(w).data + w.data
g(w).data[1,4] = 0 #
w.data = -lr * g(w).data + w.data # self.failUnless('3.08560636025' == str(loss.data))
#
self.failUnless('3.08560636025' == str(loss.data)) # def test_graph_bprop1(self):
# x = tensor.astensor(numpy.random.rand(10,2))
def test_graph_bprop1(self): # w = assparse(sparse.csr_matrix(
x = core.wrap(numpy.random.rand(10,2)) # numpy.asarray([[1, 0, 3, 0, 5], [0, 0, -2, 0,0]],dtype='float64')
w = SparseR(sparse.csr_matrix(numpy.asarray([[1, 0, 3, 0, 5], [0, 0, -2, 0, # ))
0]],dtype='float64'))) #
# for epoch in xrange(50):
for epoch in xrange(50): # xw = dense_from_sparse(dot(x, w))
xw = sparse2dense(dot(x, w)) # y = dense_from_sparse(dot(xw, transpose(w)))
y = sparse2dense(dot(xw, transpose(w))) # loss = core.sum(core.sqr(x-y))
loss = core.sum(core.sqr(x-y)) # g = grad.grad(loss)
g = grad.grad(loss) # lr = 0.001
lr = 0.001 #
# g(w).data[1,0] = 0
g(w).data[1,0] = 0 # g(w).data[1,4] = 0
g(w).data[1,4] = 0 # w.data = -lr * g(w).data + w.data
w.data = -lr * g(w).data + w.data #
# self.failUnless('3.08560636025' == str(loss.data))
self.failUnless('3.08560636025' == str(loss.data))
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -131,15 +131,19 @@ class Op(object): ...@@ -131,15 +131,19 @@ class Op(object):
this L{Op}'s inputs. this L{Op}'s inputs.
To do a bottom-up copy of a graph, use clone_with_new_inputs. To do a bottom-up copy of a graph, use clone_with_new_inputs.
@attention: If your L{Op} has additional options or a different
constructor you probably want to override this.
""" """
return self.__class__(*self.inputs) return self.__class__(*self.inputs)
def clone_with_new_inputs(self, *new_inputs): def clone_with_new_inputs(self, *new_inputs):
""" """
Returns a clone of this L{Op} that takes different inputs. The Returns a clone of this L{Op} that takes different inputs. The
default behavior is to call the constructor on the new inputs, default behavior is to call the constructor on the new inputs.
but if your L{Op} has additional options or a different constructor
you might want to override this. @attention: If your L{Op} has additional options or a different
constructor you probably want to override this.
""" """
return self.__class__(*new_inputs) return self.__class__(*new_inputs)
......
"""
Classes for handling sparse matrices.
To read about different sparse formats, see U{http://www-users.cs.umn.edu/~saad/software/SPARSKIT/paper.ps}.
@todo Automatic methods for determining best sparse format?
"""
import copy #for __copy__ import copy #for __copy__
import numpy import numpy
from scipy import sparse from scipy import sparse
...@@ -14,10 +22,14 @@ def assparse(sp, **kwargs): ...@@ -14,10 +22,14 @@ def assparse(sp, **kwargs):
@param sp: A sparse matrix. assparse reads dtype and format properties @param sp: A sparse matrix. assparse reads dtype and format properties
out of this sparse matrix. out of this sparse matrix.
@return: SparseR version of sp. @return: SparseR version of sp.
@todo Verify that sp is sufficiently sparse, and raise a warning if it is not
""" """
if isinstance(sp, SparseR): if isinstance(sp, SparseR):
return sp return sp
else: else:
# @todo Verify that sp is sufficiently sparse, and raise a
# warning if it is not
rval = SparseR(str(sp.dtype), sp.format, **kwargs) rval = SparseR(str(sp.dtype), sp.format, **kwargs)
rval.data = sp rval.data = sp
return rval return rval
...@@ -156,43 +168,65 @@ class AddSS(gof.op.Op): #add two sparse matrices ...@@ -156,43 +168,65 @@ class AddSS(gof.op.Op): #add two sparse matrices
return gz, gz return gz, gz
add_s_s = gof.op.constructor(AddSS) add_s_s = gof.op.constructor(AddSS)
#class Dot(gof.op.Op): class Dot(gof.op.Op):
# def __init__(self, x, y): """
# self.inputs = [x, y] # Need to convert? e.g. _as_tensor Attributes:
# # broadcastable grad_preserves_dense - a boolean flags [default: True].
# def perform: grad_preserves_dense controls whether gradients with respect to inputs
# #return numpy.dot(x, y) are converted to dense matrices when the corresponding input y is
# def grad: dense (not in a L{SparseR} wrapper). This is generally a good idea
# when L{Dot} is in the middle of a larger graph, because the types
# """ of gy will match that of y. This conversion might be inefficient if
# Attributes: the gradients are graph outputs though, hence this mask.
# grad_preserves_dense - an array of boolean flags (described below) """
# def __init__(self, x, y, grad_preserves_dense=True):
# """
# grad_preserves_dense controls whether gradients with respect to inputs are Because of trickiness of implementing, we assume that the left argument x is SparseR (not dense)
# converted to dense matrices when the corresponding inputs are not in a """
# SparseR wrapper. This can be a good idea when dot is in the middle of a if x.dtype != y.dtype:
# larger graph, because the types of gx and gy will match those of x and y. raise NotImplementedError()
# This conversion might be annoying if the gradients are graph outputs though,
# hence this mask. # These are the conversions performed by scipy.sparse.dot
# """ if x.format == "csc" or x.format == "coo":
# def __init__(self, *args, **kwargs): myformat = "csc"
# gof.op.Op.__init__(self, **kwargs) elif x.format == "csr":
# self.grad_preserves_dense = [True, True] myformat = "csr"
# def gen_outputs(self): return [SparseR()] else:
# def impl(x,y): raise NotImplementedError()
# if hasattr(x, 'getnnz'):
# # if x is sparse, then do this. self.inputs = [x, y] # Need to convert? e.g. assparse
# return x.dot(y) self.outputs = [SparseR(x.dtype, myformat)]
# else: self.grad_preserves_dense = grad_preserves_dense
# # if x is dense (and y is sparse), we do this def perform(self):
# return y.transpose().dot(x.transpose()).transpose() """
# @todo Verify that output is sufficiently sparse, and raise a warning if it is not
# def grad(self, x, y, gz): @todo Also determine that we are storing the output in the best storage format?
# rval = [dot(gz, y.T), dot(x.T, gz)] """
# for i in 0,1: self.outputs[0].data = self.inputs[0].data.dot(self.inputs[1].data)
# if not isinstance(self.inputs[i], SparseR): def grad(self, (x, y), (gz,)):
# #assume it is a dense matrix rval = [dot(gz, y.T), dot(x.T, gz)]
# if self.grad_preserves_dense[i]: assert isinstance(self.inputs[0], SparseR)
# rval[i] = dense_from_sparse(rval[i]) if not isinstance(self.inputs[1], SparseR):
# return rval if self.grad_preserves_dense:
rval[1] = dense_from_sparse(rval[1])
return rval
def __copy__(self):
return self.__class__(self.inputs[0], self.inputs[1], self.grad_preserves_dense)
def clone_with_new_inputs(self, *new_inputs):
return self.__class__(new_inputs[0], new_inputs[1], self.grad_preserves_dense)
def dot(x, y, grad_preserves_dense=True):
"""
@todo Maybe the triple-transposition formulation (when x is dense)
is slow. See if there is a direct way to do this.
"""
if hasattr(x, 'getnnz'): x = assparse(x)
if hasattr(y, 'getnnz'): y = assparse(y)
x_is_sparse = isinstance(x, SparseR)
y_is_sparse = isinstance(y, SparseR)
if not x_is_sparse and not y_is_sparse:
raise TypeError()
if x_is_sparse:
return Dot(x,y,grad_preserves_dense).outputs[0]
else:
return transpose(Dot(transpose(y), transpose(x), grad_preserves_dense).outputs[0])
...@@ -351,6 +351,9 @@ class Dot(_Op): ...@@ -351,6 +351,9 @@ class Dot(_Op):
def impl(self, x, y): def impl(self, x, y):
return numpy.dot(x, y) return numpy.dot(x, y)
def grad(self, (x, y), gz): def grad(self, (x, y), gz):
"""
@todo Shouldn't it be (gz,) ? -jpt
"""
return dot(gz, y.T), dot(x.T, gz) return dot(gz, y.T), dot(x.T, gz)
if 0: if 0:
def c_support_code(self): def c_support_code(self):
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论