在modelarts上使用notebook上使用evs空间默认大小是5G,能满足大部分文本和图片训练模型的需求。如果训练数据稍微超过这个限额,可以适当的扩增下空间。但如果训练对象是视频,或是实际生成过程中的海量数据,这个空间就显得小了,这时候扩增evs空间就显得很不经济了。

最近老山便碰到这样的案例,客户的训练数据大约在1T的量级,在obs上存储的数据结构大概如下图所示。

your-obs-name
└── ...
└── video
├── folder1
│ ├── text.txt
│ └── video.mp4
├── folder2
│ ├── text.txt
│ └── video.mp4
├── folder3
│ ├── text.txt
│ └── video.mp4
├── folder4
│ ├── text.txt
│ └── video.mp4
├── folder5
│ ├── text.txt
│ └── video.mp4
├── ...

虽然使用华为云自带的moxing模块可以直接读取obs的数据,但由于实质是通过http实时读取数据,这个速度比从evs的ssd硬盘上读取数据要慢得多。而解决方案也比较直接,在evs上开辟一个固定大小的空间作为缓存区,一方面不断把obs数据读入缓存区,如果缓存区满了,就等待其腾出空间,另一方面训练任务消费evs数据,当消费完后便删除数据。

程序上也自然选用生产者-消费者模型。程序定义了管道类Pipeline,有生产者线程producer用于将obs数据保存到evs;同时输出evs数据用于外部模型的消费。由于每个视频文件都单独放在一个文件夹下,所以程序的输出对象也是这个文件夹在evs上保存的地址,如folder1,folder2等。至于读取文件夹内部文件信息等消费工作,由用户自行定义。

不多说,直接上代码。

