Thứ năm, 28/03/2019 | 00:00 GMT+7

Cách xây dựng mạng neural để nhận ra chữ số viết tay với TensorFlow

Mạng nơ-ron được sử dụng như một phương pháp học sâu, một trong nhiều lĩnh vực con của trí tuệ nhân tạo. Chúng được đề xuất lần đầu tiên vào khoảng 70 năm trước như một nỗ lực mô phỏng cách thức hoạt động của bộ não con người, mặc dù ở dạng đơn giản hơn nhiều. Các 'tế bào thần kinh' riêng lẻ được kết nối theo từng lớp, với các trọng số được chỉ định để xác định cách tế bào thần kinh phản ứng khi tín hiệu được truyền qua mạng. Trước đây, mạng nơ-ron bị giới hạn về số lượng nơ-ron mà chúng có thể mô phỏng, và do đó độ phức tạp của việc học mà chúng có thể đạt được. Nhưng trong những năm gần đây, do những tiến bộ trong phát triển phần cứng, ta đã có thể xây dựng các mạng rất sâu và đào tạo chúng trên các bộ dữ liệu khổng lồ để đạt được những đột phá về trí thông minh của máy móc.

Những đột phá này đã cho phép máy móc phù hợp và vượt quá khả năng của con người trong việc thực hiện một số nhiệm vụ. Một trong những nhiệm vụ đó là nhận dạng đối tượng. Mặc dù máy móc trong lịch sử không thể phù hợp với tầm nhìn của con người, nhưng những tiến bộ gần đây trong học sâu đã giúp ta có thể xây dựng mạng lưới thần kinh có thể nhận dạng vật thể, khuôn mặt, văn bản và thậm chí cả cảm xúc.

Trong hướng dẫn này, bạn sẽ triển khai một tiểu mục nhỏ của nhận dạng đối tượng — nhận dạng chữ số. Sử dụng TensorFlow , một thư viện Python open-souce được phát triển bởi phòng thí nghiệm Google Brain để nghiên cứu học tập sâu, bạn sẽ chụp các hình ảnh vẽ tay của các số 0-9 và xây dựng và đào tạo mạng nơ-ron để nhận ra và dự đoán nhãn chính xác cho chữ số hiển thị.

Mặc dù bạn sẽ không cần kinh nghiệm trước về học sâu thực tế hoặc TensorFlow để làm theo hướng dẫn này, nhưng ta sẽ cho rằng bạn đã quen với các thuật ngữ và khái niệm học máy như đào tạo và kiểm tra, các tính năng và nhãn, tối ưu hóa và đánh giá. Bạn có thể tìm hiểu thêm về các khái niệm này trong Giới thiệu về Học máy .

Yêu cầu

Để hoàn thành hướng dẫn này, bạn cần :

Bước 1 - Cấu hình dự án

Trước khi có thể phát triển chương trình nhận dạng, bạn cần cài đặt một số phụ thuộc và tạo không gian làm việc để chứa các file của bạn .

Ta sẽ sử dụng môi trường ảo Python 3 để quản lý các phần phụ thuộc của dự án. Tạo một folder mới cho dự án của bạn và chuyển đến folder mới:

  • mkdir tensorflow-demo
  • cd tensorflow-demo

Thực hiện các lệnh sau để cài đặt môi trường ảo cho hướng dẫn này:

  • python3 -m venv tensorflow-demo
  • source tensorflow-demo/bin/activate

Tiếp theo, cài đặt các thư viện bạn sẽ sử dụng trong hướng dẫn này. Ta sẽ sử dụng các version cụ thể của các thư viện này bằng cách tạo ra một requirements.txt file trong folder dự án trong đó nêu rõ các yêu cầu và version ta cần. Tạo requirements.txt file:

  • touch requirements.txt

Mở file trong editor của bạn và thêm các dòng sau để chỉ định các thư viện Image, NumPy, TensorFlow và các version của chúng:

