Featured image of post Nếu kết quả giống nhau, trả về bất kỳ kết quả nào - game bài đổi thưởng tặng quà khởi nghiệp

Nếu kết quả giống nhau, trả về bất kỳ kết quả nào - game bài đổi thưởng tặng quà khởi nghiệp

Hãy tham gia ngay để nhận những phần thưởng hấp dẫn từ trò chơi bài đổi thưởng tặng quà khởi nghiệp.

  • Ngày 19 tháng 5 năm 2024 lúc 00:13:48
  • Từ góc độ của các mô hình lớn hiện nay, việc phân từ đã không còn thực sự cần thiết nữa. Tuy nhiên, từ góc độ học tập, có thể xem xét lại bài viết này để hiểu rõ hơn.

Bối cảnh

Tuần trước, trong một cuộc trò chuyện với một bạn cùng lớp về tính cần thiết của thuật toán phân từ trong thời đại học sâu (deep learning), tôi đã suy nghĩ thêm về vấn đề này. Đúng vậy, sunvip.club nhờ sự phát triển mạnh mẽ của học sâu và khả năng tính toán ngày càng tăng của máy móc, các mô hình cấp ký tự đang dần chiếm ưu thế. Hiệu quả của các mô hình cấp ký tự thậm chí đã vượt qua các mô hình cấp từ [1], và trong nghiên cứu tiên tiến về xử lý ngôn ngữ tự nhiên, nhiều người đã bắt đầu cân nhắc việc từ bỏ các mô hình cấp từ, đặc biệt là trong các nhiệm vụ đánh dấu chuỗi như nhận diện thực thể tên riêng. Nhưng liệu phân từ đã hoàn toàn trở nên vô ích chưa?

Câu trả lời chắc chắn là không. Hãy tưởng tượng một tình huống, nếu người dùng trên Baidu hoặc Taobao nhập một câu truy vấn (query), liệu họ sẽ sử dụng toàn bộ câu đó để tìm kiếm kết quả phù hợp ngay lập tức hay không? Điều đó dường như là không thể. Thay vào đó, câu truy vấn sẽ được phân từ, chỉnh sửa lỗi chính tả, tái cấu trúc, sau đó mới tiến hành so sánh với cơ sở dữ liệu tài liệu.

Do đó, dù trong các ứng dụng thực tế, phân từ vẫn giữ vai trò quan trọng, nhưng đây cũng là một trong những thuật toán đơn giản nhất để học NLP cơ bản. Vậy đâu là các phương pháp phân từ phổ biến hiện nay? Chúng ta có thể kể đến các thuật toán khớp tối đa theo chiều thuận và ngược, HMM, CRF, v.v. Dưới đây sẽ chủ yếu giới thiệu cách tiếp cận và thực thi mã nguồn của thuật toán khớp tối đa.

Phân từ là gì?

Có lẽ câu hỏi này không cần thiết phải đặt ra, nhưng để làm rõ mục tiêu của nhiệm vụ, chúng ta nên thảo luận qua. Giả sử chúng ta có một câu:

Tôi giai đoạn thạc sĩ nghiên cứu khoa học sinh mệnh

Phân từ có nghĩa là chia câu thành các phần nhỏ hơn dựa trên ranh giới giữa các từ:

Tôi/thạc sĩ/giai đoạn/nghiên cứu/khoa học/sinh mệnh

Một số người có thể nghĩ rằng điều này giống như cách chúng ta học “đứt câu” khi còn học tiểu học. Nhưng thực tế, mặc dù con người có thể dễ dàng thực hiện công việc này, thì đối với máy móc, nó lại là một thách thức lớn.

Thuật toán khớp tối đa dựa trên từ điển

Thuật toán khớp tối đa [2] bao gồm ba phương pháp chính: khớp tối đa theo chiều thuận, khớp tối đa theo chiều ngược và khớp hai chiều.

1. Khớp tối đa theo chiều thuận

Khớp tối đa theo chiều thuận là một phương pháp đơn giản nhưng hiệu quả. Về cơ bản, nó hoạt động bằng cách kiểm tra từng phần của câu từ trái sang phải, cố gắng tìm một đoạn dài nhất có mặt trong từ điển, sau đó cắt đoạn đó ra và lặp lại quá trình với phần còn lại của câu. Nếu ký tự đầu tiên không phải là tiền tố của bất kỳ từ nào trong từ điển, nó sẽ được coi là một từ đơn lẻ (có thể áp dụng cấu trúc cây Trie để tăng tốc độ). Cuối cùng, nếu chỉ còn lại một ký tự duy nhất, nó cũng sẽ được coi là một từ độc lập.

