日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

bert 文本分类实战

發布時間:2024/1/1 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 bert 文本分类实战 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言:

? ? ? ?由于課題需要,學習自然語言處理(NLP),于是在網上找了找文章和代碼進行學習,在此記錄,課題代碼就不展示了,使用網上的代碼和大家分享。思想和代碼大部分參考蘇神,在此感謝。

任務目標:

? ? ?希望bert模型解決的問題: 輸入:一段話; 輸出:這段話屬于的類別。

任務實現原理:

? ? ? 本次模型為監督學習模型,根據已有標簽的文本數據集,對bert模型進行訓練。使用訓練好的模型對句子進行預測,輸出得到句子的類別。本質上屬于多分類問題。

? ? ? 大致流程為,數據集預處理;劃分數據集();對數據集加工處理(文本數據編碼成符合bert輸入的向量);構建模型(bert模型導入與使用); 將數據送入模型進行訓練和預測。

模型總體結構:

?具體代碼:

數據集預處理:

? ? ?將數據集讀入,并打亂數據的排列順序。

mainPath = 'bert多文本分類//' rc = pd.read_csv(mainPath + 'data/tnews/toutiao_news_dataset.txt', delimiter="_!_", names=['labels', 'text'], header=None, encoding='utf-8') rc = shuffle(rc) #打亂順序

劃分數據集

? ? ?將數據集劃分為訓練集和測試集(驗證集)

# 構建全部所需數據集 data_list = [] for d in rc.iloc[:].itertuples(): #itertuples(): 將DataFrame迭代為元祖。data_list.append((d.text, d.labels))# 取一部分數據做訓練和驗證 train_data = data_list[0:20000] valid_data = data_list[20000:22000]

?數據加工處理:

修改原有的字典:

修改原因:蘇神解讀,本來 Tokenizer 有自己的 _tokenize 方法,我這里重寫了這個方法,是要保證 tokenize 之后的結果,跟原來的字符串長度等長(如果算上兩個標記,那么就是等長再加 2)。 Tokenizer 自帶的 _tokenize 會自動去掉空格,然后有些字符會粘在一塊輸出,導致 tokenize 之后的列表不等于原來字符串的長度了,這樣如果做序列標注的任務會很麻煩。主要就是用 [unused1] 來表示空格類字符,而其余的不在列表的字符用 [UNK] 表示,其中 [unused*] 這些標記是未經訓練的(隨即初始化),是 Bert 預留出來用來增量添加詞匯的標記,所以我們可以用它們來指代任何新字符。

#vocabPath里存儲了大量的詞語,每個詞語對應的著一個編號 例如10640 posts # 將詞表中的詞編號轉換為字典 # 字典的形式為 '侖': 796, #得到最原始的字典 tokenDict = {} with codecs.open(vocabPath, 'r', encoding='utf-8') as reader:for line in reader:token = line.strip() # 去除首尾空格tokenDict[token] = len(tokenDict)#原始的字典存在著瑕疵,在原始的字典上需要根據自己的數據集,創造自己的字典 # 重寫tokenizer class OurTokenizer(Tokenizer):def _tokenize(self, content):reList = []for t in content:if t in self._token_dict:reList.append(t)elif self._is_space(t):# 用[unused1]來表示空格類字符reList.append('[unused1]')else:# 不在列表的字符用[UNK]表示reList.append('[UNK]')return reList#使用新的字典 tokenizer = OurTokenizer(tokenDict)

?

? ?文本數據根據字典編碼成符合bert輸入的向量,逐批生成數據([X1,X2],Y),從而可以丟到模型中訓練。

