pub fn dequantize_affine(data: &[i8], zp: i32, scale: f32) -> Vec<f32> {
data.iter()
.map(|&v| (v as f32 - zp as f32) * scale)
.collect()
}
pub fn nc1hwc2_to_flat<T: Copy + Default>(
data: &[T],
c1: usize,
h: usize,
w: usize,
c2: usize,
total_channels: usize,
) -> Vec<T> {
let mut out = vec![T::default(); total_channels * h * w];
for c1_idx in 0..c1 {
for y in 0..h {
for x in 0..w {
for c2_idx in 0..c2 {
let ch = c1_idx * c2 + c2_idx;
if ch >= total_channels {
continue;
}
let src_offset =
((c1_idx * h + y) * w + x) * c2 + c2_idx;
let dst_offset = ch * h * w + y * w + x;
if src_offset < data.len() {
out[dst_offset] = data[src_offset];
}
}
}
}
}
out
}
#[derive(Debug, Clone)]
pub struct TensorAttr {
pub index: u32,
pub shape: Vec<u32>,
pub n_elems: u32,
pub size: u32,
pub size_with_stride: u32,
pub format: TensorFormat,
pub data_type: TensorType,
pub qnt_type: QuantType,
pub zp: i32,
pub scale: f32,
pub name: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TensorFormat {
NCHW,
NHWC,
NC1HWC2,
Undefined,
}
impl From<u32> for TensorFormat {
fn from(v: u32) -> Self {
match v {
0 => TensorFormat::NCHW,
1 => TensorFormat::NHWC,
2 => TensorFormat::NC1HWC2,
_ => TensorFormat::Undefined,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TensorType {
Float32,
Float16,
Int8,
Uint8,
Int16,
Int32,
Unknown(u32),
}
impl From<u32> for TensorType {
fn from(v: u32) -> Self {
match v {
0 => TensorType::Float32,
1 => TensorType::Float16,
2 => TensorType::Int8,
3 => TensorType::Uint8,
4 => TensorType::Int16,
5 => TensorType::Int32,
other => TensorType::Unknown(other),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum QuantType {
None,
Dfp,
Affine,
Unknown(u32),
}
impl From<u32> for QuantType {
fn from(v: u32) -> Self {
match v {
0 => QuantType::None,
1 => QuantType::Dfp,
2 => QuantType::Affine,
other => QuantType::Unknown(other),
}
}
}
#[derive(Debug, Clone)]
pub struct Nc1hwc2Layout {
c2: usize,
hw_c2: usize,
w_c2: usize,
num_predictions: usize,
zp: i32,
scale: f32,
}
impl Nc1hwc2Layout {
pub fn from_attr(attr: &TensorAttr) -> Result<Self, crate::Error> {
if attr.format != TensorFormat::NC1HWC2 {
return Err(crate::Error::InvalidFormat {
expected: "NC1HWC2",
got: format!("{:?}", attr.format),
});
}
if attr.shape.len() != 5 {
return Err(crate::Error::InvalidFormat {
expected: "5D shape [N, C1, H, W, C2]",
got: format!("{}D shape {:?}", attr.shape.len(), attr.shape),
});
}
let h = attr.shape[2] as usize;
let w = attr.shape[3] as usize;
let c2 = attr.shape[4] as usize;
Ok(Self {
c2,
hw_c2: h * w * c2,
w_c2: w * c2,
num_predictions: h * w,
zp: attr.zp,
scale: attr.scale,
})
}
#[inline]
pub fn channel_offset(&self, ch: usize) -> usize {
(ch / self.c2) * self.hw_c2 + (ch % self.c2)
}
pub fn precompute_channel_offsets(&self, start_ch: usize, count: usize) -> Vec<usize> {
(0..count)
.map(|i| self.channel_offset(start_ch + i))
.collect()
}
#[inline]
pub fn prediction_stride(&self) -> usize {
self.w_c2
}
#[inline]
pub fn num_predictions(&self) -> usize {
self.num_predictions
}
#[inline]
pub fn c2(&self) -> usize {
self.c2
}
#[inline]
pub fn zp(&self) -> i32 {
self.zp
}
#[inline]
pub fn scale(&self) -> f32 {
self.scale
}
#[inline]
pub fn dequant(&self, raw: i8) -> f32 {
(raw as i32 - self.zp) as f32 * self.scale
}
#[inline]
pub fn threshold_i8(&self, conf: f32) -> i8 {
if self.scale > 0.0 {
let raw_f = conf / self.scale + self.zp as f32;
(raw_f.ceil() as i32).clamp(i8::MIN as i32, i8::MAX as i32) as i8
} else {
i8::MIN
}
}
}
impl From<&crate::ffi::RknnTensorAttr> for TensorAttr {
fn from(raw: &crate::ffi::RknnTensorAttr) -> Self {
Self {
index: raw.index,
shape: raw.shape().to_vec(),
n_elems: raw.n_elems,
size: raw.size,
size_with_stride: raw.size_with_stride,
format: TensorFormat::from(raw.fmt),
data_type: TensorType::from(raw.type_),
qnt_type: QuantType::from(raw.qnt_type),
zp: raw.zp,
scale: raw.scale,
name: raw.name_str().to_string(),
}
}
}