You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何更高效地对数组进行独热编码?

问题描述

拥有约25000个类似下方“原始映射”的数组,需根据数值将每个数组拆分为3个分量(类似灰度图转RGB图),本质是实现独热编码。当前采用嵌套循环的方式实现,效率极低,处理全部数组时会耗尽内存;虽尝试过分批处理,但希望找到更优的数组拆分/独热编码方案,最终用于CNN训练。

原始映射示例

# Original Map:
# 0 0 0 1 1 1 0 0 0 0
# 0 0 1 1 1 1 1 0 0 0
# 0 1 1 2 2 2 1 1 0 0
# 1 1 1 2 2 2 1 1 1 0
# 0 1 1 2 2 2 1 1 0 0
# 0 0 1 1 1 1 1 0 0 0
# 0 0 0 1 1 1 0 0 0 0
# 0 0 0 0 0 0 0 0 0 0

# First component[0,;,;,0]   Second component[0,;,;,1] Last component[0,;,;,2]
# (Padding)                   (Good Die)                (Bad Die)

# 1 1 1 0 0 0 1 1 1 1        # 0 0 0 1 1 1 0 0 0 0    # 0 0 0 0 0 0 0 0 0 0
# 1 1 0 0 0 0 0 1 1 1        # 0 0 1 1 1 1 1 0 0 0    # 0 0 0 0 0 0 0 0 0 0
# 1 0 0 0 0 0 0 0 1 1        # 0 1 1 0 0 0 1 1 0 0    # 0 0 0 1 1 1 0 0 0 0
# 0 0 0 0 0 0 0 0 0 1        # 1 1 1 0 0 0 1 1 1 0    # 0 0 0 1 1 1 0 0 0 0
# 1 0 0 0 0 0 0 0 1 1        # 0 1 1 0 0 0 1 1 0 0    # 0 0 0 1 1 1 0 0 0 0
# 1 1 0 0 0 0 0 1 1 1        # 0 0 1 1 1 1 1 0 0 0    # 0 0 0 0 0 0 0 0 0 0
# 1 1 1 0 0 0 1 1 1 1        # 0 0 0 1 1 1 0 0 0 0    # 0 0 0 0 0 0 0 0 0 0
# 1 1 1 1 1 1 1 1 1 1        # 0 0 0 0 0 0 0 0 0 0    # 0 0 0 0 0 0 0 0 0 0

当前低效代码

reshaped = np.zeros((1,map_exm.shape[0], map_exm.shape[1], 3))
for h in range(map_exm.shape[0]):
  for w in range(map_exm.shape[1]):
    reshaped[0,h, w, map_exm[h][w]] = 1
优化方案

1. 用NumPy向量化操作替代嵌套循环

NumPy的向量化操作由C底层实现,速度比Python循环快几个数量级,同时内存分配更高效。推荐两种实现方式:

方法1:np.eye直接索引

import numpy as np

# 假设map_exm是单个形状为(H, W)的数组
num_classes = 3
# 直接生成独热编码数组,形状为(H, W, 3)
one_hot = np.eye(num_classes)[map_exm]
# 调整维度为(1, H, W, 3),匹配CNN输入格式
reshaped = one_hot[np.newaxis, ...]

方法2:广播式索引赋值

如果担心np.eye创建额外数组占用内存,可直接用广播索引赋值:

import numpy as np

num_classes = 3
reshaped = np.zeros((1, map_exm.shape[0], map_exm.shape[1], num_classes), dtype=np.int8)
# 利用NumPy高级索引直接批量赋值
reshaped[0, np.arange(map_exm.shape[0])[:, None], np.arange(map_exm.shape[1]), map_exm] = 1

注意:用np.int8/np.uint8替代默认的float64,可将内存占用降低75%以上,因为独热编码只有0和1,整数类型完全足够。

2. 批量处理+内存控制

如果25000个数组一次性处理内存不足,可结合向量化操作分批处理,比如每次处理100个:

import numpy as np

# 假设所有数据存储在all_maps中,形状为(25000, H, W)
batch_size = 100
num_classes = 3
H, W = all_maps.shape[1], all_maps.shape[2]
processed_batches = []

for i in range(0, len(all_maps), batch_size):
    # 取出当前批次
    batch = all_maps[i:i+batch_size]
    # 批量生成独热编码
    batch_one_hot = np.eye(num_classes)[batch]
    # 或者用广播赋值:
    # batch_one_hot = np.zeros((len(batch), H, W, num_classes), dtype=np.int8)
    # batch_one_hot[np.arange(len(batch))[:, None, None], np.arange(H)[:, None], np.arange(W), batch] = 1
    processed_batches.append(batch_one_hot)

# 合并所有批次(内存允许的情况),否则可直接用批次列表喂给训练流程
processed_data = np.concatenate(processed_batches, axis=0)

3. 用深度学习框架内置函数(适配CNN训练)

如果用TensorFlow/PyTorch训练,直接用框架自带的独热编码函数,不仅高效,还支持GPU加速,且能和训练流程无缝衔接:

TensorFlow版本

import tensorflow as tf

# 若数据是NumPy数组,先转为Tensor
map_tensor = tf.convert_to_tensor(all_maps, dtype=tf.int32)
# 生成独热编码,形状为(25000, H, W, 3)
one_hot = tf.one_hot(map_tensor, depth=3, axis=-1)

# 可直接结合tf.data.Dataset分批加载,无需提前处理全部数据
dataset = tf.data.Dataset.from_tensor_slices(one_hot).batch(32)

PyTorch版本

import torch
from torch.utils.data import DataLoader, TensorDataset

# 转为PyTorch LongTensor(one_hot要求输入为整数类型)
map_tensor = torch.tensor(all_maps, dtype=torch.long)
# 生成独热编码,形状为(25000, H, W, 3)
one_hot = torch.nn.functional.one_hot(map_tensor, num_classes=3)
# 调整为PyTorch常用的(批量, 通道, H, W)格式
one_hot = one_hot.permute(0, 3, 1, 2)

# 用DataLoader分批加载
dataset = TensorDataset(one_hot)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)

4. 极致内存优化:动态生成独热编码

若内存极度紧张,可在训练时动态生成独热编码,无需提前保存全部处理后的数据:

import torch
from torch.utils.data import Dataset, DataLoader

class MapDataset(Dataset):
    def __init__(self, maps):
        self.maps = maps
    
    def __len__(self):
        return len(self.maps)
    
    def __getitem__(self, idx):
        # 取出单张图
        map_data = self.maps[idx]
        # 动态生成独热编码
        one_hot = torch.nn.functional.one_hot(torch.tensor(map_data, dtype=torch.long), num_classes=3)
        # 转为PyTorch训练所需的(通道, H, W)格式
        return one_hot.permute(2, 0, 1)

# 加载数据,batch_size按需设置
dataset = MapDataset(all_maps)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)

这种方式每次仅加载一个批次的数据并生成独热编码,内存占用极小。

内容的提问来源于stack exchange,提问作者TeslaWasRobbed0710

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 08:52:03