1. Tổng quan
Trong lớp học lập trình này, bạn sẽ tìm hiểu cách tạo, huấn luyện và điều chỉnh mạng nơron tích chập của riêng mình từ đầu bằng Keras và Tensorflow 2. Giờ đây, bạn có thể thực hiện việc này trong vài phút bằng sức mạnh của TPU. Bạn cũng sẽ khám phá nhiều cách tiếp cận từ phương pháp học chuyển giao rất đơn giản sang các kiến trúc tích chập hiện đại như Squeezenet. Phòng thí nghiệm này bao gồm các nội dung giải thích lý thuyết về mạng nơron và là một điểm xuất phát phù hợp cho các nhà phát triển muốn tìm hiểu về học sâu.
Việc đọc các bài viết học sâu có thể khó và khó hiểu. Hãy cùng tìm hiểu thực tế về kiến trúc mạng nơron tích chập hiện đại.
Kiến thức bạn sẽ học được
- Để sử dụng Keras và Bộ xử lý tensor (TPU) nhằm xây dựng mô hình tuỳ chỉnh nhanh hơn.
- Sử dụng API tf.data.Dataset và định dạng TFRecord để tải dữ liệu huấn luyện một cách hiệu quả.
- Để lừa đảo 😈, hãy dùng phương pháp học chuyển giao thay vì tự xây dựng mô hình của riêng bạn.
- Sử dụng kiểu mô hình chức năng và tuần tự Keras.
- Để xây dựng thuật toán phân loại Keras của riêng bạn bằng lớp softmax và tổn thất entropy.
- Để tinh chỉnh mô hình của bạn bằng một lựa chọn tốt về các lớp tích chập.
- Để khám phá các ý tưởng về cấu trúc convnet hiện đại như mô-đun, phương pháp gộp trung bình toàn cục, v.v.
- Để tạo một mạng nơron kết hợp hiện đại và đơn giản bằng cách sử dụng cấu trúc Squeezenet.
Phản hồi
Nếu bạn thấy có thiếu sót trong lớp học lập trình này, vui lòng cho chúng tôi biết. Bạn có thể cung cấp ý kiến phản hồi thông qua các vấn đề trên GitHub [ feedback link].
2. Bắt đầu nhanh với Google Colaboratory
Phòng thí nghiệm này sử dụng tính năng Cộng tác của Google và bạn không cần phải thiết lập. Bạn có thể chạy ứng dụng này từ Chromebook. Vui lòng mở tệp bên dưới rồi thực thi các ô để làm quen với sổ tay Colab.
Chọn phần phụ trợ TPU
Trong trình đơn Colab, hãy chọn Thời gian chạy > Thay đổi loại thời gian chạy rồi chọn TPU. Trong lớp học lập trình này, bạn sẽ sử dụng một TPU (Bộ xử lý tensor) mạnh mẽ được hỗ trợ để huấn luyện tăng tốc phần cứng. Kết nối với môi trường thời gian chạy sẽ tự động diễn ra trong lần thực thi đầu tiên, hoặc bạn có thể sử dụng nút "Kết nối" ở góc trên bên phải.
Thực thi sổ tay
Thực thi lần lượt từng ô bằng cách nhấp vào một ô và sử dụng Shift-ENTER. Bạn cũng có thể chạy toàn bộ sổ tay bằng cách chọn Thời gian chạy > Chạy tất cả
Mục lục
Tất cả sổ tay đều có mục lục. Bạn có thể mở mục này bằng mũi tên màu đen ở bên trái.
Các ô bị ẩn
Một số ô sẽ chỉ hiển thị tiêu đề. Đây là một tính năng của sổ tay dành riêng cho Colab. Bạn có thể nhấp đúp vào chúng để xem mã bên trong nhưng thường không được thú vị lắm. Thường có các hàm hỗ trợ hoặc trực quan hoá. Bạn vẫn cần chạy các ô này để xác định các hàm bên trong.
Xác thực
Colab có thể truy cập vào các bộ chứa riêng tư trên Google Cloud Storage của bạn, miễn là bạn xác thực bằng một tài khoản được uỷ quyền. Đoạn mã trên sẽ kích hoạt quá trình xác thực.
3. [THÔNG TIN] Đơn vị xử lý Tensor là gì?
Tóm tắt
Mã để huấn luyện mô hình trên TPU trong Keras (và quay lại GPU hoặc CPU nếu không có TPU):
try: # detect TPUs
tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()
strategy = tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
strategy = tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines
# use TPUStrategy scope to define model
with strategy.scope():
model = tf.keras.Sequential( ... )
model.compile( ... )
# train model normally on a tf.data.Dataset
model.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)
Hôm nay, chúng tôi sẽ dùng TPU để xây dựng và tối ưu hoá một thuật toán phân loại hoa với tốc độ tương tác (số phút mỗi lượt chạy huấn luyện).
Tại sao nên chọn TPU?
GPU hiện đại được sắp xếp xung quanh các "lõi" có thể lập trình, một cấu trúc rất linh hoạt cho phép GPU xử lý nhiều tác vụ như kết xuất 3D, học sâu, mô phỏng vật lý, v.v. Mặt khác, TPU ghép nối một bộ xử lý vectơ cổ điển với một đơn vị nhân ma trận chuyên dụng và vượt trội trong mọi tác vụ mà phép nhân ma trận lớn chiếm ưu thế, chẳng hạn như mạng nơron.
Hình minh hoạ: một lớp mạng nơron dày đặc dưới dạng phép nhân ma trận, với một lô gồm 8 hình ảnh được xử lý qua mạng nơron cùng một lúc. Vui lòng chạy qua một phép nhân dòng x cột để xác minh rằng phép nhân này thực sự đang thực hiện phép cộng trọng số của tất cả các giá trị pixel của một hình ảnh. Các lớp Convolutional cũng có thể được biểu diễn dưới dạng phép nhân ma trận, mặc dù phức tạp hơn một chút ( giải thích tại đây, trong phần 1).
Phần cứng
MXU và VPU
Lõi TPU v2 được tạo thành từ Đơn vị nhân ma trận (MXU) chạy phép nhân ma trận và Bộ xử lý vectơ (VPU) cho tất cả các tác vụ khác như kích hoạt, mềm tối đa, v.v. VPU xử lý các phép tính float32 và int32. Mặt khác, MXU hoạt động ở định dạng dấu phẩy động 16-32 bit có độ chính xác hỗn hợp.
Dấu phẩy động có độ chính xác kết hợp và bfloat16
MXU tính các phép nhân ma trận bằng cách sử dụng đầu vào bfloat16 và đầu ra float32. Việc tích luỹ trung gian được thực hiện với độ chính xác float32.
Quá trình huấn luyện mạng nơron thường có khả năng chống lại nhiễu do độ chính xác của dấu phẩy động bị giảm. Có những trường hợp mà nhiễu thậm chí còn giúp trình tối ưu hoá hội tụ. Độ chính xác dấu phẩy động 16 bit thường được dùng để tăng tốc tính toán, nhưng định dạng float16 và float32 có phạm vi rất khác nhau. Việc giảm độ chính xác từ float32 xuống float16 thường dẫn đến tình trạng tràn và thiếu dữ liệu. Có các giải pháp nhưng thường phải làm thêm việc để float16 hoạt động.
Đó là lý do Google giới thiệu định dạng bfloat16 trong TPU. bfloat16 là một float32 bị cắt bớt với số mũ và phạm vi giống hệt với float32. Điều này, cùng với việc TPU tính toán phép nhân ma trận ở độ chính xác kết hợp với đầu vào bfloat16 nhưng đầu ra float32, có nghĩa là thường thì bạn không cần thay đổi mã để hưởng lợi từ hiệu suất tăng lên khi giảm độ chính xác.
Mảng tâm thu
MXU triển khai các phép nhân ma trận trong phần cứng bằng cách sử dụng kiến trúc được gọi là "mảng tâm thu", trong đó các phần tử dữ liệu chuyển qua một mảng các đơn vị tính toán phần cứng. (Trong y học, "tâm thu" đề cập đến các cơn co thắt tim và dòng máu, ở đây là dòng dữ liệu.)
Phần tử cơ bản của phép nhân ma trận là tích dấu chấm giữa một đường của một ma trận và một cột của ma trận khác (xem hình minh hoạ ở đầu phần này). Đối với phép nhân ma trận Y=X*W, một phần tử của kết quả sẽ là:
Y[2,0] = X[2,0]*W[0,0] + X[2,1]*W[1,0] + X[2,2]*W[2,0] + ... + X[2,n]*W[n,0]
Trên GPU, người ta sẽ lập trình sản phẩm chấm này thành một "lõi" GPU rồi thực thi trên số lượng "lõi" có sẵn song song để thử và tính toán mọi giá trị của ma trận thu được cùng một lúc. Nếu ma trận thu được có kích thước 128x128, thì bạn cần có 128x128=16K "lõi", điều này thường không thể thực hiện được. Các GPU lớn nhất có khoảng 4.000 lõi. Mặt khác, TPU sử dụng phần cứng tối thiểu cho các đơn vị điện toán trong MXU: chỉ có bfloat16 x bfloat16 => float32
bộ tích luỹ nhân, không có gì khác. Các phép tính này nhỏ đến mức TPU có thể triển khai 16K phép tính trong một MXU 128x128 và xử lý phép nhân ma trận này cùng một lúc.
Hình minh hoạ: mảng tâm thu MXU. Các phần tử điện toán là bộ tích luỹ nhân. Các giá trị của một ma trận được tải vào mảng (các dấu chấm màu đỏ). Các giá trị của ma trận khác sẽ chảy qua mảng (các chấm màu xám). Các đường dọc sẽ truyền giá trị lên trên. Các đường ngang truyền tổng một phần. Bên phải là một bài tập dành cho người dùng để xác minh rằng khi dữ liệu di chuyển qua mảng, bạn sẽ nhận được kết quả của phép nhân ma trận ở phía bên phải.
Ngoài ra, trong khi các tích vô hướng đang được tính toán trong một MXU, các tổng trung gian chỉ di chuyển giữa các đơn vị điện toán liền kề. Chúng không cần được lưu trữ và truy xuất vào/từ bộ nhớ hoặc thậm chí không cần tệp đăng ký. Kết quả cuối cùng là cấu trúc mảng tâm thu TPU có mật độ và công suất đáng kể, cũng như lợi thế về tốc độ không thể bỏ qua so với GPU khi tính toán phép nhân ma trận.
Cloud TPU
Khi yêu cầu một "TPU trên đám mây phiên bản 2" trên Google Cloud Platform, bạn sẽ nhận được một máy ảo (VM) có bo mạch TPU gắn PCI. Bảng TPU có 4 chip TPU lõi kép. Mỗi lõi TPU có một VU (Bộ xử lý vectơ) và một Đơn vị nhân matriX (MatriX nhân) 128x128. Sau đó, "Cloud TPU" này thường được kết nối thông qua mạng với máy ảo đã yêu cầu. Vì vậy, toàn bộ hình ảnh sẽ có dạng như sau:
Hình minh hoạ: máy ảo của bạn có trình tăng tốc "Cloud TPU" được gắn mạng. Bản thân "Cloud TPU" được tạo thành từ một máy ảo có một bo mạch TPU gắn PCI với 4 chip TPU lõi kép trên đó.
Nhóm TPU
Trong các trung tâm dữ liệu của Google, TPU được kết nối với một kết nối điện toán hiệu suất cao (HPC). Nhờ vậy, chúng có thể xuất hiện như một trình tăng tốc rất lớn. Google gọi chúng là các nhóm và chúng có thể bao gồm tối đa 512 lõi TPU v2 hoặc 2048 lõi TPU v3.
Hình minh hoạ: một nhóm TPU phiên bản 3. Các bo mạch và giá đỡ TPU được kết nối thông qua kết nối HPC.
Trong quá trình huấn luyện, các độ dốc được trao đổi giữa các nhân TPU bằng thuật toán tất cả đều giảm ( giải thích rõ về thuật toán tất cả đều giảm tại đây). Mô hình đang được huấn luyện có thể tận dụng phần cứng bằng cách huấn luyện trên các lô lớn.
Hình minh hoạ: đồng bộ hoá các độ dốc trong quá trình huấn luyện bằng thuật toán rút gọn tất cả trên mạng HPC lưới hình xuyến 2D của Google TPU.
Phần mềm
Đào tạo theo lô lớn
Kích thước lô lý tưởng cho TPU là 128 mục dữ liệu trên mỗi lõi TPU, nhưng phần cứng đã có thể cho thấy mức sử dụng hiệu quả từ 8 mục dữ liệu trên mỗi lõi TPU. Hãy nhớ rằng một Cloud TPU có 8 nhân.
Trong lớp học lập trình này, chúng ta sẽ sử dụng Keras API. Trong Keras, lô bạn chỉ định là kích thước lô chung cho toàn bộ TPU. Các lô của bạn sẽ tự động được chia thành 8 và chạy trên 8 lõi của TPU.
Để biết thêm các mẹo về hiệu suất, hãy xem Hướng dẫn về hiệu suất của TPU. Đối với các kích thước lô rất lớn, bạn có thể cần phải đặc biệt chú ý trong một số mô hình. Hãy xem LARSOptimizer để biết thêm chi tiết.
Nâng cao: XLA
Các chương trình Tensorflow xác định các đồ thị tính toán. TPU không trực tiếp chạy mã Python mà chạy biểu đồ tính toán do chương trình Tensorflow xác định. Trong trường hợp này, một trình biên dịch có tên là XLA (trình biên dịch Đại số tuyến tính tăng tốc) sẽ biến đổi đồ thị Tensorflow của các nút tính toán thành mã máy TPU. Trình biên dịch này cũng thực hiện nhiều hoạt động tối ưu hoá nâng cao trên mã và bố cục bộ nhớ của bạn. Quá trình biên dịch tự động diễn ra khi công việc được gửi đến TPU. Bạn không cần phải đưa XLA vào chuỗi bản dựng của mình một cách rõ ràng.
Hình minh hoạ: để chạy trên TPU, trước tiên, đồ thị tính toán do chương trình Tensorflow xác định sẽ được dịch sang biểu diễn XLA (trình biên dịch đại số tuyến tính tăng tốc), sau đó được XLA biên dịch thành mã máy TPU.
Sử dụng TPU trong Keras
TPU được hỗ trợ thông qua API Keras kể từ Tensorflow 2.1. Tính năng hỗ trợ Keras hoạt động trên TPU và các nhóm TPU. Sau đây là một ví dụ hoạt động trên TPU, GPU và CPU:
try: # detect TPUs
tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()
strategy = tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
strategy = tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines
# use TPUStrategy scope to define model
with strategy.scope():
model = tf.keras.Sequential( ... )
model.compile( ... )
# train model normally on a tf.data.Dataset
model.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)
Trong đoạn mã này:
TPUClusterResolver().connect()
tìm thấy TPU trên mạng. API này hoạt động mà không cần tham số trên hầu hết hệ thống của Google Cloud (công việc của Nền tảng AI, Colaboratory, Kubeflow, máy ảo học sâu được tạo thông qua tiện ích "ctpu up"). Các hệ thống này biết vị trí của TPU nhờ biến môi trường TPU_NAME. Nếu bạn tạo TPU theo cách thủ công, hãy đặt biến môi trường TPU_NAME trên máy ảo mà bạn đang sử dụng hoặc gọiTPUClusterResolver
bằng các tham số rõ ràng:TPUClusterResolver(tp_uname, zone, project)
TPUStrategy
là phần triển khai thuật toán phân phối và đồng bộ hoá độ dốc "tất cả đều giảm".- Chiến lược được áp dụng theo phạm vi. Mô hình phải được xác định trong phạm vi chiến lược().
- Hàm
tpu_model.fit
cần một đối tượng tf.data.Dataset làm dữ liệu đầu vào để huấn luyện TPU.
Các thao tác phổ biến khi chuyển TPU
- Mặc dù có nhiều cách tải dữ liệu trong mô hình Tensorflow, nhưng đối với TPU, bạn bắt buộc phải sử dụng API
tf.data.Dataset
. - TPU rất nhanh và việc nhập dữ liệu thường trở thành nút thắt cổ chai khi chạy trên các TPU đó. Bạn có thể sử dụng các công cụ để phát hiện điểm tắc nghẽn dữ liệu và các mẹo khác về hiệu suất trong Hướng dẫn về hiệu suất của TPU.
- Số int8 hoặc int16 được coi là int32. TPU không có phần cứng số nguyên hoạt động dưới 32 bit.
- Một số thao tác Tensorflow không được hỗ trợ. Danh sách này có tại đây. Tin vui là giới hạn này chỉ áp dụng cho mã huấn luyện, tức là truyền dữ liệu qua lại qua mô hình của bạn. Bạn vẫn có thể sử dụng tất cả các thao tác Tensorflow trong quy trình nhập dữ liệu vì quy trình này sẽ được thực thi trên CPU.
tf.py_func
không được hỗ trợ trên TPU.
4. Đang tải dữ liệu
Chúng ta sẽ làm việc với một tập dữ liệu gồm các bức ảnh hoa. Mục tiêu là tìm hiểu cách phân loại chúng thành 5 loại hoa. Quá trình tải dữ liệu được thực hiện bằng API tf.data.Dataset
. Trước tiên, hãy cùng tìm hiểu về API.
Thực hành
Vui lòng mở sổ tay dưới đây, thực thi các ô (Shift-ENTER) và làm theo hướng dẫn ở bất cứ nơi nào bạn thấy nhãn "CẦN CÔNG VIỆC".
Fun with tf.data.Dataset (playground).ipynb
Thông tin khác
Giới thiệu về tập dữ liệu "flowers"
Tập dữ liệu này được sắp xếp trong 5 thư mục. Mỗi thư mục chứa hoa của một loại. Các thư mục có tên là hoa hướng dương, hoa cúc, bồ công anh, hoa tulip và hoa hồng. Dữ liệu được lưu trữ trong một bộ chứa công khai trên Google Cloud Storage. Phần trích dẫn:
gs://flowers-public/sunflowers/5139971615_434ff8ed8b_n.jpg
gs://flowers-public/daisy/8094774544_35465c1c64.jpg
gs://flowers-public/sunflowers/9309473873_9d62b9082e.jpg
gs://flowers-public/dandelion/19551343954_83bb52f310_m.jpg
gs://flowers-public/dandelion/14199664556_188b37e51e.jpg
gs://flowers-public/tulips/4290566894_c7f061583d_m.jpg
gs://flowers-public/roses/3065719996_c16ecd5551.jpg
gs://flowers-public/dandelion/8168031302_6e36f39d87.jpg
gs://flowers-public/sunflowers/9564240106_0577e919da_n.jpg
gs://flowers-public/daisy/14167543177_cd36b54ac6_n.jpg
Tại sao nên dùng tf.data.Dataset?
Keras và Tensorflow chấp nhận Tập dữ liệu trong tất cả các chức năng huấn luyện và đánh giá. Sau khi bạn tải dữ liệu trong Tập dữ liệu, API này sẽ cung cấp tất cả các chức năng phổ biến hữu ích cho dữ liệu huấn luyện mạng nơron:
dataset = ... # load something (see below)
dataset = dataset.shuffle(1000) # shuffle the dataset with a buffer of 1000
dataset = dataset.cache() # cache the dataset in RAM or on disk
dataset = dataset.repeat() # repeat the dataset indefinitely
dataset = dataset.batch(128) # batch data elements together in batches of 128
AUTOTUNE = tf.data.AUTOTUNE
dataset = dataset.prefetch(AUTOTUNE) # prefetch next batch(es) while training
Bạn có thể tìm thấy các mẹo về hiệu suất và các phương pháp hay nhất về Tập dữ liệu trong bài viết này. Tài liệu tham khảo tại đây.
Thông tin cơ bản về tf.data.Dataset
Dữ liệu thường có trong nhiều tệp, ở đây là hình ảnh. Bạn có thể tạo một tập dữ liệu tên tệp bằng cách gọi:
filenames_dataset = tf.data.Dataset.list_files('gs://flowers-public/*/*.jpg')
# The parameter is a "glob" pattern that supports the * and ? wildcards.
Sau đó, bạn "ánh xạ" một hàm đến từng tên tệp. Tên tệp này thường sẽ tải và giải mã tệp thành dữ liệu thực tế trong bộ nhớ:
def decode_jpeg(filename):
bits = tf.io.read_file(filename)
image = tf.io.decode_jpeg(bits)
return image
image_dataset = filenames_dataset.map(decode_jpeg)
# this is now a dataset of decoded images (uint8 RGB format)
Cách lặp lại trên một Tập dữ liệu:
for data in my_dataset:
print(data)
Tập dữ liệu của các bộ dữ liệu
Trong phương pháp học có giám sát, tập dữ liệu huấn luyện thường bao gồm các cặp dữ liệu huấn luyện và câu trả lời chính xác. Để cho phép việc này, hàm giải mã có thể trả về các bộ dữ liệu. Sau đó, bạn sẽ có một tập dữ liệu gồm các bộ dữ liệu và các bộ dữ liệu sẽ được trả về khi bạn lặp lại tập dữ liệu đó. Các giá trị được trả về là các tensor Tensorflow sẵn sàng để mô hình của bạn sử dụng. Bạn có thể gọi .numpy()
trên chúng để xem các giá trị thô:
def decode_jpeg_and_label(filename):
bits = tf.read_file(filename)
image = tf.io.decode_jpeg(bits)
label = ... # extract flower name from folder name
return image, label
image_dataset = filenames_dataset.map(decode_jpeg_and_label)
# this is now a dataset of (image, label) pairs
for image, label in dataset:
print(image.numpy().shape, label.numpy())
Kết luận:việc tải từng hình ảnh một cách nhanh chóng!
Khi lặp lại trên tập dữ liệu này, bạn sẽ thấy rằng bạn có thể tải khoảng 1-2 hình ảnh mỗi giây. Quá chậm! Các trình tăng tốc phần cứng mà chúng tôi dùng để huấn luyện có thể duy trì tốc độ này gấp nhiều lần so với trước đây. Hãy chuyển đến phần tiếp theo để xem cách chúng tôi đạt được mục tiêu này.
Giải pháp
Dưới đây là sổ tay giải pháp. Bạn có thể sử dụng tính năng này nếu gặp khó khăn.
Fun with tf.data.Dataset (solution).ipynb
Nội dung đã đề cập
- 🤔 tf.data.Dataset.list_files
- 🤔 tf.data.Dataset.map
- 🤔 Tập dữ liệu của các bộ dữ liệu
- 😀 lặp lại qua Tập dữ liệu
Vui lòng dành chút thời gian để xem lại danh sách kiểm tra này.
5. Tải dữ liệu nhanh
Trình tăng tốc phần cứng Bộ xử lý tensor (TPU) mà chúng ta sẽ sử dụng trong lớp học này rất nhanh. Thách thức thường là cung cấp dữ liệu cho chúng đủ nhanh để chúng luôn bận rộn. Google Cloud Storage (GCS) có khả năng duy trì thông lượng rất cao, nhưng cũng giống như tất cả các hệ thống lưu trữ đám mây, việc bắt đầu kết nối sẽ làm hao tổn mạng qua lại. Do đó, việc lưu trữ dữ liệu của chúng tôi dưới dạng hàng nghìn tệp riêng lẻ không phải là điều lý tưởng. Chúng ta sẽ phân lô các tệp này thành một số lượng tệp nhỏ hơn và sử dụng sức mạnh của tf.data.Dataset để đọc song song từ nhiều tệp.
Đọc hết
Mã tải tệp hình ảnh, đổi kích thước tệp hình ảnh thành kích thước phổ biến rồi lưu trữ các tệp hình ảnh đó trên 16 tệp TFRecord có trong sổ tay sau. Vui lòng đọc nhanh qua email đó. Bạn không cần thực thi vì dữ liệu được định dạng đúng cách của TFRecord sẽ được cung cấp cho những phần còn lại của lớp học lập trình.
Flower pictures to TFRecords.ipynb
Bố cục dữ liệu lý tưởng để lưu lượng GCS tối ưu
Định dạng tệp TFRecord
Định dạng tệp ưu tiên của Tensorflow để lưu trữ dữ liệu là định dạng TFRecord dựa trên protobuf. Các định dạng chuyển đổi tuần tự khác cũng sẽ hoạt động, nhưng bạn có thể tải trực tiếp tập dữ liệu từ các tệp TFRecord bằng cách viết:
filenames = tf.io.gfile.glob(FILENAME_PATTERN)
dataset = tf.data.TFRecordDataset(filenames)
dataset = dataset.map(...) # do the TFRecord decoding here - see below
Để đạt được hiệu suất tối ưu, bạn nên sử dụng mã phức tạp hơn sau đây để đọc từ nhiều tệp TFRecord cùng một lúc. Mã này sẽ đọc song song từ N tệp và bỏ qua thứ tự dữ liệu để ưu tiên tốc độ đọc.
AUTOTUNE = tf.data.AUTOTUNE
ignore_order = tf.data.Options()
ignore_order.experimental_deterministic = False
filenames = tf.io.gfile.glob(FILENAME_PATTERN)
dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTOTUNE)
dataset = dataset.with_options(ignore_order)
dataset = dataset.map(...) # do the TFRecord decoding here - see below
Bản tóm tắt về TFRecord
Có thể lưu trữ ba loại dữ liệu trong TFRecords: chuỗi byte (danh sách byte), số nguyên 64 bit và số thực có độ chính xác đơn 32 bit. Các mục này luôn được lưu trữ dưới dạng danh sách, một phần tử dữ liệu sẽ là danh sách có kích thước 1. Bạn có thể sử dụng các hàm trợ giúp sau để lưu trữ dữ liệu vào TFRecords.
ghi chuỗi byte
# warning, the input is a list of byte strings, which are themselves lists of bytes
def _bytestring_feature(list_of_bytestrings):
return tf.train.Feature(bytes_list=tf.train.BytesList(value=list_of_bytestrings))
ghi số nguyên
def _int_feature(list_of_ints): # int64
return tf.train.Feature(int64_list=tf.train.Int64List(value=list_of_ints))
dấu phẩy động
def _float_feature(list_of_floats): # float32
return tf.train.Feature(float_list=tf.train.FloatList(value=list_of_floats))
viết một TFRecord, sử dụng các trình trợ giúp ở trên
# input data in my_img_bytes, my_class, my_height, my_width, my_floats
with tf.python_io.TFRecordWriter(filename) as out_file:
feature = {
"image": _bytestring_feature([my_img_bytes]), # one image in the list
"class": _int_feature([my_class]), # one class in the list
"size": _int_feature([my_height, my_width]), # fixed length (2) list of ints
"float_data": _float_feature(my_floats) # variable length list of floats
}
tf_record = tf.train.Example(features=tf.train.Features(feature=feature))
out_file.write(tf_record.SerializeToString())
Để đọc dữ liệu của TFRecords, trước tiên bạn phải khai báo bố cục của các bản ghi mà bạn đã lưu trữ. Trong phần khai báo, bạn có thể truy cập vào bất kỳ trường nào được đặt tên dưới dạng danh sách độ dài cố định hoặc danh sách độ dài thay đổi:
đọc từ TFRecords
def read_tfrecord(data):
features = {
# tf.string = byte string (not text string)
"image": tf.io.FixedLenFeature([], tf.string), # shape [] means scalar, here, a single byte string
"class": tf.io.FixedLenFeature([], tf.int64), # shape [] means scalar, i.e. a single item
"size": tf.io.FixedLenFeature([2], tf.int64), # two integers
"float_data": tf.io.VarLenFeature(tf.float32) # a variable number of floats
}
# decode the TFRecord
tf_record = tf.io.parse_single_example(data, features)
# FixedLenFeature fields are now ready to use
sz = tf_record['size']
# Typical code for decoding compressed images
image = tf.io.decode_jpeg(tf_record['image'], channels=3)
# VarLenFeature fields require additional sparse.to_dense decoding
float_data = tf.sparse.to_dense(tf_record['float_data'])
return image, sz, float_data
# decoding a tf.data.TFRecordDataset
dataset = dataset.map(read_tfrecord)
# now a dataset of triplets (image, sz, float_data)
Đoạn mã hữu ích:
đọc các phần tử dữ liệu đơn lẻ
tf.io.FixedLenFeature([], tf.string) # for one byte string
tf.io.FixedLenFeature([], tf.int64) # for one int
tf.io.FixedLenFeature([], tf.float32) # for one float
đọc danh sách phần tử có kích thước cố định
tf.io.FixedLenFeature([N], tf.string) # list of N byte strings
tf.io.FixedLenFeature([N], tf.int64) # list of N ints
tf.io.FixedLenFeature([N], tf.float32) # list of N floats
đọc một số lượng mục dữ liệu có thể thay đổi
tf.io.VarLenFeature(tf.string) # list of byte strings
tf.io.VarLenFeature(tf.int64) # list of ints
tf.io.VarLenFeature(tf.float32) # list of floats
VarLenFeature trả về một vectơ thưa thớt và bạn cần thực hiện thêm một bước sau khi giải mã TFRecord:
dense_data = tf.sparse.to_dense(tf_record['my_var_len_feature'])
Cũng có thể có các trường tuỳ chọn trong TFRecords. Nếu bạn chỉ định giá trị mặc định khi đọc một trường, thì giá trị mặc định sẽ được trả về thay vì lỗi nếu thiếu trường đó.
tf.io.FixedLenFeature([], tf.int64, default_value=0) # this field is optional
Nội dung đã đề cập
- 🤔 phân đoạn các tệp dữ liệu để truy cập nhanh từ GCS
- 😓 cách viết TFRecords. (Bạn đã quên cú pháp? Được rồi, hãy đánh dấu trang này làm bản tóm tắt)
- 🤔 tải Tập dữ liệu từ TFRecords bằng TFRecordDataset
Vui lòng dành chút thời gian để xem danh sách kiểm tra này trong đầu bạn.
6. [INFO] Thuật toán phân loại mạng nơron 101
Tóm tắt
Nếu bạn đã biết tất cả những thuật ngữ in đậm trong đoạn tiếp theo, thì bạn có thể chuyển sang bài tập tiếp theo. Nếu bạn chỉ mới bắt đầu sử dụng công nghệ học sâu, vui lòng đọc tiếp.
Đối với các mô hình được xây dựng dưới dạng một trình tự các lớp, Keras cung cấp API tuần tự. Ví dụ: một trình phân loại hình ảnh sử dụng ba lớp dày đặc có thể được viết trong Keras như sau:
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=[192, 192, 3]),
tf.keras.layers.Dense(500, activation="relu"),
tf.keras.layers.Dense(50, activation="relu"),
tf.keras.layers.Dense(5, activation='softmax') # classifying into 5 classes
])
# this configures the training of the model. Keras calls it "compiling" the model.
model.compile(
optimizer='adam',
loss= 'categorical_crossentropy',
metrics=['accuracy']) # % of correct answers
# train the model
model.fit(dataset, ... )
Mạng nơron dày đặc
Đây là mạng nơron đơn giản nhất để phân loại hình ảnh. Nó được tạo thành từ các "nơ-ron" được sắp xếp theo lớp. Lớp đầu tiên xử lý dữ liệu đầu vào và cấp dữ liệu đầu ra của nó vào các lớp khác. Nó được gọi là "dày đặc" vì mỗi nơron được kết nối với tất cả các nơron trong lớp trước.
Bạn có thể đưa hình ảnh vào một mạng như vậy bằng cách làm phẳng các giá trị RGB của tất cả các pixel của hình ảnh đó thành một vectơ dài và sử dụng hình ảnh đó làm đầu vào. Đây không phải là kỹ thuật tốt nhất để nhận dạng hình ảnh, nhưng chúng ta sẽ cải thiện kỹ thuật này sau.
nơ-ron, kích hoạt, RELU
Một "neuron" (tế bào thần kinh) tính toán tổng trọng số của tất cả các đầu vào, thêm một giá trị gọi là "độ lệch" và đưa kết quả vào thông qua một "hàm kích hoạt". Ban đầu, trọng số và độ chệch không được xác định. Các giá trị này sẽ được khởi tạo ngẫu nhiên và "học" bằng cách huấn luyện mạng nơron trên nhiều dữ liệu đã biết.
Hàm kích hoạt phổ biến nhất được gọi là RELU (Đơn vị tuyến tính được sửa đổi). Đây là một hàm rất đơn giản như bạn có thể thấy trong biểu đồ ở trên.
Kích hoạt Softmax
Mạng lưới ở trên kết thúc bằng một lớp 5 tế bào thần kinh vì chúng ta đang phân loại hoa thành 5 loại (hoa hồng, hoa tulip, bồ công anh, hoa cúc, hoa hướng dương). Các tế bào thần kinh trong các lớp trung gian được kích hoạt bằng hàm kích hoạt RELU cổ điển. Tuy nhiên, ở lớp cuối cùng, chúng ta muốn tính toán các số từ 0 đến 1 thể hiện xác suất để bông hoa này là hoa hồng, hoa tulip, v.v. Để làm được điều này, chúng tôi sẽ sử dụng chức năng kích hoạt có tên là "softmax".
Áp dụng softmax trên một vectơ được thực hiện bằng cách lấy số mũ của từng phần tử và sau đó chuẩn hoá vectơ, thường sử dụng định mức L1 (tổng các giá trị tuyệt đối) để các giá trị cộng lại bằng 1 và có thể được hiểu là xác suất.
Hệ số hao tổn entropy chéo
Giờ đây, mạng nơron của chúng ta đã tạo ra các dự đoán từ hình ảnh đầu vào, chúng ta cần đo lường độ chính xác của các dự đoán đó, tức là khoảng cách giữa những gì mạng nơron cho chúng ta biết và câu trả lời chính xác, thường được gọi là "nhãn". Hãy nhớ rằng chúng tôi có nhãn chính xác cho tất cả hình ảnh trong tập dữ liệu.
Bất kỳ khoảng cách nào cũng hoạt động, nhưng đối với các bài toán phân loại, khoảng cách được gọi là "khoảng cách entropy" là hiệu quả nhất. Chúng tôi gọi hàm này là hàm lỗi hay hàm "mất":
Phương pháp giảm độ dốc
"Huấn luyện" mạng nơron thực ra có nghĩa là sử dụng hình ảnh và nhãn huấn luyện để điều chỉnh trọng số và độ chệch sao cho giảm thiểu hàm mất entropy. Dưới đây là cách thức hoạt động.
Độ chênh lệch entropy là một hàm của trọng số, độ lệch, pixel của hình ảnh huấn luyện và lớp đã biết của hình ảnh đó.
Nếu chúng ta tính các đạo hàm riêng của entropy chéo tương đối với tất cả các trọng số và tất cả độ chệch, chúng ta sẽ có được độ dốc, được tính cho một hình ảnh, nhãn, giá trị hiện tại của trọng số và độ chệch. Hãy nhớ rằng chúng ta có thể có hàng triệu trọng số và độ lệch, vì vậy, việc tính toán độ dốc có vẻ như là một công việc rất lớn. Rất may là Tensorflow sẽ giúp chúng tôi làm việc này. Thuộc tính toán học của dải chuyển màu là nó trỏ "lên trên". Vì chúng ta muốn đi đến nơi có entropy chéo thấp, nên chúng ta sẽ đi theo hướng ngược lại. Chúng tôi cập nhật các trọng số và độ chệch theo một phần nhỏ của độ dốc. Sau đó, chúng ta làm tương tự nhiều lần bằng cách sử dụng các lô hình ảnh và nhãn huấn luyện tiếp theo trong một vòng lặp huấn luyện. Hy vọng rằng giá trị này hội tụ đến một nơi mà giá trị chéo entropy là tối thiểu, mặc dù không có gì đảm bảo rằng giá trị tối thiểu này là duy nhất.
Tạo lô nhỏ và động lượng
Bạn có thể tính toán độ dốc của mình chỉ trên một hình ảnh ví dụ và cập nhật ngay lập tức trọng số và độ chệch, nhưng làm như vậy trên một loạt, ví dụ 128 hình ảnh sẽ tạo ra một độ dốc thể hiện tốt hơn các hạn chế do các hình ảnh mẫu khác nhau áp đặt và do đó có khả năng hội tụ về phía giải pháp nhanh hơn. Kích thước của lô nhỏ là một tham số có thể điều chỉnh.
Kỹ thuật này đôi khi được gọi là "giảm độ dốc ngẫu nhiên" có một lợi ích khác và thực tế hơn: làm việc với các lô cũng có nghĩa là làm việc với các ma trận lớn hơn và các phương pháp này thường dễ tối ưu hoá trên GPU và TPU hơn.
Tuy nhiên, quá trình hội tụ vẫn có thể hơi hỗn loạn và thậm chí có thể dừng lại nếu vectơ độ dốc toàn là số 0. Điều đó có nghĩa là chúng ta đã tìm thấy giá trị tối thiểu không? Không phải lúc nào cũng vậy. Thành phần chuyển màu có thể bằng 0 ở giá trị tối thiểu hoặc tối đa. Với vectơ độ dốc có hàng triệu phần tử, nếu tất cả các phần tử đều bằng 0, xác suất mà mỗi số 0 đều tương ứng với giá trị tối thiểu và không có phần tử nào trong số đó đạt điểm tối đa là khá nhỏ. Trong không gian nhiều chiều, các điểm yên ngựa khá phổ biến và chúng ta không muốn dừng lại ở đó.
Hình minh hoạ: một điểm yên xe. Độ dốc là 0 nhưng không phải là giá trị tối thiểu theo mọi hướng. (Ghi nhận tác giả hình ảnh Wikimedia: Của Nicoguaro – Tác phẩm riêng, CC BY 3.0)
Giải pháp là thêm động lượng vào thuật toán tối ưu hoá để thuật toán có thể vượt qua các điểm an toàn mà không dừng lại.
Bảng thuật ngữ
Lô hoặc lô nhỏ: quá trình huấn luyện luôn được thực hiện trên các lô dữ liệu và nhãn huấn luyện. Làm như vậy sẽ giúp thuật toán hội tụ. Phương diện "bộ dữ liệu" thường là phương diện đầu tiên của tensor dữ liệu. Ví dụ: tensor có hình dạng [100, 192, 192, 3] chứa 100 hình ảnh có kích thước 192x192 pixel với ba giá trị mỗi pixel (RGB).
mất entropy chéo: một hàm mất đặc biệt thường dùng trong thuật toán phân loại.
lớp dày đặc: một lớp nơron trong đó mỗi nơron được kết nối với tất cả các nơron trong lớp trước.
tính năng: đầu vào của mạng nơron đôi khi được gọi là "tính năng". Nghệ thuật tìm ra những phần của tập dữ liệu (hoặc tổ hợp các phần) cần đưa vào mạng nơron để có được kết quả dự đoán chính xác được gọi là "kỹ thuật xử lý đặc điểm".
nhãn: tên khác của "lớp học" hoặc câu trả lời chính xác trong một bài toán phân loại được giám sát
tốc độ học tập: tỷ lệ độ dốc mà theo đó trọng số và độ chệch được cập nhật ở mỗi lần lặp lại của vòng lặp huấn luyện.
logits: đầu ra của một lớp tế bào thần kinh trước khi áp dụng hàm kích hoạt được gọi là "logits". Thuật ngữ này bắt nguồn từ "hàm logistic" hay còn gọi là "hàm sigmoid", từng là hàm kích hoạt phổ biến nhất. "Đầu ra của tế bào thần kinh trước hàm logistic" được rút gọn thành "logit".
loss: hàm lỗi so sánh đầu ra của mạng nơron với câu trả lời đúng
neuron: tính tổng trọng số của các đầu vào, thêm một độ lệch và truyền kết quả thông qua một hàm kích hoạt.
mã hoá một nóng: lớp 3/5 được mã hoá thành một vectơ gồm 5 phần tử, tất cả đều là số 0, ngoại trừ phần thứ 3 là 1.
relu: đơn vị tuyến tính đã chỉnh sửa. Một hàm kích hoạt phổ biến cho nơron.
sigmoid: một hàm kích hoạt khác từng phổ biến và hiện vẫn hữu ích trong các trường hợp đặc biệt.
softmax: một hàm kích hoạt đặc biệt hoạt động trên một vectơ, tăng hiệu số giữa thành phần lớn nhất và tất cả các thành phần khác, đồng thời chuẩn hoá vectơ có tổng bằng 1 để có thể hiểu vectơ đó là vectơ xác suất. Được dùng làm bước cuối cùng trong các thuật toán phân loại.
tensor: "Tensor" giống như một ma trận nhưng có số lượng chiều tuỳ ý. Tensor 1 chiều là một vectơ. Tensor 2 chiều là một ma trận. Và sau đó bạn có thể có các tensor với 3, 4, 5 hoặc nhiều chiều.
7. Học chuyển
Đối với vấn đề phân loại hình ảnh, các lớp dày đặc có thể sẽ không đủ. Chúng ta phải tìm hiểu về các lớp tích chập và nhiều cách để sắp xếp chúng.
Nhưng chúng ta cũng có thể sử dụng một lối tắt! Bạn có thể tải xuống các mạng nơron tích chập đã được huấn luyện đầy đủ. Bạn có thể cắt lớp cuối cùng của chúng, phần đầu phân loại softmax và thay thế bằng của riêng bạn. Tất cả các trọng số và độ lệch đã huấn luyện vẫn giữ nguyên, bạn chỉ cần huấn luyện lại lớp softmax mà bạn thêm. Kỹ thuật này được gọi là học chuyển giao và thật đáng kinh ngạc, nó hoạt động miễn là tập dữ liệu mà mạng nơron được huấn luyện trước "đủ gần" với tập dữ liệu của bạn.
Tự thực hành
Vui lòng mở sổ tay sau, thực thi các ô (Shift-ENTER) và làm theo hướng dẫn bất cứ khi nào bạn thấy nhãn "WORK REQUIRED" (CẦN LÀM).
Keras Flowers transfer learning (playground).ipynb
Thông tin khác
Với công nghệ học chuyển giao, bạn được hưởng lợi từ cả kiến trúc mạng nơron tích chập nâng cao do các nhà nghiên cứu hàng đầu phát triển và từ quá trình đào tạo trước về một tập dữ liệu hình ảnh khổng lồ. Trong trường hợp này, chúng ta sẽ chuyển đổi việc học từ một mạng được huấn luyện trên ImageNet, một cơ sở dữ liệu hình ảnh chứa nhiều cây và cảnh ngoài trời, khá gần với hoa.
Hình minh hoạ: sử dụng một mạng nơron tích chập phức tạp, đã được huấn luyện, dưới dạng hộp đen, chỉ huấn luyện lại phần phân loại. Đây là phương pháp học chuyển giao. Chúng ta sẽ xem cách hoạt động của các lớp convolutional phức tạp này sau. Hiện tại, vấn đề là do người khác.
Chuyển giao nội dung học tập trong Keras
Trong Keras, bạn có thể tạo thực thể cho một mô hình huấn luyện trước từ bộ sưu tập tf.keras.applications.*
. Ví dụ: MobileNet V2 là một cấu trúc tích chập rất tốt và có kích thước hợp lý. Bằng cách chọn include_top=False
, bạn sẽ nhận được mô hình được huấn luyện trước mà không có lớp softmax cuối cùng để bạn có thể thêm lớp của riêng mình:
pretrained_model = tf.keras.applications.MobileNetV2(input_shape=[*IMAGE_SIZE, 3], include_top=False)
pretrained_model.trainable = False
model = tf.keras.Sequential([
pretrained_model,
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(5, activation='softmax')
])
Ngoài ra, hãy lưu ý đến chế độ cài đặt pretrained_model.trainable = False
. Phương pháp này cố định các trọng số và độ chệch của mô hình luyện sẵn để bạn chỉ huấn luyện lớp softmax. Việc này thường tương đối ít trọng số và có thể được thực hiện nhanh chóng mà không cần đến một tập dữ liệu quá lớn. Tuy nhiên, nếu bạn có nhiều dữ liệu, tính năng học chuyển có thể hoạt động hiệu quả hơn nữa với pretrained_model.trainable = True
. Sau đó, các trọng số đã huấn luyện trước sẽ cho biết những giá trị ban đầu rất tốt và bạn vẫn có thể điều chỉnh các trọng số này bằng quá trình huấn luyện cho phù hợp hơn với bài tập của mình.
Cuối cùng, hãy lưu ý rằng lớp Flatten()
được chèn trước lớp softmax dày đặc. Các lớp dày đặc hoạt động trên các vectơ phẳng của dữ liệu nhưng chúng ta không biết đó có phải là điều mà mô hình huấn luyện trước trả về hay không. Đó là lý do chúng ta cần làm phẳng. Trong chương tiếp theo, khi tìm hiểu sâu về kiến trúc tích chập, chúng ta sẽ giải thích định dạng dữ liệu mà lớp tích chập trả về.
Bạn sẽ đạt được độ chính xác gần 75% với phương pháp này.
Giải pháp
Dưới đây là sổ tay giải pháp. Bạn có thể sử dụng tính năng này nếu gặp khó khăn.
Keras Flowers transfer learning (solution).ipynb
Nội dung đã đề cập
- 🤔 Cách viết thuật toán phân loại trong Keras
- 🤓 được định cấu hình bằng lớp cuối softmax và tổn thất entropy chéo
- 😈 Chuyển đổi nội dung học tập
- 🤔 Huấn luyện mô hình đầu tiên
- 🧐 Theo dõi mức độ hao tổn và độ chính xác trong quá trình huấn luyện
Vui lòng dành chút thời gian để xem danh sách kiểm tra này trong đầu bạn.
8. [INFO] Mạng nơron tích chập
Tóm tắt
Nếu đã biết tất cả các thuật ngữ được in đậm trong đoạn tiếp theo, bạn có thể chuyển sang bài tập tiếp theo. Nếu bạn chỉ mới bắt đầu sử dụng mạng nơron tích chập, vui lòng đọc tiếp.
Hình minh hoạ: lọc một hình ảnh có hai bộ lọc liên tiếp, có kích thước 4x4x3=48 trọng số có thể học.
Sau đây là giao diện của một mạng nơron tích chập đơn giản trong Keras:
model = tf.keras.Sequential([
# input: images of size 192x192x3 pixels (the three stands for RGB channels)
tf.keras.layers.Conv2D(kernel_size=3, filters=24, padding='same', activation='relu', input_shape=[192, 192, 3]),
tf.keras.layers.Conv2D(kernel_size=3, filters=24, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=2),
tf.keras.layers.Conv2D(kernel_size=3, filters=12, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=2),
tf.keras.layers.Conv2D(kernel_size=3, filters=6, padding='same', activation='relu'),
tf.keras.layers.Flatten(),
# classifying into 5 categories
tf.keras.layers.Dense(5, activation='softmax')
])
model.compile(
optimizer='adam',
loss= 'categorical_crossentropy',
metrics=['accuracy'])
Mạng nơron tích chập 101
Trong một lớp của mạng nơron tích chập, một "nơron" thực hiện phép cộng trọng số của các pixel ngay phía trên nó, chỉ trên một vùng nhỏ của hình ảnh. Lớp này thêm một độ lệch và truyền tổng số đó thông qua một hàm kích hoạt, giống như một tế bào thần kinh trong một lớp dày đặc thông thường. Sau đó, thao tác này được lặp lại trên toàn bộ hình ảnh với cùng trọng số. Hãy nhớ rằng trong các lớp dày đặc, mỗi tế bào thần kinh đều có trọng số riêng. Ở đây, một "vùng" trọng số trượt qua hình ảnh theo cả hai hướng ("tích chập"). Kết quả có nhiều giá trị bằng số pixel trong hình ảnh (mặc dù cần có một số khoảng đệm ở các cạnh). Đây là một thao tác lọc, sử dụng bộ lọc có trọng số 4x4x3=48.
Tuy nhiên, 48 trọng số là không đủ. Để thêm nhiều bậc tự do hơn, chúng ta lặp lại cùng một phép toán với một bộ trọng số mới. Thao tác này sẽ tạo ra một tập hợp đầu ra mới của bộ lọc. Hãy gọi nó là "kênh" của các đầu ra bằng cách tương tự với các kênh R,G,B trong hình ảnh đầu vào.
Hai (hoặc nhiều) tập hợp trọng số có thể được tổng hợp thành một tensor bằng cách thêm một phương diện mới. Điều này cho chúng ta hình dạng chung của tensor trọng số cho một lớp tích chập. Do số lượng kênh đầu vào và đầu ra là tham số, nên chúng ta có thể bắt đầu xếp chồng và tạo chuỗi các lớp tích chập.
Hình minh hoạ: một mạng nơron tích chập biến đổi các "khối" dữ liệu thành các "khối" dữ liệu khác.
Lớp phủ có bước, tích chập tối đa
Bằng cách thực hiện các phép tích chập với một bước tiến 2 hoặc 3, chúng ta cũng có thể thu nhỏ khối dữ liệu thu được theo kích thước ngang của nó. Có hai cách phổ biến để thực hiện việc này:
- Động lực xoá bỏ theo bước: một bộ lọc trượt như trên nhưng có bước >1
- Gộp tối đa: một cửa sổ trượt áp dụng thao tác MAX (thường là trên 2x2 bản vá, lặp lại mỗi 2 pixel)
Hình minh hoạ: việc trượt cửa sổ tính toán thêm 3 pixel sẽ dẫn đến ít giá trị đầu ra hơn. Động tác tích chập theo bước hoặc tích chập tối đa (tối đa trên cửa sổ 2x2 trượt theo bước 2) là một cách thu nhỏ khối dữ liệu theo phương diện ngang.
Thuật toán phân loại dựa trên môi trường
Cuối cùng, chúng tôi đính kèm phần đầu phân loại bằng cách làm phẳng khối dữ liệu cuối cùng và đưa khối này qua một lớp dày đặc, được kích hoạt bằng max mềm. Một thuật toán phân loại tích chập điển hình có thể có dạng như sau:
Hình minh hoạ: một thuật toán phân loại hình ảnh sử dụng lớp tích chập và lớp mềm max. Lớp này sử dụng bộ lọc 3x3 và 1x1. Các lớp maxpool lấy tối đa nhóm gồm 2x2 điểm dữ liệu. Phần phân loại được triển khai bằng một lớp dày đặc với hoạt động kích hoạt softmax.
Ở Keras
Ngăn xếp tích chập minh hoạ ở trên có thể được viết bằng Keras như sau:
model = tf.keras.Sequential([
# input: images of size 192x192x3 pixels (the three stands for RGB channels)
tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu', input_shape=[192, 192, 3]),
tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=2),
tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=2),
tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=2),
tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=2),
tf.keras.layers.Conv2D(kernel_size=3, filters=16, padding='same', activation='relu'),
tf.keras.layers.Conv2D(kernel_size=1, filters=8, padding='same', activation='relu'),
tf.keras.layers.Flatten(),
# classifying into 5 categories
tf.keras.layers.Dense(5, activation='softmax')
])
model.compile(
optimizer='adam',
loss= 'categorical_crossentropy',
metrics=['accuracy'])
9. Mạng chuyển đổi tuỳ chỉnh
Thực hành
Hãy cùng xây dựng và huấn luyện một mạng nơron tích chập từ đầu. Việc sử dụng TPU sẽ cho phép chúng ta lặp lại rất nhanh. Vui lòng mở sổ tay sau, thực thi các ô (Shift-ENTER) và làm theo hướng dẫn bất cứ khi nào bạn thấy nhãn "WORK REQUIRED" (CẦN LÀM).
Keras_Flowers_TPU (playground).ipynb
Mục tiêu là vượt qua độ chính xác 75% của mô hình học chuyển đổi. Mô hình đó có một lợi thế là được huấn luyện trước trên một tập dữ liệu gồm hàng triệu hình ảnh, trong khi chúng ta chỉ có 3670 hình ảnh ở đây. Ít nhất thì bạn có thể so khớp được không?
Thông tin khác
Có bao nhiêu lớp, kích thước bao nhiêu?
Việc chọn kích thước lớp không chỉ là nghệ thuật mà còn là một môn khoa học. Bạn phải tìm sự cân bằng phù hợp giữa việc có quá ít và quá nhiều tham số (trọng số và độ lệch). Với quá ít trọng số, mạng nơron không thể biểu thị sự phức tạp của các hình bông hoa. Nếu có quá nhiều, mô hình có thể dễ bị "quá thích ứng", tức là chuyên biệt hoá cho các hình ảnh huấn luyện và không thể khái quát hoá. Với nhiều tham số, mô hình cũng sẽ chậm được huấn luyện. Trong Keras, hàm model.summary()
cho thấy cấu trúc và số lượng tham số của mô hình:
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 192, 192, 16) 448
_________________________________________________________________
conv2d_1 (Conv2D) (None, 192, 192, 30) 4350
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 96, 96, 30) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 96, 96, 60) 16260
_________________________________________________________________
...
_________________________________________________________________
global_average_pooling2d (Gl (None, 130) 0
_________________________________________________________________
dense (Dense) (None, 90) 11790
_________________________________________________________________
dense_1 (Dense) (None, 5) 455
=================================================================
Total params: 300,033
Trainable params: 300,033
Non-trainable params: 0
_________________________________________________________________
Một vài mẹo:
- Việc có nhiều lớp chính là điều làm cho mạng nơron "sâu" trở nên hiệu quả. Đối với bài toán nhận dạng hoa đơn giản này, bạn nên thêm 5 đến 10 lớp.
- Sử dụng các bộ lọc nhỏ. Thông thường, bộ lọc 3x3 sẽ phù hợp với mọi nơi.
- Bộ lọc 1x1 cũng có thể được sử dụng và rẻ. Chúng không thực sự "lọc" bất cứ thứ gì ngoài việc tính toán các tổ hợp tuyến tính của các kênh. Hãy thay thế bằng các bộ lọc thực. (Tìm hiểu thêm về "lớp phủ 1x1" trong phần tiếp theo.)
- Đối với vấn đề phân loại như thế này, hãy thu thập mẫu thường xuyên với các lớp gộp tối đa (hoặc tích chập có sải chân >1). Bạn không quan tâm đến vị trí của hoa, chỉ quan tâm đó là hoa hồng hay hoa bồ công anh, vì vậy, việc mất thông tin x và y không quan trọng và việc lọc các khu vực nhỏ hơn sẽ rẻ hơn.
- Số lượng bộ lọc thường trở nên tương tự như số lượng lớp ở cuối mạng (tại sao? hãy xem thủ thuật "thu thập trung bình toàn cục" bên dưới). Nếu bạn phân loại thành hàng trăm lớp, hãy tăng dần số lượng bộ lọc trong các lớp liên tiếp. Đối với tập dữ liệu hoa có 5 lớp, thì việc lọc chỉ có 5 bộ lọc là không đủ. Bạn có thể sử dụng cùng một số lượng bộ lọc trong hầu hết các lớp, ví dụ như 32 và giảm số lượng bộ lọc xuống cuối.
- (Các) lớp dày đặc cuối cùng rất đắt. Lớp này có thể có nhiều trọng số hơn tất cả các lớp convolutional cộng lại. Ví dụ: ngay cả khi có đầu ra rất hợp lý từ khối dữ liệu cuối cùng gồm 24x24x10 điểm dữ liệu, một lớp dày đặc 100 tế bào thần kinh sẽ có chi phí 24x24x10x100=576.000 trọng số!!! Hãy suy nghĩ kỹ hoặc thử tính năng tổng hợp trung bình toàn cục (xem bên dưới).
Gộp mức trung bình trên toàn cầu
Thay vì sử dụng một lớp dày đặc tốn kém ở cuối mạng nơron tích chập, bạn có thể chia "khối" dữ liệu đến thành nhiều phần bằng số lượng lớp bạn có, tính trung bình các giá trị của các phần đó và truyền các giá trị này thông qua hàm kích hoạt softmax. Cách tạo đầu phân loại này không có trọng số. Trong Keras, cú pháp là tf.keras.layers.GlobalAveragePooling2D().
Giải pháp
Dưới đây là sổ tay giải pháp. Bạn có thể sử dụng tính năng này nếu gặp khó khăn.
Keras_Flowers_TPU (solution).ipynb
Nội dung đã đề cập
- 🤔 Sử dụng các lớp tích chập
- 🤓 Thử nghiệm các phương pháp gộp tối đa, sải chân, gộp trung bình trên toàn cầu, ...
- 😀 đã lặp lại trên một mô hình thực tế nhanh chóng, trên TPU
Vui lòng dành chút thời gian để xem danh sách kiểm tra này trong đầu bạn.
10. [INFO] Cấu trúc tích chập hiện đại
Tóm tắt
Hình minh hoạ: một "mô-đun" tích chập. Tại thời điểm này, tính năng nào là tốt nhất? Lớp tích chập tối đa, theo sau là lớp tích chập 1x1 hay một tổ hợp lớp khác? Hãy thử tất cả các cách, nối kết các kết quả và để mạng quyết định. Ở bên phải: kiến trúc tích chập " inception" sử dụng các mô-đun như vậy.
Trong Keras, để tạo các mô hình mà luồng dữ liệu có thể phân nhánh vào và ra, bạn phải sử dụng kiểu mô hình "hàm". Dưới đây là ví dụ:
l = tf.keras.layers # syntax shortcut
y = l.Conv2D(filters=32, kernel_size=3, padding='same',
activation='relu', input_shape=[192, 192, 3])(x) # x=input image
# module start: branch out
y1 = l.Conv2D(filters=32, kernel_size=1, padding='same', activation='relu')(y)
y3 = l.Conv2D(filters=32, kernel_size=3, padding='same', activation='relu')(y)
y = l.concatenate([y1, y3]) # output now has 64 channels
# module end: concatenation
# many more layers ...
# Create the model by specifying the input and output tensors.
# Keras layers track their connections automatically so that's all that's needed.
z = l.Dense(5, activation='softmax')(y)
model = tf.keras.Model(x, z)
Các thủ thuật rẻ tiền khác
Bộ lọc 3x3 nhỏ
Trong hình minh hoạ này, bạn sẽ thấy kết quả của hai bộ lọc 3x3 liên tiếp. Hãy cố gắng truy ngược lại những điểm dữ liệu nào đã đóng góp vào kết quả: hai bộ lọc 3x3 liên tiếp này tính toán một số kết hợp của vùng 5x5. Đây không phải là tổ hợp chính xác mà bộ lọc 5x5 sẽ tính toán, nhưng bạn nên thử vì hai bộ lọc 3x3 liên tiếp rẻ hơn một bộ lọc 5x5.
số tích chập 1x1 ?
Về mặt toán học, phép tích chập "1x1" là phép nhân với một hằng số, không phải là một khái niệm hữu ích. Tuy nhiên, trong mạng nơron tích chập, hãy nhớ rằng bộ lọc được áp dụng cho một khối dữ liệu chứ không chỉ hình ảnh 2D. Do đó, bộ lọc "1x1" sẽ tính tổng trọng số của cột dữ liệu 1x1 (xem hình minh hoạ) và khi trượt bộ lọc đó trên dữ liệu, bạn sẽ nhận được tổ hợp tuyến tính của các kênh đầu vào. Điều này thực sự hữu ích. Nếu bạn coi các kênh là kết quả của các phép lọc riêng lẻ, ví dụ: một bộ lọc cho "tai nhọn", một bộ lọc khác cho "ria mép" và một bộ lọc thứ ba cho "mắt hẹp", thì một lớp tích chập "1x1" sẽ tính toán nhiều tổ hợp tuyến tính có thể có của các đặc điểm này. Điều này có thể hữu ích khi tìm kiếm "mèo". Ngoài ra, các lớp 1x1 sử dụng ít trọng số hơn.
11. Squeezenet
Cách đơn giản để tập hợp những ý tưởng này lại với nhau đã được trình bày trong bài viết "Squeezenet". Các tác giả đề xuất một thiết kế mô-đun tích chập rất đơn giản, chỉ sử dụng các lớp tích chập 1x1 và 3x3.
Hình minh hoạ: kiến trúc vắt dựa trên "mô-đun kích hoạt". Các lớp này luân phiên một lớp 1x1 "nén" dữ liệu đến theo chiều dọc, theo sau là hai lớp convolutional 1x1 và 3x3 song song "mở rộng" lại chiều sâu của dữ liệu.
Thực hành
Tiếp tục trong sổ tay trước của bạn và xây dựng một mạng nơron tích chập lấy cảm hứng từ vắt. Bạn sẽ phải thay đổi mã mô hình thành "kiểu chức năng" Keras.
Keras_Flowers_TPU (playground).ipynb
Thông tin bổ sung
Sẽ rất hữu ích cho bài tập này khi xác định hàm trợ giúp cho mô-đun scramblenet:
def fire(x, squeeze, expand):
y = l.Conv2D(filters=squeeze, kernel_size=1, padding='same', activation='relu')(x)
y1 = l.Conv2D(filters=expand//2, kernel_size=1, padding='same', activation='relu')(y)
y3 = l.Conv2D(filters=expand//2, kernel_size=3, padding='same', activation='relu')(y)
return tf.keras.layers.concatenate([y1, y3])
# this is to make it behave similarly to other Keras layers
def fire_module(squeeze, expand):
return lambda x: fire(x, squeeze, expand)
# usage:
x = l.Input(shape=[192, 192, 3])
y = fire_module(squeeze=24, expand=48)(x) # typically, squeeze is less than expand
y = fire_module(squeeze=32, expand=64)(y)
...
model = tf.keras.Model(x, y)
Mục tiêu lần này là đạt độ chính xác 80%.
Những điều nên thử
Bắt đầu bằng một lớp tích chập, sau đó là "fire_modules
", xen kẽ bằng các lớp MaxPooling2D(pool_size=2)
. Bạn có thể thử nghiệm với 2 đến 4 lớp gộp tối đa trong mạng và cũng có 1, 2 hoặc 3 mô-đun lửa liên tiếp giữa các lớp gộp tối đa.
Trong các mô-đun phát, thông số "squeeze" (nén) thường phải nhỏ hơn thông số "expand" (mở rộng). Các tham số này thực sự là số lượng bộ lọc. Thông thường, chúng có thể dao động từ 8 đến 196. Bạn có thể thử nghiệm với các cấu trúc mà số lượng bộ lọc tăng dần qua mạng hoặc các cấu trúc đơn giản mà tất cả các mô-đun kích hoạt đều có cùng số lượng bộ lọc.
Dưới đây là ví dụ:
x = tf.keras.layers.Input(shape=[*IMAGE_SIZE, 3]) # input is 192x192 pixels RGB
y = tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu')(x)
y = fire_module(24, 48)(y)
y = tf.keras.layers.MaxPooling2D(pool_size=2)(y)
y = fire_module(24, 48)(y)
y = tf.keras.layers.MaxPooling2D(pool_size=2)(y)
y = fire_module(24, 48)(y)
y = tf.keras.layers.GlobalAveragePooling2D()(y)
y = tf.keras.layers.Dense(5, activation='softmax')(y)
model = tf.keras.Model(x, y)
Tại thời điểm này, bạn có thể nhận thấy rằng các thử nghiệm của mình không diễn ra suôn sẻ và mục tiêu độ chính xác 80% có vẻ như rất xa vời. Đã đến lúc thực hiện một vài thủ thuật rẻ hơn nữa.
Chuẩn hoá theo lô
Phương pháp chuẩn hoá theo lô sẽ giúp giải quyết các vấn đề hội tụ mà bạn đang gặp phải. Chúng tôi sẽ giải thích chi tiết về kỹ thuật này trong hội thảo tiếp theo. Hiện tại, vui lòng sử dụng kỹ thuật này làm trình trợ giúp "ma thuật" hộp đen bằng cách thêm dòng này sau mỗi lớp convolutional trong mạng, bao gồm cả các lớp bên trong hàm fire_module:
y = tf.keras.layers.BatchNormalization(momentum=0.9)(y)
# please adapt the input and output "y"s to whatever is appropriate in your context
Tham số động lượng phải được giảm từ giá trị mặc định của nó là 0,99 xuống 0,9 vì tập dữ liệu của chúng tôi nhỏ. Bây giờ, bạn đừng để ý đến thông tin này.
Mở rộng dữ liệu
Bạn sẽ nhận được thêm một vài điểm phần trăm bằng cách tăng cường dữ liệu bằng các phép biến đổi dễ dàng như lật thay đổi độ bão hoà từ trái sang phải:
Bạn có thể dễ dàng thực hiện việc này trong Tensorflow bằng API tf.data.Dataset. Xác định hàm biến đổi mới cho dữ liệu:
def data_augment(image, label):
image = tf.image.random_flip_left_right(image)
image = tf.image.random_saturation(image, lower=0, upper=2)
return image, label
Sau đó, sử dụng hàm này trong quá trình biến đổi dữ liệu cuối cùng (ô "training and validation datasets" (dữ liệu tập huấn và dữ liệu xác thực), hàm "get_batched_dataset"):
dataset = dataset.repeat() # existing line
# insert this
if augment_data:
dataset = dataset.map(data_augment, num_parallel_calls=AUTO)
dataset = dataset.shuffle(2048) # existing line
Đừng quên đặt tính năng tăng cường dữ liệu thành không bắt buộc và thêm mã cần thiết để đảm bảo chỉ tăng cường tập dữ liệu huấn luyện. Việc tăng cường tập dữ liệu xác thực là không hợp lý.
Độ chính xác 80% trong 35 khoảng thời gian bắt đầu của hệ thống hiện nằm trong tầm tay.
Giải pháp
Dưới đây là sổ tay giải pháp. Bạn có thể sử dụng tính năng này nếu gặp khó khăn.
Keras_Flowers_TPU_squeezenet.ipynb
Nội dung đã đề cập
- 🤔 Mô hình "phong cách chức năng" của Keras
- 🤓 Kiến trúc Squeezenet
- 🤓 Củng cố dữ liệu bằng tf.data.dateset
Vui lòng dành chút thời gian để xem lại danh sách kiểm tra này.
12. Đã tinh chỉnh chế độ xem trước
Tích chập tách biệt
Gần đây, một cách triển khai lớp tích chập khác đã trở nên phổ biến: tích chập có thể tách biệt chiều sâu. Tôi biết, câu chuyện này khá hấp dẫn nhưng lại khá đơn giản. Các lớp này được triển khai trong Tensorflow và Keras dưới dạng tf.keras.layers.SeparableConv2D
.
Một phép tích chập có thể tách rời cũng chạy một bộ lọc trên hình ảnh, nhưng sử dụng một tập hợp trọng số riêng biệt cho mỗi kênh của hình ảnh đầu vào. Tiếp theo là "lớp phủ 1x1", một loạt tích vô hướng dẫn đến tổng trọng số của các kênh đã lọc. Với trọng số mới mỗi lần, số lượng kết hợp lại có trọng số của các kênh được tính toán khi cần thiết.
Hình minh hoạ: tích chập tách biệt. Giai đoạn 1: tích chập có bộ lọc riêng cho mỗi kênh. Giai đoạn 2: tái kết hợp tuyến tính của các kênh. Lặp lại với một tập hợp trọng số mới cho đến khi đạt được số kênh đầu ra mong muốn. Giai đoạn 1 cũng có thể được lặp lại, với trọng số mới mỗi lần nhưng trên thực tế thì hiếm khi xảy ra.
Các tích chập riêng biệt được dùng trong hầu hết các kiến trúc mạng tích chập gần đây nhất: MobileNetV2, Xception, EfficiencyNet. Nhân tiện, trước đây MobileNetV2 là công cụ bạn đã dùng để học chuyển giao.
Các phép tích chập này rẻ hơn so với các phép tích chập thông thường và được phát hiện là cũng hiệu quả như nhau trong thực tế. Dưới đây là số lượng trọng số cho ví dụ minh hoạ ở trên:
Lớp tích chập: 4 x 4 x 3 x 5 = 240
Lớp tích chập riêng biệt: 4 x 4 x 3 + 3 x 5 = 48 + 15 = 63
Đây là bài tập cho người đọc để tính toán số phép nhân cần thiết để áp dụng từng kiểu tỷ lệ lớp convolutional theo cách tương tự. Các phép tích chập có thể tách rời nhỏ hơn và hiệu quả tính toán cao hơn nhiều.
Tự thực hành
Khởi động lại từ sổ tay "tự học chuyển đổi", nhưng lần này hãy chọn Xception làm mô hình được huấn luyện trước. Xception chỉ sử dụng các phép tích chập riêng biệt. Để tất cả các mức tạ đều có thể tập luyện. Chúng ta sẽ tinh chỉnh các trọng số được huấn luyện trước trên dữ liệu của mình thay vì sử dụng các lớp được huấn luyện trước như vậy.
Keras Flowers transfer learning (playground).ipynb
Mục tiêu: độ chính xác > 95% (Thật sự là có thể đạt được!)
Đây là bài tập cuối cùng nên cần nhiều mã và công việc khoa học dữ liệu hơn một chút.
Thông tin bổ sung về cách tinh chỉnh
Xception có trong các mô hình được huấn luyện trước tiêu chuẩn trên tf.keras.application.* Đừng quên để tất cả các trọng số có thể huấn luyện được lần này.
pretrained_model = tf.keras.applications.Xception(input_shape=[*IMAGE_SIZE, 3],
include_top=False)
pretrained_model.trainable = True
Để có kết quả tốt khi tinh chỉnh một mô hình, bạn cần chú ý đến tốc độ học và sử dụng lịch biểu tốc độ học có thời gian tăng dần. Chẳng hạn như:
Việc bắt đầu với tốc độ học tiêu chuẩn sẽ làm gián đoạn các trọng số được huấn luyện trước của mô hình. Việc bắt đầu lưu giữ dần các biến đó cho đến khi mô hình đã chốt dựa trên dữ liệu của bạn có thể sửa đổi chúng theo cách hợp lý. Sau khi hết giai đoạn này, bạn có thể tiếp tục với tốc độ học không đổi hoặc giảm dần theo cấp số nhân.
Trong Keras, tốc độ học được chỉ định thông qua lệnh gọi lại, trong đó bạn có thể tính toán tốc độ học phù hợp cho mỗi thời gian bắt đầu của hệ thống. Keras sẽ truyền tốc độ học chính xác cho trình tối ưu hoá cho mỗi thời gian bắt đầu của hệ thống.
def lr_fn(epoch):
lr = ...
return lr
lr_callback = tf.keras.callbacks.LearningRateScheduler(lr_fn, verbose=True)
model.fit(..., callbacks=[lr_callback])
Giải pháp
Dưới đây là sổ tay giải pháp. Bạn có thể sử dụng tính năng này nếu gặp khó khăn.
07_Keras_Flowers_TPU_xception_fine_tuned_best.ipynb
Nội dung đã đề cập
- 🤔 Tích chập phân tách chiều sâu
- 🤓 Lịch biểu tốc độ học
- 😈 Điều chỉnh mô hình được huấn luyện trước.
Vui lòng dành chút thời gian để xem danh sách kiểm tra này trong đầu bạn.
13. Xin chúc mừng!
Bạn đã xây dựng mạng nơron tích chập hiện đại đầu tiên của mình và huấn luyện mạng nơron này với độ chính xác đạt 90% trở lên, lặp đi lặp lại các bài tập huấn luyện liên tiếp chỉ trong vài phút nhờ TPU.
TPU trong thực tế
TPU và GPU hiện có trên Vertex AI của Google Cloud:
- Máy ảo học sâu
- Trong Sổ tay Vertex AI
- Trong các công việc Đào tạo AI trong Vertex
Cuối cùng, chúng tôi rất mong nhận được ý kiến phản hồi của bạn. Vui lòng cho chúng tôi biết nếu bạn thấy có điều gì thiếu trong phòng thí nghiệm này hoặc nếu bạn cho rằng điều đó cần được cải thiện. Bạn có thể cung cấp ý kiến phản hồi thông qua các vấn đề trên GitHub [ feedback link].
|