数据集 data.py
数据集为一批评论,1表示正面,0表示负面,由于只有一个数据集,要自己提取一部分出来当验证集
数据预处理
读取文件中的数据,并做一些数据预处理
1.删除换行符和第一行无用数据
2.将数据集的每一行的标签和数据分开,并分别存入标签列表和数据列表中
# 读取文档的数据
def read_txt_data(path):
label = []
data = []
with open(path, "r", encoding="utf-8") as f:
for i, line in tqdm(enumerate(f)):
if i == 0:
continue # 不读第一行,也可以删掉
if i > 200 and i < 7500:
continue
line = line.strip('\n') # 删除换行符
line = line.split(",", 1) # 按逗号分割行,限制分割次数为1,这样可以将每一行分割成两部分,第一部分作为标签,第二部分作为数据。
label.append(line[0]) # 标签
data.append(line[1]) # 数据
print(len(label))
print(len(data))
return data, label
定义数据集类和数据提取器
这里数据提取器中要进行训练集和验证集的划分,取20%作为验证集
# 数据集
class JdDataset(Dataset):
def __init__(self, x, label):
self.X = x
label = [int(i) for i in label]
self.Y = torch.LongTensor(label)
def __getitem__(self, item):
return self.X[item], self.Y[item] # 数据集一般不让返回str, 要写在字典中,或者转为矩阵。
def __len__(self):
return len(self.Y)
# 数据生成器
def get_dataloader(path, batchsize=1, valSize=0.2):
x, label = read_txt_data(path) # 读取数据集
# 数据集没有划分,所以要分割训练集和验证集,valSize为验证集的比例20%
train_x, val_x, train_y, val_y = train_test_split(x, label,test_size=valSize,shuffle=True, stratify=label)
train_set = JdDataset(train_x, train_y)
val_set = JdDataset(val_x, val_y)
train_loader = DataLoader(train_set, batch_size=batchsize)
val_loader = DataLoader(val_set, batch_size=batchsize)
return train_loader, val_loader
定义模型
文本要先进行分词,得到三个部分传进bert
# 模型
class myBertModel(nn.Module):
def __init__(self, bert_path, num_class, device):
super(myBertModel, self).__init__()
self.device = device
self.num_class = 2
# bert_config = BertConfig.from_pretrained(bert_path)
# self.bert = BertModel(bert_config)
self.bert = BertModel.from_pretrained(bert_path)
# 分词器,from_pretrained函数是在路径里直接读取预训练模型的配置
self.tokenizer = BertTokenizer.from_pretrained(bert_path)
# 分类头
self.out = nn.Sequential(
nn.Linear(768,num_class)
)
# 分词器得到三个值作为输入
def build_bert_input(self, text):
Input = self.tokenizer(text, return_tensors='pt', padding='max_length', truncation=True, max_length=128)
input_ids = Input["input_ids"].to(self.device)
attention_mask = Input["attention_mask"].to(self.device)
token_type_ids = Input["token_type_ids"].to(self.device)
return input_ids, attention_mask, token_type_ids
# 前向
def forward(self, text):
input_ids, attention_mask, token_type_ids = self.build_bert_input(text)
# bert有两个输出:sequence_out是自注意力层的输出,pooled_output是经过了pooled output层的池化的输出(一维)
sequence_out, pooled_output = self.bert(input_ids=input_ids,
attention_mask=attention_mask,
token_type_ids=token_type_ids,
return_dict=False)
# 最后的输出只要pooled output层的池化后的输出即可
out = self.out(pooled_output)
return out
训练
过程和图片分类一模一样。。