深度学习中大语料库使用基于Pytorch
·
在做机器翻译中,语料库很大,每次都要遍历文件,效率极低。正确的做法是预先将文件全部读入内存,但这对大语料不现实。
DeepSeek提供有三种思路来实现
-
方法A(推荐):使用线性访问。确保你的数据集文件是按行顺序存储的,这样操作系统会有缓存,速度会快很多。但shuffle时还是会跳转。
-
方法B(最佳):将语料库预处理成多个小文件(例如,每100000个句子一个文件),然后你的Dataset根据idx计算出在哪个小文件的哪一行,这样加载更快。或者预处理成内存映射(mmap)格式或数据库(如SQLite)。
-
方法C(通用):在
__init__中,只把每一行的起始偏移量(file pointer offset)记录到一个列表里。在__getitem__中,使用seek(offset)直接定位到行,然后读取一行。这避免了遍历,效率很高。
我是通过方法C来实现的,具体代码如下:
# 偏移读取
class EfficientTranslationDataset(torch.utils.data.Dataset):
def __init__(self, file_path):
self.file_path = file_path
self.file_offsets = self._build_offset_index(file_path)
self.num_samples = len(self.file_offsets)
with open(file_path, 'r', encoding='utf-8') as f:
self.num_samples = sum(1 for _ in f)
def __len__(self):
return self.num_samples
def __getitem__(self, idx):
en_words_list = []
zh_words_list = []
line = self._read_line_by_offset(self.file_path, self.file_offsets[idx])
line_arr = line.strip().split('\t')
if len(line_arr) >= 2:
line_en = line_arr[0].strip()
for word in line_en.split(' '):
word = word.replace('.', '').replace(',', '').lower()
if word:
add_word = remove_punctuation_at_begin_and_end(word)
if contains_only_lowercase_english(add_word):
if not (is_all_same_characters(add_word) and len(add_word) != 1):
if len(add_word) != 0:
en_words_list.append(add_word)
line_zh = line_arr[1].strip()
chinese_words = list(jieba.lcut(line_zh.strip()))
zh_words_list = [word for word in chinese_words if is_chinese_only(word) and word.strip()]
en_len = len(en_words_list)
zh_len = len(zh_words_list)
return en_words_list, en_len, zh_words_list, zh_len, idx
def _build_offset_index(self, file_path):
"""
构建文件偏移量索引列表。
返回一个列表,其中每个元素是文件中一行的起始字节偏移量。
"""
offsets = []
with open(file_path, 'rb') as f: # 用二进制模式打开以正确计算字节偏移
offsets.append(0) # 第一行的偏移量总是0
while True:
chunk = f.read(8192) # 每次读取8KB的块,提高效率
if not chunk:
break
# 在块中查找换行符的位置
# 注意:换行符在不同系统中可能不同,这里用\n
# 对于Windows生成的\r\n文件,可能需要调整
start = 0
while True:
pos = chunk.find(b'\n', start)
if pos == -1:
break
# 计算绝对偏移量:文件当前位置 - 块长度 + 换行符在块中的位置 + 1
# +1 是为了指向下一行的开始
offsets.append(f.tell() - len(chunk) + pos + 1)
start = pos + 1
return offsets
def _read_line_by_offset(self, file_path, offset):
"""
根据给定的字节偏移量,从文件中读取一行。
"""
with open(file_path, 'r', encoding='utf-8') as f:
f.seek(offset) # 跳到指定偏移量
line = f.readline().strip() # 读取一行
return line
更多推荐



所有评论(0)