def seqPadding(X, padding=0):L = [len(x) for x in X]ML = max(L)return np.array([np.concatenate([x, [padding] * (ML - len(x))]) if len(x) < ML else x for x in X])class data_generator:def __init__(self, data, batch_size=32, shuffle=True): #構造函數,使用時執行self.data = dataself.batch_size = batch_sizeself.shuffle = shuffleself.steps = len(self.data) // self.batch_sizeif len(self.data) % self.batch_size != 0:self.steps += 1def __len__(self):return self.stepsdef __iter__(self):while True:idxs = list(range(len(self.data))) #數據元組下標if self.shuffle:np.random.shuffle(idxs) #是否打亂數據下標順序X1, X2, Y = [], [], []for i in idxs:d = self.data[i]text = d[0][:maxlen]x1, x2 = tokenizer.encode(first=text) # encode方法可以一步到位地生成對應模型的輸入。y = d[1] X1.append(x1) ## x1 是字對應的索引 # x2 是句子對應的索引 X2.append(x2)Y.append([y])if len(X1) == self.batch_size or i == idxs[-1]:X1 = seqPadding(X1) #如果等于batchsize或者最后一個值后面補充0X2 = seqPadding(X2)Y = seqPadding(Y)yield [X1, X2], Y[X1, X2, Y] = [], [], []

構建模型和訓練:

? ? 加載bert模型,并對bert模型的輸出進行調整,使bert模型能夠完成我們的任務目標。

# 設置預訓練bert模型的路徑 configPath = mainPath + 'chinese_roberta_wwm_ext_L-12_H-768_A-12/bert_config.json' ckpPath = mainPath + 'chinese_roberta_wwm_ext_L-12_H-768_A-12/bert_model.ckpt' vocabPath = mainPath + 'chinese_roberta_wwm_ext_L-12_H-768_A-12/vocab.txt'# bert模型設置 bert_model = load_trained_model_from_checkpoint(configPath, ckpPath, seq_len=None) # 加載預訓練模型 for l in bert_model.layers:l.trainable = Truex1_in = Input(shape=(None,)) x2_in = Input(shape=(None,))x = bert_model([x1_in, x2_in])# 取出[CLS]對應的向量用來做分類 x = Lambda(lambda x: x[:, 0])(x) p = Dense(15, activation='softmax')(x)model = Model([x1_in, x2_in], p) model.compile(loss='sparse_categorical_crossentropy', optimizer=Adam(1e-5), metrics=['accuracy']) model.summary()train_D = data_generator(train_data) valid_D = data_generator(valid_data)model.fit_generator(train_D.__iter__(), steps_per_epoch=len(train_D), epochs=5, validation_data=valid_D.__iter__(),validation_steps=len(valid_D))

模型預測:

#測試的數據集 str1 = "上港主場1-2負于國安,遭遇聯賽兩連敗,上港到底輸在哪?" str2 = "普京總統會見了拜登總統" str3 = "這3輛10萬出頭小鋼炮,隨便改改輕松秒奔馳,第一輛還是限量款" predict_D = data_generator([(str1, 0), (str2, 3), (str3, 10)], shuffle=False) #獲取總的標簽類別 #array(['體育', '軍事', '農業', '國際', '娛樂', '房產', '教育', '文化', '旅游', '民生故事', '汽車','電競游戲', '科技', '證券股票', '財經'], dtype=object) output_label2id_file = os.path.join(mainPath, "model/keras_class/label2id.pkl") if os.path.exists(output_label2id_file):with open(output_label2id_file, 'rb') as w:labes = pickle.load(w)#加載保存的模型 from keras_bert import get_custom_objects custom_objects = get_custom_objects() model = load_model(mainPath + 'model/keras_class/tnews.h5', custom_objects=custom_objects) #使用生成器獲取測試的數據 tmpData = predict_D.__iter__() #預測 preds = model.predict_generator(tmpData, steps=len(predict_D), verbose=1) # 求每行最大值得下標,其中,axis=1表示按行計算 index_maxs = np.argmax(preds, axis=1) result = [(x, labes[x]) for x in index_maxs] print(result)

輸出preds,index_maxs, result

?完整代碼

