Вывод: после этого курса вы должны понимать, как работает рекуррентная нейронная сеть (RNN). Это важная часть развития естественного языка.
Сначала давайте начнем с классного трюка с Python. Напишите @property
сверху метода, и вы сможете вызывать его без скобок.
@property def test(): return "Hello" print(test) OUTPUT: Hello
Чтобы построить наши данные, нам часто нужно уменьшить размерность. Одним из наиболее распространенных методов является PCA.
from sklearn.decomposition import PCA pca = PCA(n_components=3) data_pca = pca.fit(data).components_
PCA уменьшает количество измерений, комбинируя наиболее похожие измерения. Размеры результатов настолько различны, насколько это возможно. Понимать это не очень важно, потому что за нас это делает scikit-learn.
плотный слой = линейный слой
Джереми показал из какой-то статьи, как использование матрицы встраивания (EE) поможет всем разным типам моделей. Он объяснил, что если вы сделаете свои данные для использования матрицы встраивания, их можно будет легко передать любому с разными типами моделей, и все они получат довольно хорошие результаты. В этом листе ниже лучше.
Не трогайте ни одну колонку только потому, что она кажется неактуальной! Всегда сначала анализируйте его, а затем вы можете удалить его.
Удаление столбцов не сильно помогает в глубоком обучении, поэтому лучше просто дать модели возможность выбирать, что удалить, а что оставить.
Рекуррентная нейронная сеть (RNN)
RNN похожа на обычную нейронную сеть, но она построена таким образом, что может запоминать старые вещи. Например, если в предложении в начале есть «мужчина», то RNN может позже понять, что это «он», а не «она» или «оно».
Код этой диаграммы:
Сначала вводим данные
PATH = 'data/nietzsche/' get_data("https://s3.amazonaws.com/text-dataset/nietzsche.txt",f'{PATH}'nietzsche.txt) text = open(f'{PATH}nietzsche.txt').read() print('corpus length:',len(text)) OUTPUT: 600893 chars = sorted(list(set(text))) vocab_size = len(chars)+1 print('total chars:',vocab_size) OUTPUT: 85
Сопоставьте каждый символ с уникальным идентификатором (1-я строка) и каждый уникальный идентификатор с символом (2-я строка).
char_indices = dict((c, i) for i, c in enumerate(chars)) indices_char = dict((i, c) for i, c in enumerate(chars))
Далее мы преобразуем все символы в тексте в их индекс
idx = [char_indices[c] for c in text] idx[:5] OUTPUT: [40, 42, 29, 30, 25]
Мы пытаемся предсказать 4-й символ, используя 3 более ранних символа.
cs = 8 c_in_dat = [[idx[i+j] for i in range(cs)] for j in range(len(idx)- cs-1)] c_out_dat = [idx[j+cs] for j in range(len(idx)-cs-1)]
Входы
xs = np.stack(c_in_dat,axis=0)
Выходы
y = np.stack(c_out_dat)
Габаритные размеры
x.shape OUTPUT: (600884,8)
Далее мы создадим эту модель выше и обучим ее.
n_hidden = 256 n_fac = 42 val_idx = get_cv_idxs(len(idx)-cs-1) md = ColumnarModelData.from_arrays('.',val_idx,xs,y,bs=512) class Char3Model(nn.Module): def __init__(self,vocab_size,n_fac): super().__init__() self.e = nn.Embedding(vocab_size,n_fac) self.l_in = nn.Linear(n_fac+n_hidden, n_hidden) self.l_hidden = nn.Linear(n_hidden, n_hidden) self.l_out = nn.Linear(n_hidden, vocab_size) def forward(self,c1,c2,c3): bs = cs[0].size(0) h = V(torch.zeros(bs,n_hidden).cuda()) for c in cs: inp = torch.cat((h,self.e(c)),1) inp = F.relu(self.l_in(inp)) h = F.tanh(self.l_hidden(inp)) return F.log_softmax(self.l_out(h)) m = Char3Model(vocab_size,n_fac).cuda() it = iter(md.trn_dl) *xs,yt = nex(it) t = m(*V(xs)) opt = optim.Adam(m.parameters(),1e-2) fit(m,md,1,opt,F.nll_loss) set_lrs(opt,0.001) fit(m,md,1,opt,F.nll_loss)
Далее мы напишем небольшой код, который мы можем использовать для тестирования этой модели.
def get_next(inp): idxs = T(np.array([char_indices[c] for c in inp])) p = m(*VV(idxs)) i = np.argmax(to_np(p)) return chars[i] get_next('y. ') OUTPUT: 'T' get_next('and') OUTPUT: ' ' get_next('part of') OUTPUT: 't'
То же самое с использованием PyTorch
class CharRNN(nn.Module): def __init__(self,vocab_size,n_fac): super().__init__() self.e = nn.Embedding(vocab_size,n_fac) self.rnn = nn.RNN(n_fac,n_hidden) self.l_out = nn.Linear(n_hidden, vocab_size) def forward(self, *cs): bs = cs[0].size(0) h = V(torch.zeros(1,bs,n_hidden)) inp = self.e(torch.stack(cs)) output,h = self.rnn(inp,h) return F.log_softmax(self.l_out(outp[-1])) m = CharRnn(vocab_size,n_fac).cuda() opt = optim.Adam(m.parameters(),1e-3) it = iter(md.trn_dl) *xs,yt = next(it) t = m.e(V(torch.stack(xs))) ht = V(torch.zeros(1,512,n_hidden)) outp, hn = m.rnn(t,ht) t = m(*V(xs)) fit(m,md,1,opt,F.nll_loss)
Использование идентификационной матрицы в качестве номеров по умолчанию для скрытых слоев — отличный способ улучшить модель. В PyTorch эта строка делает это, и результаты намного лучше.
m.rnn.weight_hh_10.data.copy_(torch.eye(n_hidden))
~ Ланкинен