Terence888 发表于 2024-11-3 13:44:52

如何在生成的inputs字典中正确加入labels这个键值对

def prepare_input(cfg, text):
    inputs = cfg.tokenizer.encode_plus(
      text,
      return_tensors=None,
      add_special_tokens=True,#自动在每个文本前后添加特殊标记(如CLS和SEP)
      return_attention_mask=True # 计算注意力(attention)时忽略那些paddle值
    )
   
    if len(inputs['input_ids']) > CFG.max_len:#句子长度大于max_length时截断
      inputs['input_ids'] = inputs['input_ids'][:CFG.max_len]
      inputs['attention_mask'] = inputs['attention_mask'][:CFG.max_len]
      inputs['token_type_ids'] = inputs['token_type_ids'][:CFG.max_len]

    for k, v in inputs.items():
      inputs = torch.tensor(v, dtype=torch.long)
    return inputs


class LLMDataset(Dataset):
    def __init__(self, cfg, df,is_grad):
      self.cfg = cfg
      self.df = df
      self.texts = df["cleaned"].values
      self.is_grad = is_grad

    def __len__(self):
      return len(self.texts)

    def __getitem__(self,idx):
      inputs = prepare_input(self.cfg, self.texts)#inputs是一个字典
      if self.is_grad:#训练集
            labels = self.df.loc['label']#标签数据形状为
            
            return {'input_ids':inputs['input_ids'],
                  'attention_mask':inputs['attention_mask'],
                  "token_type_ids": inputs['token_type_ids'],
                  # Our loss_fn wants it to be a "float" type
                  'labels':torch.tensor(labels,dtype=torch.float).unsqueeze(dim=0)}

如何正确把labels加入字典inputs中

FishC 发表于 2024-11-3 13:51:04

要在生成的 `inputs` 字典中正确加入 `labels` 键值对,你需要确保在 `prepare_input` 函数中返回的 `inputs` 是一个字典,并且在 `__getitem__` 方法中正确地将 `labels` 添加到这个字典中。以下是修改后的代码:

def prepare_input(cfg, text):
    inputs = cfg.tokenizer.encode_plus(
      text,
      return_tensors=None,
      add_special_tokens=True,
      return_attention_mask=True
    )
   
    if len(inputs['input_ids']) > cfg.max_len:
      inputs['input_ids'] = inputs['input_ids'][:cfg.max_len]
      inputs['attention_mask'] = inputs['attention_mask'][:cfg.max_len]
      if 'token_type_ids' in inputs:
            inputs['token_type_ids'] = inputs['token_type_ids'][:cfg.max_len]

    for k, v in inputs.items():
      inputs = torch.tensor(v, dtype=torch.long)
    return inputs

class LLMDataset(Dataset):
    def __init__(self, cfg, df, is_grad):
      self.cfg = cfg
      self.df = df
      self.texts = df['text'].values# 假设文本列名为 'text'
      self.is_grad = is_grad

    def __len__(self):
      return len(self.texts)

    def __getitem__(self, idx):
      inputs = prepare_input(self.cfg, self.texts)
      if self.is_grad:
            labels = self.df.loc# 假设标签列名为 'label'
            inputs['labels'] = torch.tensor(labels, dtype=torch.float).unsqueeze(dim=0)
      
      return inputs

在这个修改后的代码中:

1. `prepare_input` 函数返回一个包含 `input_ids`、`attention_mask` 和可能的 `token_type_ids` 的字典。
2. 在 `__getitem__` 方法中,使用 `self.df.loc` 获取标签值,并将其添加到 `inputs` 字典中。
3. 确保在 `prepare_input` 中对 `inputs` 的每个值都转换为 `torch.tensor`。

请根据你的数据框架的实际列名调整代码中的 `'text'` 和 `'label'

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

Terence888 发表于 2024-11-3 16:07:10

FishC 发表于 2024-11-3 13:51
要在生成的 `inputs` 字典中正确加入 `labels` 键值对,你需要确保在 `prepare_input` 函数中返回的 `input ...

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In, line 4
      1 print('Training Start!')
      2 print('=' * 100)
