0%

前处理

摘要

  • 模型前处理相关学习笔记

深度学习模型部署 前处理

在深度学习模型的部署过程中,前处理是一个至关重要的步骤。前处理的目标是将原始数据转换为模型可以接受的格式,以确保推理结果的准确性和一致性。以下是前处理的一些常见操作及其实现方法。


前处理的主要步骤

1. 数据加载

  • 从文件、摄像头、传感器、API 等读取数据。
  • 支持的格式可能包括图像(JPEG/PNG)、文本、视频、音频等。
  • 常用库:
    • 图像:OpenCVPillow
    • 文本:NLTKspaCy
    • 音频:librosatorchaudio
    • 视频:OpenCVmoviepy

2. 尺寸调整 (Resizing)

  • 模型通常需要固定大小的输入,例如 224x224。
  • 工具:
    • Python:
      1
      2
      import cv2
      resized = cv2.resize(image, (224, 224))
    • C++ (OpenCV):
      1
      cv::resize(image, resized_image, cv::Size(224, 224));

3. 归一化 (Normalization)

  • 将输入数据的像素值范围调整到 [0, 1][-1, 1]
  • 公式:
    [
    x_{\text{normalized}} = \frac{x - \text{mean}}{\text{std}}
    ]
  • 常用库实现:
    • PyTorch:
      1
      2
      3
      import torchvision.transforms as transforms
      transform = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
      normalized_image = transform(image)

4. 数据格式转换

  • 深度学习模型可能需要特定的数据格式(例如 NHWC 或 NCHW)。
    • NHWC: [Batch, Height, Width, Channels](TensorFlow 通常使用)
    • NCHW: [Batch, Channels, Height, Width](PyTorch 通常使用)
  • 转换:
    1
    2
    import numpy as np
    nhwc_image = image.transpose(0, 2, 3, 1) # NCHW -> NHWC

5. 类型转换

  • 确保数据的类型与模型要求一致,例如 float32int8 等。
  • 转换:
    1
    float_image = image.astype('float32')

6. 数据归一化与标准化的结合

  • 对于图像:
    • 首先缩放到 [0, 1] 范围。
    • 再进行归一化(减去均值,除以标准差)。
  • 对于文本或序列数据:
    • 可能需要 Tokenization 和 Padding。

7. 其他特定处理

  • 数据增强:裁剪、旋转、翻转(在推理时一般用于 TTA)。
  • 嵌入:对文本进行词嵌入转换。
  • 频谱图:将音频信号转换为频谱图。

示例代码

以下是一个典型的图像模型的前处理示例,使用 Python:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import cv2
import numpy as np

def preprocess_image(image_path, input_size=(224, 224)):
# 加载图像
image = cv2.imread(image_path)
if image is None:
raise ValueError("Image not found or unable to read!")

# 调整大小
resized = cv2.resize(image, input_size)

# 转换为浮点数并归一化到 [0, 1]
normalized = resized / 255.0

# 转换为 NCHW 格式
nchw_image = np.transpose(normalized, (2, 0, 1))

# 增加 Batch 维度并转换为 float32
batch_image = np.expand_dims(nchw_image, axis=0).astype(np.float32)

return batch_image

部署中的前处理工具

  1. TensorFlow/TF-Serving

    • 使用 tf.image 模块进行前处理。
    • 可将前处理代码直接集成到模型中(SavedModel)。
  2. PyTorch/TorchServe

    • 使用 torchvision.transforms 执行前处理。
    • 在自定义 Handler 中实现前处理。
  3. ONNX Runtime

    • 在推理时依赖外部前处理,但支持优化后的动态尺寸输入。
  4. OpenCV/DNN 模块

    • OpenCV 支持直接加载和推理模型,可在前处理阶段使用其高效工具。

前处理常见问题与优化

  1. 不匹配问题

    • 原因:模型训练和推理时的前处理设置不同。
    • 解决:确保推理阶段与训练一致(归一化参数、数据格式等)。
  2. 性能问题

    • 原因:前处理耗时过长。
    • 解决:
      • 使用并行库(如 DALI)。
      • 在 GPU/TPU 上完成前处理。
  3. 动态尺寸

    • 原因:输入尺寸不固定。
    • 解决:使用动态尺寸模型,或在前处理阶段适配输入。

