Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support of Python 3.12 #2098

Open
wants to merge 35 commits into
base: staging
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
b3abc8a
Enabling python 3.12 #2097
miguelgfierro May 15, 2024
809a1d3
Enabling python 3.12 #2097
miguelgfierro May 15, 2024
496b22f
Cornac>2
miguelgfierro May 15, 2024
2b9ddcc
setuptools >= 67
daviddavo May 15, 2024
69f2d36
Temporary use lightfm patch
daviddavo May 21, 2024
d497fc0
Merge branch 'staging' into python312
daviddavo Jul 1, 2024
c223e3d
Updated tensorflow
daviddavo Jul 3, 2024
75b884b
Update pymanopt
daviddavo Jul 3, 2024
0c28cf1
Installing pymanopt from git
daviddavo Jul 3, 2024
ad0c79d
Add setuptools (for python 3.12)
daviddavo Jul 3, 2024
cdf9515
Use numpy 1.26 on python 3.12
daviddavo Jul 3, 2024
a442edb
Update python version used to launch tests
daviddavo Jul 3, 2024
dff4b0c
Added numpy 1.26 setup requires on python 3.12
daviddavo Jul 5, 2024
2af59a1
[test ci] Force numpy 1.26
daviddavo Jul 5, 2024
100a6f5
Merge remote-tracking branch 'origin/staging' into python312
daviddavo Jul 18, 2024
a7208e8
Updated conda in azureml tests
daviddavo Jul 18, 2024
94ccdeb
Update pymanopt usage
daviddavo Jul 18, 2024
cca9669
Use numpy 1.26.4 in Python 3.12
daviddavo Jul 18, 2024
12924d6
Merge branch 'staging' into python312
daviddavo Jul 31, 2024
5f02f45
Updated pymanopt in aml_utils
daviddavo Jul 31, 2024
18ff5b7
Relaxed numpy requirements
daviddavo Jul 31, 2024
913abde
Removed Python 3.8 tests
daviddavo Jul 31, 2024
3b0d1a1
Bumped required python version
daviddavo Jul 31, 2024
108c8a0
Upgraded azure python version to python 3.12
daviddavo Jul 31, 2024
2e2c99a
Updated tf-keras for new python versions
daviddavo Aug 1, 2024
8f0265a
Revert "Removed Python 3.8 tests"
daviddavo Aug 1, 2024
7705b5d
Revert "Bumped required python version"
daviddavo Aug 2, 2024
4d4779a
#2138 Using requirements-external to specify git deps
daviddavo Aug 2, 2024
1cbe6b6
Fixed conda env file
daviddavo Aug 2, 2024
734e4ac
Changed requirements-external order
daviddavo Aug 2, 2024
7b01eff
Install requirements-external.txt from GitHub
daviddavo Aug 2, 2024
8515dbf
Relaxed scipy version for Pyton 3.8
daviddavo Aug 2, 2024
4a544b2
Merge branch 'staging' into python312
daviddavo Aug 12, 2024
450bf17
Merge in staging
SimonYansenZhao Nov 12, 2024
9e00c0c
Solve merge conflict
miguelgfierro Nov 14, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/azureml-cpu-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
strategy:
max-parallel: 50 # Usage limits: https://docs.github.com/en/actions/learn-github-actions/usage-limits-billing-and-administration
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
test-group: ${{ fromJSON(needs.get-test-groups.outputs.test_groups) }}
steps:
- name: Check out repository code
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/azureml-gpu-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
strategy:
max-parallel: 50 # Usage limits: https://docs.github.com/en/actions/learn-github-actions/usage-limits-billing-and-administration
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
test-group: ${{ fromJSON(needs.get-test-groups.outputs.test_groups) }}
steps:
- name: Check out repository code
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/azureml-release-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
- name: Setup python
uses: actions/setup-python@v5
with:
python-version: "3.10"
python-version: "3.12"
- name: Install wheel package
run: pip install wheel
- name: Create wheel from setup.py
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/azureml-spark-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ jobs:
strategy:
max-parallel: 50 # Usage limits: https://docs.github.com/en/actions/learn-github-actions/usage-limits-billing-and-administration
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
test-group: ${{ fromJSON(needs.get-test-groups.outputs.test_groups) }}
steps:
- name: Check out repository code
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/azureml-unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ jobs:
strategy:
max-parallel: 50 # Usage limits: https://docs.github.com/en/actions/learn-github-actions/usage-limits-billing-and-administration
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
test-group: ${{ fromJSON(needs.get-test-groups.outputs.test_groups) }}
steps:
- name: Check out repository code
Expand Down
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[build-system]
requires = [
"setuptools>=52",
"setuptools>=67",
"wheel>=0.36",
"numpy>=1.15,<2",
]
dependencies = [
"setuptools>=52",
"setuptools>=67",
"wheel>=0.36",
"numpy>=1.15,<2",
]
Expand All @@ -17,4 +17,4 @@ markers = [
"gpu: tests running on GPU",
"notebooks: tests for notebooks",
"spark: tests that requires Spark",
]
]
8 changes: 5 additions & 3 deletions recommenders/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,11 @@ We are currently evaluating inclusion of the following dependencies:

## Other dependencies

Some dependencies are not available via the recommenders PyPI package, but can be installed in the following ways:
- pymanopt: this dependency is required for the RLRMC and GeoIMC algorithms; a version of this code compatible with TensorFlow 2 can be
installed with `pip install "pymanopt@https://github.com/pymanopt/pymanopt/archive/fb36a272cdeecb21992cfd9271eb82baafeb316d.zip"`.
Some dependencies are not available via the recommenders PyPI package, but can be installed with the [requirements-external.txt](./requirements-external.txt) file:

```
pip install -r requirements-external.txt
```

## NNI dependencies

Expand Down
2 changes: 2 additions & 0 deletions recommenders/models/deeprec/models/dkn.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Copyright (c) Recommenders contributors.
# Licensed under the MIT License.
import os
os.environ['TF_USE_LEGACY_KERAS'] = "1"

import numpy as np
import tensorflow as tf
Expand Down
58 changes: 30 additions & 28 deletions recommenders/models/geoimc/geoimc_algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
from numba import njit, prange
from pymanopt import Problem
from pymanopt.manifolds import Stiefel, Product, SymmetricPositiveDefinite
from pymanopt.solvers import ConjugateGradient
from pymanopt.solvers.linesearch import LineSearchBackTracking
from pymanopt.autodiff.backends import numpy as backend_decorator
from pymanopt.optimizers import ConjugateGradient
from pymanopt.optimizers.line_search import BackTrackingLineSearcher


class IMCProblem(object):
Expand Down Expand Up @@ -68,23 +69,19 @@ def _computeLoss_csrmatrix(a, b, cd, indices, indptr, residual_global):
residual_global[j] = num - cd[j]
return residual_global

def _cost(self, params, residual_global):
def _cost(self, U, S, VT, residual_global):
"""Compute the cost of GeoIMC optimization problem

Args:
params (Iterator): An iterator containing the manifold point at which
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to update the docstring too

the cost needs to be evaluated.
residual_global (csr_matrix): Residual matrix.
"""
U = params[0]
B = params[1]
V = params[2]

regularizer = 0.5 * self.lambda1 * np.sum(B**2)
regularizer = 0.5 * self.lambda1 * np.sum(S**2)

