Tự học Deep Learning – Bài 2: Deep Learning với Tensorflow và Keras

ngày 27-09-2024

Cấu trúc và hoạt động của mạng nơ-ron nhân tạo 

Mạng nơ-ron (neural network), hay còn được gọi là mạng nơ-ron nhân tạo (artificial neural network - ANN), là mô hình toán học và tính toán được lấy cảm hứng từ cấu trúc và chức năng của não bộ con người. Đây là nền tảng của Deep Learning, cho phép máy tính “học” dựa trên dữ liệu tương tự như con người, điều gì chưa biết cứ “học” rồi lâu dần sẽ giỏi. Giống như cách một nhân viên mới tích lũy kinh nghiệm qua quá trình làm việc, mạng nơ-ron cũng "học" từ dữ liệu để cải thiện hiệu suất theo thời gian. 
Mạng nơ-ron bao gồm nhiều node (nơ-ron) được kết nối với nhau. Các nơ-ron này hoạt động tương tự như các nơ-ron sinh học trong não người, nhận thông tin đầu vào, xử lý và truyền kết quả đến các nơ-ron khác... Ví dụ khi con người nhìn thấy một khuôn mặt quen thuộc, các nơ-ron trong não kích hoạt theo một chuỗi phản ứng, từ nhận diện các đặc điểm cơ bản như đường nét, màu sắc, đến việc liên kết với ký ức để nhận ra người đó. Tương tự, trong mạng nơ-ron nhân tạo, mỗi nơ-ron nhận và xử lý một phần nhỏ của thông tin, rồi truyền kết quả qua nhiều lớp xử lý, cuối cùng tạo ra một "nhận thức" tổng thể về dữ liệu đầu vào.
Trong não người, nếu các tín hiệu đầu vào vượt qua một ngưỡng nhất định, nơ-ron sẽ "phóng điện" và truyền tín hiệu đến các nơ-ron khác. Tương tự, nơ-ron nhân tạo tính toán trọng số của các đầu vào, áp dụng một hàm kích hoạt và nếu kết quả thỏa điều kiện ngưỡng, nó sẽ "kích hoạt" và truyền giá trị đầu ra đến các nơ-ron tiếp theo. Quá trình này diễn ra liên tục trong toàn bộ mạng, cho phép máy tính có thể xử lý thông tin phức tạp, như nhận dạng hình ảnh, phân loại văn bản, dự đoán xu hướng….tương tự như cách não chúng ta xử lý các tác vụ nhận thức.

Tìm hiểu cấu trúc của mạng nơ-ron qua bài toán nhận dạng chữ số viết tay

Mạng nơ-ron thường được tổ chức thành các lớp (layers), mỗi lớp có vai trò riêng trong quá trình xử lý thông tin. Để dễ hình dung, trong phần này chúng ta sẽ xây dựng mạng nơ-ron đơn giản để giải quyết bài toán nhận dạng chữ số viết tay trên tập dữ liệu được tích hợp sẵn trong thư viện tensorflow MNIST (Modified National Institute of Standards and Technology). Đây là một trong những tập dữ liệu kinh điển và phổ biến nhất trong lĩnh vực học máy và nhận dạng hình ảnh, bao gồm các hình ảnh chữ số viết tay từ 0 đến 9.
Bước 1: Đọc dữ liệu MNIST dataset in Keras
from tensorflow.keras.datasets import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
Trong đó:
  • train_images, test_images: mảng 2 chiều NumPy kích thước 28x28, tương ứng ma trận pixel của các hình ảnh.
  • train_labels và test_labels: nhãn tương ứng, có giá trị từ 0-9. 
Ý tưởng là chúng ta sẽ cung cấp dữ liệu train, train_images và train_labels, cho mạng nơ-ron. Sau đó, mạng sẽ “học” cách “hiểu” để liên kết hình ảnh và nhãn. Cuối cùng, chúng ta sẽ yêu cầu mạng đưa ra dự đoán cho test_images và chúng ta sẽ kiểm tra xem những dự đoán này có khớp với nhãn ban đầu từ test_labels hay không.
Bước 2: Xây dựng mạng nơ-ron
from tensorflow import keras 
from tensorflow.keras import layers 
model = keras.Sequential([ 
        layers.Dense(512, activation="relu"), 
        layers.Dense(10, activation="softmax")])