import pickle from keras_bert import load_trained_model_from_checkpoint, Tokenizer from keras.layers import * from keras.models import Model from keras.optimizers import Adam from sklearn.preprocessing import LabelEncoder from sklearn.utils import shuffle from keras.utils.vis_utils import plot_model import codecs, gc import keras.backend as K import os import pandas as pd import numpy as np# 文件主路徑定義 mainPath = '你的目錄/keras_bert文本分類實例/'# 從文件中讀取數據,獲取訓練集和驗證集 rc = pd.read_csv(mainPath + 'data/tnews/toutiao_news_dataset.txt', delimiter="_!_", names=['labels', 'text'],header=None, encoding='utf-8') #delimiterrc = shuffle(rc) # shuffle數據,打亂# 把類別轉換為數字 # 一共15個類別:"教育","科技","軍事","旅游","國際","證券股票","農業","電競游戲", # "民生故事","文化","娛樂","體育","財經","房產","汽車" class_le = LabelEncoder() rc.iloc[:, 0] = class_le.fit_transform(rc.iloc[:, 0].values)# 保存標簽文件 output_label2id_file = os.path.join(mainPath, "model/keras_class/label2id.pkl") if not os.path.exists(output_label2id_file):with open(output_label2id_file, 'wb') as w:pickle.dump(class_le.classes_, w)# 構建全部所需數據集 data_list = [] for d in rc.iloc[:].itertuples():data_list.append((d.text, d.labels))# 取一部分數據做訓練和驗證 train_data = data_list[0:20000] valid_data = data_list[20000:22000]maxlen = 100 # 設置序列長度為100,要保證序列長度不超過512# 設置預訓練模型 configPath = mainPath + 'chinese_roberta_wwm_ext_L-12_H-768_A-12/bert_config.json' ckpPath = mainPath + 'chinese_roberta_wwm_ext_L-12_H-768_A-12/bert_model.ckpt' vocabPath = mainPath + 'chinese_roberta_wwm_ext_L-12_H-768_A-12/vocab.txt'# 將詞表中的詞編號轉換為字典 tokenDict = {} with codecs.open(vocabPath, 'r', encoding='utf-8') as reader:for line in reader:token = line.strip()tokenDict[token] = len(tokenDict)# 重寫tokenizer class OurTokenizer(Tokenizer):def _tokenize(self, content):reList = []for t in content:if t in self._token_dict:reList.append(t)elif self._is_space(t):# 用[unused1]來表示空格類字符reList.append('[unused1]')else:# 不在列表的字符用[UNK]表示reList.append('[UNK]')return reListtokenizer = OurTokenizer(tokenDict)def seqPadding(X, padding=0):L = [len(x) for x in X]ML = max(L)return np.array([np.concatenate([x, [padding] * (ML - len(x))]) if len(x) < ML else x for x in X])class data_generator: #先將數據變成元組的形式在喂入生成器def __init__(self, data, batch_size=32, shuffle=True):self.data = dataself.batch_size = batch_sizeself.shuffle = shuffleself.steps = len(self.data) // self.batch_sizeif len(self.data) % self.batch_size != 0:self.steps += 1def __len__(self):return self.stepsdef __iter__(self):while True:idxs = list(range(len(self.data)))if self.shuffle:np.random.shuffle(idxs)X1, X2, Y = [], [], []for i in idxs:d = self.data[i]text = d[0][:maxlen]x1, x2 = tokenizer.encode(first=text)y = d[1]X1.append(x1)X2.append(x2)Y.append([y])if len(X1) == self.batch_size or i == idxs[-1]:X1 = seqPadding(X1)X2 = seqPadding(X2)Y = seqPadding(Y)yield [X1, X2], Y[X1, X2, Y] = [], [], []# bert模型設置 bert_model = load_trained_model_from_checkpoint(configPath, ckpPath, seq_len=None) # 加載預訓練模型for l in bert_model.layers:l.trainable = Truex1_in = Input(shape=(None,)) x2_in = Input(shape=(None,))x = bert_model([x1_in, x2_in])# 取出[CLS]對應的向量用來做分類 x = Lambda(lambda x: x[:, 0])(x) p = Dense(15, activation='softmax')(x)model = Model([x1_in, x2_in], p) model.compile(loss='sparse_categorical_crossentropy', optimizer=Adam(1e-5), metrics=['accuracy']) model.summary()train_D = data_generator(train_data) valid_D = data_generator(valid_data)model.fit_generator(train_D.__iter__(), steps_per_epoch=len(train_D), epochs=5, validation_data=valid_D.__iter__(),validation_steps=len(valid_D))model.save(mainPath + 'model/keras_class/tnews.h5', True, True)# 保存模型結構圖 plot_model(model, to_file='model/keras_class/tnews.png', show_shapes=True)

參考鏈接
https://blog.csdn.net/qq_39290990/article/details/121672141

總結

以上是生活随笔為你收集整理的bert 文本分类实战的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。