Mengapa ReLU tunggal tidak bisa belajar ReLU?

15

Sebagai tindak lanjut dari jaringan saraf saya, saya bahkan tidak bisa mempelajari jarak Euclidean. Saya menyederhanakan lebih banyak lagi dan mencoba melatih satu ReLU tunggal (dengan berat acak) menjadi satu ReLU tunggal. Ini adalah jaringan paling sederhana yang ada, namun separuh dari waktu gagal untuk bertemu.

Jika tebakan awal berada dalam orientasi yang sama dengan target, ia akan belajar dengan cepat dan menyatu dengan bobot yang benar dari 1:

animasi ReLU belajar ReLU

kurva kehilangan menunjukkan titik konvergensi

Jika tebakan awal adalah "mundur", macet dengan berat nol dan tidak pernah melewatinya ke wilayah kehilangan yang lebih rendah:

animasi ReLU gagal belajar ReLU

kehilangan kurva ReLU gagal mempelajari ReLU

closeup of loss curve pada 0

Saya tidak mengerti mengapa. Bukankah seharusnya gradient descent dengan mudah mengikuti kurva kehilangan ke minimum global?

Kode contoh:

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, ReLU
from tensorflow import keras
import numpy as np
import matplotlib.pyplot as plt

batch = 1000


def tests():
    while True:
        test = np.random.randn(batch)

        # Generate ReLU test case
        X = test
        Y = test.copy()
        Y[Y < 0] = 0

        yield X, Y


model = Sequential([Dense(1, input_dim=1, activation=None, use_bias=False)])
model.add(ReLU())
model.set_weights([[[-10]]])

model.compile(loss='mean_squared_error', optimizer='sgd')


class LossHistory(keras.callbacks.Callback):
    def on_train_begin(self, logs={}):
        self.losses = []
        self.weights = []
        self.n = 0
        self.n += 1

    def on_epoch_end(self, batch, logs={}):
        self.losses.append(logs.get('loss'))
        w = model.get_weights()
        self.weights.append([x.flatten()[0] for x in w])
        self.n += 1


history = LossHistory()

model.fit_generator(tests(), steps_per_epoch=100, epochs=20,
                    callbacks=[history])

fig, (ax1, ax2) = plt.subplots(2, 1, True, num='Learning')

ax1.set_title('ReLU learning ReLU')
ax1.semilogy(history.losses)
ax1.set_ylabel('Loss')
ax1.grid(True, which="both")
ax1.margins(0, 0.05)

ax2.plot(history.weights)
ax2.set_ylabel('Weight')
ax2.set_xlabel('Epoch')
ax2.grid(True, which="both")
ax2.margins(0, 0.05)

plt.tight_layout()
plt.show()

masukkan deskripsi gambar di sini

Hal serupa terjadi jika saya menambahkan bias: Fungsi kehilangan 2D halus dan sederhana, tetapi jika relu mulai terbalik, berputar dan macet (titik awal merah), dan tidak mengikuti gradien ke minimum (seperti itu tidak untuk titik awal biru):

masukkan deskripsi gambar di sini

Hal serupa terjadi jika saya menambah bobot dan bias keluaran. (Ini akan beralih dari kiri ke kanan, atau turun ke atas, tetapi tidak keduanya.)

endolit
sumber
3
@ Scorax Tidak ini bukan duplikat, ia menanyakan masalah tertentu, bukan saran umum. Saya telah menghabiskan banyak waktu untuk mengurangi ini menjadi contoh Minimal, Lengkap, dan dapat diverifikasi. Tolong jangan hapus itu hanya karena samar-samar mirip dengan beberapa pertanyaan yang terlalu luas lainnya. Salah satu langkah dalam jawaban yang diterima untuk pertanyaan itu adalah "Pertama, membangun jaringan kecil dengan satu lapisan tersembunyi dan memverifikasi bahwa itu berfungsi dengan benar. Kemudian secara bertahap menambahkan kompleksitas model tambahan, dan memverifikasi bahwa masing-masing bekerja juga." Itulah tepatnya yang saya lakukan dan tidak berhasil.
endolith
2
Saya sangat menikmati "seri" ini di NN yang diterapkan ke fungsi sederhana: eats_popcorn_gif:
Cam.Davidson.Pilon
ReLU berfungsi seperti penyearah yang ideal, misalnya dioda. Itu searah. Jika Anda ingin arah koreksi, pertimbangkan untuk menggunakan softplus, kemudian beralih ke ReLU ketika pelatihan positif, atau menggunakan beberapa varian lain seperti ELU.
Carl
x<0x<0
Carl
1
x