如果你有具体的部署场景(如平台或数据类型),我可以提供更细致的实现建议!

前处理 数据加载

在深度学习模型部署中,前处理的目的是将原始输入数据转换为模型可以接受的格式和结构。数据加载是前处理的重要组成部分,涉及从存储中读取数据、对数据进行解析、归一化、格式化等步骤,为后续的推理做好准备。

以下是深度学习模型部署中 数据加载 的详细解析:


1. 数据加载的核心任务

数据加载的主要任务包括:

  1. 从各种来源读取数据

    • 常见数据来源:文件系统、数据库、API、消息队列等。
    • 文件格式:图片(JPEG/PNG)、视频(MP4)、音频(WAV/MP3)、文本(JSON/CSV)、二进制数据等。
  2. 解析和转换数据

    • 解析数据格式(如图片解码、JSON 解析)。
    • 将数据转化为模型可用的张量(Tensor)格式。
  3. 批量加载和优化性能

    • 支持批量加载(Batching)以提高吞吐量。
    • 利用多线程或异步加载优化性能。
  4. 对输入数据进行前处理

    • 标准化、归一化。
    • 调整大小、裁剪、填充。
    • 数据增强(如旋转、翻转等)。

2. 数据加载的典型步骤

(1) 数据读取

根据数据来源和格式,选择适当的读取方法:

  • 本地文件系统: 使用操作系统原生文件读写函数(如 open()fopen())。
  • 云存储/网络资源: 使用库(如 requestsboto3)下载文件。
  • 数据库: 使用 SQL 或 NoSQL 查询获取数据。

示例(读取本地图片):

1
2
from PIL import Image
image = Image.open("image.jpg")

(2) 数据解析

  • 将原始数据解析为内存中的对象。例如:
    • 图片数据解码为像素矩阵。
    • JSON 数据解析为 Python 字典。
    • CSV 数据解析为 DataFrame 或数组。

(3) 数据转换为张量

将解析后的数据转换为深度学习框架支持的张量(如 PyTorch 的 torch.Tensor 或 TensorFlow 的 tf.Tensor)。

1
2
3
4
5
import torch
from torchvision import transforms

transform = transforms.ToTensor()
tensor = transform(image)

(4) 数据预处理

根据模型需求对数据进行调整:

  • 归一化: 将像素值缩放到 [0, 1] 或 [-1, 1] 区间。
  • 调整大小: 将图片调整为固定尺寸。
  • 格式转换: 如 RGB -> BGR 或 NHWC -> NCHW。

示例:

1
2
3
4
5
6
transform = transforms.Compose([
transforms.Resize((224, 224)), # 调整大小
transforms.ToTensor(), # 转为张量
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) # 归一化
])
processed_image = transform(image)

3. 高效数据加载技巧

(1) 批量加载

通过批量加载数据,可以减少 I/O 操作的开销,提高吞吐量。

  • 示例(PyTorch DataLoader):
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    from torch.utils.data import DataLoader, Dataset

    class CustomDataset(Dataset):
    def __init__(self, file_paths, transform=None):
    self.file_paths = file_paths
    self.transform = transform

    def __len__(self):
    return len(self.file_paths)

    def __getitem__(self, idx):
    image = Image.open(self.file_paths[idx])
    if self.transform:
    image = self.transform(image)
    return image

    dataset = CustomDataset(file_paths=["img1.jpg", "img2.jpg"], transform=transform)
    data_loader = DataLoader(dataset, batch_size=32, shuffle=True)

(2) 异步加载

使用多线程或多进程加载数据,在数据加载的同时进行推理。

  • 示例(PyTorch 的多进程加载):
    1
    data_loader = DataLoader(dataset, batch_size=32, shuffle=True, num_workers=4)

(3) 数据缓存

对于频繁使用的数据,可以将其缓存到内存或更快的存储设备(如 SSD),减少加载时间。


4. 常见的数据加载场景