request.txt
image==1.5.20 numpy==1.14.3 tensorflow==1.4.0 

Lưu file và thoát khỏi editor . Sau đó, cài đặt các thư viện này bằng lệnh sau:

  • pip install -r requirements.txt

Với các phụ thuộc được cài đặt, ta có thể bắt đầu làm việc với dự án của bạn .

Bước 2 - Nhập tập dữ liệu MNIST

Tập dữ liệu mà ta sẽ sử dụng trong hướng dẫn này được gọi là tập dữ liệu MNIST và nó là một tập dữ liệu cổ điển trong cộng đồng học máy. Tập dữ liệu này được tạo thành từ hình ảnh của các chữ số viết tay, kích thước 28x28 pixel. Dưới đây là một số ví dụ về các chữ số có trong tập dữ liệu:

Ví dụ về hình ảnh MNIST

Hãy tạo một chương trình Python để làm việc với tập dữ liệu này. Ta sẽ sử dụng một file cho tất cả công việc của ta trong hướng dẫn này. Tạo một file mới có tên main.py :

  • touch main.py

Bây giờ hãy mở file này trong editor mà bạn chọn và thêm dòng mã này vào file để nhập thư viện TensorFlow:

main.py
import tensorflow as tf 

Thêm các dòng mã sau vào file của bạn để nhập tập dữ liệu MNIST và lưu trữ dữ liệu hình ảnh trong biến mnist :

main.py
... from tensorflow.examples.tutorials.mnist import input_data   mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)  # y labels are oh-encoded 

Khi đọc dữ liệu, ta đang sử dụng mã hóa một nóng để đại diện cho các nhãn (chữ số thực được vẽ, ví dụ: “3”) của hình ảnh. Mã hóa một nóng sử dụng một vectơ các giá trị binary để biểu thị các giá trị số hoặc phân loại. Vì nhãn của ta dành cho các chữ số 0-9, nên vectơ chứa mười giá trị, một giá trị cho mỗi chữ số có thể. Một trong những giá trị này được đặt thành 1, để đại diện cho chữ số tại chỉ số đó của vectơ và các giá trị còn lại được đặt thành 0. Ví dụ: chữ số 3 được biểu diễn bằng cách sử dụng vectơ [0, 0, 0, 1, 0, 0, 0, 0, 0, 0] . Vì giá trị ở chỉ số 3 được lưu trữ dưới dạng 1, do đó vectơ đại diện cho chữ số 3.

Để đại diện cho chính hình ảnh thực tế, các pixel 28x28 được làm phẳng thành một vector 1D có kích thước 784 pixel. Mỗi trong số 784 pixel tạo nên hình ảnh được lưu trữ dưới dạng giá trị từ 0 đến 255. Điều này xác định thang độ xám của pixel, vì hình ảnh của ta chỉ được trình bày bằng màu đen và trắng. Vì vậy, một điểm ảnh màu đen được biểu thị bằng 255 và một điểm ảnh màu trắng bằng 0, với các sắc độ xám khác nhau ở giữa.

Ta có thể sử dụng biến mnist để tìm ra kích thước của tập dữ liệu mà ta vừa nhập. Nhìn vào num_examples cho từng trong ba tập hợp con, ta có thể xác định rằng tập dữ liệu đã được chia thành 55.000 hình ảnh để đào tạo, 5000 hình ảnh để xác thực và 10.000 hình ảnh để thử nghiệm. Thêm các dòng sau vào file của bạn:

main.py
... n_train = mnist.train.num_examples  # 55,000 n_validation = mnist.validation.num_examples  # 5000 n_test = mnist.test.num_examples  # 10,000 

Bây giờ ta đã nhập dữ liệu của bạn , đã đến lúc nghĩ về mạng nơ-ron.

Bước 3 - Xác định kiến trúc mạng thần kinh