Ví dụ minh họa:

1
2
3
4
5
6
7
8
Bước 1: Kiểm tra cả câu “Tôi giai đoạn thạc sĩ nghiên cứu khoa học sinh mệnh” có tồn tại trong từ điển không? Không.
Bước 2: Loại bỏ từ cuối cùng, kiểm tra “Tôi giai đoạn thạc sĩ nghiên cứu khoa học sinh” có tồn tại không? Không.
Bước 3: Tiếp tục loại bỏ từ cuối cùng...
...
Bước 12: Chỉ còn lại một từ “Tôi”, tiến hành phân từ. Lặp lại với phần còn lại “giai đoạn thạc sĩ nghiên cứu khoa học sinh mệnh”.
Bước 13: Lặp lại bước 1 với phần còn lại...
...
Bước i: Kiểm tra “thạc sĩ” có tồn tại không? Có. Tiến hành phân từ và tiếp tục với phần còn lại “giai đoạn nghiên cứu khoa học sinh mệnh”.

Thực thi thuật toán:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def forward_maximum_match_segmentation(string, dictionary):
  if string == "":
    return
  for idx in range(len(string), 0, -1):
    tmp_words = string[:idx]
    remainder_str = string[idx:]
    if tmp_words in dictionary or idx == [F88 Casino Download Game Bài](/quang/14.html)  1:
      yield tmp_words
      forward_maximum_match_segmentation(
        remainder_str, dictionary)

2. Khớp tối đa theo chiều ngược

Nếu thử nghiệm thuật toán khớp chiều thuận, bạn sẽ nhận thấy rằng nó có thể dẫn đến sai sót trong một số trường hợp cụ thể. Ví dụ, với câu “nghiên cứu khoa học sinh mệnh”, thuật toán sẽ nhầm lẫn giữa “nghiên cứu sinh” và “khoa học”. Do đó, thuật toán khớp tối đa theo chiều ngược được đưa ra để giải quyết một số vấn đề tương tự.

Khác biệt chính giữa hai phương pháp là hướng di chuyển: thuật toán chiều thuận loại bỏ từ cuối cùng, trong khi thuật toán chiều ngược loại bỏ từ đầu tiên.

Thực thi thuật toán:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def backward_maximum_match_segmentation(string, dictionary):
  if string == "":
    return
  for idx in range(0, len(string)):
    tmp_words = string[idx:]
    remainder_str = string[:idx]
    if tmp_words in dictionary or idx == len(string) - 1:
      yield tmp_words
      backward_maximum_match_segmentation(
        remainder_str, dictionary)

3. Khớp hai chiều

Thuật toán khớp hai chiều hoạt động bằng cách áp dụng cả hai phương pháp trên: khớp chiều thuận và chiều ngược. Theo nghiên cứu [4], đối với tiếng Trung Quốc, khoảng 90% các câu có kết quả khớp giống nhau giữa hai phương pháp. Khoảng 9% trường hợp, một trong hai phương pháp đúng, và chỉ khoảng 1% trường hợp cả hai đều sai.

Để chọn kết quả cuối cùng, thuật toán sử dụng quy tắc heuristics sau:

  1. Nếu số lượng từ khác nhau, chọn kết quả có ít từ hơn.
  2. Nếu số lượng từ bằng nhau: a. Nếu kết quả giống nhau, trả về bất kỳ kết quả nào. b. Nếu khác nhau, chọn kết quả có ít từ đơn lẻ hơn.

Thực thi thuật toán:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
def bi_directional_maximum_match_segmentation(string, dictionary):
  def _count_single(res):
    cnt = 0
    for i in res:
      if len(i) == 1:
        cnt += 1
    return cnt
  fm_res = list(forward_maximum_match_segmentation(string, dictionary))
  bm_res = list(backward_maximum_match_segmentation(string, dictionary))
  if len(fm_res) > len(bm_res):
    return bm_res
  elif len(fm_res) < len(bm_res):
    return fm_res
  if fm_res == reversed(bm_res):
    return fm_res
  else:
    if _count_single(fm_res) > _count_single(bm_res):
      return bm_res
    else:
      return fm_res
Built with Hugo
Theme Stack thiết kế bởi Jimmy