Xây dựng bộ mã hóa tự động trong Tensorflow để vượt qua PCA


31

Hinton và Salakhutdinov trong việc giảm kích thước dữ liệu với mạng nơ ron, Science 2006 đã đề xuất một PCA phi tuyến tính thông qua việc sử dụng bộ mã hóa tự động sâu. Tôi đã cố gắng xây dựng và huấn luyện bộ mã hóa tự động PCA với Tensorflow nhiều lần nhưng tôi chưa bao giờ có thể có được kết quả tốt hơn PCA tuyến tính.

Làm thế nào tôi có thể đào tạo một bộ mã hóa tự động một cách hiệu quả?

(Bản chỉnh sửa sau này của @amoeba: phiên bản gốc của câu hỏi này chứa mã Python Tensorflow không hoạt động chính xác. Người ta có thể tìm thấy nó trong lịch sử chỉnh sửa.)


Tôi đã tìm thấy một lỗi trong chức năng kích hoạt của lớp Layer. Tôi đang thử nghiệm nếu bây giờ nó hoạt động
Donbeo

bạn đã sửa lỗi chưa?
Pinocchio

Xin chào Donbeo. Tôi đã tự do xóa mã khỏi câu hỏi của bạn (mã vẫn có thể dễ dàng tìm thấy trong lịch sử chỉnh sửa). Với mã, câu hỏi của bạn trông hơi giống câu hỏi "Giúp tôi tìm lỗi", câu hỏi không đúng chủ đề ở đây. Đồng thời, chủ đề này có 4k lượt xem, có lẽ có nghĩa là nhiều người đến đây thông qua các tìm kiếm của google, vì vậy tôi không muốn đóng câu hỏi của bạn. Tôi đã quyết định đăng một câu trả lời với bộ giải mã tự động, nhưng vì lý do đơn giản, tôi đã sử dụng Keras (chạy trên đỉnh của dòng chảy) thay vì dòng chảy thô. Bạn có nghĩ rằng điều này trả lời Q của bạn?
amip nói rằng Phục hồi lại

Câu trả lời:


42

Đây là con số chính từ bài báo Khoa học năm 2006 của Hinton và Salakhutdinov:

Nó cho thấy giảm kích thước của bộ dữ liệu MNIST ( 28×28 hình ảnh đen trắng của các chữ số đơn) từ kích thước 784 ban đầu xuống còn hai.

Hãy thử tái tạo nó. Tôi sẽ không trực tiếp sử dụng Tensorflow, bởi vì việc sử dụng Keras (một thư viện cấp cao hơn chạy trên đỉnh Tensorflow) dễ dàng hơn nhiều cho các nhiệm vụ học sâu đơn giản như thế này. H & S đã sử dụng kiến ​​trúc với các đơn vị logistic, được đào tạo trước với ngăn xếp của Máy Boltzmann bị hạn chế. Mười năm sau, trường này nghe có vẻ rất cũ. Tôi sẽ sử dụng đơn giản hơn 784 512 128 2 128 512

784100050025022505001000784
Kiến trúc 784 với các đơn vị tuyến tính theo cấp số nhân mà không cần đào tạo trước. Tôi sẽ sử dụng trình tối ưu hóa Adam (một triển khai cụ thể của việc giảm độ dốc ngẫu nhiên thích ứng với động lượng).
7845121282128512784

Mã này được sao chép từ một máy tính xách tay Jupyter. Trong Python 3.6, bạn cần cài đặt matplotlib (cho pylab), NumPy, seaborn, TensorFlow và Keras. Khi chạy trong shell Python, bạn có thể cần thêm plt.show()để hiển thị các ô.

Khởi tạo

%matplotlib notebook

import pylab as plt
import numpy as np
import seaborn as sns; sns.set()

import keras
from keras.datasets import mnist
from keras.models import Sequential, Model
from keras.layers import Dense
from keras.optimizers import Adam