----> 4 train(model,
      5   device,
      6   train_dataloader,
      7   valid_dataloader,
      8   CFG.epochs,
      9   loss_fn,
   10   optimizer,
   11   metric)
   13 del model,train_dataloader, valid_dataloader
   14 gc.collect()

Cell In, line 25, in train(model, device, train_dataloader, valid_dataloader, epochs, loss_fn, optimizer, metric)
   23 train_attention_mask = batch['attention_mask'].to(device)
   24 train_token_type_ids = batch['token_type_ids'].to(device)
---> 25 train_labels = batch['labels'].squeeze().to(device).long()#label真实值long()转化成一维张量
   27 # You can refer to the class "TweetsModel" for understand
   28 # what would be logits
   29 logits = model(train_input_ids, train_attention_mask,train_token_type_ids).to(device)

KeyError: 'labels'

报错信息如上,代码如下
print('Training Start!')
print('=' * 100)

train(model,
    device,
    train_dataloader,
    valid_dataloader,
    CFG.epochs,
    loss_fn,
    optimizer,
    metric)

del model,train_dataloader, valid_dataloader
gc.collect()
import gc,os
from tqdm.auto import tqdm # visualizing tool for progress

# They will be used to pick the best model.pt given to the valid loss
best_model_epoch, valid_loss_values = [],[]
valid_loss_min = # arbitrary loss I set here
def train(model,device,train_dataloader,valid_dataloader,epochs,loss_fn,optimizer,metric):

    for epoch in range(epochs):
      gc.collect() # memory cleaning垃圾回收机制,减少占用内存
      model.train()

      train_loss = 0
      train_step = 0
      pbar = tqdm(train_dataloader, total=len(train_dataloader))#tqdm参数是一个iterable

      for batch in pbar: # you can also write like "for batch in tqdm(train_dataloader"
            optimizer.zero_grad() # initialize
            train_step += 1
            

            train_input_ids = batch['input_ids'].to(device)#batch是一个字典
            train_attention_mask = batch['attention_mask'].to(device)
            train_token_type_ids = batch['token_type_ids'].to(device)
            train_labels = batch['labels'].squeeze().to(device).long()#label真实值long()转化成一维张量
            
            # You can refer to the class "TweetsModel" for understand
            # what would be logits
            logits = model(train_input_ids, train_attention_mask,train_token_type_ids).to(device)
            predictions = torch.argmax(logits, dim=1) # get an index from larger one
            detached_predictions = predictions.detach().cpu().numpy()
            
            loss = loss_fn(logits, train_labels)
            loss.backward()
            optimizer.step()
            model.zero_grad()

            train_loss += loss.detach().cpu().numpy().item()

            pbar.set_postfix({'train_loss':train_loss/train_step})#设置进度条显示信息
      pbar.close()

      with torch.no_grad():
            model.eval()

            valid_loss = 0
            valid_step = 0
            total_valid_score = 0

            y_pred = [] # for getting f1_score that is a metric of the competition
            y_true = []

            pbar = tqdm(valid_dataloader)
            for batch,labels in pbar:
                valid_step += 1

                valid_input_ids = batch['input_ids'].to(device)
                valid_attention_mask = batch['attention_mask'].to(device)
                valid_token_type_ids = batch['token_type_ids'].to(device)
                valid_labels = batch['labels'].squeeze().to(device).long()

                logits = model(valid_input_ids, valid_attention_mask).to(device)
                predictions = torch.argmax(logits, dim=1)
                detached_predictions = predictions.detach().cpu().numpy()
               
                loss = loss_fn(logits, valid_labels)
                valid_loss += loss.detach().cpu().numpy().item()

                y_pred.extend(predictions.cpu().numpy())
                y_true.extend(valid_labels.cpu().numpy())

            valid_loss /= valid_step
            f1 = f1_score(y_true,y_pred)

            print(f'Epoch [{epoch+1}/{epochs}] Score: {f1}')
            print(f'Epoch [{epoch+1}/{epochs}] Valid_loss: {valid_loss}')

            if valid_loss < min(valid_loss_min):
                print('model improved!')
            else:
                print('model not improved')
   
            torch.save(model.state_dict(), f'epoch:{epoch+1}_model.pt')#state_dict 是一个字典对象,包含了模型的所有可学习参数(如权重和偏置)及其当前值
            print('save checkpoint!')
            valid_loss_min.append(valid_loss)
            print(f'valid_loss_min:{min(valid_loss_min)}')

      best_model_epoch.append(f'/kaggle/working/epoch:{epoch+1}_model.pt')
      valid_loss_values.append(valid_loss)
      print('='*100)

    select_best_model() # refer to below function
    print('Train/Valid Completed!!')
    del train_dataloader, valid_dataloader # memory cleaning
    gc.collect()

