2010-11-17 6 views
16

Мне нужно обучить сеть, чтобы умножить или добавить 2 входа, но она не кажется хорошо аппроксимируемой для всех точек после 20000 итераций. В частности, я тренирую его по всему набору данных, и он хорошо подходит для последних точек, но кажется , как будто он не становится лучше для первых конечных точек. Я нормализую данные так, чтобы они находились между -0.8 и 0.8. Сама сеть состоит из 2 входов 3 скрытых нейронов и 1 выходного нейрона. Я также установил скорость обучения в сети 0,25, и использовал ее как функцию обучения tanh (x).Тренировка нейронной сети для добавления

Он очень хорошо подходит для очков, которые обучаются последним в наборе данных, но для первых точек кажется, что не может хорошо аппроксимироваться. Интересно, что это такое, что не помогает ему хорошо подстраиваться, будь то топология, которую я использую, или что-то еще?

Также, сколько нейронов подходит для скрытого слоя для этой сети?

+0

Насколько я знаю, у нейрона есть двоичный выход, он «срабатывает» или нет. Как вы планируете получать вывод, например, добавление или умножение, если выход по умолчанию равен 1 или 0? – dStulle

+3

@dStulle Нет, это всего лишь один тип нейрона (хотя и общий), о котором вы говорите. – Kos

ответ

-4

Подумайте, что произойдет, если вы замените пороговую функцию tanh(x) линейной функцией x - назовите ее a.x - и обработайте a как единственный параметр обучения в каждом нейроне. Это эффективно то, что ваша сеть будет оптимизировать; это приближение нулевого пересечения функции tanh.

Теперь, когда вы накладываете нейроны этого линейного типа? Вы умножаете выход каждого нейрона, поскольку импульс идет от входа к выходу. Вы пытаетесь аппроксимировать добавление с помощью набора умножений. Это, как говорится, не вычисляется.

+3

Я думаю, что с вашей математикой что-то не так. Без нелинейной функции активации многослойный ANN сворачивается в однослойный, который, в свою очередь, просто умножает входной вектор на весовую матрицу. Каждый выход представляет собой только взвешенную * сумму * входов. Один нейрон/персептрон с весами «1» и смещением 0 суммируют два входа. –

6

Сеть, состоящая из одного нейрона с весами = {1,1}, смещение = 0 и функция линейной активации выполняет добавление двух входных чисел.

Умножение может быть сложнее. Вот два подхода, которые может использовать сеть:

  1. Преобразование одного из чисел в цифрах (например, двоичных) и выполнение умножения, как в начальной школе. a*b = a*(b0*2^0 + b1*2^1 + ... + bk*2^k) = a*b0*2^0 + a*b1*2^1 + ... + a*bk*2^k. Этот подход прост, но требует переменное число нейронов, пропорциональное длине (логарифму) ввода b.
  2. Возьмите логарифмы входов, добавьте их и оцените результат. a*b = exp(ln(a) + ln(b)) Эта сеть может работать с номерами любой длины, если она достаточно хорошо приближает логарифм и показатель экспоненты.
1

Если вы хотите, чтобы держать вещи нейронных (ссылки имеют веса, нейрон вычисляет на ponderated сумму входов с помощью весов и ответов 0 или 1 в зависимости от сигмы суммы и использование обратного распространения в градиент), тогда вы должны думать о нейроне скрытого слоя как классификаторы . Они определяют линию, которая отделяет входное пространство от классов: 1 класс соответствует той части, где нейрон отвечает 1, другой, когда он отвечает 0. Второй нейрон скрытого слоя определит другое разделение и так далее. Выходной нейрон объединяет выходы скрытого слоя, адаптируя его веса для его вывода, чтобы соответствовать тем, которые вы представили во время обучения.
Следовательно, один нейрон будет классифицировать входное пространство в 2 классах (возможно, соответствующее добавлению в зависимости от базы данных обучения). Два нейрона смогут определить 4 класса. Три нейроны 8 классов и т. Д.Подумайте о выходе скрытых нейронов в виде степеней 2: h1*2^0 + h2*2^1+...+hn*2^n, где hi является результатом скрытого нейрона i. NB: вам понадобятся n выходных нейронов. Это отвечает на вопрос о количестве скрытых нейронов для использования.
Но NN не вычисляет дополнение. Он рассматривает это как проблему классификации, основанную на том, что он узнал. Он никогда не сможет генерировать правильный ответ для значений, которые находятся вне его базы обучения. На этапе обучения он настраивает весы для размещения разделителей (линий в 2D), чтобы дать правильный ответ. Если ваши входы находятся в [0,10], он научится производить правильные ответы на добавление значений в [0,10]^2, но никогда не даст хорошего ответа для 12 + 11.
Если ваши последние значения хорошо изучены и первые забыты, попробуйте снизить скорость обучения: модификации весов (в зависимости от градиента) последних примеров могут переопределить первый (если вы используете стохастический backprop) , Убедитесь, что ваша учебная база является справедливой. Вы также можете чаще представлять примеры с плохо изученными примерами. И попробуйте многие значения скорости обучения, пока не найдете хороший.

