Nhìn chung, bạn có thể xem autoencoder như một kỹ thuật học không giám sát, vì bạn không cần nhãn rõ ràng để huấn luyện mô hình. Tất cả những gì bạn cần để huấn luyện một autoencoder là dữ liệu đầu vào thô.
Trong hướng dẫn này, bạn sẽ tìm hiểu về autoencoder trong học sâu và sẽ triển khai một convolutional autoencoder và một denoising autoencoder bằng Python với Keras. Bạn sẽ làm việc với bộ dữ liệu bảng chữ cái NotMNIST làm ví dụ.
Tóm gọn lại, hôm nay bạn sẽ đề cập các chủ đề sau:
Trước tiên bạn sẽ tìm hiểu thêm về autoencoder: chúng là gì, so sánh với các kỹ thuật giảm chiều như thế nào, và những loại thuật toán này mà bạn có thể bắt gặp;
Tiếp theo, bạn sẽ tập trung vào convolutional autoencoder: bạn sẽ xem loại autoencoder này làm gì và cách bạn có thể xây dựng nó. Sau đó, bạn sẽ tự triển khai một mô hình! Bạn sẽ học cách tải dữ liệu khi ở định dạng ubyte gzip, rồi khám phá dữ liệu, tiền xử lý dữ liệu, đưa dữ liệu vào mô hình, trực quan hóa biểu đồ loss huấn luyện và xác thực, và cuối cùng dự đoán trên tập kiểm tra.
Tiếp theo, bạn sẽ được giới thiệu về denoising autoencoder và xem cách triển khai: bạn sẽ học cách thêm nhiễu vào ảnh. Sau đó, bạn đưa các ảnh này vào mô hình học sâu và huấn luyện! Cuối cùng, bạn sẽ dự đoán trên các ảnh kiểm tra có nhiễu.
Autoencoder
Như bạn đã đọc trong phần mở đầu, autoencoder là một thuật toán học máy không giám sát nhận một ảnh làm đầu vào và cố gắng tái tạo ảnh đó bằng việc sử dụng ít bit hơn tại nút thắt (bottleneck), còn gọi là không gian tiềm ẩn (latent space). Ảnh được nén mạnh tại nút thắt. Việc nén trong autoencoder đạt được bằng cách huấn luyện mạng trong một khoảng thời gian; khi học, mạng tìm cách biểu diễn tốt nhất ảnh đầu vào tại nút thắt. Các thuật toán nén ảnh thông thường như JPEG và JPEG lossless nén ảnh mà không cần bất kỳ quá trình huấn luyện nào và làm khá tốt việc nén ảnh.
Autoencoder tương tự các kỹ thuật giảm chiều như Phân tích Thành phần Chính (PCA). Chúng chiếu dữ liệu từ không gian chiều cao xuống chiều thấp bằng biến đổi tuyến tính và cố gắng giữ lại các đặc trưng quan trọng của dữ liệu trong khi loại bỏ các phần không thiết yếu.
Tuy nhiên, khác biệt lớn giữa autoencoder và PCA nằm ở phần biến đổi: như bạn đã đọc, PCA sử dụng biến đổi tuyến tính trong khi autoencoder sử dụng các biến đổi phi tuyến.
Bây giờ bạn đã có chút hiểu biết về autoencoder, hãy cùng “mổ xẻ” thuật ngữ này và xây dựng trực giác về nó!
Hình trên là một autoencoder “vanilla” hai lớp với một lớp ẩn. Trong thuật ngữ học sâu, bạn sẽ thường thấy rằng lớp đầu vào không được tính khi đếm tổng số lớp trong một kiến trúc. Tổng số lớp trong kiến trúc chỉ bao gồm số lớp ẩn và lớp đầu ra.
Như hình minh họa, lớp đầu vào và đầu ra có cùng số lượng neuron.
Lấy một ví dụ. Bạn đưa vào autoencoder một ảnh chỉ với năm giá trị điểm ảnh, được bộ mã hóa (encoder) nén thành ba giá trị điểm ảnh tại nút thắt (lớp giữa) hay không gian tiềm ẩn. Dựa trên ba giá trị này, bộ giải mã (decoder) cố gắng tái tạo lại năm giá trị điểm ảnh hay chính ảnh đầu vào mà bạn đã nạp vào mạng.
Trong thực tế, có nhiều lớp ẩn hơn giữa đầu vào và đầu ra.
Autoencoder có thể được chia thành ba phần
Encoder: phần này của mạng nén hoặc lấy mẫu thưa đầu vào thành ít bit hơn. Không gian được biểu diễn bởi số bit ít hơn này thường được gọi là latent-space hoặc bottleneck. Bottleneck cũng được gọi là “điểm nén tối đa” vì tại điểm này đầu vào được nén nhiều nhất. Các bit nén đại diện cho đầu vào gốc được gọi chung là “mã hóa” (encoding) của đầu vào.
Decoder: phần này của mạng cố gắng tái tạo đầu vào chỉ sử dụng phần mã hóa của đầu vào. Khi decoder có thể tái tạo đầu vào chính xác như những gì đã đưa vào encoder, bạn có thể nói encoder đã tạo ra các mã hóa tốt nhất để decoder tái tạo hiệu quả!
Có nhiều loại autoencoder, như convolutional autoencoder, denoising autoencoder, variational autoencoder và sparse autoencoder. Tuy nhiên, như đã đề cập ở phần mở đầu, trong hướng dẫn này bạn sẽ chỉ tập trung vào convolutional và denoising.Convolutional Autoencoders bằng Python với Keras
Vì dữ liệu đầu vào của bạn là ảnh, sẽ là một ý tưởng tốt khi dùng một convolutional autoencoder. Đây không phải là một biến thể autoencoder mới, mà là một autoencoder truyền thống được xếp chồng với các lớp tích chập: về cơ bản, bạn thay thế các lớp kết nối đầy đủ bằng các lớp tích chập. Các lớp tích chập cùng với các lớp max-pooling chuyển đổi đầu vào từ rộng (ảnh 28 x 28) và mỏng (một kênh hoặc thang xám) thành nhỏ (ảnh 7 x 7 tại không gian tiềm ẩn) và dày (128 kênh).
Đừng lo nếu bạn chưa hiểu rõ ý tưởng trên! Phần hai của hướng dẫn, nơi bạn tập trung vào triển khai, sẽ giúp bạn làm rõ mọi thắc mắc (nếu có!).
Mẹo: nếu bạn muốn biết thêm về mạng nơ-ron tích chập, hãy xem hướng dẫn này.
Điều này giúp mạng trích xuất đặc trưng thị giác từ ảnh và do đó thu được biểu diễn không gian tiềm ẩn chính xác hơn. Quá trình tái tạo sử dụng upsampling và tích chập, được gọi là decoder. Quá trình downsampling là khi ảnh được nén vào không gian thấp, còn gọi là encoder.
Lưu ý rằng encoder chủ yếu nén ảnh đầu vào, ví dụ: nếu ảnh đầu vào có kích thước 176 x 176 x 1 (~30976), thì điểm nén tối đa có thể có kích thước 22 x 22 x 512 (~247808). Vậy, trong trường hợp này, bạn bắt đầu với ảnh thang xám kích thước 176 x 176 và bằng cách đưa qua một vài lớp tích chập và chính xác là ba lớp max-pooling, ảnh của bạn cuối cùng được lấy mẫu thưa xuống kích thước 22 x 22 nhưng số kênh tăng từ 1 lên 512. Như đã nêu ở trên, đầu vào của bạn từ rộng (176 x 176) và mỏng (1) trở thành nhỏ (22x22) và dày (512).
Tải dữ liệu
Bộ dữ liệu notMNIST là bộ dữ liệu nhận dạng ký tự phông chữ cho các chữ cái từ A đến J. Nó khá giống với bộ dữ liệu kinh điển MNIST, chứa ảnh chữ số viết tay 0 đến 9: trong trường hợp này, bạn sẽ thấy bộ NotMNIST gồm các ảnh thang xám 28x28 của 70.000 chữ cái từ A - J, tổng cộng 10 hạng mục, và 6.000 ảnh mỗi hạng mục.
Mẹo: nếu bạn muốn học cách triển khai một Multi-Layer Perceptron (MLP) cho bài toán phân loại với bộ MNIST, hãy xem hướng dẫn này.
Bộ dữ liệu NotMNIST không được định nghĩa sẵn trong Keras hay TensorFlow, vì vậy bạn sẽ phải tải dữ liệu từ nguồn này. Dữ liệu sẽ được tải xuống ở định dạng ubyte.gzip, nhưng đừng lo! Bạn sẽ sớm học cách đọc các định dạng bytestream và chuyển đổi chúng thành mảng NumPy. Bắt đầu thôi!
Mạng sẽ được huấn luyện trên Nvidia Tesla K40, nên nếu bạn huấn luyện trên GPU và dùng Jupyter Notebook, bạn sẽ cần thêm ba dòng mã để chỉ định thứ tự thiết bị CUDA và CUDA visible devices bằng mô-đun os.
Trong đoạn mã dưới đây, bạn thiết lập biến môi trường trong notebook bằng os.environ. Nên làm như sau trước khi khởi tạo Keras để giới hạn backend TensorFlow của Keras dùng GPU đầu tiên. Nếu máy bạn huấn luyện có GPU ở 0, hãy chắc chắn dùng 0 thay vì 1. Bạn có thể kiểm tra bằng một lệnh đơn giản trên terminal: ví dụ, nvidia-smi
import os
os.environ["CUDA_DEVICE_ORDER"]="PCI_BUS_ID"
os.environ["CUDA_VISIBLE_DEVICES"]="1"#model will be trained on GPU 1Được hỗ trợ bởi
Tiếp theo, bạn nhập tất cả các mô-đun cần thiết như numpy, matplotlib và quan trọng nhất là keras, vì bạn sẽ dùng framework này trong hướng dẫn hôm nay!
import keras
from matplotlib import pyplot as plt
import numpy as np
import gzip
%matplotlib inline
from keras.layers import Input,Conv2D,MaxPooling2D,UpSampling2D
from keras.models import Model
from keras.optimizers import RMSprop
Được hỗ trợ bởi
Tại đây, bạn định nghĩa một hàm mở tệp gzip, đọc tệp bằng bytestream.read(). Bạn truyền kích thước ảnh và tổng số ảnh vào hàm này. Sau đó, dùng np.frombuffer(), bạn chuyển chuỗi lưu trong biến buf thành mảng NumPy kiểu float32.
Tiếp theo, bạn reshape mảng thành mảng ba chiều hoặc tensor, trong đó chiều thứ nhất là số ảnh, chiều thứ hai và ba là kích thước ảnh. Cuối cùng, bạn trả về mảng NumPy data.
defextract_data(filename, num_images):with gzip.open(filename)as bytestream:
bytestream.read(16)
buf = bytestream.read(28*28* num_images)
data = np.frombuffer(buf, dtype=np.uint8).astype(np.float32)
data = data.reshape(num_images,28,28)return data
Được hỗ trợ bởi
Bây giờ bạn sẽ gọi hàm extract_data() bằng cách truyền các tệp huấn luyện và kiểm tra cùng với số lượng ảnh tương ứng:
train_data = extract_data('train-images-idx3-ubyte.gz',60000)
test_data = extract_data('t10k-images-idx3-ubyte.gz',10000)Được hỗ trợ bởi
Tương tự, bạn định nghĩa một hàm trích xuất nhãn mở tệp gzip, đọc tệp bằng bytestream.read(), trong đó bạn truyền kích thước nhãn (1) và tổng số ảnh. Sau đó, dùng np.frombuffer(), bạn chuyển chuỗi lưu trong biến buf thành mảng NumPy kiểu int64.
Lần này, bạn không cần reshape mảng vì biến labels sẽ trả về một vector cột kích thước 60.000 x 1. Cuối cùng, bạn trả về mảng NumPy labels.
defextract_labels(filename, num_images):with gzip.open(filename)as bytestream:
bytestream.read(8)
buf = bytestream.read(1* num_images)
labels = np.frombuffer(buf, dtype=np.uint8).astype(np.int64)return labels
Được hỗ trợ bởi
Bây giờ bạn sẽ gọi hàm trích xuất nhãn bằng cách truyền các tệp nhãn huấn luyện và kiểm tra cùng với số lượng ảnh tương ứng:
train_labels = extract_labels('train-labels-idx1-ubyte.gz',60000)
test_labels = extract_labels('t10k-labels-idx1-ubyte.gz',10000)Được hỗ trợ bởi
Khi đã tải xong dữ liệu huấn luyện và kiểm tra, bạn sẵn sàng phân tích dữ liệu để có trực giác về bộ dữ liệu mà bạn sẽ làm việc trong hướng dẫn hôm nay!
Khám phá dữ liệu
Giờ hãy phân tích cách các ảnh trong bộ dữ liệu trông như thế nào và xem kích thước ảnh với thuộc tính mảng NumPy .shape:
# Shapes of training setprint("Training set (images) shape: {shape}".format(shape=train_data.shape))# Shapes of test setprint("Test set (images) shape: {shape}".format(shape=test_data.shape))Được hỗ trợ bởi
Training set(images) shape:(60000,28,28)
Test set(images) shape:(10000,28,28)Được hỗ trợ bởi
Từ kết quả trên, bạn có thể thấy dữ liệu huấn luyện có kích thước 60000 x 28 x 28 vì có 60.000 mẫu huấn luyện, mỗi mẫu là ma trận kích thước 28 x 28. Tương tự, dữ liệu kiểm tra có kích thước 10000 x 28 x 28 vì có 10.000 mẫu kiểm tra.
Lưu ý rằng trong tác vụ này, bạn sẽ không dùng nhãn huấn luyện và kiểm tra. Nhiệm vụ hiện tại chỉ xử lý ảnh huấn luyện và kiểm tra. Tuy nhiên, để mục đích khám phá, giúp bạn có trực giác tốt hơn về dữ liệu, bạn sẽ sử dụng nhãn.
Hãy tạo một từ điển chứa tên lớp với nhãn phân loại tương ứng:
# Create dictionary of target classes
label_dict ={0:'A',1:'B',2:'C',3:'D',4:'E',5:'F',6:'G',7:'H',8:'I',9:'J',}Được hỗ trợ bởi
Bây giờ, hãy xem một vài ảnh trong bộ dữ liệu của bạn:
plt.figure(figsize=[5,5])# Display the first image in training data
plt.subplot(121)
curr_img = np.reshape(train_data[0],(28,28))
curr_lbl = train_labels[0]
plt.imshow(curr_img, cmap='gray')
plt.title("(Label: "+str(label_dict[curr_lbl])+")")# Display the first image in testing data
plt.subplot(122)
curr_img = np.reshape(test_data[0],(28,28))
curr_lbl = test_labels[0]
plt.imshow(curr_img, cmap='gray')
plt.title("(Label: "+str(label_dict[curr_lbl])+")")Được hỗ trợ bởi
Kết quả của hai biểu đồ trên là một trong số các ảnh mẫu từ cả dữ liệu huấn luyện và kiểm tra, và các ảnh này được gán nhãn lớp 5 hay F ở một bên, và 3 hay D ở bên còn lại. Tương tự, các chữ cái khác sẽ có nhãn khác nhau, nhưng các chữ cái giống nhau sẽ có cùng nhãn. Điều này có nghĩa là tất cả 6.000 ảnh lớp F sẽ có nhãn lớp 5.
Tiền xử lý dữ liệu
Các ảnh trong bộ dữ liệu thực sự là ảnh thang xám với giá trị điểm ảnh từ 0 đến 255 và kích thước 28 x 28, nên trước khi đưa dữ liệu vào mô hình, việc tiền xử lý rất quan trọng. Bạn sẽ chuyển từng ảnh 28 x 28 của tập train và test thành ma trận kích thước 28 x 28 x 1, để có thể đưa vào mạng:
train_data = train_data.reshape(-1,28,28,1)
test_data = test_data.reshape(-1,28,28,1)
train_data.shape, test_data.shape
Được hỗ trợ bởi
Tiếp theo, bạn cần kiểm tra kiểu dữ liệu của các mảng NumPy huấn luyện và kiểm tra, chúng nên ở định dạng float32; nếu không, bạn sẽ cần chuyển đổi, nhưng vì bạn đã chuyển đổi khi đọc dữ liệu nên không cần làm lại. Bạn cũng phải chuẩn hóa giá trị điểm ảnh về khoảng 0 - 1. Hãy làm điều đó!
Đừng quên xác minh kiểu dữ liệu của dữ liệu huấn luyện và kiểm tra:
Sau tất cả, việc phân chia dữ liệu là quan trọng. Để mô hình của bạn tổng quát tốt, bạn chia dữ liệu huấn luyện thành hai phần: tập huấn luyện và tập xác thực. Bạn sẽ huấn luyện mô hình trên 80% dữ liệu và xác thực trên 20% dữ liệu huấn luyện còn lại.
Điều này cũng giúp giảm khả năng quá khớp, vì bạn sẽ xác thực mô hình trên dữ liệu mà nó không nhìn thấy trong giai đoạn huấn luyện.
Bạn có thể dùng mô-đun train_test_split của scikit-learn để chia dữ liệu đúng cách:
from sklearn.model_selection import train_test_split
train_X,valid_X,train_ground,valid_ground = train_test_split(train_data,
train_data,
test_size=0.2,
random_state=13)Được hỗ trợ bởi
Lưu ý rằng với tác vụ này, bạn không cần nhãn huấn luyện và kiểm tra. Đó là lý do bạn truyền ảnh huấn luyện hai lần. Ảnh huấn luyện vừa đóng vai trò đầu vào vừa là ground truth tương tự như nhãn trong bài toán phân loại.
Bây giờ bạn sẵn sàng định nghĩa mạng và đưa dữ liệu vào. Không chần chừ nữa, sang bước tiếp theo!
Convolutional Autoencoder
Các ảnh có kích thước 28 x 28 x 1 hay vector 784 chiều. Bạn chuyển ma trận ảnh thành mảng, chuẩn hóa về khoảng 0 đến 1, reshape về kích thước 28 x 28 x 1, và đưa làm đầu vào cho mạng.
Ngoài ra, bạn sẽ dùng batch size 128; dùng batch size lớn hơn như 256 hoặc 512 cũng được, tùy vào hệ thống bạn huấn luyện mô hình. Tham số này ảnh hưởng lớn đến các tham số học và độ chính xác dự đoán. Bạn sẽ huấn luyện mạng trong 50 epoch.
batch_size =128
epochs =50
inChannel =1
x, y =28,28
input_img = Input(shape =(x, y, inChannel))Được hỗ trợ bởi
Như đã thảo luận, autoencoder được chia thành hai phần: encoder và decoder.
Encoder
Lớp đầu tiên có 32 bộ lọc kích thước 3 x 3, theo sau là một lớp lấy mẫu thưa (max-pooling),
Lớp thứ hai có 64 bộ lọc kích thước 3 x 3, theo sau là một lớp lấy mẫu thưa khác,
Lớp cuối của encoder có 128 bộ lọc kích thước 3 x 3.
Decoder
Lớp đầu tiên có 128 bộ lọc kích thước 3 x 3 theo sau là một lớp upsampling,/li>
Lớp thứ hai có 64 bộ lọc kích thước 3 x 3 theo sau là một lớp upsampling khác,
Lớp cuối của encoder có 1 bộ lọc kích thước 3 x 3.
Lớp max-pooling sẽ giảm lấy mẫu đầu vào xuống hai lần mỗi khi bạn dùng, trong khi lớp upsampling sẽ tăng lấy mẫu đầu vào lên hai lần mỗi khi sử dụng.
Lưu ý: Số lượng bộ lọc, kích thước bộ lọc, số lớp, số epoch bạn huấn luyện mô hình đều là siêu tham số và nên được quyết định dựa trên trực giác của bạn; bạn được tự do thử nghiệm bằng cách tinh chỉnh các siêu tham số này và đo lường hiệu năng mô hình. Và đó là cách bạn dần học được “nghệ thuật” của học sâu!
defautoencoder(input_img):#encoder#input = 28 x 28 x 1 (wide and thin)
conv1 = Conv2D(32,(3,3), activation='relu', padding='same')(input_img)#28 x 28 x 32
pool1 = MaxPooling2D(pool_size=(2,2))(conv1)#14 x 14 x 32
conv2 = Conv2D(64,(3,3), activation='relu', padding='same')(pool1)#14 x 14 x 64
pool2 = MaxPooling2D(pool_size=(2,2))(conv2)#7 x 7 x 64
conv3 = Conv2D(128,(3,3), activation='relu', padding='same')(pool2)#7 x 7 x 128 (small and thick)#decoder
conv4 = Conv2D(128,(3,3), activation='relu', padding='same')(conv3)#7 x 7 x 128
up1 = UpSampling2D((2,2))(conv4)# 14 x 14 x 128
conv5 = Conv2D(64,(3,3), activation='relu', padding='same')(up1)# 14 x 14 x 64
up2 = UpSampling2D((2,2))(conv5)# 28 x 28 x 64
decoded = Conv2D(1,(3,3), activation='sigmoid', padding='same')(up2)# 28 x 28 x 1return decoded
Được hỗ trợ bởi
Sau khi tạo mô hình, bạn phải biên dịch nó với bộ tối ưu hóa RMSProp.
Mẹo: xem hướng dẫn này của Andrew Ng về RMSProp nếu bạn muốn biết thêm.
Lưu ý rằng bạn cũng phải chỉ định loại loss qua tham số loss. Ở đây là mean squared error, vì loss sau mỗi batch sẽ được tính giữa batch đầu ra dự đoán và ground truth bằng sai số bình phương trung bình theo từng pixel:
Hãy trực quan hóa các lớp bạn đã tạo ở bước trên bằng hàm summary, hàm này sẽ hiển thị số tham số (trọng số và bias) ở mỗi lớp và tổng tham số trong mô hình.
Đã đến lúc huấn luyện mô hình với hàm fit() của Keras! Mô hình huấn luyện trong 50 epoch. Hàm fit() sẽ trả về một đối tượng lịch sử; Bằng cách lưu kết quả này vào fashion_train, bạn có thể dùng sau để vẽ biểu đồ loss giữa huấn luyện và xác thực giúp bạn phân tích hiệu năng mô hình bằng trực quan.
Huấn luyện mô hình
autoencoder_train = autoencoder.fit(train_X, train_ground, batch_size=batch_size,epochs=epochs,verbose=1,validation_data=(valid_X, valid_ground))Được hỗ trợ bởi
Cuối cùng! Bạn đã huấn luyện mô hình trên Not-MNIST trong 50 epoch. Bây giờ, hãy vẽ biểu đồ loss giữa dữ liệu huấn luyện và xác thực để trực quan hóa hiệu năng mô hình.
Biểu đồ Training vs Validation Loss
loss = autoencoder_train.history['loss']
val_loss = autoencoder_train.history['val_loss']
epochs =range(epochs)
plt.figure()
plt.plot(epochs, loss,'bo', label='Training loss')
plt.plot(epochs, val_loss,'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()Được hỗ trợ bởi
Cuối cùng, bạn có thể thấy rằng validation loss và training loss đồng bộ với nhau. Điều này cho thấy mô hình của bạn không bị quá khớp: validation loss đang giảm chứ không tăng, và hiếm khi có khoảng cách lớn giữa training và validation loss.
Vì vậy, có thể nói khả năng tổng quát hóa của mô hình là tốt.
Cuối cùng, đã đến lúc tái tạo ảnh kiểm tra bằng hàm predict() của Keras và xem mô hình tái tạo trên dữ liệu kiểm tra tốt đến đâu.
Dự đoán trên dữ liệu kiểm tra
Bạn sẽ dùng mô hình đã huấn luyện để dự đoán trên toàn bộ 10.000 ảnh kiểm tra và vẽ một vài ảnh đã tái tạo để trực quan hóa mức độ tái tạo của mô hình.
Từ các hình trên, bạn có thể quan sát mô hình đã làm rất tốt việc tái tạo các ảnh kiểm tra được dự đoán bằng mô hình. Ít nhất là về mặt trực quan, ảnh kiểm tra và ảnh tái tạo trông gần như giống hệt nhau.
Denoising Autoencoder
Một denoising autoencoder cố gắng học một biểu diễn (không gian tiềm ẩn hay nút thắt) bền vững với nhiễu. Bạn thêm nhiễu vào ảnh rồi đưa ảnh nhiễu làm đầu vào cho phần encoder của mạng. Phần encoder của autoencoder biến đổi ảnh sang một không gian khác, cố gắng giữ lại chữ cái nhưng loại bỏ nhiễu.
Nhưng nó loại bỏ nhiễu chính xác như thế nào?
Trong quá trình huấn luyện, bạn định nghĩa một hàm loss, tương tự như root mean squared error mà bạn đã dùng trước đó trong convolutional autoencoder. Ở mỗi vòng lặp huấn luyện, mạng sẽ tính loss giữa ảnh nhiễu được decoder xuất ra và ground truth (ảnh đã khử nhiễu) và cũng sẽ cố gắng tối thiểu hóa loss hay chênh lệch giữa ảnh tái tạo và ảnh gốc không nhiễu. Nói cách khác, mạng sẽ học một không gian 7 x 7 x 128 với các mã hóa không nhiễu cho dữ liệu mà bạn huấn luyện!
Triển khai Denoising Autoencoder
Bây giờ, để xem cách hoạt động trong Python, bạn sẽ dùng cùng bộ dữ liệu NotMNIST như ở phần đầu hướng dẫn. Điều đó có nghĩa là bạn không cần tiền xử lý dữ liệu nữa vì đã làm từ trước! Tuy nhiên, một bước tiền xử lý quan trọng trong phần này là thêm nhiễu vào các ảnh huấn luyện, xác thực và kiểm tra. Vậy hãy làm nhanh bước đó trước!
Thêm nhiễu vào ảnh
Đầu tiên hãy định nghĩa một hệ số nhiễu, đây là một siêu tham số. Hệ số nhiễu được nhân với một ma trận ngẫu nhiên có trung bình 0,0 và độ lệch chuẩn 1,0. Ma trận này sẽ lấy mẫu từ phân phối chuẩn (Gaussian). Hình dạng mảng normal ngẫu nhiên sẽ tương tự như hình dạng dữ liệu mà bạn sẽ thêm nhiễu.
Để đơn giản, hiểu bằng ví dụ: biến train_X có kích thước 48000 x 28 x 28 x 1. Do đó, mảng normal ngẫu nhiên cũng sẽ có kích thước tương tự train_X; chỉ khi đó bạn mới có thể cộng hai mảng vì chúng có cùng kích thước.
np.clip() sẽ ngưỡng hóa tất cả giá trị âm thành 0 và tất cả giá trị lớn hơn 1 thành 1. Vì bạn muốn giá trị điểm ảnh nằm trong khoảng 0 đến 1. Và có khả năng sau khi đưa nhiễu vào dữ liệu, dải giá trị điểm ảnh có thể thay đổi đôi chút, nên để an toàn, thực hành tốt là đưa các giá trị điểm ảnh về ngưỡng.
Trực quan hóa ảnh nhiễu
plt.figure(figsize=[5,5])# Display the first image in training data
plt.subplot(121)
curr_img = np.reshape(x_train_noisy[1],(28,28))
plt.imshow(curr_img, cmap='gray')# Display the first image in testing data
plt.subplot(122)
curr_img = np.reshape(x_test_noisy[1],(28,28))
plt.imshow(curr_img, cmap='gray')Được hỗ trợ bởi
<matplotlib.image.AxesImage at 0x7f3ec6b20e48>Được hỗ trợ bởi
Bây giờ bạn đã có dữ liệu nhiễu, bạn có thể đưa vào mạng và xem nhiễu được loại bỏ “thần kỳ” khỏi ảnh như thế nào!
Mạng Denoising Autoencoder
Như đã thảo luận, autoencoder được chia làm hai phần: encoder và decoder. Kiến trúc bạn sẽ xây dựng sẽ trông như sau:
Encoder
Lớp đầu có 32 bộ lọc 3 x 3 theo sau là một lớp lấy mẫu thưa (max-pooling),
Lớp thứ hai có 64 bộ lọc 3 x 3 theo sau là một lớp lấy mẫu thưa khác,
Lớp cuối của encoder có 128 bộ lọc 3 x 3.
Decoder
Lớp đầu có 128 bộ lọc 3 x 3 theo sau là một lớp upsampling,
Lớp thứ hai có 64 bộ lọc 3 x 3 theo sau là một lớp upsampling khác,
Lớp cuối của encoder có 1 bộ lọc 3 x 3.
batch_size =128
epochs =20
inChannel =1
x, y =28,28
input_img = Input(shape =(x, y, inChannel))Được hỗ trợ bởi
Nếu bạn còn nhớ, khi huấn luyện convolutional autoencoder, bạn đã đưa ảnh huấn luyện vào hai lần vì đầu vào và ground truth giống nhau. Tuy nhiên, trong denoising autoencoder, bạn đưa ảnh có nhiễu làm đầu vào trong khi ground truth là các ảnh không nhiễu mà bạn đã thêm nhiễu. Chỉ như vậy mạng mới có thể tính loss giữa ảnh nhiễu và ảnh thật không nhiễu.
autoencoder_train = autoencoder.fit(x_train_noisy, train_X, batch_size=batch_size,epochs=epochs,verbose=1,validation_data=(x_valid_noisy, valid_X))Được hỗ trợ bởi
loss = autoencoder_train.history['loss']
val_loss = autoencoder_train.history['val_loss']
epochs =range(epochs)
plt.figure()
plt.plot(epochs, loss,'bo', label='Training loss')
plt.plot(epochs, val_loss,'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()Được hỗ trợ bởi
Từ biểu đồ trên, bạn có thể rút ra trực giác rằng mô hình bị quá khớp ở một vài epoch trong khi phần lớn thời gian thì đồng bộ. Bạn hoàn toàn có thể cố gắng cải thiện hiệu năng bằng cách tăng độ phức tạp để loss giảm hơn nữa, thử huấn luyện thêm epoch rồi quyết định.
Trong hướng dẫn tiếp theo, bạn sẽ học cách đọc ảnh từ đầu, phân tích, tiền xử lý và đưa chúng vào mô hình sử dụng bộ dữ liệu dấu vân tay. Bạn cũng sẽ học cách đọc ảnh y khoa của chế độ T-1 và tái tạo chúng bằng autoencoder!
Vẫn còn nhiều điều để khám phá, vậy tại sao không tham gia khóa Deep Learning in Python của DataCamp? Nếu bạn chưa làm. Bạn sẽ học từ những kiến thức cơ bản và dần tiến tới làm chủ lĩnh vực học sâu; đây chắc chắn sẽ là nguồn tài nguyên không thể thiếu khi bạn học cách làm việc với mạng nơ-ron tích chập trong Python, cách phát hiện khuôn mặt, đối tượng, v.v.
Nhìn chung, bạn có thể xem autoencoder như một kỹ thuật học không giám sát, vì bạn không cần nhãn rõ ràng để huấn luyện mô hình. Tất cả những gì bạn cần để huấn luyện một autoencoder là dữ liệu đầu vào thô.
Trong hướng dẫn này, bạn sẽ tìm hiểu về autoencoder trong học sâu và sẽ triển khai một convolutional autoencoder và một denoising autoencoder bằng Python với Keras. Bạn sẽ làm việc với bộ dữ liệu bảng chữ cái NotMNIST làm ví dụ.
Tóm gọn lại, hôm nay bạn sẽ đề cập các chủ đề sau:
Autoencoder
Như bạn đã đọc trong phần mở đầu, autoencoder là một thuật toán học máy không giám sát nhận một ảnh làm đầu vào và cố gắng tái tạo ảnh đó bằng việc sử dụng ít bit hơn tại nút thắt (bottleneck), còn gọi là không gian tiềm ẩn (latent space). Ảnh được nén mạnh tại nút thắt. Việc nén trong autoencoder đạt được bằng cách huấn luyện mạng trong một khoảng thời gian; khi học, mạng tìm cách biểu diễn tốt nhất ảnh đầu vào tại nút thắt. Các thuật toán nén ảnh thông thường như JPEG và JPEG lossless nén ảnh mà không cần bất kỳ quá trình huấn luyện nào và làm khá tốt việc nén ảnh.
Autoencoder tương tự các kỹ thuật giảm chiều như Phân tích Thành phần Chính (PCA). Chúng chiếu dữ liệu từ không gian chiều cao xuống chiều thấp bằng biến đổi tuyến tính và cố gắng giữ lại các đặc trưng quan trọng của dữ liệu trong khi loại bỏ các phần không thiết yếu.
Tuy nhiên, khác biệt lớn giữa autoencoder và PCA nằm ở phần biến đổi: như bạn đã đọc, PCA sử dụng biến đổi tuyến tính trong khi autoencoder sử dụng các biến đổi phi tuyến.
Bây giờ bạn đã có chút hiểu biết về autoencoder, hãy cùng “mổ xẻ” thuật ngữ này và xây dựng trực giác về nó!
Hình trên là một autoencoder “vanilla” hai lớp với một lớp ẩn. Trong thuật ngữ học sâu, bạn sẽ thường thấy rằng lớp đầu vào không được tính khi đếm tổng số lớp trong một kiến trúc. Tổng số lớp trong kiến trúc chỉ bao gồm số lớp ẩn và lớp đầu ra.
Như hình minh họa, lớp đầu vào và đầu ra có cùng số lượng neuron.
Lấy một ví dụ. Bạn đưa vào autoencoder một ảnh chỉ với năm giá trị điểm ảnh, được bộ mã hóa (encoder) nén thành ba giá trị điểm ảnh tại nút thắt (lớp giữa) hay không gian tiềm ẩn. Dựa trên ba giá trị này, bộ giải mã (decoder) cố gắng tái tạo lại năm giá trị điểm ảnh hay chính ảnh đầu vào mà bạn đã nạp vào mạng.
Trong thực tế, có nhiều lớp ẩn hơn giữa đầu vào và đầu ra.
Autoencoder có thể được chia thành ba phần
Có nhiều loại autoencoder, như convolutional autoencoder, denoising autoencoder, variational autoencoder và sparse autoencoder. Tuy nhiên, như đã đề cập ở phần mở đầu, trong hướng dẫn này bạn sẽ chỉ tập trung vào convolutional và denoising.Convolutional Autoencoders bằng Python với Keras
Vì dữ liệu đầu vào của bạn là ảnh, sẽ là một ý tưởng tốt khi dùng một convolutional autoencoder. Đây không phải là một biến thể autoencoder mới, mà là một autoencoder truyền thống được xếp chồng với các lớp tích chập: về cơ bản, bạn thay thế các lớp kết nối đầy đủ bằng các lớp tích chập. Các lớp tích chập cùng với các lớp max-pooling chuyển đổi đầu vào từ rộng (ảnh 28 x 28) và mỏng (một kênh hoặc thang xám) thành nhỏ (ảnh 7 x 7 tại không gian tiềm ẩn) và dày (128 kênh).
Đừng lo nếu bạn chưa hiểu rõ ý tưởng trên! Phần hai của hướng dẫn, nơi bạn tập trung vào triển khai, sẽ giúp bạn làm rõ mọi thắc mắc (nếu có!).
Mẹo: nếu bạn muốn biết thêm về mạng nơ-ron tích chập, hãy xem hướng dẫn này.
Điều này giúp mạng trích xuất đặc trưng thị giác từ ảnh và do đó thu được biểu diễn không gian tiềm ẩn chính xác hơn. Quá trình tái tạo sử dụng upsampling và tích chập, được gọi là decoder. Quá trình downsampling là khi ảnh được nén vào không gian thấp, còn gọi là encoder.
Lưu ý rằng encoder chủ yếu nén ảnh đầu vào, ví dụ: nếu ảnh đầu vào có kích thước 176 x 176 x 1 (~30976), thì điểm nén tối đa có thể có kích thước 22 x 22 x 512 (~247808). Vậy, trong trường hợp này, bạn bắt đầu với ảnh thang xám kích thước 176 x 176 và bằng cách đưa qua một vài lớp tích chập và chính xác là ba lớp max-pooling, ảnh của bạn cuối cùng được lấy mẫu thưa xuống kích thước 22 x 22 nhưng số kênh tăng từ 1 lên 512. Như đã nêu ở trên, đầu vào của bạn từ rộng (176 x 176) và mỏng (1) trở thành nhỏ (22x22) và dày (512).
Tải dữ liệu
Bộ dữ liệu notMNIST là bộ dữ liệu nhận dạng ký tự phông chữ cho các chữ cái từ A đến J. Nó khá giống với bộ dữ liệu kinh điển MNIST, chứa ảnh chữ số viết tay 0 đến 9: trong trường hợp này, bạn sẽ thấy bộ NotMNIST gồm các ảnh thang xám 28x28 của 70.000 chữ cái từ A - J, tổng cộng 10 hạng mục, và 6.000 ảnh mỗi hạng mục.
Mẹo: nếu bạn muốn học cách triển khai một Multi-Layer Perceptron (MLP) cho bài toán phân loại với bộ MNIST, hãy xem hướng dẫn này.
Bộ dữ liệu NotMNIST không được định nghĩa sẵn trong Keras hay TensorFlow, vì vậy bạn sẽ phải tải dữ liệu từ nguồn này. Dữ liệu sẽ được tải xuống ở định dạng
ubyte.gzip, nhưng đừng lo! Bạn sẽ sớm học cách đọc các định dạng bytestream và chuyển đổi chúng thành mảng NumPy. Bắt đầu thôi!Mạng sẽ được huấn luyện trên Nvidia Tesla K40, nên nếu bạn huấn luyện trên GPU và dùng Jupyter Notebook, bạn sẽ cần thêm ba dòng mã để chỉ định thứ tự thiết bị CUDA và CUDA visible devices bằng mô-đun
os.Trong đoạn mã dưới đây, bạn thiết lập biến môi trường trong notebook bằng
os.environ. Nên làm như sau trước khi khởi tạo Keras để giới hạn backend TensorFlow của Keras dùng GPU đầu tiên. Nếu máy bạn huấn luyện có GPU ở0, hãy chắc chắn dùng0thay vì1. Bạn có thể kiểm tra bằng một lệnh đơn giản trên terminal: ví dụ,nvidia-smiTiếp theo, bạn nhập tất cả các mô-đun cần thiết như
numpy,matplotlibvà quan trọng nhất làkeras, vì bạn sẽ dùng framework này trong hướng dẫn hôm nay!Tại đây, bạn định nghĩa một hàm mở tệp
gzip, đọc tệp bằngbytestream.read(). Bạn truyền kích thước ảnh và tổng số ảnh vào hàm này. Sau đó, dùngnp.frombuffer(), bạn chuyển chuỗi lưu trong biếnbufthành mảng NumPy kiểufloat32.Tiếp theo, bạn reshape mảng thành mảng ba chiều hoặc tensor, trong đó chiều thứ nhất là số ảnh, chiều thứ hai và ba là kích thước ảnh. Cuối cùng, bạn trả về mảng NumPy
data.Bây giờ bạn sẽ gọi hàm
extract_data()bằng cách truyền các tệp huấn luyện và kiểm tra cùng với số lượng ảnh tương ứng:Tương tự, bạn định nghĩa một hàm trích xuất nhãn mở tệp
gzip, đọc tệp bằngbytestream.read(), trong đó bạn truyền kích thước nhãn (1) và tổng số ảnh. Sau đó, dùngnp.frombuffer(), bạn chuyển chuỗi lưu trong biếnbufthành mảng NumPy kiểuint64.Lần này, bạn không cần reshape mảng vì biến
labelssẽ trả về một vector cột kích thước 60.000 x 1. Cuối cùng, bạn trả về mảng NumPylabels.Bây giờ bạn sẽ gọi hàm trích xuất nhãn bằng cách truyền các tệp nhãn huấn luyện và kiểm tra cùng với số lượng ảnh tương ứng:
Khi đã tải xong dữ liệu huấn luyện và kiểm tra, bạn sẵn sàng phân tích dữ liệu để có trực giác về bộ dữ liệu mà bạn sẽ làm việc trong hướng dẫn hôm nay!
Khám phá dữ liệu
Giờ hãy phân tích cách các ảnh trong bộ dữ liệu trông như thế nào và xem kích thước ảnh với thuộc tính mảng NumPy
.shape:Từ kết quả trên, bạn có thể thấy dữ liệu huấn luyện có kích thước 60000 x 28 x 28 vì có 60.000 mẫu huấn luyện, mỗi mẫu là ma trận kích thước 28 x 28. Tương tự, dữ liệu kiểm tra có kích thước 10000 x 28 x 28 vì có 10.000 mẫu kiểm tra.
Lưu ý rằng trong tác vụ này, bạn sẽ không dùng nhãn huấn luyện và kiểm tra. Nhiệm vụ hiện tại chỉ xử lý ảnh huấn luyện và kiểm tra. Tuy nhiên, để mục đích khám phá, giúp bạn có trực giác tốt hơn về dữ liệu, bạn sẽ sử dụng nhãn.
Hãy tạo một từ điển chứa tên lớp với nhãn phân loại tương ứng:
Bây giờ, hãy xem một vài ảnh trong bộ dữ liệu của bạn:
Kết quả của hai biểu đồ trên là một trong số các ảnh mẫu từ cả dữ liệu huấn luyện và kiểm tra, và các ảnh này được gán nhãn lớp
5hayFở một bên, và3hayDở bên còn lại. Tương tự, các chữ cái khác sẽ có nhãn khác nhau, nhưng các chữ cái giống nhau sẽ có cùng nhãn. Điều này có nghĩa là tất cả 6.000 ảnh lớpFsẽ có nhãn lớp5.Tiền xử lý dữ liệu
Các ảnh trong bộ dữ liệu thực sự là ảnh thang xám với giá trị điểm ảnh từ 0 đến 255 và kích thước 28 x 28, nên trước khi đưa dữ liệu vào mô hình, việc tiền xử lý rất quan trọng. Bạn sẽ chuyển từng ảnh 28 x 28 của tập train và test thành ma trận kích thước 28 x 28 x 1, để có thể đưa vào mạng:
Tiếp theo, bạn cần kiểm tra kiểu dữ liệu của các mảng NumPy huấn luyện và kiểm tra, chúng nên ở định dạng float32; nếu không, bạn sẽ cần chuyển đổi, nhưng vì bạn đã chuyển đổi khi đọc dữ liệu nên không cần làm lại. Bạn cũng phải chuẩn hóa giá trị điểm ảnh về khoảng 0 - 1. Hãy làm điều đó!
Đừng quên xác minh kiểu dữ liệu của dữ liệu huấn luyện và kiểm tra:
Tiếp theo, chuẩn hóa dữ liệu huấn luyện và kiểm tra theo giá trị điểm ảnh tối đa của chúng:
Hãy xác minh giá trị tối đa của dữ liệu huấn luyện và kiểm tra, sau khi chuẩn hóa, phải là 1.0!
Sau tất cả, việc phân chia dữ liệu là quan trọng. Để mô hình của bạn tổng quát tốt, bạn chia dữ liệu huấn luyện thành hai phần: tập huấn luyện và tập xác thực. Bạn sẽ huấn luyện mô hình trên 80% dữ liệu và xác thực trên 20% dữ liệu huấn luyện còn lại.
Điều này cũng giúp giảm khả năng quá khớp, vì bạn sẽ xác thực mô hình trên dữ liệu mà nó không nhìn thấy trong giai đoạn huấn luyện.
Bạn có thể dùng mô-đun
train_test_splitcủa scikit-learn để chia dữ liệu đúng cách:Lưu ý rằng với tác vụ này, bạn không cần nhãn huấn luyện và kiểm tra. Đó là lý do bạn truyền ảnh huấn luyện hai lần. Ảnh huấn luyện vừa đóng vai trò đầu vào vừa là ground truth tương tự như nhãn trong bài toán phân loại.
Bây giờ bạn sẵn sàng định nghĩa mạng và đưa dữ liệu vào. Không chần chừ nữa, sang bước tiếp theo!
Convolutional Autoencoder
Các ảnh có kích thước 28 x 28 x 1 hay vector 784 chiều. Bạn chuyển ma trận ảnh thành mảng, chuẩn hóa về khoảng 0 đến 1, reshape về kích thước 28 x 28 x 1, và đưa làm đầu vào cho mạng.
Ngoài ra, bạn sẽ dùng batch size 128; dùng batch size lớn hơn như 256 hoặc 512 cũng được, tùy vào hệ thống bạn huấn luyện mô hình. Tham số này ảnh hưởng lớn đến các tham số học và độ chính xác dự đoán. Bạn sẽ huấn luyện mạng trong 50 epoch.
Như đã thảo luận, autoencoder được chia thành hai phần: encoder và decoder.
Encoder
Decoder
Lớp max-pooling sẽ giảm lấy mẫu đầu vào xuống hai lần mỗi khi bạn dùng, trong khi lớp upsampling sẽ tăng lấy mẫu đầu vào lên hai lần mỗi khi sử dụng.
Lưu ý: Số lượng bộ lọc, kích thước bộ lọc, số lớp, số epoch bạn huấn luyện mô hình đều là siêu tham số và nên được quyết định dựa trên trực giác của bạn; bạn được tự do thử nghiệm bằng cách tinh chỉnh các siêu tham số này và đo lường hiệu năng mô hình. Và đó là cách bạn dần học được “nghệ thuật” của học sâu!
Sau khi tạo mô hình, bạn phải biên dịch nó với bộ tối ưu hóa RMSProp.
Mẹo: xem hướng dẫn này của Andrew Ng về RMSProp nếu bạn muốn biết thêm.
Lưu ý rằng bạn cũng phải chỉ định loại loss qua tham số
loss. Ở đây là mean squared error, vì loss sau mỗi batch sẽ được tính giữa batch đầu ra dự đoán và ground truth bằng sai số bình phương trung bình theo từng pixel:Hãy trực quan hóa các lớp bạn đã tạo ở bước trên bằng hàm summary, hàm này sẽ hiển thị số tham số (trọng số và bias) ở mỗi lớp và tổng tham số trong mô hình.
Đã đến lúc huấn luyện mô hình với hàm
fit()của Keras! Mô hình huấn luyện trong 50 epoch. Hàmfit()sẽ trả về một đối tượng lịch sử; Bằng cách lưu kết quả này vào fashion_train, bạn có thể dùng sau để vẽ biểu đồ loss giữa huấn luyện và xác thực giúp bạn phân tích hiệu năng mô hình bằng trực quan.Huấn luyện mô hình
Cuối cùng! Bạn đã huấn luyện mô hình trên Not-MNIST trong 50 epoch. Bây giờ, hãy vẽ biểu đồ loss giữa dữ liệu huấn luyện và xác thực để trực quan hóa hiệu năng mô hình.
Biểu đồ Training vs Validation Loss
Cuối cùng, bạn có thể thấy rằng validation loss và training loss đồng bộ với nhau. Điều này cho thấy mô hình của bạn không bị quá khớp: validation loss đang giảm chứ không tăng, và hiếm khi có khoảng cách lớn giữa training và validation loss.
Vì vậy, có thể nói khả năng tổng quát hóa của mô hình là tốt.
Cuối cùng, đã đến lúc tái tạo ảnh kiểm tra bằng hàm
predict()của Keras và xem mô hình tái tạo trên dữ liệu kiểm tra tốt đến đâu.Dự đoán trên dữ liệu kiểm tra
Bạn sẽ dùng mô hình đã huấn luyện để dự đoán trên toàn bộ 10.000 ảnh kiểm tra và vẽ một vài ảnh đã tái tạo để trực quan hóa mức độ tái tạo của mô hình.
Từ các hình trên, bạn có thể quan sát mô hình đã làm rất tốt việc tái tạo các ảnh kiểm tra được dự đoán bằng mô hình. Ít nhất là về mặt trực quan, ảnh kiểm tra và ảnh tái tạo trông gần như giống hệt nhau.
Denoising Autoencoder
Một denoising autoencoder cố gắng học một biểu diễn (không gian tiềm ẩn hay nút thắt) bền vững với nhiễu. Bạn thêm nhiễu vào ảnh rồi đưa ảnh nhiễu làm đầu vào cho phần encoder của mạng. Phần encoder của autoencoder biến đổi ảnh sang một không gian khác, cố gắng giữ lại chữ cái nhưng loại bỏ nhiễu.
Nhưng nó loại bỏ nhiễu chính xác như thế nào?
Trong quá trình huấn luyện, bạn định nghĩa một hàm loss, tương tự như root mean squared error mà bạn đã dùng trước đó trong convolutional autoencoder. Ở mỗi vòng lặp huấn luyện, mạng sẽ tính loss giữa ảnh nhiễu được decoder xuất ra và ground truth (ảnh đã khử nhiễu) và cũng sẽ cố gắng tối thiểu hóa loss hay chênh lệch giữa ảnh tái tạo và ảnh gốc không nhiễu. Nói cách khác, mạng sẽ học một không gian 7 x 7 x 128 với các mã hóa không nhiễu cho dữ liệu mà bạn huấn luyện!
Triển khai Denoising Autoencoder
Bây giờ, để xem cách hoạt động trong Python, bạn sẽ dùng cùng bộ dữ liệu NotMNIST như ở phần đầu hướng dẫn. Điều đó có nghĩa là bạn không cần tiền xử lý dữ liệu nữa vì đã làm từ trước! Tuy nhiên, một bước tiền xử lý quan trọng trong phần này là thêm nhiễu vào các ảnh huấn luyện, xác thực và kiểm tra. Vậy hãy làm nhanh bước đó trước!
Thêm nhiễu vào ảnh
Đầu tiên hãy định nghĩa một hệ số nhiễu, đây là một siêu tham số. Hệ số nhiễu được nhân với một ma trận ngẫu nhiên có trung bình 0,0 và độ lệch chuẩn 1,0. Ma trận này sẽ lấy mẫu từ phân phối chuẩn (Gaussian). Hình dạng mảng normal ngẫu nhiên sẽ tương tự như hình dạng dữ liệu mà bạn sẽ thêm nhiễu.
Để đơn giản, hiểu bằng ví dụ: biến
train_Xcó kích thước 48000 x 28 x 28 x 1. Do đó, mảng normal ngẫu nhiên cũng sẽ có kích thước tương tựtrain_X; chỉ khi đó bạn mới có thể cộng hai mảng vì chúng có cùng kích thước.np.clip()sẽ ngưỡng hóa tất cả giá trị âm thành 0 và tất cả giá trị lớn hơn 1 thành 1. Vì bạn muốn giá trị điểm ảnh nằm trong khoảng 0 đến 1. Và có khả năng sau khi đưa nhiễu vào dữ liệu, dải giá trị điểm ảnh có thể thay đổi đôi chút, nên để an toàn, thực hành tốt là đưa các giá trị điểm ảnh về ngưỡng.Trực quan hóa ảnh nhiễu
Bây giờ bạn đã có dữ liệu nhiễu, bạn có thể đưa vào mạng và xem nhiễu được loại bỏ “thần kỳ” khỏi ảnh như thế nào!
Mạng Denoising Autoencoder
Như đã thảo luận, autoencoder được chia làm hai phần: encoder và decoder. Kiến trúc bạn sẽ xây dựng sẽ trông như sau:
Encoder
Decoder
Huấn luyện
Nếu bạn còn nhớ, khi huấn luyện convolutional autoencoder, bạn đã đưa ảnh huấn luyện vào hai lần vì đầu vào và ground truth giống nhau. Tuy nhiên, trong denoising autoencoder, bạn đưa ảnh có nhiễu làm đầu vào trong khi ground truth là các ảnh không nhiễu mà bạn đã thêm nhiễu. Chỉ như vậy mạng mới có thể tính loss giữa ảnh nhiễu và ảnh thật không nhiễu.
Biểu đồ Train và Validation Loss
Từ biểu đồ trên, bạn có thể rút ra trực giác rằng mô hình bị quá khớp ở một vài epoch trong khi phần lớn thời gian thì đồng bộ. Bạn hoàn toàn có thể cố gắng cải thiện hiệu năng bằng cách tăng độ phức tạp để loss giảm hơn nữa, thử huấn luyện thêm epoch rồi quyết định.
Dự đoán trên tập kiểm tra
Có vẻ như chỉ với 20 epoch, một kiến trúc mạng khá đơn giản đã làm rất tốt việc loại bỏ nhiễu khỏi các ảnh kiểm tra, phải không?
Tiến xa hơn!
Hướng dẫn này là khởi đầu tốt để hiểu autoencoder cả lý thuyết lẫn thực hành. Nếu bạn theo kịp dễ dàng hoặc dù phải nỗ lực hơn chút, rất tuyệt! Hãy xem Keras Tutorial: Deep Learning in Python của DataCamp và khóa Introduction to Deep Learning in Python.
Trong hướng dẫn tiếp theo, bạn sẽ học cách đọc ảnh từ đầu, phân tích, tiền xử lý và đưa chúng vào mô hình sử dụng bộ dữ liệu dấu vân tay. Bạn cũng sẽ học cách đọc ảnh y khoa của chế độ T-1 và tái tạo chúng bằng autoencoder!
Vẫn còn nhiều điều để khám phá, vậy tại sao không tham gia khóa Deep Learning in Python của DataCamp? Nếu bạn chưa làm. Bạn sẽ học từ những kiến thức cơ bản và dần tiến tới làm chủ lĩnh vực học sâu; đây chắc chắn sẽ là nguồn tài nguyên không thể thiếu khi bạn học cách làm việc với mạng nơ-ron tích chập trong Python, cách phát hiện khuôn mặt, đối tượng, v.v.