import moxing as mox
mox.file.shift('os', 'mox')
import os, shutil
from queue import Queue
from time import sleep
import threading
import logging
logging.basicConfig(level=logging.INFO,
format="%(asctime)s %(name)s %(levelname)s %(message)s",) class ObsClient:
def __init__(self, root):
'''获取obs路径上需要读取的文件夹的相关信息'''
self.root = root
self.directory = self.list_directory()
self.maxSize = self.getMaxSize() def getMaxSize(self):
'''最大的文件夹的大小'''
return max([size for *_, size in self.directory]) def list_directory(self):
'''输出用于训练的文件夹的路径,输出directory:
[(文件夹相对路径,文件夹绝对路径,文件夹大小), ...]
'''
directory = []
folders = mox.file.list_directory(self.root)
for folder in folders:
folderPath = os.path.join(self.root, folder)
if mox.file.is_directory(folderPath):
size = self.get_size(folderPath)
directory.append((folder, folderPath, size))
return directory def get_size(self, path):
'''获取文件(夹)的大小'''
if mox.file.is_directory(path):
return self.get_size_folder(path)
return self.get_size_file(path) def get_size_file(self, path):
'''获取文件的大小'''
return mox.file.get_size(path) def get_size_folder(self, path):
'''获取文件夹的大小'''
size = 0
for filename in mox.file.list_directory(path, recursive=True):
filepath = os.path.join(path, filename)
if not mox.file.is_directory(filepath):
size+= self.get_size_file(filepath)
return size class EvsClient:
def __init__(self, root, memory, queue, directory, interval = 0.1):
self.root = root # evs缓存区根目录
self.directory = directory # obs文件夹信息
self.size = 0 # evs缓存区已使用的空间
self.memory = memory # evs上用于缓存的空间大小
self.queue = queue # 队列,存储了evs缓存区文件夹的信息
self.interval = interval # 如果缓存区满后,查询缓存大小的间隔时间 def remove(self, folder, size):
'''删除evs文件夹,在文件夹被消费后调用'''
logging.info(f"consumer: start removing folder {folder} with size {size}|{self.size}")
shutil.rmtree(folder, True)
self.size -= size
logging.info(f"consumer: end removing folder {folder} with size -{size}|{self.size}") def work(self):
'''生成者主程序,用于从obs中copy文件夹到evs'''
for relObsFolder, absObsFolder, size in self.directory:
while True:
# 缓存区没满,就copy文件
if not self.waitOrDo(size):
self.copy(relObsFolder, absObsFolder, size)
break
# 如果缓存区满了,就等待
sleep(self.interval)
# 当所有文件都拷贝后,置入结束符(None, None)
self.queue.put((None, None)) def waitOrDo(self, size):
'''返回True时等待,返回False时工作'''
return self.size + size > self.memory def copy(self, relObsFolder, absObsFolder, size):
'''从obs中copy文件夹到evs'''
evsFolder = os.path.join(self.root, relObsFolder)
logging.info(f"producer: start copying folder {relObsFolder} with size {size}|{self.size}")
mox.file.copy_parallel(absObsFolder, evsFolder)
self.queue.put((evsFolder, size))
self.size += size
logging.info(f"producer: end copying folder {relObsFolder} with size +{size}|{self.size}") class Pipeline:
def __init__(self, evsRoot, obsRoot, memory = '1g', timeout = 300, interval = 0.1):
self.memory = self.rescript(memory) # evs上用于缓存的空间大小
self.timeout = timeout # 消费者获取evs缓存区文件夹的最长等待时间
self.queue = Queue() # 队列,存储了evs缓存区文件夹的信息
self.obsClient = ObsClient(obsRoot) # 存储obs上的文件夹信息
# evs上的操作
self.evsClient = EvsClient(evsRoot, self.memory, self.queue, self.obsClient.directory, interval)
self.checkMemory() # 验证evs上用于缓存的空间大小是否足够大 def checkMemory(self):
'''evs上用于缓存的空间大小不能小于obs上最大文件夹大小'''
if self.memory<self.obsClient.maxSize:
raise Exception("memory should bigger than maxFolderSize!") def rescript(self, memory):
'''将文本或数值类型的memory转写成数值'''
try:
if isinstance(memory, str):
if memory[-1].lower()=='g':
return int(float(memory[:-1])*1024*1024*1024)
elif memory[-1].lower()=='m':
return int(float(memory[:-1])*1024*1024)
elif memory[-1].lower()=='k':
return int(float(memory[:-1])*1024)
else:
return int(float(memory))
else:
return int(float(memory))
except:
raise Exception("Error when rescripting memory!") def __iter__(self):
'''生成器,yield输出evs文件夹路径和大小'''
# 生产者线程
producer = threading.Thread(target = self.evsClient.work)
producer.start()
# 主程序提供生成器用于消费,输出evs文件夹路径和大小
while True:
logging.info(f"consumer: start to get the queue")
path, size = self.queue.get(timeout=self.timeout)
logging.info(f"consumer: get the queue {path}, {size} ")
if path is None and size is None:
break
yield path, size
self.evsClient.remove(path, size)
# 主程序等待
producer.join() if __name__ == '__main__':
# 使用示例
for path, size in Pipeline('./video', 's3://your-obs-name/.../video'):
do_job(path, size)

如果你觉得老山的文章不错,不妨点击下关注。

作者::山找海味

