Как построить RNN, используя NumPy - PullRequest
0 голосов
/ 06 января 2019

Я пытаюсь реализовать рекуррентную нейронную сеть, используя Numpy в python. Я пытаюсь реализовать RNN "многие-к-одному" для проблемы классификации. Я немного запутался в коде psuedo, особенно в концепции BPTT. Я доволен прямым проходом (не совсем уверен, верна ли моя реализация), но действительно перепутан с обратным проходом, и мне нужен совет от экспертов в этой области.

Я проверил похожие посты: 1) Реализация RNN в numpy

2) Выход для RNN

3) Как построить RNN

Но я чувствую, что моя проблема в том, чтобы сначала понять код / ​​концепцию псевдо, код в этих постах завершен и достиг более высокого уровня, чем мой.

Моя реализация основана на руководстве:

WildML RNN с нуля

Я реализовал нейронную сеть с прямой связью после части урока того же автора, но я действительно запутался с этой реализацией его. RNN-видео Эндрю Нга предлагает 3 различных веса (веса для уровней активации, входного и выходного слоев), но в приведенном выше руководстве есть только два набора весов (поправьте меня, если я ошибаюсь).

Номенклатура в моем коде соответствует номенклатуре псевдокода Эндрю Нга ...

Я изменяю свои входные сэмплы в 3D (batch_size, n_time шаги, n_ измерения) ... Как только я изменяю свои сэмплы, я делаю прямую передачу каждого сэмпла отдельно ...

Вот мой код:

def RNNCell(X, lr, y=None, n_timesteps=None, n_dimensions=None, return_sequence = None, bias = None):



'''Simple function to compute forward and bakward passes for a Many-to-One Recurrent  Neural Network Model.

This function Reshapes X,Y in to 3D array of shape (batch_size, n_timesteps, n_ dimensions) and then performs

recurrent operations on each sample of the data for n_timesteps'''

# If user has specified some target variable
if len(y) != 0:

    # No. of unique values in the target variables will be the dimesions for the output layer
    _,n_unique = np.unique(y, return_counts=True)

else:

    # If there's no target variable given, then dimensions of target variable by default is 2
    n_unique = 2


# Weights of Vectors to multiply with input samples
Wx = np.random.uniform(low = 0.0,

                       high = 0.3,

                      size = (n_dimensions, n_dimensions))

# Weights of  Vectors to multiply with resulting activations
Wy = np.random.uniform(low = 0.0,

                      high = 0.3,

                      size = (n_dimensions, n_timesteps))

# Weights of Vectors to multiple with activations of previous time steps
Wa = np.random.randn(n_dimensions, n_dimensions)


# List to hold activations of each time step
activations = {'a-0' : np.zeros(shape=(n_timesteps-1, n_dimensions),

                               dtype=float)}


# List to hold Yhat at each time step
Yhat = []

try:
    # Reshape X to align with the shape of RNN architecture
    X = np.reshape(X, newshape=(len(X), n_timesteps, n_dimensions))

except:

    return "Sorry can't reshape and array in to your shape"


def Forward_Prop(sample):

    # Outputs at the last time step
    Ot = 0

    # In each time step
    for time_step in range(n_timesteps+1):

        if time_step < n_timesteps:

            # activation G ( Wa.a<t> + X<t>.Wx )
            activations['a-' + str(time_step+1)] = ReLu( np.dot( activations['a-' + str(time_step)], Wa )   
                                            + np.dot(   sample[time_step, :].reshape(1, n_dimensions)    , Wx    ) )

        # IF it's the last time step then use softmax activation function
        elif time_step == n_timesteps:

            # Wy.a<t> and appending that to Yhat list
            Ot = softmax( np.dot( activations['a-' + str(time_step)], Wy ) ) 

    # Return output probabilities
    return Ot


def Backward_Prop(Yhat):

    # List to hold errors for the last layer
    error = []

    for ind in range(len(Yhat)):

        error.append(   y[ind] - Yhat[ind]  )

    error = np.array(error)

    # Calculating Delta for the output layer
    delta_out = error * lr 
    #* relu_derivative(activations['a-' + str(n_timesteps)])



    # Calculating gradient for the output layer
    grad_out = np.dot(delta_out.reshape(len(X), n_timesteps),
                      activations['a-' + str(n_timesteps)])


    # I'm basically stuck at this point

    # Adjusting weights for the output layer
    Wy = Wy - (lr * grad_out.reshape((n_dimesions, n_timesteps)))








for sample in X:

    Yhat.append( Forward_Prop(sample) )


Backward_Prop(Yhat)


return Yhat




  # DUMMY INPUT DATA
   X = np.random.random_integers(low=0, high = 5, size = (10, 10 ));

# DUMMY LABELS
y = np.array([[0],
             [1],
             [1],
             [1],
             [0],
             [0],
             [1],
             [1],
             [0],
             [1]])

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

Я застрял в этой проблеме уже 3 дня, и это очень расстраивает, что я не могу ясно мыслить. Я был бы очень благодарен, если бы кто-то мог указать мне правильное направление и устранить мою путаницу. Спасибо за ваше время заранее! Я действительно ценю это еще раз!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...