IMCProblem._computeLoss_csrmatrix(
self.X.dot(U.dot(B)),
V.T.dot(self.Z.T),
self.X.dot(U.dot(S)),
VT.T.dot(self.Z.T),
self.Y.data,
self.Y.indices,
self.Y.indptr,
Expand All @@ -94,37 +91,33 @@ def _cost(self, params, residual_global):

return cost

def _egrad(self, params, residual_global):
def _egrad(self, U, S, VT, residual_global):
"""Computes the euclidean gradient

Args:
params (Iterator): An iterator containing the manifold point at which
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please update docstring

the cost needs to be evaluated.
residual_global (csr_matrix): Residual matrix.
"""
U = params[0]
B = params[1]
V = params[2]

residual_global_csr = csr_matrix(
(residual_global, self.Y.indices, self.Y.indptr),
shape=self.shape,
)

gradU = (
np.dot(self.X.T, residual_global_csr.dot(self.Z.dot(V.dot(B.T))))
np.dot(self.X.T, residual_global_csr.dot(self.Z.dot(VT.dot(S.T))))
/ self.nSamples
)

gradB = (
np.dot((self.X.dot(U)).T, residual_global_csr.dot(self.Z.dot(V)))
np.dot((self.X.dot(U)).T, residual_global_csr.dot(self.Z.dot(VT)))
/ self.nSamples
+ self.lambda1 * B
+ self.lambda1 * S
)
gradB_sym = (gradB + gradB.T) / 2

gradV = (
np.dot((self.X.dot(U.dot(B))).T, residual_global_csr.dot(self.Z)).T
np.dot((self.X.dot(U.dot(S))).T, residual_global_csr.dot(self.Z)).T
/ self.nSamples
)

Expand Down Expand Up @@ -154,20 +147,29 @@ def _optimize(self, max_opt_time, max_opt_iter, verbosity):
residual_global = np.zeros(self.Y.data.shape)

solver = ConjugateGradient(
maxtime=max_opt_time,
maxiter=max_opt_iter,
linesearch=LineSearchBackTracking(),
max_time=max_opt_time,
max_iterations=max_opt_iter,
line_searcher=BackTrackingLineSearcher(),
verbosity=verbosity,
)

@backend_decorator(self.manifold)
def _cost(u, s, vt):
return self._cost(u, s, vt, residual_global)

@backend_decorator(self.manifold)
def _egrad(u, s, vt):
return self._egrad(u, s, vt, residual_global)

prb = Problem(
manifold=self.manifold,
cost=lambda x: self._cost(x, residual_global),
egrad=lambda z: self._egrad(z, residual_global),
verbosity=verbosity,
cost=_cost,
euclidean_gradient=_egrad,
)
solution = solver.solve(prb, x=self.W)
self.W = [solution[0], solution[1], solution[2]]
solution = solver.run(prb, initial_point=self.W)
self.W = [solution.point[0], solution.point[1], solution.point[2]]

return self._cost(self.W, residual_global)
return solution.cost

def reset(self):
"""Reset the model."""
Expand Down
5 changes: 5 additions & 0 deletions requirements-external.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# 2024/02/29: pymanopt bumped to python 3.8
pymanopt @git+https://github.com/pymanopt/pymanopt@e13cecaec3089c790cc93174840b2f557d179b3f ; python_version<'3.12'

# Jun 2024: Fixes py312
pymanopt @git+https://github.com/pymanopt/pymanopt@1de3b6f47258820fdc072fceaeaa763b9fd263b0 ; python_version>='3.12'
16 changes: 12 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"locust>=2.12.2,<3", # requires jinja2
"memory-profiler>=0.61.0,<1",
"nltk>=3.8.1,<4", # requires tqdm
"numpy>=1.26.4;python_version>='3.12'", # https://stackoverflow.com/a/77364602/4505998
"notebook>=6.5.5,<8", # requires ipykernel, jinja2, jupyter, nbconvert, nbformat, packaging, requests
"numba>=0.57.0,<1",
"pandas>2.0.0,<3.0.0", # requires numpy
Expand All @@ -55,8 +56,12 @@
"numpy<1.25.0;python_version<='3.8'",
"nvidia-ml-py>=11.525.84",
"spacy<=3.7.5;python_version<='3.8'",
"tensorflow>=2.8.4,!=2.9.0.*,!=2.9.1,!=2.9.2,!=2.10.0.*,<2.16", # Fixed TF due to constant security problems and breaking changes #2073
"tensorflow>=2.8.4,!=2.9.0.*,!=2.9.1,!=2.9.2,!=2.10.0.*,<2.16; python_version<='3.8'", # Fixed TF due to constant security problems and breaking changes #2073
"tensorflow~=2.16; python_version>'3.8'", # Version needed for python 3.12
"tf-slim>=1.1.0", # No python_requires in its setup.py
# Use keras 2 instead of keras 3
"tf-keras~=2.15; python_version<='3.8'", # Not compatible with py3.12
"tf-keras~=2.16; python_version>'3.8'",
"torch>=2.0.1,<3",
],
"spark": [
Expand Down Expand Up @@ -86,8 +91,8 @@
]

# The following dependency can be installed as below, however PyPI does not allow direct URLs.
# Temporary fix for pymanopt, only this commit works with TF2
# "pymanopt@https://github.com/pymanopt/pymanopt/archive/fb36a272cdeecb21992cfd9271eb82baafeb316d.zip",
# Temporary fix for pymanopt, pypi version does not work with TF2
# pip install -r requirements-external.txt

setup(
name="recommenders",
Expand All @@ -114,6 +119,7 @@
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Operating System :: POSIX :: Linux",
],
extras_require=extras_require,
Expand All @@ -126,5 +132,7 @@
where=".",
exclude=["contrib", "docs", "examples", "scenarios", "tests", "tools"],
),
setup_requires=["numpy>=1.19"],
setup_requires=[
"numpy>=1.15",
],
)
8 changes: 4 additions & 4 deletions tests/unit/recommenders/models/test_geoimc.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
reduce_dims,
)
from pymanopt.manifolds import Stiefel, SymmetricPositiveDefinite
except:
except ImportError:
pass # skip if pymanopt not installed


Expand Down Expand Up @@ -141,9 +141,9 @@ def test_inferer_infer(dataPtr):
colFeatureDim = test_data.get_entity("col").shape[1]
rank = 2
W = [
Stiefel(rowFeatureDim, rank).rand(),
SymmetricPositiveDefinite(rank).rand(),
Stiefel(colFeatureDim, rank).rand(),
Stiefel(rowFeatureDim, rank).random_point(),
SymmetricPositiveDefinite(rank).random_point(),
Stiefel(colFeatureDim, rank).random_point(),
]

Inferer(method="dot").infer(test_data, W)
Expand Down
Loading