Tinh chỉnh cải thiện mô hình bằng cách đào tạo trên nhiều ví dụ hơn có thể phù hợp với lời nhắc, cho phép bạn đạt được kết quả tốt hơn trên nhiều tác vụ. Sổ tay này cung cấp hướng dẫn từng bước cho tinh chỉnh GPT-4o mini mới của chúng tôi. Chúng tôi sẽ thực hiện trích xuất thực thể bằng cách sử dụng tập dữ liệu RecipeNLG , cung cấp nhiều công thức khác nhau và danh sách các thành phần chung được trích xuất cho từng công thức. Đây là tập dữ liệu phổ biến cho các tác vụ nhận dạng thực thể được đặt tên (NER).
Lưu ý: GPT-4o mini fine-tuning có sẵn cho các nhà phát triển trong các tầng sử dụng Tier 4 và 5 của chúng tôi . Bạn có thể bắt đầu tinh chỉnh tài khoản Chat GPT-4 mini bằng cách truy cập bảng điều khiển tinh chỉnh của mình, nhấp vào "create" và chọn "gpt-4o-mini-2024-07-18" từ danh sách thả xuống mô hình cơ sở.
Chúng ta sẽ thực hiện theo các bước sau:
+ Thiết lập: Tải tập dữ liệu của chúng tôi và lọc xuống một miền để tinh chỉnh.
+ Chuẩn bị dữ liệu: Chuẩn bị dữ liệu của bạn để tinh chỉnh bằng cách tạo các ví dụ đào tạo và xác thực, sau đó tải chúng lên Filesđiểm cuối.
+ Tinh chỉnh: Tạo mô hình tinh chỉnh của bạn.
+ Suy luận: Sử dụng mô hình tinh chỉnh của bạn để suy luận về các dữ liệu đầu vào mới.
Đến cuối khóa học này, bạn sẽ có thể đào tạo, đánh giá và triển khai một gpt-4o-mini-2024-07-18mô hình được tinh chỉnh.
Để biết thêm thông tin về tinh chỉnh, bạn có thể tham khảo hướng dẫn tài liệu hoặc tài liệu tham khảo API của chúng tôi .
Cài đặt
# make sure to use the latest version of the openai python package!pip install --upgrade --quiet openaiimport json
import openai
import os
import pandas as pd
from pprint import pprint
client = openai.OpenAI( api_key=os.environ.get("OPENAI_API_KEY"), organization="", project="",
)Tinh chỉnh hoạt động tốt nhất khi tập trung vào một miền cụ thể. Điều quan trọng là đảm bảo tập dữ liệu của bạn vừa đủ tập trung để mô hình có thể học, vừa đủ tổng quát để các ví dụ chưa thấy không bị bỏ sót. Với suy nghĩ này, chúng tôi đã trích xuất một tập hợp con từ tập dữ liệu RecipesNLG để chỉ chứa các tài liệu từ cookbooks.com .
# Read in the dataset we'll use for this task.
# This will be the RecipesNLG dataset, which we've cleaned to only contain documents from www.cookbooks.com
recipe_df = pd.read_csv("data/cookbook_recipes_nlg_10k.csv")
recipe_df.head()| tiêu đề | thành phần | hướng dẫn | liên kết | nguồn | XUỐNG | |
|---|---|---|---|---|---|---|
| 0 | Bánh quy hạt không cần nướng | ["1 cốc đường nâu đóng chặt", "1/2 cốc eva... | ["Trong một chiếc chảo nặng 2 lít, trộn đường nâu... | www.cookbooks.com/Recipe-Details.aspx?id=44874 | www.cookbooks.com | ["đường nâu", "sữa", "vani", "hạt", "bu... |
| 1 | Gà của Jewell Ball | ["1 lọ thịt bò băm nhỏ, thái nhỏ", "4 miếng ... | ["Đặt thịt bò thái nhỏ vào đáy đĩa nướng.... | www.cookbooks.com/Recipe-Details.aspx?id=699419 | www.cookbooks.com | ["thịt bò", "ức gà", "kem nấm... |
| 2 | Ngô kem | ["2 (16 oz.) gói ngô đông lạnh", "1 (8 oz.) gói... | ["Trong nồi nấu chậm, trộn tất cả các nguyên liệu. C... | www.cookbooks.com/Recipe-Details.aspx?id=10570 | www.cookbooks.com | ["ngô đông lạnh", "phô mai kem", "bơ", "sốt... |
| 3 | Gà buồn cười | ["1 con gà nguyên con lớn", "2 lon (10 1/2 oz.)... | ["Luộc chín và bỏ xương gà.", "Cho một miếng pi vừa ăn vào... | www.cookbooks.com/Recipe-Details.aspx?id=897570 | www.cookbooks.com | ["gà", "nước sốt gà", "kem nấm... |
| 4 | Reeses Cups (Kẹo) | ["1 cốc bơ đậu phộng", "3/4 cốc bánh quy graham ... | ["Trộn bốn nguyên liệu đầu tiên và ấn vào ... | www.cookbooks.com/Recipe-Details.aspx?id=659239 | www.cookbooks.com | ["bơ đậu phộng", "vụn bánh quy graham", "bu... |
Chuẩn bị dữ liệu
Chúng ta sẽ bắt đầu bằng cách chuẩn bị dữ liệu của mình. Khi tinh chỉnh định ChatCompletiondạng, mỗi ví dụ đào tạo là một danh sách đơn giản của messages. Ví dụ, một mục nhập có thể trông như sau:
[{'role': 'system', 'content': 'You are a helpful recipe assistant. You are to extract the generic ingredients from each of the recipes provided.'}, {'role': 'user', 'content': 'Title: No-Bake Nut Cookies\n\nIngredients: ["1 c. firmly packed brown sugar", "1/2 c. evaporated milk", "1/2 tsp. vanilla", "1/2 c. broken nuts (pecans)", "2 Tbsp. butter or margarine", "3 1/2 c. bite size shredded rice biscuits"]\n\nGeneric ingredients: '}, {'role': 'assistant', 'content': '["brown sugar", "milk", "vanilla", "nuts", "butter", "bite size shredded rice biscuits"]'}]Trong quá trình đào tạo, cuộc hội thoại này sẽ được chia nhỏ, với mục nhập cuối cùng là mục completionmà mô hình sẽ tạo ra và phần còn lại đóng messagesvai trò là lời nhắc. Hãy cân nhắc điều này khi xây dựng các ví dụ đào tạo của bạn - nếu mô hình của bạn sẽ hoạt động trên các cuộc hội thoại nhiều lượt, thì hãy cung cấp các ví dụ đại diện để nó không hoạt động kém khi cuộc hội thoại bắt đầu mở rộng.
Xin lưu ý rằng hiện tại có giới hạn 4096 mã thông báo cho mỗi ví dụ đào tạo. Bất kỳ ví dụ nào dài hơn giới hạn này sẽ bị cắt bớt ở mức 4096 mã thông báo.
system_message = "You are a helpful recipe assistant. You are to extract the generic ingredients from each of the recipes provided."
def create_user_message(row): return f"Title: {row['title']}\n\nIngredients: {row['ingredients']}\n\nGeneric ingredients: "
def prepare_example_conversation(row): return { "messages": [ {"role": "system", "content": system_message}, {"role": "user", "content": create_user_message(row)}, {"role": "assistant", "content": row["NER"]}, ] }
pprint(prepare_example_conversation(recipe_df.iloc[0])){'messages': [{'content': 'Bạn là trợ lý công thức nấu ăn hữu ích. Bạn phải ' 'trích xuất các thành phần chung từ mỗi ' 'công thức được cung cấp.', 'role': 'system'}, {'content': 'Tiêu đề: Bánh quy hạt không cần nướng\n' '\n' 'Thành phần: ["1 cốc đường nâu đóng chặt", ' '"1/2 cốc sữa đặc", "1/2 thìa cà phê vani", "1/2 cốc hạt vỡ (hạt hồ đào)", "2 thìa canh bơ hoặc ' 'bơ thực vật", "3 1/2 cốc gạo vụn vừa ăn ' 'bánh quy"]\n' '\n' 'Thành phần chung: ', 'role': 'người dùng'}, {'content': '["đường nâu", "sữa", "vani", "hạt", ' '"bơ", "bánh quy gạo vụn vừa ăn"]', 'role': 'trợ lý'}]}Bây giờ chúng ta hãy làm điều này cho một tập hợp con của tập dữ liệu để sử dụng làm dữ liệu đào tạo của chúng ta. Bạn có thể bắt đầu với 30-50 ví dụ được cắt tỉa kỹ lưỡng. Bạn sẽ thấy hiệu suất tiếp tục tăng theo tuyến tính khi bạn tăng kích thước của tập đào tạo, nhưng công việc của bạn cũng sẽ mất nhiều thời gian hơn.
# use the first 100 rows of the dataset for training
training_df = recipe_df.loc[0:100]
# apply the prepare_example_conversation function to each row of the training_df
training_data = training_df.apply(prepare_example_conversation, axis=1).tolist()
for example in training_data[:5]: print(example){'messages': [{'role': 'system', 'content': 'Bạn là trợ lý công thức nấu ăn hữu ích. Bạn phải trích xuất các thành phần chung từ mỗi công thức được cung cấp.'}, {'role': 'user', 'content': 'Tiêu đề: Bánh quy hạt không cần nướng\n\nThành phần: ["1 cốc đường nâu đóng chặt", "1/2 cốc sữa đặc", "1/2 thìa cà phê vani", "1/2 cốc hạt vỡ (hạt hồ đào)", "2 thìa canh bơ hoặc bơ thực vật", "3 1/2 cốc bánh quy gạo xé nhỏ"]\n\nThành phần chung: '}, {'role': 'assistant', 'content': '["đường nâu", "sữa", "vani", "hạt", "bơ", "bánh quy gạo xé nhỏ"]'}]} {'messages': [{'role': 'system', 'content': 'Bạn là trợ lý công thức hữu ích. Bạn phải trích xuất các thành phần chung từ mỗi công thức được cung cấp.'}, {'role': 'user', 'content': 'Tiêu đề: Gà Jewell Ball\n\nThành phần: ["1 lọ thịt bò băm nhỏ, cắt nhỏ", "4 ức gà bỏ xương", "1 hộp súp kem nấm", "1 hộp kem chua"]\n\nThành phần chung: '}, {'role': 'assistant', 'content': '["thịt bò", "ngực gà", "súp kem nấm", "kem chua"]'}]} {'messages': [{'role': 'system', 'content': 'Bạn là một trợ lý công thức hữu ích. Bạn phải trích xuất các thành phần chung từ mỗi công thức được cung cấp.'}, {'role': 'user', 'content': 'Tiêu đề: Ngô kem\n\nThành phần: ["2 (16 oz.) gói ngô đông lạnh", "1 (8 oz.) gói phô mai kem, thái hạt lựu", "1/3 cốc bơ, thái hạt lựu", "1/2 thìa cà phê bột tỏi", "1/2 thìa cà phê muối", "1/4 thìa cà phê tiêu"]\n\nThành phần chung: '}, {'role': 'assistant', 'content': '["ngô đông lạnh", "phô mai kem", "bơ", "bột tỏi", "muối", "tiêu"]'}]} {'messages': [{'role': 'system', 'content': 'Bạn là trợ lý công thức hữu ích. Bạn phải trích xuất các thành phần chung từ mỗi công thức được cung cấp.'}, {'role': 'user', 'content': 'Tiêu đề: Chicken Funny\n\nThành phần: ["1 con gà nguyên con lớn", "2 hộp nước sốt gà (10 1/2 oz.)", "1 hộp súp kem nấm (10 1/2 oz.)", "1 hộp nhồi thịt nướng Stove Top (6 oz.), "4 oz. phô mai bào"]\n\nThành phần chung: '}, {'role': 'assistant', 'content': '["gà", "nước sốt gà", "súp kem nấm",
"pho mát vụn"]'}]} {'messages': [{'role': 'system', 'content': 'Bạn là trợ lý công thức hữu ích. Bạn phải trích xuất các thành phần chung từ mỗi công thức được cung cấp.'}, {'role': 'user', 'content': 'Tiêu đề: Reeses Cups(Candy) \n\nThành phần: ["1 c. bơ đậu phộng", "3/4 c. vụn bánh quy graham", "1 c. bơ tan chảy", "1 lb. (3 1/2 c.) đường bột", "1 gói lớn vụn sô cô la"]\n\nThành phần chung: '}, {'role': 'assistant', 'content': '["bơ đậu phộng", "vụn bánh quy graham", "bơ", "đường bột", "vụn sô cô la"]'}]}Ngoài dữ liệu đào tạo, chúng tôi cũng có thể tùy chọn cung cấp dữ liệu xác thực, dữ liệu này sẽ được sử dụng để đảm bảo rằng mô hình không phù hợp quá mức với tập đào tạo của bạn.
validation_df = recipe_df.loc[101:200]
validation_data = validation_df.apply( prepare_example_conversation, axis=1).tolist()Sau đó, chúng ta cần lưu dữ liệu dưới dạng .jsonltệp, với mỗi dòng là một cuộc hội thoại mẫu để đào tạo.
def write_jsonl(data_list: list, filename: str) -> None: with open(filename, "w") as out: for ddict in data_list: jout = json.dumps(ddict) + "\n" out.write(jout)training_file_name = "tmp_recipe_finetune_training.jsonl"
write_jsonl(training_data, training_file_name)
validation_file_name = "tmp_recipe_finetune_validation.jsonl"
write_jsonl(validation_data, validation_file_name)Đây là hình ảnh 5 dòng đầu tiên trong .jsonltệp đào tạo của chúng tôi:
# print the first 5 lines of the training file!head -n 5 tmp_recipe_finetune_training.jsonl{"messages": [{"role": "system", "content": "Bạn là trợ lý công thức hữu ích. Bạn phải trích xuất các thành phần chung từ mỗi công thức được cung cấp."}, {"role": "user", "content": "Tiêu đề: Bánh quy hạt không cần nướng\n\nThành phần: [\"1 cốc đường nâu đóng chặt\", \"1/2 cốc sữa đặc\", \"1/2 thìa cà phê vani\", \"1/2 cốc hạt vỡ (hạt hồ đào)\", \"2 thìa canh bơ hoặc bơ thực vật\", \"3 1/2 cốc. bánh quy gạo xé nhỏ \ "]\n\nThành phần chung: "}, {"role": "trợ lý", "content": "[\"đường nâu \ "sữa \ "vani \ "hạt \ ", \"bơ \ ", \"bánh quy gạo xé nhỏ \ "]"}]} {"messages": [{"role": "hệ thống", "content": "Bạn là trợ lý công thức nấu ăn hữu ích. Bạn phải trích xuất các thành phần chung từ mỗi công thức được cung cấp."}, {"role": "người dùng", "content": "Tiêu đề: Gà Jewell Ball\n\nThành phần: [\"1 lọ nhỏ thịt bò băm nhỏ, cắt nhỏ \ ", \"4 ức gà bỏ xương \ ", \"1 lon súp kem nấm \ ", \"1 hộp kem chua \ "]\n\nThành phần chung: "}, {"role": "trợ lý", "content": "[\"thịt bò \ ", \"ức gà \ ", \"kem súp nấm\", \"kem chua\"]"}]} {"messages": [{"role": "system", "content": "Bạn là trợ lý công thức hữu ích. Bạn phải trích xuất các thành phần chung từ mỗi công thức được cung cấp."}, {"role": "user", "content": "Tiêu đề: Ngô kem\n\nThành phần: [\"2 (16 oz.) gói ngô đông lạnh\", \"1 (8 oz.) gói phô mai kem, thái hạt lựu\", \"1/3 cốc bơ, thái hạt lựu\", \"1/2 thìa cà phê bột tỏi\", \"1/2 thìa cà phê muối\", \"1/4 thìa cà phê. pepper\"]\n\nThành phần chung: "}, {"role": "trợ lý", "content": "[\"ngô đông lạnh\", \"phô mai kem\", \"bơ\", \"bột tỏi\", \"muối\", \"tiêu\"]"}]} {"messages": [{"role": "hệ thống", "content": "Bạn là trợ lý công thức nấu ăn hữu ích. Bạn phải trích xuất các thành phần chung từ mỗi công thức được cung cấp."}, {"role": "người dùng", "content": "Tiêu đề: Gà vui nhộn\n\nThành phần: [\"1 con gà nguyên con lớn\", \"2 hộp nước sốt gà (10 1/2 oz.)\", \"1 hộp súp kem nấm (10 1/2 oz.)\", \"1 hộp nhồi thịt nướng (6 oz.)\", \"4 oz. phô mai bào\"]\n\nThành phần chung: "},
{"role": "assistant", "content": "[\"gà\", \"nước sốt gà\", \"súp kem nấm\", \"phô mai bào\"]"}]} {"messages": [{"role": "system", "content": "Bạn là trợ lý công thức nấu ăn hữu ích. Bạn phải trích xuất các thành phần chung từ mỗi công thức được cung cấp."}, {"role": "user", "content": "Tiêu đề: Reeses Cups (Kẹo) \n\nThành phần: [\"1 cốc bơ đậu phộng\", \"3/4 cốc vụn bánh quy graham\", \"1 cốc bơ đã đun chảy\", \"1 lb. (3 1/2 cốc) đường bột\", \"1 gói lớn. vụn sô cô la\"]\n\nThành phần chung: "}, {"vai trò": "trợ lý", "nội dung": "[\"bơ đậu phộng\", \"vụn bánh quy graham\", \"bơ\", \"đường bột\", \"vụn sô cô la\"]"}]}Tải lên các tập tin
Bây giờ bạn có thể tải các tệp lên Filesđiểm cuối của chúng tôi để mô hình được tinh chỉnh sử dụng.
def upload_file(file_name: str, purpose: str) -> str: with open(file_name, "rb") as file_fd: response = client.files.create(file=file_fd, purpose=purpose) return response.id
training_file_id = upload_file(training_file_name, "fine-tune")
validation_file_id = upload_file(validation_file_name, "fine-tune")
print("Training file ID:", training_file_id)
print("Validation file ID:", validation_file_id)ID tệp đào tạo: file-3wfAfDoYcGrSpaE17qK0vXT0 ID tệp xác thực: file-HhFhnyGJhazYdPcd3wrtvIoXTinh chỉnh
Bây giờ chúng ta có thể tạo công việc tinh chỉnh của mình với các tệp đã tạo và hậu tố tùy chọn để xác định mô hình. Phản hồi sẽ chứa một idmà bạn có thể sử dụng để truy xuất các bản cập nhật về công việc.
Lưu ý: Các tập tin phải được hệ thống của chúng tôi xử lý trước, do đó bạn có thể gặp lỗi File not ready. Trong trường hợp đó, chỉ cần thử lại sau vài phút.
MODEL = "gpt-4o-mini-2024-07-18"
response = client.fine_tuning.jobs.create( training_file=training_file_id, validation_file=validation_file_id, model=MODEL, suffix="recipe-ner",
)
job_id = response.id
print("Job ID:", response.id)
print("Status:", response.status)ID công việc: ftjob-UiaiLwGdGBfdLQDBAoQheufN Trạng thái: validating_filesKiểm tra trạng thái công việc
Bạn có thể gửi GETyêu cầu đến https://api.openai.com/v1/alpha/fine-tunesđiểm cuối để liệt kê các tác vụ tinh chỉnh alpha của mình. Trong trường hợp này, bạn sẽ muốn kiểm tra xem ID bạn nhận được từ bước trước có kết thúc là status: succeeded.
Sau khi hoàn tất, bạn có thể sử dụng result_filesđể lấy mẫu kết quả từ bộ xác thực (nếu bạn đã tải lên) và sử dụng ID từ tham fine_tuned_modelsố để gọi mô hình đã đào tạo của bạn.
response = client.fine_tuning.jobs.retrieve(job_id)
print("Job ID:", response.id)
print("Status:", response.status)
print("Trained Tokens:", response.trained_tokens)ID công việc: ftjob-UiaiLwGdGBfdLQDBAoQheufN Trạng thái: đang chạy Mã thông báo đã đào tạo: Không cóChúng ta có thể theo dõi tiến trình tinh chỉnh bằng điểm cuối sự kiện. Bạn có thể chạy lại ô bên dưới một vài lần cho đến khi tinh chỉnh sẵn sàng.
response = client.fine_tuning.jobs.list_events(job_id)
events = response.data
events.reverse()
for event in events: print(event.message)Bước 288/303: mất mát đào tạo=0,00 Bước 289/303: mất mát đào tạo=0,01 Bước 290/303: mất mát đào tạo=0,00, mất mát xác thực=0,31 Bước 291/303: mất mát đào tạo=0,00 Bước 292/303: mất mát đào tạo=0,00 Bước 293/303: mất mát đào tạo=0,00 Bước 294/303: mất mát đào tạo=0,00 Bước 295/303: mất mát đào tạo=0,00 Bước 296/303: mất mát đào tạo=0,00 Bước 297/303: mất mát đào tạo=0,00 Bước 298/303: mất mát đào tạo=0,01 Bước 299/303: mất mát đào tạo=0,00 Bước 300/303: mất mát đào tạo=0,00, mất mát xác thực=0,04 Bước 301/303: mất mát đào tạo=0,16 Bước 302/303: mất mát đào tạo=0,00 Bước 303/303: mất mát đào tạo=0,00, mất mát xác thực đầy đủ=0,33 Điểm kiểm tra được tạo tại bước 101 với ID ảnh chụp nhanh: ft:gpt-4o-mini-2024-07-18:openai-gtm:recipe-ner:9o1eNlSa:ckpt-step-101 Điểm kiểm tra được tạo tại bước 202 với ID ảnh chụp nhanh: ft:gpt-4o-mini-2024-07-18:openai-gtm:recipe-ner:9o1eNFnj:ckpt-step-202 Mô hình tinh chỉnh mới được tạo: ft:gpt-4o-mini-2024-07-18:openai-gtm:recipe-ner:9o1eNNKO Công việc đã hoàn thành thành côngBây giờ khi đã hoàn tất, chúng ta có thể có được ID mô hình được tinh chỉnh từ công việc:
response = client.fine_tuning.jobs.retrieve(job_id)
fine_tuned_model_id = response.fine_tuned_model
if fine_tuned_model_id is None: raise RuntimeError( "Fine-tuned model ID not found. Your job has likely not been completed yet." )
print("Fine-tuned model ID:", fine_tuned_model_id)Mã số mô hình tinh chỉnh: ft:gpt-4o-mini-2024-07-18:openai-gtm:recipe-ner:9o1eNNKOSuy luận
Bước cuối cùng là sử dụng mô hình tinh chỉnh của bạn để suy luận. Tương tự như mô hình cổ điển FineTuning, bạn chỉ cần gọi ChatCompletionsbằng tên mô hình tinh chỉnh mới của mình để điền tham modelsố.
test_df = recipe_df.loc[201:300]
test_row = test_df.iloc[0]
test_messages = []
test_messages.append({"role": "system", "content": system_message})
user_message = create_user_message(test_row)
test_messages.append({"role": "user", "content": user_message})
pprint(test_messages)[{'content': 'Bạn là trợ lý công thức hữu ích. Bạn phải trích xuất ' 'thành phần chung từ mỗi công thức được cung cấp.', 'role': 'system'}, {'content': 'Tiêu đề: Thịt ức bò\n' '\n' 'Thành phần: ["4 lb. thịt ức bò", "1 c. tương cà", "1 c. nước", ' '"1/2 củ hành tây, băm nhỏ", "2 thìa canh giấm táo", "1 thìa canh ' 'cải ngựa đã chế biến", "1 thìa canh mù tạt đã chế biến", "1 thìa cà phê muối", "1/2 ' 'tsp. tiêu"]\n' '\n' 'Thành phần chung: ', 'role': 'user'}]response = client.chat.completions.create( model=fine_tuned_model_id, messages=test_messages, temperature=0, max_tokens=500
)
print(response.choices[0].message.content)["thịt bò ức", "tương cà", "nước", "hành tây", "giấm táo", "cải ngựa", "mù tạt", "muối", "hạt tiêu"]Phần kết luận
Xin chúc mừng, bây giờ bạn đã sẵn sàng tinh chỉnh các mô hình của riêng mình bằng cách sử dụng ChatCompletionđịnh dạng này! Chúng tôi mong muốn được xem những gì bạn xây dựng
Xem thêm: mua tài khoản ChatGPT Plus chính hãng giá rẻ với nhiều ưu đãi đặc biệt

Cách đổi Mật khẩu Chat GPT - Hướng dẫn đổi Pass Chat GPT 100% Thành công
Hướng dẫn Cách đăng nhập Chat GPT Nhanh nhất | Có hỗ trợ Miễn phí qua Teamview-Ultraview
Chat GPT Plus là gì? So sánh Chat GPT Plus với Chat GPT Miễn phí
Chat GPT bị giới hạn giải thích vì sao và cách khắc phục
Chat GPT là gì ? Cách đăng Ký Chat GPT Miễn Phí tại Việt Nam