मैं आरएनएन का उपयोग कर एक साधारण पाठ (नाम) जनरेटर बनाने की कोशिश कर रहा हूँ। मैं मॉडल को ठीक बनाता हूं लेकिन जब मैं मूल्यों की भविष्यवाणी करने की कोशिश करता हूं तो मुझे हमेशा एक ही अक्षर मिलता है।

मेरा कोड इस प्रकार है:

from tensorflow.keras.activations import softmax
from tensorflow.keras.losses import categorical_crossentropy
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense

# parameters
LSTM_NODES = 100
MAX_NAME_LEN = 30
STOP_MARKER = '.'

# hyper-parameters
EPOCHS = 10

# read _names.train into an array
names = open('names.train', encoding='utf-8').read().strip().split('\n')

# precompute the number of samples
SAMPLES = 0
for name in names:
    for _ in name:
        SAMPLES = SAMPLES + 1

# get a sorted list of all unique characters used
corpus = sorted(list({l for name in names for l in name}))

# the first letter in the corpus must be the stop indicator
corpus.insert(0, STOP_MARKER)

# write out the corpus so that the predict script can use it
open('corpus.txt', 'w').write('\n'.join(corpus))

# calculate the input shape for the network
input_shape = (MAX_NAME_LEN, len(corpus))

# Creating a mapping from unique characters to indices
char2idx = {u:i for i, u in enumerate(corpus)}
idx2char = np.array(corpus)


def get_text(sample):
    t = ''
    for x in sample:
        n = idx2char[np.argmax(x)]
        t = t + n
    return t


# I need a 3-D array, samples x character position x character one-hot encoded
X = np.zeros((SAMPLES, MAX_NAME_LEN, len(corpus)), int)
Y = np.zeros((SAMPLES, len(corpus)), int)

# for each sample name
for name in names:
    # number of samples for this name is equal to the number of letters (we add one letter per loop)
    for i in range(len(name)):
        j = 0
        # create one sample
        while j <= i:
            one_hot_letter = np.zeros(len(corpus), int)
            one_hot_letter[char2idx[name[j]]] = 1
            X[i, j] = one_hot_letter
            j = j + 1
        # get the next character in the sequence
        one_hot_next = np.zeros(len(corpus), int)
        if j < len(name):
            one_hot_next[char2idx[name[j]]] = 1
        # add this character to the Y sample
        Y[i] = one_hot_next
        # print this sample
        print('X={} Y={}'.format(get_text(X[i]), idx2char[np.argmax(Y[i])]))

# build the model
model = Sequential()
model.add(LSTM(LSTM_NODES, input_shape=input_shape))
model.add(Dense(input_shape[1], activation=softmax))
model.compile(loss=categorical_crossentropy, optimizer='adam')
model.summary()

# train the model
model.fit(X, Y, epochs=EPOCHS)

# save the model
model.save('model.h5')

# try a sample prediction
# first letter is the seed
SEED = 'M'
name = SEED
x = np.zeros((1, input_shape[0], input_shape[1]), int)
one_hot_letter = np.zeros(len(corpus), int)
one_hot_letter[char2idx[SEED]] = 1
x[0, 0] = one_hot_letter
for i in range(1, MAX_NAME_LEN):
    predictions = model.predict(x)
    # get the next letter and add it to the prediction
    next_letter = np.zeros(input_shape[1], int)
    next_letter[np.argmax(predictions[0])] = 1
    x[0, i] = next_letter
    name = name + idx2char[np.argmax(next_letter)]
    print(name)

अंत में आउटपुट है:

Mww
Mwww
Mwwww
Mwwwww
Mwwwwww
Mwwwwwww
Mwwwwwwww
Mwwwwwwwww
Mwwwwwwwwww
Mwwwwwwwwwww
Mwwwwwwwwwwww
Mwwwwwwwwwwwww
Mwwwwwwwwwwwwww
Mwwwwwwwwwwwwwww
Mwwwwwwwwwwwwwwww
Mwwwwwwwwwwwwwwwww
Mwwwwwwwwwwwwwwwwww
Mwwwwwwwwwwwwwwwwwww
Mwwwwwwwwwwwwwwwwwwww
Mwwwwwwwwwwwwwwwwwwwww
Mwwwwwwwwwwwwwwwwwwwwww
Mwwwwwwwwwwwwwwwwwwwwwww
Mwwwwwwwwwwwwwwwwwwwwwwww
Mwwwwwwwwwwwwwwwwwwwwwwwww
Mwwwwwwwwwwwwwwwwwwwwwwwwww
Mwwwwwwwwwwwwwwwwwwwwwwwwwww
Mwwwwwwwwwwwwwwwwwwwwwwwwwwww
Mwwwwwwwwwwwwwwwwwwwwwwwwwwwww

