keras自带数据集(横线生成器)

原文地址:AdetailedexampleofhowtousedatageneratorswithKeras引言在使用kears训练model的时候,一般会将所有的训练数据加载到内存中,然后喂给网络,但当内存有限,且数据量过大时,此方法则不再可用。此博客,将介绍如何在多核(多线程)上实时的生成数据,并立即的送入到模型当中训练。工具为keras。Tu…

大家好,又见面了,我是你们的朋友全栈君。

原文地址: A detailed example of how to use data generators with Keras

引言

在使用kears训练model的时候,一般会将所有的训练数据加载到内存中,然后喂给网络,但当内存有限,且数据量过大时,此方法则不再可用。此博客,将介绍如何在多核(多线程)上实时的生成数据,并立即的送入到模型当中训练。
工具为keras。

Tutorial

先看一下还未改进的版本:

import numpy as np
from keras.models import Sequential
#载入全部的数据!!
X, y = np.load('some_training_set_with_labels.npy')
#设计模型
model = Sequential()
[...] #网络结构
model.compile()
# 在数据集上进行模型训练
model.fit(x=X, y=y)

下面的结构将改变一次性载入全部数据的情况。接下来将介绍如何一步一步的构造数据生成器,此数据生成器也可应用在你自己的项目当中;复制下来,并根据自己的需求填充空白处。

定义

在构建之前先定义统一几个变量,并介绍几个小tips,对我们处理大的数据量很重要。
ID type为string,代表数据集中的某个样本。
调整以下结构,编译处理样本和他们的label:

1.新建一个词典名叫 partition

  • partition[‘train’] 为训练集的ID,type为list
  • partition[‘validation’] 为验证集的ID,type为list

2.新建一个词典名叫 * labels * ,根据ID可找到数据集中的样本,同样可通过labels[ID]找到样本标签。
举个例子:
假设训练集包含三个样本,ID分别为id-1,id-2和id-3,相应的label分别为0,1,2。验证集包含样本ID id-4,标签为 1。此时两个词典partitionlabels分别如下:

>>> partition
{
  
  'train': ['id-1', 'id-2', 'id-3'], 'validation': ['id-4']}
>>> labels
{
  
  'id-1': 0, 'id-2': 1, 'id-3': 2, 'id-4': 1}

为了模块化,将keras的代码与设计的类class分别放在两个不同的文件中,文件结构如下:

folder/
├── my_classes.py
├── keras_script.py
└── data/

data/ 中为数据集文件。

数据生成器(data generator)

接下来将介绍如何构建数据生成器 DataGenerator ,DataGenerator将实时的对训练模型feed数据。
接下来,将先初始化类。我们使此类继承自keras.utils.Sequence,这样我们可以使用多线程。

def __init__(self, list_IDs, labels, batch_size=32, dim=(32,32,32), n_channels=1, n_classes=10, shuffle=True):
    'Initialization'
    self.dim = dim
    self.batch_size = batch_size
    self.labels = labels
    self.list_IDs = list_IDs
    self.n_channels = n_channels
    self.n_classes = n_classes
    self.shuffle = shuffle
    self.on_epoch_end()

我们给了一些与数据相关的参数 dim,channels,classes,batch size ;方法 on_epoch_end 在一个epoch开始时或者结束时触发,shuffle决定是否在数据生成时要对数据进行打乱。

def on_epoch_end(self):
  'Updates indexes after each epoch'
  self.indexes = np.arange(len(self.list_IDs))
  if self.shuffle == True:
      np.random.shuffle(self.indexes)

另一个数据生成核心的方法__data_generation 是生成批数据。

def __data_generation(self, list_IDs_temp):
  'Generates data containing batch_size samples' # X : (n_samples, *dim, n_channels)
  # Initialization
  X = np.empty((self.batch_size, *self.dim, self.n_channels))
  y = np.empty((self.batch_size), dtype=int)

  # Generate data
  for i, ID in enumerate(list_IDs_temp):
      # Store sample
      X[i,] = np.load('data/' + ID + '.npy')

      # Store class
      y[i] = self.labels[ID]

  return X, keras.utils.to_categorical(y, num_classes=self.n_classes)

在数据生成期间,代码读取包含各个样本ID的代码ID.py.因为我们的代码是可以应用多线程的,所以可以采用更为复杂的操作,不用担心数据生成成为总体效率的瓶颈。
另外,我们使用Keras的方法keras.utils.to_categorical对label进行2值化
(比如,对6分类而言,第三个label则相应的变成 to [0 0 1 0 0 0]) 。
现在我们将要把这些部分进行组合,每一个请求需要一个batch的index,从0到所有的batch。此处定义在_len_ 中。
TODO

def __len__(self):
  'Denotes the number of batches per epoch'
  return int(np.floor(len(self.list_IDs) / self.batch_size))

现在,当相应的index的batch被选到,则生成器执行_getitem_方法来生成它。

def __getitem__(self, index):
  'Generate one batch of data'
  # Generate indexes of the batch
  indexes = self.indexes[index*self.batch_size:(index+1)*self.batch_size]

  # Find list of IDs
  list_IDs_temp = [self.list_IDs[k] for k in indexes]

  # Generate data
  X, y = self.__data_generation(list_IDs_temp)

  return X, y

完整的代码

