एक एकल ReLU एक ReLU क्यों नहीं सीख सकता है?


15

मेरे न्यूरल नेटवर्क के फॉलो-अप के रूप में यूक्लिडियन दूरी भी नहीं सीखी जा सकती है, मैंने इसे और भी सरल बना दिया और एक एकल ReLU के लिए एक एकल ReLU (यादृच्छिक वजन के साथ) को प्रशिक्षित करने की कोशिश की। यह सबसे सरल नेटवर्क है, और फिर भी आधा समय यह अभिसरण करने में विफल रहता है।

यदि प्रारंभिक अनुमान लक्ष्य के समान अभिविन्यास में है, तो यह जल्दी से सीखता है और 1 के सही वजन में परिवर्तित होता है:

ReLU सीखने का ReLU का एनीमेशन

नुकसान वक्र अभिसरण बिंदु दिखा रहा है

यदि प्रारंभिक अनुमान "पीछे की ओर" है, तो यह शून्य के वजन पर अटक जाता है और कभी भी निम्न हानि के क्षेत्र में नहीं जाता है:

ReLU सीखने में असफल होने पर ReLU का एनीमेशन

ReLU सीखने में असफल होने पर ReLU की हानि वक्र

0 पर हानि वक्र का क्लोज़अप

मुझे समझ नहीं आता क्यों। क्या ग्रैडिएंट डिसेंट्रेंट को आसानी से ग्लोबल मिनिमा को लॉस वक्र का पालन नहीं करना चाहिए?

उदाहरण कोड:

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

यहाँ छवि विवरण दर्ज करें

अगर मैं पूर्वाग्रह जोड़ता हूं तो ऐसी ही चीजें होती हैं: 2 डी लॉस फ़ंक्शन सुचारू और सरल होता है, लेकिन अगर रिले उल्टा शुरू होता है, तो यह चारों ओर घूमता है और अटक जाता है (लाल शुरुआती बिंदु), और ग्रेडिएंट को न्यूनतम तक का पालन नहीं करता है (जैसे यह नीले रंग के शुरुआती बिंदुओं के लिए):

यहाँ छवि विवरण दर्ज करें

अगर मैं आउटपुट वेट और पूर्वाग्रह भी जोड़ता हूं, तो ऐसी ही चीजें होती हैं। (यह बाएँ-से-दाएँ, या नीचे-ऊपर-ऊपर फ्लिप करेगा, लेकिन दोनों नहीं।)


3
@ साइकोरेक्स नहीं यह कोई डुप्लिकेट नहीं है, यह एक विशिष्ट समस्या के बारे में पूछता है, सामान्य सलाह नहीं। मैंने इसे मिनिमल, कम्प्लीट और वेरिफ़ाइबल उदाहरण में कम करने के लिए महत्वपूर्ण समय बिताया है। कृपया इसे केवल इसलिए न हटाएं क्योंकि यह अस्पष्ट रूप से कुछ अन्य व्यापक प्रश्नों के समान है। उस प्रश्न के स्वीकृत उत्तर में चरणों में से एक है "पहले, एक छिपी हुई परत के साथ एक छोटा नेटवर्क बनाएं और सत्यापित करें कि यह सही ढंग से काम करता है। फिर अतिरिक्त मॉडल जटिलता जोड़ें, और सत्यापित करें कि उनमें से प्रत्येक भी काम करता है।" ठीक यही मैं कर रहा हूं और यह काम नहीं कर रहा है।
एंडोलिथ

2
मैं वास्तव में एनएन पर इस "श्रृंखला" का आनंद ले रहा हूं जो सरल कार्यों पर लागू होता है: eats_popcorn_gif:
Cam.Davidson.Pilon

ReLU एक आदर्श रेक्टिफायर की तरह काम करता है, जैसे, एक डायोड। यह यूनिडायरेक्शनल है। यदि आप दिशा को सही करना चाहते हैं, तो सॉफ्टप्लस का उपयोग करने पर विचार करें, फिर प्रशिक्षण सकारात्मक होने पर, या एलयू जैसे कुछ अन्य प्रकार का उपयोग करके, ReLU पर स्विच करें।
कार्ल