4

Возможно, слишком поздно, но простым решением является использование RNN (Recurrent Neural Network).

RNN SUM TWO DIGITS

После преобразования ваших номеров в цифры, ваш NN займет пару цифр из последовательности цифр слева направо.

RNN должен зациклиться на одном из своих выходов, чтобы он мог автоматически понимать, что есть цифра для переноса (если сумма равна 2, напишите 0 и нести 1).

Чтобы обучить его, вам нужно будет предоставить ему входы, состоящие из двух цифр (один от первого номера, второго от второго номера) и желаемого выхода. И RNN в конечном итоге найдет, как сделать сумму.

Обратите внимание, что этот РНН будет необходимо знать 8 следующие случаи только чтобы узнать, как суммировать два числа:

  • 1 + 1, 0 + 0, 1 + 0, 0 + 1 с переносом
  • 1 + 1, 0 + 0, 1 + 0, 0 + 1, не несут
0

Я пытался сделать то же самое. Получил 2,3,4 разряда цифр и смог достичь 97% -ной точности. Вы можете достичь с помощью одного из нейронной сети типа,

Sequence to Sequence Learning with Neural Networks

пример программа с Juypter ноутбуками от keras доступен по следующей ссылке,

https://github.com/keras-team/keras/blob/master/examples/addition_rnn.py

Надеется, что это помогает.

Прикрепление кода здесь для ознакомления.

from __future__ import print_function 
from keras.models import Sequential 
from keras import layers 
import numpy as np 
from six.moves import range 


class CharacterTable(object): 
    """Given a set of characters: 
    + Encode them to a one hot integer representation 
    + Decode the one hot integer representation to their character output 
    + Decode a vector of probabilities to their character output 
    """ 
    def __init__(self, chars): 
     """Initialize character table. 
     # Arguments 
      chars: Characters that can appear in the input. 
     """ 
     self.chars = sorted(set(chars)) 
     self.char_indices = dict((c, i) for i, c in enumerate(self.chars)) 
     self.indices_char = dict((i, c) for i, c in enumerate(self.chars)) 

    def encode(self, C, num_rows): 
     """One hot encode given string C. 
     # Arguments 
      num_rows: Number of rows in the returned one hot encoding. This is 
       used to keep the # of rows for each data the same. 
     """ 
     x = np.zeros((num_rows, len(self.chars))) 
     for i, c in enumerate(C): 
      x[i, self.char_indices[c]] = 1 
     return x 

    def decode(self, x, calc_argmax=True): 
     if calc_argmax: 
      x = x.argmax(axis=-1) 
     return ''.join(self.indices_char[x] for x in x) 


class colors: 
    ok = '\033[92m' 
    fail = '\033[91m' 
    close = '\033[0m' 

# Parameters for the model and dataset. 
TRAINING_SIZE = 50000 
DIGITS = 3 
INVERT = True 

# Maximum length of input is 'int + int' (e.g., '345+678'). Maximum length of 
# int is DIGITS. 
MAXLEN = DIGITS + 1 + DIGITS 

# All the numbers, plus sign and space for padding. 
chars = '' 
ctable = CharacterTable(chars) 