(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(60000, 784) / 255
x_test = x_test.reshape(10000, 784) / 255

PCA

mu = x_train.mean(axis=0)
U,s,V = np.linalg.svd(x_train - mu, full_matrices=False)
Zpca = np.dot(x_train - mu, V.transpose())

Rpca = np.dot(Zpca[:,:2], V[:2,:]) + mu    # reconstruction
err = np.sum((x_train-Rpca)**2)/Rpca.shape[0]/Rpca.shape[1]
print('PCA reconstruction error with 2 PCs: ' + str(round(err,3)));

Kết quả này:

PCA reconstruction error with 2 PCs: 0.056

Đào tạo bộ mã hóa tự động

m = Sequential()
m.add(Dense(512,  activation='elu', input_shape=(784,)))
m.add(Dense(128,  activation='elu'))
m.add(Dense(2,    activation='linear', name="bottleneck"))
m.add(Dense(128,  activation='elu'))
m.add(Dense(512,  activation='elu'))
m.add(Dense(784,  activation='sigmoid'))
m.compile(loss='mean_squared_error', optimizer = Adam())
history = m.fit(x_train, x_train, batch_size=128, epochs=5, verbose=1, 
                validation_data=(x_test, x_test))

encoder = Model(m.input, m.get_layer('bottleneck').output)
Zenc = encoder.predict(x_train)  # bottleneck representation
Renc = m.predict(x_train)        # reconstruction

Quá trình này mất ~ 35 giây trên màn hình làm việc và kết quả đầu ra của tôi:

Train on 60000 samples, validate on 10000 samples
Epoch 1/5
60000/60000 [==============================] - 7s - loss: 0.0577 - val_loss: 0.0482
Epoch 2/5
60000/60000 [==============================] - 7s - loss: 0.0464 - val_loss: 0.0448
Epoch 3/5
60000/60000 [==============================] - 7s - loss: 0.0438 - val_loss: 0.0430
Epoch 4/5
60000/60000 [==============================] - 7s - loss: 0.0423 - val_loss: 0.0416
Epoch 5/5
60000/60000 [==============================] - 7s - loss: 0.0412 - val_loss: 0.0407

vì vậy bạn có thể thấy rằng chúng tôi đã vượt qua mất PCA chỉ sau hai kỷ nguyên đào tạo.

(Nhân tiện, hướng dẫn thay đổi tất cả các chức năng kích hoạt thành activation='linear'và quan sát cách thức tổn thất hội tụ chính xác với tổn thất PCA. Đó là vì bộ tự động tuyến tính tương đương với PCA.)

Vẽ kế hoạch chiếu PCA cạnh nhau với biểu diễn nút cổ chai

plt.figure(figsize=(8,4))
plt.subplot(121)
plt.title('PCA')
plt.scatter(Zpca[:5000,0], Zpca[:5000,1], c=y_train[:5000], s=8, cmap='tab10')
plt.gca().get_xaxis().set_ticklabels([])
plt.gca().get_yaxis().set_ticklabels([])

plt.subplot(122)
plt.title('Autoencoder')
plt.scatter(Zenc[:5000,0], Zenc[:5000,1], c=y_train[:5000], s=8, cmap='tab10')
plt.gca().get_xaxis().set_ticklabels([])
plt.gca().get_yaxis().set_ticklabels([])

plt.tight_layout()

nhập mô tả hình ảnh ở đây

Tái thiết

Và bây giờ, hãy nhìn vào các bản dựng lại (hàng đầu tiên - hình ảnh gốc, hàng thứ hai - PCA, hàng thứ ba - autoencoder):

plt.figure(figsize=(9,3))
toPlot = (x_train, Rpca, Renc)
for i in range(10):
    for j in range(3):
        ax = plt.subplot(3, 10, 10*j+i+1)
        plt.imshow(toPlot[j][i,:].reshape(28,28), interpolation="nearest", 
                   vmin=0, vmax=1)
        plt.gray()
        ax.get_xaxis().set_visible(False)
        ax.get_yaxis().set_visible(False)

plt.tight_layout()

nhập mô tả hình ảnh ở đây

Người ta có thể thu được kết quả tốt hơn nhiều với mạng lưới sâu hơn, một số chính quy và đào tạo lâu hơn. Thí nghiệm. Học sâu thật dễ!


2
Tôi ngạc nhiên khi PCA hoạt động tốt như thế nào chỉ với 2 thành phần! cảm ơn vì đã đăng mã
Aksakal

2
Tưởng tượng! Ngạc nhiên!
Matthew Drury

2
@shadi Tôi thực sự tìm thấy một cuộc gọi trực tiếp đến svd () đơn giản hơn :)
amoeba nói Phục hồi lại

