李宏毅机器学习特训营机器学习作业4-语句分类

2023-10-22 06:40

本文主要是介绍李宏毅机器学习特训营机器学习作业4-语句分类,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 项目描述
    • 数据集介绍
    • 项目要求
    • 环境配置/安装
  • 编码
    • 1-of-N encoding
    • Bag of Words (BOW)
    • word embedding
  • 文本数据预处理
  • Word2Vec
  • 定义数据读取器
  • 定义模型
  • 半监督学习
  • 训练
  • 预测测试集
  • 修改
  • 总结

项目描述

  • 本次作业是要让同学接触自然语言处理当中一个简单的任务 —— 语句分类(文本分类)
  • 给定一个语句,判断他有没有恶意(负面标 1,正面标 0)

数据集介绍

有三个文件,分别是 training_label.txt、training_nolabel.txt、testing_data.txt

  • training_label.txt:有标签的训练数据(句子配上 0 or 1,+++$+++ 只是分隔符号,不要理它)

    • e.g., 1 +++$+++ are wtf … awww thanks !
  • training_nolabel.txt:没有标签的训练数据(只有句子),用来做半监督学习

    • ex: hates being this burnt !! ouch
  • testing_data.txt:你要判断测试数据里面的句子是 0 or 1

    id,text

    0,my dog ate our dinner . no , seriously … he ate it .

    1,omg last day sooon n of primary noooooo x im gona be swimming out of school wif the amount of tears am gona cry

    2,stupid boys … they ’ re so … stupid !

项目要求

  • 用一些方法 pretrain 出 word embedding (e.g., skip-gram, CBOW. )
  • 请使用 RNN 实现文本分类
  • 不能使用额外 data (禁止使用其他 corpus 或 pretrained model)

环境配置/安装

作业基于paddle2.0

pip install gensim==3.8.3
path_prefix = "./"
pip install -U numpyimport numpy
numpy.__version__'1.20.2'

先看一下文本数据。

带有标签的文本数据:
在这里插入图片描述

不带有标签的文本数据:
在这里插入图片描述

编码

计算机要分析一句话的情感,前提是计算机要能“认识”单词,这就需要把单词转为能够被计算机处理的数据。单词的表示方法有下面几种:

1-of-N encoding

也叫one-hot编码,中文翻译过来就是“独热编码”。

这里用training_ label.txt里面的一个句子:are wtf … awww thanks ! → are wtf awww thanks (去掉标点符号)

编码后就成了 a1:[1,0,0,0] are

a2:[0,1,0,0] wtf
a3:[0,0,1,0] awww
a4:[0,0,0,1] thanks (当然编码的顺序也可以变)

Bag of Words (BOW)

词袋。BOW 的概念就是将句子里的文字变成一个袋子装着这些词,BOW不考虑文法以及词的顺序。很形象的说明了一个袋子里有很多单词。

这里用training_ label.txt里面的句子: i feel icky i need a hug. 然后袋子里有单词[“i”,“feel”,“icky”,“need”,“a”,“hug”]

上面的句子的表示向量就是[2,1,1,1,1,1],含义就是"i"在句子中出现了2次,"feel"在句子中出现了1次等等

再比如一个句子i feel icky. 表示向量就是[1,1,1,0,0,0] 0就表示袋子里的单词没出现在句子里。

word embedding

词嵌入。也叫词的向量化(word to vector),即把单词变成向量(vector)。这也是作业要求的:用一些方法 pretrain 出 word embedding (e.g., skip-gram, CBOW. )

在1-of-N encoding中,表示一个单词are是[1,0,0,0],如果一个单词经过1-of-N encoding是1000维,其实是很浪费空间的,还有就是1-of-N encoding相当于简单的给每个单词编了个号,但是单词和单词之间的关系则完全体现不出来。这时候word embedding的优势就体现出来了。

word embedding可以简单地理解为:经过某种变换处理,为单词分配一个维度比较低的向量,这个向量可以丢进模型中处理。同时,向量与向量之间可能还有一些相似性,比如father和mother这两个单词的向量在空间中会比较相近,而father和pencil这两个单词的向量在空间中就会离得比较远。

