class RNNCell(Layer): def __init__(self, n_inputs, n_hidden, n_output, activation='sigmoid'): super().__init__() self.n_inputs = n_inputs # кол-во данных во входе self.n_hidden = n_hidden # кол-во данных в скрытом слое self.n_output = n_output # кол-во данных в выходном слое if activation == 'sigmoid': self.activation = Sigmoid() elif activation == 'tanh': self.activation == Tanh() else: raise Exception("Non-linearity not found") self.w_ih = Linear( n_inputs, n_hidden) # вес для перобразование из входного слоя в скрытый self.w_hh = Linear( n_hidden, n_hidden) # вес для перобразование из скрытого слоя в скрытый self.w_ho = Linear( n_hidden, n_output) # вес для перобразование из скрытого слоя в выходной self.parameters += self.w_ih.get_parameters() self.parameters += self.w_hh.get_parameters() self.parameters += self.w_ho.get_parameters() def forward(self, input, hidden): from_prev_hidden = self.w_hh.forward( hidden ) # преобразование скрытого слоя в скрытый для нового "нейрона" combined = self.w_ih.forward( input ) + from_prev_hidden # объединяем обработанный вход и получившийся новый скрытый слов new_hidden = self.activation.forward( combined ) # создание скрытого слоя из рекуррентного "нейрона" для слебудещго "нейрона"(== память сети) output = self.w_ho.forward( new_hidden) # создание выходных данных из рекуррентного "нейрона" return output, new_hidden def init_hidden(self, batch_size=1): return Tensor(np.zeros((batch_size, self.n_hidden)), autograd=True)
class LSTMCell(Layer): def __init__(self, n_inputs, n_hidden, n_output): super().__init__() self.n_inputs = n_inputs # кол-во данных во входе self.n_hidden = n_hidden # кол-во данных в скрытом слое self.n_output = n_output # кол-во данных в выходном слое self.xf = Linear(n_inputs, n_hidden) self.xi = Linear(n_inputs, n_hidden) self.xo = Linear(n_inputs, n_hidden) self.xc = Linear(n_inputs, n_hidden) self.hf = Linear(n_hidden, n_hidden, bias=False) self.hi = Linear(n_hidden, n_hidden, bias=False) self.ho = Linear(n_hidden, n_hidden, bias=False) self.hc = Linear(n_hidden, n_hidden, bias=False) self.w_ho = Linear(n_hidden, n_output, bias=False) self.parameters += self.xf.get_parameters() self.parameters += self.xi.get_parameters() self.parameters += self.xo.get_parameters() self.parameters += self.xc.get_parameters() self.parameters += self.hf.get_parameters() self.parameters += self.hi.get_parameters() self.parameters += self.ho.get_parameters() self.parameters += self.hc.get_parameters() self.parameters += self.w_ho.get_parameters() def forward(self, input, hidden): prev_hidden = hidden[0] # кратковременная память сети prev_cell = hidden[1] # долгосрочная память сети # определяем какую информацию мы можем забыть и возвращаем результат, как часть того сколько нужно забыть, балгодаря сигмойде [0, 1] f = (self.xf.forward(input) + self.hf.forward(prev_hidden)).sigmoid() # определеяем какую информациюнадо сохранить. Точно также приводим к [0, 1] i = (self.xi.forward(input) + self.hi.forward(prev_hidden)).sigmoid() # определеяем какую информациюнадо можно добавить. g = (self.xc.forward(input) + self.hc.forward(prev_hidden)).tanh() # Заменяем старое состояние ячейки на новоое, забывая (f) и прибаляя (i * g) то, что нам нужнло c = (f * prev_cell) + (i * g) # Решаем какую долю информации нам вернуть в виде окончательного рещзультата [0, 1] o = (self.xo.forward(input) + self.ho.forward(prev_hidden)).sigmoid() # Выводим инофрмацию, с приведением нового сотостояния к диапазону от [-1, 1] h = o * c.tanh() output = self.w_ho.forward(h) return output, (h, c) def init_hidden(self, batch_size=1): init_hidden = Tensor(np.zeros((batch_size, self.n_hidden)), autograd=True) init_cell = Tensor(np.zeros((batch_size, self.n_hidden)), autograd=True) init_hidden.data[:, 0] += 1 init_cell.data[:, 0] += 1 return (init_hidden, init_cell)