Trong Keras, chúng ta không cần phải định nghĩa rõ ràng Lớp đầu vào (Input layer) vì Keras sẽ tự động tính kích thước Lớp đầu vào từ dữ liệu huấn luyện. Trong bài toán nhận dạng chữ số viết tay, Lớp đầu vào có 784 nơ-ron có giá trị trong khoảng [0, 1]. 
Cú pháp trên tạo mạng nơ-ron gồm 2 lớp:
  • Lớp ẩn (Hidden layer) (layers.Dense(512, activation="relu")):  có 512 nơ-ron và hàm kích hoạt ReLU giúp mô hình học các đặc trưng phi tuyến từ dữ liệu đầu vào. Lớp này nhận đầu vào là ma trận ảnh chữ số và trích xuất 512 đặc trưng quan trọng. Chỗ này có lưu ý là chúng ta hoàn toàn có thể chọn giá trị số bất kỳ nhưng xét về mặt kỹ thuật, để phần cứng tính toán hiệu quả thì chúng ta nên chọn giá trị là lũy thừa của 2 (512 = 2^9). Tùy theo bài toán, nhưng nếu tăng số lượng nơ-ron lớn có thể giúp mô hình học được các đặc trưng phức tạp hơn, nhưng cũng tăng nguy cơ overfitting và thời gian huấn luyện. Ngược lại, nếu giảm số nơ-ron thì có thể giảm khả năng overfitting, tăng tốc độ huấn luyệ, nhưng có thể hạn chế khả năng học của mô hình.
  • Lớp thứ hai (layers.Dense(10, activation="softmax")): Đây là Lớp đầu ra (Output layer) với 10 nơ-ron, tương ứng với 10 chữ số (0-9). Hàm kích hoạt softmax sẽ trả về một mảng gồm 10 giá trị xác suất (tổng bằng 1). Mỗi giá trị trong mảng là xác suất của chữ số [0-9] tương ứng với ảnh. Chữ số có xác suất cao nhất sẽ được chọn làm kết quả nhận dạng.
Mạng nơ-ron có thể có một hoặc nhiều lớp ẩn, tùy thuộc vào độ phức tạp của nhiệm vụ cần giải quyết. Càng nhiều lớp ẩn, mạng càng có khả năng học được các biểu diễn phức tạp hơn từ dữ liệu. Đây là nơi diễn ra phần lớn quá trình "học" của mạng nơ-ron. Mỗi lớp ẩn tạo ra một biểu diễn mới của dữ liệu, có ý nghĩa hơn đối với nhiệm vụ cần giải quyết.
Lớp đầu ra (Output layer) là lớp cuối cùng của mạng nơ-ron. Số lượng nơ-ron trong lớp này phụ thuộc vào loại bài toán:
  • Đối với bài toán phân loại nhị phân: 1 nơ-ron, có hai nhãn (ví dụ: "0" hoặc "1", "có" hoặc "không"). Hàm kích hoạt (activation function) thường được sử dụng là sigmoid, vì giá trị đầu ra nằm trong khoảng từ 0 đến 1, thuận tiện cho việc phân loại nhị phân.
  • Đối với bài toán phân loại đa lớp: số nơ-ron bằng số lớp cần phân loại. Như với bài toán nhận diện chữ số (0-9), có 10 lớp, do đó lớp đầu ra sẽ có 10 nơ-ron. Hàm kích hoạt thường được sử dụng là softmax, cho biết xác suất cho từng lớp và tổng các xác suất này bằng 1.
  • Đối với bài toán hồi quy: mục tiêu là dự đoán một giá trị số thực (dự đoán giá nhà, nhiệt độ,…). Do đó, lớp đầu ra thường có 1 nơ-ron vì đầu ra chỉ là một giá trị duy nhất. Hàm kích hoạt thường được sử dụng là linear để đưa ra một giá trị liên tục.
Bước 3: Biên dịch mô hình
model.compile(optimizer="rmsprop",
              loss="sparse_categorical_crossentropy", 
              metrics=["accuracy"])
Để mô hình sẵn sàng cho việc huấn luyện, quá trình học từ dữ liệu train, chúng ta cần thực hiện một bước gọi là biên dịch (compile) mô hình. Quá trình huấn luyện mạng nơ-ron dựa trên dữ liệu là quá trình lặp nhiều lần, trong bước biên dịch này, chúng ta cần xác định ba yếu tố quan trọng để mô hình có thể “học” và tự cải thiện qua từng vòng huấn luyện:
  1. Bộ tối ưu hóa (optimizer): là một thành phần cực kỳ quan trọng, có nhiệm vụ điều chỉnh các tham số của mô hình (các trọng số của nơ-ron) sao cho mô hình có thể đưa ra dự đoán chính xác hơn sau mỗi vòng huấn luyện. Mỗi nơ-ron trong mạng có trọng số quyết định mức độ ảnh hưởng của mỗi đầu vào. Optimizer sẽ cập nhật các trọng số này dựa trên sai số mà mô hình tạo ra trong lần dự đoán trước đó, giúp mô hình học từ những sai lầm và cải thiện trong lần dự đoán tiếp theo. Trong đoạn mã, rmsprop là bộ tối ưu hóa được sử dụng để tối ưu hóa quá trình học tập.
  2. Hàm mất mát (loss function): Đây là cách mô hình đo lường xem nó đang hoạt động tốt đến đâu. Khi mô hình dự đoán, nó cần biết sai số giữa dự đoán và kết quả thật là bao nhiêu, để có thể điều chỉnh trong lần “học” kế tiếp. 
  3. Chỉ số đánh giá (metrics): Đây là những gì chúng ta quan tâm khi theo dõi quá trình huấn luyện và kiểm tra mô hình. Ở đây, chúng ta sử dụng "accuracy" (độ chính xác), để biết tỷ lệ phần trăm các hình ảnh được phân loại nhãn đúng. Chỉ số này giúp chúng ta đánh giá hiệu quả tổng thể của mô hình trong suốt quá trình học.
