note
一、NLG任務
NLG:自然語言生成任務,很多NLP任務可以被描述為NLG任務,如經(jīng)典的T5模型(text to text transfer transformer模型)就是NLG模型,如文本糾錯任務,輸出正確的文本描述、智能問答根據(jù)一定背景進行推理,然后回答。
# 安裝一些必要的包
!pip install openai
# torch install 命令 https://pytorch.org/get-started/locally/
!pip install torch==2.0.0+cpu torchvision==0.15.1+cpu --extra-index-url https://download.pytorch.org/whl/cpu
!pip install tokenizers==0.13.2
!pip install transformers==4.27.4
!pip install --no-binary=protobuf protobuf==3.20.1
!pip install sentencepiece==0.1.97
!pip install shap==2.8.2
# 配置openai api key
import openai
OPENAI_API_KEY = "填入專屬的API key" # TODO
openai.api_key = OPENAI_API_KEY
models = openai.Model.list()
# 有60+個模型,fine-tune模型是以ft-personal開頭
print([x.id for x in models.data])
二、NLG之文本摘要
主要分為三種:
- 抽取式摘要:從原文檔中提取現(xiàn)成的句子作為摘要句。
- 壓縮式摘要:對原文檔的冗余信息進行過濾,壓縮文本作為摘要。
- 生成式摘要:基于NLG技術,根據(jù)源文檔內(nèi)容,由算法模型自己生成自然語言描述。
2.1 基于mT5的文本摘要
這里先使用huggingface進行測試:
''''''
import re
import torch
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
# 載入模型
tokenizer = AutoTokenizer.from_pretrained("csebuetnlp/mT5_multilingual_XLSum")
model = AutoModelForSeq2SeqLM.from_pretrained("csebuetnlp/mT5_multilingual_XLSum")
WHITESPACE_HANDLER = lambda k: re.sub('\s+', ' ', re.sub('\n+', ' ', k.strip()))
text = """全球游戲用戶已經(jīng)達到37億,占到全球人口的一半,這是一個非常龐大的市場,這個市場完全值得我們?nèi)リP注和應用,其中休閑游戲用戶又占了很大的比例。為什么休閑游戲用戶能夠占那么大的比例,且還在不斷增長呢?我們拿短視頻迅猛的發(fā)展來舉例。現(xiàn)在大家生活節(jié)奏很快,壓力也很大,用戶需要一些輕松快樂的體驗來緩解壓力、調(diào)整情緒。短視頻的體驗就非常輕松,想看就看,想停就停,看的時候可以給人帶來快樂,還可以讓你學到一些東西。在大數(shù)據(jù)的加持下,不斷推給用戶想看的東西,甚至讓用戶停不下來。休閑游戲也是類似的,休閑游戲本質(zhì)上也是輕松,可以帶來快樂并幫助用戶減壓的,而且休閑游戲比短視頻有一個優(yōu)勢是其提供的各種各樣的核心玩法,具備更多交互元素和不同的體驗。"""
text = WHITESPACE_HANDLER(text)
input_ids = tokenizer([text], return_tensors="pt", padding="max_length", truncation=True, max_length=512)["input_ids"]
# 生成結(jié)果文本
output_ids = model.generate(input_ids=input_ids, max_length=84, no_repeat_ngram_size=2, num_beams=4)[0]
output_text = tokenizer.decode(output_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)
print("原始文本: ", text)
print("摘要文本: ", output_text)
# 摘要文本: 休閑游戲已經(jīng)成為人們生活中不可或缺的一部分。
2.2 基于openai接口測試
def summarize_text(text):
response = openai.Completion.create(
engine="text-davinci-003",
prompt=f"請對以下文本進行總結(jié),注意總結(jié)的凝煉性,將總結(jié)字數(shù)控制在20個字以內(nèi):\n{text}",
temperature=0.7,
max_tokens=500,
)
summarized_text = response.choices[0].text.strip()
return summarized_text
text = "全球游戲用戶已經(jīng)達到37億,占到全球人口的一半,這是一個非常龐大的市場,這個市場完全值得我們?nèi)リP注和應用,其中休閑游戲用戶又占了很大的比例。為什么休閑游戲用戶能夠占那么大的比例,且還在不斷增長呢?我們拿短視頻迅猛的發(fā)展來舉例?,F(xiàn)在大家生活節(jié)奏很快,壓力也很大,用戶需要一些輕松快樂的體驗來緩解壓力、調(diào)整情緒。短視頻的體驗就非常輕松,想看就看,想停就停,看的時候可以給人帶來快樂,還可以讓你學到一些東西。在大數(shù)據(jù)的加持下,不斷推給用戶想看的東西,甚至讓用戶停不下來。休閑游戲也是類似的,休閑游戲本質(zhì)上也是輕松,可以帶來快樂并幫助用戶減壓的,而且休閑游戲比短視頻有一個優(yōu)勢是其提供的各種各樣的核心玩法,具備更多交互元素和不同的體驗。"""
output_text = summarize_text(text)
print("原始文本: ", text)
print("摘要文本: ", output_text)
print("摘要文本長度: ", len(output_text))
# 摘要文本: 全球游戲用戶已達37億,休閑游戲占比很大且不斷增長,因其輕松快樂的體驗及大數(shù)據(jù)推送,可緩解生活壓力并學習新知識。
# 摘要文本長度: 56
2.3 基于chatGPT接口
def summarize_text(text):
content = f"請對以下文本進行總結(jié),注意總結(jié)的凝煉性,將總結(jié)字數(shù)控制在20個字以內(nèi):\n{text}"
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": content}]
)
summarized_text = response.get("choices")[0].get("message").get("content")
return summarized_text
text = """全球游戲用戶已經(jīng)達到37億,占到全球人口的一半,這是一個非常龐大的市場,這個市場完全值得我們?nèi)リP注和應用,其中休閑游戲用戶又占了很大的比例。為什么休閑游戲用戶能夠占那么大的比例,且還在不斷增長呢?我們拿短視頻迅猛的發(fā)展來舉例?,F(xiàn)在大家生活節(jié)奏很快,壓力也很大,用戶需要一些輕松快樂的體驗來緩解壓力、調(diào)整情緒。短視頻的體驗就非常輕松,想看就看,想停就停,看的時候可以給人帶來快樂,還可以讓你學到一些東西。在大數(shù)據(jù)的加持下,不斷推給用戶想看的東西,甚至讓用戶停不下來。休閑游戲也是類似的,休閑游戲本質(zhì)上也是輕松,可以帶來快樂并幫助用戶減壓的,而且休閑游戲比短視頻有一個優(yōu)勢是其提供的各種各樣的核心玩法,具備更多交互元素和不同的體驗。"""
output_text = summarize_text(text)
print("原始文本: ", text)
print("摘要文本: ", output_text)
print("摘要文本長度: ", len(output_text))
# 注意,chatgpt并不能完美限制摘要輸出的字數(shù)
# 摘要文本: 全球游戲用戶超37億,休閑游戲用戶增長迅速,因為輕松解壓,且提供多樣化體驗。
# 摘要文本長度: 38
從上面的三種方法結(jié)果對比,可以發(fā)現(xiàn)huggingface的預訓練模型mT5結(jié)果其實還不太好,后面兩種結(jié)果挺好,還概括出游戲受歡迎的原因。
三、根據(jù)自己的數(shù)據(jù)集進行模型微調(diào)
數(shù)據(jù)集來源:CSL摘要數(shù)據(jù)集,是計算機領域的論文摘要和標題數(shù)據(jù),包含3500條數(shù)據(jù),
- 標題:平均字數(shù) 18,字數(shù)標準差 4,最大字數(shù)41,最小數(shù)字 6;
- 正文:平均字數(shù) 200,字數(shù)標準差 63,最大字數(shù) 631,最小數(shù)字 41;
這里我們根據(jù)自己的數(shù)據(jù)集進行模型微調(diào),3500條數(shù)據(jù),每個數(shù)據(jù)都包括title
和content
兩個內(nèi)容。data
列表中每個元素是一個含有這兩坨的字典。
數(shù)據(jù)源地址:https://github.com/liucongg/GPT2-NewsTitle 項目中的CSL摘要數(shù)據(jù)集
import json
with open('/home/andy/torch_rechub_n/hug_llm/content/dataset/csl_data.json', 'r', encoding='utf-8') as f:
data = json.load(f)
len(data) # 3500
data[0]
{'title': '保細節(jié)的網(wǎng)格剛性變形算法',
'content': '提出了一種新的保細節(jié)的變形算法,可以使網(wǎng)格模型進行盡量剛性的變形,以減少變形中幾何細節(jié)的扭曲.首先根據(jù)網(wǎng)格曲面局部細節(jié)的豐富程度,對原始網(wǎng)格進行聚類生成其簡化網(wǎng)格;然后對簡化網(wǎng)格進行變形,根據(jù)其相鄰面片變形的相似性,對簡化網(wǎng)格作進一步的合并,生成新的變形結(jié)果,將該變形傳遞給原始網(wǎng)格作為初始變形結(jié)果.由于對屬于同一個類的網(wǎng)格頂點進行相同的剛性變形,可在變形中較好地保持該區(qū)域的表面細節(jié),但分屬不同類的頂點之間會出現(xiàn)變形的不連續(xù).為此,通過迭代優(yōu)化一個二次能量函數(shù),對每個網(wǎng)格頂點的變形進行調(diào)整來得到最終變形結(jié)果.實驗結(jié)果顯示,該算法簡單高效,結(jié)果令人滿意.'}
import pandas as pd
df = pd.DataFrame(data)
df = df[['content', 'title']]
df.columns = ["prompt", "completion"]
df_train = df.iloc[:500]
df_train.head(5)
file_path = "/home/andy/torch_rechub_n/hug_llm/content/dataset"
df_train.to_json(file_path + "/csl_summarize_finetune.jsonl", \
orient='records', lines=True, force_ascii=False)
!openai tools fine_tunes.prepare_data -f /home/andy/torch_rechub_n/hug_llm/content/dataset/csl_summarize_finetune.jsonl -q
file_path = "/home/andy/torch_rechub_n/hug_llm/content/dataset"
!openai api fine_tunes.create \
-t "/home/andy/torch_rechub_n/hug_llm/content/dataset/csl_summarize_finetune_prepared.jsonl" \
-m ada\
--no_check_if_files_exist
huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks...
To disable this warning, you can either:
- Avoid using `tokenizers` before the fork if possible
- Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false)
Upload progress: 100%|███████████████████████| 380k/380k [00:00<00:00, 841Mit/s]
Uploaded file from /home/andy/torch_rechub_n/hug_llm/content/dataset/csl_summarize_finetune_prepared.jsonl: file-cNMh8V9gYipAoLlqgoL0upll
Created fine-tune: ft-6IqMLGVl0FXEWifOvBsY0Aoc
Streaming events until fine-tuning is complete...
(Ctrl-C will interrupt the stream, but not cancel the fine-tune)
[2023-04-25 02:48:37] Created fine-tune: ft-6IqMLGVl0FXEWifOvBsY0Aoc
[2023-04-25 02:48:49] Fine-tune costs $0.43
[2023-04-25 02:48:50] Fine-tune enqueued. Queue number: 2
從上面得到fine tune運行所需的key:
!openai api fine_tunes.get -i ft-6IqMLGVl0FXEWifOvBsY0Aoc
# 保存openai fine tune過程的記錄
!openai api fine_tunes.results -i ft-6IqMLGVl0FXEWifOvBsY0Aoc > /home/andy/torch_rechub_n/hug_llm/content/dataset/metric.csv
# 后面的執(zhí)行步驟是和之前一致的
# game text
def summarize_text(text, model_name):
response = openai.Completion.create(
engine=model_name,
prompt=f"請對以下文本進行總結(jié),注意總結(jié)的凝煉性,將總結(jié)字數(shù)控制在20個字以內(nèi):\n{text}",
temperature=0.7,
max_tokens=100,
)
summarized_text = response.choices[0].text.strip()
return summarized_text
text = "全球游戲用戶已經(jīng)達到37億,占到全球人口的一半,這是一個非常龐大的市場,這個市場完全值得我們?nèi)リP注和應用,其中休閑游戲用戶又占了很大的比例。為什么休閑游戲用戶能夠占那么大的比例,且還在不斷增長呢?我們拿短視頻迅猛的發(fā)展來舉例。現(xiàn)在大家生活節(jié)奏很快,壓力也很大,用戶需要一些輕松快樂的體驗來緩解壓力、調(diào)整情緒。短視頻的體驗就非常輕松,想看就看,想停就停,看的時候可以給人帶來快樂,還可以讓你學到一些東西。在大數(shù)據(jù)的加持下,不斷推給用戶想看的東西,甚至讓用戶停不下來。休閑游戲也是類似的,休閑游戲本質(zhì)上也是輕松,可以帶來快樂并幫助用戶減壓的,而且休閑游戲比短視頻有一個優(yōu)勢是其提供的各種各樣的核心玩法,具備更多交互元素和不同的體驗。"""
print("一、原始文本: ", text, "\n")
print("二、ada摘要文本: ", summarize_text(text, model_name='ada'), "\n")
# print("ada fine-tune摘要文本: ", summarize_text(text, model_name='ada:ft-personal-2023-04-15-13-29-50'))
# # ft model: ada:ft-personal-2023-04-25-02-56-14
print("三、ada fine-tune摘要文本: ", summarize_text(text, model_name='ada:ft-personal-2023-04-25-02-56-14'))
二、ada摘要文本: 因此,多達到休閑游戲的最佳解決方式是在推給用戶帶來快樂的時候,提醒一個人做好改進活動。
三、ada fine-tune摘要文本: 休閑游戲產(chǎn)品的結(jié)構(gòu)和價值出現(xiàn)在游戲的結(jié)構(gòu)上的字數(shù)較偏高的地位。有類似的游戲主題非演講系
四、文本糾錯任務
如飛機寫錯為灰機。常見的文本糾錯技術主要有以下幾種:
- 基于規(guī)則的文本糾錯技術:在數(shù)據(jù)庫中加入常見錯誤的映射,如金字塔和金子塔,但耗時耗力;
- 基于語言模型的文本糾錯技術:如Kenlm模型
- 錯誤檢測:使用
jieba
中文分詞器對句子進行切詞,然后結(jié)合字粒度和詞粒度兩方面的疑似錯誤結(jié)果,形成疑似錯誤位置候選集。 - 錯誤糾正:遍歷所有的候選集并使用音似、形似詞典替換錯誤位置的詞,然后通過語言模型計算句子困惑度,最后比較并排序所有候選集結(jié)果,得到最優(yōu)糾正詞。
- 錯誤檢測:使用
- 基于MLM的文本糾錯技術:bert就使用了Masked Language Model掩碼語言模型(MLM)及Next Sentence Prediction下一句預測(NSP)兩個任務,其中MLM任務中有15%*10%的Token會被替換為隨機的其他詞匯,迫使模型更多地依賴于上下文信息去預測Mask詞匯,在一定程度上賦予了模型糾錯能力。
- 可以針對MLM, 將輸入設計為錯誤詞匯,輸出為正確詞匯,進fine tune,參考ACL2020的Soft-Masked BERT模型
- 于NLG的文本糾錯技術:mask方法只能用于輸入和輸出等長的情況,可以在bert后嵌入一層transformer decoder,將文本糾錯,轉(zhuǎn)為將錯誤的文本翻譯為正確文本
pycorrector
是一個文本糾錯工具集,內(nèi)置了KenLM、MacBERT、Transformer等多種文本糾錯模型。
- pycorrector的項目地址:https://github.com/shibing624/pycorrector
- 一個基于MacBERT的線上Demo:https://huggingface.co/spaces/shibing624/pycorrector
??pycorrector不僅可以通過“import pycorrector”調(diào)用,也提供了Huggingface的預訓練模型調(diào)用方式,以下是一個基于Huggingface的MacBERT4CSC調(diào)用樣例。
# 1. 預訓練模型
from transformers import BertTokenizer, BertForMaskedLM
# 載入模型
tokenizer = BertTokenizer.from_pretrained("shibing624/macbert4csc-base-chinese")
model = BertForMaskedLM.from_pretrained("shibing624/macbert4csc-base-chinese")
# text = "作為學生,一定要學習好學校的課乘!"
text = "重慶是一個好地方,今天天氣好,適合除去玩"
input_ids = tokenizer([text], padding=True, return_tensors='pt')
# 生成結(jié)果文本
with torch.no_grad():
outputs = model(**input_ids)
output_ids = torch.argmax(outputs.logits, dim=-1)
output_text = tokenizer.decode(output_ids[0], skip_special_tokens=True).replace(' ', '')
print("原始文本: ", text)
print("糾錯文本: ", output_text)
# 原始文本: 重慶是一個好地方,今天天氣好,適合除去玩
# 糾錯文本: 重慶是一個好地方,今天天氣好,適合出去玩
# 查看修改點
import operator
def get_errors(corrected_text, origin_text):
sub_details = []
for i, ori_char in enumerate(origin_text):
if ori_char in [' ', '“', '”', '‘', '’', '琊', '\n', '…', '—', '擤']:
# add unk word
corrected_text = corrected_text[:i] + ori_char + corrected_text[i:]
continue
if i >= len(corrected_text):
continue
if ori_char != corrected_text[i]:
if ori_char.lower() == corrected_text[i]:
# pass english upper char
corrected_text = corrected_text[:i] + ori_char + corrected_text[i + 1:]
continue
sub_details.append((ori_char, corrected_text[i], i, i + 1))
sub_details = sorted(sub_details, key=operator.itemgetter(2))
return corrected_text, sub_details
correct_text, details = get_errors(output_text[:len(text)], text)
print(details)
# 2. 基于OpenAI接口的文本糾錯實驗
def correct_text(text):
content = f"請對以下文本進行文本糾錯:\n{text}"
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": content}]
)
corrected_text = response.get("choices")[0].get("message").get("content")
return corrected_text
# text = "作為學生,一定要學習好學校的課乘!"
text = "重慶是一個好地方,今天天氣好,適合除去玩"
output_text = correct_text(text)
print("原始文本: ", text)
print("糾錯文本: ", output_text)
五、機器翻譯任務
- 基于規(guī)則的方法
- 基于統(tǒng)計的方法
- 基于神經(jīng)網(wǎng)絡的方法
# 1. huggingface的pre-trained model
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
tokenizer = AutoTokenizer.from_pretrained("Helsinki-NLP/opus-mt-zh-en")
model = AutoModelForSeq2SeqLM.from_pretrained("Helsinki-NLP/opus-mt-zh-en")
# text = "作為學生,一定要學習好學校的課乘!"
text = "重慶是一個好地方, 今天適合出去玩"
inputs = tokenizer(text, return_tensors="pt", )
outputs = model.generate(inputs["input_ids"], max_length=40, num_beams=4, early_stopping=True)
translated_sentence = tokenizer.decode(outputs[0], skip_special_tokens=True)
print('原始文本: ', text)
print('翻譯文本: ', translated_sentence)
#原始文本: 重慶是一個好地方, 今天適合出去玩
#翻譯文本: Chongqing is a good place to go. It's a good day.
# 2. 基于OpenAI接口的機器翻譯實驗
def translate_text(text):
content = f"請將以下中文文本翻譯成英文:\n{text}"
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": content}]
)
translated_text = response.get("choices")[0].get("message").get("content")
return translated_text
text_to_translate = "重慶是一個好地方,今天天氣好,適合出去玩"
translated_text = translate_text(text_to_translate)
print("原始文本: ", text_to_translate)
print("輸出文本: ", translated_text)
# 原始文本: 重慶是一個好地方,今天天氣好,適合出去玩
# 輸出文本: Chongqing is a great place. Today, the weather is good and it's suitable for going out and having fun.
上面的翻譯結(jié)果對比:ChatGPT明顯比Helsinki-NLP在中翻英上的效果更好,而不是簡單的”直譯“,用詞相對更為豐富。
翻譯數(shù)據(jù):數(shù)據(jù)來源 https://github.com/LouisScorpio/datamining/tree/master/tensorflow-program/nlp/word2vec/dataset
下面翻譯《哈利波特》并保存結(jié)果,第一冊共有token數(shù): 119873。GPT3的token限制數(shù)是4k,而GPT4是3萬+,所以可以將每個段落當成一個文本塊,每次翻譯一段。
with open(file_path + "/哈利波特1-7英文原版.txt", "r", encoding='gbk') as f:
text = f.read()
from transformers import GPT2Tokenizer
tokenizer = GPT2Tokenizer.from_pretrained("gpt2") # GPT-2的tokenizer和GPT-3是一樣的
token_counts = len(tokenizer.encode(text))
print('全書token數(shù): ', token_counts)
# chatgpt的api調(diào)用價格是 1000 token 0.01美元,因此可以大致計算翻譯一本書的價格
translate_cost = 0.01 / 1000 * token_counts
print(f'翻譯全書約需{translate_cost}美元')
# 翻譯全書約需115.14 rmb成本,有點貴了,我們試著只翻譯第一本
end_idx = text.find('2.Harry Potter and The Chamber Of Secrets.txt') # 第一冊的結(jié)束位置
text = text[:end_idx]
print('第一冊字符數(shù): ', len(text))
tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
token_counts = len(tokenizer.encode(text))
print('第一冊token數(shù): ', token_counts)
translate_cost = 0.01 / 1000 * token_counts
print(f'翻譯第一冊約需{translate_cost}美元')
paragraphs = text.split('\n')
print('段落數(shù): ', len(paragraphs))
ntokens = []
for paragraph in paragraphs:
ntokens.append(len(tokenizer.encode(paragraph)))
print('最長段落的token數(shù): ', max(ntokens))
# 段落數(shù): 3038
# 最長段落的token數(shù): 275
但是切分文本塊太小會導致語境缺失,可以設置閾值為1000,即文本段落達到1k則新開一個,最后將翻譯結(jié)果拼接:
def group_paragraphs(paragraphs, ntokens, max_len=1000):
"""
合并短段落為文本塊,用于豐富上下文語境,提升文本連貫性,并提升運算效率。
:param paragraphs: 段落集合
:param ntokens: token數(shù)集合
:param max_len: 最大文本塊token數(shù)
:return: 組合好的文本塊
"""
batches = []
cur_batch = ""
cur_tokens = 0
# 對于每個文本段落做處理
for paragraph, ntoken in zip(paragraphs, ntokens):
if ntoken + cur_tokens + 1 > max_len: # '1' 指的是'\n'
# 如果加入這段文本,總token數(shù)超過閾值,則開啟新的文本塊
batches.append(cur_batch)
cur_batch = paragraph
cur_tokens = ntoken
else:
# 否則將段落插入文本塊中
cur_batch += "\n" + paragraph
cur_tokens += (1 + ntoken)
batches.append(cur_batch) # 記錄最后一個文本塊
return batches
batchs = group_paragraphs(paragraphs, ntokens)
print('文本塊數(shù): ', len(batchs))
new_tokens = []
for batch in batchs:
new_tokens.append(len(tokenizer.encode(batch)))
print('最長文本塊的token數(shù): ', max(new_tokens))
# 文本塊數(shù): 125
# 最長文本塊的token數(shù): 1000
def translate_text(text):
content = f"請將以下英文文本翻譯成中文:\n{text}"
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": content}]
)
translated_text = response.get("choices")[0].get("message").get("content")
return translated_text
print(translate_text(batchs[0]))
translated_batchs = []
for i in range(len(batchs)):
batch_context = batchs[i]
translated_batchs.append(translate_text(batch_context))
文章來源:http://www.zghlxwxcb.cn/news/detail-425648.html
Reference
[1] fine tune tutorial
[2] 中文文本糾錯算法整體介紹
[3] 中文文本糾錯任務簡介
[4] pycorrector介紹
[5] 長文本英翻中tutorial
[6] https://learnprompting.org/docs/intermediate/least_to_most
[7] https://github.com/datawhalechina/hugging-llm文章來源地址http://www.zghlxwxcb.cn/news/detail-425648.html
到了這里,關于【GPT】文本生成任務(生成摘要、文本糾錯、機器翻譯等的模型微調(diào))的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!