Kiến trúc của mạng nơ-ron đề cập đến các yếu tố như số lớp trong mạng, số đơn vị trong mỗi lớp và cách các đơn vị được kết nối giữa các lớp. Vì mạng lưới thần kinh được lấy cảm hứng từ hoạt động của bộ não con người, nên ở đây thuật ngữ đơn vị được sử dụng để biểu thị những gì ta sẽ nghĩ về mặt sinh học như một tế bào thần kinh. Giống như các tế bào thần kinh truyền tín hiệu xung quanh não, các đơn vị lấy một số giá trị từ các đơn vị trước đó làm đầu vào, thực hiện tính toán, sau đó chuyển giá trị mới dưới dạng kết quả cho các đơn vị khác. Các đơn vị này được xếp lớp để tạo thành mạng, tối thiểu bắt đầu với một lớp để nhập giá trị và một lớp để xuất giá trị. Thuật ngữ lớp ẩn được sử dụng cho tất cả các lớp ở giữa các lớp đầu vào và kết quả , tức là những lớp “ẩn” khỏi thế giới thực.

Các kiến trúc khác nhau có thể mang lại các kết quả khác nhau đáng kể, vì hiệu suất có thể được coi là một chức năng của kiến trúc trong số những thứ khác, chẳng hạn như các tham số, dữ liệu và thời gian đào tạo.

Thêm các dòng mã sau vào file của bạn để lưu trữ số lượng đơn vị trên mỗi lớp trong các biến toàn cục. Điều này cho phép ta thay đổi kiến trúc mạng ở một nơi và ở phần cuối của hướng dẫn, bạn có thể tự kiểm tra số lượng lớp và đơn vị khác nhau sẽ ảnh hưởng như thế nào đến kết quả của mô hình của ta :

main.py
... n_input = 784  # input layer (28x28 pixels) n_hidden1 = 512  # 1st hidden layer n_hidden2 = 256  # 2nd hidden layer n_hidden3 = 128  # 3rd hidden layer n_output = 10  # output layer (0-9 digits) 

Sơ đồ sau đây cho thấy hình ảnh trực quan về kiến trúc mà ta đã thiết kế, với mỗi lớp được kết nối đầy đủ với các lớp xung quanh:

Sơ đồ mạng nơron

Thuật ngữ “mạng nơ-ron sâu” liên quan đến số lượng lớp ẩn, với “nông” thường chỉ nghĩa là một lớp ẩn và “sâu” đề cập đến nhiều lớp ẩn. Với đủ dữ liệu huấn luyện, một mạng nơron nông với đủ số lượng đơn vị về mặt lý thuyết sẽ có thể biểu diễn bất kỳ chức năng nào mà mạng nơron sâu có thể. Nhưng thường hiệu quả hơn về mặt tính toán khi sử dụng một mạng nơ ron sâu nhỏ hơn để đạt được cùng một nhiệm vụ đòi hỏi một mạng nông với các đơn vị ẩn hơn theo cấp số nhân. Mạng nơron nông cũng thường gặp phải tình trạng overfitting, trong đó mạng về cơ bản ghi nhớ dữ liệu huấn luyện mà nó đã thấy, và không thể tổng quát hóa kiến thức thành dữ liệu mới. Đây là lý do tại sao mạng nơron sâu được sử dụng phổ biến hơn: nhiều lớp giữa dữ liệu đầu vào thô và nhãn kết quả cho phép mạng tìm hiểu các tính năng ở các mức trừu tượng khác nhau, làm cho bản thân mạng có khả năng tổng quát hóa tốt hơn.

Các phần tử khác của mạng nơ-ron cần được xác định ở đây là các siêu tham số. Không giống như các tham số sẽ được cập nhật trong quá trình huấn luyện, các giá trị này được đặt ban đầu và không đổi trong suốt quá trình. Trong file của bạn, hãy đặt các biến và giá trị sau:

main.py
... learning_rate = 1e-4 n_iterations = 1000 batch_size = 128 dropout = 0.5 