安装的gensim就是常用的一个NLP工具包,其中的word2vec模块可以把单词转为向量。把很多单词转为向量后,就可以得到一个word embedding矩阵。比如:

are [0.3,0.5,0.6]
wtf [0.9,0.8,0.6]
awww [0.1,0.2,0.3]
thanks [0.8,0.7,0.6]

如果有10000个单词,每个单词分配的向量是20维,那么word embedding矩阵就是10000 20的矩阵。*

文本数据预处理

一,读取文件,这里可以用正则表达式把标点符号都去掉,然后把英文都转为小写;

比如:

import re
x=["are wtf ... awww thanks !","i know eep ! i can ' t wait for one more day ...."]
x = [re.sub(r"([.!?,'])", r"", s) for s in x]
x = [' '.join(s.split()) for s in x]
x = [s.split() for s in x]
x[['are', 'wtf', 'awww', 'thanks'],['i', 'know', 'eep', 'i', 'can', 't', 'wait', 'for', 'one', 'more', 'day']]

二,word embedding。利用gensim中的word2vec模块可以把单词转为向量。

import re
import paddle
import numpy as npdef load_training_data(path='work/data/training_label.txt'):# 读取 training 需要的数据# 如果是 'training_label.txt',需要读取 label,如果是 'training_nolabel.txt',不需要读取 labelif 'training_label' in path:with open(path, 'r') as f:lines = f.readlines()lines = [line.strip('\n') for line in lines]x = [line[10:] for line in lines]  #1 +++$+++ are wtf ... awww thanks !  从are开始往后读取x = [re.sub(r"([.!?,'])", r"", s) for s in x]x = [' '.join(s.split()) for s in x]x = [s.split() for s in x]# 每行按空格分割后,第0个符号是labely = [line[0] for line in lines]return x, yelse:with open(path, 'r') as f:lines = f.readlines()x = [line.strip('\n') for line in lines]x = [re.sub(r"([.!?,'])", r"", s) for s in x]x = [' '.join(s.split()) for s in x]x = [s.split() for s in x]return xdef load_testing_data(path='work/data/testing_data.txt'):# 读取 testing 需要的数据with open(path, 'r') as f:lines = f.readlines()# 第0行是表头id,tex,从第1行开始才是要读取的数据# 第0列是id,第1列是文本,按逗号分割,需要逗号之后的文本X = [line.strip('\n') for line in lines[2:]]#X = ["".join(line.strip('\n').split(",")[1:]).strip() for line in lines[1:]]X = [re.sub(r"([.!?,'])", r"", s) for s in X]X = [' '.join(s.split()) for s in X]X = [s.split() for s in X]return X
# 读取 训练 数据
print("加载训练数据 ...")
train_x, y = load_training_data('work/data/training_label.txt')
train_x_no_label = load_training_data('work/data/training_nolabel.txt')# 读取测试数据
print("加载测试数据 ...")
test_x = load_testing_data('work/data/testing_data.txt')
print("完成。")
#查看加载好的数据
print(train_x[0],y[0])
print(train_x_no_label[1])
print(test_x[0])

打印:
在这里插入图片描述

Word2Vec

把上面读取出来的单词转为向量,用word2vec 模块,具体 API 如下:

class gensim.models.word2vec.Word2Vec( sentences=None, size=100, alpha=0.025, window=5, min_count=5,
max_vocab_size=None,
sample=0.001,
seed=1,
workers=3,
min_alpha=0.0001,
sg=0,
hs=0,
negative=5,
cbow_mean=1,
hashfxn=,
iter=5,
null_word=0,
trim_rule=None,
sorted_vocab=1,
batch_words=10000,
compute_loss=False)

size就是词向量的维度。主要需要设置的就是size,min_count:过滤掉语料中出现频率小于min_count的词。其他都可以按默认的来。

