สร้างตัวเข้ารหัสอัตโนมัติใน Tensorflow เพื่อให้เกิน PCA


31

Hinton และ Salakhutdinov ในการลดมิติข้อมูลด้วย Neural Networks, Science 2006เสนอ PCA แบบไม่เชิงเส้นผ่านการใช้ autoencoder แบบลึก ฉันพยายามสร้างและฝึกอบรมโปรแกรมสร้างรหัสอัตโนมัติ PCA ด้วย Tensorflow หลายครั้ง แต่ฉันไม่เคยได้รับผลลัพธ์ที่ดีกว่า linear PCA

ฉันจะฝึกอบรมตัวเข้ารหัสอัตโนมัติได้อย่างมีประสิทธิภาพได้อย่างไร

(แก้ไขในภายหลังโดย @amoeba: เวอร์ชันเดิมของคำถามนี้มีรหัส Python Tensorflow ที่ทำงานไม่ถูกต้องสามารถพบได้ในประวัติการแก้ไข)


ฉันพบข้อผิดพลาดในฟังก์ชัน activaction ของคลาส Layer ฉันกำลังทดสอบว่าตอนนี้ใช้งานได้หรือไม่
Donbeo

คุณแก้ไขข้อผิดพลาดของคุณหรือไม่
Pinocchio

สวัสดี Donbeo ฉันใช้เสรีภาพในการลบรหัสออกจากคำถามของคุณ (รหัสยังสามารถพบได้ง่ายในประวัติการแก้ไข) เมื่อใช้รหัสแล้วคำถามของคุณจะดูเหมือนคำถามประเภท "ช่วยฉันหาบั๊ก" ซึ่งอยู่นอกหัวข้อที่นี่ ในขณะเดียวกันเธรดนี้มีจำนวนการดู 4k ซึ่งอาจหมายความว่ามีผู้คนจำนวนมากมาที่นี่ผ่านการค้นหาโดย Google ดังนั้นฉันไม่ต้องการปิดคำถามของคุณ ฉันตัดสินใจที่จะโพสต์คำตอบด้วย autoencoder walk-through แต่ด้วยเหตุผลของความเรียบง่ายฉันใช้ Keras (ทำงานบน Tensorflow) แทน Tensorflow แบบดิบ คุณคิดว่านี่เป็นการตอบคำถามของคุณหรือไม่?
อะมีบาพูดว่า Reinstate Monica

คำตอบ:


42

นี่คือตัวเลขสำคัญจากบทความวิทยาศาสตร์ปี 2549 โดย Hinton และ Salakhutdinov:

มันแสดงให้เห็นถึงการลดขนาดของชุดข้อมูล MNIST (ภาพขาวดำตัวเลขเดียว) จาก 784 มิติเดิมถึงสอง28×28

ลองทำซ้ำอีกครั้ง ฉันจะไม่ใช้ Tensorflow โดยตรงเพราะมันง่ายกว่าการใช้ Keras (ไลบรารีระดับสูงที่ทำงานอยู่ด้านบนของ Tensorflow) สำหรับงานการเรียนรู้อย่างง่ายเช่นนี้ H&S ใช้สถาปัตยกรรมสถาปัตยกรรมกับหน่วยโลจิสติกส์ฝึกอบรมล่วงหน้าด้วยสแต็คของเครื่อง Boltzmann ที่ จำกัด สิบปีต่อมามันฟังดูเก่าแก่มาก ฉันจะใช้สถาปัตยกรรมที่ง่ายกว่าสถาปัตยกรรมกับหน่วยเชิงเส้นแบบเอ็กซ์โพเนนเชียลโดยไม่ต้องมีการฝึกอบรมล่วงหน้า ฉันจะใช้เครื่องมือเพิ่มประสิทธิภาพของอาดัม784 512 128 2 128 512 784

784100050025022505001000784
7845121282128512784

รหัสถูกคัดลอกวางจากสมุดบันทึก Jupyter ใน Python 3.6 คุณต้องติดตั้ง matplotlib (สำหรับ pylab), NumPy, seaborn, TensorFlow และ Keras เมื่อทำงานใน Python shell คุณอาจต้องเพิ่มplt.show()เพื่อแสดงพล็อต

การเริ่มต้น

%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)));

ผลลัพธ์นี้:

PCA reconstruction error with 2 PCs: 0.056

การฝึกอบรม autoencoder

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

