这个问题一定是要结合具体的代码,下面就自己遇到问题,询问chatGPT后发现问题所在的过程进行记录,当然绝大部分情况下都是batch_size设置太大了,显卡内存不足导致
部分重点代码:
'''
导入模型部分略
'''
#自定义数据集有关类
class MyDataset(Dataset):
def __init__(self, data):
self.data = np.array(data)
def __len__(self):
return len(self.data)
def __getitem__(self, idx):
data = self.data[idx]
return data
#批量处理数据
#在批量处理数据时对输入数据进行统一的处理用于在批量处理数据时对输入数据进行统一的处理,常用于NLP任务中的数据整理,特别是在使用 PyTorch 的数据加载器时
def collate_fn(data):
max_length = max([len(x) for x in data])
#长度限制为 512,以便防止序列太长导致内存不足或者计算效率低下。通常是为了适应模型(例如 BERT)的输入长度限制
max_length = min(512,max_length)
#attention_mask: 存放注意力掩码,标识哪些位置是有效的输入,哪些是填充(padding)
#input_ids: 存放每个输入序列(已做过截断或填充)的 token ID。
#weight: 存放每个序列的权重信息,权重值根据序列长度条件决定。
attention_mask,input_ids,weight =[], [], []
for x in data:
if len(x)>max_length:
#截断方式:取前半部分的前 max_length // 2 个 token 和后半部分的后 max_length // 2 个 token。
#这种截断方式保留了序列的开头和结尾,适用于场景中间内容可能不重要的情况
x = x[:max_length//2] + x[len(x)-max_length//2:]
#attention表示哪些token 是有效的(值为 1),哪些是填充的(值为 0)。有效部分根据序列长度 len(x) 生成 1,剩下的部分补齐 0
attention = [1] * len(x) + [0] * (max_length - len(x))
attention_mask.append(attention)
if len(x) == 2:
weight.append(0)
else:
weight.append(1)
#将每个序列 x 填充到指定的最大长度 max_length
#[0] * (max_length - len(x)) 创建一个长度为 max_length - len(x) 的列表,所有元素都是 0。0通常代表 padding token(填充标记)
x = x + [0] * (max_length - len(x))#x是一个list
input_ids.append(x)
#list换为 PyTorch 的 tensor 格式,以便于后续在模型中进行批量计算。
input_ids = torch.tensor(input_ids)
attention_mask = torch.tensor(attention_mask)
weight = torch.tensor(weight).unsqueeze(1)#unsqueeze(1),增加一个维度,变成形如 (batch_size, 1),符合后续使用需求
return input_ids, attention_mask, weight
#加载数据
title_ids = np.load(os.path.join(data_dir,'title_ids.npy'),allow_pickle=True)
data_set = MyDataset(title_ids)
dataloader = DataLoader(data_set, batch_size=128, collate_fn=collate_fn, shuffle=False, pin_memory=True,num_workers=4)
'''
运行以下代码时程序卡住,但是不报错
'''
title_embeddings = []
for input_ids, attention_mask, weight in tqdm(dataloader):
with torch.no_grad():
with autocast():
input_ids = input_ids.to(device)
attention_mask = attention_mask.to(device)
hidden = model(input_ids = input_ids,
attention_mask=attention_mask,
output_hidden_states=True,
).hidden_states
avg = (hidden[0]+hidden[-1])/2
embeddings = avg*attention_mask.unsqueeze(-1)
embeddings = embeddings.sum(1) / attention_mask.sum(1).unsqueeze(-1)
embeddings = embeddings*weight.to(device)
title_embeddings += embeddings.tolist()
1.首先觉得是dataloader出现问题
#迭代 DataLoader 对象来查看数据的实际内容
for batch in dataloader:
input_ids, attention_mask, weight = batch
print('input_ids:', input_ids)
print('attention_mask:', attention_mask)
print('weight:', weight)
break # 只查看第一个批次的数据
#使用 iter 函数查看部分数据
data_iter = iter(dataloader)
batch = next(data_iter)
print(batch)
两种方式作用一样,但是仍然卡住,没有报任何错误
2.接着尝试改变DataLoader的参数
(1)num_workers
设置过大
如果 num_workers
较大,DataLoader
会创建多个子进程来并行加载数据。在某些环境限制较大的服务器上,多线程的数据加载可能会出现问题,导致进程阻塞或卡住。
解决方法: 将 num_workers
设置为 0
,以禁用多进程加载,使用单线程数据加载方式。
无效
(2)pin_memory
设置问题
pin_memory=True
会将数据拷贝到固定内存(pinned memory),有助于在 GPU 加速的场景中提高数据传输效率。但在某些系统中,它可能导致数据加载效率降低甚至卡住。
解决方法: 尝试将 pin_memory
设置为 False
,尤其是在 CPU 上训练时,通常不需要固定内存。
仍然无效
3.检查自定义函数collate_fn
是否有问题
函数问题
如果使用了自定义的 collate_fn
,它可能存在问题,比如在处理数据时某些数据格式不正确
验证函数功能正确:
sample_data = [dataloader.dataset[i] for i in range(10)]
processed_batch = collate_fn(sample_data)
print(processed_batch)
4.数据集太大或者存储问题
数据集非常大,加载数据时可能会耗费大量内存,导致系统负载过高或者卡住。
解决方法: 通过减少批次大小来减轻内存压力。
最终还是发现是自己显卡内存过低,batch_size设置为128直接卡住,逐渐减小batch_size会出现OutOfMemoryError
ps:经验不足,刚开始没想到是显存问题
管理GPU内存的一些方法
1.处理数据时,设置合理的batch_size,尽可能填满显存
2.使用混合精度训练,不仅减少显存占用,还可以加快计算速度,比如卡住的程序一段中使用的with.autocast()
3.报错中有一个提示,当出现reserved memory>>allocated memory,设置max_split_size_mb
来减少内存碎片。
方法:在程序的最开头
import os
os.environ['PYTORCH_CUDA_ALLOC_CONF'] = 'max_split_size_mb:128'