Tỷ lệ học tập thể hiện mức độ các thông số sẽ điều chỉnh ở mỗi bước của quá trình học tập. Những điều chỉnh này là một thành phần quan trọng của quá trình luyện tập: sau mỗi lần đi qua mạng, ta điều chỉnh trọng lượng một chút để thử và giảm sự mất mát. Tỷ lệ học tập lớn hơn có thể hội tụ nhanh hơn, nhưng cũng có khả năng vượt quá các giá trị tối ưu khi chúng được cập nhật. Số lần lặp đề cập đến số lần ta trải qua bước đào tạo và kích thước lô đề cập đến số lượng ví dụ đào tạo mà ta đang sử dụng ở mỗi bước. Biến số người dropout đại diện cho một ngưỡng mà tại đó ta loại bỏ một số đơn vị một cách ngẫu nhiên. Ta sẽ sử dụng tính năng dropout trong lớp ẩn cuối cùng của ta để cho mỗi đơn vị có 50% cơ hội bị loại ở mỗi bước huấn luyện. Điều này giúp ngăn ngừa việc mặc quá nhiều.

Bây giờ ta đã xác định kiến trúc của mạng nơ-ron và các siêu tham số ảnh hưởng đến quá trình học tập. Bước tiếp theo là xây dựng mạng dưới dạng đồ thị TensorFlow.

Bước 4 - Xây dựng đồ thị TensorFlow

Để xây dựng mạng của bạn , ta sẽ cài đặt mạng dưới dạng đồ thị tính toán để TensorFlow thực thi. Khái niệm cốt lõi của TensorFlow là tensor , một cấu trúc dữ liệu tương tự như một mảng hoặc danh sách. được khởi tạo, thao tác khi chúng được chuyển qua biểu đồ và được cập nhật trong quá trình học tập.

Ta sẽ bắt đầu bằng cách xác định ba tensor làm trình giữ chỗ , là những tensor mà ta sẽ đưa các giá trị vào sau. Thêm phần sau vào file của bạn:

main.py
... X = tf.placeholder("float", [None, n_input]) Y = tf.placeholder("float", [None, n_output]) keep_prob = tf.placeholder(tf.float32) 

Tham số duy nhất cần được chỉ định khi khai báo là kích thước của dữ liệu mà ta sẽ cung cấp. Đối với X ta sử dụng hình dạng [None, 784] , trong đó None đại diện cho bất kỳ số lượng nào, vì ta sẽ cung cấp trong một không xác định số lượng hình ảnh 784 pixel. Hình dạng của Y[None, 10] vì ta sẽ sử dụng nó cho một số lượng kết quả nhãn không xác định, với 10 lớp có thể. Tensor keep_prob được sử dụng để kiểm soát tỷ lệ bỏ học và ta khởi tạo nó dưới dạng trình giữ chỗ thay vì biến bất biến vì ta muốn sử dụng cùng tensor cho cả việc đào tạo (khi dropout được đặt thành 0.5 ) và thử nghiệm (khi dropout được đặt thành 1.0 ).

Các tham số mà mạng sẽ cập nhật trong quá trình huấn luyện là các giá trị weightbias , vì vậy đối với các tham số này, ta cần đặt một giá trị ban đầu thay vì một trình giữ chỗ trống. Các giá trị này về cơ bản là nơi mạng thực hiện việc học của nó, vì chúng được sử dụng trong các chức năng kích hoạt của các nơ-ron, đại diện cho sức mạnh của các kết nối giữa các đơn vị.