इस एक और तरीका है कहते हैं कि करने के लिए, एक Relu के लिए बेकार होने की उम्मीद है , के लिए सीखने पर नज़र ; यह सपाट है, यह नहीं सीखता है। x < x<0x<0
कार्ल

1
ढाल शून्य से नीचे के लिए शून्य हो जाती है; यह स्टाल। x
कार्ल

जवाबों:


14

वहाँ एक समारोह के रूप में नुकसान के अपने भूखंडों में एक संकेत है । इन भूखंडों के पास पास एक "किंक" है : ऐसा इसलिए है क्योंकि 0 के बाईं ओर, हानि की ढाल 0 पर गायब हो रही है (हालाँकि, एक उप-अपनाने वाला समाधान है क्योंकि नुकसान वहां से अधिक है जो )। इसके अलावा, इस साजिश से पता चलता है कि नुकसान फ़ंक्शन गैर-उत्तल है (आप एक रेखा खींच सकते हैं जो 3 या अधिक स्थानों में हानि वक्र को पार करता है), ताकि यह संकेत मिले कि हमें स्थानीय ऑप्टिमाइज़र जैसे कि डब्ल्यूडब्ल्यूडी का उपयोग करते समय सतर्क रहना चाहिए। वास्तव में, निम्नलिखित विश्लेषण से पता चलता है कि जब को नकारात्मक होने के लिए आरंभीकृत किया जाता है, तो एक उप-अपनाने वाले समाधान में परिवर्तित करना संभव है।ww=0w = 0 w = 1 ww=0w=1w

अनुकूलन समस्या

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

और आप ऐसा करने के लिए प्रथम-क्रम अनुकूलन का उपयोग कर रहे हैं। इस दृष्टिकोण के साथ एक समस्या यह है कि में ग्रेडिएंट हैf

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

जब आप शुरू करते हैं , तो आपको सही उत्तर के करीब आने के लिए के दूसरी ओर जाना होगा, जो । यह करना कठिन है, क्योंकि जब आपके पासबहुत, बहुत छोटा, ढाल वैसे ही गायब हो जाएगा छोटा है। इसके अलावा, आप बाईं ओर से 0 के करीब हो जाएंगे, आपकी प्रगति धीमी हो जाएगी!w<00w=1|w|

यही कारण है कि आपके प्लॉट्स में इनिशियलाइज़ेशन के लिए नेगेटिव , आपके ट्रैजेटरी सभी पास स्टाल करते हैं । यह वही है जो आपका दूसरा एनीमेशन दिखा रहा है।w(0)<0w(i)=0

यह मरने वाली रिले घटना से संबंधित है; कुछ चर्चा के लिए, मेरा ReLU नेटवर्क लॉन्च करने में विफल रहता है

एक दृष्टिकोण जो अधिक सफल हो सकता है, वह लीक रिल्यू के रूप में एक अलग नॉनलाइनियरिटी का उपयोग करना होगा, जिसमें तथाकथित "लुप्त होने वाली ढाल" मुद्दा नहीं है। टपका हुआ रिले समारोह है

