zoukankan      html  css  js  c++  java
  • 如何在nlp问题中定义自己的数据集

    我之前大致写了一篇在pytorch中如何自己定义数据集合,在这里如何自定义数据集

    不过这个例子使用的是image,也就是图像。如果我们用到的是文本呢,处理的是NLP问题呢?

    在解决这个问题的时候,我在网上无意间搜索到这样一篇文章PyTorch 入门实战(三)——Dataset和DataLoader

    在这篇博文中,作者从dataset和dataloader一步步讲解,让我有了很大的感悟。然后我根据自己之前那篇文章,总结了一下如何在nlp问题中自定义数据集。

    首先上一个简单的例子,

    import torch
    from torch.utils.data import Dataset, DataLoader
    import numpy as np
     
    Data = np.array([[1, 2], [3, 4],[5, 6], [7, 8]])
    Label = np.array([[0], [1], [0], [2]])
    #创建子类
    class subDataset(Dataset):
        #初始化,定义数据内容和标签
        def __init__(self, Data, Label):
            self.Data = Data
            self.Label = Label
        #返回数据集大小
        def __len__(self):
            return len(self.Data)
        #得到数据内容和标签
        def __getitem__(self, index):
            data = torch.Tensor(self.Data[index])
            label = torch.IntTensor(self.Label[index])
            return data, label
    
    dataset = subDataset(Data, Label)
    print(dataset)
    print('dataset大小为:', dataset.__len__())
    print(dataset.__getitem__(0))
    print(dataset[0])
    
    #创建DataLoader迭代器
    dataloader =DataLoader(dataset,batch_size= 2, shuffle = False, num_workers= 4)
    for i, item in enumerate(dataloader):
        print('i:', i)
        data, label = item
        print('data:', data)
        print('label:', label)
    
    
    
    result:
    
    <__main__.subDataset object at 0x10b697198>
    dataset大小为: 4
    (tensor([1., 2.]), tensor([0], dtype=torch.int32))
    (tensor([1., 2.]), tensor([0], dtype=torch.int32))
    i: 0
    data: tensor([[1., 2.],
            [3., 4.]])
    label: tensor([[0],
            [1]], dtype=torch.int32)
    i: 1
    data: tensor([[5., 6.],
            [7., 8.]])
    label: tensor([[0],
            [2]], dtype=torch.int32)
    

    在上面这个例子中,需要特别注意的是我们定义的数据,使用的是数组形式。当我看到这一点的时候,我就很自然的联想到了这不不就是文本的数据形式吗?
    每个句子通过一个向量代表,每个向量是一个数组的元素。
    而且区别于图像,我们需要得到图像的路径,然后得到图像的数据,在文本这里,我们对句子向量化之后,这个数据可以直接被使用进来。
    这就是为啥在子类中的__init__函数和__getitem__函数比较简单的原因。

    所以我们只需要类别,把我们的句子向量转化为类似上面例子中Data的格式,Label转化为上面例子中的格式就好了。

    接下来我们进入实践环节。
    首先,我们从[这里(https://github.com/DA-southampton/cnn-lstm-bilstm-deepcnn-clstm-in-pytorch/tree/master/Data)中的训练数据中截取了2000条保存下来,作为我们的训练数据,命名为train.txt。

    数据形式大概是这样的:A lovely film for the holiday season . ||| 3

    接下来上代码:

    #首先读取数据集合,并且构建词汇表格
    file = open('train.txt','r')
    
    i = 0
    data,tag,sentence_lst = [],[],[]
    word_to_idx,idx_to_word = {},{}
    
    
    for line in file:
        lst=line.strip().split('|||')
        if len(lst)!=2: #确保上一步拆分成句子和类别的元素才进行下面的操作,保证成功
                continue
        sentence,label= lst[0],lst[1] #提取出句子和类别
        words=sentence.split(' ')#在中文中,这一步可以使用结巴分词操作
        for word in words:
            if word not in word_to_idx:
                word_to_idx[word] = i
                idx_to_word[i] = word
                i=i+1
            sentence_lst.append(word_to_idx[word])
            if (len(sentence_lst)>=50):
                break
        for j in range(50-len(sentence_lst)):
            sentence_lst.append(0) #这之上的操作完成了两件事情,一个是构建词汇表,二就是将句子向量化
        data.append(sentence_lst)
        tag.append([int(label)])
        sentence_lst = []
    
    
    #将list转化为数组
    data=np.array(data)
    tag=np.array(tag)  #这个步骤很重要,就是把我们生成的list转化为数组的形式
    
    
    import torch
    from torch.utils.data import Dataset, DataLoader
    import numpy as np
     
    Data =data
    Label = tag
    #创建子类
    class subDataset(Dataset):
        #初始化,定义数据内容和标签
        def __init__(self, Data, Label):
            self.Data = Data
            self.Label = Label
        #返回数据集大小
        def __len__(self):
            return len(self.Data)
        #得到数据内容和标签
        def __getitem__(self, index):
            data = torch.Tensor(self.Data[index])
            label = torch.IntTensor(self.Label[index])
            return data, label
    
    
    dataset = subDataset(Data, Label)
    print(dataset)
    print('dataset大小为:', dataset.__len__())
    print(dataset.__getitem__(0))
    print(dataset[0])
    
    #创建DataLoader迭代器
    dataloader =DataLoader(dataset,batch_size= 100, shuffle = False, num_workers= 4)
    for i, item in enumerate(dataloader):
        print('i:', i)
        data, label = item
        print('data:', data)
        print('label:', label)
    

    这样,我们就自己定义了一个数据集合并且使用dataloader将其切分。

    data.size()
    torch.Size([99, 50])#为啥是99呢,因为切分到最后不够100个了。这里不用纠结,大小就是batch_size * seq_length
    
    label.size()
    torch.Size([99, 1]) # 
    

    我们知道这里data就是我们在训练模型的时候的输入,对于这个输入我们的维度是这样的batch_size * seq_length,这一点时参考的How to correctly give inputs to Embedding, LSTM and Linear layers in PyTorch?

    这里我们得到的data正合适是符合这个size的,所以我可以把这个数据带入到模型中去。

    textcnn 模型

    import torch
    import torch.nn as nn
    import torch.nn.functional as F
    from torch.autograd import Variable
    
    class Textcnn(nn.Module):
    	def __init__(self,vocabulary_size,embedding_dim,kernel_num,batch_size,class_size,dropout):
    		super(Textcnn,self).__init__()
    		self.embedding = nn.Embedding(vocabulary_size,embedding_dim)
    		self.conv1 = nn.Conv2d(1,kernel_num,(3,embedding_dim))
    		self.conv2 = nn.Conv2d(1,kernel_num,(4,embedding_dim))
    		self.conv3 = nn.Conv2d(1,kernel_num,(5,embedding_dim))
    		self.dropout = nn.Dropout(dropout)
    		self.fc = nn.Linear(3*kernel_num,class_size)
    
    	def conv_maxplooing1(self,x):
    		x = F.relu(self.conv1(x)) #(batch_size*kernel_num*(vocabulary_len-3+1)*1)
    		x = x.squeeze(3)  #(batch_size*kernel_num*(vocabulary_len-3+1))
    		x = F.max_pool1d(x,x.size(2)).squeeze(2) #(batch_size*kernel_num)
    		return x
    	def conv_maxplooing2(self,x):
    		x = F.relu(self.conv2(x)) #(batch_size*kernel_num*(vocabulary_len-3+1)*1)
    		x = x.squeeze(3)  #(batch_size*kernel_num*(vocabulary_len-3+1))
    		x = F.max_pool1d(x,x.size(2)).squeeze(2) #(batch_size*kernel_num)
    		return x
    	def conv_maxplooing3(self,x):
    		x = F.relu(self.conv3(x)) #(batch_size*kernel_num*(vocabulary_len-3+1)*1)
    		x = x.squeeze(3)  #(batch_size*kernel_num*(vocabulary_len-3+1))
    		x = F.max_pool1d(x,x.size(2)).squeeze(2) #(batch_size*kernel_num)
    		return x
    
    	def forward(self,x):
    		emb = self.embedding(x) #(batch_size*vocabulary_len*embedding_dim)
    		emb = emb.unsqueeze(1)  #(batch_size*1*vocabulary_len*embedding_dim)
    		out1 = self.conv_maxplooing1(emb) #(batch_size*kernel_num)
    		out2 = self.conv_maxplooing2(emb)
    		out3 = self.conv_maxplooing3(emb)
    		out = torch.cat((out1,out2,out3),1) #(batch_size*(kernel_num*3))
    		out = self.dropout(out)
    		result = self.fc(out)  #(batch_size*class_size)
    		return result
    
    

    但是令人惊讶的是,在带入data的时候,出现了错误,错误代码大致是这样的:Expected tensor for argument #1 'indices' to have scalar type Long; but got CPUFloatTensor instead (while checking arguments for embedding)

    就是讲,你这个输入tesor格式不对,应该long,而不是float
    于是我要进行一个操作

    data=data.long()
    label=label.squeeze(1).long() ##注意这里我们把label去除了一个维度,通过上面我们知道,label维度本来是99*1,也就是这样的[[1],[2],[3]...],我们需要把它转化为这种[1,2,3...]才能在模型中使用
    
    for i, item in enumerate(dataloader):
        data, label = item
        data=data.long()
        label=label.squeeze(1).long()
        outputs = model(sentence.long())
        loss = criterion(outputs, label.squeeze(1).long())
    

    具体详细的展示我会弄一个ipynb

  • 相关阅读:
    操作系统
    Typora
    C++
    linux sftp 和scp 运用
    python GIL锁与多cpu
    django model 高级进阶
    django template 模板
    django view 视图控制之数据返回的视图函数
    django 创建管理员用户
    jango 模型管理数据model入门
  • 原文地址:https://www.cnblogs.com/lzida9223/p/10536167.html
Copyright © 2011-2022 走看看