1. Trang chủ
  2. » Giáo Dục - Đào Tạo

BÁO cáo NHẬP môn TRÍ TUỆ NHÂN tạo đề tài NHẬN DIỆN kí tự VIẾT TAY áp DỤNG mô HÌNH CNN

27 79 3
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 27
Dung lượng 1,33 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

* Yêu cầu: • Ảnh đầu vào là ảnh chụp kí tự cần nhận diện, rõ nét, không bị khuyết thiếu • Ứng dụng đưa ra kết quả với độ chính xác cao, nhanh chóng, ít lỗi • Sử dụng mạng noron * Ứng dụn

Trang 1

TRƯỜNG ĐẠI HỌC BÁCH KHOA HÀ NỘI VIỆN CÔNG NGHỆ THÔNG TIN & TRUYỀN THÔNG

**********

BÁO CÁO NHẬP MÔN TRÍ TUỆ NHÂN TẠO

ĐỀ TÀI : NHẬN DIỆN KÍ TỰ VIẾT TAY

ÁP DỤNG MÔ HÌNH CNN

Trang 2

Mục lục

Mục lục 1

I Giới thiệu đề tài 2

II Mô tả bài toán 2

III Cơ sở lý thuyết và phương pháp giải quyết 3

1 Cơ sở lý thuyết 3

1.1 Mạng noron và giải thuật lan truyền ngược 3

1.2 Mô hình CNN 6

1.3 Xử lý ảnh 9

2 Phương pháp giải quyết 10

2.1 Chuẩn bị dữ liệu huấn luyện 10

2.2 Xử lí ảnh và trích chọn đặc trưng 10

2.3 Mô hình mạng CNN 12

2.4 Đánh giá mô hình 17

IV Xây dựng ứng dụng nhận dạng 19

V Đề xuất phát triển 21

Mã nguồn và tài liệu tham khảo 22

Trang 3

I Giới thiệu đề tài

Hiện nay, thông tin, tri thức được chuyển thành dữ liệu lưu trữ trên các thiết bị như máy tính, laptop, hay trên các nền tảng trực tuyến Đối với những dữ liệu mới, việc đưa dữ liệu vào kho lưu trữ có thể thực hiện rất dễ dàng bằng cách nhập trực tiếp Tuy nhiên, có rất nhiều tài liệu

cũ được viết bằng tay cần được lưu trữ vào máy mà việc nhập trục tiếp gây tốn thời gian và không hiệu quả

Bài toán nhận dạng chữ viết tay được đặt ra để giải quyết vấn đề này Bài toán đã được nghiên cứu rất nhiều và đạt được kết quả đáng kể với nhiều phương pháp khác nhau Trong đó, phương pháp sử dụng mạng noron tích chập được sử dụng khá phổ biến và đem lại hiệu quả tốt

Do đó, nhóm em đã chọn đề tài: “ Nhận diện kí tự viết tay áp dụng mô hình CNN “ để tìm hiểu

và xây dựng được một mô hình giải quyết bài toán

III Mô tả bài toán

Tên đề tài: Nhận diện kí tự viết tay áp dụng mô hình CNN

* Mục đích: Nhận diện kí tự viết tay (số và chữ Latin), từ ảnh đầu chụp đầu vào đưa ra kết quả là

kí tự dưới dạng UNICODE

* Yêu cầu:

• Ảnh đầu vào là ảnh chụp kí tự cần nhận diện, rõ nét, không bị khuyết thiếu

• Ứng dụng đưa ra kết quả với độ chính xác cao, nhanh chóng, ít lỗi

• Sử dụng mạng noron

* Ứng dụng: Kết quả bài toán có thể ứng dụng trong nhận diện biển số xe, chấm bài thi trắc nghiệm,…

Trang 4

IV Cơ sở lý thuyết và phương pháp giải quyết

Trong phần này chúng em xin trình bày qua về những kiến thức mà chúng em đã áp dụng vào

để hoàn thành project này Trong đó bao gồm các kiến thức về mạng nơ-ron nhiều lớp, thuật toánlan truyền ngược, mô hình mạng tích chập Và phương pháp giải quyết bài toán được áp dụng bao gồm phương pháp xử lý ảnh và xây dựng mô hình nhận diện