1
Hiệu suất khác thậm chí còn lớn hơn khi sử dụng nhiều thành phần. Tôi đã thử 10 thay vì hai và autoencoder tốt hơn nhiều. Nhược điểm là tốc độ và mức tiêu thụ bộ nhớ
Aksakal

1
đối với python 2, bạn cần thêm các lần nhập saufrom __future__ import absolute_import from __future__ import division from __future__ import print_function
user2589273

7

Đạo cụ khổng lồ cho @amoeba để làm ví dụ tuyệt vời này. Tôi chỉ muốn chỉ ra rằng quy trình đào tạo và tái cấu trúc bộ mã hóa tự động được mô tả trong bài đăng đó cũng có thể được thực hiện trong R một cách dễ dàng. Bộ mã hóa tự động bên dưới là thiết lập để nó mô phỏng ví dụ của amip càng gần càng tốt - cùng trình tối ưu hóa và kiến ​​trúc tổng thể. Các chi phí chính xác không thể tái sản xuất do back-end TensorFlow không được gieo tương tự.

Khởi tạo

library(keras)
library(rARPACK) # to use SVDS
rm(list=ls())
mnist   = dataset_mnist()
x_train = mnist$train$x
y_train = mnist$train$y
x_test  = mnist$test$x
y_test  = mnist$test$y

# reshape & rescale
dim(x_train) = c(nrow(x_train), 784)
dim(x_test)  = c(nrow(x_test), 784)
x_train = x_train / 255
x_test = x_test / 255

PCA

mus = colMeans(x_train)
x_train_c =  sweep(x_train, 2, mus)
x_test_c =  sweep(x_test, 2, mus)
digitSVDS = svds(x_train_c, k = 2)

ZpcaTEST = x_test_c %*% digitSVDS$v # PCA projection of test data

Bộ giải mã tự động

model = keras_model_sequential() 
model %>%
  layer_dense(units = 512, activation = 'elu', input_shape = c(784)) %>%  
  layer_dense(units = 128, activation = 'elu') %>%
  layer_dense(units = 2,   activation = 'linear', name = "bottleneck") %>%
  layer_dense(units = 128, activation = 'elu') %>% 
  layer_dense(units = 512, activation = 'elu') %>% 
  layer_dense(units = 784, activation='sigmoid')

model %>% compile(
  loss = loss_mean_squared_error, optimizer = optimizer_adam())

history = model %>% fit(verbose = 2, validation_data = list(x_test, x_test),
                         x_train, x_train, epochs = 5, batch_size = 128)

# Unsurprisingly a 3-year old laptop is slower than a desktop
# Train on 60000 samples, validate on 10000 samples
# Epoch 1/5
#  - 14s - loss: 0.0570 - val_loss: 0.0488
# Epoch 2/5
#  - 15s - loss: 0.0470 - val_loss: 0.0449
# Epoch 3/5
#  - 15s - loss: 0.0439 - val_loss: 0.0426
# Epoch 4/5
#  - 15s - loss: 0.0421 - val_loss: 0.0413
# Epoch 5/5
#  - 14s - loss: 0.0408 - val_loss: 0.0403

# Set the auto-encoder
autoencoder = keras_model(model$input, model$get_layer('bottleneck')$output)
ZencTEST = autoencoder$predict(x_test)  # bottleneck representation  of test data

Vẽ kế hoạch chiếu PCA cạnh nhau với biểu diễn nút cổ chai

par(mfrow=c(1,2))
myCols = colorRampPalette(c('green',     'red',  'blue',  'orange', 'steelblue2',
                            'darkgreen', 'cyan', 'black', 'grey',   'magenta') )
plot(ZpcaTEST[1:5000,], col= myCols(10)[(y_test+1)], 
     pch=16, xlab = 'Score 1', ylab = 'Score 2', main = 'PCA' ) 
legend( 'bottomright', col= myCols(10), legend = seq(0,9, by=1), pch = 16 )

plot(ZencTEST[1:5000,], col= myCols(10)[(y_test+1)], 
     pch=16, xlab = 'Score 1', ylab = 'Score 2', main = 'Autoencoder' ) 
legend( 'bottomleft', col= myCols(10), legend = seq(0,9, by=1), pch = 16 )

nhập mô tả hình ảnh ở đây

Tái thiết

Chúng ta có thể thực hiện việc xây dựng lại các chữ số theo cách thông thường. (Hàng trên cùng là các chữ số gốc, hàng giữa là bản dựng lại PCA và hàng dưới cùng là bản tái tạo bộ mã hóa tự động.)

