Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ jobs:
- image: cimg/python:3.10.2
environment:
LIMIT_NUMPY_VERSION: 2.0.0
LIMIT_SCIPY_VERSION: 1.13.1
steps:
- checkout
- python/install-packages:
Expand All @@ -20,7 +19,7 @@ jobs:
no_output_timeout: 30m
command: |
pip install --upgrade pip
pip install --only-binary=numpy,scipy "numpy<$LIMIT_NUMPY_VERSION" "scipy<=$LIMIT_SCIPY_VERSION" Cython pytest pytest-cov codecov
pip install --only-binary=numpy,scipy "numpy>$LIMIT_NUMPY_VERSION" Cython pytest pytest-cov codecov
pip install -e .[tests]
- run:
name: Run tests
Expand Down
5 changes: 2 additions & 3 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
build:
name: Building on ${{ matrix.os }}
Expand All @@ -20,7 +20,6 @@ jobs:
python-version: ["3.9", "3.10", "3.11", "3.12"]
env:
LIMIT_NUMPY_VERSION: 2.0.0
LIMIT_SCIPY_VERSION: 1.13.1
steps:
- name: Get number of CPU cores
uses: SimenB/github-actions-cpu-cores@v2
Expand Down Expand Up @@ -63,7 +62,7 @@ jobs:

- name: Install other dependencies
run: |
python${{ matrix.python-version }} -m pip install Cython pytest pytest-cov flake8 "numpy<${{ env.LIMIT_NUMPY_VERSION }}" "scipy<=${{ env.LIMIT_SCIPY_VERSION }}"
python${{ matrix.python-version }} -m pip install Cython pytest pytest-cov flake8 "numpy>${{ env.LIMIT_NUMPY_VERSION }}" scipy
python${{ matrix.python-version }} setup.py build_ext -j${{ steps.cpu-cores.outputs.count }}
python${{ matrix.python-version }} -m pip install -e .[tests]

Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ on:

env:
LIMIT_NUMPY_VERSION: 2.0.0
LIMIT_SCIPY_VERSION: 1.13.1

jobs:
build-wheels:
Expand Down Expand Up @@ -59,7 +58,7 @@ jobs:
run: python${{ matrix.python-version }} -m pip install wheel setuptools pip --upgrade

- name: Install numpy, scipy
run: pip install "numpy<${{ env.LIMIT_NUMPY_VERSION }}" "scipy<=${{ env.LIMIT_SCIPY_VERSION }}"
run: pip install "numpy>${{ env.LIMIT_NUMPY_VERSION }}" scipy

- name: Install other dependencies
run: |
Expand Down
14 changes: 7 additions & 7 deletions cornac/metrics/ranking.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def dcg_score(gt_pos, pd_rank, k=-1):
else:
truncated_pd_rank = pd_rank

ranked_scores = np.in1d(truncated_pd_rank, gt_pos).astype(int)
ranked_scores = np.isin(truncated_pd_rank, gt_pos).astype(int)
gain = 2**ranked_scores - 1
discounts = np.log2(np.arange(len(ranked_scores)) + 2)

Expand Down Expand Up @@ -162,7 +162,7 @@ def compute(self, gt_pos, pd_rank, **kwargs):
truncated_pd_rank = pd_rank

# Compute CRR
rec_rank = np.where(np.in1d(truncated_pd_rank, gt_pos))[0]
rec_rank = np.where(np.isin(truncated_pd_rank, gt_pos))[0]
if len(rec_rank) == 0:
return 0.0
rec_rank = rec_rank + 1 # +1 because indices starts from 0 in python
Expand Down Expand Up @@ -210,7 +210,7 @@ def compute(self, gt_pos, pd_rank, **kwargs):
Mean Reciprocal Rank score.

"""
matched_items = np.nonzero(np.in1d(pd_rank, gt_pos))[0]
matched_items = np.nonzero(np.isin(pd_rank, gt_pos))[0]

if len(matched_items) == 0:
raise ValueError(
Expand Down Expand Up @@ -267,7 +267,7 @@ def compute(self, gt_pos, pd_rank, **kwargs):
else:
truncated_pd_rank = pd_rank

tp = np.sum(np.in1d(truncated_pd_rank, gt_pos))
tp = np.sum(np.isin(truncated_pd_rank, gt_pos))
tp_fn = len(gt_pos)
tp_fp = self.k if self.k > 0 else len(truncated_pd_rank)

Expand Down Expand Up @@ -470,11 +470,11 @@ def compute(self, item_indices, pd_scores, gt_pos, gt_neg=None, **kwargs):

"""

