在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. vue中组件的data为什么是一个函数

    1. 前言 在学习vue的时候,一直纳闷一件事:组件的data数据为什么必须要以函数返回的形式,为什么不是简单的对象形式呢?遂带着问题去翻官方文档,文档中自然也写明了这么做的原因,本篇博文以官方文档给 ...

  2. 一文学会Go语言

    go语言随手记 -- go语言定位于高并发服务端程序 1.基本数据类型 boolstringint int8 int16 int32 int64uint uint8 uint16 uint32 uin ...

  3. 通俗地说逻辑回归【Logistic regression】算法(二)sklearn逻辑回归实战

    前情提要: 通俗地说逻辑回归[Logistic regression]算法(一) 逻辑回归模型原理介绍 上一篇主要介绍了逻辑回归中,相对理论化的知识,这次主要是对上篇做一点点补充,以及介绍sklear ...

  4. 『题解』POJ1753 Flip Game

    题目传送门 题意描述 有\(4 \times 4\)的正方形,每个格子要么是黑色,要么是白色,当把一个格子的颜色改变(黑\(\to\)白 或 白\(\to\)黑)时,其周围上下左右(如果存在的话)的格 ...

  5. pandas处理excel的常用方法技巧(上)

    1. 导库 import pandas as pd 2. 读取excel文件 这里要注意的就是第二个参数header如果不设置,pandas会默认把excel的第一行当作columns,header= ...

  6. java 打包web 项目

    1 选择你的web项目 2 右击,选择export 3 选择web下的war file 4 将打包好war包,保存在tomcat的webapps下 5 运行tomcat,tomcat会自动帮你解压这个 ...

  7. linux 设置固定ip和dns

    目录 1. centos 1.1 ifconfig 查看网卡名称 1.2 设置固定ip和dns 1.3 重启网络 2. ubuntu 2.1 ifconfig 查看网卡名称 2.2 设置固定ip和dn ...

  8. HashMap深入分析及使用要点

    本文内容来自深入理解HashMap.从数据结构谈HashMap.HashMap深度分析 先说使用要点. 1.不要在并发场景中使用HashMap HashMap是线程不安全的,如果被多个线程共享的操作, ...

  9. 通过canvas合成图片

    通过canvas合成图片 效果图 页面布局部分 两个图片以及一个canvas画布 <img src="https://qnlite.gtimg.com/qqnewslite/20190 ...

  10. Linux系统中文件行末尾出现^M的原因及解决办法

    不同系统,有不同的换行符号: 在windows下的文本文件的每一行结尾,都有一个回车('\n')和换行('\r') 在linux下的文本文件的每一行结尾,只有一个回车('\n'); 在Mac下的文本文 ...