(1) 图片数据加载

  • 格式: JPEG、PNG、TIFF 等。
  • 前处理:
    • 调整大小、裁剪。
    • 归一化为 [0, 1] 或 [-1, 1]。
  • 库支持: OpenCV、Pillow、Torchvision、TensorFlow。

(2) 视频数据加载

  • 格式: MP4、AVI 等。
  • 前处理:
    • 抽帧、调整帧率。
    • 归一化。
  • 库支持: OpenCV、FFmpeg、Decord。

(3) 文本数据加载

  • 格式: JSON、CSV、纯文本。
  • 前处理:
    • 分词、去停用词。
    • 将文本转换为向量(如词嵌入)。
  • 库支持: pandas、NLTK、Hugging Face。

(4) 音频数据加载

  • 格式: WAV、MP3。
  • 前处理:
    • 采样率调整。
    • 转换为梅尔频谱或 MFCC 特征。
  • 库支持: librosa、torchaudio。

5. 数据加载中的常见问题及优化

问题 1:数据加载瓶颈

  • 原因: 数据加载速度不足以跟上推理速度。
  • 优化:
    • 增加 num_workers 使用多线程/多进程。
    • 缓存数据。
    • 使用高效的数据格式(如 TFRecord)。

问题 2:内存占用过高

  • 原因: 一次性加载过多数据。
  • 优化:
    • 使用生成器或流式加载。
    • 控制批量大小。

问题 3:数据预处理耗时长

  • 原因: 复杂的预处理步骤在加载时完成。
  • 优化:
    • 将预处理离线完成,保存为中间格式。
    • 使用 GPU 加速数据预处理(如 DALI)。

6. 高级工具与框架支持

  • NVIDIA DALI(Data Loading Library):

    • 高效的数据加载和预处理库,支持 GPU 加速。
    • 示例:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      from nvidia.dali.pipeline import Pipeline
      import nvidia.dali.ops as ops

      class SimplePipeline(Pipeline):
      def __init__(self, batch_size, num_threads, device_id):
      super(SimplePipeline, self).__init__(batch_size, num_threads, device_id)
      self.decode = ops.ImageDecoder(device="mixed")
      self.resize = ops.Resize(resize_x=224, resize_y=224)

      def define_graph(self):
      images = self.decode(self.input)
      return self.resize(images)

      pipe = SimplePipeline(batch_size=32, num_threads=4, device_id=0)
  • TensorFlow Data API:

    • 支持高效的输入管道。
    • 示例:
      1
      2
      3
      4
      5
      import tensorflow as tf

      dataset = tf.data.Dataset.list_files("images/*.jpg")
      dataset = dataset.map(lambda x: preprocess(x))
      dataset = dataset.batch(32).prefetch(tf.data.AUTOTUNE)

总结

数据加载在深度学习模型部署中至关重要。通过高效的读取、解析、转换、批量加载和预处理,能够显著提升模型推理的性能与可靠性。根据具体场景选择合适的工具和优化策略,可以大大改善部署效果。

图像数据转为模型可用的张量格式 详解

将图像数据转换为深度学习模型可用的张量格式,是图像处理和模型前处理中的关键步骤。不同的深度学习框架(如 TensorFlow、PyTorch)对张量的具体格式要求略有不同,但总体过程类似。

以下是将图像数据转为模型可用的张量格式的详细步骤和注意事项:


1. 张量的基本要求

张量是一个多维数组,常见的格式包括:

  1. 形状(Shape): 模型通常要求特定形状的输入,例如 (Batch, Channels, Height, Width)(Batch, Height, Width, Channels)
  2. 数据类型(Data Type): 常用 float32float16
  3. 数值范围:
    • 一般要求归一化为 [0, 1] 或标准化为均值为 0、方差为 1。
    • 部分模型(如 ResNet、MobileNet)可能要求特定的归一化范围或通道顺序。

2. 转换步骤

(1) 读取图像数据

  • 使用图像处理库读取图像文件,将其转化为像素矩阵(通常是 Height x Width x Channels 格式)。
  • 常用库:
    • OpenCV (cv2): 默认读取为 BGR 格式。
    • Pillow (PIL): 默认读取为 RGB 格式。

示例(读取图片):

1
2
from PIL import Image
image = Image.open("image.jpg") # 使用 Pillow 读取图片

