百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

如何在Keras中训练大型数据集

bigegpt 2024-08-31 16:40 8 浏览

在本文中,我们将讨论如何使用Keras在不适合内存的大数据集上训练我们的深度学习网络。

介绍

深度学习算法优于所有其他算法,能够在大多数问题上产生最先进的结果。深度学习算法成功的主要原因是数据集的大小越来越大。现在,深度学习算法在大型数据集上进行训练,这些数据集甚至不适合内存。问题是:如何在如此庞大的数据集上训练我们的模型?本文分为以下几个部分:

一般情况下,深度学习算法的性能优于其他算法,并且能够在大多数问题上产生较好的结果。深度学习算法成功的主要原因是数据集的不断增大。现在,深度学习算法在大型数据集上进行训练,这些数据集甚至不适合内存。问题是:如何在如此巨的数据集中训练我们的深度学习模型呢?本文分为以下几个部分:

  • 下载和了解数据集
  • 数据集的准备 - 批量加载数据集
  • 数据集在训练和验证集中的Shuffling和拆分
  • 创建自定义生成器
  • 定义模型体系结构和训练模型
  • 结论

作为一个例子,我们将解决Kaggle“Plant Seedlings Classification”的挑战。这个数据集并不大,但我们将假设数据集太大,无法装入内存,然后将批量加载数据集。

下载和了解数据集

