2026-01-28 06:16:04 +00:00

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