Renc = predict(model, x_test)        # autoencoder reconstruction
Rpca = sweep( ZpcaTEST %*% t(digitSVDS$v), 2, -mus) # PCA reconstruction

dev.off()
par(mfcol=c(3,9), mar = c(1, 1, 0, 0))
myGrays = gray(1:256 / 256)
for(u in seq_len(9) ){
  image( matrix( x_test[u,], 28,28, byrow = TRUE)[,28:1], col = myGrays, 
         xaxt='n', yaxt='n')
  image( matrix( Rpca[u,], 28,28, byrow = TRUE)[,28:1], col = myGrays , 
         xaxt='n', yaxt='n')
  image( matrix( Renc[u,], 28,28, byrow = TRUE)[,28:1], col = myGrays, 
         xaxt='n', yaxt='n')
}

nhập mô tả hình ảnh ở đây

k0,03560,0359


2
+1. Tốt đẹp. Thật tốt khi thấy rằng việc sử dụng Keras in R đơn giản như trong Python. Theo như tôi có thể thấy, trong cộng đồng học tập sâu, mọi người đang sử dụng Python ngày nay, vì vậy tôi có ấn tượng rằng nó sẽ khó khăn hơn ở những nơi khác.
amip nói rằng Phục hồi lại vào

2

Đây là máy tính xách tay jupyter của tôi, nơi tôi cố gắng sao chép kết quả của bạn, với những khác biệt sau:

  • thay vì sử dụng trực tiếp dòng chảy, tôi sử dụng nó để xem máy ảnh
  • Relu rò rỉ thay vì relu để tránh bão hòa (nghĩa là đầu ra được mã hóa là 0)
    • đây có thể là một lý do cho hiệu suất kém của AE
  • đầu vào bộ mã hóa tự động được thu nhỏ theo [0,1]
    • Tôi nghĩ rằng tôi đã đọc ở đâu đó rằng bộ điều khiển tự động với relu hoạt động tốt nhất với dữ liệu [0-1]
    • chạy máy tính xách tay của tôi với đầu vào bộ tự động là trung bình = 0, std = 1 đã cho MSE cho AE> 0,7 cho tất cả các giảm kích thước, vì vậy có thể đây là một trong những vấn đề của bạn
  • Đầu vào PCA được giữ là dữ liệu với mean = 0 và std = 1
    • Điều này cũng có nghĩa là kết quả MSE của PCA không thể so sánh với kết quả MSE của PCA
    • Có lẽ tôi sẽ chạy lại cái này sau với dữ liệu [0-1] cho cả PCA và AE
  • Đầu vào PCA cũng được chia tỷ lệ thành [0-1]. PCA cũng hoạt động với dữ liệu (mean = 0, std = 1), nhưng MSE sẽ không thể so sánh được với AE

Kết quả MSE của tôi cho PCA từ giảm kích thước từ 1 xuống 6 (trong đó đầu vào có 6 cột) và cho AE từ mờ. màu đỏ. từ 1 đến 6 dưới đây:

Với đầu vào PCA là (mean = 0, std = 1) trong khi đầu vào AE là [0-1] phạm vi - 4e-15: PCA6 - .015: PCA5 - .0502: AE5 - .0508: AE6 - .051: AE4 - .053: AE3 - .157: PCA4 - .258: AE2 - .259: PCA3 - .377: AE1 - .483: PCA2 - .682: PCA1

  • 9e-15: PCA6
  • 0,0094: PCA5
  • .0502: AE5
  • .0507: AE6
  • 0,0514: AE4
  • 0,0532: AE3
  • .0772: PCA4
  • .1231: PCA3
  • .2588: AE2
  • .2831: PCA2
  • .3773: AE1
  • .3885: PCA1

PCA tuyến tính không giảm kích thước có thể đạt được 9e-15 vì nó chỉ có thể đẩy bất cứ thứ gì nó không thể phù hợp với thành phần cuối cùng.


shadi, máy tính xách tay của bạn nhập một gói utils dường như có rất nhiều chức năng không chuẩn utils.buildNetwork và utils.ae_fit_encode_plot_mse chẳng hạn ...
Berowne Hlavaty

Đó chỉ là một tệp trong cùng một kho lưu trữ ở cùng cấp độ với sổ ghi chép.
shadi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.