from gensim.models.word2vec import Word2Vecdef train_word2vec(x):# 训练 word to vector 的 word embeddingmodel = Word2Vec(x, size=250, window=5, min_count=5, workers=12, iter=10, sg=1)return model# 把所有文本数据中的单词变成 向量
model = train_word2vec(train_x + train_x_no_label + test_x)
# 保存
model.save('w2v_all.model')

训练好的word embedding矩阵,可以通过Word2Vec.load()得到

想获取一个单词的词向量,可以通过embedding[‘dog’]获得。

embedding = Word2Vec.load('w2v_all.model')
embedding_dim = embedding.vector_size  #词向量维度 250
print(embedding['dog'])
print(embedding_dim) 
#可以查看一共有多少个单词
len(embedding.wv.vocab)

拿到word embedding矩阵后,需要考虑如何用到模型中去。就比如有一组单词[‘are’, ‘wtf’, ‘awww’, ‘thanks’],可以通过word embedding矩阵查到得到对应的词向量,组成一个4* 250的矩阵,然后把矩阵送到模型中。但是通过embedding[‘are’]的方式获取词向量是很麻烦的。

这里需要用paddle的一个函数,paddle.nn.Embedding(num_embeddings, embedding_dim, padding_idx=None, sparse=False, weight_attr=None, name=None)

嵌入层(Embedding Layer)
该接口用于构建 Embedding 的一个可调用对象 。其根据input中的id信息从embedding矩阵中查询对应embedding信息,并会根据输入的size (num_embeddings, embedding_dim)和weight_attr自动构造一个二维embedding矩阵。

这里先把构造方法给出来embedding=paddle.nn.Embedding(embedding.shape[0],embedding.shape[1],weight_attr=paddle.framework.ParamAttr(initializer=paddle.nn.initializer.Assign(embedding)))

这句代码的意思就是构造了一个embedding层,层的参数初始化为word embedding矩阵中的向量的值。当一个输入进来后,会根据输入矩阵中的值(单词的序号)查找对应词向量,如下图所示:
在这里插入图片描述
现在明白了embedding层可以通过inputs输入中的值,找到对应的词向量。

现在就把一组单词变成一组序号;比如[‘are’, ‘wtf’, ‘awww’, ‘thanks’] → [1,2,3,4]

序号又怎么来?就是通过查找一个单词在词袋中的位置。比如有词袋:

[‘are’, ‘wtf’, ‘awww’, ‘thanks’,‘to’, ‘find’, ‘out’, ‘that’, ‘the’, ‘ending’, ‘sucks’]

那么单词’are’的序号就是1,wtf的序号就是2。。。。。。

下面就要有一个数据预处理类:类中有能把一个句子中的单词转为词袋中的序号的函数,def sentence_word2id(self):

函数def make_embedding():获取训练好的word embedding矩阵

为方便模型的进行批处理,所以需要把长度不一的句子调整为相同长度的。

定义数据读取器