Vì các giá trị được tối ưu hóa trong quá trình đào tạo, ta có thể đặt chúng thành 0 ngay bây giờ. Nhưng giá trị ban đầu thực sự có tác động đáng kể đến độ chính xác cuối cùng của mô hình. Ta sẽ sử dụng các giá trị ngẫu nhiên từ phân phối chuẩn bị cắt ngắn cho các trọng số. Ta muốn chúng gần bằng 0, vì vậy chúng có thể điều chỉnh theo hướng tích cực hoặc tiêu cực và hơi khác một chút, do đó chúng tạo ra các lỗi khác nhau. Điều này sẽ đảm bảo mô hình học được điều gì đó hữu ích. Thêm những dòng này:

main.py
... weights = {     'w1': tf.Variable(tf.truncated_normal([n_input, n_hidden1], stddev=0.1)),     'w2': tf.Variable(tf.truncated_normal([n_hidden1, n_hidden2], stddev=0.1)),     'w3': tf.Variable(tf.truncated_normal([n_hidden2, n_hidden3], stddev=0.1)),     'out': tf.Variable(tf.truncated_normal([n_hidden3, n_output], stddev=0.1)), } 

Đối với độ lệch, ta sử dụng một giá trị không đổi nhỏ đảm bảo rằng các tenxơ kích hoạt trong các giai đoạn ban đầu và do đó góp phần vào sự lan truyền. Các trọng số và tensor thiên vị được lưu trữ trong các đối tượng từ điển để dễ dàng truy cập. Thêm mã này vào file của bạn để xác định các thành kiến:

main.py
... biases = {     'b1': tf.Variable(tf.constant(0.1, shape=[n_hidden1])),     'b2': tf.Variable(tf.constant(0.1, shape=[n_hidden2])),     'b3': tf.Variable(tf.constant(0.1, shape=[n_hidden3])),     'out': tf.Variable(tf.constant(0.1, shape=[n_output])) } 

Tiếp theo, cài đặt các lớp của mạng bằng cách xác định các hoạt động sẽ thao tác các tensors. Thêm những dòng này vào file của bạn:

main.py
... layer_1 = tf.add(tf.matmul(X, weights['w1']), biases['b1']) layer_2 = tf.add(tf.matmul(layer_1, weights['w2']), biases['b2']) layer_3 = tf.add(tf.matmul(layer_2, weights['w3']), biases['b3']) layer_drop = tf.nn.dropout(layer_3, keep_prob) output_layer = tf.matmul(layer_3, weights['out']) + biases['out'] 

Mỗi lớp ẩn sẽ thực hiện phép nhân ma trận trên các kết quả của lớp trước và trọng số của lớp hiện tại, đồng thời thêm độ lệch vào các giá trị này. Ở lớp ẩn cuối cùng, ta sẽ áp dụng thao tác bỏ qua sử dụng giá trị keep_prob của ta là 0,5.

Bước cuối cùng trong việc xây dựng biểu đồ là xác định hàm mất mát mà ta muốn tối ưu hóa. Một lựa chọn phổ biến của hàm mất mát trong các chương trình TensorFlow là cross-entropy , còn gọi là log-loss , định lượng sự khác biệt giữa hai phân phối xác suất (dự đoán và nhãn). Một phân loại hoàn hảo sẽ dẫn đến entropy chéo bằng 0, với sự mất mát hoàn toàn được giảm thiểu.

Ta cũng cần chọn thuật toán tối ưu hóa sẽ được sử dụng để giảm thiểu hàm mất mát. Một quy trình có tên là tối ưu hóa gradient giảm dần là một phương pháp phổ biến để tìm điểm tối thiểu (cục bộ) của một hàm bằng cách thực hiện các bước lặp lại dọc theo gradient theo hướng âm (giảm dần). Có một số lựa chọn thuật toán tối ưu hóa độ dốc dốc đã được triển khai trong TensorFlow và trong hướng dẫn này, ta sẽ sử dụng trình tối ưu hóa Adam . Điều này mở rộng khi tối ưu hóa độ dốc xuống bằng cách sử dụng xung lượng để tăng tốc quá trình thông qua tính toán trung bình có trọng số theo cấp số nhân của các độ dốc và sử dụng nó trong các điều chỉnh. Thêm mã sau vào file của bạn:

main.py
... cross_entropy = tf.reduce_mean(     tf.nn.softmax_cross_entropy_with_logits(         labels=Y, logits=output_layer         )) train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy) 

Bây giờ ta đã xác định mạng và xây dựng nó với TensorFlow. Bước tiếp theo là cung cấp dữ liệu thông qua biểu đồ để đào tạo nó và sau đó kiểm tra xem nó đã thực sự học được điều gì đó chưa.

Bước 5 - Đào tạo và Kiểm tra

Quá trình đào tạo bao gồm việc cung cấp tập dữ liệu đào tạo thông qua biểu đồ và tối ưu hóa hàm mất mát. Mỗi khi mạng lặp qua một loạt hình ảnh huấn luyện khác, nó sẽ cập nhật các thông số để giảm tổn thất nhằm dự đoán chính xác hơn các chữ số được hiển thị. Quá trình thử nghiệm bao gồm việc chạy bộ dữ liệu thử nghiệm của ta thông qua biểu đồ được đào tạo và theo dõi số lượng hình ảnh được dự đoán chính xác, để ta có thể tính toán độ chính xác.

Trước khi bắt đầu quá trình đào tạo, ta sẽ xác định phương pháp đánh giá độ chính xác của bạn để ta có thể in nó ra trên các lô dữ liệu nhỏ trong khi đào tạo. Các câu lệnh in này sẽ cho phép ta kiểm tra xem từ lần lặp đầu tiên đến lần cuối cùng, tổn thất giảm và độ chính xác tăng lên; chúng cũng sẽ cho phép ta theo dõi xem ta đã chạy đủ số lần lặp để đạt được kết quả nhất quán và tối ưu hay chưa:

main.py
... correct_pred = tf.equal(tf.argmax(output_layer, 1), tf.argmax(Y, 1)) accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32)) 

Trong correct_pred , ta sử dụng hàm arg_max để so sánh những hình ảnh nào đang được dự đoán chính xác bằng cách nhìn vào output_layer (dự đoán) và Y (nhãn), và ta sử dụng hàm equal để trả về đây là danh sách các Boolean . Sau đó, ta có thể chọn danh sách này để thả nổi và tính toán giá trị trung bình để có được tổng điểm chính xác.

Bây giờ ta đã sẵn sàng chạy một phiên để chạy biểu đồ. Trong phần này, ta sẽ cung cấp cho mạng các ví dụ đào tạo của ta và sau khi được đào tạo, ta cung cấp cùng một biểu đồ với các ví dụ thử nghiệm mới để xác định độ chính xác của mô hình. Thêm các dòng mã sau vào file của bạn:

main.py
... init = tf.global_variables_initializer() sess = tf.Session() sess.run(init) 

Bản chất của quá trình đào tạo trong học sâu là tối ưu hóa hàm mất mát. Ở đây ta đang hướng tới việc giảm thiểu sự khác biệt giữa nhãn dự đoán của hình ảnh và nhãn thực của hình ảnh. Quy shell gồm bốn bước được lặp lại cho một số lần lặp lại:

  • Truyền tải các giá trị về phía trước thông qua mạng
  • Tính toán khoản lỗ
  • Truyền ngược các giá trị qua mạng
  • Cập nhật các thông số

Ở mỗi bước huấn luyện, các thông số được điều chỉnh một chút để thử và giảm hao hụt cho bước tiếp theo. Khi quá trình học tập tiến triển, ta sẽ thấy sự giảm sút và cuối cùng ta có thể ngừng đào tạo và sử dụng mạng làm mô hình để kiểm tra dữ liệu mới của bạn .

Thêm mã này vào file :