def select_best_model():
    best_model = best_model_epoch
    os.rename(best_model, best_model.split('.pt') + '_best.pt')#重命名文件

FishC 发表于 2024-11-3 16:13:25

Terence888 发表于 2024-11-03 16:07
-------------------------------------------------- ...

从错误信息来看,`KeyError: 'labels'` 表示在 `batch` 字典中找不到 `labels` 键。要解决这个问题,你需要确保在数据加载器中正确地将 `labels` 包含在 `batch` 中。

以下是一些可能的解决方案:

1. **检查数据集的 `__getitem__` 方法**:确保在 `LLMDataset` 的 `__getitem__` 方法中,`inputs` 字典中包含 `labels` 键。

2. **检查数据加载器**:确保在创建数据加载器时,`collate_fn` 函数正确地将 `labels` 包含在 `batch` 中。

3. **修改 `train` 函数**:在 `train` 函数中,确保从 `batch` 中正确地提取 `labels`。

以下是一些可能的代码修改:

### 修改 `LLMDataset` 的 `__getitem__` 方法

确保 `inputs` 字典中包含 `labels`:

def __getitem__(self, idx):
    inputs = prepare_input(self.cfg, self.texts)
    if self.is_grad:
      labels = self.df.loc# 假设标签列名为 'label'
      inputs['labels'] = torch.tensor(labels, dtype=torch.float).unsqueeze(dim=0)
    return inputs

### 修改 `train` 函数

确保从 `batch` 中正确地提取 `labels`:

for batch in pbar:
    optimizer.zero_grad()
    train_step += 1

    train_input_ids = batch['input_ids'].to(device)
    train_attention_mask = batch['attention_mask'].to(device)
    train_token_type_ids = batch['token_type_ids'].to(device)
    train_labels = batch['labels'].squeeze().to(device).long()

    logits = model(train_input_ids, train_attention_mask, train_token_type_ids).to(device)
    predictions = torch.argmax(logits, dim=1)
    detached_predictions = predictions.detach().cpu().numpy()

    loss = loss_fn(logits, train_labels)
    loss.backward()
    optimizer.step()
    model.zero_grad()

    train_loss += loss.detach().cpu().numpy().item()

    pbar.set_postfix({'train_loss': train_loss / train_step})

确保在数据集和数据加载器中正确地处理 `labels`,这样在训练过程中就不会出现 `KeyError

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

FishC 发表于 2024-11-3 16:13:30

Terence888 发表于 2024-11-03 16:07
-------------------------------------------------- ...

从错误信息来看,`KeyError: 'labels'` 表示在数据加载器中没有找到 `labels` 这个键。要解决这个问题,你需要确保在数据集的 `__getitem__` 方法中正确地将 `labels` 键值对添加到返回的字典中。

以下是一些可能的解决方案:

1. **检查数据集的 `__getitem__` 方法**:确保 `inputs` 字典中包含 `labels` 键。

2. **确保数据加载器返回的批次包含 `labels`**:在训练循环中,`batch` 应该是一个包含 `labels` 的字典。

以下是如何修改 `LLMDataset` 类的 `__getitem__` 方法以确保 `labels` 被正确添加:

def __getitem__(self, idx):
    inputs = prepare_input(self.cfg, self.texts)
    if self.is_grad:
      labels = self.df.iloc['label']# 假设标签列名为 'label'
      inputs['labels'] = torch.tensor(labels, dtype=torch.float).unsqueeze(dim=0)
    return inputs

3. **检查训练循环**:在训练循环中,确保你正确地从 `batch` 中提取 `labels`:

for batch in pbar:
    train_input_ids = batch['input_ids'].to(device)
    train_attention_mask = batch['attention_mask'].to(device)
    train_token_type_ids = batch['token_type_ids'].to(device)
    train_labels = batch['labels'].squeeze().to(device).long()

确保数据集和数据加载器的实现与模型训练代码一致,这样可以避免 `KeyError`。如果 `labels` 是从数据集中提取的,确保数据集的每个样本都包含 `labels

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