# 数据预处理
class Preprocess():def __init__(self,sen_len, w2v_path):self.w2v_path = w2v_path   # word2vec的存储路径self.sen_len = sen_len    # 句子的固定长度,方便模型进行批处理self.BagofWords = []      #保存获取到的所有单词(单词不重复),词袋self.dic_word2id = {}        # 比如{"dog":0,"hug":1},字典中的key为单词,value为对应的序号self.embedding_matrix = []  #用于保存之前训练得到的词向量矩阵def get_w2v_model(self):# 读取之前训练好的 word2vec self.embedding = Word2Vec.load(self.w2v_path)self.embedding_dim = self.embedding.vector_size  #获取词向量维度def add_embedding(self, word):# 这里的 word 只会是 "<PAD>" 或 "<UNK>"  <PAD>是空白符,<UNK>是未知单词符号# 把一个随机生成的向量作为 "<PAD>" 或 "<UNK>" 的词向量vector = paddle.uniform(shape=[1,self.embedding_dim]) # 它的 序号id 是 dic_word2id 这个词典的长度,即最后一个self.dic_word2id[word] = len(self.dic_word2id)self.BagofWords.append(word)self.embedding_matrix = paddle.concat([self.embedding_matrix, vector], 0)def make_embedding(self, load=True):# 获取训练好的 Word2vec word embeddingif load:print("加载word embedding矩阵 ...")self.get_w2v_model()print("加载完成。")else:raise NotImplementedError# 遍历嵌入后的单词for i, word in enumerate(self.embedding.wv.vocab):print('单词数量:#{}'.format(i+1), end='\r')# 新加入的 单词 的索引号是 dic_word2id 这个词典的长度,即最后一个self.dic_word2id[word] = len(self.dic_word2id)self.BagofWords.append(word)self.embedding_matrix.append(self.embedding[word])print('')# 把 embedding_matrix 变成 tensor,因为要用于设置embedding层参数self.embedding_matrix = paddle.to_tensor(self.embedding_matrix)# 将 <PAD> 和 <UNK> 加入 embedding self.add_embedding("<PAD>")self.add_embedding("<UNK>")print("单词总数量: {}".format(len(self.embedding_matrix)))return self.embedding_matrixdef pad_sequence(self, sentence):# 将每个句子变成一样的长度,即 sen_len 的长度if len(sentence) > self.sen_len:# 如果句子长度大于 sen_len 的长度,就截断sentence = sentence[:self.sen_len]else:# 如果句子长度小于 sen_len 的长度,就补上 <PAD> 符号,缺多少个单词就补多少个 <PAD> pad_len = self.sen_len - len(sentence)for _ in range(pad_len):sentence.append(self.dic_word2id["<PAD>"])assert len(sentence) == self.sen_lenreturn sentencedef sentence_word2id(self,sentences):# 把句子里面的单词变成相对应的序号sentence_list = []for i, sen in enumerate(sentences):print('句子数量 #{}'.format(i+1), end='\r')sentence_idx = []for word in sen:if (word in self.dic_word2id.keys()):sentence_idx.append(self.dic_word2id[word])else:# 没有出现过的单词就用 <UNK> 表示sentence_idx.append(self.dic_word2id["<UNK>"])# 将每个句子变成一样的长度,方便批量处理sentence_idx = self.pad_sequence(sentence_idx)sentence_list.append(sentence_idx)return sentence_list
#定义数据读取器
from paddle.io import Dataset,DataLoaderclass Reader(Dataset):def __init__(self, datas, labels):self.data = datasself.label = labelsdef __getitem__(self, idx):if self.label is None:return np.array(self.data[idx])else:return np.array(self.data[idx]), np.array(self.label[idx],dtype='float32') #dtype='float32'是因为paddle.nn.BCELoss()需要input数据类型是float32、float64。def __len__(self):return len(self.data)

定义模型

from paddle import nnclass LSTM_Net(nn.Layer):def __init__(self, embedding, embedding_dim, hidden_dim, num_layers, dropout=0.5):  #, fix_embedding=Truesuper(LSTM_Net, self).__init__()# embedding layerself.embedding = paddle.nn.Embedding(embedding.shape[0],embedding.shape[1],weight_attr=paddle.framework.ParamAttr(initializer=paddle.nn.initializer.Assign(embedding)))self.embedding_dim = embedding.shape[1]self.hidden_dim = hidden_dimself.num_layers = num_layersself.dropout = dropoutself.lstm = nn.LSTM(embedding_dim, hidden_dim, num_layers=num_layers)self.classifier = nn.Sequential( nn.Dropout(dropout),nn.Linear(hidden_dim, 1),nn.Sigmoid() )def forward(self, inputs):inputs = self.embedding(inputs)x, _ = self.lstm(inputs, None)# 取用 LSTM 最后一层的 hidden state 丢到分类器中x = x[:, -1, :] x = self.classifier(x)return x

半监督学习

利用没有标签的文本数据进行半监督学习,比如说:在验证过程中,对一句文本进行情感分类预测,得到概率值为0.98,假设这时预测为标签1,其实这种预测的可信度还是挺高了,那就把这个文本数据和预测的标签添加到训练集中去;同理,如果概率值为0.02,这时预测为标签0,同样也把文本数据和标签添加到训练集中去。训练集的数据会越来越多,样本越多,对于模型训练是好事。