(2) 调整尺寸

  • 深度学习模型通常要求固定尺寸的输入图像,例如 224x224
  • 可以通过调整大小(resize)、裁剪(crop)、填充(pad)等方式实现。

示例(调整大小):

1
image = image.resize((224, 224))  # 调整到 224x224

(3) 转换为数组

  • 将图像对象转换为数值数组(通常为 NumPy 数组)。

示例(Pillow 转 NumPy):

1
2
import numpy as np
image_array = np.array(image) # 转换为 NumPy 数组

(4) 归一化或标准化

  • 将像素值范围从 [0, 255] 转换为 [0, 1] 或 [-1, 1]。
  • 如果模型要求,可以使用特定均值和标准差进行标准化。

示例(归一化为 [0, 1]):

1
image_array = image_array / 255.0

示例(标准化):

1
2
3
mean = [0.485, 0.456, 0.406]
std = [0.229, 0.224, 0.225]
image_array = (image_array - mean) / std

(5) 调整通道顺序

  • 不同框架要求的张量通道顺序可能不同:
    • PyTorch: 通道优先,即 (Channels, Height, Width)
    • TensorFlow/Keras: 通道最后,即 (Height, Width, Channels)
  • 可以通过 transpose 改变通道顺序。

示例(HWC 转为 CHW):

1
image_array = np.transpose(image_array, (2, 0, 1))  # 从 HWC 转为 CHW

(6) 转换为张量

  • 将 NumPy 数组转换为深度学习框架支持的张量。
  • 框架示例:
    • PyTorch:torch.Tensor
    • TensorFlow:tf.convert_to_tensor

示例(PyTorch 张量转换):

1
2
3
import torch
image_tensor = torch.tensor(image_array, dtype=torch.float32) # 转为张量
image_tensor = image_tensor.unsqueeze(0) # 增加 Batch 维度

示例(TensorFlow 张量转换):

1
2
3
import tensorflow as tf
image_tensor = tf.convert_to_tensor(image_array, dtype=tf.float32) # 转为张量
image_tensor = tf.expand_dims(image_tensor, axis=0) # 增加 Batch 维度

3. 不同框架的常见操作

(1) PyTorch

使用 torchvision.transforms 提供了高效的图像预处理工具。

示例:

1
2
3
4
5
6
7
8
9
10
11
from torchvision import transforms
from PIL import Image

transform = transforms.Compose([
transforms.Resize((224, 224)), # 调整大小
transforms.ToTensor(), # 转为张量并归一化为 [0, 1]
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) # 标准化
])

image = Image.open("image.jpg")
image_tensor = transform(image).unsqueeze(0) # 增加 Batch 维度

(2) TensorFlow

使用 tf.image 提供了一系列操作。

示例:

1
2
3
4
5
6
7
import tensorflow as tf

image = tf.io.read_file("image.jpg")
image = tf.image.decode_jpeg(image, channels=3)
image = tf.image.resize(image, [224, 224]) # 调整大小
image = image / 255.0 # 归一化
image = tf.expand_dims(image, axis=0) # 增加 Batch 维度

4. 常见问题与优化

问题 1:通道顺序错误

  • 模型可能因通道顺序不同而报错(如 TensorFlow 使用 NHWC,而 PyTorch 使用 NCHW)。
  • 解决: 确认模型要求并调整顺序。

问题 2:未归一化或标准化

  • 部分模型对输入的数值范围敏感,未归一化可能导致推理结果异常。
  • 解决: 检查模型要求并按需处理。

问题 3:性能瓶颈

  • 数据加载和预处理可能成为瓶颈,尤其是在实时推理中。
  • 解决:
    • 使用多线程/多进程。
    • 将预处理步骤迁移到 GPU(如 NVIDIA DALI)。
    • 提前预处理并保存为高效格式(如 TFRecord)。

5. 总结

将图像数据转为模型可用的张量格式是模型推理的关键步骤,核心流程包括:

  1. 读取图像数据(文件、内存或流式读取)。
  2. 调整尺寸、归一化、标准化。
  3. 转换通道顺序和数据类型。
  4. 将数据打包为张量格式并加入批量维度。

