Hàm kích hoạt
Hàm kích hoạt
Kéo một đầu vào rồi xem bốn hàm kích hoạt biến nó thành bốn đầu ra khác nhau, và bốn gradient khác nhau nữa.
Bài sigmoid và phân loại logistic đã mổ sigmoid rất sâu: ranh giới ở -b/w, bề rộng dải chuyển tiếp 2·ln(99)/|w|, chỗ nó tràn số. Bài này đứng ở chỗ khác. Nó không hỏi một hàm kích hoạt hoạt động thế nào, nó hỏi vì sao phải có một hàm kích hoạt, rồi hỏi tiếp chọn hàm nào. Và câu trả lời cho câu thứ hai gần như không nằm ở đường cong mà nằm ở đạo hàm của nó, vì đạo hàm mới là con số mà một bước huấn luyện nhân vào.
Kéo đầu vào x để xem cùng một con số cho ra bốn kết quả rất khác nhau: ReLU cắt phần âm, leaky ReLU giữ lại một chút, còn sigmoid và tanh ép vào một khoảng chặn.
Ở trạng thái mở bài, sim đang nói gì
Đầu vào mặc định là x = 1.5. Bốn ô đọc kết quả in 1.50, 0.82, 0.91 và 1.50. Hai con số bằng nhau ở hai đầu không phải trùng hợp: trên nửa dương thì ReLU và leaky ReLU là cùng một hàm, cả hai trả về đúng 1.5 không sai một bit. Kéo sang x = -1.5 thì hai hàm đó tách nhau ngay, và đó là toàn bộ khác biệt giữa chúng.
Hai ô còn lại đang che số thật. Sigmoid ở đó là 0.8175744761936437 và tanh là 0.9051482536448664; màn hình làm tròn hai chữ số nên bạn thấy 0.82 và 0.91.
Bốn gradient ở cùng đầu vào thì không hiện trên màn hình, nhưng chúng là phần đáng nhớ hơn: ReLU cho 1, leaky ReLU cho 1, sigmoid cho 0.14914645207033286, còn tanh cho 0.18070663892364858. Nghĩa là ở ngay chỗ mở bài, hai hàm bị chặn đã trả về gradient nhỏ hơn hai hàm không chặn khoảng bảy lần, dù đường cong của chúng trông vẫn còn dốc.
Thanh kéo chạy từ -6 tới 6 theo bước 0.05, tức 241 đầu vào bấm tới được. Mốc x = 0 là điểm lưới số 120, hai láng giềng của nó là -0.05 và 0.05, và mốc đó sẽ là chỗ nguy hiểm nhất của cả bài.
Vì sao phải có phi tuyến: xếp chồng tuyến tính vẫn là tuyến tính
Nếu bỏ hết hàm kích hoạt đi thì mỗi tầng chỉ còn w·x + b, và xếp bao nhiêu tầng như thế lại cũng chỉ ra đúng một tầng như thế. Chứng minh dài hai dòng: ghép {w1, b1} rồi {w2, b2} cho w2·(w1·x + b1) + b2, tức (w2·w1)·x + (w2·b1 + b2), lại đúng dạng một tầng.
Đây là con số. Lấy hai tầng w = 2, b = 1 và w = 3, b = -4: chúng gộp lại thành đúng một tầng w = 6, b = -1, và ở x = 1.5 cả hai đường tính đều cho 8. Thêm tầng thứ ba w = -1, b = 0.5 thì ba tầng gộp thành w = -6, b = 1.5, và ở x = 1.5 cả hai cho -7.5. Ba tầng, ba trọng số, ba bias, mà năng lực biểu diễn vẫn đúng bằng một đường thẳng.
Nói cho chính xác thì hai đường tính không khớp nhau tới từng bit ở mọi chỗ. Cổng kiểm quét cả 241 đầu vào và thấy 209 cấu hình khớp bit y nguyên, phần còn lại lệch nhiều nhất 3.552713678800501e-15. Đó là làm tròn, không phải hai hàm khác nhau.
Có một phép thử phát hiện phi tuyến mà không cần đạo hàm, không cần giới hạn, và bạn kiểm được bằng đầu. Với một hàm bậc nhất thì giá trị tại điểm giữa đúng bằng trung bình hai giá trị hai đầu, nên đại lượng f(x1) + f(x2) - 2·f((x1+x2)/2) phải bằng 0. Gọi nó là độ lệch bậc nhất. Với ba tầng tuyến tính ở trên và cặp (-2, 2) thì độ lệch bậc nhất bằng đúng 0. Nhét ReLU vào giữa các tầng rồi thử lại cùng cặp đó thì nó bằng -11, vì ReLU đã kéo cả -2 và 0 về cùng một đầu ra 0.5 trong khi bản tuyến tính vẫn giữ chúng ở 13.5 và 1.5.
Quét 1830 cặp trên lưới thì bức tranh rõ hẳn:
- không có hàm kích hoạt: độ lệch bằng đúng
0ở975cặp, và ở các cặp còn lại không bao giờ vượt1.5e-14. Tức câu đúng là "tuyến tính thì bậc nhất tới mức làm tròn", không phải một dấu bằng. - có
ReLU: độ lệch lên tới35, tức mười lăm bậc độ lớn trên sàn làm tròn. Nhưng nó vẫn bằng0ở692cặp, vìReLUchỉ gãy ở đúng một chỗ và cặp nào không vắt qua chỗ gãy thì nó vẫn là hàm bậc nhất. - có
sigmoidhoặctanh: không một cặp nào trong1830cặp có độ lệch bằng0. Hai hàm này cong ở khắp nơi.
Chỗ này có một cái bẫy đáng chỉ ra: độ lệch tệ nhất của sigmoid chỉ là 0.2417059658386257, nhỏ hơn 35 của ReLU rất nhiều. Cong ở khắp nơi không có nghĩa là phi tuyến mạnh hơn ở mọi thang đo, vì sigmoid bị chặn nên nó không thể lệch nhiều được. Hai chuyện khác nhau, và bài này không gộp chúng lại.
ReLU và cái nửa âm chết hẳn
Trên nửa âm, ReLU trả về 0, và đạo hàm của nó ở đó bằng đúng 0, không phải nhỏ. Đây là chỗ khác nhau quan trọng nhất giữa "gradient bé" và "gradient bằng không": một nơ-ron có đầu vào âm nhận về chính xác không có gì từ mọi tầng phía sau, nên trọng số của nó không còn được cập nhật nữa. Người ta gọi nó là nơ-ron chết, và chữ chết là chữ đúng: nó không hồi phục được bằng cách huấn luyện thêm, vì huấn luyện thêm nghĩa là nhân thêm với 0.
Con số cho biết chuyện này phổ biến tới đâu trong chính sim này. Trong 241 đầu vào bấm tới được, ReLU cho gradient bằng đúng 0 ở 121 đầu vào, tức hơn một nửa thanh kéo. Trong đó 120 đầu vào âm chằn chặn, còn đầu vào thứ 121 là chính mốc x = 0.
Mốc x = 0 là quy ước, không phải sự thật toán học
ReLU không có đạo hàm tại 0. Bên trái độ dốc là 0, bên phải là 1, và không có một con số nào là đạo hàm ở đúng điểm đó. Engine phải trả về một cái gì, và nó chọn giao điểm đó cho nhánh phẳng, vì phép thử của hàm xuôi là x > 0 nên 0 cũng thuộc nhánh phẳng. Kết quả: dReLU(0) bằng 0, và dLeakyReLU(0) bằng a, tức 0.1. Đây là quy ước của cài đặt này. Các thư viện lớn cũng chọn 0, nhưng đó là lựa chọn của họ chứ không phải một định lý.
Cái quy ước đó lộ ra rất rõ khi bạn thử tính đạo hàm bằng sai phân số. Lấy (f(x+h) - f(x-h)) / (2h), tại x = 0:
- với
ReLU: tử số làh - 0, nên sai phân cho0.5, không phải0. - với
leaky ReLU: tử số làh - (-a·h), nên sai phân cho(1 + a)/2, tức0.55, không phải0.1.
Và khe lệch đó không nhỏ đi khi h nhỏ đi. Cổng kiểm thử h bằng 1e-3, 1e-4, 1e-5, 1e-6 và cả bốn đều cho đúng 0.5 cho ReLU. Đó chính là cách phân biệt một chỗ gãy với một lỗi làm tròn: lỗi làm tròn co lại theo h, chỗ gãy thì không. Lùi một bước lưới sang -0.05 hay tiến một bước sang 0.05 thì hai đường tính khớp lại với nhau ngay.
Sai phân số cũng chính là đường độc lập mà cổng kiểm dùng để kiểm bốn đạo hàm còn lại. Với h = 1e-5, quét 962 mẫu, tức bốn hàm nhân 241 đầu vào rồi bỏ đúng hai mốc gãy, khe lệch tệ nhất đo được là 3.78578279836006e-11, xảy ra với ReLU quanh x = 4.05. Khe đó không phải lỗi của đạo hàm mà là lỗi của chính phép sai phân: nó lấy hai số gần bằng nhau trừ nhau rồi chia cho một số bé. Vì vậy cổng ghim một ngưỡng kèm số đo, chứ không ghim một dấu bằng.
Bão hoà: sigmoid và tanh trả gradient về 0 ở hai đầu
Hai hàm bị chặn đều phẳng dần ở hai phía, nên gradient chúng trả về teo dần. Đây là hai con số then chốt của cả học phần, và cổng kiểm tìm chúng bằng quét vét cạn 1200001 đầu vào cho mỗi hàm chứ không chép từ sách:
- gradient lớn nhất của
sigmoidlà0.25, và nó chỉ đạt được ở đúng một trong1200001điểm quét, tứcx = 0. - gradient lớn nhất của
tanhlà1, cũng ở đúngx = 0, cũng đúng một điểm. ReLUvàleaky ReLUcũng đạt1, nhưng chúng giữ1ở600000điểm quét, tức cả nửa dương.
Cả 0.25 và 1 đều là số thực chính xác, không phải một giá trị xấp xỉ chúng. Lệch khỏi 0 một phần trăm nghìn thì sigmoid đã xuống dưới 0.25 và tanh đã xuống dưới 1, nên 0 là một đỉnh thật chứ không phải một khoảng phẳng.
Ra xa thì gradient sụp nhanh. Ở x = 6, tức mốc cuối của thanh kéo, sigmoid cho 0.002466509291359931 và tanh cho 0.000024576547405286142. So với đỉnh của chính chúng thì sigmoid còn khoảng một phần trăm, còn tanh còn dưới một phần bốn mươi nghìn. Trong khi đó ReLU vẫn trả về đúng 1 ở đó.
Và đây là chỗ chữ "học chậm" có con số. Lan truyền ngược nhân các gradient dọc theo chuỗi tầng, nên mười tầng sigmoid ở điểm tốt nhất của chúng cho 0.25 lũy thừa 10, bằng 9.5367431640625e-7, đúng bằng 2 lũy thừa -20. Nói cách khác gradient tới tầng đầu đã bị chia cho 1048576. Mười tầng tanh ở điểm tốt nhất của chúng cho 1 lũy thừa 10, bằng đúng 1, không teo một chút nào. Chênh lệch giữa hai con số đó là lý do lịch sử người ta bỏ sigmoid ở tầng ẩn để chuyển sang tanh, rồi bỏ cả tanh để chuyển sang ReLU. Bài gradient tiêu biến đi sâu vào chính chuỗi nhân này.
Nhưng "điểm tốt nhất" là một điều kiện rất ngặt, và bỏ nó đi thì thứ tự đảo ngược. Ở x = 2, gradient của sigmoid là 0.10499358540350662 còn của tanh là 0.07065082485316443, nên qua mười tầng thì sigmoid cho 1.6278997858476353e-10 mà tanh chỉ cho 3.0986488720970614e-12, tức tanh teo mạnh hơn khoảng năm mươi lần. Vậy câu "tanh luôn tốt hơn sigmoid" là sai; câu đúng là "tanh tốt hơn ở gần 0, và nó tốt hơn vì gradient cực đại của nó gấp bốn lần".
Còn một mức nữa mà máy tính mới thấy: gradient của hai hàm này không chỉ bé, nó bằng đúng 0 nếu ra đủ xa. Đo trên lưới phần trăm, gradient của sigmoid bằng đúng 0 từ x = 36.74 trở đi, còn ở 36.73 nó vẫn còn 2.2204460492503126e-16. Với tanh thì mốc đó là 19.07, chỉ hơn một nửa khoảng cách. Hai mốc này nằm xa ngoài thanh kéo nên không bao giờ hiện trên màn hình, và chúng khớp với bài sigmoid, nơi đã đo được sigmoid tròn hẳn lên 1 giữa z = 36 và z = 37.
sigmoid và tanh là một đường cong, khác nhau đúng một phép co giãn
tanh(x) = 2·sigmoid(2x) - 1. Đây không phải một mẹo mà là quan hệ giải thích mọi con số ở mục trên: lấy đạo hàm hai vế được tanh'(x) = 4·sigmoid'(2x), và cái hệ số 4 đó chính là lý do gradient cực đại là 1 chứ không phải 0.25.
Trên số thực 64 bit thì đẳng thức này đúng gần hết. Cổng kiểm quét cả 241 đầu vào bấm tới được: 141 khớp bit y nguyên, và chỗ lệch nhiều nhất là 3.3306690738754696e-16, đúng một đơn vị cuối rưỡi tại 1. Quét dày hơn bảy mươi lần, 17143 mẫu nằm ngoài lưới thanh kéo, thì 9924 mẫu khớp bit và khe lệch tệ nhất vẫn đúng bằng con số đó. Nên đây là một đẳng thức đại số đúng, cộng với một khe lệch làm tròn đo được, không phải một dấu bằng trên máy.
Kèm theo đó là một chi tiết về cài đặt mà bài này nói thẳng vì cổng kiểm đo được. Engine tính đạo hàm của tanh bằng 1 - t², dạng dùng lại giá trị xuôi mà mạng đã có sẵn. Dạng đó mất chính xác khi t tiến về 1: ở x = 5.5 thì tanh bằng 0.9999665971563038, nên 1 - t² phải trừ hai số gần bằng nhau và bỏ đi bốn chữ số thập phân đầu. So với giá trị thật tính tới trăm chữ số, engine lệch tới 1.9274513307119138e-12 xét theo tỉ lệ, còn dạng sech² mà cổng kiểm dùng làm đối chứng thì lệch dưới 1e-15. Nghĩa là cổng kiểm chính xác hơn engine ở chỗ này, engine giữ 1 - t² vì nó rẻ hơn, và cái giá đúng bằng con số vừa nêu. Ở trạng thái mở bài thì cả hai dạng đều nằm trong một đơn vị cuối của giá trị thật nên màn hình không bị ảnh hưởng.
Bảng so sánh bốn hàm
Mọi cột trong bảng dưới đây đều được cổng kiểm đo lại, không phải chỉ đọc từ chỗ khai báo. Cột miền giá trị đối chiếu với giá trị nhỏ nhất và lớn nhất thật trên thanh kéo, cột gradient lớn nhất đối chiếu với lượt quét vét cạn, cột bão hoà đối chiếu với gradient ở hai mốc -6 và 6, còn cột tâm ở 0 đối chiếu với trung bình đầu ra trên lưới đối xứng 241 điểm.
| hàm | miền giá trị | gradient lớn nhất | bão hoà | tâm ở 0 |
|---|---|---|---|---|
ReLU | [0, +∞) | 1, trên cả nửa dương | không | không, trung bình 1.5062240663900415 |
sigmoid | (0, 1) | 0.25, chỉ tại x = 0 | có, cả hai đầu | không, trung bình 0.5000000000000001 |
tanh | (-1, 1) | 1, chỉ tại x = 0 | có, cả hai đầu | có, trung bình 4.514599851172836e-17 |
leaky ReLU | (-∞, +∞) | 1, trên cả nửa dương | không | không, trung bình 1.3556016597510372 |
Cột cuối cần nói rõ. "Tâm ở 0" nghĩa là đầu ra của một tầng trung bình quanh 0 thay vì đẩy tầng sau lệch về một phía. Ba trong bốn hàm đều đẩy lệch, và ba con số trung bình trong bảng trên đều dương hẳn. Chỉ tanh trung bình về 0, và con số 4.514599851172836e-17 là 0 tới mức làm tròn chứ không phải 0 chằn chặn, dù tanh(-x) = -tanh(x) đúng tới từng bit ở cả 241 đầu vào. Phần dư đó sinh ra từ thứ tự cộng dồn 241 số thực, không phải từ bản thân hàm.
Còn sigmoid cũng có đối xứng của nó, chỉ là quanh 0.5 chứ không quanh 0: sigmoid(-x) = 1 - sigmoid(x). Đẳng thức này khớp bit y nguyên ở chỉ 78 trong 241 đầu vào, và chỗ lệch không bao giờ vượt 1e-15.
Trên thanh kéo, hai hàm bị chặn không bao giờ chạm mốc của chúng: sigmoid chạy từ 0.0024726231566347743 tới 0.9975273768433653, tanh chạy từ -0.9999877116507956 tới 0.9999877116507956. Hai hàm không chặn thì lên tới 6, và trên hình bạn thấy chúng ra khỏi khung từ x = 4.2, đúng chỗ đầu ra bằng mốc trên của trục dọc.
leaky ReLU chữa nơ-ron chết bằng gì, và trả giá bằng gì
Cách chữa gọn tới mức tầm thường: thay 0 ở nửa âm bằng a·x với a nhỏ. Nhờ đó gradient ở nửa âm bằng a thay vì 0, nên nó không bao giờ bằng đúng 0, và một nơ-ron lạc sang nửa âm vẫn còn nhận được một phần nghìn tín hiệu để bò về. Đo trên 241 đầu vào của sim: ReLU cho gradient bằng đúng 0 ở 121 đầu vào, leaky ReLU ở 0 đầu vào. Với 120 đầu vào âm chằn chặn thì ReLU cho đúng 0 ở cả 120, còn leaky ReLU cho đúng 0.1 ở cả 120.
Cái giá thì có ba phần, và cả ba đều đo được.
Thứ nhất, mất tính thưa. Đầu ra của ReLU bằng đúng 0 ở 121 trong 241 đầu vào, còn leaky ReLU chỉ bằng đúng 0 ở 1 đầu vào duy nhất, chính gốc toạ độ. Nếu bạn đang trông vào chuyện quá nửa nơ-ron im lặng để tiết kiệm tính toán hay để biểu diễn thưa, leaky ReLU lấy chuyện đó đi. Ô đọc kết quả cho thấy ngay: ReLU in 0.00 cho cả 121 đầu vào đó, còn leaky ReLU in 0.00 cho đúng một đầu vào, sang -0.05 nó đã in -0.01.
Thứ hai, mất tính không âm. leaky ReLU cho số âm ở 120 trong 241 đầu vào, nên đầu ra không đọc được như một cường độ kích hoạt nữa.
Thứ ba, a là một siêu tham số phải chọn, và hai đầu của khoảng chọn đều vô nghĩa. Ở a = 0 thì leaky ReLU không xấp xỉ ReLU mà đúng bằng ReLU, ở cả 241 đầu vào, cả hàm xuôi lẫn đạo hàm, kể cả tại mốc gãy: nửa âm chết quay lại nguyên vẹn. Ở a = 1 thì nó đúng bằng hàm đồng nhất, ở cả 241 đầu vào, tức phi tuyến mất sạch. Cổng kiểm chứng minh vế thứ hai bằng đúng phép thử ở mục đầu: một chồng tầng dùng leaky ReLU với a = 1 có hồ sơ độ lệch bậc nhất y hệt một chồng tầng không có hàm kích hoạt nào, 975 cặp bằng đúng 0 và cùng một trần làm tròn. Vậy câu "a phải nằm hẳn trong khoảng giữa 0 và 1" là một câu đo được, không phải một sở thích.
Với a = 0.1 như mặc định của sim, leakyRelu(-3) cho -0.30000000000000004, không phải -0.3, vì 0.1 không phải phân số nhị phân. Chi tiết vụn nhưng nó nhắc lại bài học chung: đừng viết dấu bằng ở chỗ chỉ đúng tới mức làm tròn.
Chọn theo tầng: tầng ẩn khác tầng ra
Hai chỗ trong mạng hỏi hai câu hoàn toàn khác nhau, nên đừng lấy một câu trả lời dùng cho cả hai.
Tầng ẩn chỉ cần một điều: dẫn gradient về được. Vậy tiêu chí là cột gradient lớn nhất và cột bão hoà, và ReLU cùng họ của nó thắng vì chúng cho đúng 1 trên cả nửa dương chứ không chỉ tại một điểm. Nếu bạn thấy nhiều nơ-ron chết thì leaky ReLU là bước tiếp theo, kèm ba cái giá ở mục trên.
Tầng ra thì không được chọn theo gradient, nó bị quy định bởi thứ phải xuất ra. Cần một xác suất trong khoảng (0, 1) thì phải là sigmoid, và đây là chỗ ReLU không dùng được: trên chính thanh kéo này ReLU trả về tới 6, vượt bất kỳ trần nào mà một xác suất có thể có. Cần một phân phối trên nhiều lớp thì dùng softmax, là bản nhiều lớp của cùng ý tưởng. Cần một giá trị có dấu và bị chặn thì tanh. Cần một số thực bất kỳ, ví dụ hồi quy giá, thì đừng đặt hàm kích hoạt nào cả, vì mọi hàm ở đây đều cắt bớt miền giá trị.
Nói cách khác: ở tầng ẩn bạn chọn hàm kích hoạt, ở tầng ra bạn chỉ đang khai báo kiểu dữ liệu của câu trả lời. Bài nơ-ron và lan truyền xuôi đặt cả bốn hàm này vào đúng chỗ của chúng trong một mạng chạy được.
Cái mà bài này không chứng minh, và một chỗ màn hình nói dối
Trong sim không có huấn luyện, không có dữ liệu, không có hàm mất mát. Nên không câu nào ở đây nói ReLU tốt hơn tanh cho một bài toán thật; cổng kiểm chỉ canh được giá trị của từng hàm và từng đạo hàm tại từng đầu vào. Chuyện "ReLU đang là mặc định ở tầng ẩn" là thực hành đã được cả ngành chấp nhận, không phải một kết luận rút ra từ trang này.
Và một chỗ màn hình nói dối mà đáng biết. Trong 240 bước của thanh kéo, có 33 bước mà cả bốn ô đọc kết quả không đổi một chữ nào, còn số thực bên dưới thì đổi ở cả 240 bước, không trừ bước nào. Ví dụ đi từ -6 sang -5.95: sigmoid chuyển từ 0.0024726231566347743 sang 0.002599067762323347 mà cả hai đều in 0.00. Cái núm sống ở mọi bước, chỉ có màn hình là đứng yên. Nếu bạn viết một bộ quét núm chết mà chỉ đọc chữ trên màn hình thì nó sẽ báo cái thanh kéo này chết ở 33 chỗ, và nó sai. Bài học đem đi được: một phép thử chỉ có nghĩa khi bước thử lớn hơn độ chia của đầu ra.
Hàm kích hoạt tồn tại vì xếp chồng tuyến tính vẫn là tuyến tính: ba tầng w = 2, 3, -1 và b = 1, -4, 0.5 gộp lại thành đúng một tầng w = -6, b = 1.5. Chọn hàm nào thì hãy nhìn đạo hàm, không nhìn đường cong. ReLU cho gradient đúng 1 trên cả nửa dương nhưng đúng 0 trên nửa âm, ở 121 trong 241 đầu vào của sim, và đúng 0 nghĩa là nơ-ron đó chết chứ không phải học chậm. sigmoid không bao giờ vượt 0.25 và tanh không bao giờ vượt 1, cả hai chỉ tại x = 0, nên mười tầng sigmoid ở điểm tốt nhất đã chia gradient cho 1048576 trong khi mười tầng tanh thì không teo chút nào. Nhưng ra tới x = 2 thì thứ tự đảo: tanh teo mạnh hơn sigmoid khoảng năm mươi lần. leaky ReLU chữa nửa âm chết bằng độ dốc a, đổi lấy tính thưa từ 121 đầu ra 0 xuống 1, và a phải nằm hẳn giữa 0 và 1 vì a = 0 đúng bằng ReLU còn a = 1 đúng bằng hàm đồng nhất. Cuối cùng, mốc x = 0 của ReLU là quy ước: đạo hàm ở đó không tồn tại, engine trả 0, còn sai phân số trả 0.5 và không chịu nhỏ đi khi h nhỏ đi.
- 1Bỏ hết hàm kích hoạt rồi xếp ba tầng tuyến tính w = 2, 3, -1 với b = 1, -4, 0.5 lên nhau. Mạng đó biểu diễn được gì?
- 2Với x = -3 thì gradient của ReLU bằng bao nhiêu, và điều đó gây ra chuyện gì cho việc huấn luyện?
- 3Gradient lớn nhất của sigmoid là 0.25 và của tanh là 1, cả hai tại x = 0. Kết luận nào đúng?