1 Cơ sở lý thuyết

1.1 Mạng noron và giải thuật lan truyền ngược

Ý tưởng của mạng nơ-ron

Một mạng nơ-ron đơn giản có cấu trúc như sau:

Cấu tạo của một mạng nơ ron bao gồm:

- Các node: mỗi node thực hiện một các phép tính toán

- Các kết nối: thực hiện việc truyền tín hiệu từ node này đến node khác Thông tin của mỗi kết nối là một trọng số (weight) để chỉ ra mức độ tín hiệu mạnhhay yếu

Dữ liệu đầu vào sẽ đi qua các lớp và mạng sẽ tính toán để cho ra đầu ra phù hợp

Hình 1: Kiến trúc một mạng nơ-ron đơn giản.

Nguồn: < https://mlfromscratch.com/neural-networks-explained/#/ >

Mạng nơ-ron nhiều lớp

Trong thực tế áp dụng, người ta thường dùng mạng nơ-ron bao gồm nhiều lớp kề

nhau.Các node giữa hai lớp kề nhau sẽ liên kết với nhau Đầu ra của lớp trước sẽ trở thành đầu vào của lớp kế tiếp Những lớp ở giữa của mạng (tức là trừ input và output) được gọi chung là các hidden layers

Trang 6

Hình 2: Cấu trúc mạng nơ-ron nhiều lớp.

Nguồn: Natural Language In Action.Hobson Lane, Cole Howard, Hannes Max Hapke (2019)

Trang 7

Hàm kích hoạt

Hoạt động tính toán tại mỗi node được minh họa thông qua một mô hình đơn giản

Perceptron dưới đây:

Từ sơ đồ Hình 3, ta có:

-Đầu vào là vector x gồm n chiều x = [1, x1, x2, …, xn] Đầu ra là nhãn 0 hoặc 1

-Vector trọng số w = [w0, w1, w2, …, wn] Mỗi thuộc tính của đầu vào xi sẽ được gắn với một kết nối đặc trưng bởi trọng số wi

Hình 3: Mô hình Perceptron.

Nguồn: Natural Language In Action Hobson Lane, Cole Howard, Hannes Max Hapke (2019)

Mỗi node sẽ thực hiện tính toán wxT Sau đó tích vô hướng này được đưa vào hàm kích hoạt f(x) Hàm kích hoạt ở đây sẽ biến wxTvề dạng 0 hoặc 1

f(x) = 1 nếu wxT > t

0 nếu wxT <= t

Hàm kích hoạt phải là hàm phi tuyến và khả vi Do là hàm phi tuyến nên nó giúp mạng nơ-ron cókhả năng mô hình hóa quan hệ phi tuyến giữa input và output Hơn nữa, do là hàm khả vi nên nó cho phép thực hiện đạo hàm từng phần hàm mất mát theo các trọng số

Thuật toán lan truyền ngược

Mạng nơ-ron hoạt động dựa trên 2 thuật toán lan truyền: lan truyền ngược và lan truyền tiến

- Thuật toán lan truyền tiến (Propagation): thực hiện truyền input dọc theo mạng, tính toán đầu

ra (theo chiều xuôi từ input đến output)

Trang 8

- Thuật toán lan truyền ngược (Backpropagation): thực hiện tính toán mức độ đóng góp vào hàm mất mát của mỗi trọng số ở từng lớp để cập nhật nó Trong đó, kết quả tính được của lớpsau được dùng làm cơ sở tính toán cho lớp trước (chiều ngược với lan truyền tiến).

Thuật toán lan truyền ngược đóng vai trò tạo nên sức mạnh cho mạng nơ-ron vì khả năng cậpnhật trọng số và bias dựa vào đầu ra output (như các mô hình học máy khác) Dưới đây là phần mô tả toán học của thuật toán

* Một số biểu diễn dùng trong bài toán:

Lan truyền ngược cho phép mô hình mạng có thể cập nhật w và b để giảm giá trị của hàm C

Để xem ảnh hưởng của trọng số tới C, ta tính đạo hàm của C theo w:

Ta thấy đạo hàm hàm mất mát theo trọng số của lớp l: ∂C