main.py
... # train on mini batches for i in range(n_iterations):     batch_x, batch_y = mnist.train.next_batch(batch_size)     sess.run(train_step, feed_dict={         X: batch_x, Y: batch_y, keep_prob: dropout         })      # print loss and accuracy (per minibatch)     if i % 100 == 0:         minibatch_loss, minibatch_accuracy = sess.run(             [cross_entropy, accuracy],             feed_dict={X: batch_x, Y: batch_y, keep_prob: 1.0}             )         print(             "Iteration",             str(i),             "\t| Loss =",             str(minibatch_loss),             "\t| Accuracy =",             str(minibatch_accuracy)             ) 

Sau 100 lần lặp lại của mỗi bước đào tạo, trong đó ta cung cấp một loạt ảnh nhỏ qua mạng, ta sẽ in ra mức độ mất mát và độ chính xác của lô đó. Lưu ý ta không nên mong đợi sự mất mát ngày càng giảm và độ chính xác ngày càng tăng ở đây, vì các giá trị là trên mỗi lô, không phải cho toàn bộ mô hình. Ta sử dụng các lô hình ảnh nhỏ thay vì cung cấp chúng qua từng file riêng lẻ để tăng tốc quá trình đào tạo và cho phép mạng xem một số ví dụ khác nhau trước khi cập nhật các thông số.

Sau khi quá trình đào tạo hoàn tất, ta có thể chạy phiên trên các hình ảnh thử nghiệm. Lần này, ta đang sử dụng tỷ lệ bỏ qua keep_prob1.0 đảm bảo tất cả các đơn vị đang hoạt động trong quá trình thử nghiệm.

Thêm mã này vào file :

main.py
... test_accuracy = sess.run(accuracy, feed_dict={X: mnist.test.images, Y: mnist.test.labels, keep_prob: 1.0}) print("\nAccuracy on test set:", test_accuracy) 

Bây giờ đã đến lúc chạy chương trình của ta và xem mạng nơ-ron của ta có thể nhận ra những chữ số viết tay này chính xác đến mức nào. Lưu file main.py và thực hiện lệnh sau trong terminal để chạy tập lệnh:

  • python main.py

Bạn sẽ thấy kết quả giống như sau , mặc dù kết quả về độ chính xác và mất mát riêng lẻ có thể khác nhau một chút:

Output
Iteration 0 | Loss = 3.67079 | Accuracy = 0.140625 Iteration 100 | Loss = 0.492122 | Accuracy = 0.84375 Iteration 200 | Loss = 0.421595 | Accuracy = 0.882812 Iteration 300 | Loss = 0.307726 | Accuracy = 0.921875 Iteration 400 | Loss = 0.392948 | Accuracy = 0.882812 Iteration 500 | Loss = 0.371461 | Accuracy = 0.90625 Iteration 600 | Loss = 0.378425 | Accuracy = 0.882812 Iteration 700 | Loss = 0.338605 | Accuracy = 0.914062 Iteration 800 | Loss = 0.379697 | Accuracy = 0.875 Iteration 900 | Loss = 0.444303 | Accuracy = 0.90625 Accuracy on test set: 0.9206

Để thử và cải thiện độ chính xác của mô hình của ta hoặc để tìm hiểu thêm về tác động của việc điều chỉnh siêu tham số, ta có thể kiểm tra ảnh hưởng của việc thay đổi tỷ lệ học tập, ngưỡng bỏ học, kích thước lô và số lần lặp lại. Ta cũng có thể thay đổi số lượng đơn vị trong các lớp ẩn của bạn và thay đổi số lượng các lớp ẩn để xem các kiến trúc khác nhau làm tăng hoặc giảm độ chính xác của mô hình như thế nào.

Để chứng minh rằng mạng thực sự nhận ra các hình ảnh vẽ tay, ta hãy kiểm tra nó trên một hình ảnh duy nhất của ta .