कोई विचार की क्या गलत हो सकता है? मुझे लगता है कि मेरे नमूने ठीक हैं। मैंने उन्हें किसी और के द्वारा लिखे गए एक अन्य उदाहरण में इस्तेमाल किया और उन्होंने अलग-अलग परिणाम दिए। मेरे पास 280 नमूने हैं। यहाँ names.train कैसा दिखता है:

Adaldrida
Celendine
Gloriana
Pimpernel
Tanta
Alfrida
Cora
Goldilocks
Melba

प्रशिक्षण से पूरा आउटपुट है:

[snip]
X=Valde......................... Y=m
X=Valdem........................ Y=a
X=Valdema....................... Y=r
X=Valdemar...................... Y=.
2020-03-09 13:38:26.827190: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2020-03-09 13:38:26.843439: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x7fa8f211d590 initialized for platform Host (this does not guarantee that XLA will be used). Devices:
2020-03-09 13:38:26.843450: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Host, Default Version
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
lstm (LSTM)                  (None, 100)               58800     
_________________________________________________________________
dense (Dense)                (None, 46)                4646      
=================================================================
Total params: 63,446
Trainable params: 63,446
Non-trainable params: 0
_________________________________________________________________
Train on 1795 samples
Epoch 1/10
1795/1795 [==============================] - 2s 1ms/sample - loss: 0.0168
Epoch 2/10
1795/1795 [==============================] - 1s 462us/sample - loss: 0.0167
Epoch 3/10
1795/1795 [==============================] - 1s 445us/sample - loss: 0.0164
Epoch 4/10
1795/1795 [==============================] - 1s 450us/sample - loss: 0.0163
Epoch 5/10
1795/1795 [==============================] - 1s 449us/sample - loss: 0.0162
Epoch 6/10
1795/1795 [==============================] - 1s 453us/sample - loss: 0.0160
Epoch 7/10
1795/1795 [==============================] - 1s 593us/sample - loss: 0.0159
Epoch 8/10
1795/1795 [==============================] - 1s 599us/sample - loss: 0.0160
Epoch 9/10
1795/1795 [==============================] - 1s 442us/sample - loss: 0.0160
Epoch 10/10
1795/1795 [==============================] - 1s 440us/sample - loss: 0.0160
Mw
Mww
Mwww
Mwwww
Mwwwww
Mwwwwww
Mwwwwwww
Mwwwwwwww
Mwwwwwwwww
Mwwwwwwwwww
Mwwwwwwwwwww
[snip]```

1
DungeonTiger 9 मार्च 2020, 20:44
आपके model.fit() का आउटपुट क्या है, क्या प्रशिक्षण के दौरान हानि और सटीकता में परिवर्तन होता है?
 – 
abdoulsn
9 मार्च 2020, 20:49
क्या आप np.zeros() के साथ वजन शुरू कर रहे हैं यदि हाँ यह ग्रेडिएंट डिसेंट के साथ काम नहीं करता है।
 – 
abdoulsn
9 मार्च 2020, 20:50
1795 नमूनों पर ट्रेन युग 5/10 1795/1795 [==========================] - 1s 449us/नमूना - हानि : 0.0162 युग 6/10 1795/1795 [==========================] - 1s 453us/नमूना - हानि: 0.0160 युग 7/10 1795/1795 [===========================] - 1s 593us/नमूना - हानि: 0.0159 युग 8 /10 1795/1795 [===========================] - 1s 599us/नमूना - हानि: 0.0160 युग 9/10 1795/1795 [===========================] - 1s 442us/नमूना - हानि: 0.0160 युग 10/10 1795/ 1795 [============================] - 1s 440us/नमूना - हानि: 0.0160
 – 
DungeonTiger
9 मार्च 2020, 21:00
1
यदि आप यहां आउटपुट दिखा सकते हैं (पोस्ट संपादित करके) तो यह हमारी मदद कर सकता है।
 – 
abdoulsn
9 मार्च 2020, 21:00
और नहीं, मैं वज़न को शून्य पर प्रारंभ नहीं कर रहा हूं।
 – 
DungeonTiger
9 मार्च 2020, 21:00

3 जवाब

मुझे लगता है कि आपके कोड और प्रशिक्षण पद्धति में कोई समस्या नहीं है, हालांकि मुझे लगता है कि आपको अलग-अलग डेटा सेट से अलग परिणाम मिलते हैं जो 2 संभावित कारणों से आ सकते हैं।

1) आपने मॉडल को पर्याप्त रूप से प्रशिक्षित नहीं किया और परिणामस्वरूप अंडर-फिटिंग समस्या हुई। मुझे लगता है कि आपका मॉडल अधिक उपयुक्त नहीं है क्योंकि आपके डेटा सेट में केवल 'w' नहीं है जो 'M' का अनुसरण करता है। (शायद मैं गलत हूं, आप अपने डेटा सेट और अपने आउटपुट वितरण की जांच कर सकते हैं)

2) यह आपके char2idx और idx2char मैपिंग से आता है। चूंकि आप कॉर्पस से इंडेक्स और कैरेक्टर से मैपिंग डिक्शनरी बनाने की कोशिश कर रहे हैं, इसके परिणामस्वरूप प्रत्येक कॉर्पस के लिए अलग मैपिंग हो सकती है। आप प्रत्येक वर्ण के लिए एक सामान्य मैपिंग डिक्शनरी बनाकर इस समस्या को हल कर सकते हैं और मैपिंग स्थिरता बनाए रखने के लिए प्रत्येक डेटा सेट में प्रशिक्षण और भविष्यवाणी के लिए इसका उपयोग कर सकते हैं (आप अपने मैपिंग डिक्शनरी को JSON फ़ाइल के रूप में सहेज सकते हैं)। उदाहरण के लिए, अक्षर 'ए' हमेशा [1,0,0,0,...] होगा, अक्षर 'ए' हमेशा हर प्रशिक्षण और भविष्यवाणी में [0,1,0,0,...] होगा। इसके अलावा, क्योंकि आप चरित्र आधार भविष्यवाणी करने की कोशिश कर रहे हैं, आपको अपने चरित्र की संख्या के बराबर अपनी आउटपुट परत की संख्या की आवश्यकता है ताकि आप सभी संभावित पात्रों पर संभाव्यता वितरण कर सकें।

युक्ति

डिबगिंग उद्देश्य के लिए, आपको अपने संभाव्यता वितरण को प्रिंट करना होगा, इस मामले में predictions चर है, बस अपने मॉडल के वितरण को देखने के लिए ताकि आपको पता चल सके कि आपका मॉडल अंडरफिट या ओवरफिट है।

3
Ronakrit W. 13 मार्च 2020, 21:38

यह यहाँ SO पर

संक्षेप में, इस मुद्दे को टेक्स्ट डिजनरेशन और पहले पूछे गए उत्तर के लिए (भयानक) उत्तर कहा जाता है। प्रश्न इस सटीक समस्या का समाधान करने वाला उत्कृष्ट पेपर से लिंक करता है। लेखकों को उद्धृत करने के लिए:

शुद्ध नमूने द्वारा निर्मित पाठ इतना पतित क्यों है? इस काम में हम दिखाएँ कि "अविश्वसनीय पूंछ" को दोष देना है। यह अविश्वसनीय पूंछ अपेक्षाकृत कम संभावना वाले हजारों उम्मीदवार टोकन से बना है जो कुल में अधिक प्रतिनिधित्व करते हैं।

वे पाते हैं कि साधारण नमूने से लूप या दोहराव हो सकता है क्योंकि जनरेटिव मॉडल ऐसे सैंपलिंग टोकन रखेंगे जो अनुक्रम बनाते हैं जो बहुत संभावित हैं, यानी, पुनरावृत्ति उपन्यास टोकन की तुलना में कम "आश्चर्यजनक" है। लालची नमूने की आधार रेखा की तुलना उन तरीकों से करें जो अविश्वसनीय पूंछ को स्पष्ट रूप से काटते हैं: figure

चित्र 9, Holtzman et al। (2020)

तो सबसे पहले, जैसा कि रोनाकृत ने उल्लेख किया है, आपको टोकन के एक निश्चित शब्दकोश पर लॉगिट्स (संभावनाओं) का एक वेक्टर आउटपुट करना चाहिए।

फिर, लालची नमूने की तुलना में थोड़ी अधिक परिष्कृत डिकोडिंग रणनीति चुनें। TensorFlow बीम खोज और top-k, लेकिन मेरा सुझाव है कि आप रैंडम डिकोडिंग से शुरुआत करें, जिसके लिए आप TensorFlow टेक्स्ट जेनरेशन ट्यूटोरियल में एक कारगर क्रियान्वयन देखें:

# Generate probabilities from the model.
for input_example_batch, target_example_batch in dataset.take(1):
  example_batch_predictions = model(input_example_batch)
  print(example_batch_predictions.shape, "# (batch_size, sequence_length, vocab_size)")

# Sample from model outputs.
sampled_indices = tf.random.categorical(example_batch_predictions[0], num_samples=1)
sampled_indices = tf.squeeze(sampled_indices,axis=-1).numpy()

# Look up tokens from the dictionary.
print("Input: \n", repr("".join(idx2char[input_example_batch[0]])))
print()
print("Next Char Predictions: \n", repr("".join(idx2char[sampled_indices ])))
2
Talmo Pereira 19 मार्च 2020, 23:55

इसलिए मैंने आपके कोड के साथ एक सरल प्रयोग करने की कोशिश की, और एडम ऑप्टिमाइज़र पर सीखने की दर को घटाकर 0.00001 कर दिया, और नीचे परिणाम है:

Train on 1453 samples
Epoch 1/30

AEcOOOOONfffffwfwffwfpXWHfHHfA
BEEcOOOfffffwfwfwzffwfzffAdfWH
CEEccOOffffffwfwfwzfffpigMIwHH
FEcOOOOffffffwfwfwfzffwfWgCwHH
MEEcOOcffffffwfwfwfpXW.WggCIwH
PEEcOfffffffwfwfwzffwfzfzfAfAd

1453/1453 - 10s - loss: 0.0162
Epoch 2/30

AEEEcOcOOOOOffffwffwffpbWAHfHH
BEEEEccOOOfffffwffwffpbWAHfHHf
CEEEcEcOOOffffffwffwfpbWAHfHHf
FEEEccOOOOOfffffwffwffpbWAHfHH
MEEEcOOOOOOcOOONfffwfffFFooewG
PEEEcOOOOOOONcffffwffwffWpbAHH

1453/1453 - 4s - loss: 0.0162
Epoch 3/30

AEEEEcOOOOOcOOOOONcuuuullNulXy
BEEEEcOOOOOOOONcOOONEOEFFFFFFC
CEEEEcOOOOOOOONcOOONEOEFFFFFFC
FEEEEcOOOcOOOOOONcOOEOEOEFFFFF
MEEEEcOOOOOOOONcOOONEOEFFFFFFC
PEEEEcOOOOOOOONcOOONEOEFFFFFFC

1453/1453 - 4s - loss: 0.0162
Epoch 4/30

AEEEEOOOOOOOOONcOOONEOEFFFFFFF
BEEEEEcOOOOOOOOONcOOEOEOEFFFFF
CEEEEEcOOOOOOOOONcOOEOEOEFFFFF
FEEEEOOOOOOOcOOOONONcuuuulllXy
MEEEEOOOOOOOOONcOOONEOEFFFFFFF
PEEEEEcOOOOOOOOONcOOEOEOEFFFFF

1453/1453 - 4s - loss: 0.0162
Epoch 5/30

AEEEEOOOOOOOOOOONcOOEOEOEFFFFF
BEEEEEOOOOOOOOOONcOOEOEOEFFFFF
CEEEEEOOOOOOOOOONcOOEOEOEFFFFF
FEEEEOOOOOOOOOOONcOOEOEOEFFFFF
MEEEEOOOOOOOOOOONcOOEOEOEFFFFF
PEEEEEOOOOOOOOOONcOOEOEOEFFFFF

1453/1453 - 4s - loss: 0.0162
Epoch 6/30

AEEEEOOOOOOOOOOOONcOOEOEEFFFFF
BEEEEEOOOOOOOOOOONcOOEOEEFFFFF
CEEEEEOOOOOOOOOOOONcOEOEEFFFFF
FEEEEOOOOOOOOOOOONcOOEOEEFFFFF
MEEEEOOOOOOOOOOOONcOOEOEEFFFFF
PEEEEEOOOOOOOOOOOONcOEOEEFFFFF

...

Epoch 26/30

AOOOOOOOOOOOEOEOOEOEOEOEEEEEEE
BOOOOOOOOOOOOEOEOEOOEEOEEEEEEE
COOOOOOOOOOOOEOEOEOOEOEEEEEEEE
FOOOOOOOOOOOOOEOEOOEOEEOEEEEEE
MOOOOOOOOOOOOEOEOEOEOEOEEEEEEE
POOOOOOOOOOOOEOEOEOOEOEEEEEEEE

1453/1453 - 4s - loss: 0.0159
Epoch 27/30

AOEEEEEEEEEEEEEEOEOEOEOEEEEEEE
BOEEEEEEEEEEEEEEOEOEOOEEEEEEEE
COEEEEEEEEEEEEEEOEOOEOEEEEEEEE
FOOEEEEEEEEEEEEEOOEOEOEOEEEEEE
MOEEEEEEEEEEEEEEOEOEOEOEEEEEEE
POEEEEEEEEEEEEEEOEOOEOEEEEEEEE

1453/1453 - 4s - loss: 0.0155
Epoch 28/30

AEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
BEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
CEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
FEEEEEEEEEEEEEEEEEEEEEEEOEEEEE
MEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
PEEEEEEEEEEEEEEEEEEEEEEEEEEEEE

1453/1453 - 4s - loss: 0.0165
Epoch 29/30

AEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
BEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
CEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
FEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
MEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
PEEEEEEEEEEEEEEEEEEEEEEEEEEEEE

1453/1453 - 4s - loss: 0.0158
Epoch 30/30

AEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
BEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
CEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
FEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
MEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
PEEEEEEEEEEEEEEEEEEEEEEEEEEEEE

1453/1453 - 4s - loss: 0.0159

जैसा कि आप देख सकते हैं, प्रारंभ में, यह हमेशा एक ही अक्षर उत्पन्न नहीं करता है, लेकिन युग 29 पर यह एक ही अक्षर उत्पन्न करता है, इसका अर्थ है कि आपकी सीखने की दर बहुत अधिक थी।

लेकिन निश्चित रूप से, अभी भी एक समस्या है जो यह सीखने के लिए प्रतीत नहीं होता है (अंडरफिटिंग), इस बार आपको और प्रयोग करने की आवश्यकता है, मुझे लगता है कि यह अधिक संभावना है क्योंकि आप मेरे अनुभव में इनपुट और आउटपुट को कैसे मॉडल करते हैं , अगर मैं अगली भविष्यवाणी करना चाहता हूं, तो मैं आमतौर पर इसे इस तरह से मॉडल करता हूं:

X -> Y
Adaldrida -> daldrida.

और return_sequences=True का उपयोग करके केवल अंतिम समय चरण के बजाय, प्रत्येक समय चरण से आउटपुट प्राप्त करें, जैसा कि यह लिंक वर्णन करें। इसके विपरीत आप इसे कैसे मॉडल करते हैं:

X -> Y
A -> d
Ad -> a
Ada -> l
etc.

उस तरह के इनपुट-आउटपुट मॉडलिंग का उपयोग करते हुए, मुझे लगता है कि आपको समस्याओं का सामना करना पड़ेगा जैसे कि पहले वर्ण के बाद बहुत अधिक शून्य होंगे, और नेटवर्क ने पहले वर्ण को अनदेखा कर दिया होगा, आप प्री-पैडिंग का उपयोग करने का प्रयास कर सकते हैं, इसलिए पिछला शून्य शुरुआत में होगा, अंत में नहीं, या आप अनुक्रम को उलटने का भी प्रयास कर सकते हैं।

एक और कारण है कि आपका मॉडल क्यों नहीं सीख सकता है, हो सकता है कि आपको अधिक डेटा जोड़ने का प्रयास करना चाहिए या अधिकतम नाम लंबाई में बदलाव करना चाहिए।

0
Damzaky 19 मार्च 2020, 07:03