Terence888 发表于 2024-11-3 16:19:11

FishC 发表于 2024-11-3 16:13
从错误信息来看,`KeyError: 'labels'` 表示在 `batch` 字典中找不到 `labels` 键。要解决这个问题,你 ...

class CollateCls:
    def __init__(self, cfg):
      self.tokenizer = cfg.tokenizer
      self.cfg = cfg
      
    def __call__(self, batch):
      output = dict()
      output["input_ids"] = for sample in batch]
      output["attention_mask"] = for sample in batch]
      output["token_type_ids"] = for sample in batch]
      # calculate max token length of this batch
      batch_max = max(])

      # add padding
      if self.tokenizer.padding_side == "right":
            output["input_ids"] = [
                list(s) + (batch_max - len(s)) *
                for s in output["input_ids"]
            ]
            output["attention_mask"] = [
                list(s) + (batch_max - len(s)) * for s in output["attention_mask"]
            ]
            output["token_type_ids"] = for s in output["token_type_ids"]]

      else:
            output["input_ids"] = [
                (batch_max - len(s)) * + list(s)
                for s in output["input_ids"]
            ]
            output["attention_mask"] = [
                (batch_max - len(s)) * + list(s) for s in output["attention_mask"]
            ]
            output["token_type_ids"] = [(batch_max - len(s)) * + list(s) for s in output["token_type_ids"]]
      
      
      # convert to tensors
      output["input_ids"] = torch.tensor(output["input_ids"], dtype=torch.long)
      output["attention_mask"] = torch.tensor(output["attention_mask"], dtype=torch.long)
      output["token_type_ids"] = torch.tensor(output["token_type_ids"], dtype=torch.long)
      
      return output

如何确保在创建数据加载器时,`collate_fn` 函数正确地将 `labels` 包含在 `batch` 中

FishC 发表于 2024-11-3 16:19:22

Terence888 发表于 2024-11-03 16:19
class CollateCls:
    def __init__(self, cfg):
...

要确保在创建数据加载器时,`collate_fn` 函数正确地将 `labels` 包含在 `batch` 中,你需要在 `CollateCls` 类的 `__call__` 方法中处理 `labels`。假设每个样本是一个字典,包含 `input_ids` 和 `labels`,你可以这样修改 `CollateCls`:

class CollateCls:
    def __init__(self, cfg):
      self.tokenizer = cfg.tokenizer
      self.cfg = cfg
      
    def __call__(self, batch):
      input_ids = for sample in batch]
      labels = for sample in batch]

      # calculate max token length of this batch
      batch_max = max()

      # add padding
      if self.tokenizer.padding_side == "right":
            input_ids = [
                list(ids) + (batch_max - len(ids)) *
                for ids in input_ids
            ]
      else:
            input_ids = [
                (batch_max - len(ids)) * + list(ids)
                for ids in input_ids
            ]
      
      # convert to tensors
      input_ids = torch.tensor(input_ids, dtype=torch.long)
      labels = torch.tensor(labels, dtype=torch.float)# or torch.long, depending on your use case
      
      return {'input_ids': input_ids, 'labels': labels}

在这个修改后的代码中:

1. **提取 `input_ids` 和 `labels`**:从 `batch` 中分别提取 `input_ids` 和 `labels`。
2. **计算最大长度并填充**:根据 `input_ids` 的最大长度进行填充。
3. **转换为张量**:将 `input_ids` 和 `labels` 转换为 PyTorch 张量。
4. **返回字典**:返回一个包含 `input_ids` 和 `labels` 的字典。

这样,`collate_fn` 函数就能正确地将 `labels` 包含在 `batch` 中。确保在创建数据加载器时使用这个 `collate_fn

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

Terence888 发表于 2024-11-3 16:27:04

FishC 发表于 2024-11-3 16:19
要确保在创建数据加载器时,`collate_fn` 函数正确地将 `labels` 包含在 `batch` 中,你需要在 `Collat ...

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In, line 4
      1 print('Training Start!')
      2 print('=' * 100)
----> 4 train(model,
      5   device,
      6   train_dataloader,
      7   valid_dataloader,
      8   CFG.epochs,
      9   loss_fn,
   10   optimizer,
   11   metric)
   13 del model,train_dataloader, valid_dataloader
   14 gc.collect()

Cell In, line 17, in train(model, device, train_dataloader, valid_dataloader, epochs, loss_fn, optimizer, metric)
   14 train_step = 0
   15 pbar = tqdm(train_dataloader, total=len(train_dataloader))#tqdm参数是一个iterable
---> 17 for batch in pbar: # you can also write like "for batch in tqdm(train_dataloader"
   18   optimizer.zero_grad() # initialize
   19   train_step += 1

File /opt/conda/lib/python3.10/site-packages/tqdm/notebook.py:250, in tqdm_notebook.__iter__(self)
    248 try:
    249   it = super().__iter__()
--> 250   for obj in it:
    251         # return super(tqdm...) will not catch exception
    252         yield obj
    253 # NB: except ... [ as ...] breaks IPython async KeyboardInterrupt

File /opt/conda/lib/python3.10/site-packages/tqdm/std.py:1181, in tqdm.__iter__(self)
   1178 time = self._time
   1180 try:
-> 1181   for obj in iterable:
   1182         yield obj
   1183         # Update and possibly print the progressbar.
   1184         # Note: does not call self.update(1) for speed optimisation.

File /opt/conda/lib/python3.10/site-packages/torch/utils/data/dataloader.py:630, in _BaseDataLoaderIter.__next__(self)
    627 if self._sampler_iter is None:
    628   # TODO(https://github.com/pytorch/pytorch/issues/76750)
    629   self._reset()# type: ignore
--> 630 data = self._next_data()
    631 self._num_yielded += 1
    632 if self._dataset_kind == _DatasetKind.Iterable and \
    633         self._IterableDataset_len_called is not None and \
    634         self._num_yielded > self._IterableDataset_len_called:

File /opt/conda/lib/python3.10/site-packages/torch/utils/data/dataloader.py:1344, in _MultiProcessingDataLoaderIter._next_data(self)
   1342 else:
   1343   del self._task_info
-> 1344   return self._process_data(data)

File /opt/conda/lib/python3.10/site-packages/torch/utils/data/dataloader.py:1370, in _MultiProcessingDataLoaderIter._process_data(self, data)
   1368 self._try_put_index()
   1369 if isinstance(data, ExceptionWrapper):
-> 1370   data.reraise()
   1371 return data

File /opt/conda/lib/python3.10/site-packages/torch/_utils.py:706, in ExceptionWrapper.reraise(self)
    702 except TypeError:
    703   # If the exception takes multiple arguments, don't try to
    704   # instantiate since we don't know how to
    705   raise RuntimeError(msg) from None
--> 706 raise exception

TypeError: Caught TypeError in DataLoader worker process 0.
Original Traceback (most recent call last):
File "/opt/conda/lib/python3.10/site-packages/torch/utils/data/_utils/worker.py", line 309, in _worker_loop
    data = fetcher.fetch(index)# type: ignore
File "/opt/conda/lib/python3.10/site-packages/torch/utils/data/_utils/fetch.py", line 55, in fetch
    return self.collate_fn(data)
