use embedded_nn::{
float_ops::fully_connected_f32,
fully_connected::{
batch_matmul_s16, batch_matmul_s8, fully_connected_per_channel_s8, fully_connected_s16,
fully_connected_s8,
},
subbyte::{fully_connected_s4, pack_s4_pair},
Activation, Dims, FcParams, PerChannelQuantParams, PerTensorQuantParams,
};
#[test]
fn test_fully_connected_s8_per_tensor_variations() {
let fc_params = FcParams {
input_offset: 5,
filter_offset: 0,
output_offset: -10,
activation: Activation::new(-20, 20),
};
let quant_params = PerTensorQuantParams::new(1073741824, 0);
let input_dims = Dims::new(2, 1, 1, 3); let input = [
5i8, 15i8, 25i8, -5i8, 0i8, 5i8, ];
let filter_dims = Dims::new(3, 1, 1, 2); let kernel = [
1i8, 2i8, 3i8, 2i8, 0i8, -1i8, ];
let bias = [10i32, -20i32];
let output_dims = Dims::new(2, 1, 1, 2);
let mut output = [0i8; 4];
fully_connected_s8(
&fc_params,
&quant_params,
&input_dims,
&input,
&filter_dims,
&kernel,
Some(&bias),
&output_dims,
&mut output,
)
.unwrap();
assert_eq!(output[0], 20);
assert_eq!(output[1], -20);
}
#[test]
fn test_fully_connected_per_channel_s8_comprehensive() {
let fc_params = FcParams {
input_offset: 0,
filter_offset: 0,
output_offset: 0,
activation: Activation::int8_unconstrained(),
};
let mults = [1073741824, 2147483647]; let shifts = [0, 0];
let quant_params = PerChannelQuantParams::new(&mults, &shifts);
let input_dims = Dims::new(1, 1, 1, 2);
let input = [10i8, 20i8];
let filter_dims = Dims::new(2, 1, 1, 2);
let kernel = [
1i8, 1i8, 2i8, 2i8, ];
let output_dims = Dims::new(1, 1, 1, 2);
let mut output = [0i8; 2];
fully_connected_per_channel_s8(
&fc_params,
&quant_params,
&input_dims,
&input,
&filter_dims,
&kernel,
None,
&output_dims,
&mut output,
)
.unwrap();
assert_eq!(output[0], 15);
assert_eq!(output[1], 60);
}
#[test]
fn test_fully_connected_s16_comprehensive() {
let fc_params = FcParams {
input_offset: 0,
filter_offset: 0,
output_offset: 0,
activation: Activation::int16_unconstrained(),
};
let quant_params = PerTensorQuantParams::new(2147483647, 0);
let input_dims = Dims::new(1, 1, 1, 2);
let input = [1000i16, 2000i16];
let filter_dims = Dims::new(2, 1, 1, 2);
let kernel = [10i8, 20i8, 5i8, 15i8];
let bias = [100i64, -200i64];
let output_dims = Dims::new(1, 1, 1, 2);
let mut output = [0i16; 2];
fully_connected_s16(
&fc_params,
&quant_params,
&input_dims,
&input,
&filter_dims,
&kernel,
Some(&bias),
&output_dims,
&mut output,
)
.unwrap();
assert_eq!(output[0], 1);
}
#[test]
fn test_batch_matmul_s8_broadcasting_and_execution() {
let fc_params = FcParams {
input_offset: 0,
filter_offset: 0,
output_offset: 0,
activation: Activation::int8_unconstrained(),
};
let quant_params = PerTensorQuantParams::new(2147483647, 0);
let lhs_dims = Dims::new(2, 2, 3, 1); let lhs = [
1i8, 2i8, 3i8, 4i8, 5i8, 6i8, 7i8, 8i8, 9i8, 10i8, 11i8, 12i8, ];
let rhs_dims = Dims::new(1, 3, 1, 2); let rhs = [
1i8, 0i8, 0i8, 1i8, 1i8, 1i8, ];
let output_dims = Dims::new(2, 2, 2, 1); let mut output = [0i8; 8];
batch_matmul_s8(
&fc_params,
&quant_params,
&lhs_dims,
&lhs,
&rhs_dims,
&rhs,
&output_dims,
&mut output,
)
.unwrap();
assert_eq!(output[0], 4);
assert_eq!(output[1], 5);
}
#[test]
fn test_batch_matmul_s16_execution() {
let fc_params = FcParams {
input_offset: 0,
filter_offset: 0,
output_offset: 0,
activation: Activation::int16_unconstrained(),
};
let quant_params = PerTensorQuantParams::new(2147483647, 0);
let lhs_dims = Dims::new(1, 1, 2, 1); let lhs = [100i16, 200i16];
let rhs_dims = Dims::new(1, 2, 1, 1); let rhs = [3i16, 4i16];
let output_dims = Dims::new(1, 1, 1, 1);
let mut output = [0i16; 1];
batch_matmul_s16(
&fc_params,
&quant_params,
&lhs_dims,
&lhs,
&rhs_dims,
&rhs,
&output_dims,
&mut output,
)
.unwrap();
assert_eq!(output[0], 0);
}
#[test]
fn test_fully_connected_s4_odd_accum_depth() {
let fc_params = FcParams {
input_offset: 0,
filter_offset: 0,
output_offset: 0,
activation: Activation::int8_unconstrained(),
};
let quant_params = PerTensorQuantParams::new(2147483647, 0);
let input_dims = Dims::new(1, 1, 1, 3); let input = [2i8, 3i8, 4i8];
let filter_dims = Dims::new(3, 1, 1, 1); let packed_kernel = [
pack_s4_pair(1i8, 2i8), pack_s4_pair(3i8, 0i8), ];
let output_dims = Dims::new(1, 1, 1, 1);
let mut output = [0i8; 1];
fully_connected_s4(
&fc_params,
&quant_params,
&input_dims,
&input,
&filter_dims,
&packed_kernel,
None,
&output_dims,
&mut output,
)
.unwrap();
assert_eq!(output[0], 20);
}
#[test]
fn test_fully_connected_f32_execution() {
let input_dims = Dims::new(1, 1, 1, 3);
let input = [1.0f32, 2.0f32, 3.0f32];
let filter_dims = Dims::new(3, 1, 1, 2);
let kernel = [
1.0f32, 2.0f32, 3.0f32, 4.0f32, 5.0f32, 6.0f32, ];
let bias = [0.5f32, -1.0f32];
let output_dims = Dims::new(1, 1, 1, 2);
let mut output = [0.0f32; 2];
fully_connected_f32(
&input_dims,
&input,
&filter_dims,
&kernel,
Some(&bias),
&output_dims,
&mut output,
)
.unwrap();
assert_eq!(output[0], 14.5);
assert_eq!(output[1], 31.0);
}