Move to separate repo
This commit is contained in:
98
rs/src/feed_forward.rs
Normal file
98
rs/src/feed_forward.rs
Normal file
@ -0,0 +1,98 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
extern crate blas_src;
|
||||
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
use std::time::Instant;
|
||||
|
||||
use csv;
|
||||
use glob::glob;
|
||||
use ndarray::{Array, Array1, Array2};
|
||||
|
||||
mod sigmoids; // different custom implementations of the sigmoid function
|
||||
use sigmoids::{sigmoid_ndarr_mapv_inplace as sigmoid};
|
||||
|
||||
|
||||
const DIR_DATA: &str = "data";
|
||||
|
||||
|
||||
fn csv_row_to_float_vec(row: &csv::StringRecord) -> Vec<f32> {
|
||||
return row.iter().map(
|
||||
|item| {item.parse::<f32>().expect("Not a float")}
|
||||
).collect();
|
||||
}
|
||||
|
||||
|
||||
fn csv_to_float_vec(file_path: &Path) -> (Vec<f32>, usize) {
|
||||
let mut output: Vec<f32> = Vec::new();
|
||||
let mut num_columns: usize = 0;
|
||||
let file = File::open(file_path).expect("Can't open file");
|
||||
let mut reader = csv::ReaderBuilder::new().has_headers(false).from_reader(file);
|
||||
for result in reader.records() {
|
||||
let row: Vec<f32> = csv_row_to_float_vec(&result.expect("No csv record"));
|
||||
if num_columns == 0 {
|
||||
num_columns = row.len();
|
||||
}
|
||||
output.extend(row);
|
||||
}
|
||||
return (output, num_columns);
|
||||
}
|
||||
|
||||
fn csv_to_array1(file_path: &Path) -> Array1<f32> {
|
||||
let (vec, _) = csv_to_float_vec(&file_path);
|
||||
return Array::from_shape_vec((vec.len(), ), vec).unwrap();
|
||||
}
|
||||
|
||||
fn csv_to_array2(file_path: &Path) -> Array2<f32> {
|
||||
let (vec, num_colums) = csv_to_float_vec(&file_path);
|
||||
return Array2::from_shape_vec((vec.len() / num_colums, num_colums), vec).unwrap();
|
||||
}
|
||||
|
||||
fn load_test_data() -> (Array1<f32>, Vec<(Array2<f32>, Array1<f32>)>) {
|
||||
let test_data_dir = Path::new(".").join(DIR_DATA);
|
||||
let inputs: Array1<f32> = csv_to_array1(&test_data_dir.join("inputs.csv"));
|
||||
let weights_glob = test_data_dir.join("weights*.csv");
|
||||
let biases_glob = test_data_dir.join("biases*.csv");
|
||||
let weights_iter = glob(weights_glob.to_str().unwrap()).unwrap().map(
|
||||
|path_result| {csv_to_array2(&path_result.unwrap())}
|
||||
);
|
||||
let biases_iter = glob(biases_glob.to_str().unwrap()).unwrap().map(
|
||||
|path_result| {csv_to_array1(&path_result.unwrap())}
|
||||
);
|
||||
return (inputs, weights_iter.zip(biases_iter).collect());
|
||||
}
|
||||
|
||||
|
||||
fn layer_func<F>(input_vector: &Array1<f32>, weight_matrix: &Array2<f32>,
|
||||
bias_vector: &Array1<f32>, activation: &F,
|
||||
virtual_vector: Option<&Array1<bool>>) -> Array1<f32>
|
||||
where F: Fn(Array1<f32>, Option<&Array1<bool>>) -> Array1<f32> {
|
||||
return activation(weight_matrix.dot(input_vector) + bias_vector, virtual_vector)
|
||||
}
|
||||
|
||||
|
||||
fn feed_forward<F>(x: &Array1<f32>, layers: &[(Array2<f32>, Array1<f32>)], activation: &F) -> Array1<f32>
|
||||
where F: Fn(Array1<f32>, Option<&Array1<bool>>) -> Array1<f32> {
|
||||
let mut y = x.to_owned();
|
||||
for (w, b) in layers {
|
||||
y = layer_func(&y, w, b, activation, Some(&Array::from_elem(b.raw_dim(), false)))
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
fn time_feed_forward(n: usize) {
|
||||
let (inp, layers) = load_test_data();
|
||||
let t0 = Instant::now();
|
||||
for _ in 0..n { feed_forward(&inp, &layers, &sigmoid); }
|
||||
let elapsed = t0.elapsed();
|
||||
println!("{:.5}", elapsed.as_secs_f64());
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
let n: usize = args[1].parse::<usize>().expect("Not an integer");
|
||||
time_feed_forward(n);
|
||||
}
|
107
rs/src/sigmoids.rs
Normal file
107
rs/src/sigmoids.rs
Normal file
@ -0,0 +1,107 @@
|
||||
use std::time::Instant;
|
||||
|
||||
use ndarray::{Array1, Zip};
|
||||
use ndarray_rand::{RandomExt, rand_distr::Uniform};
|
||||
|
||||
|
||||
pub fn sigmoid_val(x: f32) -> f32 {
|
||||
return 1. / (1. + (-x).exp());
|
||||
}
|
||||
|
||||
pub fn sigmoid_ref(x: &f32) -> f32 {
|
||||
return 1. / (1. + (-x).exp());
|
||||
}
|
||||
|
||||
pub fn sigmoid_mut_ref(x: &mut f32) {
|
||||
*x = 1. / (1. + (-*x).exp());
|
||||
}
|
||||
|
||||
|
||||
pub fn sigmoid_vec(x: &Vec<f32>) -> Vec<f32> {
|
||||
return x.iter().map(|&v| sigmoid_val(v)).collect();
|
||||
}
|
||||
|
||||
|
||||
pub fn sigmoid_ndarr_map(x: Array1<f32>) -> Array1<f32> {
|
||||
return x.map(sigmoid_ref);
|
||||
}
|
||||
|
||||
pub fn sigmoid_ndarr_mapv(x: Array1<f32>) -> Array1<f32> {
|
||||
return x.mapv(sigmoid_val);
|
||||
}
|
||||
|
||||
pub fn sigmoid_ndarr_map_inplace(mut x: Array1<f32>) -> Array1<f32> {
|
||||
x.map_inplace(sigmoid_mut_ref);
|
||||
return x;
|
||||
}
|
||||
|
||||
pub fn sigmoid_ndarr_mapv_inplace(mut x: Array1<f32>, virt: Option<&Array1<bool>>) -> Array1<f32> {
|
||||
if virt.is_some() {
|
||||
Zip::from(&mut x).and(virt.unwrap()).for_each(
|
||||
|elem, is_virt| *elem = if *is_virt { *elem } else { sigmoid_ref(elem) }
|
||||
);
|
||||
} else {
|
||||
x.mapv_inplace(sigmoid_val);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
pub fn sigmoid_ndarr_par_map_inplace(mut x: Array1<f32>) -> Array1<f32> {
|
||||
x.par_map_inplace(sigmoid_mut_ref);
|
||||
return x;
|
||||
}
|
||||
|
||||
pub fn sigmoid_ndarr_par_mapv_inplace(mut x: Array1<f32>) -> Array1<f32> {
|
||||
x.par_mapv_inplace(sigmoid_val);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
pub fn time_sigmoids(n: usize, arr_len: usize) {
|
||||
let arr: Array1<f32> = Array1::random(arr_len, Uniform::new(0., 1.));
|
||||
let vec: Vec<f32> = arr.to_vec();
|
||||
|
||||
let t0 = Instant::now();
|
||||
for _ in 0..n { let _result = sigmoid_vec(&vec); }
|
||||
let elapsed = t0.elapsed();
|
||||
println!("sigmoid_vec took {:.5} seconds", elapsed.as_secs_f64());
|
||||
|
||||
let mut arr_copy = arr.to_owned();
|
||||
|
||||
let t0 = Instant::now();
|
||||
for _ in 0..n { arr_copy = sigmoid_ndarr_map(arr_copy); }
|
||||
let elapsed = t0.elapsed();
|
||||
println!("sigmoid_ndarr_map took {:.5} seconds", elapsed.as_secs_f64());
|
||||
|
||||
arr_copy = arr.to_owned();
|
||||
let t0 = Instant::now();
|
||||
for _ in 0..n { arr_copy = sigmoid_ndarr_mapv(arr_copy); }
|
||||
let elapsed = t0.elapsed();
|
||||
println!("sigmoid_ndarr_mapv took {:.5} seconds", elapsed.as_secs_f64());
|
||||
|
||||
arr_copy = arr.to_owned();
|
||||
let t0 = Instant::now();
|
||||
for _ in 0..n { arr_copy = sigmoid_ndarr_map_inplace(arr_copy); }
|
||||
let elapsed = t0.elapsed();
|
||||
println!("sigmoid_ndarr_map_inplace took {:.5} seconds", elapsed.as_secs_f64());
|
||||
|
||||
arr_copy = arr.to_owned();
|
||||
let virt = ndarray::Array::from_elem(arr.raw_dim(), false);
|
||||
let t0 = Instant::now();
|
||||
for _ in 0..n { arr_copy = sigmoid_ndarr_mapv_inplace(arr_copy, Some(&virt)); }
|
||||
let elapsed = t0.elapsed();
|
||||
println!("sigmoid_ndarr_mapv_inplace took {:.5} seconds", elapsed.as_secs_f64());
|
||||
|
||||
arr_copy = arr.to_owned();
|
||||
let t0 = Instant::now();
|
||||
for _ in 0..n { arr_copy = sigmoid_ndarr_par_map_inplace(arr_copy); }
|
||||
let elapsed = t0.elapsed();
|
||||
println!("sigmoid_ndarr_par_map_inplace took {:.5} seconds", elapsed.as_secs_f64());
|
||||
|
||||
arr_copy = arr.to_owned();
|
||||
let t0 = Instant::now();
|
||||
for _ in 0..n { arr_copy = sigmoid_ndarr_par_mapv_inplace(arr_copy); }
|
||||
let elapsed = t0.elapsed();
|
||||
println!("sigmoid_ndarr_par_mapv_inplace took {:.5} seconds", elapsed.as_secs_f64());
|
||||
|
||||
}
|
Reference in New Issue
Block a user