preprocess_input()源码解析

preprocess_input(),这是tensorflow下keras自带的类似于一个归一化的函数;

其对传入的图像做了一些意想不到的事情,虽然能够加快图像的处理速度等优点,但是用起来还是不大方便,来回转化不够通用,虽然也有其自带的转化函数,但是总感觉有些问题;

现将此函数源码分析如下:

源码路径可以通过如下方式找到:

1.#在windows下的cmd或者linux下,输入:

python
from tensorflow import keras
print(keras.__path__)

2.#找到keras路径,然后根据引用进一步查找
#这里以inceptionv3为例:

from keras.applications.inception_v3 import preprocess_input
#找到keras下的applications下的inception_v3:
#打开init文件:

from tensorflow.python.keras._impl.keras.applications import InceptionV3
from tensorflow.python.keras._impl.keras.applications.densenet import decode_predictions
from tensorflow.python.keras._impl.keras.applications.inception_v3 import preprocess_input

#根据如上引用找到tensorflow下python下keras下_impl下keras下applications下inception_v3:
#找到preprocess_input()函数:

@tf_export('keras.applications.nasnet.preprocess_input',
           'keras.applications.inception_v3.preprocess_input')
def preprocess_input(x):
  """Preprocesses a numpy array encoding a batch of 
from libs.PipeLine import PipeLine, ScopedTiming from libs.AIBase import AIBase from libs.AI2D import Ai2d import os import ujson from media.media import * from time import * import nncase_runtime as nn import ulab.numpy as np import time import image import aidemo import random import gc import sys # 自定义人脸检测任务类 class FaceDetApp(AIBase): def __init__(self,kmodel_path,model_input_size,anchors,confidence_threshold=0.25,nms_threshold=0.3,rgb888p_size=[1280,720],display_size=[1920,1080],debug_mode=0): super().__init__(kmodel_path,model_input_size,rgb888p_size,debug_mode) # kmodel路径 self.kmodel_path=kmodel_path # 检测模型输入分辨率 self.model_input_size=model_input_size # 置信度阈值 self.confidence_threshold=confidence_threshold # nms阈值 self.nms_threshold=nms_threshold self.anchors=anchors # sensor给到AI的图像分辨率,宽16字节对齐 self.rgb888p_size=[ALIGN_UP(rgb888p_size[0],16),rgb888p_size[1]] # 视频输出VO分辨率,宽16字节对齐 self.display_size=[ALIGN_UP(display_size[0],16),display_size[1]] # debug模式 self.debug_mode=debug_mode # 实例化Ai2d,用于实现模型预处理 self.ai2d=Ai2d(debug_mode) # 设置Ai2d的输入输出格式和类型 self.ai2d.set_ai2d_dtype(nn.ai2d_format.NCHW_FMT,nn.ai2d_format.NCHW_FMT,np.uint8, np.uint8) # 配置预处理操作,这里使用了pad和resize,Ai2d支持crop/shift/pad/resize/affine,具体代码请打开/sdcard/app/libs/AI2D.py查看 def config_preprocess(self,input_image_size=None): with ScopedTiming("set preprocess config",self.debug_mode > 0): # 初始化ai2d预处理配置,默认为sensor给到AI的尺寸,可以通过设置input_image_size自行修改输入尺寸 ai2d_input_size=input_image_size if input_image_size else self.rgb888p_size # 计算padding参数,并设置padding预处理 self.ai2d.pad(self.get_pad_param(), 0, [104,117,123]) # 设置resize预处理 self.ai2d.resize(nn.interp_method.tf_bilinear, nn.interp_mode.half_pixel) # 构建预处理流程,参数为预处理输入tensor的shape和预处理输出的tensor的shape self.ai2d.build([1,3,ai2d_input_size[1],ai2d_input_size[0]],[1,3,self.model_input_size[1],self.model_input_size[0]]) # 自定义后处理,results是模型输出的array列表,这里调用了aidemo库的face_det_post_process接口 def postprocess(self,results): with ScopedTiming("postprocess",self.debug_mode > 0): res = aidemo.face_det_post_process(self.confidence_threshold,self.nms_threshold,self.model_input_size[0],self.anchors,self.rgb888p_size,results) if len(res)==0: return res else: return res[0] # 计算padding参数 def get_pad_param(self): dst_w = self.model_input_size[0] dst_h = self.model_input_size[1] # 计算最小的缩放比例,等比例缩放 ratio_w = dst_w / self.rgb888p_size[0] ratio_h = dst_h / self.rgb888p_size[1] if ratio_w < ratio_h: ratio = ratio_w else: ratio = ratio_h new_w = (int)(ratio * self.rgb888p_size[0]) new_h = (int)(ratio * self.rgb888p_size[1]) dw = (dst_w - new_w) / 2 dh = (dst_h - new_h) / 2 top = (int)(round(0)) bottom = (int)(round(dh * 2 + 0.1)) left = (int)(round(0)) right = (int)(round(dw * 2 - 0.1)) return [0,0,0,0,top, bottom, left, right] # 自定义人脸解析任务类 class FaceParseApp(AIBase): def __init__(self,kmodel_path,model_input_size,rgb888p_size=[1920,1080],display_size=[1920,1080],debug_mode=0): super().__init__(kmodel_path,model_input_size,rgb888p_size,debug_mode) # kmodel路径 self.kmodel_path=kmodel_path # 检测模型输入分辨率 self.model_input_size=model_input_size # sensor给到AI的图像分辨率,宽16字节对齐 self.rgb888p_size=[ALIGN_UP(rgb888p_size[0],16),rgb888p_size[1]] # 视频输出VO分辨率,宽16字节对齐 self.display_size=[ALIGN_UP(display_size[0],16),display_size[1]] # debug模式 self.debug_mode=debug_mode # 实例化Ai2d,用于实现模型预处理 self.ai2d=Ai2d(debug_mode) # 设置Ai2d的输入输出格式和类型 self.ai2d.set_ai2d_dtype(nn.ai2d_format.NCHW_FMT,nn.ai2d_format.NCHW_FMT,np.uint8, np.uint8) # 配置预处理操作,这里使用了affine,Ai2d支持crop/shift/pad/resize/affine,具体代码请打开/sdcard/app/libs/AI2D.py查看 def config_preprocess(self,det,input_image_size=None): with ScopedTiming("set preprocess config",self.debug_mode > 0): # 初始化ai2d预处理配置,默认为sensor给到AI的尺寸,可以通过设置input_image_size自行修改输入尺寸 ai2d_input_size=input_image_size if input_image_size else self.rgb888p_size # 计算仿射变换矩阵并设置affine预处理 matrix_dst = self.get_affine_matrix(det) self.ai2d.affine(nn.interp_method.cv2_bilinear,0, 0, 127, 1,matrix_dst) # 构建预处理流程,参数为预处理输入tensor的shape和预处理输出的tensor的shape self.ai2d.build([1,3,ai2d_input_size[1],ai2d_input_size[0]],[1,3,self.model_input_size[1],self.model_input_size[0]]) # 自定义后处理,results是模型输出的array列表,这里将第一个输出返回 def postprocess(self,results): with ScopedTiming("postprocess",self.debug_mode > 0): return results[0] def get_affine_matrix(self,bbox): # 获取仿射矩阵,用于将边界框映射到模型输入空间 with ScopedTiming("get_affine_matrix", self.debug_mode > 1): # 设置缩放因子 factor = 2.7 # 从边界框提取坐标和尺寸 x1, y1, w, h = map(lambda x: int(round(x, 0)), bbox[:4]) # 模型输入大小 edge_size = self.model_input_size[1] # 平移距离,使得模型输入空间的中心对准原点 trans_distance = edge_size / 2.0 # 计算边界框中心点的坐标 center_x = x1 + w / 2.0 center_y = y1 + h / 2.0 # 计算最大边长 maximum_edge = factor * (h if h > w else w) # 计算缩放比例 scale = edge_size * 2.0 / maximum_edge # 计算平移参数 cx = trans_distance - scale * center_x cy = trans_distance - scale * center_y # 创建仿射矩阵 affine_matrix = [scale, 0, cx, 0, scale, cy] return affine_matrix # 人脸解析任务 class FaceParse: def __init__(self,face_det_kmodel,face_parse_kmodel,det_input_size,parse_input_size,anchors,confidence_threshold=0.25,nms_threshold=0.3,rgb888p_size=[1920,1080],display_size=[1920,1080],debug_mode=0): # 人脸检测模型路径 self.face_det_kmodel=face_det_kmodel # 人脸解析模型路径 self.face_pose_kmodel=face_parse_kmodel # 人脸检测模型输入分辨率 self.det_input_size=det_input_size # 人脸解析模型输入分辨率 self.parse_input_size=parse_input_size # anchors self.anchors=anchors # 置信度阈值 self.confidence_threshold=confidence_threshold # nms阈值 self.nms_threshold=nms_threshold # sensor给到AI的图像分辨率,宽16字节对齐 self.rgb888p_size=[ALIGN_UP(rgb888p_size[0],16),rgb888p_size[1]] # 视频输出VO分辨率,宽16字节对齐 self.display_size=[ALIGN_UP(display_size[0],16),display_size[1]] # debug_mode模式 self.debug_mode=debug_mode # 人脸检测任务类实例 self.face_det=FaceDetApp(self.face_det_kmodel,model_input_size=self.det_input_size,anchors=self.anchors,confidence_threshold=self.confidence_threshold,nms_threshold=self.nms_threshold,rgb888p_size=self.rgb888p_size,display_size=self.display_size,debug_mode=0) # 人脸解析实例 self.face_parse=FaceParseApp(self.face_pose_kmodel,model_input_size=self.parse_input_size,rgb888p_size=self.rgb888p_size,display_size=self.display_size) # 人脸检测预处理配置 self.face_det.config_preprocess() # run函数 def run(self,input_np): # 执行人脸检测 det_boxes=self.face_det.run(input_np) parse_res=[] for det_box in det_boxes: # 对检测到每一个人脸进行人脸解析 self.face_parse.config_preprocess(det_box) res=self.face_parse.run(input_np) parse_res.append(res) return det_boxes,parse_res # 绘制人脸解析效果 def draw_result(self,pl,dets,parse_res): pl.osd_img.clear() if dets: draw_img_np = np.zeros((self.display_size[1],self.display_size[0],4),dtype=np.uint8) draw_img=image.Image(self.display_size[0], self.display_size[1], image.ARGB8888,alloc=image.ALLOC_REF,data=draw_img_np) for i,det in enumerate(dets): # (1)将人脸检测框画到draw_img x, y, w, h = map(lambda x: int(round(x, 0)), det[:4]) x = x * self.display_size[0] // self.rgb888p_size[0] y = y * self.display_size[1] // self.rgb888p_size[1] w = w * self.display_size[0] // self.rgb888p_size[0] h = h * self.display_size[1] // self.rgb888p_size[1] aidemo.face_parse_post_process(draw_img_np,self.rgb888p_size,self.display_size,self.parse_input_size[0],det.tolist(),parse_res[i]) pl.osd_img.copy_from(draw_img) if __name__=="__main__": # 显示模式,默认"hdmi",可以选择"hdmi"和"lcd",k230d受限于内存不支持 display_mode="hdmi" if display_mode=="hdmi": display_size=[1920,1080] else: display_size=[800,480] # 人脸检测模型路径 face_det_kmodel_path="/sdcard/examples/kmodel/face_detection_320.kmodel" # 人脸解析模型路径 face_parse_kmodel_path="/sdcard/examples/kmodel/face_parse.kmodel" # 其他参数 anchors_path="/sdcard/examples/utils/prior_data_320.bin" rgb888p_size=[1920,1080] face_det_input_size=[320,320] face_parse_input_size=[320,320] confidence_threshold=0.5 nms_threshold=0.2 anchor_len=4200 det_dim=4 anchors = np.fromfile(anchors_path, dtype=np.float) anchors = anchors.reshape((anchor_len,det_dim)) # 初始化PipeLine,只关注传给AI的图像分辨率,显示的分辨率 pl=PipeLine(rgb888p_size=rgb888p_size,display_size=display_size,display_mode=display_mode) pl.create() fp=FaceParse(face_det_kmodel_path,face_parse_kmodel_path,det_input_size=face_det_input_size,parse_input_size=face_parse_input_size,anchors=anchors,confidence_threshold=confidence_threshold,nms_threshold=nms_threshold,rgb888p_size=rgb888p_size,display_size=display_size) try: while True: os.exitpoint() with ScopedTiming("total",1): img=pl.get_frame() # 获取当前帧 det_boxes,parse_res=fp.run(img) # 推理当前帧 fp.draw_result(pl,det_boxes,parse_res) # 绘制当前帧推理结果 pl.show_image() # 展示推理效果 gc.collect() except Exception as e: sys.print_exception(e) finally: fp.face_det.deinit() fp.face_parse.deinit() pl.destroy() 以上是全部代码,请帮我解决问题 Traceback (most recent call last): File "<stdin>", line 156, in <module> Exception: IDE interrupt MPY: soft reboot CanMV v1.2.2(based on Micropython e00a144) on 2025-06-16; k230_canmv_lckfb with K230
最新发布
07-14
<think>好的,我现在需要详细解释一下用户提供的代码行`example_input = torch.rand(1, 3, 224, 224)`。首先,我要确保自己完全理解这行代码的作用和各个参数的含义。用户可能对PyTorch不太熟悉,或者刚入门,需要了解张量的创建和参数设置。 首先,`torch.rand`是PyTorch中生成随机张量的函数。括号里的参数是张量的形状。这里的四个数字`(1, 3, 224, 224)`代表四个维度。我需要明确每个维度的意义。通常在图像处理中,张量的形状遵循特定的格式,比如批量大小、通道数、高度、宽度。 接下来,我需要考虑用户的背景。他们可能在将PyTorch模型转换为TorchScript时遇到了问题,或者在准备输入数据时不清楚如何正确设置形状。因此,详细解释每个维度及其在模型中的作用会很有帮助。用户可能想知道为什么选择这样的形状,以及是否可以根据自己的需求调整这些参数。 另外,用户可能会混淆`torch.rand`和其他类似的函数,比如`torch.randn`或者`torch.zeros`。简要比较这些函数的区别可以增加答案的全面性。同时,强调`example_input`在模型跟踪(tracing)过程中的作用也很重要,即用于生成模型的计算图。 还需要注意数据类型和设备的问题。默认情况下,`torch.rand`生成的张量是在CPU上的,数据类型是float32。如果模型在GPU上运行,可能需要将张量移动到GPU上,但在这个例子中可能没有涉及,所以可以提到这一点作为扩展知识。 用户可能还会关心为什么选择特定的数值,比如1作为批量大小,3作为通道数,224作为高度和宽度。解释这些数值的典型应用场景,比如ResNet模型的处理,可以增强答案的相关性。此外,强调输入形状必须与模型期望的输入一致,以避免错误,这一点非常重要。 最后,考虑到用户可能希望在实际应用中使用自己的数据,可以简要提到如何将真实数据转换为合适的张量格式,比如使用图像加载库和预处理步骤。但在这个问题中,重点还是解释给定的代码行,所以这部分可以作为补充说明。 总结来说,我需要分步骤详细解释每个参数的含义,函数的作用,以及其在模型转换中的重要性,同时覆盖可能的常见问题和注意事项,确保用户能够全面理解这行代码的意义和应用场景。</think>以下是对`example_input = torch.rand(1, 3, 224, 224)`的详细解析: --- ### 一、代码作用 这行代码用于**生成一个符合深度学习模型输入要求的随机测试张量**,主要用于: 1. 模型转换时的示例输入(如转换为TorchScript格式) 2. 验证模型前向传播的可行性 3. 测试输入输出维度是否匹配 --- ### 二、参数详解 函数格式:`torch.rand(*size)` ```python example_input = torch.rand(1, 3, 224, 224) # 参数对应维度: (N, C, H, W) ``` #### 1. 维度说明(4D张量) | 维度位置 | 参数值 | 专业术语 | 实际意义 | |----------|--------|-------------------|-----------------------------------| | 第1维 | 1 | Batch Size | 批量大小(同时处理的样本数量) | | 第2维 | 3 | Channels | 图像通道数(RGB三通道) | | 第3维 | 224 | Height | 图像高度(像素尺寸) | | 第4维 | 224 | Width | 图像宽度(像素尺寸) | #### 2. 数值特性 - **数值范围**:均匀分布在$[0, 1)$区间(与`torch.randn`的正态分布不同) - **数据类型**:默认`torch.float32` - **设备位置**:默认在CPU内存中(未指定GPU时) --- ### 三、典型应用场景 #### 1. 模型转换示例(配合`torch.jit.trace`) ```python # 当使用ResNet等CNN模型时 model = torchvision.models.resnet18(pretrained=True) traced_model = torch.jit.trace(model, example_input) # 需要与模型输入维度严格匹配 ``` #### 2. 输入规范验证 ```python print(model(example_input).shape) # 验证输出维度是否符合预期 # 输出示例:torch.Size([1, 1000]) 表示1000分类结果 ``` --- ### 四、重要注意事项 1. **维度顺序必须与模型预期严格一致** - 部分模型使用$(N, H, W, C)$格式(如TF/Keras风格),需特别注意 - 可通过`model.forward`的文档或源码确认输入要求 2. **实际应用时的替换** ```python # 真实数据应替换为: real_input = torch.stack([preprocess(img) for img in batch_imgs]) ``` 3. **设备一致性** ```python # 如果模型在GPU上,需要匹配设备 example_input = torch.rand(1,3,224,224).to("cuda") ``` --- ### 五、相关函数对比 | 函数 | 数值分布 | 典型用途 | |--------------------|---------------|---------------------------| | `torch.rand()` | 均匀分布[0,1) | 生成测试输入(本文示例) | | `torch.randn()` | 标准正态分布 | 初始化网络权重 | | `torch.randint()` | 整数均匀分布 | 生成标签数据 | | `torch.zeros()` | 全零矩阵 | 初始化缓冲区 | --- ### 六、可视化理解 对于输入张量$(1,3,224,224)$,可以理解为: ``` 1个样本 -> 3个颜色通道(R/G/B) -> 224行像素 -> 224列像素 ``` 实际内存排列示意图: $[ [[[0.12, 0.45, ...], ...224列], ...224行], ...3通道 ]$(共$1 \times 3 \times 224 \times 224 = 150,528$个浮点数) --- 通过这种标准化的输入格式,可以确保CNN模型正确执行卷积等空间操作,同时与常见预训练模型的输入规范(如ImageNet标准)保持一致。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值