多卡情况下,同一份数据集会加载多次吗
shinerdeng opened this issue · 6 comments
不同的进程代表不同的GPU,不同GPU打印的prompt应该是不一样的。
如果你使用MyDataset
的话,多GPU的情况下需要设置keep_in_memory=True
,否则分布式数据分发不会生效。你拉一下最新的代码,已经强制校验了,pre_train.py
改用huggingface datasets
了。
多GPU下,__getitem__
方法通过index去获取那一条数据,迭代器yield
是为单GPU大数据集设计的。
是,accelerate自动拆分index。
是的,多进程情况下,内存中是会有多份(Python多进程的锅),可以先将文本tokenize转换为uint16的token_id用保存(词表小于65535可用uint16,否则用uint32),再读取进来,能省不少内存。我当时没这样做是为了方便debug😂。
如果还想要多进程继续减少内存使用,可以考虑将数据保存为内存映射文件.arrow
,而不是.parquet
,但是读取会消耗硬盘随机读取的时间。不想手错繁琐的.arrow
文件读写,可以直接使用huggingface的datasets
库(你拉最新代码pre_train.py
是用的就是datasets
库了)。如果是小数据集(或者内存可以放下)建议放在内存,加快读取速度,datasets
库的load_dataset
方法keep_in_memory
参数决定是否将数据集放入内存。
感谢您的建议。目前是在单机多卡环境,把大文件直接拆成和gpu数量一样,按rank各加载各的。这样一换环境就要重新生成文件不灵活。考虑到内存不是无限的而训练集可能超大,能不能不save和load模型,动态切换dataset呢,比如训练到一定程度就加载下一个文件。。这样对内存就没那么多要求了。
可以做到动态切换dataset,不过得自己手搓了,但是往各个机器拷贝数据集的步骤少不了。
一个不成熟的想法:先把数据集分割为很多文件(也可以是很多个不同数据集),可以参考 MyDataset
的写法,继承Dataset
,然后重写__getitem__
方法,根据传进来的index
决定去加载某个文件(dataloader不能打乱数据,index是按顺序传进来的),比如index在[1000, 2000]加载B数据集并放在内存中,之后index
在[1000, 2000]就直接读内存的数据,如果不在[1000, 2000]就加载另外一个数据集进来。分桶的概念,做个index、rank和桶的映射关系表就好了。
训练到一定程度就加载下一个文件,得自己手搓训练的for循环(huggingface的trainer callback也行)+Sampler(用来接收切换数据集的信号,并传递到getitem方法实现数据集切换)吧,比如根据损失、ppl情况切换数据集。
谢谢,官方没提供这样的例子的话手搓确实比较麻烦。