#函数用于打标签(大于0.99的,标签为1,小于0.01的标签为0)
#此时的outputs是张量!
#负面标 1,正面标 0
def make_tag(outputs):outputs = outputs.numpy()outputs = outputs.reshape((1,-1))    outputs[outputs>=0.99] = 1 outputs[outputs<=0.01] = 0index = np.argwhere([outputs==1,outputs==0])index = index[:,-1]return outputs,index
#计算模型预测的准确率
def evaluation(outputs, labels):# outputs => 预测值,概率(float)# labels => 真实值,标签(0或1)# 负面标 1,正面标 0outputs = outputs.reshape((1,-1))labels = labels.reshape((1,-1))outputs = paddle.round(outputs)accuracy = outputs.shape[1]-paddle.sum(paddle.abs(outputs-labels))return accuracy
def training(batchSize, epochs, learningRate, data_train, lable_train,val_loader, data_train_no_label, model,start_selftraining=18):  v_batch = len(val_loader)  # validation 数据的batch size大小loss = nn.BCELoss() # 定义损失函数为二元交叉熵损失 binary cross entropy loss#lable_train = np.array(lable_train)optimizer = paddle.optimizer.Adam(learning_rate=learningRate,parameters=model.parameters()) # optimizer用Adamtotal_loss, total_acc, best_acc = 0, 0, 0for epoch in range(epochs):print('训练集大小:{}'.format(len(data_train)))train_dataset = Reader(datas=data_train, labels=lable_train)  #因为是半监督学习,所以训练集数据会增加,每个epoch都需要重新实例化数据读取器train_loader = DataLoader(train_dataset, batch_size = batchSize, shuffle = True) total_loss, total_acc = 0, 0# 训练model.train() #train模式for i, (inputs, labels) in enumerate(train_loader):			optimizer.clear_grad() # 由于 loss.backward() 的 gradient 会累加,所以每一个 batch 后需要归零outputs = model(inputs) # 模型输入Input,输出outputoutputs = outputs.squeeze() # 删除等于1的维度batch_loss = loss(outputs, labels) # 计算模型此时的 training lossbatch_loss.backward() # 计算 loss 的 gradientoptimizer.step() # 更新模型参数accuracy = evaluation(outputs, labels) # 计算模型此时的训练准确率total_acc += (accuracy / batchSize)total_loss += batch_loss.numpy()[0]   #从张量转为numpyprint('Epoch | {}/{}'.format(epoch+1,epochs))n_batch = len(train_loader) #获取数据共有几个批次(batch)print('训练集 | Loss:{:.5f} Acc: {:.3f}'.format(total_loss/n_batch, total_acc.numpy()[0]/n_batch*100))#self trainingmodel.eval() # 将 model 的模式设为 evalif epoch >= start_selftraining :temp_data = data_train_no_labeltrain_no_label_dataset = Reader(datas=temp_data, labels=None)train_no_label_loader = DataLoader(train_no_label_dataset, batch_size = batchSize, shuffle = True)print("self training...")print("总批次:{}".format(len(train_no_label_loader)))with paddle.no_grad():for ii, (inputs) in enumerate(train_no_label_loader):print('Batch | {}/{}'.format(ii+1,len(train_no_label_loader)), end='\r')inp = inputs[0]outputs = model(inp)outputs = outputs.squeeze() # 删除等于1的维度#给无标签文本打上标签labels_tag,index = make_tag(outputs= outputs)# index = index.tolist()# 加入新标注的数据for iii in index:data_train.append(inp[int(iii)].numpy().tolist())lable_train.append(labels_tag[0][iii])if ii == 0:data_train_no_label = np.delete(inp.numpy(), index, 0).tolist()else:data_train_no_label.extend(np.delete(inp.numpy(), index, 0).tolist())print("self training finished!")# 验证with paddle.no_grad():total_loss, total_acc = 0, 0				for i, (inputs, labels) in enumerate(val_loader):				outputs = model(inputs) # 模型输入Input,输出outputoutputs = outputs.squeeze()                batch_loss = loss(outputs, labels) # 计算模型此时的 training lossaccuracy = evaluation(outputs, labels) # 计算模型此时的 training accuracytotal_acc += (accuracy / batchSize)total_loss += batch_loss.numpy()[0]print("验证集 | Loss:{:.5f} Acc: {:.3f} ".format(total_loss/v_batch, total_acc.numpy()[0]/v_batch*100))if total_acc > best_acc:# 如果验证集的准确率优于之前所有的准确率,就把当下的模型保存下来,用于之后的testingbest_acc = total_accpaddle.save(model.state_dict(), "model.pdparams")print('-----------------------------------------------')
from sklearn.model_selection import train_test_split# 定义句子长度、要训练几个 epoch、 学习率的值、 w2v的路径
sen_len = 20
batchsize = 128
epoch = 50
lr = 0.000125
w2v_path = 'w2v_all.model' print("加载文本数据 ...") # 读取 'training_label.txt'  'training_nolabel.txt' 
train_x, y = load_training_data('work/data/training_label.txt')
train_x_no_label = load_training_data('work/data/training_nolabel.txt')
print("加载完成。")# 对 input 跟 labels 做预处理
preprocess = Preprocess(sen_len, w2v_path=w2v_path)
embedding_ = preprocess.make_embedding(load=True)
train_x = preprocess.sentence_word2id(train_x)
train_x_no_label = preprocess.sentence_word2id(train_x_no_label)# 定义模型
model = LSTM_Net(embedding_, embedding_dim=250, hidden_dim=150, num_layers=1, dropout=0.5) #, fix_embedding=fix_embedding#用sklearn中的函数,划分训练集与验证集
X_train, X_val, y_train, y_val = train_test_split(train_x, y, test_size = 0.1, random_state = 4)
print('Train | Len:{} \nValid | Len:{}'.format(len(y_train), len(y_val)))# 把 data 做成 dataset 供 dataloader 取用
# train_dataset = TwitterDataset(X=X_train, y=y_train)
val_dataset = Reader(datas= X_val, labels= y_val)# 把 data 转成 batch of tensors
# train_loader = DataLoader(train_dataset, batch_size= batchsize, shuffle = True) 
val_loader = DataLoader(val_dataset, batch_size= batchsize, shuffle = False)

