Views
No views yet
transformersCS221DoAn/vietnamese_food_order_extraction is a fine-tuned Named Entity Recognition (NER) model based on the pre-trained monolingual language model PhoBERT-base (vinai/phobert-base)[cite: 1]. It is specifically trained and optimized for Token Classification on domain-specific Vietnamese unstructured text: Online Food Delivery Orders and Messages.| Tag | Entity Class | Description | Examples |
|---|---|---|---|
B-FOOD, I-FOOD | FOOD | Names of dishes, drinks, toppings | cơm sườn, trà sữa, trân châu |
B-QUANTITY, I-QUANTITY | QUANTITY | Portions, servings, item counts | 1p, 2 ly, một hộp, 3 suất |
B-NOTE, I-NOTE | NOTE | Special requests, flavor modifications | không ..., ít ngọt, nhiều ... |
B-PLACE, I-PLACE | PLACE | Delivery location, addresses | Ký túc xá khu A, tòa D6, rào b4 |
B-PHONE, I-PHONE | PHONE | Receiver's contact number | 0794987xxx, 0903123xxx |
B-TIME, I-TIME | TIME | Expected/requested delivery time | lúc 11h30, trưa nay, 18h |
B-PRICE, I-PRICE | PRICE | Monetary cost, item prices | 35k, 40000, 25 ngàn |
O | OUTSIDE | Non-entity words, syntax connecting words | cho em, giao qua, với, ạ, nhé |
seqeval framework:1 precision recall f1-score support
2
3 FOOD 0.9921 0.9947 0.9934 1135
4 NOTE 0.9938 0.9815 0.9876 162
5 PHONE 1.0000 1.0000 1.0000 225
6 PLACE 0.9926 0.9963 0.9945 270
7 PRICE 1.0000 1.0000 1.0000 34
8 QUANTITY 0.9965 0.9965 0.9965 282
9 TIME 0.9593 0.9752 0.9672 121
10
11 micro avg 0.9919 0.9937 0.9928 2229
12 macro avg 0.9906 0.9920 0.9913 2229
13weighted avg 0.9920 0.9937 0.9928 2229
14Trainer API from Hugging Face with the following configuration:2e-516100.01transformers1pip install -q transformers py_vncorenlp torch
21import os
2import re
3import torch
4import urllib.request
5import py_vncorenlp
6from transformers import AutoTokenizer, AutoModelForTokenClassification
7
8# 1. Setup Device and Load Model from Hugging Face Hub
9device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
10MODEL_ID = "CS221DoAn/vietnamese_food_order_extraction"
11
12print("Loading Model and Tokenizer...")
13tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
14model = AutoModelForTokenClassification.from_pretrained(MODEL_ID).to(device)
15model.eval()
16
17# 2. Initialize VnCoreNLP (Robust setup for Windows/Linux/Colab)
18vncorenlp_dir = os.path.abspath('./vncorenlp')
19os.makedirs(os.path.join(vncorenlp_dir, "models", "wordsegmenter"), exist_ok=True)
20
21if not os.path.exists(os.path.join(vncorenlp_dir, "VnCoreNLP-1.2.jar")):
22 print("Downloading VnCoreNLP models...")
23 base_url = "https://raw.githubusercontent.com/vncorenlp/VnCoreNLP/master/"
24 files = ["VnCoreNLP-1.2.jar", "models/wordsegmenter/vi-vocab", "models/wordsegmenter/wordsegmenter.rdr"]
25 for f in files:
26 urllib.request.urlretrieve(base_url + f, os.path.join(vncorenlp_dir, f))
27
28rdrsegmenter = py_vncorenlp.VnCoreNLP(annotators=["wseg"], save_dir=vncorenlp_dir)
29user_dict = {"a", "giao"} # Custom lexicon to prevent incorrect compounding
30
31def predict_food_order(raw_text):
32 print(f"\nInput: {raw_text}")
33
34 # Preprocessing & Text Cleaning
35 clean_text = re.sub(r'([.,()!?:+])', r' \1 ', raw_text.replace('_', ' '))
36 clean_text = re.sub(r'\s+', ' ', clean_text).strip()
37
38 # Word Segmentation
39 tokens = []
40 for token in rdrsegmenter.word_segment(clean_text)[0].split():
41 parts = token.split('_')
42 if any(p.lower() in user_dict for p in parts):
43 tokens.extend(parts)
44 else:
45 tokens.append(token)
46
47 # Tokenization & Subword Alignment
48 input_ids = [tokenizer.cls_token_id]
49 word_ids = [None]
50
51 for i, word in enumerate(tokens):
52 sub_ids = tokenizer.encode(word, add_special_tokens=False)
53 input_ids.extend(sub_ids)
54 word_ids.extend([i] * len(sub_ids))
55
56 input_ids.append(tokenizer.sep_token_id)
57 word_ids.append(None)
58
59 # Forward Pass / Inference
60 inputs = torch.tensor([input_ids]).to(device)
61 with torch.no_grad():
62 logits = model(inputs).logits
63 preds = logits.argmax(dim=-1)[0].tolist()
64
65 # Display Extracted Entities
66 prev_idx = None
67 for i, idx in enumerate(word_ids):
68 if idx is not None and idx != prev_idx:
69 tag_id = preds[i]
70 label = model.config.id2label.get(tag_id, "O")
71 print(f"{tokens[idx]:<20} {label}")
72 prev_idx = idx
73
74# --- EXECUTE TEST CASES ---
75test_cases = [
76 "1p cải xào, gà lát chiên giòn, chả giò, cơm thêm, Start Cf, 0384293xxx, giao lúc 12h15 ạ",
77 "em 1p sườn ngào, bầu xào, chả giò, rau củ kho + cơm thêm. giao rào b4, 11h30. 0773570xxx.",
78 "1p 15k thập cẩm ( cơm thêm) giao rào D6 0585115xxx ạ"
79]
80
81for sample in test_cases:
82 predict_food_order(sample)
83cơm_sườn).tokenizer.encode() will break word boundaries and significantly degrade NER accuracy. The example code above handles this pipeline automatically using py_vncorenlp.1@misc{cs221_food_order_ner,
2 author = {Vo Thanh Loc and Nguyen Anh Nguyen},
3 title = {Food Order Extraction: Vietnamese NER using PhoBERT},
4 year = {2026},
5 publisher = {Hugging Face},
6 howpublished = https://huggingface.co/CS221DoAn/vietnamese_food_order_extraction
7}
8
9@inproceedings{phobert,
10 title = {{PhoBERT: Pre-trained language models for Vietnamese}},
11 author = {Dat Quoc Nguyen and Anh Tuan Nguyen},
12 booktitle = {Findings of the Association for Computational Linguistics: EMNLP 2020},
13 year = {2020},
14 pages = {1037--1042}
15}