Nếu bạn đang sử dụng máy local và bạn muốn sử dụng số vẽ tay của riêng mình, bạn có thể sử dụng editor đồ họa để tạo hình ảnh chữ số 28x28 pixel của bạn . Nếu không, bạn có thể sử dụng curl để tải hình ảnh thử nghiệm mẫu sau xuống server hoặc máy tính của bạn :

  • curl -O https://raw.githubusercontent.com/do-community/tensorflow-digit-recognition/master/test_img.png

Mở file main.py trong editor và thêm các dòng mã sau vào đầu file để nhập hai thư viện cần thiết cho thao tác hình ảnh.

main.py
import numpy as np from PIL import Image ... 

Sau đó, ở cuối file , thêm dòng mã sau để tải hình ảnh kiểm tra của chữ số viết tay:

main.py
... img = np.invert(Image.open("test_img.png").convert('L')).ravel() 

Chức năng open của Thư viện Image tải hình ảnh thử nghiệm dưới dạng một mảng 4D chứa ba kênh màu RGB và độ trong suốt Alpha. Đây không phải là biểu diễn giống như ta đã sử dụng trước đây khi đọc trong tập dữ liệu với TensorFlow, vì vậy ta cần thực hiện thêm một số công việc để trùng với định dạng.

Đầu tiên, ta sử dụng hàm convert với tham số L để giảm biểu diễn 4D RGBA thành một kênh màu thang độ xám. Ta lưu trữ nó dưới dạng một mảng numpy và đảo ngược nó bằng cách sử dụng np.invert , bởi vì ma trận hiện tại biểu thị màu đen là 0 và màu trắng là 255, trong khi ta cần điều ngược lại. Cuối cùng, ta gọi ravel để làm phẳng mảng.

Bây giờ, dữ liệu hình ảnh đã được cấu trúc chính xác, ta có thể chạy một phiên theo cách giống như trước đây, nhưng lần này chỉ cấp dữ liệu trong một hình ảnh duy nhất để thử nghiệm.

Thêm mã sau vào file của bạn để kiểm tra hình ảnh và in nhãn đã xuất.

main.py
... prediction = sess.run(tf.argmax(output_layer, 1), feed_dict={X: [img]}) print ("Prediction for test image:", np.squeeze(prediction)) 

Hàm np.squeeze được gọi trên dự đoán để trả về một số nguyên duy nhất từ mảng (nghĩa là đi từ [2] đến 2). Kết quả kết quả chứng tỏ rằng mạng đã nhận dạng hình ảnh này là chữ số 2.

Output
Prediction for test image: 2

Bạn có thể thử kiểm tra mạng với các hình ảnh phức tạp hơn –– các chữ số trông giống các chữ số khác, chẳng hạn hoặc các chữ số được vẽ kém hoặc không chính xác –– để xem giá cước của nó như thế nào.

Kết luận

Trong hướng dẫn này, bạn đã đào tạo thành công mạng nơ-ron để phân loại tập dữ liệu MNIST với độ chính xác khoảng 92% và kiểm tra nó trên hình ảnh của bạn . Nghiên cứu hiện đại đạt được khoảng 99% về cùng một vấn đề này, sử dụng các kiến trúc mạng phức tạp hơn liên quan đến các lớp phức hợp. Chúng sử dụng cấu trúc 2D của hình ảnh để thể hiện nội dung tốt hơn, không giống như phương pháp của ta là làm phẳng tất cả các pixel thành một vectơ gồm 784 đơn vị. Bạn có thể đọc thêm về chủ đề này trên trang web TensorFlow , và xem các bài nghiên cứu chi tiết kết quả chính xác nhất trên trang web MNIST .

Giờ bạn đã biết cách xây dựng và đào tạo mạng nơ-ron, bạn có thể thử và sử dụng cách triển khai này trên dữ liệu của riêng mình hoặc thử nghiệm nó trên các tập dữ liệu phổ biến khác như Số nhà của Chế độ xem phố của Google hoặc tập dữ liệu CIFAR-10 để có hình ảnh tổng quát hơn sự công nhận.


Tags:

Các tin liên quan