打印:
在这里插入图片描述

训练

验证集上的准确率在76%左右

# 开始训练
training(batchsize, epoch, lr, X_train,y_train,val_loader, train_x_no_label, model)

在这里插入图片描述

预测测试集

#加载测试数据
print("加载测试数据 ...")
test_x = load_testing_data('work/data/testing_data.txt')
print("完成。")#对测试数据进行预处理
test_x = preprocess.sentence_word2id(test_x)# 测试数据读取
test_dataset = Reader(datas= test_x, labels= None) 
test_loader = DataLoader(test_dataset, batch_size= batchsize, shuffle = False)#加载模型
model = LSTM_Net(embedding_, embedding_dim=250, hidden_dim=150, num_layers=1, dropout=0.5)
model.set_state_dict(paddle.load("model.pdparams"))
#测试函数
def testing(test_loader, model):model.eval()results = []print("预测中...")print("总批次:{}".format(len(test_loader)))with paddle.no_grad():for i, inputs in enumerate(test_loader):print('Batch | {}/{}'.format(i+1,len(test_loader)), end='\r')inp = inputs[0] #取出tensoroutputs = model(inp)outputs = outputs.squeeze() # 删除等于1的维度outputs = outputs.numpy()outputs = outputs.reshape((1,-1))#负面标 1,正面标 0outputs[outputs>=0.5] = 1 # 大于等于0.5为负面outputs[outputs<0.5] = 0 # 小于0.5为正面outputs = outputs.astype(int)results += outputs[0].tolist()print('预测完成!')return results
#开始预测
outputs = testing(test_loader, model)#把预测结果保存起来
import pandas as pd
tmp = pd.DataFrame({"id":[str(i) for i in range(len(test_x))],"label":outputs})
tmp.to_csv('predict_result.csv', index=False)

