pytorch文本数据处理
目录
- pytorch文本数据处理
- 1. Pytorch背景
- 2. 数据分割
- 3. 数据加载
- Dataset
- 代码分析
- 字典的用途
- 代码修改的目的
- Dataloader
- 4. 练习
原学习任务链接
相关数据链接:https://pan.baidu.com/s/1iwE3LdRv3uAkGGI2fF9BjA?pwd=ro0v
提取码:ro0v
–来自百度网盘超级会员V4的分享
1. Pytorch背景
Pytorch介绍
PyTorch是一个开源的Python机器学习库,应用于人工智能领域,如自然语言处理。它主要由Facebook的人工智能研究团队开发。
Pytroch 数据处理流程
Pytorch的数据处理流程主要是数据分割和数据加载这两部分,其中数据分割包含创建Dataset和DataLoader,循环DataLoader,将text, label加载到模型中进行训练。
2. 数据分割
随机将一个数据集分割成给定长度的不重叠的新数据集。可选择固定生成器以获得可复现的结果(效果同设置随机种子)。
torch.utils.data.random_split(dataset, lengths, generator=<torch._C.Generator object>)
参数介绍:
dataset (Dataset) :要分割的数据集。
lengths (Sequence) :要分割的长度。
generator (Generator) :用于随机排列的生成器。
import torch
from torch.utils.data import random_split
dataset = range(10) # range类型,可以通过for循环或者直接转换为list后打印出来。
train_dataset, test_dataset = random_split(dataset=dataset,lengths=[7, 3],generator=torch.Generator().manual_seed(0)) #分割测试和训练集
print(list(train_dataset))
print(list(test_dataset))
[4, 1, 7, 5, 3, 9, 0]
[8, 6, 2]
C:\Users\chengyuanting\.conda\envs\pytorch_cpu\lib\site-packages\tqdm\auto.py:22: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
from .autonotebook import tqdm as notebook_tqdm
’ generator=torch.Generator().manual_seed(0) '解析:
-
’ torch.Generator() ’ :这是一个PyTorch对象,提供了生成随机数的机制。PyTorch中使用生成器来管理各种随机数生成函数和操作的随机数生成状态,特别是那些涉及随机过程的随机数生成,如洗牌数据或初始化权重。使用生成器确保随机数的生成更容易控制和再现。
-
’ .manual_seed(0) ’ :在生成器对象上调用此方法以设置其种子。设置种子是编程中的一种常见做法,特别是在机器学习和数据科学中,以确保结果的可重复性。当您设置种子时,它将随机数生成器初始化为已知状态。在本例中,种子被设置为’ 0 '。因此,每次运行此代码时,生成器都会生成相同的随机数序列,这反过来意味着每次执行代码时,诸如变换或分割数据集之类的操作都会产生相同的结果。
在代码片段的上下文中,您将数据集拆分为训练集和测试集,“generator=torch.Generator().manual_seed(0)”用于确保拆分是可重复的。这意味着每次运行代码时,您都会得到相同的训练和测试子集,这在实验设置中通常是理想的,因为您希望在不同的运行中得到一致的结果。
3. 数据加载
Pytorch的数据加载主要依赖torch.utils.data.Dataset和torch.utils.data.DataLoader两个模块,可以完成傻瓜式加载。
Dataset
Pytorch中,任何基于索引读取数据(map-style: from keys to data samples)的类均需继承torch.utils.data.Dataset,该类为数据的读取定义了格式。我们可以通过torch.utils.data.Dataset源码得到该类的具体结构:
class Dataset(object):
def __getitem__(self, index):
raise NotImplementedError
def __add__(self, other):
return ConcatDataset([self, other])
数据示例:
# 创建自定义的Dataset
import pandas as pd
import torch
from torch.utils.data import Dataset
class textDataset(Dataset):
def __init__(self,csv_path):
# Initialize file path or list of file names.
super().__init__()
self.install_data = pd.read_csv(csv_path, encoding='utf8', sep=',')
def __len__(self):
# You should change 0 to the total size of your dataset.
return len(self.install_data)
def __getitem__(self, idx):
# 1. Read one data from file (e.g. using numpy.fromfile, PIL.Image.open).
# 2. Preprocess the data (e.g. torchvision.Transform).
# 3. Return a data pair (e.g. image and label).
#这里需要注意的是,第一步:read one data,是一个data
input_data = pd.DataFrame([])
label = pd.DataFrame([])
input_data = self.install_data.iloc[idx, 3]
label = self.install_data.iloc[idx, 0]
return label, input_data
#实例化
lyrics = textDataset('./data/songdata.csv')
label = []
label,text = lyrics[20:50]
print('label:',label[20],'\nlyrics: ',text[20]) #读取第20行的歌手label和歌词text
label: ABBA
lyrics: I'm down and I feel depressed
Sitting here just waiting
For next bus travelling
Downtown
It's a crying shame
Isn't it
The beautiful weather
If I could have my way
Well, I would not be working
On a day like this I know what I'd like to be
As free as a bumble bee
Take a sip from
Every flower
Free as a bumble bee
While away each lazy hour
What a good life
Lying laid back
Like an old railroad bum by the track
What a good life
Living outdoors
Lie in the grass and chew on a straw
针对以上通用代码,GPT提出的定制化建议:
您的代码通常结构良好,可以在PyTorch中定义自定义’ Dataset '类来处理CSV文件中的数据。但是,要使其正常工作,需要解决一些问题:
-
在’ getitem '中切片:PyTorch ’ Dataset ‘中的’ getitem ‘方法被设计用于处理单个项目访问,而不是切片(如’ lyrics[20:50] ‘)。如果你想访问一个范围的项,你应该遍历索引或修改’ getitem '方法来处理切片。
-
DataFrame初始化:在’ getitem ‘方法中,您将’ input_data ‘和’ label '初始化为空DataFrame,但随后您为它们分配一个来自Series的值。这是不必要的;您可以直接赋值。
-
返回张量:通常,PyTorch数据集以PyTorch张量的形式返回数据。如果你的’ input_data ‘和’ label '还不是张量,你可能需要在返回之前转换它们。
-
切片语法错误:在’ label, text = lyrics[20:50] ‘行中,您试图解压缩切片操作的结果,这将不会像当前’ getitem '定义所期望的那样工作。
这是你的代码调整后的版本(确实要比原版代码好哈哈哈):
class textDataset(Dataset):
def __init__(self, csv_path):
super().__init__()
self.install_data = pd.read_csv(csv_path, encoding='utf8', sep=',')
def __len__(self):
return len(self.install_data)
def __getitem__(self, idx):
if torch.is_tensor(idx):
idx = idx.tolist()
input_data = self.install_data.iloc[idx, 3]
label = self.install_data.iloc[idx, 0]
# Convert to tensor if necessary, e.g.:
# input_data = torch.tensor(input_data)
# label = torch.tensor(label)
return label, input_data
# To access a range of items, you can do something like this:
lyrics = textDataset('./data/songdata.csv')
for i in range(20, 50):
label, text = lyrics[i]
print(f'label: {label}, lyrics: {text}')
label: ABBA, lyrics: I'm down and I feel depressed
Sitting here just waiting
For next bus travelling
Downtown
It's a crying shame
Isn't it
The beautiful weather
If I could have my way
Well, I would not be working
On a day like this I know what I'd like to be
As free as a bumble bee
Take a sip from
Every flower
Free as a bumble bee
While away each lazy hour
What a good life
Lying laid back
Like an old railroad bum by the track
What a good life
Living outdoors
Lie in the grass and chew on a straw
label: ABBA, lyrics: Twinkle, Twinkle little star
How I wonder what you are
Like a diamond glitt'ring in the sky
Seems to me you shine your light
Down to me to say goodnight
Twinkle, Twinkle my old friend
Sleep is waiting round the bend
While you travel through the milky way
From afar
Twinkle, Twinkle, Twinkle little star.
...
Knowing me, knowing you (ah-haa)
There is nothing we can do
Knowing me, knowing you (ah-haa)
We just have to face it, this time we're through
(This time we're through, this time we're through
This time we're through, we're really through)
Breaking up is never easy, i know but i have to go
(I have to go this time
I have to go, this time i know)
Knowing me, knowing you
It's the best i can do
import time
import torchtext
from torchtext.data.utils import get_tokenizer
from torchtext.vocab import build_vocab_from_iterator
tokenizer = get_tokenizer('basic_english')
train_iter = lyrics
def yield_tokens(data_iter):
# for _,text in data_iter:
# yield tokenizer(text)
for i in range(len(data_iter)): # 通过索引去遍历整个数据集
_, text = data_iter[i]
yield tokenizer(text)
start = time.time()
vocab = build_vocab_from_iterator(yield_tokens(train_iter), specials=["<unk>"])
cost = time.time() - start
print(f"Build vocab cost: {cost:.4f}")
vocab.set_default_index(vocab["<unk>"])
print('The vocabulary "wonderful" is ', vocab['wonderful'])
print('The vocabulary "beautiful" is ', vocab['beautiful'])
Build vocab cost: 9.8542
The vocabulary "wonderful" is 991
The vocabulary "beautiful" is 430
当然,我将逐句分析您的代码,并解释建立字典的用途,以及对代码的修改如何确保正确遍历数据集。
代码分析
-
导入模块和设置分词器:
import time import torchtext from torchtext.data.utils import get_tokenizer from torchtext.vocab import build_vocab_from_iterator tokenizer = get_tokenizer('basic_english')
这段代码导入了必要的模块,并创建了一个用于英语的基本分词器。分词器的作用是将文本分割成单词或词素。
-
定义数据迭代器:
train_iter = lyrics
这里将自定义的数据集
lyrics
赋值给train_iter
,意味着后续的操作将对这个数据集进行迭代。 -
定义生成单词的函数:
def yield_tokens(data_iter): for i in range(len(data_iter)): # Iterating through the dataset _, text = data_iter[i] yield tokenizer(text)
这个函数遍历数据集
data_iter
,对每个样本的文本部分应用分词器,并逐个产生单词。我在这里修改了遍历方式,使用索引来确保可以逐个访问数据集中的每个样本。 -
建立词汇表:
start = time.time() vocab = build_vocab_from_iterator(yield_tokens(train_iter), specials=["<unk>"]) cost = time.time() - start print(f"Build vocab cost: {cost:.4f}")
这段代码使用从数据集中提取的单词建立词汇表,并记录所花费的时间。
specials=["<unk>"]
表示在词汇表中添加一个特殊的未知单词标记<unk>
。 -
设置未知单词的默认索引:
vocab.set_default_index(vocab["<unk>"])
这行代码设定了对于词汇表中不存在的单词,默认返回
<unk>
的索引。 -
获取特定单词的索引:
print('The vocabulary "wonderful" is ', vocab['wonderful']) print('The vocabulary "beautiful" is ', vocab['beautiful'])
这里打印了单词 “wonderful” 和 “beautiful” 在词汇表中的索引。
字典的用途
建立字典(词汇表)在自然语言处理(NLP)中非常重要,主要用途包括:
-
单词到索引的映射:字典提供了一种将单词转换为数字索引的方式,这对于计算机处理文本数据是必要的。
-
统计和限制词汇:通过字典,可以控制模型学习的词汇范围,并且可以统计和分析数据集中单词的出现频率。
-
数据预处理:在训练神经网络模型时,通常需要将文本转换为数值形式,字典是实现这一转换的关键组件。
代码修改的目的
原始代码中,yield_tokens
函数直接遍历 data_iter
,这在某些情况下可能会导致问题,因为标准的 PyTorch Dataset
类不支持直接通过 for 循环进行遍历。通过使用索引访问每个元素,可以确保无论 Dataset
的具体实现如何,代码都能正确地访问每个数据点。这种方法更加通用,可以适用于更广泛的 Dataset
实现。
Dataloader
torch.utils.data.DataLoader是实际的数据采样器/迭代器,以单/多进程迭代的方式在封装的Dataset上获取数据。具体地,迭代器DataLoader使用next()方法以不断获得数据。❗️需注意,DataLoader只读取tensor,故常需在Dataset中将源数据转化为tensor。常用模块如transforms等。
由torch.utils.data.DataLoader源码可以得到该类的参数如下,接下来简单介绍一下主要参数的用法:
class torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=False, sampler=None,
batch_sampler=None, num_workers=0, collate_fn=None,
pin_memory=False, drop_last=False, timeout=0,
worker_init_fn=None, multiprocessing_context=None)
batch_size(Int):即一次训练所抓取的数据样本数量,它的大小影响训练速度和模型优化,也同样影响每一epoch训练模型次数。设置batch_size可以使得CPU或GPU不会内存爆炸,提高了训练的速度,其次是使得梯度下降的方向更加准确。
shuffle(Boolean):shuffle是深度学习中将训练模型的数据集进行打乱的操作。原始的数据,在样本均衡的情况下可能是按照某种顺序进行排列,如前半部分为a类数据,后半部分为b类数据。但经过打乱之后数据的排列就会拥有一定的随机性,在顺序读取的时候下一次得到的样本为任何一类型的数据的可能性相同。shuffle的好处是,在针对随机性敏感的数据集上,可以提升模型质量和提升预测表现。
num_workers(Int):用于数据加载的子进程数量。 0 表示数据将在主进程中加载。
# 使用Dataloader去加载数据集
from torch.utils.data import DataLoader
dataloader = DataLoader(train_iter, batch_size=8, shuffle=False)
print('The length of dataloader is ',len(dataloader))
The length of dataloader is 7207
4. 练习
- BATCH_SIZE = 64,而数据集的大小为120,问一个epoch要训练几个批次?
answer_1 = '2' #答案填在引号内
- 使用数据分割样例代码,按照80%的训练集和20%的测试集的比例来切割’/home/mw/input/geci_82079530/songdata.csv’中的英文语料后,问训练集和测试集的数量分别是多少?
length = len(lyrics)
len_train = int(0.8*length)
len_test = int(0.2*length)
answer_2 = f'{len_train}' #训练集的样本数量,答案填在引号内
answer_3 = f'{len_test}' #测试集的样本数量,答案填在引号内