questions = [] 
expected = [] 
seen = set() 
print('Generating data...') 
while len(questions) < TRAINING_SIZE: 
    f = lambda: int(''.join(np.random.choice(list('')) 
        for i in range(np.random.randint(1, DIGITS + 1)))) 
    a, b = f(), f() 
    # Skip any addition questions we've already seen 
    # Also skip any such that x+Y == Y+x (hence the sorting). 
    key = tuple(sorted((a, b))) 
    if key in seen: 
     continue 
    seen.add(key) 
    # Pad the data with spaces such that it is always MAXLEN. 
    q = '{}+{}'.format(a, b) 
    query = q + ' ' * (MAXLEN - len(q)) 
    ans = str(a + b) 
    # Answers can be of maximum size DIGITS + 1. 
    ans += ' ' * (DIGITS + 1 - len(ans)) 
    if INVERT: 
     # Reverse the query, e.g., '12+345 ' becomes ' 543+21'. (Note the 
     # space used for padding.) 
     query = query[::-1] 
    questions.append(query) 
    expected.append(ans) 
print('Total addition questions:', len(questions)) 

print('Vectorization...') 
x = np.zeros((len(questions), MAXLEN, len(chars)), dtype=np.bool) 
y = np.zeros((len(questions), DIGITS + 1, len(chars)), dtype=np.bool) 
for i, sentence in enumerate(questions): 
    x[i] = ctable.encode(sentence, MAXLEN) 
for i, sentence in enumerate(expected): 
    y[i] = ctable.encode(sentence, DIGITS + 1) 

# Shuffle (x, y) in unison as the later parts of x will almost all be larger 
# digits. 
indices = np.arange(len(y)) 
np.random.shuffle(indices) 
x = x[indices] 
y = y[indices] 

# Explicitly set apart 10% for validation data that we never train over. 
split_at = len(x) - len(x) // 10 
(x_train, x_val) = x[:split_at], x[split_at:] 
(y_train, y_val) = y[:split_at], y[split_at:] 

print('Training Data:') 
print(x_train.shape) 
print(y_train.shape) 

print('Validation Data:') 
print(x_val.shape) 
print(y_val.shape) 

# Try replacing GRU, or SimpleRNN. 
RNN = layers.LSTM 
HIDDEN_SIZE = 128 
BATCH_SIZE = 128 
LAYERS = 1 

print('Build model...') 
model = Sequential() 
# "Encode" the input sequence using an RNN, producing an output of HIDDEN_SIZE. 
# Note: In a situation where your input sequences have a variable length, 
# use input_shape=(None, num_feature). 
model.add(RNN(HIDDEN_SIZE, input_shape=(MAXLEN, len(chars)))) 
# As the decoder RNN's input, repeatedly provide with the last hidden state of 
# RNN for each time step. Repeat 'DIGITS + 1' times as that's the maximum 
# length of output, e.g., when DIGITS=3, max output is 999+999=1998. 
model.add(layers.RepeatVector(DIGITS + 1)) 
# The decoder RNN could be multiple layers stacked or a single layer. 
for _ in range(LAYERS): 
    # By setting return_sequences to True, return not only the last output but 
    # all the outputs so far in the form of (num_samples, timesteps, 
    # output_dim). This is necessary as TimeDistributed in the below expects 
    # the first dimension to be the timesteps. 
    model.add(RNN(HIDDEN_SIZE, return_sequences=True)) 

# Apply a dense layer to the every temporal slice of an input. For each of step 
# of the output sequence, decide which character should be chosen. 
model.add(layers.TimeDistributed(layers.Dense(len(chars)))) 
model.add(layers.Activation('softmax')) 
model.compile(loss='categorical_crossentropy', 
       optimizer='adam', 
       metrics=['accuracy']) 
model.summary() 

# Train the model each generation and show predictions against the validation 
# dataset. 
for iteration in range(1, 200): 
    print() 
    print('-' * 50) 
    print('Iteration', iteration) 
    model.fit(x_train, y_train, 
       batch_size=BATCH_SIZE, 
       epochs=1, 
       validation_data=(x_val, y_val)) 
    # Select 10 samples from the validation set at random so we can visualize 
    # errors. 
    for i in range(10): 
     ind = np.random.randint(0, len(x_val)) 
     rowx, rowy = x_val[np.array([ind])], y_val[np.array([ind])] 
     preds = model.predict_classes(rowx, verbose=0) 
     q = ctable.decode(rowx[0]) 
     correct = ctable.decode(rowy[0]) 
     guess = ctable.decode(preds[0], calc_argmax=False) 
     print('Q', q[::-1] if INVERT else q, end=' ') 
     print('T', correct, end=' ') 
     if correct == guess: 
      print(colors.ok + '☑' + colors.close, end=' ') 
     else: 
      print(colors.fail + '☒' + colors.close, end=' ') 
     print(guess) 
Смежные вопросы