Skip to content

Commit 24bbfd8

Browse files
authored
Merge branch 'master' into feature/logistic-offset
2 parents c971f0e + 070c028 commit 24bbfd8

29 files changed

Lines changed: 1376 additions & 77 deletions

File tree

.github/workflows/checking.yml

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
fail-fast: false
1111
matrix:
1212
toolchain:
13-
- 1.87.0
13+
- 1.88.0
1414
- stable
1515
- nightly
1616
os:
@@ -39,4 +39,25 @@ jobs:
3939
run: cargo check --workspace --all-targets
4040

4141
- name: Run cargo check (with serde)
42-
run: cargo check --workspace --all-targets --features "linfa-clustering/serde linfa-ica/serde linfa-kernel/serde linfa-reduction/serde linfa-svm/serde linfa-elasticnet/serde linfa-pls/serde linfa-trees/serde linfa-nn/serde linfa-linear/serde linfa-preprocessing/serde linfa-bayes/serde linfa-logistic/serde linfa-ftrl/serde"
42+
run: cargo check --workspace --all-targets --features "linfa-clustering/serde linfa-ica/serde linfa-kernel/serde linfa-reduction/serde linfa-svm/serde linfa-elasticnet/serde linfa-pls/serde linfa-trees/serde linfa-nn/serde linfa-linear/serde linfa-preprocessing/serde linfa-bayes/serde linfa-logistic/serde linfa-ftrl/serde linfa-ensemble/serde"
43+
44+
check-wasm-browser:
45+
name: check-wasm-browser
46+
runs-on: ubuntu-latest
47+
48+
steps:
49+
- name: Checkout sources
50+
uses: actions/checkout@master
51+
52+
- name: Install toolchain
53+
uses: dtolnay/rust-toolchain@master
54+
with:
55+
toolchain: stable
56+
targets: wasm32-unknown-unknown
57+
58+
- name: Run browser WASM checks
59+
run: |
60+
cargo check -p linfa --lib --target wasm32-unknown-unknown --features wasm-bindgen
61+
cargo check -p linfa-linear --lib --target wasm32-unknown-unknown --features wasm-bindgen
62+
cargo check -p linfa-logistic --lib --target wasm32-unknown-unknown --features wasm-bindgen
63+
cargo check -p linfa-ftrl --lib --target wasm32-unknown-unknown --features wasm-bindgen

.github/workflows/docs.yml

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,12 @@ name: Build website with Zola, build rust docs and publish to GH pages
1010
jobs:
1111
build:
1212
runs-on: ubuntu-latest
13-
if: github.ref != 'refs/heads/master' && github.repository == 'rust-ml/linfa'
13+
if: github.ref != 'refs/heads/master' || github.repository != 'rust-ml/linfa'
1414
steps:
15-
- name: 'Checkout'
15+
- name: Checkout
1616
uses: actions/checkout@master
1717

18-
19-
20-
- name: 'Build only'
18+
- name: Build only
2119
uses: shalzz/zola-deploy-action@v0.22.1
2220
env:
2321
BUILD_DIR: docs/website/
@@ -31,18 +29,16 @@ jobs:
3129

3230
build_and_deploy:
3331
runs-on: ubuntu-latest
34-
if: github.ref == 'refs/heads/master' || github.repository != 'rust-ml/linfa'
32+
if: github.ref == 'refs/heads/master' && github.repository == 'rust-ml/linfa'
3533
steps:
36-
- name: 'Checkout'
34+
- name: Checkout
3735
uses: actions/checkout@master
3836

3937
- name: Install Rust toolchain
4038
uses: dtolnay/rust-toolchain@stable
4139
with:
4240
components: rustfmt, rust-src
4341

44-
45-
4642
- name: Build Documentation
4743
run: cargo doc --workspace --no-deps
4844
env:
@@ -51,7 +47,7 @@ jobs:
5147
- name: Copy Rust Documentation to Zola
5248
run: cp -R "target/doc/" "docs/website/static/rustdocs/"
5349

54-
- name: 'Build and deploy'
50+
- name: Build and deploy website
5551
uses: shalzz/zola-deploy-action@master
5652
env:
5753
PAGES_BRANCH: gh-pages

.github/workflows/testing.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
fail-fast: false
1111
matrix:
1212
toolchain:
13-
- 1.87.0
13+
- 1.88.0
1414
- stable
1515
os:
1616
- ubuntu-latest
@@ -37,7 +37,7 @@ jobs:
3737
fail-fast: false
3838
matrix:
3939
toolchain:
40-
- 1.87.0
40+
- 1.88.0
4141
- stable
4242
os:
4343
- ubuntu-latest

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,13 @@ intel-mkl-system = ["blas", "ndarray-linalg/intel-mkl-system"]
3434
blas = ["ndarray/blas"]
3535

3636
serde = ["serde_crate", "ndarray/serde"]
37+
wasm-bindgen = ["dep:getrandom"]
3738

3839
[dependencies]
3940
num-traits = "0.2"
4041
rand = { version = "0.8", features = ["small_rng"] }
4142
approx = "0.5"
43+
getrandom = { version = "0.2", optional = true, features = ["js"] }
4244