如何使用modelarts训练海量数据的更多相关文章

  1. Modelarts与无感识别技术生态总结(浅出版)

    [摘要] Modelarts技术及相关产业已成为未来AI与大数据重点发展行业模式之一,为了促进人工智能领域科学技术快速发展,modelarts现状及生态前景成为研究热点.笔者首先总结modelarts ...

  2. 从软件开发到 AI 领域工程师:模型训练篇

    前言 4 月热播的韩剧<王国>,不知道大家有没有看?我一集不落地看完了.王子元子出生时,正逢宫内僵尸作乱,元子也被咬了一口,但是由于大脑神经元尚未形成,寄生虫无法控制神经元,所以医女在做了 ...

  3. 【深度学习系列】PaddlePaddle之手写数字识别

    上周在搜索关于深度学习分布式运行方式的资料时,无意间搜到了paddlepaddle,发现这个框架的分布式训练方案做的还挺不错的,想跟大家分享一下.不过呢,这块内容太复杂了,所以就简单的介绍一下padd ...

  4. ubuntu之路——day8.1 深度学习优化算法之mini-batch梯度下降法

    所谓Mini-batch梯度下降法就是划分训练集和测试集为等分的数个子集,比如原来有500W个样本,将其划分为5000个baby batch,每个子集中有1000个样本,然后每次对一个mini-bat ...

  5. “蚂蚁牙黑”太火,想玩就用ModelArts做一个!

    摘要:本文将介绍如何借力一站式 AI 开发平台,"傻瓜式"操作实现生成"蚂蚁牙黑"小视频. 作者:华为云EI专家胡琦 一夜之间,朋友圈都在"蚂蚁牙黑& ...

  6. 跟着TensorFlow的进阶级教程实现MNIST库的训练

    转载出处:http://blog.csdn.net/feifei884431/article/details/51429829 背景介绍 代码实现及结果 小问题  ResourceExhaustedE ...

  7. 人脸检测及识别python实现系列(3)——为模型训练准备人脸数据

    人脸检测及识别python实现系列(3)——为模型训练准备人脸数据 机器学习最本质的地方就是基于海量数据统计的学习,说白了,机器学习其实就是在模拟人类儿童的学习行为.举一个简单的例子,成年人并没有主动 ...

  8. MxNet教程:使用一台机器训练1400万张图片

    官网链接:http://mxnet.readthedocs.io/en/latest/tutorials/imagenet_full.html Training Deep Net on 14 Mill ...

  9. 实际体验华为云AI : ModelArts

    国庆前看到了博客园官方博客发布的一篇博客: 学AI有奖:博客园&华为云AI有奖训练营开战啦 本着对AI这种火热的话题,以及华为云博客园联名公仔(次要),我决定参与这个活动. 现在华为云开始全面 ...

随机推荐

  1. ElasticSearch(五):Mapping和常见字段类型

    ElasticSearch(五):Mapping和常见字段类型 学习课程链接<Elasticsearch核心技术与实战> 什么是Mapping Mapping类似数据库中的schema的定 ...

  2. Scrapy进阶知识点总结(三)——Items与Item Loaders

    一.Items 抓取的主要目标是从非结构化源(通常是网页)中提取结构化数据.Scrapy蜘蛛可以像Python一样返回提取的数据.虽然方便和熟悉,但Python缺乏结构:很容易在字段名称中输入拼写错误 ...

  3. Apache Spark 3.0 预览版正式发布,多项重大功能发布

    2019年11月08日 数砖的 Xingbo Jiang 大佬给社区发了一封邮件,宣布 Apache Spark 3.0 预览版正式发布,这个版本主要是为了对即将发布的 Apache Spark 3. ...

  4. Dubbo的应用

    导语:Dubbo是阿里巴巴的一个分布式服务的开源框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000 ...

  5. 03-MyBatis拦截器机制

    目录 MyBatis拦截器介绍 拦截器的使用 拦截器介绍及配置 源码分析 总结 本文转载自MyBatis拦截器原理探究 MyBatis拦截器介绍 MyBatis提供了一种插件(plugin)的功能,虽 ...

  6. Nebula 架构剖析系列(二)图数据库的查询引擎设计

    摘要 上文(存储篇)说到数据库重要的两部分为存储和计算,本篇内容为你解读图数据库 Nebula 在查询引擎 Query Engine 方面的设计实践. 在 Nebula 中,Query Engine ...

  7. codeblocks 调试

    codeblocks 调试工具使用的注意事项: 1.codebloccks 调试,必须要在一个项目下才可以,也就是说“单独的文件是不能运行debug工具的” 2.项目的目录文件名必须是全英文,同时文件 ...

  8. webpack安装与核心概念

    安装webpack webpack核心概念:入口.输出.加载器.插件.模块.模式 一.安装webpack 1.安装webpack之前需要安装nodejs环境,在使用nodejs环境自带的包管理工具np ...

  9. Linux网络基本配置命令

    修改方法: 命令方式,大多是立即生效.临时有效: GUI图形方式, 修改配置文件,重启服务有效 1.修改主机名 hostname查看 hostname name临时修改 hostnamectl set ...

  10. 剑指Offer-20.包含min函数的栈(C++/Java)

    题目: 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1)). 分析: 因为题目要求得到栈中最小元素的min函数时间复杂度为O(1),这里便不选择遍历栈 ...