Remove some allocations (#262)

* Remove some allocations

* Remove some more allocations
This commit is contained in:
Ruben De Smet
2023-04-26 15:46:26 +02:00
committed by GitHub
parent 8939ed93b9
commit 545ed6ce2b
3 changed files with 82 additions and 73 deletions
+20
View File
@@ -15,6 +15,25 @@ pub struct VecView<'a, T: Debug + Display + Copy + Sized> {
ptr: &'a [T], ptr: &'a [T],
} }
impl<T: Debug + Display + Copy + Sized> Array<T, usize> for &[T] {
fn get(&self, i: usize) -> &T {
&self[i]
}
fn shape(&self) -> usize {
self.len()
}
fn is_empty(&self) -> bool {
self.len() > 0
}
fn iterator<'b>(&'b self, axis: u8) -> Box<dyn Iterator<Item = &'b T> + 'b> {
assert!(axis == 0, "For one dimensional array `axis` should == 0");
Box::new(self.iter())
}
}
impl<T: Debug + Display + Copy + Sized> Array<T, usize> for Vec<T> { impl<T: Debug + Display + Copy + Sized> Array<T, usize> for Vec<T> {
fn get(&self, i: usize) -> &T { fn get(&self, i: usize) -> &T {
&self[i] &self[i]
@@ -46,6 +65,7 @@ impl<T: Debug + Display + Copy + Sized> MutArray<T, usize> for Vec<T> {
} }
impl<T: Debug + Display + Copy + Sized> ArrayView1<T> for Vec<T> {} impl<T: Debug + Display + Copy + Sized> ArrayView1<T> for Vec<T> {}
impl<T: Debug + Display + Copy + Sized> ArrayView1<T> for &[T] {}
impl<T: Debug + Display + Copy + Sized> MutArrayView1<T> for Vec<T> {} impl<T: Debug + Display + Copy + Sized> MutArrayView1<T> for Vec<T> {}
+55 -64
View File
@@ -322,19 +322,26 @@ impl<'a, TX: Number + RealNumber, TY: Number + Ord, X: Array2<TX> + 'a, Y: Array
let (n, _) = x.shape(); let (n, _) = x.shape();
let mut y_hat: Vec<TX> = Array1::zeros(n); let mut y_hat: Vec<TX> = Array1::zeros(n);
let mut row = Vec::with_capacity(n);
for i in 0..n { for i in 0..n {
let row_pred: TX = row.clear();
self.predict_for_row(Vec::from_iterator(x.get_row(i).iterator(0).copied(), n)); row.extend(x.get_row(i).iterator(0).copied());
let row_pred: TX = self.predict_for_row(&row);
y_hat.set(i, row_pred); y_hat.set(i, row_pred);
} }
Ok(y_hat) Ok(y_hat)
} }
fn predict_for_row(&self, x: Vec<TX>) -> TX { fn predict_for_row(&self, x: &[TX]) -> TX {
let mut f = self.b.unwrap(); let mut f = self.b.unwrap();
let xi: Vec<_> = x.iter().map(|e| e.to_f64().unwrap()).collect();
for i in 0..self.instances.as_ref().unwrap().len() { for i in 0..self.instances.as_ref().unwrap().len() {
let xj: Vec<_> = self.instances.as_ref().unwrap()[i]
.iter()
.map(|e| e.to_f64().unwrap())
.collect();
f += self.w.as_ref().unwrap()[i] f += self.w.as_ref().unwrap()[i]
* TX::from( * TX::from(
self.parameters self.parameters
@@ -343,13 +350,7 @@ impl<'a, TX: Number + RealNumber, TY: Number + Ord, X: Array2<TX> + 'a, Y: Array
.kernel .kernel
.as_ref() .as_ref()
.unwrap() .unwrap()
.apply( .apply(&xi, &xj)
&x.iter().map(|e| e.to_f64().unwrap()).collect(),
&self.instances.as_ref().unwrap()[i]
.iter()
.map(|e| e.to_f64().unwrap())
.collect(),
)
.unwrap(), .unwrap(),
) )
.unwrap(); .unwrap();
@@ -472,14 +473,12 @@ impl<'a, TX: Number + RealNumber, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>
let tol = self.parameters.tol; let tol = self.parameters.tol;
let good_enough = TX::from_i32(1000).unwrap(); let good_enough = TX::from_i32(1000).unwrap();
let mut x = Vec::with_capacity(n);
for _ in 0..self.parameters.epoch { for _ in 0..self.parameters.epoch {
for i in self.permutate(n) { for i in self.permutate(n) {
self.process( x.clear();
i, x.extend(self.x.get_row(i).iterator(0).take(n).copied());
Vec::from_iterator(self.x.get_row(i).iterator(0).copied(), n), self.process(i, &x, *self.y.get(i), &mut cache);
*self.y.get(i),
&mut cache,
);
loop { loop {
self.reprocess(tol, &mut cache); self.reprocess(tol, &mut cache);
self.find_min_max_gradient(); self.find_min_max_gradient();
@@ -511,24 +510,17 @@ impl<'a, TX: Number + RealNumber, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>
let mut cp = 0; let mut cp = 0;
let mut cn = 0; let mut cn = 0;
let mut x = Vec::with_capacity(n);
for i in self.permutate(n) { for i in self.permutate(n) {
x.clear();
x.extend(self.x.get_row(i).iterator(0).take(n).copied());
if *self.y.get(i) == TY::one() && cp < few { if *self.y.get(i) == TY::one() && cp < few {
if self.process( if self.process(i, &x, *self.y.get(i), cache) {
i,
Vec::from_iterator(self.x.get_row(i).iterator(0).copied(), n),
*self.y.get(i),
cache,
) {
cp += 1; cp += 1;
} }
} else if *self.y.get(i) == TY::from(-1).unwrap() } else if *self.y.get(i) == TY::from(-1).unwrap()
&& cn < few && cn < few
&& self.process( && self.process(i, &x, *self.y.get(i), cache)
i,
Vec::from_iterator(self.x.get_row(i).iterator(0).copied(), n),
*self.y.get(i),
cache,
)
{ {
cn += 1; cn += 1;
} }
@@ -539,7 +531,7 @@ impl<'a, TX: Number + RealNumber, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>
} }
} }
fn process(&mut self, i: usize, x: Vec<TX>, y: TY, cache: &mut Cache<TX, TY, X, Y>) -> bool { fn process(&mut self, i: usize, x: &[TX], y: TY, cache: &mut Cache<TX, TY, X, Y>) -> bool {
for j in 0..self.sv.len() { for j in 0..self.sv.len() {
if self.sv[j].index == i { if self.sv[j].index == i {
return true; return true;
@@ -551,15 +543,14 @@ impl<'a, TX: Number + RealNumber, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>
let mut cache_values: Vec<((usize, usize), TX)> = Vec::new(); let mut cache_values: Vec<((usize, usize), TX)> = Vec::new();
for v in self.sv.iter() { for v in self.sv.iter() {
let xi: Vec<_> = v.x.iter().map(|e| e.to_f64().unwrap()).collect();
let xj: Vec<_> = x.iter().map(|e| e.to_f64().unwrap()).collect();
let k = self let k = self
.parameters .parameters
.kernel .kernel
.as_ref() .as_ref()
.unwrap() .unwrap()
.apply( .apply(&xi, &xj)
&v.x.iter().map(|e| e.to_f64().unwrap()).collect(),
&x.iter().map(|e| e.to_f64().unwrap()).collect(),
)
.unwrap(); .unwrap();
cache_values.push(((i, v.index), TX::from(k).unwrap())); cache_values.push(((i, v.index), TX::from(k).unwrap()));
g -= v.alpha * k; g -= v.alpha * k;
@@ -578,7 +569,7 @@ impl<'a, TX: Number + RealNumber, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>
cache.insert(v.0, v.1.to_f64().unwrap()); cache.insert(v.0, v.1.to_f64().unwrap());
} }
let x_f64 = x.iter().map(|e| e.to_f64().unwrap()).collect(); let x_f64: Vec<_> = x.iter().map(|e| e.to_f64().unwrap()).collect();
let k_v = self let k_v = self
.parameters .parameters
.kernel .kernel
@@ -701,8 +692,10 @@ impl<'a, TX: Number + RealNumber, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>
let km = sv1.k; let km = sv1.k;
let gm = sv1.grad; let gm = sv1.grad;
let mut best = 0f64; let mut best = 0f64;
let xi: Vec<_> = sv1.x.iter().map(|e| e.to_f64().unwrap()).collect();
for i in 0..self.sv.len() { for i in 0..self.sv.len() {
let v = &self.sv[i]; let v = &self.sv[i];
let xj: Vec<_> = v.x.iter().map(|e| e.to_f64().unwrap()).collect();
let z = v.grad - gm; let z = v.grad - gm;
let k = cache.get( let k = cache.get(
sv1, sv1,
@@ -711,10 +704,7 @@ impl<'a, TX: Number + RealNumber, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>
.kernel .kernel
.as_ref() .as_ref()
.unwrap() .unwrap()
.apply( .apply(&xi, &xj)
&sv1.x.iter().map(|e| e.to_f64().unwrap()).collect(),
&v.x.iter().map(|e| e.to_f64().unwrap()).collect(),
)
.unwrap(), .unwrap(),
); );
let mut curv = km + v.k - 2f64 * k; let mut curv = km + v.k - 2f64 * k;
@@ -732,6 +722,12 @@ impl<'a, TX: Number + RealNumber, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>
} }
} }
let xi: Vec<_> = self.sv[idx_1]
.x
.iter()
.map(|e| e.to_f64().unwrap())
.collect::<Vec<_>>();
idx_2.map(|idx_2| { idx_2.map(|idx_2| {
( (
idx_1, idx_1,
@@ -742,16 +738,12 @@ impl<'a, TX: Number + RealNumber, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>
.as_ref() .as_ref()
.unwrap() .unwrap()
.apply( .apply(
&self.sv[idx_1] &xi,
.x
.iter()
.map(|e| e.to_f64().unwrap())
.collect(),
&self.sv[idx_2] &self.sv[idx_2]
.x .x
.iter() .iter()
.map(|e| e.to_f64().unwrap()) .map(|e| e.to_f64().unwrap())
.collect(), .collect::<Vec<_>>(),
) )
.unwrap() .unwrap()
}), }),
@@ -765,8 +757,11 @@ impl<'a, TX: Number + RealNumber, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>
let km = sv2.k; let km = sv2.k;
let gm = sv2.grad; let gm = sv2.grad;
let mut best = 0f64; let mut best = 0f64;
let xi: Vec<_> = sv2.x.iter().map(|e| e.to_f64().unwrap()).collect();
for i in 0..self.sv.len() { for i in 0..self.sv.len() {
let v = &self.sv[i]; let v = &self.sv[i];
let xj: Vec<_> = v.x.iter().map(|e| e.to_f64().unwrap()).collect();
let z = gm - v.grad; let z = gm - v.grad;
let k = cache.get( let k = cache.get(
sv2, sv2,
@@ -775,10 +770,7 @@ impl<'a, TX: Number + RealNumber, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>
.kernel .kernel
.as_ref() .as_ref()
.unwrap() .unwrap()
.apply( .apply(&xi, &xj)
&sv2.x.iter().map(|e| e.to_f64().unwrap()).collect(),
&v.x.iter().map(|e| e.to_f64().unwrap()).collect(),
)
.unwrap(), .unwrap(),
); );
let mut curv = km + v.k - 2f64 * k; let mut curv = km + v.k - 2f64 * k;
@@ -797,6 +789,12 @@ impl<'a, TX: Number + RealNumber, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>
} }
} }
let xj: Vec<_> = self.sv[idx_2]
.x
.iter()
.map(|e| e.to_f64().unwrap())
.collect();
idx_1.map(|idx_1| { idx_1.map(|idx_1| {
( (
idx_1, idx_1,
@@ -811,12 +809,8 @@ impl<'a, TX: Number + RealNumber, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>
.x .x
.iter() .iter()
.map(|e| e.to_f64().unwrap()) .map(|e| e.to_f64().unwrap())
.collect(), .collect::<Vec<_>>(),
&self.sv[idx_2] &xj,
.x
.iter()
.map(|e| e.to_f64().unwrap())
.collect(),
) )
.unwrap() .unwrap()
}), }),
@@ -835,12 +829,12 @@ impl<'a, TX: Number + RealNumber, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>
.x .x
.iter() .iter()
.map(|e| e.to_f64().unwrap()) .map(|e| e.to_f64().unwrap())
.collect(), .collect::<Vec<_>>(),
&self.sv[idx_2] &self.sv[idx_2]
.x .x
.iter() .iter()
.map(|e| e.to_f64().unwrap()) .map(|e| e.to_f64().unwrap())
.collect(), .collect::<Vec<_>>(),
) )
.unwrap(), .unwrap(),
)), )),
@@ -895,7 +889,10 @@ impl<'a, TX: Number + RealNumber, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>
self.sv[v1].alpha -= step.to_f64().unwrap(); self.sv[v1].alpha -= step.to_f64().unwrap();
self.sv[v2].alpha += step.to_f64().unwrap(); self.sv[v2].alpha += step.to_f64().unwrap();
let xi_v1: Vec<_> = self.sv[v1].x.iter().map(|e| e.to_f64().unwrap()).collect();
let xi_v2: Vec<_> = self.sv[v2].x.iter().map(|e| e.to_f64().unwrap()).collect();
for i in 0..self.sv.len() { for i in 0..self.sv.len() {
let xj: Vec<_> = self.sv[i].x.iter().map(|e| e.to_f64().unwrap()).collect();
let k2 = cache.get( let k2 = cache.get(
&self.sv[v2], &self.sv[v2],
&self.sv[i], &self.sv[i],
@@ -903,10 +900,7 @@ impl<'a, TX: Number + RealNumber, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>
.kernel .kernel
.as_ref() .as_ref()
.unwrap() .unwrap()
.apply( .apply(&xi_v2, &xj)
&self.sv[v2].x.iter().map(|e| e.to_f64().unwrap()).collect(),
&self.sv[i].x.iter().map(|e| e.to_f64().unwrap()).collect(),
)
.unwrap(), .unwrap(),
); );
let k1 = cache.get( let k1 = cache.get(
@@ -916,10 +910,7 @@ impl<'a, TX: Number + RealNumber, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>
.kernel .kernel
.as_ref() .as_ref()
.unwrap() .unwrap()
.apply( .apply(&xi_v1, &xj)
&self.sv[v1].x.iter().map(|e| e.to_f64().unwrap()).collect(),
&self.sv[i].x.iter().map(|e| e.to_f64().unwrap()).collect(),
)
.unwrap(), .unwrap(),
); );
self.sv[i].grad -= step.to_f64().unwrap() * (k2 - k1); self.sv[i].grad -= step.to_f64().unwrap() * (k2 - k1);
+7 -9
View File
@@ -248,19 +248,20 @@ impl<'a, T: Number + FloatNumber + PartialOrd, X: Array2<T>, Y: Array1<T>> SVR<'
let mut y_hat: Vec<T> = Vec::<T>::zeros(n); let mut y_hat: Vec<T> = Vec::<T>::zeros(n);
let mut x_i = Vec::with_capacity(n);
for i in 0..n { for i in 0..n {
y_hat.set( x_i.clear();
i, x_i.extend(x.get_row(i).iterator(0).copied());
self.predict_for_row(Vec::from_iterator(x.get_row(i).iterator(0).copied(), n)), y_hat.set(i, self.predict_for_row(&x_i));
);
} }
Ok(y_hat) Ok(y_hat)
} }
pub(crate) fn predict_for_row(&self, x: Vec<T>) -> T { pub(crate) fn predict_for_row(&self, x: &[T]) -> T {
let mut f = self.b; let mut f = self.b;
let xi: Vec<_> = x.iter().map(|e| e.to_f64().unwrap()).collect();
for i in 0..self.instances.as_ref().unwrap().len() { for i in 0..self.instances.as_ref().unwrap().len() {
f += self.w.as_ref().unwrap()[i] f += self.w.as_ref().unwrap()[i]
* T::from( * T::from(
@@ -270,10 +271,7 @@ impl<'a, T: Number + FloatNumber + PartialOrd, X: Array2<T>, Y: Array1<T>> SVR<'
.kernel .kernel
.as_ref() .as_ref()
.unwrap() .unwrap()
.apply( .apply(&xi, &self.instances.as_ref().unwrap()[i])
&x.iter().map(|e| e.to_f64().unwrap()).collect(),
&self.instances.as_ref().unwrap()[i],
)
.unwrap(), .unwrap(),
) )
.unwrap() .unwrap()