南寧建站模板展示西安seo外包行者seo
🚩🚩🚩Hugging Face 實(shí)戰(zhàn)系列 總目錄
有任何問題歡迎在下面留言
本篇文章的代碼運(yùn)行界面均在PyCharm中進(jìn)行
本篇文章配套的代碼資源已經(jīng)上傳
從零構(gòu)建屬于自己的GPT系列1:文本數(shù)據(jù)預(yù)處理
從零構(gòu)建屬于自己的GPT系列2:語言模型訓(xùn)練
0 任務(wù)基本流程
- 拿到txt文本數(shù)據(jù),本文以15本金庸小說為例
- CpmTokenizer預(yù)訓(xùn)練模型將所有文本處理成.pkl的token文件
- 配置訓(xùn)練參數(shù)
- token數(shù)據(jù)轉(zhuǎn)化為索引
- 導(dǎo)入GPT2LMHeadModel預(yù)訓(xùn)練中文模型,訓(xùn)練文本數(shù)據(jù)
- 訓(xùn)練結(jié)束得到個(gè)人文本數(shù)據(jù)特征的新模型
- 搭載簡易網(wǎng)頁界面,部署本地模型
- text-to-text專屬GPT搭建完成
- 獲取新數(shù)據(jù),模型更加個(gè)性化
- 優(yōu)化模型,一次性讀取更長文本,生成更長的結(jié)果
1 訓(xùn)練數(shù)據(jù)
在本任務(wù)的訓(xùn)練數(shù)據(jù)中,我選擇了金庸的15本小說,全部都是txt文件
數(shù)據(jù)打開后的樣子
數(shù)據(jù)預(yù)處理需要做的事情就是使用huggingface的transformers包的tokenizer模塊,將文本轉(zhuǎn)化為token
最后生成的文件就是train_novel.pkl文件,就不用在訓(xùn)練的時(shí)候讀txt文件了
數(shù)據(jù)預(yù)處理:preprocess.py
2 設(shè)置參數(shù)
import argparse
from utils import set_logger
from transformers import CpmTokenizer
import os
import pickle
from tqdm import tqdm
parser = argparse.ArgumentParser()
parser.add_argument('--vocab_file', default='vocab/chinese_vocab.model', type=str, required=False,help='詞表路徑')
parser.add_argument('--log_path', default='log/preprocess.log', type=str, required=False, help='日志存放位置')
parser.add_argument('--data_path', default='data/novel', type=str, required=False, help='數(shù)據(jù)集存放位置')
parser.add_argument('--save_path', default='data/train.pkl', type=str, required=False,help='對訓(xùn)練數(shù)據(jù)集進(jìn)行tokenize之后的數(shù)據(jù)存放位置')
parser.add_argument('--win_size', default=200, type=int, required=False,help='滑動(dòng)窗口的大小,相當(dāng)于每條數(shù)據(jù)的最大長度')
parser.add_argument('--step', default=200, type=int, required=False, help='滑動(dòng)窗口的滑動(dòng)步幅')
args = parser.parse_args()
- 參數(shù)包
- 本項(xiàng)目utils.py中初始化參數(shù)函數(shù)
- chinese pre-trained model Tokenizer包
- 系統(tǒng)包
- pickle包,用于將 python 對象序列化(serialization)為字節(jié)流,或者將字節(jié)流反序列化為 Python 對象
- 進(jìn)度條包
- 創(chuàng)建一個(gè)用于解析命令行參數(shù)的 ArgumentParser 對象
- 處理中文文本的變成token的預(yù)訓(xùn)練模型的模型文件存放位置
- 運(yùn)行日志文件存放位置
- 數(shù)據(jù)集存放位置
- 對訓(xùn)練數(shù)據(jù)集進(jìn)行tokenize之后的數(shù)據(jù)存放位置
- 滑動(dòng)窗口的大小,相當(dāng)于每條數(shù)據(jù)的最大長度
- 滑動(dòng)窗口的滑動(dòng)步幅
3 初始化日志對象
logger = set_logger(args.log_path)
def set_logger(log_path):logger = logging.getLogger(__name__)logger.setLevel(logging.INFO)formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')file_handler = logging.FileHandler(filename=log_path)file_handler.setFormatter(formatter)file_handler.setLevel(logging.INFO)logger.addHandler(file_handler)console = logging.StreamHandler()console.setLevel(logging.DEBUG)console.setFormatter(formatter)logger.addHandler(console)return logger
- 選擇日志路徑,調(diào)用日志函數(shù)
- 創(chuàng)建 logger 對象
- 設(shè)置日志級別為’logging.INFO’
- 創(chuàng)建格式化器 formatter
- 創(chuàng)建文件處理器file_handler并指定了日志文件的路徑為log_path
- 設(shè)置處理器的日志級別為 logging.INFO
- 添加文件處理器 file_handler 到創(chuàng)建的 logger 對象中
- 創(chuàng)建控制臺處理器 console,用 logging.StreamHandler() 創(chuàng)建一個(gè)將日志輸出到控制臺的處理器
- 設(shè)置其日志級別為 logging.DEBUG
- 將格式化器 formatter 應(yīng)用到這個(gè)控制臺處理器上
- 控制臺處理器 console 添加到 logger 對象中
- 返回了這個(gè)配置好的 logger 對象
4 初始化
logger = set_logger(args.log_path)
tokenizer = CpmTokenizer(vocab_file="vocab/chinese_vocab.model") # pip install jieba
eod_id = tokenizer.convert_tokens_to_ids("<eod>") # 文檔結(jié)束符
sep_id = tokenizer.sep_token_id
train_list = []
logger.info("start tokenizing data")
- 初始化日志
- 創(chuàng)建CPMTokenizer 對象,用于分詞和處理中文文本
- tokenizer 將特殊標(biāo)記 轉(zhuǎn)換為其對應(yīng)的 ID
- 獲取分詞器中分隔符的 ID
- 最后處理的數(shù)據(jù)
- 打印
5 處理數(shù)據(jù)
for file in tqdm(os.listdir(args.data_path)):file = os.path.join(args.data_path, file)with open(file, "r", encoding="utf8") as reader:lines = reader.readlines()for i in range(len(lines)):if lines[i].isspace() != True and lines[i] != '\n':token_ids = tokenizer.encode(lines[i].strip(), add_special_tokens=False) + [eod_id]if i % 1000 == 0:print('cur_step', i, lines[i].strip())else:continuewin_size = args.win_sizestep = args.stepstart_index = 0end_index = win_sizedata = token_ids[start_index:end_index]train_list.append(data)start_index += stepend_index += stepwhile end_index + 50 < len(token_ids): # 剩下的數(shù)據(jù)長度,大于或等于50,才加入訓(xùn)練數(shù)據(jù)集data = token_ids[start_index:end_index]train_list.append(data)start_index += stepend_index += step# 序列化訓(xùn)練數(shù)據(jù)
with open(args.save_path, "wb") as f:pickle.dump(train_list, f)
os.listdir(args.data_path)
:得到該路徑下所有文件的文件名字符串并返回一個(gè)字符串?dāng)?shù)組,for file in tqdm的for循環(huán)會(huì)打印讀取進(jìn)度的進(jìn)度條- 獲得當(dāng)前文件的完整路徑
- 按照
file
路徑、utf-8編碼格式、只讀模式打開文件 - 按行來讀取文件,line在這里是一個(gè)list,list每個(gè)數(shù)據(jù)都對于文件的一行數(shù)據(jù)
- 按照行數(shù)遍歷讀取文件數(shù)據(jù)
- 判斷當(dāng)前行是否為空行,或者這行只有換行
- 使用tokenizer進(jìn)行encode,加入結(jié)束索引
- 每1000行進(jìn)行一次打印操作
- 每1000行進(jìn)行一次打印操作
- 空行不處理
- 空行不處理
- 滑動(dòng)窗口長度
- 滑動(dòng)次數(shù)
- 第一個(gè)文件的第i行的第一條數(shù)據(jù)的開始索引
- 第一個(gè)文件的第i行的第一條數(shù)據(jù)的結(jié)束索引
- 第一個(gè)文件的第i行的第一條數(shù)據(jù)
- 添加第一條數(shù)據(jù)到總數(shù)據(jù)中
- while循環(huán)取數(shù)據(jù),最后一條數(shù)據(jù)不足50時(shí)就不要了,逐個(gè)取數(shù)據(jù)直到換行,注意這里一行數(shù)據(jù)可能是一段哦,不一定有逗號或者句號就會(huì)換行
- 第一個(gè)文件的第i行的第k條數(shù)據(jù)
- 添加第k條數(shù)據(jù)到總數(shù)據(jù)中
- 按照滑動(dòng)次數(shù)更新開始索引
- 按照滑動(dòng)次數(shù)更新結(jié)束索引
- 最后所有的數(shù)據(jù)都保存在了train_list中
- 保存為pickle文件
從零構(gòu)建屬于自己的GPT系列1:文本數(shù)據(jù)預(yù)處理
從零構(gòu)建屬于自己的GPT系列2:語言模型訓(xùn)練