∂ w(l) chỉ tính toán trực tiếp được khi

l = L (l: lớp cuối cùng) Do đó, để cập nhật trọng số và bias của toàn mạng, ta phải tính toán đạo hàm từ cuối trở về đầu, lấy đạo hàm riêng đã tính ở lớp sau làm cơ sở tính toán đạo hàm của lớp trước đó

Như vậy, hoạt động cơ bản của mạng nơ-ron là như sau:

- Thực hiện lan truyền tiến ra được output

Trang 9

- Từ output tính toán hàm mất mát

- Tính đạo hàm của hàm mất mát theo thuật lan truyền ngược để cập nhật trọng số và bias

Trang 10

Hình 4 Mô hình điển hình của mạng tích chập

Nguồn: CS231n: Convolutional Neural Networks for Visual Recognition | Spring 2020

Mạng tích chập thường có 2 phần:

- Các lớp đầu tiên thường là kết hợp của nhiều Convolutional Layer và Pooling Layer Chức

năng của phần này là trích chọn đặc trưng của đầu vào

- Phần sau của mạng thường là các lớp kết nối toàn phần (Fully Connected Layer) làm nhiệm

vụ chuyển các đặc trưng học được sang thông số để phân loại

Các lớp thường sử dụng trong mạng tích chập

- Convolutional layer (Conv Layer)

Tham số cần học: các bộ lọc Mỗi bộ lọc sẽ trích ra 1 đặc trưng của ảnh như cạnh, đường

thay đổi màu sắc,…

Việc tính toán ở Conv Layer được thực hiện như sau:

Trọng số của lớp này là tập các bộ lọc Tập này là một ma trận trọng số (kernel) có kích thước dài-rộng nhỏ hơn ảnh đầu vào và có độ sâu bằng với ảnh Kernel sẽ dịch trên toàn bộảnh, tại mỗi bước dịch nó sẽ thực hiện nhân tích vô hướng với phần ảnh tương ứng

Hình 5:.Hoạt động của Conv

Layer

Trang 11

Từ Hình 5 ta thấy output của Conv Layer có kích thước dài-rộng khác với của input (nó

bị thu nhỏ lại) Do khi dịch bộ lọc, số lần bộ lọc nhân với các phần tử ở biên ít hơn so với phần tử ở giữa ảnh Do đó, nếu như trong ảnh có những đặc trưng quan trọng ở biên thì nó sẽ

rất dễ bị bỏ qua Vậy nên, trong Conv Layer người ta áp dụng kỹ thuật zero-padding, tức là

bọc ma trận input bằng các phần tử 0 Kỹ thuật này giúp tất cả các phần tử trong ảnh sẽ có đóng góp như nhau vào mô hình Hơn nữa, nó cũng giúp kiểm soát kích thước của đầu ra, đảm bảo kích thước dài-rộng của output bằng với input

Conv Layer thường được sử dụng kết hợp với một hàm kích hoạt Hàm này có chức năng là làm gia tăng độ chênh lệch giữa các giá trị đầu ra của Conv Layer Những giá trị bé

sẽ được loại bớt từ đó những giá trị lớn của mô hình sẽ được kích hoạt Các hàm kích hoạt

thường được dùng là: Leaky ReLU, ReLU, tanh, sigmoid,…

Ưu điểm của Conv Layer so với việc kết nối toàn bộ trong Neural Network đó là:

 Số lượng tham số = số phần tử của bộ lọc +1 (Nhỏ hơn so với NN)

 Do bộ tham số cho mỗi node như nhau nên đặc trưng nên Conv có thể trích được các đặc trưng giống nhau ở vị trí khác nhau

- Pooling Layer:

Trong mô hình CNN, giữa các Conv Layer kế tiếp nhau thường là 1 lớp Pooling Layer

Hoạt động như sau:

Trang 12

Hình 6.Hoạt động của MaxPooling Layer

Nguồn: CS231n: Convolutional Neural Networks for Visual Recognition | Spring 2020

Tham số cần chỉ rõ đó là kích thước của sổ để thực hiện phép lấy max và độ dài bước dịch chuyển

