Skip to content

Commit 0ff776f

Browse files
author
dante.l
committed
Merge branch 'release/v1.2.2'
2 parents faa7f8d + 054ef1d commit 0ff776f

File tree

36 files changed

+856
-308
lines changed

36 files changed

+856
-308
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ dist/
88
*.egg-info/
99
Makefile
1010
!docs/Makefile
11+
version.py

CMakeLists.txt

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -fPIC -Wall -Wextra -fopenmp
44

55
include(GNUInstallDirs)
66

7-
include_directories("./include")
8-
include_directories("./3rd/json11")
9-
include_directories("./3rd/spdlog/include")
10-
include_directories("./3rd/n2/include")
11-
include_directories("./3rd/eigen3")
12-
137
set(SOURCES
148
"./3rd/json11/json11.cpp"
159
)
@@ -20,8 +14,16 @@ file(GLOB CFR_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/lib/algo_impl/cfr/*.cc)
2014
file(GLOB BPR_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/lib/algo_impl/bpr/*.cc)
2115
file(GLOB WARP_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/lib/algo_impl/warp/*.cc)
2216
file(GLOB W2V_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/lib/algo_impl/w2v/*.cc)
23-
add_library(cbuffalo SHARED ${SOURCES} ${ALGO_SRCS} ${ALS_SRCS} ${CFR_SRCS} ${BPR_SRCS} ${WARP_SRCS} ${W2V_SRCS} ${MISC_SRCS})
24-
include_directories(cbuffalo "/usr/local/include/eigen3")
17+
file(GLOB PLSI_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/lib/algo_impl/plsi/*.cc)
18+
add_library(cbuffalo SHARED ${SOURCES} ${ALGO_SRCS} ${ALS_SRCS} ${CFR_SRCS} ${BPR_SRCS} ${WARP_SRCS} ${W2V_SRCS} ${PLSI_SRCS} ${MISC_SRCS})
19+
target_include_directories(cbuffalo
20+
PRIVATE
21+
./include
22+
./3rd/json11
23+
./3rd/spdlog/include
24+
./3rd/n2/include
25+
./3rd/eigen3
26+
)
2527

2628
set_target_properties(cbuffalo PROPERTIES VERSION 0.1.0)
2729
set_target_properties(cbuffalo PROPERTIES SOVERSION 1)
@@ -34,3 +36,34 @@ install(DIRECTORY "${CMAKE_SOURCE_DIR}/include/buffalo" # source directory
3436
FILES_MATCHING # install only matched files
3537
PATTERN "*.hpp" # select header files
3638
)
39+
40+
set(N2_DIR "./3rd/n2")
41+
file(GLOB_RECURSE N2_SRC CONFIGURE_DEPENDS ${N2_DIR}/src/*.cc)
42+
add_library(n2 SHARED ${N2_SRC})
43+
target_compile_options(n2 PRIVATE
44+
${OpenMP_CXX_FLAGS}
45+
"-DBOOST_DISABLE_ASSERTS"
46+
)
47+
target_link_libraries(n2 PRIVATE pthread)
48+
target_include_directories(n2
49+
PRIVATE
50+
${N2_DIR}/include/
51+
${N2_DIR}/third_party/eigen/
52+
${N2_DIR}/third_party/spdlog/include/
53+
${N2_DIR}/third_party/boost/mpl/include/
54+
${N2_DIR}/third_party/boost/bind/include/
55+
${N2_DIR}/third_party/boost/core/include/
56+
${N2_DIR}/third_party/boost/heap/include/
57+
${N2_DIR}/third_party/boost/mp11/include/
58+
${N2_DIR}/third_party/boost/assert/include/
59+
${N2_DIR}/third_party/boost/config/include/
60+
${N2_DIR}/third_party/boost/detail/include/
61+
${N2_DIR}/third_party/boost/utility/include/
62+
${N2_DIR}/third_party/boost/iterator/include/
63+
${N2_DIR}/third_party/boost/parameter/include/
64+
${N2_DIR}/third_party/boost/type_traits/include/
65+
${N2_DIR}/third_party/boost/preprocessor/include/
66+
${N2_DIR}/third_party/boost/concept_check/include/
67+
${N2_DIR}/third_party/boost/static_assert/include/
68+
${N2_DIR}/third_party/boost/throw_exception/include/
69+
)

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
include cuda_setup.py
22
include CMakeLists.txt
33
include requirements.txt
4+
include pyproject.toml
45
include tests/res/*.json
56
recursive-exclude buffalo/ *.cpp
67
recursive-include buffalo/ *.pyx

NOTICE.md

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -114,16 +114,6 @@ Copyright 2005-2018, NumPy Developers.
114114
BSD 3-Clause "New" or "Revised" License
115115

116116

117-
**pathlib**
118-
119-
https://bitbucket.org/pitrou/pathlib
120-
121-
Copyright 2012 Antoine Pitrou
122-
123-
124-
MIT License
125-
126-
127117
**psutil**
128118

129119
https://github.com/giampaolo/psutil
@@ -164,14 +154,14 @@ Copyright 2007-2019 by the Sphinx team (see AUTHORS file).
164154
BSD 2-Clause "Simplified" License
165155

166156

167-
**TensorFlow**
157+
**Tensorboard**
168158

169-
https://github.com/tensorflow/tensorflow
159+
https://github.com/tensorflow/tensorboard
170160

171-
Copyright 2019 The TensorFlow Authors.
161+
Copyright 2017 The TensorFlow Authors.
172162

173163

174-
Apache License 2.0
164+
Apache License 2.0
175165

176166

177167
**tqdm**

benchmark/evaluate.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def filter_seen_items(_topk, seen, topk):
3838
HIT += hit
3939

4040
# ndcg, map
41-
idcg = idcgs[min(len(_gt), len(_topk)) - 1]
41+
idcg = idcgs[min(len(_gt), topk) - 1]
4242
dcg = 0.0
4343
hit, miss, ap = 0.0, 0.0, 0.0
4444

@@ -60,7 +60,7 @@ def filter_seen_items(_topk, seen, topk):
6060

6161
ndcg = dcg / idcg
6262
NDCG += ndcg
63-
ap /= min(len(_gt), len(_topk))
63+
ap /= min(len(_gt), topk)
6464
AP += ap
6565
N += 1.0
6666
AUC += auc

buffalo/algo/_plsi.pyx

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# cython: experimental_cpp_class_def=True, language_level=3
2+
# distutils: language=c++
3+
# -*- coding: utf-8 -*-
4+
import cython
5+
import numpy as np
6+
cimport numpy as np
7+
8+
from libcpp.string cimport string
9+
from libcpp cimport bool as bool_t
10+
from libc.stdint cimport int32_t, int64_t
11+
12+
13+
cdef extern from "buffalo/algo_impl/plsi/plsi.hpp" namespace "plsi":
14+
cdef cppclass CPLSI:
15+
bool_t init(string) nogil except +
16+
void release() nogil except +
17+
void swap() nogil except +
18+
void reset() nogil except +
19+
void initialize_model(float*, int, float*, int) nogil except +
20+
float partial_update(int, int, int64_t*, int32_t*, float*) nogil except +
21+
void normalize(float, float) nogil except +
22+
23+
24+
cdef class CyPLSI:
25+
"""CPLSI object holder"""
26+
cdef CPLSI* obj # C-PLSI object
27+
28+
def __cinit__(self):
29+
self.obj = new CPLSI()
30+
31+
def __dealloc__(self):
32+
self.obj.release()
33+
del self.obj
34+
35+
def init(self, opt_path):
36+
return self.obj.init(opt_path)
37+
38+
def swap(self):
39+
self.obj.swap()
40+
41+
def release(self):
42+
self.obj.release()
43+
44+
def reset(self):
45+
self.obj.reset()
46+
47+
def initialize_model(self, np.ndarray[np.float32_t, ndim=2] P,
48+
np.ndarray[np.float32_t, ndim=2] Q):
49+
self.obj.initialize_model(&P[0, 0], P.shape[0],
50+
&Q[0, 0], Q.shape[0])
51+
52+
def normalize(self, alpha1, alpha2):
53+
self.obj.normalize(alpha1, alpha2)
54+
55+
@cython.boundscheck(False)
56+
@cython.wraparound(False)
57+
def partial_update(self, int start_x, int next_x,
58+
np.ndarray[np.int64_t, ndim=1] indptr,
59+
np.ndarray[np.int32_t, ndim=1] keys,
60+
np.ndarray[np.float32_t, ndim=1] vals):
61+
return self.obj.partial_update(start_x, next_x, &indptr[0], &keys[0], &vals[0])

buffalo/algo/als.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from buffalo.algo.options import ALSOption
1414
from buffalo.algo.optimize import Optimizable
1515
from buffalo.data.buffered_data import BufferedDataMatrix
16-
from buffalo.algo.base import Algo, Serializable, TensorboardExtention
16+
from buffalo.algo.base import Algo, Serializable, TensorboardExtension
1717

1818
inited_CUALS = True
1919
try:
@@ -22,7 +22,7 @@
2222
inited_CUALS = False
2323

2424

25-
class ALS(Algo, ALSOption, Evaluable, Serializable, Optimizable, TensorboardExtention):
25+
class ALS(Algo, ALSOption, Evaluable, Serializable, Optimizable, TensorboardExtension):
2626
"""Python implementation for C-ALS.
2727
2828
Implementation of Collaborative Filtering for Implicit Feedback datasets.

buffalo/algo/base.py

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# -*- coding: utf-8 -*-
22
import os
3-
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
43
import abc
54
import json
65
import pickle
@@ -9,10 +8,7 @@
98
import datetime
109

1110
import numpy as np
12-
import tensorflow as tf
13-
tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)
14-
from tensorflow.keras.utils import Progbar
15-
# what the...
11+
import tensorboard as tb
1612
import absl.logging
1713
logging.root.removeHandler(absl.logging._absl_handler)
1814
absl.logging._warn_preinit_stderr = False
@@ -331,18 +327,15 @@ def instantiate(cls, cls_opt, path, data_fields):
331327
return c
332328

333329

334-
class TensorboardExtention(object):
330+
class TensorboardExtension(object):
335331
@abc.abstractmethod
336332
def get_evaluation_metrics(self):
337333
raise NotImplementedError
338334

339335
def _get_initial_tensorboard_data(self):
340336
tb = aux.Option({'summary_writer': None,
341337
'name': None,
342-
'metrics': {},
343-
'feed_dict': {},
344-
'merged_summary_op': None,
345-
'session': None,
338+
'metrics': [],
346339
'pbar': None,
347340
'data_root': None,
348341
'step': 1})
@@ -352,41 +345,28 @@ def initialize_tensorboard(self, num_steps, name_prefix='', name_postfix='', met
352345
if not self.opt.tensorboard:
353346
if not hasattr(self, '_tb_setted'):
354347
self.logger.debug('Cannot find tensorboard configuration.')
355-
self.tb_setted = False
348+
self._tb_setted = False
356349
return
357350
name = self.opt.tensorboard.name
358351
name = name_prefix + name + name_postfix
359352
dtm = datetime.datetime.now().strftime('%Y%m%d-%H.%M')
360353
template = self.opt.tensorboard.get('name_template', '{name}.{dtm}')
361354
self._tb = self._get_initial_tensorboard_data()
362355
self._tb.name = template.format(name=name, dtm=dtm)
363-
if not os.path.isdir(self.opt.tensorboard.root):
364-
os.makedirs(self.opt.tensorboard.root)
356+
os.makedirs(self.opt.tensorboard.root, exist_ok=True)
365357
tb_dir = os.path.join(self.opt.tensorboard.root, self._tb.name)
366358
self._tb.data_root = tb_dir
367-
self._tb.summary_writer = tf.summary.FileWriter(tb_dir)
368-
if not metrics:
369-
metrics = self.get_evaluation_metrics()
370-
for m in metrics:
371-
self._tb.metrics[m] = tf.placeholder(tf.float32)
372-
tf.summary.scalar(m, self._tb.metrics[m])
373-
self._tb.feed_dict[self._tb.metrics[m]] = 0.0
374-
self._tb.merged_summary_op = tf.summary.merge_all()
375-
self._tb.session = tf.Session()
376-
self._tb.pbar = Progbar(num_steps, stateful_metrics=self._tb.metrics, verbose=0)
359+
self._tb.summary_writer = tb.summary.Writer(tb_dir)
360+
self._tb.metrics = metrics if metrics is not None else self.get_evaluation_metrics()
377361
self._tb_setted = True
378362

379363
def update_tensorboard_data(self, metrics):
380364
if not self.opt.tensorboard:
381365
return
382-
metrics = [(m, np.float32(metrics.get(m, 0.0)))
383-
for m in self._tb.metrics.keys()]
384-
self._tb.feed_dict = {self._tb.metrics[k]: v
385-
for k, v in metrics}
386-
summary = self._tb.session.run(self._tb.merged_summary_op,
387-
feed_dict=self._tb.feed_dict)
388-
self._tb.summary_writer.add_summary(summary, self._tb.step)
389-
self._tb.pbar.update(self._tb.step, metrics)
366+
for m in self._tb.metrics:
367+
v = metrics.get(m, 0.0)
368+
self._tb.summary_writer.add_scalar(m, v, self._tb.step)
369+
self._tb.summary_writer.flush()
390370
self._tb.step += 1
391371

392372
def finalize_tensorboard(self):
@@ -395,6 +375,4 @@ def finalize_tensorboard(self):
395375
with open(os.path.join(self._tb.data_root, 'opt.json'), 'w') as fout:
396376
fout.write(json.dumps(self.opt, indent=2))
397377
self._tb.summary_writer.close()
398-
self._tb.session.close()
399378
self._tb = None
400-
tf.reset_default_graph()

buffalo/algo/bpr.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from buffalo.algo.options import BPRMFOption
1616
from buffalo.algo.optimize import Optimizable
1717
from buffalo.data.buffered_data import BufferedDataMatrix
18-
from buffalo.algo.base import Algo, Serializable, TensorboardExtention
18+
from buffalo.algo.base import Algo, Serializable, TensorboardExtension
1919

2020
# TODO init structure of gpu modules will be abstracted to a higher module
2121
inited_CUBPR = True
@@ -25,7 +25,7 @@
2525
inited_CUBPR = False
2626

2727

28-
class BPRMF(Algo, BPRMFOption, Evaluable, Serializable, Optimizable, TensorboardExtention):
28+
class BPRMF(Algo, BPRMFOption, Evaluable, Serializable, Optimizable, TensorboardExtension):
2929
"""Python implementation for C-BPRMF.
3030
"""
3131
def __init__(self, opt_path=None, *args, **kwargs):
@@ -41,7 +41,7 @@ def __init__(self, opt_path=None, *args, **kwargs):
4141
self.opt, self.opt_path = self.get_option(opt_path)
4242

4343
if self.opt.accelerator and not inited_CUBPR:
44-
self.logger.error(f"ImportError CuBPRMF, no cuda library exists.")
44+
self.logger.error('ImportError CuBPRMF, no cuda library exists.')
4545
raise RuntimeError()
4646
self.obj = CuBPRMF() if self.opt.accelerator else CyBPRMF()
4747

@@ -92,11 +92,11 @@ def init_factors(self):
9292
for attr_name in ['P', 'Q', 'Qb']:
9393
setattr(self, attr_name, None)
9494
self.P = np.abs(np.random.normal(scale=1.0 / (self.opt.d ** 2),
95-
size=(header['num_users'], self.opt.d)).astype("float32"), order='C')
95+
size=(header['num_users'], self.opt.d)).astype('float32'), order='C')
9696
self.Q = np.abs(np.random.normal(scale=1.0 / (self.opt.d ** 2),
97-
size=(header['num_items'], self.opt.d)).astype("float32"), order='C')
97+
size=(header['num_items'], self.opt.d)).astype('float32'), order='C')
9898
self.Qb = np.abs(np.random.normal(scale=1.0 / (self.opt.d ** 2),
99-
size=(header['num_items'], 1)).astype("float32"), order='C')
99+
size=(header['num_items'], 1)).astype('float32'), order='C')
100100
if not self.opt.use_bias:
101101
self.Qb *= 0
102102
self.obj.initialize_model(self.P, self.Q, self.Qb, self.num_nnz)
@@ -200,7 +200,7 @@ def compute_loss(self):
200200
def _prepare_train(self):
201201
if self.opt.accelerator:
202202
vdim = self.obj.get_vdim()
203-
for attr in ["P", "Q"]:
203+
for attr in ['P', 'Q']:
204204
F = getattr(self, attr)
205205
if F.shape[1] < vdim:
206206
_F = np.empty(shape=(F.shape[0], vdim), dtype=np.float32)

buffalo/algo/cfr.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414
from buffalo.algo.options import CFROption
1515
from buffalo.algo.optimize import Optimizable
1616
from buffalo.data.buffered_data import BufferedDataMatrix
17-
from buffalo.algo.base import Algo, Serializable, TensorboardExtention
17+
from buffalo.algo.base import Algo, Serializable, TensorboardExtension
1818

1919

20-
class CFR(Algo, CFROption, Evaluable, Serializable, Optimizable, TensorboardExtention):
20+
class CFR(Algo, CFROption, Evaluable, Serializable, Optimizable, TensorboardExtension):
2121
"""Python implementation for CoFactor.
2222
2323
Reference: Factorization Meets the Item Embedding:

0 commit comments

Comments
 (0)