import numpy as np
import keras

class DataGenerator(keras.utils.Sequence):
    'Generates data for Keras'
    def __init__(self, list_IDs, labels, batch_size=32, dim=(32,32,32), n_channels=1, n_classes=10, shuffle=True):
        'Initialization'
        self.dim = dim
        self.batch_size = batch_size
        self.labels = labels
        self.list_IDs = list_IDs
        self.n_channels = n_channels
        self.n_classes = n_classes
        self.shuffle = shuffle
        self.on_epoch_end()

    def __len__(self):
        'Denotes the number of batches per epoch'
        return int(np.floor(len(self.list_IDs) / self.batch_size))

    def __getitem__(self, index):
        'Generate one batch of data'
        # Generate indexes of the batch
        indexes = self.indexes[index*self.batch_size:(index+1)*self.batch_size]

        # Find list of IDs
        list_IDs_temp = [self.list_IDs[k] for k in indexes]

        # Generate data
        X, y = self.__data_generation(list_IDs_temp)

        return X, y

    def on_epoch_end(self):
        'Updates indexes after each epoch'
        self.indexes = np.arange(len(self.list_IDs))
        if self.shuffle == True:
            np.random.shuffle(self.indexes)

    def __data_generation(self, list_IDs_temp):
        'Generates data containing batch_size samples' # X : (n_samples, *dim, n_channels)
        # Initialization
        X = np.empty((self.batch_size, *self.dim, self.n_channels))
        y = np.empty((self.batch_size), dtype=int)

        # Generate data
        for i, ID in enumerate(list_IDs_temp):
            # Store sample
            X[i,] = np.load('data/' + ID + '.npy')

            # Store class
            y[i] = self.labels[ID]

        return X, keras.utils.to_categorical(y, num_classes=self.n_classes)

keras脚本

import numpy as np

from keras.models import Sequential
from my_classes import DataGenerator

# Parameters
params = {
  
  'dim': (32,32,32),
          'batch_size': 64,
          'n_classes': 6,
          'n_channels': 1,
          'shuffle': True}

# Datasets
partition = # IDs
labels = # Labels

# Generators
training_generator = DataGenerator(partition['train'], labels, **params)
validation_generator = DataGenerator(partition['validation'], labels, **params)

# Design model
model = Sequential()
[...] # Architecture
model.compile()

# Train model on dataset
model.fit_generator(generator=training_generator,
                    validation_data=validation_generator,
                    use_multiprocessing=True,
                    n_workers=6)

n_workers设置线程数。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/128930.html原文链接:https://javaforall.net

(0)
上一篇 2022年4月15日 下午3:00
下一篇 2022年4月15日 下午3:00


相关推荐

  • [MFC]同步对象——CCriticalSection临界区,CSemaphore信号量

    [MFC]同步对象——CCriticalSection临界区,CSemaphore信号量实例——CCriticalSection临界区临界区是保证在某一个时间只有一个线程可以访问数据的方法。使用它的过程中,需要给每个线程提供一个共享的临界区对象,无论哪个线程占有临界区对象,都可以访问受到保护的数据,这时候其他的线程需要等待,直至该线程释放临界区对象为止,临界区被释放后,另外的线程可以强占这个临界区,以便访问共享的数据。临界区对应的一个CCriticalSection对象,

    2022年7月20日
    22
  • Nano-Banana Studio多语言支持配置教程

    Nano-Banana Studio多语言支持配置教程

    2026年3月15日
    2
  • C语言中的指针详解

    C语言中的指针详解1 指针的定义 C 语言中指针是一种数据类型 指针是存放数据的内存单元地址 计算机系统的内存拥有大量的存储单元 每个存储单元的大小为 1 字节 为了便于管理 必须为每个存储单元编号 该编号就是存储单元的 地址 每个存储单元拥有一个唯一的地址 指针变量除了可以存放变量的地址外 还可以存放其他数据的地址 例如可以存放数组和函数的地址 2 指针的定义和初始化格式 数据类型符 指针变量名 初始地址值 功能 定义指向 数据类型符 的变量或数组的指针变量 同时为其赋初值

    2026年3月18日
    2
  • 被卖半年后的Hutool:还适合继续使用吗?

    被卖半年后的Hutool:还适合继续使用吗?

    2026年3月15日
    2
  • 提示用微信浏览器打开_浏览器如何设置消息提醒

    提示用微信浏览器打开_浏览器如何设置消息提醒概述大体思路是这样的:先建一个蒙版,蒙版放上提示的信息,然后写一个js,在页面打开的时候判断是不是用微信自带的浏览器打开的,如果是就打开蒙版,提示用浏览器打开基本页面添加蒙版添加js最终效果

    2022年8月16日
    6
  • mnist手写数字识别代码_数字识别

    mnist手写数字识别代码_数字识别MNIST手写数字识别模型建立与优化本篇的主要内容有:TensorFlow处理MNIST数据集的基本操作建立一个基础的识别模型介绍SoftmaxSoftmaxSoftmax回归以及交叉熵等MNIST是一个很有名的手写数字识别数据集(基本可以算是“HelloWorld”级别的了吧),我们要了解的情况是,对于每张图片,存储的方式是一个28*28的矩阵,但是我们在导入数据进…

    2025年11月13日
    10

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号