想实现,通过预先收集但未经处理的txt文件训练模型,在向模型提问有关这些txt文件内容时得到符合逻辑的答案,需要怎么做?
在基于深度学习的目标检测任务中,往往需要将数据图片划分成训练集、验证集与测试集,在此记录一种笨办法,各位大佬可忽略。
训练集:日常学习
验证集:模拟考试
测试集:期末考试
# 将一个文件夹下数据按比例分在三个文件夹下
import os
import random
import shutil
from shutil import copy2
datadir_normal = "/****/*****/****/****/JPEGImages/labels"#更换为自己的路径
all_data = os.listdir(datadir_normal)#(图片文件夹)
num_all_data = len(all_data)
print( "总数量: " + str(num_all_data) )
index_list = list(range(num_all_data))
print(index_list)
#生成随机种子,使得每一次划分的数据一样,如果没有要求,可以删除本段代码
r=random.random
random.seed(2021)
random.shuffle(index_list,random=r)
print(index_list)
#生成随机种子,使得每一次划分的数据一样,如果没有要求,可以删除本段代码
num = 0
trainDir = "/****/*****/****/****/JPEGImages/train/"#(将训练集放在这个文件夹下)
if not os.path.exists(trainDir):
os.mkdir(trainDir)
validDir = '/****/*****/****/****/JPEGImages/valid/'#(将验证集放在这个文件夹下)
if not os.path.exists(validDir):
os.mkdir(validDir)
testDir = '/****/*****/****/****/JPEGImages/test/'#(将测试集放在这个文件夹下)
if not os.path.exists(testDir):
os.mkdir(testDir)
for i in index_list:
fileName = os.path.join(datadir_normal, all_data[i])
if num < num_all_data*0.6: #Train:0.6
print(str(fileName))
copy2(fileName, trainDir)
elif num>num_all_data*0.6 and num < num_all_data*0.8:#valid:0.2
print(str(fileName))
copy2(fileName, validDir)
else:#test:0.2
copy2(fileName, testDir)
num += 1
运行后,将在JPEGImages文件夹下看到多了train、test、valid3个文件夹,如下图:
文件夹内容就是根据上边的程序划分的标签txt文件。
find /*****/******/*****/****/JPEGImages/test -name "*.txt" > TEST.txt
find /*****/******/*****/****/JPEGImages/train -name "*.txt" > TRAIN.txt
find /*****/******/*****/****/JPEGImages/valid -name "*.txt" > VALID.txt
/home/outsider/其他/1/JPEGImages/valid/20210110113149061.txt
需要使用文档的查找与替换功能将3个txt文档内的名称修改为如下格式:
20210110113149061
文档的查找与修改如下:
替换后效果如下:
from PIL import Image
im_num = []
for line in open("/***/****/***/VALID.txt", "r"):
im_num.append(line)
print(im_num)
for a in im_num:
im_name = '/***/***/***/JPEGImages/images/{}'.format(a[:-1]) + '.jpg' #原始路径
print(im_name)
im = Image.open(im_name) # 打开指定路径下的图像
tar_name = '/***/***/***/JPEGImages/valid/{}'.format(a[:-1]) + '.jpg' #移动后的路径
print(tar_name)
im=im.convert('RGB')
im.save(tar_name) # 另存
im.close()
每次运行后,需要将文件名修改下,修改为相对应的txt文档,程序运行结束后,将在train、test、valid3个文件夹内看到程序已经将标签txt对应的图片复制过来了。
到此,数据集就已经划分好了,也可以根据图片名称将对应的txt文件复制到相应的文件夹内,方法比较老实,大佬们就不用看啦。
最后,我将两个py文件放在下方。
针对该问题,我可以提供以下解决方案:
步骤1:读取txt文件并为每个文档打标签 读取txt文件,遍历每一行,并将每个文档的类型作为标签存储。可以使用如下代码实现:
import os import numpy as np from sklearn.model_selection import train_test_split
def read_txt_file(txt_path): """ 读取txt文件并为每个文档打上标签 """ with open(txt_path, 'r', encoding='utf-8') as f: data = f.readlines() labels = [] docs = [] for line in data: line = line.strip().split('\t') label = line[0] text = line[1] labels.append(label) docs.append(text) return docs, labels
train_docs, train_labels = read_txt_file('train.txt')
步骤2:数据预处理 数据预处理是非常重要的步骤,可以有效地提高模型的性能和准确性。在文本分类任务中,常见的预处理步骤包括:
分词:将文本拆分成单词或短语。常用的分词工具包括jieba,nltk等 去停用词:在文本分类中,很多单词并不能提供有用的信息,如“的”、“了”,需要去除这些词。可以使用停用词表来去除这些词。 词向量化:将单词转换为向量,常见的词向量化方法有one-hot编码和词嵌入(word embedding)。 TF-IDF:考虑词汇在文档中的重要性。 这些预处理步骤可以通过Python和各种第三方库轻松实现。例如,可以使用jieba库进行中文分词,同时使用sklearn库中的TfidfVectorizer函数将文本转换为基于TF-IDF的向量表示。使用如下代码实现:
import jieba from sklearn.feature_extraction.text import TfidfVectorizer
def jieba_cut(doc): """ 使用jieba对文本进行分词 """ word_list = jieba.cut(doc) return ' '.join(word_list)
def tfidf(docs): """ 使用TF-IDF将文本转换为向量表示 """ vectorizer=TfidfVectorizer(tokenizer=jieba_cut, ngram_range=(1,3), max_features=30000) doc_vectors = vectorizer.fit_transform(docs) return doc_vectors, vectorizer
train_docs_cut = [jieba_cut(doc) for doc in train_docs] train_vectors, vectorizer = tfidf(train_docs_cut)
步骤3:使用预处理好的数据集训练模型 在预处理好数据集后,可以使用各种机器学习算法或深度学习模型训练模型。在深度学习中,常见的模型包括Word2Vec,CNN,RNN和Transformer。在这里,我以PyTorch为例,使用TextCNN网络训练模型。使用如下代码可实现:
import torch import torch.nn as nn
class TextCNN(nn.Module): def init(self, embedding_dim, hidden_dim, num_classes, kernel_sizes=[3, 4, 5]): super(TextCNN, self).init() self.embedding = nn.Embedding(pretrained_embeddings.shape[0], embedding_dim, padding_idx=0) self.convs = nn.ModuleList([nn.Conv2d(1, hidden_dim, (k, embedding_dim)) for k in kernel_sizes]) self.dropout = nn.Dropout(0.5) self.fc1 = nn.Linear(hidden_dim * len(kernel_sizes), num_classes)
def forward(self, x):
x = self.embedding(x)
x = x.unsqueeze(1) # (batch_size, 1, seq_len, embedding_dim)
x = [nn.functional.relu(conv(x)).squeeze(3) for conv in self.convs] # [(batch_size, hidden_dim, seq_len - k + 1), ...]
x = [nn.functional.max_pool1d(i, i.size(2)).squeeze(2) for i in x] # [(batch_size, hidden_dim), ...]
x = torch.cat(x, 1)
x = self.dropout(x)
out = self.fc1(x)
return out
embedding_dims = [50, 100, 200, 300] num_filters = [100, 200, 300] kernel_sizes = [(3, 4, 5), (4, 5, 6), (3, 4, 5, 6)] batch_sizes = [32, 64, 128] learning_rates = [0.001, 0.01, 0.1]
criterion = nn.CrossEntropyLoss() optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
for epoch in range(num_epochs): for i, (data, labels) in enumerate(train_loader): optimizer.zero_grad() outputs = model(data) loss = criterion(outputs, labels) loss.backward() optimizer.step()
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item()}')
步骤4:利用模型回答问题 训练好模型后,可以将测试数据集输入模型并得到预测结果。可以使用如下代码实现:
def predict(model, vectorizer, text): """ 对新的问题进行预测,并返回预测结果 """ inputs = vectorizer.transform([jieba_cut(text)]) outputs = model(torch.LongTensor(inputs.toarray())) _, predicted = torch.max(outputs.data, 1) return predicted.item()
pred = predict(model, vectorizer, '这篇文章讲述了什么?') print(pred)
需要注意的是,在训练和预测过程中,应该始终使用相同的数据预处理流程和词汇表,以确保模型获得相同的输入数据。