ใช้เวลาประมาณ 35 วินาทีบนเดสก์ท็อปและเอาต์พุตของฉัน:

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

ดังนั้นคุณจะเห็นแล้วว่าเราเอาชนะการสูญเสีย PCA หลังจากการฝึกเพียงสองครั้ง

(โดยวิธีการนั้นมันเป็นคำแนะนำในการเปลี่ยนฟังก์ชั่นการเปิดใช้งานทั้งหมดเป็นactivation='linear'และเพื่อสังเกตว่าการสูญเสียมาบรรจบกันอย่างแม่นยำกับการสูญเสีย PCA นั่นเป็นเพราะ linear autoencoder เทียบเท่ากับ PCA)

พล็อตการฉาย PCA แบบเคียงข้างกันด้วยการแสดงคอขวด

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()

ป้อนคำอธิบายรูปภาพที่นี่

ไทปัน

และตอนนี้ให้ดูที่ไทปัน (แถวแรก - ภาพดั้งเดิม, แถวที่สอง - PCA, แถวที่สาม - 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()

ป้อนคำอธิบายรูปภาพที่นี่

สามารถรับผลลัพธ์ที่ดีกว่ามากด้วยเครือข่ายที่ลึกกว่าปกติการกำหนดมาตรฐานและการฝึกอบรมที่ยาวนานขึ้น การทดลอง การเรียนรู้ลึกเป็นเรื่องง่าย!


2
ฉันประหลาดใจที่ PCA ทำงานได้ดีเพียง 2 องค์ประกอบ! ขอบคุณที่โพสต์รหัส
Aksakal

2
ประหลาด! Stupendousness!
Matthew Drury

2
@shadi ที่จริงผมพบว่ามีการโทรโดยตรงกับ SVD () ง่าย :)
อะมีบากล่าวว่าคืนสถานะโมนิกา

1
ประสิทธิภาพจะแตกต่างกันมากยิ่งขึ้นเมื่อใช้ส่วนประกอบเพิ่มเติม ฉันลอง 10 แทนที่จะเป็นสองและ autoencoder ดีกว่ามาก ข้อเสียคือความเร็วและการใช้หน่วยความจำ
Aksakal

1
สำหรับ python 2 คุณต้องเพิ่มการนำเข้าต่อไปนี้from __future__ import absolute_import from __future__ import division from __future__ import print_function
user2589273

7

อุปกรณ์ประกอบฉากขนาดใหญ่เพื่อ @amoeba สำหรับการทำตัวอย่างที่ยอดเยี่ยมนี้ ฉันแค่ต้องการแสดงให้เห็นว่าการฝึกอบรมการเข้ารหัสอัตโนมัติและขั้นตอนการสร้างใหม่ที่อธิบายไว้ในโพสต์นั้นสามารถทำได้ใน R ด้วยเช่นกัน ตัวเข้ารหัสอัตโนมัติด้านล่างมีการตั้งค่าดังนั้นจึงจำลองตัวอย่างของอะมีบาให้ใกล้เคียงที่สุดเท่าที่จะเป็นไปได้ - ตัวเพิ่มประสิทธิภาพเดียวกันและสถาปัตยกรรมโดยรวม ค่าใช้จ่ายที่แน่นอนไม่สามารถทำซ้ำได้เนื่องจาก TensorFlow แบ็คเอนด์ที่ไม่ได้ถูกเพาะในทำนองเดียวกัน

initialisation

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

Autoencoder

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

พล็อตการฉาย PCA แบบเคียงข้างกันด้วยการแสดงคอขวด

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 )

ป้อนคำอธิบายรูปภาพที่นี่

ไทปัน

เราสามารถสร้างตัวเลขใหม่ด้วยวิธีปกติ (แถวบนสุดคือตัวเลขเดิมแถวกลางของไทปัน PCA และแถวล่างของไทปันโค้ดอัตโนมัติ)

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')
}

ป้อนคำอธิบายรูปภาพที่นี่

