869 lines
40 KiB
Python
869 lines
40 KiB
Python
"""Collection of ctypes classes to pass data needed for calling processing functions in C.
|
|
|
|
The main classes will be KDPImage, which will be the only parameter passed into the C processing
|
|
function. The KDPImage attributes store parameters from Python to be passed to the C functions and
|
|
hold the C results for Python to extract. A majority of the classes will not need to be accessed
|
|
by the user since they are not involved in the processing functions themselves, but they exist
|
|
because the entire KDPImage structure is ported from other platforms. The relevant classes are as
|
|
follows:
|
|
Parameters
|
|
KDPImageRaw
|
|
KDPModelDims
|
|
KDPPreproc
|
|
KDPPostproc
|
|
KDPImage
|
|
|
|
Additionally, each class may have a specific version for a specific CSIM platform. If that is the
|
|
case, the CSIM version will be added to the end of the name of the class, such as KDPImageRaw520.
|
|
Consequently, the generic version, KDPImageRaw, will apply for all CSIM versions that do not have
|
|
a specific corresponding class. These will be specified in the docstrings.
|
|
|
|
The related C structure definitions can be found at c_interface/src/include.
|
|
|
|
Example 520 usage:
|
|
parameters = Parameters(params=[0, 1, 2])
|
|
kdp_image_raw = KDPImageRaw520(input_row=480, input_col=640, input_channel=3,
|
|
params_s=parameters)
|
|
kdp_model_dims = KDPModelDims(input_row=112, input_col=112)
|
|
kdp_preproc = KDPPreproc520(input_radix=8, input_scale=1.2)
|
|
kdp_postproc = KDPPostproc520(output_num=8)
|
|
kdp_image = KDPImage520(raw_img_p=kdp_image_raw, model_id=24, dim=kdp_model_dims,
|
|
preproc=kdp_preproc, postproc=kdp_postproc)
|
|
"""
|
|
import copy
|
|
import ctypes
|
|
import platform
|
|
from typing import List, Mapping, Optional, Sequence, Union
|
|
|
|
import c_interface.constants as constants
|
|
|
|
_IS_64 = platform.machine().endswith("64")
|
|
|
|
_MAX_CNN_NODES = 10
|
|
_MAX_PARAMS_LEN = 40
|
|
_MULTI_MODEL_MAX = 16
|
|
|
|
class Parameters(ctypes.Structure):
|
|
"""Preprocessing parameters that may be used for postprocessing.
|
|
|
|
Depending on the postprocessing function, not all of these parameters will be needed. To
|
|
get the optimal result, the values here should be retrieved from the corresponding preprocess
|
|
functions.
|
|
|
|
For more details regarding the structure itself, refer to c_interface/include/xxx/ipc.h
|
|
where xxx is the corresponding CSIM platform.
|
|
|
|
Attributes:
|
|
crop_top: An integer amount of cropping done to the top of the preprocessed image.
|
|
crop_bottom: An integer amount of cropping done to the bottom of the preprocessed image.
|
|
crop_left: An integer amount of cropping done to the left of the preprocessed image.
|
|
crop_right: An integer amount of cropping done to the right of the preprocessed image.
|
|
pad_top: An integer amount of padding added to the top of the preprocessed image.
|
|
pad_bottom: An integer amount of padding added to the bottom of the preprocessed image.
|
|
pad_left: An integer amount of padding added to the left of the preprocessed image.
|
|
pad_right: An integer amount of padding added to the right of the preprocessed image.
|
|
scale_width: A float multiplier to scale the width of the preprocessed image
|
|
back to the original image.
|
|
scale_height: A float multiplier to scale the height of the preprocessed image
|
|
back to the original image.
|
|
flip_face: An integer indicating if FR preprocessing needs to flip the face.
|
|
params: A sequence of floats for any extra variables needed for processing.
|
|
"""
|
|
_fields_ = [("crop_top", ctypes.c_int),
|
|
("crop_bottom", ctypes.c_int),
|
|
("crop_left", ctypes.c_int),
|
|
("crop_right", ctypes.c_int),
|
|
("pad_top", ctypes.c_int),
|
|
("pad_bottom", ctypes.c_int),
|
|
("pad_left", ctypes.c_int),
|
|
("pad_right", ctypes.c_int),
|
|
("scale_width", ctypes.c_float),
|
|
("scale_height", ctypes.c_float),
|
|
("flip_face", ctypes.c_int), # for FR use only
|
|
("params", ctypes.c_float * _MAX_PARAMS_LEN)]
|
|
|
|
def __init__(self, crop_top: int = 0, crop_bottom: int = 0, crop_left: int = 0,
|
|
crop_right: int = 0, pad_top: int = 0, pad_bottom: int = 0, pad_left: int = 0,
|
|
pad_right: int = 0, scale_width: float = 0, scale_height: float = 0,
|
|
flip_face: int = 0, params: Optional[Sequence[float]] = None):
|
|
self.crop_top = crop_top
|
|
self.crop_bottom = crop_bottom
|
|
self.crop_left = crop_left
|
|
self.crop_right = crop_right
|
|
self.pad_top = pad_top
|
|
self.pad_bottom = pad_bottom
|
|
self.pad_left = pad_left
|
|
self.pad_right = pad_right
|
|
self.scale_width = scale_width
|
|
self.scale_height = scale_height
|
|
self.flip_face = flip_face
|
|
if params is not None:
|
|
self.params = (ctypes.c_float * _MAX_PARAMS_LEN)(*params)
|
|
super().__init__()
|
|
|
|
def __repr__(self):
|
|
cropping = (f"Cropping (t, b, l, r): ({self.crop_top}, {self.crop_bottom}, "
|
|
f"{self.crop_left}, {self.crop_right})")
|
|
padding = (f"Padding (t, b, l, r): ({self.pad_top}, {self.pad_bottom}, "
|
|
f"{self.pad_left}, {self.pad_right})")
|
|
scale = f"Scale (w, h): ({self.scale_width}, {self.scale_height})"
|
|
params = "Extra nonzero parameters:\n"
|
|
for index, val in enumerate(self.params[:_MAX_PARAMS_LEN]):
|
|
if val:
|
|
params = f"{params}param[{index}] = {val}\n"
|
|
return ("-------------------------- Processing Parameters --------------------------\n"
|
|
f"{cropping}\n{padding}\n{scale}\n{params}\n")
|
|
|
|
class ResultBuf(ctypes.Structure):
|
|
"""Model result info. Only used to fill out other structures and should be unused."""
|
|
_fields_ = [("model_id", ctypes.c_int32),
|
|
("result_mem_addr", ctypes.c_uint32),
|
|
("result_mem_len", ctypes.c_int32),
|
|
("result_ret_len", ctypes.c_int32)]
|
|
|
|
if _IS_64:
|
|
_fields_[1] = ("result_mem_addr", ctypes.c_uint64)
|
|
|
|
class KDPImageRawBase():
|
|
"""Parameters for all versions related to the original input image.
|
|
|
|
For the E2E platform, a majority of these variables will not be used. The only relevant
|
|
fields are the input dimensions, format, and extra parameters, which will be described
|
|
further below in this section.
|
|
|
|
For more details regarding the structure itself, refer to c_interface/include/xxx/ipc.h
|
|
where xxx is the corresponding CSIM platform.
|
|
|
|
Attributes:
|
|
input_row: An integer size indicating the height of the original image.
|
|
input_col: An integer size indicating the width of the original image.
|
|
input_channel: An integer size indicating the channel number of the original image.
|
|
format: An integer indicating the image format processing to be done. Examples can be
|
|
found at c_interface/include/520/ipc.h.
|
|
params_s: A Parameters instance.
|
|
"""
|
|
fields = [("state", ctypes.c_int),
|
|
("seq_num", ctypes.c_int),
|
|
("ref_idx", ctypes.c_int),
|
|
("input_row", ctypes.c_uint32),
|
|
("input_col", ctypes.c_uint32),
|
|
("input_channel", ctypes.c_uint32),
|
|
("format", ctypes.c_uint32),
|
|
("params_s", Parameters),
|
|
("image_mem_addr", ctypes.c_uint32),
|
|
("image_mem_len", ctypes.c_int32)]
|
|
|
|
if _IS_64:
|
|
fields[8] = ("image_mem_addr", ctypes.c_uint64)
|
|
|
|
def __init__(self, input_row: int = 0, input_col: int = 0, input_channel: int = 0,
|
|
in_format: int = 0, params_s: Parameters = Parameters()):
|
|
self.input_row = input_row
|
|
self.input_col = input_col
|
|
self.input_channel = input_channel
|
|
self.format = in_format
|
|
self.params_s = params_s
|
|
|
|
def __repr__(self):
|
|
image_size = (f"Shape (c, h, w): ({self.input_channel}, {self.input_row}, "
|
|
f"{self.input_col})")
|
|
image_format = f"Format: {hex(self.format)}"
|
|
return ("------------------------------ Raw Image Info -----------------------------\n"
|
|
f"{image_size}\n{image_format}\n{self.params_s}\n")
|
|
|
|
class KDPImageRaw520(KDPImageRawBase, ctypes.Structure):
|
|
"""Parameters related to the original input image (only 520).
|
|
|
|
For attribute details, refer to KDPImageRawBase, as the relevant ones are the same.
|
|
For more details regarding the structure itself, refer to c_interface/include/520/ipc.h.
|
|
"""
|
|
_fields_ = copy.copy(KDPImageRawBase.fields)
|
|
_fields_.extend([("result", ResultBuf * _MULTI_MODEL_MAX),
|
|
("tick_start", ctypes.c_uint32),
|
|
("tick_end", ctypes.c_uint32),
|
|
("tick_start_pre", ctypes.c_uint32),
|
|
("tick_end_pre", ctypes.c_uint32),
|
|
("tick_start_npu", ctypes.c_uint32),
|
|
("tick_end_npu", ctypes.c_uint32),
|
|
("tick_start_post", ctypes.c_uint32),
|
|
("tick_end_post", ctypes.c_uint32)])
|
|
|
|
class KDPImageRaw(KDPImageRawBase, ctypes.Structure):
|
|
"""Parameters related to the original input image (all platforms except 520).
|
|
|
|
For attribute details, refer to KDPImageRawBase, as the relevant ones are the same.
|
|
For more details regarding the structure itself, refer to c_interface/include/xxx/ipc.h
|
|
where xxx is the corresponding CSIM platform.
|
|
"""
|
|
_fields_ = copy.copy(KDPImageRawBase.fields)
|
|
_fields_.extend([("result", ResultBuf),
|
|
("tick_start", ctypes.c_uint32),
|
|
("tick_end", ctypes.c_uint32),
|
|
("tick_got_ncpu_ack", ctypes.c_uint32),
|
|
("tick_start_parse", ctypes.c_uint32),
|
|
("tick_end_parse", ctypes.c_uint32),
|
|
("tick_start_inproc", ctypes.c_uint32),
|
|
("tick_end_inproc", ctypes.c_uint32),
|
|
("tick_start_pre", ctypes.c_uint32),
|
|
("tick_end_pre", ctypes.c_uint32),
|
|
("tick_start_npu", ctypes.c_uint32),
|
|
("tick_cnn_interrupt_rvd", ctypes.c_uint32),
|
|
("tick_end_npu", ctypes.c_uint32),
|
|
("tick_start_post", ctypes.c_uint32),
|
|
("tick_end_post", ctypes.c_uint32),
|
|
("tick_start_dram_copy", ctypes.c_uint32),
|
|
("tick_end_dram_copy", ctypes.c_uint32),
|
|
("tick_rslt_got_scpu_ack", ctypes.c_uint32),
|
|
("tick_ncpu_img_req", ctypes.c_uint32),
|
|
("tick_ncpu_img_ack", ctypes.c_uint32),
|
|
("tick_last_img_req;", ctypes.c_uint32)])
|
|
|
|
class KDPModel(ctypes.Structure):
|
|
"""520/720 model info. Only used to fill out other structures and should be unused."""
|
|
_fields_ = [("model_type", ctypes.c_uint32),
|
|
("model_version", ctypes.c_uint32),
|
|
("input_mem_addr", ctypes.c_uint32),
|
|
("input_mem_len", ctypes.c_int32),
|
|
("output_mem_addr", ctypes.c_uint32),
|
|
("output_mem_len", ctypes.c_int32),
|
|
("buf_addr", ctypes.c_uint32),
|
|
("buf_len", ctypes.c_int32),
|
|
("cmd_mem_addr", ctypes.c_uint32),
|
|
("cmd_mem_len", ctypes.c_int32),
|
|
("weight_mem_addr", ctypes.c_uint32),
|
|
("weight_mem_len", ctypes.c_int32),
|
|
("setup_mem_addr", ctypes.c_uint32),
|
|
("setup_mem_len", ctypes.c_int32)]
|
|
|
|
if _IS_64:
|
|
_fields_[2] = ("input_mem_addr", ctypes.c_uint64)
|
|
_fields_[4] = ("output_mem_addr", ctypes.c_uint64)
|
|
_fields_[6] = ("buf_addr", ctypes.c_uint64)
|
|
_fields_[8] = ("cmd_mem_addr", ctypes.c_uint64)
|
|
_fields_[10] = ("weight_mem_addr", ctypes.c_uint64)
|
|
_fields_[12] = ("setup_mem_addr", ctypes.c_uint64)
|
|
|
|
class CNNHeader720(ctypes.Structure):
|
|
"""720 header info structure. Only used to fill out other structures and should be unused."""
|
|
_fields_ = [("crc", ctypes.c_uint32),
|
|
("version", ctypes.c_uint32),
|
|
("reamaining_models", ctypes.c_uint32),
|
|
("model_type", ctypes.c_uint32),
|
|
("application_type", ctypes.c_uint32),
|
|
("dram_start", ctypes.c_uint32),
|
|
("dram_size", ctypes.c_uint32),
|
|
("cmd_start", ctypes.c_uint32),
|
|
("cmd_size", ctypes.c_uint32),
|
|
("weight_start", ctypes.c_uint32),
|
|
("weight_size", ctypes.c_uint32),
|
|
("input_start", ctypes.c_uint32),
|
|
("input_size", ctypes.c_uint32),
|
|
("input_num", ctypes.c_uint32),
|
|
("output_num", ctypes.c_uint32)]
|
|
|
|
if _IS_64:
|
|
_fields_[5] = ("dram_start", ctypes.c_uint64)
|
|
_fields_[7] = ("cmd_start", ctypes.c_uint64)
|
|
_fields_[9] = ("weight_start", ctypes.c_uint64)
|
|
_fields_[11] = ("input_start", ctypes.c_uint64)
|
|
|
|
class InNode720(ctypes.Structure):
|
|
"""720 input node info. Only used to fill out other structures and should be unused."""
|
|
_fields_ = [("node_id", ctypes.c_uint32),
|
|
("next_npu", ctypes.c_uint32)]
|
|
|
|
class SuperNode(ctypes.Structure):
|
|
"""520/720 super node info. Only used to fill out other structures and should be unused."""
|
|
_fields_ = [("node_id", ctypes.c_uint32),
|
|
("addr", ctypes.c_uint32),
|
|
("row_start", ctypes.c_uint32),
|
|
("col_start", ctypes.c_uint32),
|
|
("ch_start", ctypes.c_uint32),
|
|
("row_length", ctypes.c_uint32),
|
|
("col_length", ctypes.c_uint32),
|
|
("ch_length", ctypes.c_uint32)]
|
|
|
|
if _IS_64:
|
|
_fields_[1] = ("addr", ctypes.c_uint64)
|
|
|
|
class DataNodeBase(ctypes.Structure):
|
|
"""Base data node info. Only used to fill out other structures and should be unused."""
|
|
_fields_ = [("node_id", ctypes.c_uint32),
|
|
("supernum", ctypes.c_uint32),
|
|
("data_format", ctypes.c_uint32),
|
|
("data_radix", ctypes.c_uint32),
|
|
("data_scale", ctypes.c_uint32),
|
|
("row_start", ctypes.c_uint32),
|
|
("col_start", ctypes.c_uint32),
|
|
("ch_start", ctypes.c_uint32),
|
|
("row_length", ctypes.c_uint32),
|
|
("col_length", ctypes.c_uint32),
|
|
("ch_length", ctypes.c_uint32)]
|
|
|
|
class DataNode520(DataNodeBase):
|
|
"""520 data node info. Only used to fill out other structures and should be unused."""
|
|
_fields_ = [("node_list", SuperNode * 1)]
|
|
|
|
class DataNode720(DataNodeBase):
|
|
"""720 data node info. Only used to fill out other structures and should be unused."""
|
|
_fields_ = [("node_list", ctypes.POINTER(SuperNode))]
|
|
|
|
class OutNodeBase(ctypes.Structure):
|
|
"""Base output node info. Only used to fill out other structures and should be unused.
|
|
|
|
For the E2E platform, a majority of these variables will not be used. The only relevant
|
|
fields are the output dimensions, radix, and scale, which will be described further below
|
|
in this section.
|
|
|
|
For more details regarding the structure itself, refer to c_interface/include/xxx/kdpio.h
|
|
where xxx is the corresponding CSIM platform.
|
|
|
|
Attributes:
|
|
row_length: An integer size indicating the number of rows in the output node.
|
|
col_length: An integer size indicating the number of columns in the output node.
|
|
ch_length: An integer size indicating the number of channels in the output node.
|
|
output_radix: An integer radix to convert integer values to float values.
|
|
output_scale: A float scaling factor that is saved as an integer in memory to convert
|
|
integer values to float values.
|
|
"""
|
|
_fields_ = [("node_id", ctypes.c_uint32),
|
|
("supernum", ctypes.c_uint32),
|
|
("data_format", ctypes.c_uint32),
|
|
("row_start", ctypes.c_uint32),
|
|
("col_start", ctypes.c_uint32),
|
|
("ch_start", ctypes.c_uint32),
|
|
("row_length", ctypes.c_uint32),
|
|
("col_length", ctypes.c_uint32),
|
|
("ch_length", ctypes.c_uint32),
|
|
("output_index", ctypes.c_uint32),
|
|
("output_radix", ctypes.c_uint32),
|
|
("output_scale", ctypes.c_uint32)]
|
|
|
|
def __init__(self, row_length: int = 0, col_length: int = 0, ch_length: int = 0,
|
|
output_radix: int = 0, output_scale: int = 0):
|
|
self.row_length = row_length
|
|
self.col_length = col_length
|
|
self.ch_length = ch_length
|
|
self.output_radix = output_radix
|
|
self.output_scale = output_scale
|
|
super().__init__()
|
|
|
|
class OutNode520(OutNodeBase):
|
|
"""520 output node info. Only used to fill out other structures and should be unused."""
|
|
_fields_ = [("node_list", SuperNode * 1)]
|
|
|
|
class OutNode720(OutNodeBase):
|
|
"""720 output node info. Only used to fill out other structures and should be unused."""
|
|
_fields_ = [("node_list", ctypes.POINTER(SuperNode))]
|
|
|
|
class CPUNodeBase(ctypes.Structure):
|
|
"""Base CPU node info. Only used to fill out other structures and should be unused."""
|
|
_fields_ = [("node_id", ctypes.c_uint32),
|
|
("input_datanode_num", ctypes.c_uint32),
|
|
("op_type", ctypes.c_uint32),
|
|
("in_num_row", ctypes.c_uint32),
|
|
("in_num_col", ctypes.c_uint32),
|
|
("in_num_ch", ctypes.c_uint32),
|
|
("out_num_row", ctypes.c_uint32),
|
|
("out_num_col", ctypes.c_uint32),
|
|
("out_num_ch", ctypes.c_uint32),
|
|
("h_pad", ctypes.c_uint32),
|
|
("w_pad", ctypes.c_uint32),
|
|
("kernel_h", ctypes.c_uint32),
|
|
("kernel_w", ctypes.c_uint32),
|
|
("stride_h", ctypes.c_uint32),
|
|
("stride_w", ctypes.c_uint32)]
|
|
|
|
class CPUNode520(CPUNodeBase):
|
|
"""520 CPU node info. Only used to fill out other structures and should be unused."""
|
|
_fields_ = [("output_datanode", DataNode520),
|
|
("input_datanode", DataNode520 * 1)]
|
|
|
|
class CPUNode720(CPUNodeBase):
|
|
"""720 CPU node info. Only used to fill out other structures and should be unused."""
|
|
_fields_ = [("output_datanode", ctypes.POINTER(DataNode720)),
|
|
("input_datanodes", ctypes.POINTER(DataNode720))]
|
|
|
|
class NetInputNode720(ctypes.Structure):
|
|
"""720 network node info. Only used to fill out other structures and should be unused."""
|
|
_fields_ = [("node_id", ctypes.c_uint32),
|
|
("input_index", ctypes.c_uint32),
|
|
("input_format", ctypes.c_uint32),
|
|
("input_row", ctypes.c_uint32),
|
|
("input_col", ctypes.c_uint32),
|
|
("input_channel", ctypes.c_uint32),
|
|
("input_start", ctypes.c_uint32),
|
|
("input_size", ctypes.c_uint32),
|
|
("input_radix", ctypes.c_uint32)]
|
|
|
|
class OperationNode720(ctypes.Structure):
|
|
"""720 operation node info. Only used to fill out other structures and should be unused."""
|
|
pass
|
|
|
|
OperationNode720._fields_ = [("node_id", ctypes.c_uint32), # pylint: disable=protected-access
|
|
("buffer_index", ctypes.c_uint32),
|
|
("inN", ctypes.POINTER(InNode720)),
|
|
("outN", ctypes.POINTER(OutNode720)),
|
|
("cpuN", ctypes.POINTER(CPUNode720)),
|
|
("netinN", ctypes.POINTER(NetInputNode720)),
|
|
("next", ctypes.POINTER(OperationNode720))]
|
|
|
|
class ParsedFWModel720(ctypes.Structure):
|
|
"""720 firmware model info. Only used to fill out other structures and should be unused."""
|
|
_fields_ = [("nTotalNodes", ctypes.c_int),
|
|
("pSetupHead", ctypes.POINTER(CNNHeader720)),
|
|
("pNodeHead", ctypes.POINTER(OperationNode720)),
|
|
("oModel", KDPModel),
|
|
("total_nodes", ctypes.c_int),
|
|
("current_node_id", ctypes.c_int),
|
|
("pNodePositions", ctypes.c_uint32 * _MAX_CNN_NODES)]
|
|
|
|
if _IS_64:
|
|
_fields_[-1] = ("pNodePositions", ctypes.c_uint64 * _MAX_CNN_NODES)
|
|
|
|
class KDPModelDims(ctypes.Structure):
|
|
"""Dimensions of the model input image.
|
|
|
|
For more details regarding the structure itself, refer to c_interface/include/xxx/kdpio.h
|
|
where xxx is the corresponding CSIM platform.
|
|
|
|
Attributes:
|
|
input_row: An integer size indicating the height of the model input image.
|
|
input_col: An integer size indicating the width of the model input image.
|
|
input_channel: An integer size indicating the channel number of the model input image.
|
|
"""
|
|
_fields_ = [("input_row", ctypes.c_uint32),
|
|
("input_col", ctypes.c_uint32),
|
|
("input_channel", ctypes.c_uint32)]
|
|
|
|
def __init__(self, input_row: int = 0, input_col: int = 0, input_channel: int = 0):
|
|
self.input_row = input_row
|
|
self.input_col = input_col
|
|
self.input_channel = input_channel
|
|
super().__init__()
|
|
|
|
def __repr__(self):
|
|
image_size = (f"Model input shape (c, h, w): ({self.input_channel}, {self.input_row}, "
|
|
f"{self.input_col})")
|
|
return ("----------------------------- Model Dimensions ----------------------------\n"
|
|
f"{image_size}\n")
|
|
|
|
class KDPPreprocBase():
|
|
"""Parameters that may be used for preprocessing in all versions.
|
|
|
|
For the E2E platform, a majority of these variables will not be used. The only relevant
|
|
fields are the radix, scale, and parameters, which will be described further below in
|
|
this section.
|
|
|
|
Attributes:
|
|
input_radix: An integer radix to convert integer values to float values.
|
|
input_scale: A float scaling factor to convert integer values to float values.
|
|
params_p: A sequence of floats for any extra variables needed for preprocessing.
|
|
"""
|
|
fields = [("input_mem_addr", ctypes.c_uint32),
|
|
("input_mem_len", ctypes.c_int32),
|
|
("input_mem_addr2", ctypes.c_uint32),
|
|
("input_mem_len2", ctypes.c_int32),
|
|
("input_radix", ctypes.c_uint32),
|
|
("input_scale", ctypes.c_float),
|
|
("params_p", ctypes.c_void_p)]
|
|
|
|
if _IS_64:
|
|
fields[0] = ("input_mem_addr", ctypes.c_uint64)
|
|
fields[2] = ("input_mem_addr2", ctypes.c_uint64)
|
|
|
|
def __init__(self, input_radix: int = 0, input_scale: float = 0,
|
|
params_p: Optional[Sequence[float]] = None):
|
|
self.input_radix = input_radix
|
|
self.input_scale = input_scale
|
|
self.set_params_p(params_p)
|
|
|
|
def set_params_p(self, params_p: Optional[Sequence[float]] = None):
|
|
"""Assigns the parameter list into a ctypes void pointer."""
|
|
if params_p is not None:
|
|
float_params = (ctypes.c_float * len(params_p))(*params_p)
|
|
self.params_p = ctypes.cast(float_params, ctypes.c_void_p)
|
|
|
|
def __repr__(self):
|
|
# extra parameters not displayed since count is unknown
|
|
return ("-------------------------- Preprocess Parameters --------------------------\n"
|
|
f"Radix: {self.input_radix}\nScale: {self.input_scale}\n")
|
|
|
|
class KDPPreproc520(KDPPreprocBase, ctypes.Structure):
|
|
"""520 parameters that may be used for preprocessing.
|
|
|
|
For attribute details, refer to KDPPreprocBase, as the relevant ones are the same.
|
|
For more details regarding the structure itself, refer to c_interface/include/520/kdpio.h.
|
|
"""
|
|
_fields_ = copy.copy(KDPPreprocBase.fields)
|
|
_fields_.insert(4, ("inproc_mem_addr", ctypes.c_uint32))
|
|
|
|
if _IS_64:
|
|
_fields_[4] = ("inproc_mem_addr", ctypes.c_uint64)
|
|
|
|
class KDPPreproc(KDPPreprocBase, ctypes.Structure):
|
|
"""Non-520 parameters that may be used for preprocessing.
|
|
|
|
For attribute details, refer to KDPPreprocBase, as the relevant ones are the same.
|
|
For more details regarding the structure itself, refer to c_interface/include/xxx/kdpio.h
|
|
where xxx is the corresponding CSIM platform.
|
|
"""
|
|
_fields_ = copy.copy(KDPPreprocBase.fields)
|
|
|
|
class KDPPostprocBase():
|
|
"""Parameters that may be used for postprocessing in all versions.
|
|
|
|
For the E2E platform, a majority of these variables will not be used. The only relevant
|
|
fields are the output numbers, format, and parameters, which will be described further
|
|
below in this section.
|
|
|
|
Attributes:
|
|
output_num: An integer indicating number of outputs the model has.
|
|
output_format: An integer indicating the image format processing that was done. Examples
|
|
can be found at c_interface/include/xxx/ipc.h where xxx is the corresponding CSIM
|
|
platform.
|
|
params_p: A sequence of floats for any extra variables needed for postprocessing.
|
|
"""
|
|
fields = [("output_num", ctypes.c_uint32),
|
|
("output_mem_addr", ctypes.c_uint32),
|
|
("output_mem_len", ctypes.c_int32),
|
|
("result_mem_addr", ctypes.c_uint32),
|
|
("result_mem_len", ctypes.c_int32),
|
|
("output_mem_addr3", ctypes.c_uint32),
|
|
("output_mem_addr4", ctypes.c_uint32),
|
|
("output_format", ctypes.c_uint32),
|
|
("params_p", ctypes.c_void_p)]
|
|
|
|
if _IS_64:
|
|
fields[1] = ("output_mem_addr", ctypes.c_uint64)
|
|
fields[3] = ("result_mem_addr", ctypes.c_uint64)
|
|
fields[5] = ("output_mem_addr3", ctypes.c_uint64)
|
|
fields[6] = ("output_mem_addr4", ctypes.c_uint64)
|
|
|
|
def __init__(self, output_num: int = 0, output_format: int = 0,
|
|
params_p: Optional[Sequence[float]] = None):
|
|
self.output_num = output_num
|
|
self.output_format = output_format
|
|
self.set_params_p(params_p)
|
|
|
|
def set_params_p(self, params_p: Optional[Sequence[float]] = None):
|
|
"""Assigns the parameter list into a ctypes void pointer."""
|
|
if params_p is not None:
|
|
float_params = (ctypes.c_float * len(params_p))(*params_p)
|
|
self.params_p = ctypes.cast(float_params, ctypes.c_void_p)
|
|
|
|
def __repr__(self):
|
|
# extra parameters not displayed since count is unknown
|
|
return ("-------------------------- Postprocess Parameters -------------------------\n"
|
|
f"Output number: {self.output_num}\nOutput format: {hex(self.output_format)}\n")
|
|
|
|
class KDPPostproc(KDPPostprocBase, ctypes.Structure):
|
|
"""530/630 parameters that may be used for postprocessing.
|
|
|
|
For attribute details, refer to KDPPostprocBase, as the relevant ones are the same.
|
|
For more details regarding the structure itself, refer to c_interface/include/xxx/kdpio.h
|
|
where xxx is the corresponding CSIM platform.
|
|
"""
|
|
_fields_ = copy.copy(KDPPostprocBase.fields)
|
|
|
|
class KDPPostproc720(KDPPostprocBase, ctypes.Structure):
|
|
"""720 parameters that may be used for postprocessing.
|
|
|
|
For attribute details, refer to KDPPostprocBase, as the relevant ones are the same.
|
|
For more details regarding the structure itself, refer to c_interface/include/720/kdpio.h.
|
|
"""
|
|
_fields_ = copy.copy(KDPPostprocBase.fields)
|
|
_fields_.insert(8, ("node_p", ctypes.POINTER(OutNode720)))
|
|
|
|
def set_node_p(self, node_list: Optional[Sequence[OutNode720]] = None):
|
|
"""Assigns the OutNode720 list into a ctypes OutNode720 pointer."""
|
|
if node_list is not None:
|
|
node_p = (OutNode720 * len(node_list))(*node_list)
|
|
self.node_p = ctypes.cast(node_p, ctypes.POINTER(OutNode720))
|
|
|
|
class KDPPostproc520(KDPPostprocBase, ctypes.Structure):
|
|
"""520 parameters that may be used for postprocessing.
|
|
|
|
For attribute details, refer to KDPPostprocBase, as the relevant ones are the same.
|
|
For more details regarding the structure itself, refer to c_interface/include/520/kdpio.h.
|
|
"""
|
|
_fields_ = copy.copy(KDPPostprocBase.fields)
|
|
_fields_.insert(8, ("node_p", ctypes.POINTER(OutNode520)))
|
|
_fields_.insert(5, ("output_mem_len2", ctypes.c_uint32))
|
|
_fields_.insert(5, ("output_mem_addr2", ctypes.c_uint32))
|
|
|
|
if _IS_64:
|
|
_fields_[5] = ("output_mem_addr2", ctypes.c_uint64)
|
|
|
|
class KDPCPUOp520(ctypes.Structure):
|
|
"""520 CPU operation info. Only used to fill out other structures and should be unused."""
|
|
_fields_ = [("node_p", ctypes.POINTER(CPUNode520))]
|
|
|
|
class KDPCPUOp720(ctypes.Structure):
|
|
"""720 CPU operation info. Only used to fill out other structures and should be unused."""
|
|
_fields_ = [("node_p", ctypes.POINTER(CPUNode720))]
|
|
|
|
class KDPImage(ctypes.Structure):
|
|
"""Non-520/720 image structure that holds all of the data needed for processing.
|
|
|
|
This class will be passed to the C postprocess functions after inference was done with any CSIM
|
|
version except 520 or 720. Any Python variables that needs to be accessed in the C function
|
|
should be initialized in the appropriate class and assigned to the corresponding attribute.
|
|
The 'parser_session_hdl', 'in_node_hdl', 'out_node_hdl', 'cpu_node_hdl', 'slot_idx',
|
|
'pExtParam', and 'nLenExtParam' parameters will not need to be accessed by the user. The
|
|
other relevant parameters will be described further below in this section.
|
|
|
|
For more details regarding the structure itself, refer to c_interface/include/xxx/kdpio.h
|
|
where xxx is the corresponding CSIM platform.
|
|
|
|
Attributes:
|
|
csim_version: An integer indicating the version of CSIM used.
|
|
raw_img_p: A ctypes pointer to a KDPImageRaw instance holding original image parameters.
|
|
model_id: An integer indicating the ID of the model that was inferenced (not needed).
|
|
dim: A KDPModelDims instance holding the model input dimensions.
|
|
preproc: A KDPPreproc instance holding preprocess parameters.
|
|
postproc: A KDPPostproc instance holding postprocess parameters.
|
|
"""
|
|
_fields_ = [("raw_img_p", ctypes.POINTER(KDPImageRaw)),
|
|
("parser_session_hdl", ctypes.c_void_p),
|
|
("in_node_hdl", ctypes.c_void_p),
|
|
("out_node_hdl", ctypes.c_void_p),
|
|
("cpu_node_hdl", ctypes.c_void_p),
|
|
("model_id", ctypes.c_int),
|
|
("slot_idx", ctypes.c_int),
|
|
("pExtParam", ctypes.c_void_p),
|
|
("nLenExtParam", ctypes.c_int32),
|
|
("dim", KDPModelDims),
|
|
("preproc", KDPPreproc),
|
|
("postproc", KDPPostproc)]
|
|
|
|
def __init__(self, csim_version: int = 530, raw_img_p: Optional[Sequence[KDPImageRaw]] = None,
|
|
model_id: int = 0, dim: KDPModelDims = KDPModelDims(),
|
|
preproc: KDPPreproc = KDPPreproc(), postproc: KDPPostproc = KDPPostproc()):
|
|
# csim_version will only be used for print debugging
|
|
self.csim_version = csim_version
|
|
if raw_img_p is not None:
|
|
raw_images = (KDPImageRaw * len(raw_img_p))(*raw_img_p)
|
|
self.raw_img_p = ctypes.cast(raw_images, ctypes.POINTER(KDPImageRaw))
|
|
self.model_id = model_id
|
|
self.dim = dim
|
|
self.preproc = preproc
|
|
self.postproc = postproc
|
|
super().__init__()
|
|
|
|
def __repr__(self):
|
|
header = f"{self.csim_version} KDPImage"
|
|
return (f"------------------------------- {header} ------------------------------\n"
|
|
f"Model ID: {self.model_id}\n{self.raw_img_p.contents}\n{self.dim}\n"
|
|
f"{self.preproc}\n{self.postproc}")
|
|
|
|
class KDPImage520(ctypes.Structure):
|
|
"""520 image structure that holds all of the data needed for processing.
|
|
|
|
This class will be passed to the C postprocess functions after inference was done with 520
|
|
CSIM. Any Python variables that needs to be accessed in the C function should be initialized
|
|
in the appropriate class and assigned to the corresponding attribute. The 'model_p',
|
|
'setup_mem_p', and 'cpu_op' parameters will not need to be accessed by the user. The other
|
|
relevant parameters will be described further below in this section.
|
|
|
|
For more details regarding the structure itself, refer to c_interface/include/520/kdpio.h.
|
|
|
|
Attributes:
|
|
raw_img_p: A ctypes pointer to a KDPImageRaw520 instance holding original image parameters.
|
|
model_id: An integer indicating the ID of the model that was inferenced (not needed).
|
|
dim: A KDPModelDims instance holding the model input dimensions.
|
|
preproc: A KDPPreproc520 instance holding preprocess parameters.
|
|
postproc: A KDPPostproc520 instance holding postprocess parameters.
|
|
"""
|
|
_fields_ = [("raw_img_p", ctypes.POINTER(KDPImageRaw520)),
|
|
("model_p", ctypes.POINTER(KDPModel)),
|
|
("model_id", ctypes.c_int),
|
|
("setup_mem_p", ctypes.POINTER(ctypes.c_char)),
|
|
("dim", KDPModelDims),
|
|
("preproc", KDPPreproc520),
|
|
("postproc", KDPPostproc520),
|
|
("cpu_op", KDPCPUOp520)]
|
|
|
|
def __init__(self, raw_img_p: Optional[Sequence[KDPImageRaw520]] = None, model_id: int = 0,
|
|
dim: KDPModelDims = KDPModelDims(), preproc: KDPPreproc520 = KDPPreproc520(),
|
|
postproc: KDPPostproc520 = KDPPostproc520()):
|
|
if raw_img_p is not None:
|
|
raw_images = (KDPImageRaw520 * len(raw_img_p))(*raw_img_p)
|
|
self.raw_img_p = ctypes.cast(raw_images, ctypes.POINTER(KDPImageRaw520))
|
|
else:
|
|
self.raw_img_p = ctypes.pointer(KDPImageRaw520())
|
|
self.model_id = model_id
|
|
self.dim = dim
|
|
self.preproc = preproc
|
|
self.postproc = postproc
|
|
super().__init__()
|
|
|
|
def __repr__(self):
|
|
return ("------------------------------- 520 KDPImage ------------------------------\n"
|
|
f"Model ID: {self.model_id}\n{self.raw_img_p.contents}\n{self.dim}\n"
|
|
f"{self.preproc}\n{self.postproc}")
|
|
|
|
class KDPImage720(ctypes.Structure):
|
|
"""720 image structure that holds all of the data needed for processing.
|
|
|
|
This class will be passed to the C postprocess functions after inference was done with 720
|
|
CSIM. Any Python variables that needs to be accessed in the C function should be initialized
|
|
in the appropriate class and assigned to the corresponding attribute. The 'pParsedModel',
|
|
'slot_idx', 'setup_mem_p', 'pExtParam', 'nLenExtParam', and 'cpu_op' parameters will not
|
|
need to be accessed by the user. The other relevant parameters will be described further
|
|
below in this section.
|
|
|
|
For more details regarding the structure itself, refer to c_interface/include/720/kdpio.h.
|
|
|
|
Attributes:
|
|
raw_img_p: A ctypes pointer to a KDPImageRaw instance holding original image parameters.
|
|
model_id: An integer indicating the ID of the model that was inferenced (not needed).
|
|
dim: A KDPModelDims instance holding the model input dimensions.
|
|
preproc: A KDPPreproc instance holding preprocess parameters.
|
|
postproc: A KDPPostproc720 instance holding postprocess parameters.
|
|
"""
|
|
_fields_ = [("raw_img_p", ctypes.POINTER(KDPImageRaw)),
|
|
("pParsedModel", ctypes.POINTER(ParsedFWModel720)),
|
|
("model_id", ctypes.c_int),
|
|
("slot_idx", ctypes.c_int),
|
|
("setup_mem_p", ctypes.POINTER(ctypes.c_char)),
|
|
("pExtParam", ctypes.c_void_p),
|
|
("nLenExtParam", ctypes.c_int32),
|
|
("dim", KDPModelDims),
|
|
("preproc", KDPPreproc),
|
|
("postproc", KDPPostproc720),
|
|
("cpu_op", KDPCPUOp720)]
|
|
|
|
def __init__(self, raw_img_p: Optional[Sequence[KDPImageRaw]] = None, model_id: int = 0,
|
|
dim: KDPModelDims = KDPModelDims(), preproc: KDPPreproc = KDPPreproc(),
|
|
postproc: KDPPostproc720 = KDPPostproc720()):
|
|
if raw_img_p is not None:
|
|
raw_images = (KDPImageRaw * len(raw_img_p))(*raw_img_p)
|
|
self.raw_img_p = ctypes.cast(raw_images, ctypes.POINTER(KDPImageRaw))
|
|
self.model_id = model_id
|
|
self.dim = dim
|
|
self.preproc = preproc
|
|
self.postproc = postproc
|
|
super().__init__()
|
|
|
|
def __repr__(self):
|
|
return ("------------------------------- 720 KDPImage ------------------------------\n"
|
|
f"Model ID: {self.model_id}\n{self.raw_img_p.contents}\n{self.dim}\n"
|
|
f"{self.preproc}\n{self.postproc}")
|
|
|
|
KDPImageType = Union[KDPImage, KDPImage520, KDPImage720]
|
|
KDPIMAGEMAP = {
|
|
520: KDPImage520,
|
|
530: KDPImage,
|
|
540: KDPImage,
|
|
630: KDPImage,
|
|
720: KDPImage720,
|
|
730: KDPImage,
|
|
}
|
|
|
|
def init_kdp_image(
|
|
csim_platform: int, model_id: int = 0,
|
|
params_map: Optional[List[Mapping[str, Union[int, float, List[float]]]]] = None,
|
|
raw_image_map: Optional[List[Mapping[str, int]]] = None,
|
|
model_dims_map: Optional[Mapping[str, int]] = None,
|
|
pre_proc_map: Optional[Mapping[str, Union[int, List[float]]]] = None,
|
|
post_proc_map: Optional[Mapping[str, Union[int, List[float]]]] = None
|
|
) -> KDPImageType:
|
|
"""Creates a KDPImageType for the given platform using the provided parameters.
|
|
|
|
The type of KDPImage created will depend on the given 'csim_platform' parameter. Similarly,
|
|
the subclasses that make up the KDPImage will depend on 'csim_platform.' For each of the
|
|
input mappings, the string key should be the same as the parameter for the class
|
|
that wishes to be set; it will be set to the corresponding value in the mapping.
|
|
|
|
The number of KDPImageRawBase classes initialized will be equal to the length of
|
|
'raw_image_map.' If it is 'None', one KDPImageRawBase class will be initialized.
|
|
If the number of mappings in 'params_map' exceeds the number of mappings in 'raw_image_map',
|
|
any extra mappings in 'params_map' will be ignored.
|
|
|
|
Args:
|
|
csim_platform: An integer indicating the version of CSIM used.
|
|
model_id: An integer indicating the model ID associated with the postprocess. May not
|
|
necessarily be needed.
|
|
params_map: List of dictionaries mapping the kdp.Parameter attribute name to the values
|
|
they should be initialized to.
|
|
raw_image_map: List of dictionaries mapping the kdp.KDPImageRawBase to the values they
|
|
should be initialized to.
|
|
model_dims_map: Dictionary mapping the kdp.KDPModelDims attribute name to the values
|
|
they should be initialized to.
|
|
pre_proc: Dictionary mapping the kdp.KDPPreprocBase attribute name to the values they
|
|
should be initialized to.
|
|
post_proc: Dictionary mapping the kdp.KDPPostprocBase attribute name to the values
|
|
they should be initialized to.
|
|
|
|
Returns:
|
|
A kdp.KDPImageType instance initialized with the provided input parameters to be used
|
|
with the corresponding input platform.
|
|
|
|
Raises:
|
|
ValueError: If csim_platform is not supported
|
|
"""
|
|
if csim_platform not in constants.SUPPORTED_PLATFORMS:
|
|
raise ValueError(f"init_kdp_image: Platform must be one of "
|
|
f"{constants.SUPPORTED_PLATFORMS}, not {csim_platform}")
|
|
|
|
# will ignore any extra params in params_map if there are fewer raw_images specified
|
|
if raw_image_map is None:
|
|
if params_map is None:
|
|
params = Parameters()
|
|
else:
|
|
params = Parameters(**params_map[0])
|
|
|
|
if csim_platform == 520:
|
|
raw_image = [KDPImageRaw520(params_s=params)]
|
|
else:
|
|
raw_image = [KDPImageRaw(params_s=params)]
|
|
else:
|
|
raw_image = []
|
|
for index, image_map in enumerate(raw_image_map):
|
|
if params_map is not None and index < len(params_map):
|
|
params = Parameters(**params_map[index])
|
|
else:
|
|
params = Parameters()
|
|
|
|
if csim_platform == 520:
|
|
raw_image.append(KDPImageRaw520(params_s=params, **image_map))
|
|
else:
|
|
raw_image.append(KDPImageRaw(params_s=params, **image_map))
|
|
|
|
if model_dims_map is None:
|
|
model_dims = KDPModelDims()
|
|
else:
|
|
model_dims = KDPModelDims(**model_dims_map)
|
|
|
|
if pre_proc_map is None:
|
|
if csim_platform == 520:
|
|
pre_proc = KDPPreproc520()
|
|
else:
|
|
pre_proc = KDPPreproc()
|
|
else:
|
|
if csim_platform == 520:
|
|
pre_proc = KDPPreproc520(**pre_proc_map)
|
|
else:
|
|
pre_proc = KDPPreproc(**pre_proc_map)
|
|
|
|
if post_proc_map is None:
|
|
if csim_platform == 520:
|
|
post_proc = KDPPostproc520()
|
|
elif csim_platform == 720:
|
|
post_proc = KDPPostproc720()
|
|
else:
|
|
post_proc = KDPPostproc()
|
|
else:
|
|
if csim_platform == 520:
|
|
post_proc = KDPPostproc520(**post_proc_map)
|
|
elif csim_platform == 720:
|
|
post_proc = KDPPostproc720(**post_proc_map)
|
|
else:
|
|
post_proc = KDPPostproc(**post_proc_map)
|
|
|
|
kdp_image = KDPIMAGEMAP[csim_platform](raw_img_p=raw_image, dim=model_dims,
|
|
preproc=pre_proc, postproc=post_proc,
|
|
model_id=model_id)
|
|
return kdp_image
|