Tương tự như cách chúng ta học lái xe, mỗi buổi học là một "epoch" trong quá trình huấn luyện mạng nơ-ron. Chúng ta cần người Thầy/Cô để hướng dẫn điều chỉnh hành vi của bạn khi lái xe để giúp bạn cải thiện kỹ năng lái xe (bộ tối ưu hóa), một cách đánh giá xem chúng ta so với tiêu chuẩn chúng ta còn khoảng cách như thế nào (hàm mất mát) và để theo dõi hiệu quả trong quá trình học tập chúng ta cần có các tiêu chí để đánh giá tiến bộ, chẳng hạn như số lần dừng đúng đèn đỏ, mức độ kiểm soát tốc độ, số lần đỗ xe đúng vị trí… (chỉ số đánh giá).
Bước 4: Chuẩn bị dữ liệu huấn luyện
train_images = train_images.reshape((60000, 28 * 28)) 
train_images = train_images.astype("float32") / 255 
test_images = test_images.reshape((10000, 28 * 28)) 
test_images = test_images.astype("float32") / 255
Để dữ liệu có thể phù hợp hơn với đầu vào của mô hình và giúp mô hình “học” hiệu quả hơn, trong đa số trường hợp chúng ta cần thực hiện bước tiền xử lý dữ liệu. Như trong trường hợp này, dữ liệu gốc là mảng 3 chiều có kích thước (60000, 28, 28), chúng ta sẽ chuyển thành ma trận 2 chiều có kích thước mới là (60000, 28 * 28), nghĩa là chuyển ảnh từ ma trận 2D sang vector 1D có 784 giá trị. Dữ liệu gốc là các số nguyên không dấu từ 0 đến 255 (dạng uint8), tuy nhiên khi thực hiện các phép toán như chia cho 255, chúng ta cần chuyển sang kiểu số thực (float32) để có thể biểu diễn các giá trị thập phân, giúp tính toán chính xác hơn. Kiểu dữ liệu float32 cũng cần thiết cho các phép tính trong quá trình huấn luyện mạng nơ-ron. Sau đó, chúng ta chia cho 255 để chuẩn hóa giá trị từ khoảng [0, 255] sang khoảng [0, 1] để giúp mô hình hội tụ nhanh hơn và tránh vấn đề tràn số trong quá trình tính toán.
Bước 5: Huấn luyện mô hình trên dữ liệu train
model.fit(train_images, train_labels, epochs=5, batch_size=128)
Tất cả các bước chuẩn bị đã sẵn sàng để đào tạo mô hình. Trong Keras, để huấn luyện mô hình chúng ta chỉ cần gọi phương thức fit() của mô hình để mô hình có thể học từ dữ liệu train. 
Quá trình huấn luyện diễn ra như sau:
  1. Mô hình bắt đầu với các trọng số ngẫu nhiên.
  2. Mô hình sẽ xem xét 128 ảnh đầu tiên (batch) và dự đoán nhãn cho 128 ảnh này.
  3. So sánh dự đoán với nhãn thực tế và tính toán lỗi.
  4. Dựa vào lỗi, mô hình điều chỉnh trọng số (thông qua optimizer đã chọn).
  5. Lặp lại bước 2-4 cho đến khi duyệt hết tất cả ảnh trong tập huấn luyện.
  6. Khi đã duyệt hết tất cả ảnh, đó là kết thúc 1 epoch.
  7. Quá trình này lặp lại 5 lần (5 epochs).