ดังที่กล่าวไว้ยุคที่มากขึ้นและเครือข่ายที่ผ่านการฝึกฝนอย่างลึกซึ้งและ / หรือมากกว่านั้นจะให้ผลลัพธ์ที่ดีกว่ามาก ตัวอย่างเช่นข้อผิดพลาดในการสร้างใหม่ PCA ของ = 9 อยู่ที่ประมาณเราสามารถได้รับข้อผิดพลาดเดียวกัน ( ) จาก autoencoder ที่อธิบายข้างต้นเพียงแค่เพิ่ม epochs การฝึกอบรมจาก 5 เป็น 25 ในกรณีใช้งานนี้ 2 ส่วนประกอบที่ได้จาก autoencoder จะให้ข้อผิดพลาดในการสร้างใหม่คล้ายกับ 9 องค์ประกอบหลัก เย็น!0.0356 0.0359k0.03560.0359


2
+1 ดี เป็นการดีที่จะเห็นว่ามันง่ายเหมือนการใช้ Keras ใน R เหมือนกับ Python เท่าที่ฉันสามารถเห็นได้ในชุมชนการเรียนรู้อย่างลึกล้ำทุกคนใช้ Python ในทุกวันนี้ดังนั้นฉันจึงรู้สึกว่ามันน่าจะยากกว่าที่อื่น
อะมีบาพูดว่า Reinstate Monica

2

นี่คือโน๊ตบุ๊ค jupyter ของฉันที่ฉันพยายามจำลองผลลัพธ์ของคุณโดยมีความแตกต่างดังต่อไปนี้:

  • แทนที่จะใช้ tensorflow โดยตรงฉันใช้มันดู keras
  • relu ที่รั่วแทน relu เพื่อหลีกเลี่ยงความอิ่มตัว (เช่นเอาท์พุทเข้ารหัสเป็น 0)
    • นี่อาจเป็นเหตุผลสำหรับประสิทธิภาพที่ไม่ดีของ AE
  • อินพุต autoencoder เป็นข้อมูลที่ปรับขนาดเป็น [0,1]
    • ฉันคิดว่าฉันอ่านที่ไหนสักแห่งที่ระบบเข้ารหัสอัตโนมัติทำงานได้ดีกับข้อมูล [0-1]
    • การใช้งานโน้ตบุ๊คของฉันด้วยการป้อนข้อมูลของ autoencoders คือค่าเฉลี่ย = 0, std = 1 ให้ MSE สำหรับ AE> 0.7 สำหรับการลดมิติทั้งหมดดังนั้นนี่อาจเป็นปัญหาของคุณ
  • อินพุต PCA ถูกเก็บเป็นข้อมูลโดยมีค่าเฉลี่ย = 0 และ std = 1
    • นี่อาจหมายความว่าผลลัพธ์ MSE ของ PCA นั้นไม่สามารถเปรียบเทียบกับผลลัพธ์ MSE ของ PCA ได้
    • บางทีฉันจะเรียกใช้อีกครั้งในภายหลังด้วยข้อมูล [0-1] สำหรับทั้ง PCA และ AE
  • อินพุต PCA ยังถูกปรับสัดส่วนเป็น [0-1] PCA ทำงานร่วมกับข้อมูล (mean = 0, std = 1) ด้วยเช่นกัน แต่ MSE จะหาที่เปรียบมิได้กับ AE

ผลลัพธ์ MSE ของฉันสำหรับ PCA จากการลดขนาด 1 ถึง 6 (โดยที่อินพุตมี 6 คอลัมน์) และสำหรับ AE จากสลัว สีแดง ของ 1 ถึง 6 อยู่ด้านล่าง:

ด้วยอินพุต PCA กำลัง (เฉลี่ย = 0, std = 1) ในขณะที่อินพุต AE อยู่ในช่วง [0-1] - 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
  • .0094: PCA5
  • .0502: AE5
  • .0507: AE6
  • .0514: AE4
  • .0532: AE3
  • .0772: PCA4
  • .1231: PCA3
  • .2588: AE2
  • .2831: PCA2
  • .3773: AE1
  • .3885: PCA1

Linear PCA ที่ไม่มีการลดมิติสามารถบรรลุ 9e-15 ได้เพราะมันสามารถผลักสิ่งที่ไม่สามารถใส่ลงไปในองค์ประกอบสุดท้ายได้


shadi สมุดบันทึกของคุณนำเข้าแพคเกจ utils ซึ่งดูเหมือนว่าจะมีฟังก์ชั่นที่ไม่ได้มาตรฐานมากมาย utils.buildNetwork และ utils.ae_fit_encode_plot_mse เช่น ...
Berowne Hlavaty

นี่เป็นเพียงไฟล์ในที่เก็บเดียวกันในระดับเดียวกับโน้ตบุ๊ก
Shadi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.