gt_pos_mask = np.in1d(item_indices, gt_pos)
gt_pos_mask = np.isin(item_indices, gt_pos)
gt_neg_mask = (
np.logical_not(gt_pos_mask)
if gt_neg is None
else np.in1d(item_indices, gt_neg)
else np.isin(item_indices, gt_neg)
)

pos_scores = pd_scores[gt_pos_mask]
Expand Down Expand Up @@ -519,7 +519,7 @@ def compute(self, item_indices, pd_scores, gt_pos, **kwargs):
AP score.

"""
relevant = np.in1d(item_indices, gt_pos)
relevant = np.isin(item_indices, gt_pos)
rank = rankdata(-pd_scores, "max")[relevant]
L = rankdata(-pd_scores[relevant], "max")
ans = (L / rank).mean()
Expand Down
2 changes: 1 addition & 1 deletion cornac/models/beacon/recom_beacon.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ def _remove_diag(self, adj_matrix):

def _normalize(self, adj_matrix: csr_matrix):
"""Symmetrically normalize adjacency matrix."""
row_sum = adj_matrix.sum(1).A.squeeze()
row_sum = adj_matrix.sum(1).toarray().squeeze()
d_inv_sqrt = np.power(
row_sum,
-0.5,
Expand Down
11 changes: 5 additions & 6 deletions cornac/models/bivaecf/bivae.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import torch.nn as nn
from tqdm.auto import trange


EPS = 1e-10

ACT = {
Expand Down Expand Up @@ -136,7 +135,7 @@ def loss(self, x, x_, mu, mu_prior, std, kl_beta):
# Likelihood
ll_choices = {
"bern": x * torch.log(x_ + EPS) + (1 - x) * torch.log(1 - x_ + EPS),
"gaus": -(x - x_) ** 2,
"gaus": -((x - x_) ** 2),
"pois": x * torch.log(x_ + EPS) - x_,
}

Expand Down Expand Up @@ -198,7 +197,7 @@ def learn(
i_count = 0
for i_ids in train_set.item_iter(batch_size, shuffle=False):
i_batch = tx[i_ids, :]
i_batch = i_batch.A
i_batch = i_batch.toarray()
i_batch = torch.tensor(i_batch, dtype=dtype, device=device)

# Reconstructed batch
Expand Down Expand Up @@ -228,7 +227,7 @@ def learn(
u_count = 0
for u_ids in train_set.user_iter(batch_size, shuffle=False):
u_batch = x[u_ids, :]
u_batch = u_batch.A
u_batch = u_batch.toarray()
u_batch = torch.tensor(u_batch, dtype=dtype, device=device)

# Reconstructed batch
Expand Down Expand Up @@ -259,7 +258,7 @@ def learn(
# infer mu_beta
for i_ids in train_set.item_iter(batch_size, shuffle=False):
i_batch = tx[i_ids, :]
i_batch = i_batch.A
i_batch = i_batch.toarray()
i_batch = torch.tensor(i_batch, dtype=dtype, device=device)

beta, _, i_mu, _ = bivae(i_batch, user=False, theta=bivae.theta)
Expand All @@ -268,7 +267,7 @@ def learn(
# infer mu_theta
for u_ids in train_set.user_iter(batch_size, shuffle=False):
u_batch = x[u_ids, :]
u_batch = u_batch.A
u_batch = u_batch.toarray()
u_batch = torch.tensor(u_batch, dtype=dtype, device=device)

theta, _, u_mu, _ = bivae(u_batch, user=True, beta=bivae.beta)
Expand Down
10 changes: 6 additions & 4 deletions cornac/models/bpr/recom_bpr.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ from ...utils.common import scale
from ...utils.init_utils import zeros, uniform


DTYPE = np.float32

cdef extern from "recom_bpr.h" namespace "recom_bpr" nogil:
cdef int get_thread_num()

Expand Down Expand Up @@ -119,7 +121,7 @@ class BPR(Recommender, ANNMixin):
seed=None
):
super().__init__(name=name, trainable=trainable, verbose=verbose)
self.k = k
self.k = int(k)
self.max_iter = max_iter
self.learning_rate = learning_rate
self.lambda_reg = lambda_reg
Expand All @@ -144,10 +146,10 @@ class BPR(Recommender, ANNMixin):
n_users, n_items = self.total_users, self.total_items

if self.u_factors is None:
self.u_factors = (uniform((n_users, self.k), random_state=self.rng) - 0.5) / self.k
self.u_factors = (uniform((n_users, self.k), random_state=self.rng, dtype=DTYPE) - 0.5) / self.k
if self.i_factors is None:
self.i_factors = (uniform((n_items, self.k), random_state=self.rng) - 0.5) / self.k
self.i_biases = zeros(n_items) if self.i_biases is None or self.use_bias is False else self.i_biases
self.i_factors = (uniform((n_items, self.k), random_state=self.rng, dtype=DTYPE) - 0.5) / self.k
self.i_biases = zeros(n_items, dtype=DTYPE) if self.i_biases is None or self.use_bias is False else self.i_biases

def _prepare_data(self, train_set):
X = train_set.matrix # csr_matrix
Expand Down
2 changes: 1 addition & 1 deletion cornac/models/cdl/recom_cdl.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ def _fit_cdl(self, train_set):
feed_dict = {
model.text_mask: corruption_mask[batch_ids, :],
model.text_input: text_feature[batch_ids],
model.ratings: batch_R.A,
model.ratings: batch_R.toarray(),
model.C: batch_C,
model.item_ids: batch_ids,
}
Expand Down
2 changes: 1 addition & 1 deletion cornac/models/ctr/ctr.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def _df_simplex(gamma, v, lambda_v, x):


def _is_on_simplex(v, s):
if v.sum() < s + 1e-10 and np.alltrue(v > 0):
if v.sum() < s + 1e-10 and np.all(v > 0):
return True
return False

Expand Down
8 changes: 4 additions & 4 deletions cornac/models/cvae/recom_cvae.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@
import numpy as np
from tqdm.auto import trange

from ..recommender import Recommender
from ..recommender import ANNMixin, MEASURE_DOT
from ...exception import ScoreException
from ...utils import get_rng
from ...utils.init_utils import xavier_uniform
from ..recommender import MEASURE_DOT, Recommender


class CVAE(Recommender):
Expand Down Expand Up @@ -175,9 +174,10 @@ def _fit_cvae(self, train_set):
) # normalization

# VAE initialization
from .cvae import Model
import tensorflow.compat.v1 as tf

from .cvae import Model

tf.disable_eager_execution()

tf.set_random_seed(self.seed)
Expand Down Expand Up @@ -216,7 +216,7 @@ def _fit_cvae(self, train_set):

feed_dict = {
model.x: document[batch_ids],
model.ratings: batch_R.A,
model.ratings: batch_R.toarray(),
model.C: batch_C,
model.item_ids: batch_ids,
}
Expand Down
39 changes: 22 additions & 17 deletions cornac/models/cvaecf/cvaecf.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def loss(self, x, x_, mu_qz, logvar_qz, mu_qhx, logvar_qhx, mu_qhy, logvar_qhy,
ll_choices = {
"mult": x * torch.log(x_ + EPS),
"bern": x * torch.log(x_ + EPS) + (1 - x) * torch.log(1 - x_ + EPS),
"gaus": -(x - x_) ** 2,
"gaus": -((x - x_) ** 2),
"pois": x * torch.log(x_ + EPS) - x_,
}

Expand All @@ -160,29 +160,34 @@ def loss(self, x, x_, mu_qz, logvar_qz, mu_qhx, logvar_qhx, mu_qhy, logvar_qhy,
std_ph = torch.exp(0.5 * logvar_ph)

# KL(q(h|x)||p(h|x))
kld_hx = -0.5 * (1 + 2.0 * torch.log(std_qhx) - (mu_qhx - mu_ph).pow(2) - std_qhx.pow(
2)) # assuming std_ph is 1 for now
kld_hx = -0.5 * (
1 + 2.0 * torch.log(std_qhx) - (mu_qhx - mu_ph).pow(2) - std_qhx.pow(2)
) # assuming std_ph is 1 for now
kld_hx = torch.sum(kld_hx, dim=1)

# KL(q(h|x)||q(h|y))
kld_hy = -0.5 * (1 + 2.0 * torch.log(std_qhx) - 2.0 * torch.log(std_qhy) - (
(mu_qhx - mu_qhy).pow(2) + std_qhx.pow(2)) / std_qhy.pow(2)) # assuming std_ph is 1 for now
kld_hy = -0.5 * (
1
+ 2.0 * torch.log(std_qhx)
- 2.0 * torch.log(std_qhy)
- ((mu_qhx - mu_qhy).pow(2) + std_qhx.pow(2)) / std_qhy.pow(2)
) # assuming std_ph is 1 for now
kld_hy = torch.sum(kld_hy, dim=1)

return torch.mean(beta * kld_z + alpha_1 * kld_hx + alpha_2 * kld_hy - ll)


def learn(
cvae,
train_set,
n_epochs,
batch_size,
learn_rate,
beta,
alpha_1,
alpha_2,
verbose,
device=torch.device("cpu"),
cvae,
train_set,
n_epochs,
batch_size,
learn_rate,
beta,
alpha_1,
alpha_2,
verbose,
device=torch.device("cpu"),
):
optimizer = torch.optim.Adam(params=cvae.parameters(), lr=learn_rate)

Expand All @@ -197,11 +202,11 @@ def learn(
):
y_batch = y[u_ids, :]
y_batch.data = np.ones(len(y_batch.data)) # Binarize data
y_batch = y_batch.A
y_batch = y_batch.toarray()
y_batch = torch.tensor(y_batch, dtype=torch.float32, device=device)

x_batch = x[u_ids, :]
x_batch = x_batch.A
x_batch = x_batch.toarray()
x_batch = torch.tensor(x_batch, dtype=torch.float32, device=device)

# Reconstructed batch
Expand Down
8 changes: 4 additions & 4 deletions cornac/models/cvaecf/recom_cvaecf.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,25 +219,25 @@ def score(self, user_idx, item_idx=None):
if item_idx is None:
y_u = self.r_mat[user_idx].copy()
y_u.data = np.ones(len(y_u.data))
y_u = torch.tensor(y_u.A, dtype=torch.float32, device=self.device)
y_u = torch.tensor(y_u.toarray(), dtype=torch.float32, device=self.device)
z_u, _ = self.cvae.encode_qz(y_u)

x_u = self.u_adj_mat[user_idx].copy()
x_u.data = np.ones(len(x_u.data))
x_u = torch.tensor(x_u.A, dtype=torch.float32, device=self.device)
x_u = torch.tensor(x_u.toarray(), dtype=torch.float32, device=self.device)
h_u, _ = self.cvae.encode_qhx(x_u)

known_item_scores = self.cvae.decode(z_u, h_u).data.cpu().numpy().flatten()
return known_item_scores
else:
y_u = self.r_mat[user_idx].copy()
y_u.data = np.ones(len(y_u.data))
y_u = torch.tensor(y_u.A, dtype=torch.float32, device=self.device)
y_u = torch.tensor(y_u.toarray(), dtype=torch.float32, device=self.device)
z_u, _ = self.cvae.encode_qz(y_u)

x_u = self.u_adj_mat[user_idx].copy()
x_u.data = np.ones(len(x_u.data))
x_u = torch.tensor(x_u.A, dtype=torch.float32, device=self.device)
x_u = torch.tensor(x_u.toarray(), dtype=torch.float32, device=self.device)
h_u, _ = self.cvae.encode_qhx(x_u)

user_pred = (
Expand Down
6 changes: 3 additions & 3 deletions cornac/models/mf/backend_cpu.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ from tqdm.auto import trange
def fit_sgd(integral[:] rid, integral[:] cid, floating[:] val,
floating[:, :] U, floating[:, :] V,
floating[:] Bu, floating[:] Bi,
long num_users, long num_items,
integral num_users, integral num_items,
floating lr, floating reg, floating mu,
int max_iter, int num_threads,
bool use_bias, bool early_stop, bool verbose):
"""Fit the model parameters (U, V, Bu, Bi) with SGD"""
cdef:
long num_ratings = val.shape[0]
int num_factors = U.shape[1]
integral num_ratings = val.shape[0]
integral num_factors = U.shape[1]

floating loss = 0
floating last_loss = 0
Expand Down
Loading
Loading