NLP基础学习-文本情感分析

一、准备数据集

  • Dataset
    其使用需要自定义一个类继承Dataset—》class ImdbDataset(Dataset):
    其主要作用是从文件中获取数据,主要有三个方法:
    __init__该方法是初始化方法,用来获取所有文件的路径
    __getitems__该方法是通过index索引获取到每个文件的内容(包括content,label),此处利用tokenlize对获取到的文本了预处理(处理掉不必要的字符)
    __len__该方法是获取整个数据集的长度
    注意: 数据集分为训练集和测试集,所以此处在处理数据集的时候,需要标注如 def init(self, train=True): 默认是训练集
# 获取数据集,train,或者test
class ImdbDataset(Dataset):
    def __init__(self, train=True):
        self.train_data_path = r"aclImdb\train"
        self.test_data_path = r"aclImdb\test"
        data_path = self.train_data_path if train else self.test_data_path
        temp_data_path = [os.path.join(data_path, "pos"), os.path.join(data_path, "neg")]
        self.total_file_path = []
        for path in temp_data_path:
            file_name_list = os.listdir(path)
            file_path_list = [os.path.join(path, i) for i in file_name_list if i.endswith(".txt")]
            self.total_file_path.extend(file_path_list)
    def __getitem__(self, index):
        file_path = self.total_file_path[index]
        label_str = file_path.split("\\")[-2]
        label = 0 if label_str == "neg" else 1
        content = open(file_path,encoding="utf-8").read()
        tokens = tokenlize(content)
        return tokens,label
    def __len__(self):
        return len(self.total_file_path)
  • Dataloader
    该模型的作用是,使数据可迭代,可以设置batchsize(多通道),shuffle(每次取数据重排序),使用方法如下:
	imdb_dataset = ImdbDataset(train)
    # 如果此处要设置batch_size为>1的数字,则需要设置collate_fn
    data_loader = DataLoader(imdb_dataset, batch_size=128, shuffle=True,collate_fn=collate_fn)

此处需要注意,只要batch_size>1,可能会爆出这样的错误:RuntimeError: each element in list of batch should be of equal size,其原因在Dataloader的源码,要解决这个问题,可以采取以下两种方式:
(1)考虑先把数据转化为数字序列
(2)考虑自定义一个collate_fn
此处采用第二种方法:

def collate_fn(batch):
    #  batch是一个列表,其中是一个一个的元组,每个元组是dataset中_getitem__的结果(tokens,label)
    # zip(*) 相当于解压缩的意思,zip(*[(1,2),(3,4),(5,6))-->[(1,3,5),(2,4,6)]
    content,label = list(zip(*batch))
    # label = torch.tensor(label, dtype=torch.int32)
    # content = content
    # 此处的transform是将文本转化成数值,具体方法在ws里,其中ws是一个被封装的字典(源文件在wordsquence类里,内部有词--》数值,数值--》词,及相应转化方法)该类被封装到pickle类型的文件中,为了方便读取
    content = [ws.transform(i,max_len = max_len) for i in content]
    # 因为torch.tensor 是float 32类型,此处的content数值是int类型,需要用torch.LongTensor
    content = torch.LongTensor(content)
    label = torch.LongTensor(label)
    # del batch
    return content, label
  • tokenlize
    其作用是处理文本中多余的字符,并进行简单的分词,此处是英文分词
def tokenlize(content):
    content = content.replace("'s"," is")
    content = content.replace("n't"," not")
    content = re.sub("<.*?>"," " ,content)
    fileters = ["\(","\)","\t", "\n", "\x97", "\x96", "#", "$", "%","\0x93", "&", "\.", ",","!",":","\"","\'","\?","\x95"]
    content = re.sub("|".join(fileters)," ", content)
    tokens = [i.strip().lower() for i in content.split()]
    # tokens = [item.lower() for item in tokens]
    return tokens

二、构建模型

到此处,已经有字典(用于比对的数据,存于ws中),数据集(经过清洗的用于训练和测试的数据,存于get_dataloader(train=True)方法中)

  • 定义模型类,继承自torch.nn.Model
class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        # Embedding(num_embeddings: int-训练集使用的字典的总长度, embedding_dim: int)  --》(长度,用多少向量表示一个词)
        self.embedding = nn.Embedding(len(ws),100)
        # nn.Linear(input类型,output类型)
        self.fc = nn.Linear(max_len*100,2)
    def forward(self, input):
    # 此处input与dataset中input一致
        """
        :param input: [batch_size,max_len]
        :return:
        """
        x = self.embedding(input) # 经过embedding后,x是三维的,[batch_size,max_len,100]
        # 将三维的x变形成二维的,为了进行fc(x)-->linear(input,output)的矩阵计算,此处,x的第二维度需要与input的维度一致
        x = x.view([-1,100*max_len])
        out = self.fc(x)
    # dim = -1 在最后一个维度进行操作
        return F.log_softmax(out,dim = -1)

关于这个模型,还有一些不明白,比如nn.embedding的作用,引入后会发生什么变化,linear在此处的作用,其维度与其他数据之间的关联?后期希望能解决!

三、训练模型

  • 创建模型对象
  • 定义优化器对象,此处使用from torch.optim import Adam
  • 定义训练方法
    (1)导入参数
    (2)梯度设为0
    (3)调用模型 output = model(input)
    (4)计算损失 loss = F.nll_loss(output,target)
    (5)反向传播 loss.backward()
    (6)更新参数
model = MyModel()
optimizer = Adam(model.parameters(),0.001)
def train(epoch):
    for idx,(input,target) in enumerate(get_dataloader(train = True)):
        #梯度设为0
        optimizer.zero_grad()
        # 传入input,计算output
        output = model(input)
        loss = F.nll_loss(output,target)
        loss.backward()
        optimizer.step()
        print(loss.item())
if __name__ == '__main__':
# 将训练集训练三次,每一次会重新打乱数据,因为(shuffle = True)
    for i in range(3):
        train(i)

四、模型评估

def test():
    mode = False
    # 将模型切换到测试模式
    model.eval()
    test_dataloader = get_dataloader(mode,batch_size = 1000)
    # 停止更新梯度,同时加速和节省显存
    loss_list = []
    acc_list = []
    with torch.no_grad():
        for idx, (input, target) in enumerate(test_dataloader):
            output = model(input)
            cur_loss = F.nll_loss(output, target)
            loss_list.append(cur_loss)
            # 获取每一行的最大值的位置,max(dim=-1)获取每行的最大值,dim=0获取每列的最大值,该值包括两个部分,最大值和最大值的位置,
            # [-1]获取位置
            # pred = output.max(dim=-1)[-1]
            pred = torch.max(output,dim = -1,keepdim = False)[-1]
            cur_acc = pred.eq(target).float().mean()
            acc_list.append(cur_acc)
    print("准确率,平均损失", np.mean(acc_list), np.mean(loss_list))
  • 此处模型评估还不太熟悉,后期补上
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值