File "/tmp/ipykernel_30/3299407265.py", line 89, in __call__
    output['labels'] = torch.tensor(output['labels'], dtype=torch.long)
TypeError: only integer tensors of a single element can be converted to an index
再次报错如上
函数如何修改class CollateCls:
    def __init__(self, cfg):
      self.tokenizer = cfg.tokenizer
      self.cfg = cfg
      
    def __call__(self, batch):
      output = dict()
      output["input_ids"] = for sample in batch]
      output["attention_mask"] = for sample in batch]
      output["token_type_ids"] = for sample in batch]
      output['labels'] = for sample in batch]
      # calculate max token length of this batch
      batch_max = max(])

      # add padding
      if self.tokenizer.padding_side == "right":
            output["input_ids"] = [
                list(s) + (batch_max - len(s)) *
                for s in output["input_ids"]
            ]
            output["attention_mask"] = [
                list(s) + (batch_max - len(s)) * for s in output["attention_mask"]
            ]
            output["token_type_ids"] = for s in output["token_type_ids"]]

      else:
            output["input_ids"] = [
                (batch_max - len(s)) * + list(s)
                for s in output["input_ids"]
            ]
            output["attention_mask"] = [
                (batch_max - len(s)) * + list(s) for s in output["attention_mask"]
            ]
            output["token_type_ids"] = [(batch_max - len(s)) * + list(s) for s in output["token_type_ids"]]
      
      
      # convert to tensors
      output["input_ids"] = torch.tensor(output["input_ids"], dtype=torch.long)
      output["attention_mask"] = torch.tensor(output["attention_mask"], dtype=torch.long)
      output["token_type_ids"] = torch.tensor(output["token_type_ids"], dtype=torch.long)
      output['labels'] = torch.tensor(output['labels'],dtype=torch.float).unsqueeze(dim=0)
      
      return output

FishC 发表于 2024-11-3 16:27:16

Terence888 发表于 2024-11-03 16:27
-------------------------------------------------- ...

从错误信息来看,`TypeError: only integer tensors of a single element can be converted to an index` 表示在尝试将 `output` 转换为张量时出现了问题。这个问题通常是因为 `output` 的结构不正确,可能是因为 `output` 包含了不正确的数据类型或格式。

以下是如何修改 `CollateCls` 类的 `__call__` 方法,以确保正确处理 `batch` 中的 `input_ids` 和 `labels`:

class CollateCls:
    def __init__(self, cfg):
      self.tokenizer = cfg.tokenizer
      self.cfg = cfg
      
    def __call__(self, batch):
      input_ids = for sample in batch]
      labels = for sample in batch]

      # calculate max token length of this batch
      batch_max = max()

      # add padding
      if self.tokenizer.padding_side == "right":
            input_ids = [
                ids + * (batch_max - len(ids))
                for ids in input_ids
            ]
      else:
            input_ids = [
                * (batch_max - len(ids)) + ids
                for ids in input_ids
            ]
      
      # convert to tensors
      input_ids = torch.tensor(input_ids, dtype=torch.long)
      labels = torch.tensor(labels, dtype=torch.float)# or torch.long, depending on your use case
      
      return {'input_ids': input_ids, 'labels': labels}

### 关键修改:

1. **提取 `input_ids` 和 `labels`**:从 `batch` 中分别提取 `input_ids` 和 `labels`。
2. **填充 `input_ids`**:根据 `batch_max` 的长度进行填充,使用 `self.tokenizer.pad_token_id` 作为填充值。
3. **转换为张量**:将 `input_ids` 和 `labels` 转换为 PyTorch 张量。
4. **返回字典**:返回一个包含 `input_ids` 和 `labels` 的字典。

确保在数据集的 `__getitem__` 方法中返回的每个样本是一个包含 `input_ids` 和 `labels` 的字典,这样 `collate_fn` 函数才能正确处理这些数据。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
页: [1]
查看完整版本: 如何在生成的inputs字典中正确加入labels这个键值对