g(x)={x,if x>0cx,otherwise
जहां एक स्थिरांक है तोछोटा और सकारात्मक है। इसका कारण यह है कि व्युत्पन्न कार्य 0 है "बाईं ओर।"c|c|

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

सेट करना साधारण रिले है। ज्यादातर लोग का चयन कुछ ऐसे करते हैं जैसे या । मैंने उपयोग नहीं देखा है, हालांकि मैं इस बात का अध्ययन करना चाहूंगा कि इस तरह के नेटवर्क पर क्या प्रभाव पड़ता है, यदि कोई हो। (ध्यान दें कि यह पहचान फ़ंक्शन को कम कर देता है, के लिए; , ऐसी कई परतों की रचनाएं विस्फोटकों का कारण बन सकती हैं क्योंकि क्रमिक क्रमिक परतों में बड़े हो जाते हैं।)c=0c0.10.3c<0c=1,|c|>1

ओपी कोड को थोड़ा संशोधित करना एक प्रदर्शन प्रदान करता है कि समस्या सक्रियण फ़ंक्शन की पसंद के साथ है। यह कोड को ऋणात्मक बनाता है और साधारण के स्थान पर उपयोग करता है । नुकसान जल्दी से एक छोटे से मूल्य तक कम हो जाता है, और वजन सही ढंग से , जो कि इष्टतम है।wLeakyReLUReLUw=1

LeakyReLU समस्या को ठीक करता है

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)

मैंने इस कोड के साथ कुछ के आसपास खेला है और मैंने पाया है कि पर इनिशियलाइज़ेशन छोड़ रहा है और ऑप्टिमाइज़र को SGD से एडम, एडम + AMSGrad या SGD + गति में बदलने से मदद के लिए कुछ नहीं करता है। इसके अलावा, इस समस्या पर लुप्त होती प्रवणता को दूर करने में मदद नहीं करने के अलावा, एसडब्लूए से एडम को बदलने से वास्तव में प्रगति धीमी हो जाती है।w(0)=10

दूसरी ओर, आप के लिए प्रारंभ बदलते हैं और एडम (कदम आकार 0.01) के लिए अनुकूलक बदलने के लिए, तो आप वास्तव में गायब हो जाने ढाल दूर कर सकते हैं। यह तब भी काम करता है जब आप और SGD को गति (चरण आकार 0.01) के साथ उपयोग करते हैं। यहां तक ​​कि अगर आप वेनिला SGD (चरण आकार 0.01) और उपयोग करते हैं तो भी यह काम करता है ।w(0)=1 w(0)=1w(0)=1

प्रासंगिक कोड नीचे है; उपयोग opt_sgdया 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)

जब मुझे आउटपुट वज़न और पूर्वाग्रह था, तो मैंने LeakyReLU, ELU, SELU के साथ यही समस्या देखी, लेकिन मुझे यकीन नहीं है कि अगर मैंने आउटपुट के बिना कोशिश की। मैं जांच
करूंगा

1
(हां, आप सही कह रहे हैं कि LeakyReLU और ELU इस उदाहरण के लिए ठीक काम करते हैं)
Endolith

2
अच्छा मैं समझा। यह है नुकसान समारोह की ढाल वंश कर रही है, यह सिर्फ है कि नुकसान समारोह तो ढाल वंश वहाँ अटक जाता फ्लैट (0 ढाल) 0 में हो जाता है जब नकारात्मक पक्ष से आ रहा, है। अब यह स्पष्ट प्रतीत होता है। : डी
एंडोलिथ

2
बिल्कुल सही। सूचना कैसे बनाम नुकसान के अपने भूखंडों एक "गुत्थी" 0 के पास है: क्योंकि 0 की बाईं तरफ, कि की ढाल नुकसान के 0 (हालांकि करने के लिए गायब हो जाने है, यह एक से इनकी समाधान है, क्योंकि नुकसान से अधिक यह है के लिए )। इसके अलावा, इस साजिश से पता चलता है कि नुकसान फ़ंक्शन गैर-उत्तल है (आप एक रेखा खींच सकते हैं जो 3 या अधिक स्थानों में हानि वक्र को पार करता है), ताकि यह संकेत मिले कि हमें स्थानीय ऑप्टिमाइज़र जैसे कि डब्ल्यूडब्ल्यूडी का उपयोग करते समय सतर्क रहना चाहिए। ww=0
साइकोरैक्स

2
रिले सक्रियण का उपयोग करते समय, गति के बिना भी SGD होंठ पर जा सकता है यदि चरण आकार के विशिष्ट मूल्य के लिए पर्याप्त है । w(i)
साइकोरैक्स का कहना है कि मोनिका
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.