Chức năng của lớp này là giúp giảm kích thước dữ liệu khi nó đi dọc mạng Giảm kích thước dữ liệu đồng nghĩa với việc giảm số lượng tham số và công việc tính toán của mô hình,

từ đó kiểm soát được tình trạng overfitting.Ngoài ra, Pooling có chức năng giúp việc dự đoán

của mô hình gần như không đổi khi đầu vào bị thay đổi bởi các phép biến đổi nhỏ

Trong các loại pooling, Max Pooling được sử dụng phổ biến nhất do nó trích xuất các đặc trưng là các viền/rìa của ảnh Ngoài Max Pooling, còn có các kiểu pooling khác như Average Pooling hay L2-norm Pooling

Trang 13

- Batch Normalization:

Lớp này sẽ giúp chuẩn hóa kết quả đầu ra của Conv Layer Lớp này hoạt động như sau:

Hình 7.Hoạt động của BatchNormalization

Nguồn: Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift

Sergey Ioffe, Christian Szegedy(2015)

Lớp này sẽ thực hiện normalize bằng cách trừ đầu vào với kỳ vọng sau đó chia nó cho

phương sai Điều này sẽ khiến cho ^xituân theo phân phối Gaussian Tuy nhiên vì sau khi

thực hiện normalize, ta được μ β=0, σ β=1 nên nếu chỉ biến đổi như vậy thì các bước tiếp

theo hầu như ^xihầu như không thay đổi so với x i Do đó ta cần thực hiện thêm bước biến đổi cuối cùng để thay đổi phương sai và kỳ vọng của dữ liệu trong minibatch

Việc sử dụng BatchNormalization có ưu điểm đó là, khi mô hình thực hiện lan truyền

ngược, việc cập nhật trọng số của các lớp trước sẽ không ảnh hưởng nhiều đến kết quả của

lớp thực hiện Batch Normalization và từ đó cũng không ảnh hưởng nhiều đến việc cập nhật

trọng số của các lớp phía sau Do vậy, mô hình không phải cập nhật quá nhiều lần, kết quả

train qua mỗi epoch ổn định hơn

- Fully Connected Layer (FC Layer):

Sau khi đi qua các Conv Layers, Pooling Layers để trích chọn đặc trưng, dữ liệu sẽ được truyền vào FC Layer để lấy ra giá trị làm cơ sở để phân loại Trước khi cho vào FC Layer, dữ liệu sẽ được duỗi thẳng thành vector 1 chiều Sau đó, ở FC Layer thực hiện nhân tích vô hướng của vector đầu vào với vector trọng số Do là kết nối toàn phần nên FC Layer

là lớp chứa nhiều trọng số nhất của mô hình

Chức năng của lớp này là tổng hợp các đặc trưng đã được trích trọn ở các lớp trước đó để

tính toán dự đoán Thường ở cuối các mô hình CNN sẽ có một hoặc nhiều lớp Dense Việc xếp nhiều lớp Dense như vậy cuối mô hình sẽ giúp mô hình hóa được các quan hệ phức tạp

giữa đặc trưng và nhãn thực tế của dữ liệu

Trang 14

Dropout có chức năng là loại bỏ kết nỗi giữa 2 layer kế tiếp nhau theo một xác suất xác định Trong CNN, Dropout thường được sử dụng ở giữa các FC Layers Tham số cần chỉ rõ

đó là xác suất loại bỏ Giá trị này thường được đặt là 0.5 khi đặt giữa các FC Layers

Chức năng của Dropout là giúp mô hình giảm khả năng bị overfitting Đồng thời huấn

luyện một mô hình sử dụng Dropout nhiều lần sẽ cho ra kết quả mỗi lần khác nhau, điều này

cũng giống như việc thử nghiệm nhiều mô hình

Khi xử lí thông tin trên ảnh, để tiện cho quá trình xử lí dữ liệu, sẽ dễ dàng hơn nhiều khi ta chỉ

xử lí dữ liệu trên 1 ma trận số thay vì nhiều ma trận => chuyển đổi ảnh màu về ảnh xám

(grayscale converting)