不同框架提供了便利的工具和 API 支持,高效实现图像的张量化,能够显著提升模型的推理性能和兼容性。

前处理中的归一化 详解

深度学习前处理中的归一化详解

归一化是深度学习模型训练和推理中的重要步骤之一,旨在将输入数据的特征值范围调整到特定范围或分布,以提高模型的收敛速度和预测稳定性。本文将详细解析归一化的概念、目的、方法、应用场景和注意事项。


1. 为什么需要归一化?

  1. 减少特征尺度差异:

    • 输入数据可能具有不同的特征范围(例如像素值范围为 [0, 255],而温度值范围为 [-30, 50])。
    • 归一化可以让特征值具有相似的尺度,避免某些特征对模型的影响过大。
  2. 加速模型收敛:

    • 无归一化的数据可能导致梯度下降过程缓慢或震荡,归一化能够稳定梯度下降。
  3. 增强数值稳定性:

    • 极端数值可能导致计算不稳定,归一化可以避免溢出或下溢。
  4. 适应特定模型需求:

    • 某些预训练模型要求输入数据在特定范围(如 [0, 1][-1, 1])或具有特定的均值和标准差。

2. 常见的归一化方法

归一化的方法根据应用场景和数据类型有所不同,以下是常见的归一化技术。

(1) Min-Max 归一化

  • 公式:
    [
    x_{\text{norm}} = \frac{x - x_{\min}}{x_{\max} - x_{\min}}
    ]

  • 范围: 通常将数据归一化到 [0, 1],或通过线性变换调整为其他范围(如 [-1, 1])。

  • 应用场景:

    • 图像像素值归一化到 [0, 1]
    • 特征值范围固定的数据。
  • 示例:

    1
    2
    3
    4
    5
    6
    import numpy as np
    data = np.array([50, 100, 150, 200])
    data_min = np.min(data)
    data_max = np.max(data)
    normalized_data = (data - data_min) / (data_max - data_min)
    print(normalized_data) # 输出 [0. , 0.333, 0.666, 1. ]

(2) 均值-标准差标准化(Z-Score 标准化)

  • 公式:
    [
    x_{\text{norm}} = \frac{x - \mu}{\sigma}
    ]
    其中 ( \mu ) 是均值,( \sigma ) 是标准差。

  • 范围: 数据转换为均值为 0,标准差为 1 的分布。

  • 应用场景:

    • 特征值分布不固定(如自然语言处理中的词向量)。
    • 深度学习预训练模型(如 ImageNet 预训练模型)常使用固定均值和标准差归一化。
  • 示例:

    1
    2
    3
    4
    mean = np.mean(data)
    std = np.std(data)
    standardized_data = (data - mean) / std
    print(standardized_data)

(3) 归一化到特定均值和标准差

  • 公式:
    [
    x_{\text{norm}} = \frac{x - \mu}{\sigma}
    ]
    并根据目标分布调整:
    [
    x_{\text{scaled}} = x_{\text{norm}} \times \sigma_{\text{target}} + \mu_{\text{target}}
    ]

  • 应用场景:

    • 针对预训练模型(如 ResNet、VGG 等),调整到特定的均值和标准差。
  • 示例(PyTorch):

    1
    2
    from torchvision import transforms
    transform = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])

(4) 对数归一化(Log Normalization)

  • 公式:
    [
    x_{\text{norm}} = \log(x + 1)
    ]

  • 应用场景:

    • 数据分布具有较大偏态(如高光强度图像、文档字频统计)。
  • 注意:

    • 输入值必须非负。
  • 示例:

    1
    log_normalized_data = np.log(data + 1)

(5) 最大绝对值归一化

  • 公式:
    [
    x_{\text{norm}} = \frac{x}{\max(|x|)}
    ]
  • 范围: 归一化到 [-1, 1]
  • 应用场景:
    • 数据具有正负值,但范围不固定。

(6) L2 归一化

  • 公式:
    [
    x_{\text{norm}} = \frac{x}{|x|_2}
    ]
    其中 ( |x|_2 = \sqrt{\sum x_i^2} )。
  • 范围: 单位向量,适合向量空间建模。
  • 应用场景:
    • 特征向量的相似性计算(如余弦相似度)。