Bước 6: Sử dụng mô hình đã huấn luyện để dự đoán ảnh trong tập test
test_digits = test_images[0:10]
predictions = model.predict(test_digits)
print(‘Mảng chứa xác suất dự đoán của ảnh đầu tiên:’,predictions[0])
print(‘Chỉ số của xác suất cao nhất trong mảng:’,predictions[0].argmax())
print(‘Nhãn thực tế của ảnh đầu tiên: ’, test_labels[0])
Chúng ta sẽ sử dụng mô hình đã huấn luyện để dự đoán các giá trị tương ứng cho 10 ảnh (test_digits). Phương thức model.predict() sẽ đưa ra dự đoán xác suất cho mỗi ảnh trong test_digits. Kết quả trả về trong predictions[0] là một mảng chứa 10 giá trị dự đoán tương ứng với xác suất của các chữ số 0 đến 9. Trong mảng, chỉ số index có giá trị cao nhất (predictions[0].argmax()) sẽ là nhãn chữ số tương ứng. Chúng ta có thể dùng lệnh test_labels[0] để so sánh nhãn thực tế của ảnh đầu tiên.

Giới thiệu Tensorflow và Keras

TensorFlow là thư viện học sâu được Google phát triển vào năm 2015 và nhanh chóng trở thành một trong những công cụ phổ biến nhất trong lĩnh vực Deep Learning với các ưu điểm nổi trội như:  
  • Hiệu suất tính toán cao: TensorFlow được thiết kế để xử lý các phép toán trên tensor (ma trận nhiều chiều) một cách tối ưu trên nhiều loại phần cứng như CPU, GPU và cả TPU (phần cứng đặc biệt của Google). Điều này cho phép mô hình có thể xử lý lượng dữ liệu lớn và giảm đáng kể thời gian huấn luyện các mô hình phức tạp.
  • Tự động tính toán gradient: Một trong những tính năng nổi bật của TensorFlow là khả năng tự động tính toán gradient - một khái niệm toán học quan trọng trong học sâu. Gradient cho biết hướng thay đổi của các tham số mô hình để giảm thiểu sai số dự đoán. TensorFlow giúp chúng ta không phải tự tính toán gradient một cách thủ công, tiết kiệm rất nhiều thời gian và công sức.
  • Cung cấp API cấp thấp: TensorFlow cung cấp cho người dùng khả năng kiểm soát chi tiết mọi khía cạnh của mô hình, từ cấu trúc mạng đến thuật toán tối ưu hóa. Điều này rất hữu ích cho các nhà nghiên cứu muốn thử nghiệm những mô hình phức tạp.
  • Khả năng triển khai đa nền tảng: TensorFlow hỗ trợ triển khai mô hình trên nhiều nền tảng như web, di động, máy chủ và các thiết bị nhúng, giúp mô hình dễ dàng được ứng dụng vào thực tiễn hơn.
Keras được ra mắt vào năm 2015 và tác giả là François Chollet, nhà nghiên cứu và kỹ sư nổi tiếng trong lĩnh vực trí tuệ nhân tạo. Keras đã nhanh chóng trở thành một trong những công cụ phổ biến nhất trong cộng đồng Deep Learning nhờ vào giao diện thân thiện với người dùng và khả năng tích hợp với các framework mạnh mẽ như TensorFlow. Các đặc tính nổi bật của Keras:
  • API cấp cao dễ sử dụng: Keras cung cấp các API cấp cao cho phép người dùng định nghĩa mô hình học sâu một cách trực quan và dễ hiểu. Thay vì phải viết code chi tiết cho từng lớp và kết nối trong mạng neural, Keras cho phép bạn xây dựng mô hình chỉ với vài dòng mã. 
  • Tập trung vào phần quan trọng: Thay vì phải lo về các chi tiết kỹ thuật phức tạp, Keras giúp người dùng tập trung vào việc thiết kế mô hình, chọn hàm mất mát và các thuật toán tối ưu, làm cho quá trình xây dựng mô hình trở nên nhẹ nhàng hơn.
  • Tích hợp hoàn hảo với TensorFlow: Từ TensorFlow 2.0, Keras đã được tích hợp sẵn vào TensorFlow, giúp khai thác sức mạnh của TensorFlow một cách dễ dàng thông qua Keras.
Có thể nói TensorFlow và Keras là một bộ đôi mạnh mẽ và bổ sung lẫn nhau trong việc phát triển các mô hình Deep Learning. TensorFlow cung cấp nền tảng tính toán mạnh mẽ, còn Keras giúp đơn giản hóa quá trình xây dựng và triển khai mô hình. Sự kết hợp này giúp các kỹ sư và nhà nghiên cứu dễ dàng giải quyết những vấn đề phức tạp và ứng dụng học sâu vào thực tế một cách nhanh chóng và hiệu quả.
 
ai
Trung Tâm Tin Học
ai
Trung Tâm Tin Học
Chào mừng bạn đến với Trung Tâm Tin Học.
Bạn đang cần hỗ trợ thông tin gì ạ? Hãy Chat ngay với chúng tôi nhé.