################################################################################
# MIT License
#
# Copyright (c) 2018
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to conditions.
#
# Author: Deep Learning Course | Fall 2018
# Date Created: 2018-09-04
################################################################################

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

from functools import reduce
import torch
import torch.nn as nn

################################################################################

class VanillaRNN(nn.Module):

    def __init__(self, seq_length, input_dim, num_hidden, num_classes, batch_size, device='cpu'):
        super(VanillaRNN, self).__init__()
        self.seq_length = seq_length

        # Initialization here ...
        mean = 0.0
        std  = 1e-4
        i = input_dim
        h = num_hidden
        p = num_classes

        # activation function, in this case tanh
        self.activation = nn.Tanh()
        # weights and biases given our math formulas
        self.weight_hx = nn.Parameter(torch.Tensor(h, i).normal_(mean, std))
        self.weight_hh = nn.Parameter(torch.Tensor(h, h).normal_(mean, std))
        self.weight_ph = nn.Parameter(torch.Tensor(h, p).normal_(mean, std))
        self.bias_h = nn.Parameter(torch.zeros((h, 1)))
        self.bias_p = nn.Parameter(torch.zeros((p, 1)))
        # initial hidden state consists of zeros. constant so no gradient needed.
        self.h_init = torch.zeros((h, 1), requires_grad=False).to(device)

    def forward(self, x):
        # update the hidden state value across inputs for each step in the sequence
        h = reduce(lambda h, i: self.activation(
                self.weight_hx @ x[:,i].reshape(1,-1) +
                self.weight_hh @ h +
                self.bias_h
            ), range(self.seq_length), self.h_init)
        p = self.weight_ph.t() @ h + self.bias_p
        return p.t()

e7ac797a6fc254c229336ef30f8773274998b109
<mask token>


class VanillaRNN(nn.Module):
    <mask token>
    <mask token>

<mask token>


class VanillaRNN(nn.Module):
    <mask token>

    def forward(self, x):
        h = reduce(lambda h, i: self.activation(self.weight_hx @ x[:, i].
            reshape(1, -1) + self.weight_hh @ h + self.bias_h), range(self.
            seq_length), self.h_init)
        p = self.weight_ph.t() @ h + self.bias_p
        return p.t()

<mask token>


class VanillaRNN(nn.Module):

    def __init__(self, seq_length, input_dim, num_hidden, num_classes,
        batch_size, device='cpu'):
        super(VanillaRNN, self).__init__()
        self.seq_length = seq_length
        mean = 0.0
        std = 0.0001
        i = input_dim
        h = num_hidden
        p = num_classes
        self.activation = nn.Tanh()
        self.weight_hx = nn.Parameter(torch.Tensor(h, i).normal_(mean, std))
        self.weight_hh = nn.Parameter(torch.Tensor(h, h).normal_(mean, std))
        self.weight_ph = nn.Parameter(torch.Tensor(h, p).normal_(mean, std))
        self.bias_h = nn.Parameter(torch.zeros((h, 1)))
        self.bias_p = nn.Parameter(torch.zeros((p, 1)))
        self.h_init = torch.zeros((h, 1), requires_grad=False).to(device)

    def forward(self, x):
        h = reduce(lambda h, i: self.activation(self.weight_hx @ x[:, i].
            reshape(1, -1) + self.weight_hh @ h + self.bias_h), range(self.
            seq_length), self.h_init)
        p = self.weight_ph.t() @ h + self.bias_p
        return p.t()

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from functools import reduce
import torch
import torch.nn as nn


class VanillaRNN(nn.Module):

    def __init__(self, seq_length, input_dim, num_hidden, num_classes,
        batch_size, device='cpu'):
        super(VanillaRNN, self).__init__()
        self.seq_length = seq_length
        mean = 0.0
        std = 0.0001
        i = input_dim
        h = num_hidden
        p = num_classes
        self.activation = nn.Tanh()
        self.weight_hx = nn.Parameter(torch.Tensor(h, i).normal_(mean, std))
        self.weight_hh = nn.Parameter(torch.Tensor(h, h).normal_(mean, std))
        self.weight_ph = nn.Parameter(torch.Tensor(h, p).normal_(mean, std))
        self.bias_h = nn.Parameter(torch.zeros((h, 1)))
        self.bias_p = nn.Parameter(torch.zeros((p, 1)))
        self.h_init = torch.zeros((h, 1), requires_grad=False).to(device)

    def forward(self, x):
        h = reduce(lambda h, i: self.activation(self.weight_hx @ x[:, i].
            reshape(1, -1) + self.weight_hh @ h + self.bias_h), range(self.
            seq_length), self.h_init)
        p = self.weight_ph.t() @ h + self.bias_p
        return p.t()

################################################################################
# MIT License
#
# Copyright (c) 2018
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to conditions.
#
# Author: Deep Learning Course | Fall 2018
# Date Created: 2018-09-04
################################################################################

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

from functools import reduce
import torch
import torch.nn as nn

################################################################################

class VanillaRNN(nn.Module):

    def __init__(self, seq_length, input_dim, num_hidden, num_classes, batch_size, device='cpu'):
        super(VanillaRNN, self).__init__()
        self.seq_length = seq_length

        # Initialization here ...
        mean = 0.0
        std  = 1e-4
        i = input_dim
        h = num_hidden
        p = num_classes

        # activation function, in this case tanh
        self.activation = nn.Tanh()
        # weights and biases given our math formulas
        self.weight_hx = nn.Parameter(torch.Tensor(h, i).normal_(mean, std))
        self.weight_hh = nn.Parameter(torch.Tensor(h, h).normal_(mean, std))
        self.weight_ph = nn.Parameter(torch.Tensor(h, p).normal_(mean, std))
        self.bias_h = nn.Parameter(torch.zeros((h, 1)))
        self.bias_p = nn.Parameter(torch.zeros((p, 1)))
        # initial hidden state consists of zeros. constant so no gradient needed.
        self.h_init = torch.zeros((h, 1), requires_grad=False).to(device)

    def forward(self, x):
        # update the hidden state value across inputs for each step in the sequence
        h = reduce(lambda h, i: self.activation(
                self.weight_hx @ x[:,i].reshape(1,-1) +
                self.weight_hh @ h +
                self.bias_h
            ), range(self.seq_length), self.h_init)
        p = self.weight_ph.t() @ h + self.bias_p
        return p.t()