修改

把句子长度改为28

from sklearn.model_selection import train_test_split# 定义句子长度、要训练几个 epoch、 学习率的值、 w2v的路径
sen_len = 28
batchsize = 128
epoch = 50
lr = 0.000125
w2v_path = 'w2v_all.model' print("加载文本数据 ...") # 读取 'training_label.txt'  'training_nolabel.txt' 
train_x, y = load_training_data('work/data/training_label.txt')
train_x_no_label = load_training_data('work/data/training_nolabel.txt')
print("加载完成。")# 对 input 跟 labels 做预处理
preprocess = Preprocess(sen_len, w2v_path=w2v_path)
embedding_ = preprocess.make_embedding(load=True)
train_x = preprocess.sentence_word2id(train_x)
train_x_no_label = preprocess.sentence_word2id(train_x_no_label)#用sklearn中的函数,划分训练集与验证集
X_train, X_val, y_train, y_val = train_test_split(train_x, y, test_size = 0.1, random_state = 4)
print('Train | Len:{} \nValid | Len:{}'.format(len(y_train), len(y_val)))# 把 data 做成 dataset 供 dataloader 取用
# train_dataset = TwitterDataset(X=X_train, y=y_train)
val_dataset = Reader(datas= X_val, labels= y_val)# 把 data 转成 batch of tensors
# train_loader = DataLoader(train_dataset, batch_size= batchsize, shuffle = True) 
val_loader = DataLoader(val_dataset, batch_size= batchsize, shuffle = False)

使用双向LSTM

from paddle import nnclass LSTM_Net(nn.Layer):def __init__(self, embedding, embedding_dim, hidden_dim, num_layers, dropout=0.5):super(LSTM_Net, self).__init__()# embedding layerself.embedding = paddle.nn.Embedding(embedding.shape[0],embedding.shape[1],weight_attr=paddle.framework.ParamAttr(initializer=paddle.nn.initializer.Assign(embedding)))# self.embedding_dim = embedding.shape[1]# self.hidden_dim = hidden_dim# self.num_layers = num_layers# self.dropout = dropoutself.lstm = nn.LSTM(embedding_dim, hidden_dim, num_layers=num_layers,direction='bidirect')self.classifier = nn.Sequential( nn.Dropout(dropout),nn.Linear(hidden_dim*2, 128),nn.Dropout(dropout),nn.Linear(128, 64),nn.Dropout(dropout),nn.Linear(64, 1),nn.Sigmoid() )def forward(self, inputs):inputs = self.embedding(inputs)x, _ = self.lstm(inputs)# 对 LSTM 输出层的结果按列平均x = paddle.mean(x, axis=1)x = self.classifier(x)return x

训练集上的准确率提升到77%左右

# 开始训练
training(batchsize, epoch, lr, X_train,y_train,val_loader, train_x_no_label, model)

在这里插入图片描述

总结

句子长度对模型训练结果有影响。

验证集上的准确率还不够高,后面可以考虑增加LSTM 的num_layers 网络层数,加入注意力机制。

这篇关于李宏毅机器学习特训营机器学习作业4-语句分类的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/259738

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

作业提交过程之HDFSMapReduce

作业提交全过程详解 (1)作业提交 第1步:Client调用job.waitForCompletion方法,向整个集群提交MapReduce作业。 第2步:Client向RM申请一个作业id。 第3步:RM给Client返回该job资源的提交路径和作业id。 第4步:Client提交jar包、切片信息和配置文件到指定的资源提交路径。 第5步:Client提交完资源后,向RM申请运行MrAp

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

认识、理解、分类——acm之搜索

普通搜索方法有两种:1、广度优先搜索;2、深度优先搜索; 更多搜索方法: 3、双向广度优先搜索; 4、启发式搜索(包括A*算法等); 搜索通常会用到的知识点:状态压缩(位压缩,利用hash思想压缩)。

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学