Song song với các từ điển, nguồn ngữ liệu mà chương trình sử dụng cũng rất phong phú. Việc cấu trúc chúng và lưu trữ, nếu được thực hiện khéo, vừa tiết kiệm không gian bộ nhớ, vừa nâng cao tốc độ xử lý cho chương trình.
Các nguồn ngữ liệu, như đã trình bày ở các mục trước, bao gồm: Tập mẫu thô, Tập mẫu sau huấn luyện (hay tập đồ thị), Tập các liên kết Anh-Việt thực hiện cho các cặp câu tương ứng trong Tập mẫu thô, và Tập luật chuyển đổi cú pháp.
Đối với Tập mẫu thô, cấu trúc file lưu trữ rất đơn giản, cụ thể như sau:
*<Câu Tiếng Anh>
+<Câu Tiếng Việt>
Còn đối với các file: đồ thị, liên kết Anh-Việt và luật chuyển đổi cú pháp, các file lưu trữ tương ứng đều là 1 dãy liên tiếp các khối (block). Mỗi block là một đối tượng thuộc lớp được xây dựng cho mỗi thành phần (Chẳng hạn, trong file đồ thị, mỗi block là một đối tượng thuộc lớp graphClass; trong file liên kết Anh-Việt và luật chuyển đổi cú pháp thì sẽ tương ứng là: SentenceAlign và TransferRule).
Block_1 Block_2 … Block_n
Bảng 4. 6: Cấu trúc tổng quát của các file ngữ liệu: Đồ thị, Liên kết Anh-Việt và Luật chuyển đổi cú pháp.
Việc lưu trữ và truy xuất các file trên được C# hỗ trợ rất đắc lực, với các
phương thức Serialize và Deserialize (lớp BinaryFormatter) lần lượt cho phép ghi
vào và đọc ra cả một object (ở file nhị phân).
Mặc dù các file trên đều là các file truy nhập tuần tự (sequential-access file) nhưng trong chương trình của chúng ta, việc truy nhập đến các block cụ thể đều là truy nhập theo chỉ số. Bởi vì thực chất tẩt cả các file này đều chỉ được truy cập (cụ thể là đọc) một lần khi bắt đầu chương trình. Các block được đọc ra và lưu vào cấu trúc dữ liệu dạng key-value (còn gọi là dạng Từ điển, được hỗ trợ rất mạnh trong C#). Lúc này, việc truy nhập đến các thành phần cụ thể được tiến hành thông qua index là key. Bảng dưới đây liệt kê key cụ thể cho từng thành phần:
STT Loại block Key
1 Đồ thị Số content word, functional word. 2 Liên kết Anh-Việt Câu Tiếng Anh
3 Luật chuyển đổi Khung luật+Loại ngữ (Danh ngữ, Động ngữ…)
Bảng 4. 7: Truy nhập các file ngữ liệu thông qua key. 4.3. Cài đặt các module chính trong chương trình
4.3.1. Một số nét tổng quan về chương trình:
Tên chương trình: EBMTrans
Chức năng chính: Dịch tự động Anh-Việt
Ngôn ngữ lập trình C#.NET
Môi trường phát triển: Visual Studio.NET 2005
Hệ điều hành Windows
Bảng 4. 8: Các nét tổng quan của chương trình.
Hiện nay, chưa bao giờ việc phát triển phần mềm lại được hỗ trợ đắc lực bởi nhiều công cụ mạnh đến như vậy.Trong số những công nghệ đi đầu hiện nay như JAVA, .NET, tác giả đã chọn ngôn ngữ lập trình C# trên môi trường Visual Studio .NET 2005 để cài đặt và kiểm thử cho chương trình của mình. Sở dĩ như vậy là vì những lý do sau:
Đây là công cụ cho phép xây dựng ứng dụng một cách nhanh chóng, thuận
tiện (theo cơ chế gắp-thả, doubleclick-viết code…) với giao diện rất thân thuộc và trực quan (hệ thống WinForm, WebForm). Với chức năng này, nếu sử dụng các công cụ khác sẽ tốn nhiều thời gian và công sức hơn.
VS .NET cho phép quản lý việc xuất/nhập file dữ liệu được chính xác, nhanh gọn thông qua tính năng giao tiếp file mạnh.
Đây là ngôn ngữ có khả năng xử lý các cơ sở dữ liệu phẳng của bài toán một
cách nhanh chóng, trên một khối lượng lớn. Những cấu trúc dữ liệu có sẵn của C# được tác giả khai thác nhiều trong quá trình cài đặt như: ArrayList,
List<>, DictionaryBase…bởi chúng cung cấp một cơ chế tìm kiếm và truy
xuất phần tử rất linh hoạt.
4.3.2. Cài đặt module: “Huấn luyện tập mẫu”
Như đã trình bày ở trên, module này gồm có 3 pha: Phân tích cú pháp, xây dựng lớp và xây dựng đồ thị. Ở pha đầu tiên, tác giả sử dụng hàm phân tích cú pháp
có sẵn trong thư viện OpenNLP.Tools.Parser:
Tên phương thức Kiểu trả về Chức năng
ParseSentence( str ing sentence)
Parse Trả về cây cú pháp cho đầu vào : sentence
Tiếp theo, pha xây dựng lớp được cài đặt thông qua lớp sentenceClass và một phương thức để bổ sung 1 đối tượng sentenceClass vào danh sách các lớp như vậy thông qua tiêu chí là số contentword, functionalword trong mỗi thành viên:
Tên thuộc tính/ phương thức Kiểu thuộc tính / Giá trị trả về của phương thức. Mô tả
contWordNumber int Số lượng contentword của mỗi thành viên
functWordNumber int Số lượng functional word của mỗi tv parsedSentenceLst List<string> Danh sách các thành viên
Bảng 4. 9: Cài đặt lớp sentenceClass.
(Các phương thức cài đặt trong lớp này rất đơn giản, chỉ là các phương thức thực hiện chức năng get và set giá trị cho các thuộc tính.Vì vậy, tác giả không liệt kê ở đây)
Tên phương thức Kiểu trả về Chức năng
enrichSentenceLst( List<sentenceClass>
sentenceClassLst, string sentence)
List<sentenceClass> Thêm một đối tượng sentenceClass vào tập các lớp.
Pha xây dựng đồ thị, là giai đoạn cuối cùng và cũng là quan trọng nhất chuẩn bị cho quá trình so khớp sau này. Nhiệm vụ của nó, như đã trình bày, là đồ thị hoá mỗi lớp câu. Bản chất của pha xây dựng đồ thị là: Xây dựng và cực tiểu hoá Otomat đoán nhận lớp ngôn ngữ là lớp câu cần đồ thị hoá. Vì vậy, lớp đầu tiên cần cài đặt, đó chính là lớp Otomata:
Tên thuộc tính / phương thức
Kiểu thuộc tính / Giá trị trả về của
phương thức.
Mô tả
states List<State> Tập trạng thái. getStateFromName(int
name)
State Lấy về một trạng thái từ tên của nó.
getNextStateFromState( i nt i, string input)
int Hàm chuyển trạng thái: Trả về tên trạng thái tiếp theo, suy diễn trực tiếp từ trạng thái i, xâu vào là input.
getDestStateFromSource State(int i, string[] input)
int Hàm chuyển trạng thái mở rộng: Trả về tên trạng thái mà: Otomat nếu đang ở trạng thái i, đoán nhận lần lượt tất cả các xâu thành phần trong input, sẽ chuyển đến nó.
checkConfluence(State s) bool Kiểm tra xem trạng thái s có phải là trạng thái có nhiều “đầu ra” hay không ?
(Trong đó: State là một lớp được xây dựng để biểu diễn 1 trạng thái trong Otomat)
Bảng 4. 10: Cài đặt lớp Automata
Sau khi đã có lớp Automata, chúng ta tiến hành cài đặt lớp chính phục vụ chức năng xây dựng đồ thị cho mỗi lớp câu đầu vào, đó chính là lớp
MAFSAConstructor (bộ xây dựng Otomat trạng thái hữu hạn không chu trình cực
tiểu). Lớp này gồm nhiều phương thức phụ, phục vụ cho việc cài đặt phương thức
chính làconstructMAFSA()
Tên thuộc tính/ phương
thức Giá trị trả về của Kiểu thuộc tính / Mô tả
phương thức.
automat Automata Biến chứa Otomat cực tiểu cần xây
dựng.
isEquivalent(State q1,
State q2) bool Hàm kiểm tra xem hai trạng thái q1 và q2 có phải là tương đương hay không?
cloneState(State q) void Phương thức này thực hiện việc taạo ra
môột trạng thái “bắt chước” trạng thái q và bổ sung vào tập trạng thái của Otomat.
add_Suffix(State
beginState,string[] suffix)
void Bổ sung thêm trạng thái để Otomat đoán nhận mảng các xâu (thực chất là phần hậu tố của mỗi câu trong lớp), bắt đầu từ trạng thái beginState.
replace_or_register( Sta te state, string symbol)
void Kiểm tra xem trạng thái suy diễn từ state, đầu vào symbol có tương đương với bất kỳ trạng thái nào có sẵn trong Otomat hay chưa, từ đó quyết định thay thế nó bằng trạng thái tương đương hay bổ sung vào tập Register (tập trạng thái chưa tương đương với trạng thái nào khác)
prefixLeadsToFirstState( State firstState, string[]
commonPrefix)
string[] Trả về một dãy xâu, tiền tố của commonPrefix, sao cho từ trạng thái đầu của Otomat, thông qua dãy này sẽ suy diễn được đến firstState.
constructMAFSA() void Phương thức chính của lớp, xây dựng
MAFSA(Otomat trạng thái hữu hạn không chu trình cực tiểu).
Bảng 4. 11: Cài đặt lớp MAFSAConstructor. 4.3.3. Cài đặt module “Tiền xử lý”
Đối với văn bản đầu vào, quá trình tiền xử lý chỉ đơn giản là chuẩn hoá văn bản và tách thành từng câu riêng biệt dựa trên các ký hiệu nhận dạng kết thúc câu. Để thực hiện, chỉ cần sử dụng phương thức :
Tên phương thức Kiểu trả về Chức năng
SentenceDetect(strin
g input) string[] Thực hiện tách văn bản input thành tập các câu riêng biệt .
có sẵn trong thư viện OpenNLP.Tools.SentenceDetect.
Bây giờ chúng ta xét công đoạn tiền xử lý cho từng câu một.Các công việc là: Phân tích cú pháp, xác định số content word, functional word và khoanh vùng
tập mẫu cho nó. Chức năng này sẽ được đại diện bởi lớp PrepareForMatching sẽ
được xét cụ thể sau đây:
Tên thuộc tính/ phương thức Kiểu thuộc tính / Giá trị trả về của phương thức. Mô tả
matchedSentence string Câu đầu vào.
functionalWordNumber int Biến lưu số functional word. getContAndFunctWord
() int[] Trả về số content word và functional word của câu đầu vào (trong phương thức này có gọi đến hàm phân tích cú pháp trong thư viện OpenNLP).
getStandardSentence() List<string> Trả về dạng chuẩn hoá của câu, xuất phát từ cây cú pháp. Đây chính là câu tham gia vào quá trình so khớp.
corpusAfterNarrowed(A rrayList mycorpusList)
List<graphClass> Phương thức này để khoanh vùng tạp mẫu, tức chọn ra từ tạp mẫu một số lớp có số luợng từ, cũng như riêng số lượng content word “gần” với đầu vào theo một tỷ lệ chọn trước.
Bảng 4. 12: Cài đặt lớp PrepareForMatching. 4.3.4. Cài đặt module “Chọn ngữ liệu tương tự nhất”
Tên thuộc tính / phương thức Kiểu thuộc tính / Giá trị trả về của phương thức. Mô tả
path List<Record> Danh sách các dãy từ đã được so khớp. node State Đỉnh trên đồ thị mà quá trình so khớp
đang thực hiện đến.
input List<string> Dãy các từ trong câu đầu vào hiện còn chưa được so khớp.
trans char Là biến chỉ thị, giúp xác định xem những toán tử nào có thể tác động được lên trạng thái này.
isGoalState() bool Hàm kiểm tra xem đây có phải là trạng thái kết thúc (trạng thái đích) không? isInitialState() bool Hàm kiểm tra xem đây có phải là trạng
thái đầu không?
getStateCosts() float Lấy về giá của trạng thái (tổng các giá của các thành phần trong path).
Bảng 4. 13: Cài đặt lớp MatchingState
Tên thuộc tính /
phương thức Kiểu thuộc tính/ Giá trị trả về của phương thức.
Mô tả
input List<string> Câu đầu vào.
grphClss graphClass Lớp đồ thị chuẩn bị so khớp. getCorrespondentEdges(
MatchingState matchingState)
List<Edge> Trả về tập đỉnh có thể suy diễn trực tiếp từ trạng thái matchingState.
successor_states(Matchin gState s)
List<MatchingState> Tập trạng thái mới thu được bằng cách áp dụng tẩt cả các toán tử có thể được lên trạng thái s.
getStatesWithMinimumV alueOfEF(List<Matching State> OPEN)
List<MatchingState> Lấy về các phần tử (trạng thái) s trong tập OPEN sao cho f*(s) là cực tiểu.
isEquivalent(MatchingSta te ms1, MatchingState ms2)
bool Kiểm tra xem 2 trạng thái so khớp ms1, ms2 có phải là tương đương không?
mostValueableSentences(
) List<MatchingState> Chọn ra tập câu gần nhất (hàm chính của lớp) getUpperCost() float Hàm xây dựng chi phí cận trên.
Bảng 4. 14: Cài đặt lớp Matcher.
Bây giờ chúng ta điểm lại các bước thực hiện trong quá trình cài đặt thực tế
của phương thức chính của lớp này, phương thức: mostValueableSentences().
Trong quá trình cài đặt, tác giả tuân thủ theo đúng giải thuật so khớp đã được trình bày trong phần Cơ sở lý thuyết, tuy vậy, để tối ưu thêm về mặt thời gian xử lý, một số cải tiến và thay đổi nhỏ đã được áp dụng (Trong phần trình bày này, chúng được thể hiện ở những phần gạch chân):
Tên phương thức: mostValueableSentences()
Input: - Câu Tiếng Anh đầu vào.
- Một lớp câu dùng để so khớp (dưới dạng đồ thị).
Output: Một (hoặc một số) câu Tiếng Anh “tương tự” nhất với đầu vào (một số nếu tất cả chúng đều có chi phí so khớp là như nhau và cực tiểu), biểu diễn thông qua trạng thái so khớp đầy đủ tương ứng với nó.
Bước 1: Khởi tạo giá trị cho một số danh sách: OPEN (chứa các trạng thái còn
chưa được xét) khởi tạo bằng trạng thái ban đầu, CLOSED (chứa các trạng thái đã
xét rồi) và result (chứa trạng thái kết quả): khởi tạo rỗng, xác định chi phí cận trên
uppercost.
Bước 2: Chừng nào mà trong OPEN còn có trạng thái với giá nhỏ hơn uppercost
hoặc thời gian thực hiện giải thuật còn chưa vượt quá timeout thì thực hiện bước 2. Nếu không, nhảy sang bước 3.
o Lọc ra từ OPEN những trạng thái có cost thấp nhất để kết nạp vào
CLOSED. Tuy nhiên, nếu trong OPEN tồn tại ít nhất là một trạng thái
kết thúc, thì chọn ra trạng thái kết thúc nào có costs bé nhất để kết nạp (mặc dù đó có thể chưa phải là giá trị cost cực tiểu trong OPEN).
o Với mỗi trạng thái được lọc ra:
- Nếu là trạng thái kết thúc, so sánh chi phí của nó với chi phí
các trạng thái trong tập kết quả tạm thời result. Nếu nó là bé
hơn, xoá rỗng result đi và kết nạp nó vào. Nếu bằng, kết nạp
vào.Sau đó, quay về đầu bước 2.
- Ngược lại, xác định tập toán tử tác động được lên nó và áp
dụng từng toán tử một. Thu được một tập trạng thái mới.
o Với mỗi một trạng thái s mới được tạo ra: Nếu costs của nó < uppercost,
đồng thời:
- Không có trạng thái nào trong OPEN là tương đương với nó
cả: => kết nạp nó vào OPEN.
- Tồn tại trạng thái t tương đương với nó trong OPEN mà cost(t) > cost(s): => xoá t trong OPEN và thay s vào.
Bước 3: Kết thúc phương thức, kết quả thu được là result.
Bảng 4. 15: Cài đặt phương thức mostValueableSentences()
4.3.5. Cài đặt module “Xây dựng, hoàn thiện câu dịch”
Tên thuộc tính / phương thức Kiểu thuộc tính / Giá trị trả về của phương thức. Mô tả
finalResultSentence string Câu dịch cuối cùng..
matchingState string Trạng thái so khớp đầy đủ của câu ngữ liệu tương tự nhất vừa tìm được ở bước trên.
subtitutedSentence string Câu đầu vào.
senAlign SentenceAlign Liên kết Anh-Việt ứng với ngữ liệu tương tự nhất.
thu_tu_sau_chuyen_doi ( Parse parent)
ArrayList Thay đổi trật tự các từ trong một cụm từ Tiếng Anh khi nó được dịch sang Tiếng Việt, dựa vào các luật chuyển đổi mức cụm từ.
getFinalResult( WordTr
anslator trans) string Lấy về câu dịch cuối cùng (đây là phương thức chính được cài đặt cho lớp).
Bảng 4. 16: Cài đặt lớp Subtitutor.
Trong lớp này, tất cả các phương thức phụ đều được xây dựng nhằm phục vụ
cho phương thức chính, đó là: getFinalResult(WordTranslator trans). Về mặt cơ
sở lý thuyết cho phương thức, chúng ta đã bàn đến ở chương trước.Ở đây, tác giả
xin đề cập đến thực tế triển khai nó trong hệ thống như thế nào? Chúng ta cùng
xem xét:
Tên phương thức: string getFinalResult(WordTranslator trans) 89
Input:
Trạng thái so khớp đầy đủ ứng với câu ngữ liệu tương tự nhất mà quá trình so khớp vừa mang lại.
Liên kết Anh-Việt của nó.
Output: Câu dịch Tiếng Việt cần tìm.
Bước 1: Tạo cờ insertFlag để kiểm tra xem trong trạng thái so khớp có Insertion vào không? Nếu có, lấy về danh sách các từ đó và chuyển đến bước 2. Ngược lại, chuyển đến bước 3.
Bước 2: Với mỗi Insertion, tiến hành :
o Thông qua từ loại của nó và bộ dịch từ trans (Anh-Việt, tham số hình thức
của phương thức), lấy được nghĩa Tiếng Việt tương ứng.
o Đặt liên kết cho nó, trong đó vị trí liên kết = vị trí kiên kết lớn nhất hiện thời
trong senAlign+1. Sau đó, thêm liên kết này vào Alignment của senAlign,
sao cho chỉ số của mỗi từ trong Alignment mới sẽ bằng với vị trí của các bản
ghi tương ứng với nó trong matchingState
Sau khi đã hoàn thành xong cho tất cả Insertion, xoá tất cả các Deletion (trong cả matchingState và Alignment).Dựng cây cú pháp cho câu còn lại (là tổ hợp của các từ E,I,S).Tiếp tục xử lý lần lượt cho từng từ I như sau :
o Xác định ngữ (hoặc cụm từ) mà nó là một thành viên trong đó, bằng cách:
Lấy về cha của nó=> ngữ chính là tập hợp các từ con của cha đó.
o Từ cấu trúc ngữ pháp của ngữ, kết hợp với từ điển luật chuyển đổi
tudienluat xác định được vị trí của các từ Tiếng Việt của nó trong ngữ khi dịch sang Tiếng Việt.
Kết quả là tất cả các từ Tiếng Việt đã được đặt đúng vị trí mà chúng cần phải xuất hiện trong câu Tiếng Việt cuối cùng. Phần xử lý còn lại thực hiện giống như bước 3.
Bước 3 : Mảng result (chứa các từ trong câu dịch) được khởi tạo rỗng và các thành phần của nó được thêm dần vào thông qua việc xét từng phần tử của
senAlign.Alignment như sau :
o Nếu Alignment[i] là liên kết của một từ loại E hoặc I => result[chỉ số liên