Jawaban:

14

ww=0w=0w=1w diinisialisasi menjadi negatif, dimungkinkan untuk konvergen ke solusi suboptimal.

minw,bf(x)y22f(x)=max(0,wx+b)

f

f(x)={w,if x>00,if x<0

w<00w=1|w|

w(0)<0w(i)=0

Ini terkait dengan fenomena relu yang sekarat; untuk beberapa diskusi, lihat Jaringan ReLU saya gagal diluncurkan

Suatu pendekatan yang mungkin lebih berhasil adalah dengan menggunakan nonlinier yang berbeda seperti relu bocor, yang tidak memiliki apa yang disebut masalah "lenyapnya gradien". Fungsi relu yang bocor adalah

g(x)={x,if x>0cx,otherwise
c|c|

g(x)={1,if x>0c,if x<0

c=0c0.10.3c<0c=1,|c|>1

wLeakyReLUReLUw=1

LeakyReLU memperbaiki masalah

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, ReLU
from tensorflow import keras
import numpy as np
import matplotlib.pyplot as plt

batch = 1000


def tests():
    while True:
        test = np.random.randn(batch)

        # Generate ReLU test case
        X = test
        Y = test.copy()
        Y[Y < 0] = 0

        yield X, Y


model = Sequential(
    [Dense(1, 
           input_dim=1, 
           activation=None, 
           use_bias=False)
    ])
model.add(keras.layers.LeakyReLU(alpha=0.3))
model.set_weights([[[-10]]])

model.compile(loss='mean_squared_error', optimizer='sgd')


class LossHistory(keras.callbacks.Callback):
    def on_train_begin(self, logs={}):
        self.losses = []
        self.weights = []
        self.n = 0
        self.n += 1

    def on_epoch_end(self, batch, logs={}):
        self.losses.append(logs.get('loss'))
        w = model.get_weights()
        self.weights.append([x.flatten()[0] for x in w])
        self.n += 1


history = LossHistory()

model.fit_generator(tests(), steps_per_epoch=100, epochs=20,
                    callbacks=[history])

fig, (ax1, ax2) = plt.subplots(2, 1, True, num='Learning')

ax1.set_title('LeakyReLU learning ReLU')
ax1.semilogy(history.losses)
ax1.set_ylabel('Loss')
ax1.grid(True, which="both")
ax1.margins(0, 0.05)

ax2.plot(history.weights)
ax2.set_ylabel('Weight')
ax2.set_xlabel('Epoch')
ax2.grid(True, which="both")
ax2.margins(0, 0.05)

plt.tight_layout()
plt.show()

w w(0)

w(0)=10 dan mengubah pengoptimal dari SGD ke Adam, Adam + AMSGrad atau momentum SGD + tidak membantu. Selain itu, mengubah dari SGD ke Adam sebenarnya memperlambat kemajuan dan tidak membantu mengatasi gradien menghilang pada masalah ini.

w(0)=1 w(0)=1w(0)=1

Kode yang relevan di bawah ini; gunakan opt_sgdatau opt_adam.

opt_sgd = keras.optimizers.SGD(lr=1e-2, momentum=0.9)
opt_adam = keras.optimizers.Adam(lr=1e-2, amsgrad=True)
model.compile(loss='mean_squared_error', optimizer=opt_sgd)
Sycorax berkata Reinstate Monica
sumber
Saya melihat masalah yang sama dengan LeakyReLU, ELU, SELU ketika saya memiliki bobot dan bias output, tetapi saya tidak yakin apakah saya mencobanya tanpa output. Saya akan memeriksa
endolit
1
(Ya, Anda benar bahwa LeakyReLU dan ELU berfungsi dengan baik untuk contoh ini)
endolith
2
Oh, aku mengerti. Hal ini melakukan gradient descent dari fungsi kerugian, hanya saja fungsi kerugian menjadi datar (0 gradien) pada 0 ketika mendekati dari sisi negatif, sehingga gradient descent mendapat terjebak di sana. Sekarang sepertinya sudah jelas. : D
endolith
2
ww=0
2
w(i)