Tương tự như ảnh màu, ảnh xám cũng có kích thước 800 pixel * 600 pixel, có thể biểu diễn dưới dạng một ma trận kích thước 600 * 800 (số hàng*số cột) Tuy nhiên mỗi pixel trong ảnh xám biểu diễn chỉ cần 1 giá trị nguyên trong khoảng [0;255] thay vì (r,g,b) như trong ảnh màu.

Giá trị 0 là màu đen, 255 là màu trắng và giá trị pixel càng gần 0 thì càng tối và càng gần 255thì càng sáng

- Để giữ lại các chi tiết chính và loại bỏ các chi tiết thừa trên ảnh =>biến đổi ảnh về dạng

nhị phân – đen trắng (binary).

- Ảnh đen trắng là ảnh biểu diễn bởi 1 ma trận 2 chiều, trong đó các phần tử của của ma trận chỉ có 2 giá trị là 0 – màu đen và 255 – màu trắng

- Để chuyển ảnh sang dạng nhị phân ta chọn một ngưỡng (threshold) để xác định đâu là

điểm ảnh đen và đâu là điểm ảnh trắng Nếu giá trị trên ảnh xám lớn hơn ngưỡng

threshold, đấy là điểm ảnh trắng và ngược lại.

Gọi ảnh xám là Gray, ảnh đen trắng cần xác định là BW, tọa độ các pixel trên hình là (x,y), ta có

- BW(x,y) = 255 nếu Gray(x,y) => threshold

- BW(x,y) = 0 nếu Gray(x,y) <= threshold

Trang 15

2 Phương pháp giải quyết

Bộ dữ liệu mà em sử dụng đó là bộ EMNIST trong đó chúng em chia nó ra như sau:

Tập train: (90240, 28, 28, 1) Để huấn luyện

Tập validation : (22560, 28, 28, 1) Để chọn mô hình

Tập test : (18800, 28, 28, 1) Để đánh giá mô hình đã chọn

Nhãn đầu ra bao gồm 47 nhãn bao gồm các ký tự sau:

0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabdefghnqrt

Ở đây chúng em gộp các ký tự có cách viết hoa và viết thường giống nhau vào thành 1 nhãn (VD: chữ o và O; chữ m và chữ M;…)

Bộ dữ liệu sử dụng cho quá trình train model là bộ dữ liệu EMNIST Các bức ảnh trong

bộ dữ liệu EMNIST là ảnh đen trắng (1 chanel), có kích thước 28x28 pixel (tổng cộng 784

pixel) Mỗi pixel mang một giá trị là một số tự nhiên từ 0 đến 255 Các pixel màu đen có giá trị bằng 0, các pixel càng trắng thì có giá trị càng cao (nhưng không quá 255)

=> Mục tiêu: Ảnh đầu vào của ứng dụng là ảnh kĩ thuật số (digital image), sau quá trình xử lí

ảnh, ảnh sẽ có dạng giống dạng ảnh trong EMNIST để tăng tối đa tính tương đồng về độ phân giải, cường độ màu sắc => tăng độ chính xác cho dự đoán

Để thực hiện việc này chúng em sử dụng thư viện cv2 và numpy của Python để thực hiện các

bước xử lý

Các bước xử lí ảnh và trích chọn đặc trưng:

- Ảnh load được từ thiết bị:

- Chuyển ảnh từ ảnh màu qua ảnh xám

Trang 16

- Làm sắc nét ảnh, loại bỏ các thành phần tần số cao như nhiễu hay làm trơn ảnh, chuyển ảnh về dạng binary dạng nền đen chữ trắng

Trang 17

Conv: có sử dụng zero padding,

kernel: 32x3x3, stride = 1, activationfunction: ReLU

Max Pooling: kích thước cửa sổ:

Trang 18

- Lựa chọn số cặp (Conv-Maxpooling):

Trang 19

- Lựa chọn hàm kích hoạt:

Ở đây chúng em có xét 3 hàm kích hoạt ReLU, LeakyReLU, tanh Do mỗi hàm có ưu

nhược điểm riêng nên chúng em chọn cách thử nghiệm để chọn hàm cho kết quả tốt hơn Ở

trên cho thấy, hàm ReLU cho kết quả tốt hơn (xấp xỉ hơn hàm LeakyReLU và cao hơn hẳn hàm tanh) Hàm ReLU có công thức như sau:

f(x) = max(0, x)

Hình 8: Hàm ReLU

Nguồn: https://www.mygreatlearning.com/blog/relu-activation-function/

Ưu điểm của ReLU đó là tính toán nhanh hơn các hàm kích hoạt khác Hơn nữa, ReLU

biến đầu ra của lớp sử dụng nó thành vector có nhiều phần tử bằng 0 (thưa) Điều này giúp

mô hình giảm khả năng overfitting và loại bỏ được nhiễu Và ReLU không gây ra hiện tượng

mất gradient (vanishing gradient problem) như hàm sigmoid và tanh do nó không thu hẹp

khoảng giá trị của đầu vào

Trang 20

Tuy nhiên, hàm ReLU cũng có những hạn chế như là bùng nổ gradient Nó khiến mô

hình phải cập nhật trọng số đáng kể sau mỗi lần lan truyền ngược Điều này khiến mô hình

mất đi tính ổn định Ngoài ra, mô hình sử dụng ReLU có thể gặp phải tình trạng chết Một nút

sẽ bị mất hoàn toàn tác dụng khi đầu ra của nó là âm LeakyReLU khắc phục điều này tuy nhiên khi thử nghiệm thấy ReLU cho kết quả tốt hơn

Ngày đăng: 27/10/2022, 05:46

Nguồn tham khảo

Tài liệu tham khảo Loại Chi tiết
[1]Lý thuyết về Convolutional Layer, Max Pooling Layer: Fei-Fei Li(2020). CS231n: Convolutional Neural Networks for Visual Recognition | Spring 2020 | Convolutional Neural Networks (CNNs / ConvNets), [Online Course] Standford University Sách, tạp chí
Tiêu đề: CS231n: "Convolutional Neural Networks for Visual Recognition | Spring 2020 | Convolutional Neural Networks (CNNs / ConvNets)
Tác giả: Lý thuyết về Convolutional Layer, Max Pooling Layer: Fei-Fei Li
Năm: 2020
[2]Lý thuyết về Batch Normalization Layer: Sergey Ioffe, Christian Szegedy(2015). Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift [Paper]. Retrieved from: https://arxiv.org/abs/1502.03167 Sách, tạp chí
Tiêu đề: Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift
Tác giả: Lý thuyết về Batch Normalization Layer: Sergey Ioffe, Christian Szegedy
Năm: 2015
[3] Lý thuyết về thuật toán Adam: Diederik P. Kingma, Jimmy Ba(2015). Adam: A Method for Stochastic Optimization [Paper]. Retrieved from https://arxiv.org/abs/1412.6980 Sách, tạp chí
Tiêu đề: Adam: A Method forStochastic Optimization
Tác giả: Lý thuyết về thuật toán Adam: Diederik P. Kingma, Jimmy Ba
Năm: 2015
[4] Lý thuyết về thuật toán lan truyền ngược: Casper Hansen (2019). Neural Networks: Feedforward and Backpropagation Explained &amp; Optimization [Blog post]. Retrieved from https://mlfromscratch.com/neural-networks-explained/#/ Sách, tạp chí
Tiêu đề: Neural Networks: "Feedforward and Backpropagation Explained & Optimization
Tác giả: Lý thuyết về thuật toán lan truyền ngược: Casper Hansen
Năm: 2019
[5] Cách thức thử nghiệm mô hình: Chris Deotte (2019). How to choose CNN Architecture MNIST. [Online]. Retrieved from https://www.kaggle.com/cdeotte/how-to-choose-cnn-architecture-mnist Sách, tạp chí
Tiêu đề: How to choose CNN Architecture MNIST
Tác giả: Cách thức thử nghiệm mô hình: Chris Deotte
Năm: 2019
[6] Bộ dữ liệu EMNIST: Chris Crawford(2017). EMNIST (Extended MNIST). [Online]. Retrieved from https://www.kaggle.com/crawford/emnist Sách, tạp chí
Tiêu đề: EMNIST (Extended MNIST)
Tác giả: Bộ dữ liệu EMNIST: Chris Crawford
Năm: 2017

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

🧩 Sản phẩm bạn có thể quan tâm

w