3. 图像数据中的归一化

在图像处理中,归一化的目标是将原始像素值(通常是 [0, 255])转换为深度学习模型所需的格式。

(1) 常见归一化方法

  1. 归一化到 [0, 1]
    • 公式:x / 255.0
    • 应用于大多数深度学习框架。
  2. 归一化到 [-1, 1]
    • 公式:(x / 127.5) - 1
    • 常用于 GAN 和部分图像处理模型。
  3. 均值和标准差标准化:
    • 对应 ImageNet 的 RGB 通道均值和标准差:
      • 均值:[0.485, 0.456, 0.406]
      • 标准差:[0.229, 0.224, 0.225]

(2) 示例代码

归一化到 [0, 1]

1
2
3
import numpy as np
image = np.random.randint(0, 256, (224, 224, 3), dtype=np.uint8)
image_normalized = image / 255.0

归一化到特定均值和标准差:

1
2
3
4
5
6
7
8
9
10
import torch
from torchvision import transforms

transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])

# 假设 image 是一个 PIL.Image 对象
normalized_image = transform(image)

4. 深度学习框架中的归一化工具

(1) PyTorch

torchvision.transforms.Normalize

  • 用法:
    1
    transforms.Normalize(mean, std)

(2) TensorFlow/Keras

tf.image.per_image_standardization 或手动实现归一化。


5. 注意事项

  1. 模型需求: 确保归一化过程符合模型的预处理要求。
  2. 一致性: 训练和推理时的归一化方式必须一致。
  3. 异常值处理: 对异常值进行裁剪或忽略,避免对归一化结果产生不利影响。

归一化是模型预处理中的关键步骤,能够显著提升模型性能。根据不同场景选择合适的归一化方法,有助于稳定和加速训练,同时提高推理精度。

归一化

  • 常用的方法是通过对原始数据进行线性变换把数据映射到 [0, 1] 或 [-1, 1]之间。主要是:
    • 为了数据处理方便,更加便捷快速。
    • 把有量纲表达式变为无量纲表达式,便于不同单位或量级的指标能够进行比较和加权。
  • 归一化是一种简化计算的方式,即将有量纲的表达式,经过变换,化为无量纲的表达式,成为 纯量
  • 变换函数为:
    归一化线性变换公式

标准化

  • 常用的方法是 z-score 标准化,经过处理后的数据均值为0,标准差为1
  • 在机器学习中,我们可能要处理不同种类的资料。例如,音讯和图片上的像素值,这些资料可能是高纬度的,资料标准化后使每个特征中的数值平均变为0(将每个特征的值都减掉原始资料中该特征的平均),标准差变为1,这个方法被广泛的使用在许多机器学习中,例如:支持向量机,逻辑回归和类神经网络
    标准化线性变换公式

归一化和标准化的区别

  • 归一化是将样本的特征值转换到同一量纲下把数据映射到 [0, 1]或者 [-1, 1]区间内,仅由变量的极值决定,因区间放缩法是归一化的一种。
  • 标准化是依照特征矩阵的列处理数据,其通过求z-score的方法,转换为标准正态分布,和整体样本分布相关,每个样本点都能对标准化产生影响。
  • 它们的相同点在于都能取消由于量纲不同引起的误差;都是一种线性变换,都是对向量X按照比例压缩再进行平移。

标准化和中心化的区别

  • 标准化是原始分数减去平均数然后除以标准差
  • 中心化是原始分数减去平均数。所以一般流程为先中心化再标准化。

无量纲

  • 无量纲,是通过某种方法能去表实际过程中的单位,从而简化计算。

为什么要归一化/标准化

  • 归一化/标准化实质是一种线性变换,线性变换有很多良好的性质,这些性质决定了对数据改变后不会造成失效,反而能提高数据的表现,这些性质是归一化/标准化的前提。比如有一个很重要的性质:线性变换不会改变原始数据的数值排序。

  • 简单来说有以下好处

    • 由于原始数据值的范围差异很大,因此在某些机器学习算法中,如果没有归一化,目标函数将无法正常工作。
感谢老板支持!敬礼(^^ゞ