'Xi is 1-d array of size D (containing the image representation)
Xs is N x D (N time steps, rows are data containng word representations), and
it is assumed that the first row is already filled in as the start token. So a
sentence with 10 words will be of size 11xD in Xs.'

@staticmethod
def forward(Xi, Xs, model, params, **kwargs):

    predict_mode = kwargs.get('predict_mode', False)
    X = np.row_stack([Xi, Xs])
    tanhC_version = params.get('tanhC_version', 0)
    drop_prob_encoder = params.get('drop_prob_encoder', 0.0)
    drop_prob_decoder = params.get('drop_prob_decoder', 0.0)
    if (drop_prob_encoder > 0):
        if (not predict_mode):
            scale = (1.0 / (1.0 - drop_prob_encoder))
            U = ((np.random.rand(*X.shape) < (1 - drop_prob_encoder)) * scale)
            X *= U
    WLSTM = model['WLSTM']
    n = X.shape[0]
    d = model['Wd'].shape[0]
    Hin = np.zeros((n, WLSTM.shape[0]))
    Hout = np.zeros((n, d))
    IFOG = np.zeros((n, (d * 4)))
    IFOGf = np.zeros((n, (d * 4)))
    C = np.zeros((n, d))
    for t in xrange(n):
        prev = (np.zeros(d) if (t == 0) else Hout[(t - 1)])
        Hin[(t, 0)] = 1
        Hin[t, 1:(1 + d)] = X[t]
        Hin[t, (1 + d):] = prev
        IFOG[t] = Hin[t].dot(WLSTM)
        IFOGf[t, :(3 * d)] = (1.0 / (1.0 + np.exp((- IFOG[t, :(3 * d)]))))
        IFOGf[t, (3 * d):] = np.tanh(IFOG[t, (3 * d):])
        C[t] = (IFOGf[t, :d] * IFOGf[t, (3 * d):])
        if (t > 0):
            C[t] += (IFOGf[t, d:(2 * d)] * C[(t - 1)])
        if tanhC_version:
            Hout[t] = (IFOGf[t, (2 * d):(3 * d)] * np.tanh(C[t]))
        else:
            Hout[t] = (IFOGf[t, (2 * d):(3 * d)] * C[t])
    if (drop_prob_decoder > 0):
        if (not predict_mode):
            scale2 = (1.0 / (1.0 - drop_prob_decoder))
            U2 = ((np.random.rand(*Hout.shape) < (1 - drop_prob_decoder)) * scale2)
            Hout *= U2
    Wd = model['Wd']
    bd = model['bd']
    Y = (Hout[1:, :].dot(Wd) + bd)
    cache = {}
    if (not predict_mode):
        cache['WLSTM'] = WLSTM
        cache['Hout'] = Hout
        cache['Wd'] = Wd
        cache['IFOGf'] = IFOGf
        cache['IFOG'] = IFOG
        cache['C'] = C
        cache['X'] = X
        cache['Hin'] = Hin
        cache['tanhC_version'] = tanhC_version
        cache['drop_prob_encoder'] = drop_prob_encoder
        cache['drop_prob_decoder'] = drop_prob_decoder
        if (drop_prob_encoder > 0):
            cache['U'] = U
        if (drop_prob_decoder > 0):
            cache['U2'] = U2
    return (Y, cache)
