def dataloader(tokens, context_length, batch_size):
# returns inputs, targets as torch Tensors of shape (B, T), (B, )
n = len(tokens) # 计算 tokens 的长度 n,用于后续的遍历。
inputs, targets = [], [] # 创建空的列表 inputs 和 targets 用于存储输入数据和目标数据。
pos = 0 # 定义 pos 变量,表示当前窗口的起始位置。
while True: # 进入一个 while 循环,用于不断生成批次数据。
# simple sliding window over the tokens, of size context_length + 1
window = tokens[pos:pos + context_length + 1] # 取从当前 pos 开始的 context_length + 1 个 token 作为窗口。
inputs.append(window[:-1]) # 取窗口中的前 context_length 个 token 作为输入,并将它们添加到 inputs 列表中。
targets.append(window[-1]) # 取窗口中的最后一个 token 作为目标,并将它添加到 targets 列表中。
# once we've collected a batch, emit it
if len(inputs) == batch_size: # 当 inputs 列表的长度等于 batch_size 时,生成当前批次的输入和目标张量。
yield (torch.tensor(inputs), torch.tensor(targets)) # 使用 yield 关键字返回它们。此时 dataloader 函数成为一个生成器,能够在训练过程中按需提供数据。
inputs, targets = [], [] # 重置 inputs 和 targets 列表以收集下一个批次的数据。
# advance the position and wrap around if we reach the end
pos += 1 # 将 pos 前移一个 token。
if pos + context_length >= n: # 如果 pos 加上 context_length 超出了 tokens 的长度,则将 pos 重置为 0,从头开始循环。