This repository has been archived by the owner on Nov 17, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6.8k
Sparse Tensor: request for reviews #7082
Merged
Merged
Changes from 15 commits
Commits
Show all changes
87 commits
Select commit
Hold shift + click to select a range
c5f6648
[WIP] Sparse Tensor (#5800)
eric-haibin-lin db65770
move storage type vector from nnvm to mxnet (#7054)
eric-haibin-lin e2607da
fix failed tests. add back 64bit support for dot
eric-haibin-lin 978748e
Improve copy sparse tensors (#7003)
reminisce ce0fec8
bug fix for IdentityComputeRsp
eric-haibin-lin a2b3d3e
fix lint
eric-haibin-lin 27c9ac0
add data partition for libsvm iter (#7027)
eric-haibin-lin 3a394ea
fix ndarray namespace
eric-haibin-lin cf61a9e
remove sparse embedding (#7165)
eric-haibin-lin fe62976
remove untested gpu operators (#7172)
eric-haibin-lin 4de0fdd
Fix ndarray aux data issue (#7098)
reminisce a472b61
Support K-dimensional row-sparse tensor (#7179)
eric-haibin-lin 6a01b6e
Improve sparse ndarray error message (#7181)
eric-haibin-lin 05ddf38
construct row_sparse ndarray for dist-async
eric-haibin-lin f57fc3c
Merge remote-tracking branch 'upstream/master' into dmlc-sparse-squash
eric-haibin-lin 0ed14d1
fix DotCsrRspRspImpl error message (#7191)
stefanhenneking f0af872
GPU implementation of cast_storage (dense to csr) (#7081)
stefanhenneking 6f0719f
Sparse square sum (#7206)
reminisce ec2c4bf
Modify and Add documentation for mx.nd.zeros (#7197)
anirudh2290 88eaac6
Merge remote-tracking branch 'upstream/master' into dmlc-sparse-squash
eric-haibin-lin 3b94a3c
Expose kWriteInplace for imperative execution (fcompute_ex and fstate…
eric-haibin-lin 55e4763
Operator add_n for row sparse ndarrays (#7244)
reminisce 7e1647c
GPU implementation of cast_storage (dense to rsp) (#7223)
stefanhenneking 5905ddc
merge with dmlc/master
eric-haibin-lin d8a9aba
resolve merge conflict in ndarray.load
eric-haibin-lin f686174
Improve StatefulOp/FCompute storage fallback (#134)
eric-haibin-lin d0579c4
update sparse ndarray api (#139)
eric-haibin-lin 56b5a63
Merge remote-tracking branch 'upstream/master' into sparse
eric-haibin-lin 325f4db
Handle ograd_stype='row_sparse' for square_sum backward (#143)
reminisce 5866b2b
Sparse retain improvement (#138)
reminisce 9298bfa
ignoring variables in SimpleBind that is used on python's sparse bran…
sergeykolychev 1f07771
add bias term to fm test (#145)
eric-haibin-lin d511938
merge with upstream/master. resolve conflict in c_api_ndarray.cc
eric-haibin-lin 6956431
update ndarray.nd, remove `invoke` from excluded members (#137)
eric-haibin-lin 6c9a350
Merge remote-tracking branch 'upstream/master' into sparse
eric-haibin-lin 66b7b8a
support storage fallback with mutable inputs (#147)
eric-haibin-lin cf8ddcf
Merge branch 'sparse' of https://github.com/eric-haibin-lin/mxnet int…
eric-haibin-lin 0396c9a
Merge remote-tracking branch 'upstream/master' into sparse
eric-haibin-lin 2dc7dc9
Code changes based on reviews (#144)
eric-haibin-lin f318c9d
small edits according to reviews (#151)
eric-haibin-lin 85cbc60
Merge remote-tracking branch 'upstream/master' into sparse
eric-haibin-lin fc1aa6e
fix lint (#152)
eric-haibin-lin 9ba96b9
resolve conflict in ndarray.py and capi
eric-haibin-lin 6cbdf98
resolve conflicts in license header
eric-haibin-lin 253ae57
add license to all new files in sparse brnach (#154)
eric-haibin-lin b2ad302
Allocate temp data on the fly for some casting operations (#149)
cjolivier01 129148c
Merge remote-tracking branch 'upstream/master' into sparse
eric-haibin-lin d6f987d
fix utf8 encoding in sparse ndarray
eric-haibin-lin 955e97f
Merge branch 'sparse' of https://github.com/eric-haibin-lin/mxnet int…
eric-haibin-lin bc33101
Extending the GPU dot operator (#7226)
stefanhenneking 8040953
Merge remote-tracking branch 'upstream/master' into sparse
eric-haibin-lin 2d93d72
Add get_synthetic_dataset function to util (#146)
anirudh2290 80a590d
temporary fix for batch norm storage fallback (#156)
eric-haibin-lin 92f54d2
support random_uniform/normal/gamma with row_sparse output (#155)
eric-haibin-lin 17bfa4e
Merge remote-tracking branch 'upstream/master' into sparse
eric-haibin-lin ef3b442
Merge remote-tracking branch 'upstream/master' into sparse
eric-haibin-lin a44afed
Square sum backward support one more case (#161)
reminisce ceca9b6
Add documentation for sparse ops (#148)
eric-haibin-lin 1c60a05
A few fixes (#163)
eric-haibin-lin 04e9129
Merge branch 'sparse' of https://github.com/eric-haibin-lin/mxnet int…
eric-haibin-lin 8ebc012
merge with upstream/master
eric-haibin-lin 889a09e
Minor fixes sparse ops (#160)
stefanhenneking 6b0cac1
sparse Adam optimizer (#164)
eric-haibin-lin eeff444
kvstore.row_sparse_pull for GPU and end-to-end benchmark: CPU vs. mul…
reminisce 54f698b
fix bug in adam update (#167)
eric-haibin-lin 6fa078e
change sparse example from regression to classification (#165)
eric-haibin-lin 8cae272
fix python import (#166)
eric-haibin-lin bed002b
Add waitall to sparse_end2end.py (#169)
reminisce 1682b0b
resolve conflict in dist_kvstore and attach_exec_ops
eric-haibin-lin f2a0852
Dot script changes (#159)
anirudh2290 45045ac
Transpose only if trans_lhs (#171)
anirudh2290 53e94c6
fix default val for distribution (#172)
eric-haibin-lin 356c9ef
fix lint (#175)
eric-haibin-lin 73a1ac5
Merge remote-tracking branch 'upstream/master' into sparse
eric-haibin-lin f9fc789
avoid cast_storage in dist-kvstore-server (#174)
eric-haibin-lin b208b01
Add sparse namespace to ndarray and symbol (#177)
reminisce 7241bee
changes based on code reviews (#176)
eric-haibin-lin e6c775b
Merge remote-tracking branch 'upstream/master' into sparse
eric-haibin-lin a90bf26
temp fix to ndarray.md (#178)
eric-haibin-lin 1d8dce7
Fix sparse namespace pylint (#179)
reminisce bce8d4e
Merge remote-tracking branch 'origin/sparse' into sparse
eric-haibin-lin be74e64
add comments and error msg (#181)
eric-haibin-lin d3c176c
add clarification for csr (#182)
eric-haibin-lin 08435ed
revert change in test util (#183)
eric-haibin-lin 7d525f8
Merge remote-tracking branch 'upstream/master' into sparse
eric-haibin-lin aa04cd2
fix amalgamation (#184)
eric-haibin-lin c228a0d
fix lint
eric-haibin-lin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,228 @@ | ||
import ctypes | ||
|
||
from mxnet.test_utils import * | ||
import scipy.sparse as sp | ||
import os | ||
import time | ||
import argparse | ||
|
||
from mxnet.base import check_call, _LIB | ||
from util import get_data, estimate_density | ||
|
||
parser = argparse.ArgumentParser(description="Benchmark sparse operators", | ||
formatter_class=argparse.ArgumentDefaultsHelpFormatter) | ||
parser.add_argument('--num-omp-threads', type=int, default=1, help='number of omp threads to set in MXNet') | ||
args = parser.parse_args() | ||
|
||
# some data information | ||
kdda = { | ||
'data_mini': 'kdda.t.mini', | ||
'data_name': 'kdda.t', | ||
'data_origin_name': 'kdda.t.bz2', | ||
'url': "https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/binary/kdda.t.bz2", | ||
'feature_dim': 20216830, | ||
'm': 200, | ||
'batch_size': [64] | ||
} | ||
|
||
avazu = { | ||
'data_mini': 'avazu-app.t.mini', | ||
'data_name': 'avazu-app.t', | ||
'data_origin_name': 'avazu-app.t.bz2', | ||
'url': "https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/binary/avazu-app.t.bz2", | ||
'feature_dim': 1000000, | ||
'm': 500, | ||
'batch_size': [64, 128] | ||
} | ||
|
||
|
||
def measure_cost(repeat, f, *args, **kwargs): | ||
# start bench | ||
start = time.time() | ||
results = [] | ||
for i in range(repeat): | ||
results.append(f(*args, **kwargs)) | ||
for result in results: | ||
result.wait_to_read() | ||
end = time.time() | ||
diff = end - start | ||
return diff / repeat | ||
|
||
|
||
def test_dot_real(data_dict): | ||
def get_iter(path, data_shape, batch_size): | ||
data_train = mx.io.LibSVMIter(data_libsvm=path, | ||
data_shape=data_shape, | ||
batch_size=batch_size) | ||
data_iter = iter(data_train) | ||
return data_iter | ||
|
||
data_dir = os.path.join(os.getcwd(), 'data') | ||
|
||
path = os.path.join(data_dir, data_dict['data_name']) | ||
if not os.path.exists(path): | ||
get_data( | ||
data_dir, | ||
data_dict['data_name'], | ||
data_dict['url'], | ||
data_dict['data_origin_name'] | ||
) | ||
assert os.path.exists(path) | ||
|
||
k = data_dict['feature_dim'] | ||
m = data_dict['m'] | ||
density = estimate_density(path, data_dict['feature_dim']) | ||
|
||
mini_path = os.path.join(data_dir, data_dict['data_mini']) | ||
if not os.path.exists(mini_path): | ||
os.system("head -n 2000 %r > %r" % (path, mini_path)) | ||
assert os.path.exists(mini_path) | ||
|
||
print "Running Benchmarking on %r data" % data_dict['data_mini'] | ||
for batch_size in data_dict['batch_size']: # iterator through different batch size of choice | ||
print "batch_size is %d" % batch_size | ||
# model | ||
data_shape = (k, ) | ||
train_iter = get_iter(mini_path, data_shape, batch_size) | ||
weight = mx.nd.random_uniform(low=0, high=1, shape=(k, m)) | ||
|
||
csr_data = [] | ||
dns_data = [] | ||
num_batch = 0 | ||
for batch in train_iter: | ||
data = train_iter.getdata() | ||
csr_data.append(data) | ||
dns_data.append(data.todense()) | ||
num_batch += 1 | ||
bag_of_data = [csr_data, dns_data] | ||
num_repeat = 5 | ||
costs = [] | ||
for d in bag_of_data: | ||
weight.wait_to_read() | ||
cost = 0. | ||
count = 0 | ||
for d_batch in d: | ||
d_batch.wait_to_read() | ||
cost += measure_cost(num_repeat, mx.nd.dot, d_batch, weight) | ||
count += 1 | ||
costs.append(cost/count) | ||
t_sparse = costs[0] | ||
t_dense = costs[1] | ||
ratio = t_dense / t_sparse | ||
print('density(%)\tn\tm\tk\tt_dense/t_sparse\tt_dense\tt_sparse') | ||
fmt = "%0.4f\t\t%d\t%d\t%d\t%0.2f\t\t\t%0.4f\t%0.6f" | ||
print(fmt % (density * 100, batch_size, m, k, ratio, t_dense, t_sparse)) | ||
|
||
|
||
def test_dot_synthetic(): | ||
"""benchmark mx.nd.dot(sparse_ndarray, dense_ndarray) with given density. | ||
`t_sparse` is the time cost of dot(csr, dns), while `t_dense` is the time cost | ||
of dot(dns, dns), with the same matrix except that it is in default storage type. | ||
""" | ||
def measure_cost_forward_baseline(repeat, dot, lhs, rhs): | ||
start = time.time() | ||
for i in range(repeat): | ||
dot(lhs, rhs) | ||
end = time.time() | ||
diff = end - start | ||
return diff / repeat | ||
|
||
def measure_cost_backward_baseline(repeat, dot, transpose, lhs, rhs): | ||
start = time.time() | ||
for i in range(repeat): | ||
dot(transpose(lhs), rhs) | ||
end = time.time() | ||
diff = end - start | ||
return diff / repeat | ||
|
||
def bench_dot_forward(m, k, n, density, ctx, repeat): | ||
set_default_context(ctx) | ||
dns = mx.nd.random_uniform(shape=(k, n)).copyto(ctx) | ||
data_shape = (m, k) | ||
csr_data = rand_ndarray(data_shape, 'csr', density) | ||
dns_data = csr_data.todense() | ||
rhs_dns_np = dns.asnumpy() | ||
lhs_csr_sp = sp.csr_matrix(dns_data.asnumpy()) # csr in scipy | ||
lhs_dns_np = lhs_csr_sp.todense() | ||
|
||
data = [dns_data, csr_data] | ||
costs = [] | ||
for d in data: | ||
dns.wait_to_read() | ||
d.wait_to_read() | ||
cost = measure_cost(repeat, mx.nd.dot, d, dns) | ||
costs.append(cost) | ||
ratio = costs[0] / costs[1] | ||
|
||
costs_baseline = [] | ||
cost = measure_cost_forward_baseline(repeat, np.dot, lhs_dns_np, rhs_dns_np) | ||
costs_baseline.append(cost) | ||
cost = measure_cost_forward_baseline(repeat, sp.spmatrix.dot, lhs_csr_sp, rhs_dns_np) | ||
costs_baseline.append(cost) | ||
ratio_baseline = costs_baseline[0] / costs_baseline[1] | ||
fmt = "%0.1f\t\t%s\t%d\t%d\t%d\t%0.2f\t\t\t%0.2f\t%0.5f\t\t%0.2f\t\t\t\t%0.6f\t%0.5f" | ||
print(fmt % (density * 100, str(ctx), n, m, k, ratio, costs[0], costs[1], | ||
ratio_baseline, costs_baseline[0], costs_baseline[1])) | ||
|
||
def bench_dot_backward(m, k, n, density, ctx, repeat): | ||
set_default_context(ctx) | ||
dns = mx.nd.random_uniform(shape=(m, n)).copyto(ctx) | ||
data_shape = (m, k) | ||
csr_data = rand_ndarray(data_shape, 'csr', density) | ||
dns_data = csr_data.todense() | ||
rhs_dns_np = dns.asnumpy() | ||
lhs_csr_sp = sp.csr_matrix(dns_data.asnumpy()) | ||
lhs_dns_np = lhs_csr_sp.todense() | ||
|
||
data = [dns_data, csr_data] | ||
costs = [] | ||
for d in data: | ||
dns.wait_to_read() | ||
d.wait_to_read() | ||
cost = measure_cost(repeat, mx.nd.dot, d, dns, transpose_a=True) | ||
costs.append(cost) | ||
ratio = costs[0] / costs[1] | ||
|
||
costs_baseline = [] | ||
cost = measure_cost_backward_baseline(repeat, np.dot, np.transpose, lhs_dns_np, rhs_dns_np) | ||
costs_baseline.append(cost) | ||
cost = measure_cost_backward_baseline(repeat, sp.spmatrix.dot, sp.spmatrix.transpose, lhs_csr_sp, rhs_dns_np) | ||
costs_baseline.append(cost) | ||
ratio_baseline = costs_baseline[0] / costs_baseline[1] | ||
fmt = "%0.1f\t\t%s\t%d\t%d\t%d\t%0.2f\t\t\t%0.2f\t%0.5f\t\t%0.2f\t\t\t\t%0.6f\t%0.5f" | ||
print(fmt % (density * 100, str(ctx), n, m, k, ratio, costs[0], costs[1], | ||
ratio_baseline, costs_baseline[0], costs_baseline[1])) | ||
|
||
print("A = sparse NDArray of shape(m, k)") | ||
print("B = dense NDArray of shape(k, n)") | ||
print("dot_forward\tdot(csr, dns)") | ||
print('density(%)\tcontext\tn\tm\tk\tt_dense/t_sparse\tt_dense\tt_sparse' | ||
'\tt_scipy_dense/t_scipy_sparse\tt_scipy_dense\tt_scipy_sparse') | ||
|
||
check_call(_LIB.MXSetNumOMPThreads(ctypes.c_int(args.num_omp_threads))) | ||
# TODO(haibin) make these runtime options | ||
m = 512 | ||
k = [50000, 100000] | ||
n = [64, 128] | ||
density = [1.00, 0.90, 0.70, 0.50, 0.30, 0.20, 0.10, 0.07, 0.05, 0.02, 0.01, 0.005, 0.001] | ||
num_repeat = 10 | ||
# contexts = [mx.cpu(), mx.gpu(0)] | ||
contexts = [mx.cpu()] | ||
for i in range(2): | ||
for ctx in contexts: | ||
for den in density: | ||
bench_dot_forward(m, k[i], n[i], den, ctx, num_repeat) | ||
|
||
print("dot_backward\tdot(csr.T, dns)") | ||
print('density(%)\tcontext\tn\tm\tk\tt_dense/t_sparse\tt_dense\tt_sparse' | ||
'\tt_scipy_dense/t_scipy_sparse\tt_scipy_dense\tt_scipy_sparse') | ||
for i in range(2): | ||
for ctx in contexts: | ||
for den in density: | ||
bench_dot_backward(m, k[i], n[i], den, ctx, num_repeat) | ||
|
||
|
||
if __name__ == "__main__": | ||
test_dot_real(avazu) | ||
test_dot_real(kdda) | ||
test_dot_synthetic() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import os | ||
import random | ||
|
||
|
||
def get_data(data_dir, data_name, url, data_origin_name): | ||
if not os.path.isdir(data_dir): | ||
os.system("mkdir " + data_dir) | ||
os.chdir(data_dir) | ||
if (not os.path.exists(data_name)): | ||
import urllib | ||
zippath = os.path.join(data_dir, data_origin_name) | ||
urllib.urlretrieve(url, zippath) | ||
os.system("bzip2 -d %r" % data_origin_name) | ||
os.chdir("..") | ||
|
||
|
||
def estimate_density(DATA_PATH, feature_size): | ||
"""sample 10 times of a size of 1000 for estimating the density of the sparse dataset""" | ||
if not os.path.exists(DATA_PATH): | ||
raise Exception("Data is not there!") | ||
density = [] | ||
P = 0.01 | ||
for _ in xrange(10): | ||
num_non_zero = 0 | ||
num_sample = 0 | ||
with open(DATA_PATH) as f: | ||
for line in f: | ||
if (random.random() < P): | ||
num_non_zero += len(line.split(" ")) - 1 | ||
num_sample += 1 | ||
density.append(num_non_zero * 1.0 / (feature_size * num_sample)) | ||
return sum(density) / len(density) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# pylint: skip-file | ||
import os, gzip | ||
import pickle as pickle | ||
import sys | ||
|
||
def get_libsvm_data(data_dir, data_name, url, data_origin_name): | ||
if not os.path.isdir(data_dir): | ||
os.system("mkdir " + data_dir) | ||
os.chdir(data_dir) | ||
if (not os.path.exists(data_name)): | ||
import urllib | ||
zippath = os.path.join(data_dir, data_origin_name) | ||
urllib.urlretrieve(url, zippath) | ||
os.system("bzip2 -d %r" % data_origin_name) | ||
os.chdir("..") |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not os.mkdir?