🚩🚩🚩Hugging Face 實戰系列 總目錄
有任何問題歡迎在下面留言
本篇文章的代碼運行界面均在PyCharm中進行
本篇文章配套的代碼資源已經上傳
從零構建屬于自己的GPT系列1:數據預處理
從零構建屬于自己的GPT系列2:模型訓練1
從零構建屬于自己的GPT系列3:模型訓練2
從零構建屬于自己的GPT系列4:模型訓練3
從零構建屬于自己的GPT系列5:模型部署1
從零構建屬于自己的GPT系列6:模型部署2
1 前端環境安裝
安裝:
pip install streamlit
測試:
streamlit hello
安裝完成后,測試后打印的信息
(Pytorch) C:\Users\admin>streamlit hello
Welcome to Streamlit. Check out our demo in your browser.
Local URL: http://localhost:8501 Network URL:
http://192.168.1.187:8501
Ready to create your own Python apps super quickly? Head over to
https://docs.streamlit.io
May you create awesome apps!
接著會自動的彈出一個頁面
2 模型加載函數
這個函數把模型加載進來,并且設置成推理模式
def get_model(device, model_path):tokenizer = CpmTokenizer(vocab_file="vocab/chinese_vocab.model")eod_id = tokenizer.convert_tokens_to_ids("<eod>") # 文檔結束符sep_id = tokenizer.sep_token_idunk_id = tokenizer.unk_token_idmodel = GPT2LMHeadModel.from_pretrained(model_path)model.to(device)model.eval()return tokenizer, model, eod_id, sep_id, unk_id
- 模型加載函數,加載設備cuda,已經訓練好的模型的路徑
- 加載tokenizer 文件
- 結束特殊字符
- 分隔特殊字符
- 未知詞特殊字符
- 加載模型
- 模型進入GPU
- 開啟推理模式
- 返回參數
device_ids = 0
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
os.environ["CUDA_VISIBLE_DEVICE"] = str(device_ids)
device = torch.device("cuda" if torch.cuda.is_available() and int(device_ids) >= 0 else "cpu")
tokenizer, model, eod_id, sep_id, unk_id = get_model(device, "model/zuowen_epoch40")
- 指定第一個顯卡
- 設置確保 CUDA 設備的編號與 PCI 位置相匹配,使得 CUDA 設備的編號更加一致且可預測
- 通過設置為 str(device_ids)(在這個案例中為 ‘0’),指定了進程只能看到并使用編號為 0 的 GPU
- 有GPU用GPU作為加載設備,否則用CPU
- 調用get_model函數,加載模型
3 文本生成函數
對于給定的上文,生成下一個單詞
def generate_next_token(input_ids,args):input_ids = input_ids[:, -200:]outputs = model(input_ids=input_ids)logits = outputs.logitsnext_token_logits = logits[0, -1, :]next_token_logits = next_token_logits / args.temperaturenext_token_logits[unk_id] = -float('Inf')filtered_logits = top_k_top_p_filtering(next_token_logits, top_k=args.top_k, top_p=args.top_p)next_token_id = torch.multinomial(F.softmax(filtered_logits, dim=-1), num_samples=1)return next_token_id
- 對輸入進行一個截斷操作,相當于對輸入長度進行了限制
- 通過模型得到預測,得到輸出,預測的一個詞一個詞進行預測的
- 得到預測的結果值
- next_token_logits表示最后一個token的hidden_state對應的prediction_scores,也就是模型要預測的下一個token的概率
- 溫度表示讓結果生成具有多樣性
- 設置預測的結果不可以未知字(詞)的Token,防止出現異常的東西
- 通過top_k_top_p_filtering()函數對預測結果進行篩選
- 通過預測值轉換為概率,得到實際的Token ID
- 返回結果
每次都是通過這種方式預測出下一個詞是什么
4 多文本生成函數
到這里就不止是預測下一個詞了,要不斷的預測
def predict_one_sample(model, tokenizer, device, args, title, context):title_ids = tokenizer.encode(title, add_special_tokens=False)context_ids = tokenizer.encode(context, add_special_tokens=False)input_ids = title_ids + [sep_id] + context_idscur_len = len(input_ids)last_token_id = input_ids[-1] input_ids = torch.tensor([input_ids], dtype=torch.long, device=device)while True:next_token_id = generate_next_token(input_ids,args)input_ids = torch.cat((input_ids, next_token_id.unsqueeze(0)), dim=1)cur_len += 1word = tokenizer.convert_ids_to_tokens(next_token_id.item())if cur_len >= args.generate_max_len and last_token_id == 8 and next_token_id == 3:breakif cur_len >= args.generate_max_len and word in [".", "。", "!", "!", "?", "?", ",", ","]:breakif next_token_id == eod_id:breakresult = tokenizer.decode(input_ids.squeeze(0))content = result.split("<sep>")[1] # 生成的最終內容return content
- 預測一個樣本的函數
- 從用戶獲得輸入標題轉化為Token ID
- 從用戶獲得輸入正文轉化為Token ID
- 標題和正文連接到一起
- 獲取輸入長度
- 獲取已經生成的內容的最后一個元素
- 把輸入數據轉化為Tensor
- while循環
- 通過生成函數生成下一個詞的token id
- 把新生成的token id加到原本的數據中(原本有5個詞,預測出第6個詞,將第6個詞和原來的5個詞進行拼接)
- 輸入長度增加1
- 將一個 token ID 轉換回其對應的文本 token
- 如果超過最大長度并且生成換行符
- 停止生成
- 如果超過最大長度并且生成標點符號
- 停止生成
- 如果生成了結束符
- 停止生成
- 將Token ID轉化為文本
- 將生成的文本按照分隔符進行分割
- 返回生成的內容
從零構建屬于自己的GPT系列1:數據預處理
從零構建屬于自己的GPT系列2:模型訓練1
從零構建屬于自己的GPT系列3:模型訓練2
從零構建屬于自己的GPT系列4:模型訓練3
從零構建屬于自己的GPT系列5:模型部署1
從零構建屬于自己的GPT系列6:模型部署2