4345
ndarray = { version = "0.16", features = ["approx"] }
4446
ndarray-linalg = { version = "0.17", optional = true }
@@ -75,6 +77,7 @@ pprof = { version = "0.15", features = [
7577

7678
[workspace]
7779
members = ["algorithms/*", "datasets"]
80+
resolver = "2"
7881

7982
[profile.release]
8083
opt-level = 3

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ We believe that only a significant community effort can nurture, build, and sust
5353

5454
If this strikes a chord with you, please take a look at the [roadmap](https://github.com/rust-ml/linfa/issues/7) and get involved!
5555

56+
## Browser WASM
57+
58+
For browser-style WASM on `wasm32-unknown-unknown`, enable `linfa`'s `wasm-bindgen` feature.
59+
5660
## BLAS/Lapack backend
5761

5862
Some algorithm crates need to use an external library for linear algebra routines. By default, we use a pure-Rust implementation. However, you can also choose an external BLAS/LAPACK backend library instead, by enabling the `blas` feature and a feature corresponding to your BLAS backend. Currently you can choose between the following BLAS/LAPACK backends: `openblas`, `netblas` or `intel-mkl`.

algorithms/linfa-bayes/src/multinomial_nb.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,6 @@ where
7474
.entry(class.clone())
7575
.or_insert_with(ClassHistogram::default)
7676
.update_with_smoothing(xclass.view(), self.alpha(), false);
77-
78-
dbg!(&model.class_info.get(&class));
7977
}
8078

8179
// update priors

algorithms/linfa-clustering/benches/k_means.rs

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use criterion::{
55
use linfa::benchmarks::config;
66
use linfa::prelude::*;
77
use linfa::DatasetBase;
8-
use linfa_clustering::{IncrKMeansError, KMeans, KMeansInit};
8+
use linfa_clustering::{IncrKMeansError, KMeans, KMeansAlgorithm, KMeansInit};
99
use linfa_datasets::generate;
1010
use ndarray::Array2;
1111
use ndarray_rand::RandomExt;
@@ -36,9 +36,10 @@ impl Drop for Stats {
3636
fn k_means_bench(c: &mut Criterion) {
3737
let mut rng = Xoshiro256Plus::seed_from_u64(40);
3838
let cluster_sizes = [(100, 4), (400, 10), (3000, 10)];
39+
let algorithms = [KMeansAlgorithm::Lloyd, KMeansAlgorithm::Hamerly];
3940
let n_features = 3;
4041

41-
let mut benchmark = c.benchmark_group("naive_k_means");
42+
let mut benchmark = c.benchmark_group("k_means");
4243
config::set_default_benchmark_configs(&mut benchmark);
4344
benchmark.plot_config(PlotConfiguration::default().summary_scale(AxisScale::Logarithmic));
4445

@@ -47,22 +48,29 @@ fn k_means_bench(c: &mut Criterion) {
4748
let centroids =
4849
Array2::random_using((n_clusters, n_features), Uniform::new(-30., 30.), rng);
4950
let dataset = DatasetBase::from(generate::blobs(cluster_size, &centroids, rng));
50-
let mut stats = Stats::default();
51+
for &algorithm in &algorithms {
52+
let mut stats = Stats::default();
5153

52-
benchmark.bench_function(
53-
BenchmarkId::new("naive_k_means", format!("{n_clusters}x{cluster_size}")),
54-
|bencher| {
55-
bencher.iter(|| {
56-
let m = KMeans::params_with_rng(black_box(n_clusters), black_box(rng.clone()))
57-
.init_method(KMeansInit::KMeansPlusPlus)
58-
.max_n_iterations(black_box(1000))
59-
.tolerance(black_box(1e-3))
60-
.fit(&dataset)
61-
.unwrap();
62-
stats.add(m.inertia());
63-
});
64-
},
65-
);
54+
benchmark.bench_function(
55+
BenchmarkId::new(
56+
"k_means",
57+
format!("{algorithm:?}:{n_clusters}x{cluster_size}"),
58+
),
59+
|bencher| {
60+
bencher.iter(|| {
61+
let m =
62+
KMeans::params_with_rng(black_box(n_clusters), black_box(rng.clone()))
63+
.init_method(KMeansInit::KMeansPlusPlus)
64+
.algorithm(algorithm)
65+
.max_n_iterations(black_box(1000))
66+
.tolerance(black_box(1e-3))
67+
.fit(&dataset)
68+
.unwrap();
69+
stats.add(m.inertia());
70+
});
71+
},
72+
);
73+
}
6674
}
6775

6876
benchmark.finish();

algorithms/linfa-clustering/src/dbscan/algorithm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ impl<F: Float, D: Data<Elem = F>, DF: Distance<F>, N: NearestNeighbour>
131131
continue;
132132
}
133133
neighbors.iter().for_each(|&n| search_found[n] = true);
134-
search_queue.extend(neighbors.into_iter());
134+
search_queue.extend(neighbors);
135135

136136
// Now go over the neighbours adding them to the cluster
137137
cluster_memberships[i] = Some(current_cluster_id);

algorithms/linfa-clustering/src/gaussian_mixture/algorithm.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -341,10 +341,11 @@ impl<F: Float> GaussianMixtureModel<F> {
341341
observations: &ArrayBase<D, Ix2>,
342342
) -> (Array1<F>, Array2<F>) {
343343
let weighted_log_prob = self.estimate_weighted_log_prob(observations);
344-
let log_prob_norm = weighted_log_prob
345-
.mapv(|x| x.exp())
346-
.sum_axis(Axis(1))
347-
.mapv(|x| x.ln());
344+
// Log-sum-exp trick to avoid overflow: ln(Σ exp(xᵢ)) = max + ln(Σ exp(xᵢ - max))
345+
let log_max = weighted_log_prob
346+
.map_axis(Axis(1), |row| row.fold(F::neg_infinity(), |a, &b| a.max(b)));
347+
let shifted = &weighted_log_prob - &log_max.clone().insert_axis(Axis(1));
348+
let log_prob_norm = shifted.mapv(|x| x.exp()).sum_axis(Axis(1)).mapv(|x| x.ln()) + &log_max;
348349
let log_resp = weighted_log_prob - log_prob_norm.to_owned().insert_axis(Axis(1));
349350
(log_prob_norm, log_resp)
350351
}

0 commit comments

Comments
 (0)