您可以从此处下载(https://www.kaggle.com/c/plant-seedlings-classification/data)数据集。解压缩train.zip文件夹。该数据集包含分类为12种植物物种的不同阶段的植物幼苗的4750幅图像。12种植物有Black-grass,Charlock,Cleavers,Common Chickweed,Common wheat,Fat Hen,Losse Silky-bent,Maize,Scentless Mayweed,Shepherds Purse,Small-flowered Cranesbill,Sugar beet。竞赛的目标是创建一个能够从照片中确定植物种类的分类器。

当前目录如下所示:

如果您的问题数据集不是这种格式,请不要担心。您的数据集可以是任何格式。我们将在下一节中看到,目标是获取所有数据点(即我们示例中的图像)并将它们保存到单个文件夹中。数据点可以是图像,音频等。

数据集的准备 - 批量加载数据集

下一步是获取整个数据集(即所有数据点(在我们的示例中为图像))并将它们存储到一个文件夹中。我们创建一个名为“all_images”的新文件夹,目标是将数据集中的所有图像存储在这个“all_images”文件夹中。

我们使用以下脚本将所有图像存储在“all_images”文件夹中。您可以编写类似的脚本来获取数据集中的所有数据点(可以是图像,音频等)并将它们存储到新文件夹中。

import os
import shutil
train_dir = '/content/train'
dest_dir = '/content/all_images'
counter = 0
for subdir, dirs, files in os.walk(train_dir):
 #print(files)
 for file in files:
 full_path = os.path.join(subdir, file)
 shutil.copy(full_path, dest_dir)
 counter = counter + 1
print(counter)

下一步是将每个数据点的名称(即每个图像的名称)存储在一个数组中(让我们将数组命名为filename)。还有一件事是将与每个数据点关联的标签存储在另一个数组中(让我们将这个数组称为labels)。

下面是一个Python脚本,它将每个图像的名称存储在filenames数组中,并将与该图像关联的标签存储在labels数组中。

注意:请记住,每个数据点的名称应该是唯一的。

import numpy as np
subdirs, dirs, files = os.walk('/content/all_images').__next__()
m = len(files)
print(m)
filenames = []
labels = np.zeros((m, 1))
import os
import shutil
images_dir = '/content/all_images'
filenames_counter = 0
labels_counter = -1
for subdir, dirs, files in os.walk(train_dir):
 #print(files)
 for file in files:
 filenames.append(file)
 labels[filenames_counter, 0] = labels_counter
 filenames_counter = filenames_counter + 1
 labels_counter = labels_counter+1
 
print(len(filenames))
print(labels.shape)

现在,您可以保存“all_images”文件夹、“filename”数组和“labels”数组,以便稍后使用。

下面我们创建一个由filename 和labels组成的numpy数组,并将它们保存为.npy文件。

# saving the filename array as .npy file
np.save('filenames.npy', filenames)
import keras
from keras.utils import to_categorical
# One hot vector representation of labels
y_labels_one_hot = to_categorical(labels)
# saving the y_labels_one_hot array as a .npy file
np.save('y_labels_one_hot.npy', y_labels_one_hot)

数据集的shuffling和拆分

下一步是对数据集进行shuffle ,以便从数据集中删除对称性。

from sklearn.utils import shuffle
filenames_shuffled, y_labels_one_hot_shuffled = shuffle(filenames, y_labels_one_hot)
# saving the shuffled file.
# you can load them later using np.load().
np.save('y_labels_one_hot_shuffled.npy', y_labels_one_hot_shuffled)
np.save('filenames_shuffled.npy', filenames_shuffled)

现在,让我们将数据集拆分为训练和验证集。我们也可以保存这些文件,因为这些文件稍后将用于训练和验证我们的机器学习模型。

from sklearn.model_selection import train_test_split
filenames_shuffled_numpy = np.array(filenames_shuffled)
X_train_filenames, X_val_filenames, y_train, y_val = train_test_split(
 filenames_shuffled_numpy, y_labels_one_hot_shuffled, test_size=0.2, random_state=1)
print(X_train_filenames.shape)
print(y_train.shape)
print(X_val_filenames.shape)
print(y_val.shape)
np.save('X_train_filenames.npy', X_train_filenames)
np.save('y_train.npy', y_train)
np.save('X_val_filenames.npy', X_val_filenames)
np.save('y_val.npy', y_val)

您还可以将“all_images”文件夹保存为zip格式,以便与其他团队成员共享数据集。

这些代码行只创建一个“all_images.zip”文件夹。

import shutil
shutil.make_archive("all_images", "zip", "all_images")

创建自定义生成器

注意:由于我们的数据集太大而无法容纳在内存中,因此我们必须将数据集从硬盘批量加载到内存中。

为此,我们将创建一个自定义生成器。我们的自定义生成器将要将数据集从硬盘批量加载到内存中。

class My_Custom_Generator(keras.utils.Sequence) :
 
 def __init__(self, image_filenames, labels, batch_size) :
 self.image_filenames = image_filenames
 self.labels = labels
 self.batch_size = batch_size
 
 
 def __len__(self) :
 return (np.ceil(len(self.image_filenames) / float(self.batch_size))).astype(np.int)
 
 
 def __getitem__(self, idx) :
 batch_x = self.image_filenames[idx * self.batch_size : (idx+1) * self.batch_size]
 batch_y = self.labels[idx * self.batch_size : (idx+1) * self.batch_size]
 
 return np.array([
 resize(imread('/content/all_images/' + str(file_name)), (80, 80, 3))
 for file_name in batch_x])/255.0, np.array(batch_y)

让我们试着理解整个代码:

  • 第1行:我们的Custom Generator类继承自Sequence类。
  • 第3行:在这里,我们可以向生成器提供参数。
  • 第9行:此函数计算此生成器应该生成的批数。因此,我们将总样本数除以batch_size并返回该值。
  • 第14行:在这里,给定批号idx,您需要将包含数据批次和ground-truth(GT)的列表放在一起。在此示例中,我们读取大小为batch_size的批量图像,并返回一个数组[image_batch, GT]。
  • 在__getitem __(self,idx)函数中,您可以决定批量加载时数据集会发生什么。在这里,您也可以执行预处理步骤。此外,您还可以计算音频文件的mel谱图。

我们已经创建了数据生成器。下一步是创建此类的实例。

batch_size = 32
my_training_batch_generator = My_Custom_Generator(X_train_filenames, y_train, batch_size)
my_validation_batch_generator = My_Custom_Generator(X_val_filenames, y_val, batch_size)
  • 第3,4行:实例化My_Custom_Generator的两个实例(一个用于训练,一个用于验证)。

定义模型体系结构和训练模型

我们先导入一些Python库:

import numpy as np
import pandas as pd
from skimage.io import imread
from skimage.transform import resize
import keras
from keras.models import Sequential, Model, load_model
from keras.layers import Input, Conv1D, Conv2D, MaxPooling1D, MaxPooling2D, Dense, Dropout, Activation, Flatten
from keras.layers.normalization import BatchNormalization
from keras.utils import to_categorical

现在,让我们定义模型架构并编译机器学习模型。您可以在此处使用任何模型架构。

model = Sequential()
model.add(Conv2D(filters = 64, kernel_size = (5,5), activation ='relu',input_shape=(80,80,3)))
model.add(BatchNormalization(axis=3))
model.add(Conv2D(filters = 64, kernel_size = (5,5), activation ='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(BatchNormalization(axis=3))
model.add(Dropout(0.25))
model.add(Conv2D(filters = 128, kernel_size = (5,5), activation ='relu'))
model.add(BatchNormalization(axis=3))
model.add(Conv2D(filters = 128, kernel_size = (5,5), activation ='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(BatchNormalization(axis=3))
model.add(Dropout(0.25))
model.add(Conv2D(filters = 256, kernel_size = (5,5), activation ='relu'))
model.add(BatchNormalization(axis=3))
model.add(Conv2D(filters = 256, kernel_size = (5,5), activation ='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(BatchNormalization(axis=3))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(256, activation = "relu")) #Fully connected layer
model.add(BatchNormalization())
model.add(Dropout(0.5))
model.add(Dense(60, activation = "relu")) #Fully connected layer
model.add(BatchNormalization())
model.add(Dropout(0.5))
model.add(Dense(12, activation = "softmax")) #Classification layer or output layer
model.compile(optimizer="adam", loss='categorical_crossentropy', metrics=['accuracy'])
model.summary()

现在,让我们训练我们的机器学习模型。

model.fit_generator(generator=my_training_batch_generator,
 steps_per_epoch = int(3800 // batch_size),
 epochs = 10,
 verbose = 1,
 validation_data = my_validation_batch_generator,
 validation_steps = int(950 // batch_size))

训练结果:

我们的模型没有给出很好的结果,而且过度拟合。我们可以使用不同的模型架构,或者预处理我们的数据集,或使用数据增强,或者使用迁移学习来提高精度。但是,这不是本文的目的。我希望现在您已经非常清楚地理解了如何使用大数据集来训练一个深度学习模型。

结论

这篇文章,我试着用一个例子给你一个非常清晰的理解,告诉你如何用一个巨大的数据集训练你自己的深度学习模型。

注意:最好先对数据集进行预处理,然后将其提供给学习算法。

相关推荐

Java 泛型大揭秘:类型参数、通配符与最佳实践

引言在编程世界中,代码的可重用性和可维护性是至关重要的。为了实现这些目标,Java5引入了一种名为泛型(Generics)的强大功能。本文将详细介绍Java泛型的概念、优势和局限性,以及如何在...

K8s 的标签与选择器:流畅运维的秘诀

在Kubernetes的世界里,**标签(Label)和选择器(Selector)**并不是最炫酷的技术,但却是贯穿整个集群管理与运维流程的核心机制。正是它们让复杂的资源调度、查询、自动化运维变得...

哈希Hash算法:原理、应用(哈希算法 知乎)

原作者:Linux教程,原文地址:「链接」什么是哈希算法?哈希算法(HashAlgorithm),又称为散列算法或杂凑算法,是一种将任意长度的数据输入转换为固定长度输出值的数学函数。其输出结果通常被...

C#学习:基于LLM的简历评估程序(c# 简历)

前言在pocketflow的例子中看到了一个基于LLM的简历评估程序的例子,感觉还挺好玩的,为了练习一下C#,我最近使用C#重写了一个。准备不同的简历:image-20250528183949844查...

55顺位,砍41+14+3!季后赛也成得分王,难道他也是一名球星?

雷霆队最不可思议的新星:一个55号秀的疯狂逆袭!你是不是也觉得NBA最底层的55号秀,就只能当饮水机管理员?今年的55号秀阿龙·威金斯恐怕要打破你的认知了!常规赛阶段,这位二轮秀就像开了窍的天才,直接...

5分钟读懂C#字典对象(c# 字典获取值)

什么是字典对象在C#中,使用Dictionary类来管理由键值对组成的集合,这类集合被称为字典。字典最大的特点就是能够根据键来快速查找集合中的值,其键的定义不能重复,具有唯一性,相当于数组索引值,字典...

c#窗体传值(c# 跨窗体传递数据)

在WinForm编程中我们经常需要进行俩个窗体间的传值。下面我给出了两种方法,来实现传值一、在输入数据的界面中定义一个属性,供接受数据的窗体使用1、子窗体usingSystem;usingSyst...

C#入门篇章—委托(c#委托的理解)

C#委托1.委托的定义和使用委托的作用:如果要把方法作为函数来进行传递的话,就要用到委托。委托是一个类型,这个类型可以赋值一个方法的引用。C#的委托通过delegate关键字来声明。声明委托的...

C#.NET in、out、ref详解(c#.net framework)

简介在C#中,in、ref和out是用于修改方法参数传递方式的关键字,它们决定了参数是按值传递还是按引用传递,以及参数是否必须在传递前初始化。基本语义对比修饰符传递方式可读写性必须初始化调用...

C#广义表(广义表headtail)

在C#中,广义表(GeneralizedList)是一种特殊的数据结构,它是线性表的推广。广义表可以包含单个元素(称为原子),也可以包含另一个广义表(称为子表)。以下是一个简单的C#广义表示例代...

「C#.NET 拾遗补漏」04:你必须知道的反射

阅读本文大概需要3分钟。通常,反射用于动态获取对象的类型、属性和方法等信息。今天带你玩转反射,来汇总一下反射的各种常见操作,捡漏看看有没有你不知道的。获取类型的成员Type类的GetMembe...

C#启动外部程序的问题(c#怎么启动)

IT&OT的深度融合是智能制造的基石。本公众号将聚焦于PLC编程与上位机开发。除理论知识外,也会结合我们团队在开发过程中遇到的具体问题介绍一些项目经验。在使用C#开发上位机时,有时会需要启动外部的一些...

全网最狠C#面试拷问:这20道题没答出来,别说你懂.NET!

在竞争激烈的C#开发岗位求职过程中,面试是必经的一道关卡。而一场高质量的面试,不仅能筛选出真正掌握C#和.NET技术精髓的人才,也能让求职者对自身技术水平有更清晰的认知。今天,就为大家精心准备了20道...

C#匿名方法(c#匿名方法与匿名类)

C#中的匿名方法是一种没有名称只有主体的方法,它提供了一种传递代码块作为委托参数的技术。以下是关于C#匿名方法的一些重要特点和用法:特点省略参数列表:使用匿名方法可省略参数列表,这意味着匿名方法...

C# Windows窗体(.Net Framework)知识总结

Windows窗体可大致分为Form窗体和MDI窗体,Form窗体没什么好细说的,知识点总结都在思维导图里面了,下文将围绕MDI窗体来讲述。MDI(MultipleDocumentInterfac...