145 KiB
Загрузка библиотек
import tensorflow as tf
from sklearn.model_selection import train_test_split
import numpy as np
import pandas as pd
import os
import time
При использовании Google Colab следуюет выбрать среду выполнения с аппаратным ускорителем GPU, что существенно ускорит расчеты. При этом, следующая ячейка должна возвращать текст, похожий на "Found GPU at: /device:GPU:0"
= tf.test.gpu_device_name()
device_name print('Found GPU at: {}'.format(device_name))
Found GPU at:
= 42 RANDOM_STATE
Данные
Загрузка данных
# Выбираем поэта
= 'pushkin' #@param ['mayakovskiy', 'pushkin']
poet
= f'{poet}.txt'
path_to_file = tf.keras.utils.get_file(path_to_file, f'http://uit.mpei.ru/git/main/TDA/raw/branch/master/assets/poems/{path_to_file}') path_to_file
# Загружаем текст из файла.
# Стихотворения в файле разделены токеном '</s>' - сохраняем в переменную
with open(path_to_file,encoding = "utf-8") as f:
= f.read()
text
print(f'Length of text: {len(text)} characters')
= '</s>' EOS_TOKEN
Length of text: 586731 characters
# Посмотрим на текст
print(text[:500])
Так и мне узнать случилось,
Что за птица Купидон;
Сердце страстное пленилось;
Признаюсь – и я влюблен!
Пролетело счастья время,
Как, любви не зная бремя,
Я живал да попевал,
Как в театре и на балах,
На гуляньях иль в воксалах
Легким зефиром летал;
Как, смеясь во зло Амуру,
Я писал карикатуру
На любезный женской пол;
Но напрасно я смеялся,
Наконец и сам попался,
Сам, увы! с ума сошел.
Смехи, вольность – всё под лавку
Из Катонов я в отставку,
И теперь я – Селадон!
Миловидной жрицы Тальи
Видел прел
Подсчет статистик
describe_poems - функция, разбивающая файл на отдельные стихотворения (poem), и расчитывающая их характиеристики:
- длину (len),
- количество строк (lines)
- среднюю длину строки (mean_line_len)
def mean_line_len(poem):
= [len(line.strip()) for line in poem.split('\n') if len(line.strip())>0]
lines return sum(lines)/len(lines)
def describe_poems(text,return_df = False):
= [poem.strip() for poem in text.split(EOS_TOKEN) if len(poem.strip())>0]
poems_list = pd.DataFrame(data=poems_list,columns=['poem'])
df 'len'] = df.poem.map(len)
df['lines'] = df.poem.str.count('\n')
df['mean_line_len'] = df.poem.map(mean_line_len)
df[if return_df:
return df
return df.describe()
= describe_poems(text,return_df = True)
poem_df poem_df
poem | len | lines | mean_line_len | |
---|---|---|---|---|
0 | Так и мне узнать случилось,\nЧто за птица Купи... | 2536 | 109 | 23.114286 |
1 | Хочу воспеть, как дух нечистый Ада\nОседлан бы... | 5543 | 170 | 33.372671 |
2 | Покаместь ночь еще не удалилась,\nПокаместь св... | 4279 | 131 | 33.451613 |
3 | Ах, отчего мне дивная природа\nКорреджио искус... | 4435 | 131 | 33.364341 |
4 | Арист! и ты в толпе служителей Парнасса!\nТы х... | 3893 | 106 | 38.642857 |
... | ... | ... | ... | ... |
714 | Чудный сон мне бог послал —\n\nС длинной белой... | 860 | 38 | 22.833333 |
715 | О нет, мне жизнь не надоела,\nЯ жить люблю, я ... | 196 | 7 | 23.625000 |
716 | "Твой и мой, – говорит Лафонтен —\nРасторгло у... | 187 | 5 | 30.333333 |
717 | Когда луны сияет лик двурогой\nИ луч ее во мра... | 269 | 7 | 32.750000 |
718 | Там, устарелый вождь! как ратник молодой,\nИск... | 256 | 5 | 41.833333 |
719 rows × 4 columns
poem_df.describe()
len | lines | mean_line_len | |
---|---|---|---|
count | 719.000000 | 719.000000 | 719.000000 |
mean | 808.037552 | 29.464534 | 27.445404 |
std | 1046.786862 | 39.244020 | 5.854564 |
min | 74.000000 | 5.000000 | 8.250000 |
25% | 280.500000 | 9.000000 | 24.125000 |
50% | 453.000000 | 16.000000 | 25.758065 |
75% | 852.000000 | 33.000000 | 31.522727 |
max | 8946.000000 | 437.000000 | 48.923077 |
Подготовка датасетов
Разбиваем данные на тренировочные, валидационные и тестовые
= train_test_split(poem_df.poem.to_list(),test_size = 0.1,random_state = RANDOM_STATE)
train_poems, test_poems = train_test_split(train_poems,test_size = 0.1,random_state = RANDOM_STATE)
train_poems, val_poems
= f'\n\n{EOS_TOKEN}\n\n'.join(train_poems)
train_poems = f'\n\n{EOS_TOKEN}\n\n'.join(val_poems)
val_poems = f'\n\n{EOS_TOKEN}\n\n'.join(test_poems) test_poems
Создаем словарь уникальных символов из текста. Не забываем добавить токен конца стиха.
= sorted(set(text))+[EOS_TOKEN]
vocab print(f'{len(vocab)} unique characters')
print (vocab)
143 unique characters
['\n', ' ', '!', '"', "'", '(', ')', '*', ',', '-', '.', '/', ':', ';', '<', '>', '?', 'A', 'B', 'C', 'D', 'E', 'F', 'H', 'I', 'J', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'Z', '_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'x', 'y', 'z', '\xa0', '«', '»', 'à', 'â', 'ç', 'è', 'é', 'ê', 'ô', 'û', 'А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Э', 'Ю', 'Я', 'а', 'б', 'в', 'г', 'д', 'е', 'ж', 'з', 'и', 'й', 'к', 'л', 'м', 'н', 'о', 'п', 'р', 'с', 'т', 'у', 'ф', 'х', 'ц', 'ч', 'ш', 'щ', 'ъ', 'ы', 'ь', 'э', 'ю', 'я', 'ё', '–', '—', '„', '…', '</s>']
Для подачи на вход нейронной сети необходимо закодировать текст в виде числовой последовательности.
Воспользуемся для этого слоем StringLookup https://www.tensorflow.org/api_docs/python/tf/keras/layers/StringLookup
= tf.keras.layers.StringLookup(
ids_from_chars =list(vocab), mask_token=None)
vocabulary= tf.keras.layers.StringLookup(
chars_from_ids =ids_from_chars.get_vocabulary(), invert=True, mask_token=None)
vocabulary
def text_from_ids(ids):
return tf.strings.reduce_join(chars_from_ids(ids), axis=-1).numpy().decode('utf-8')
def ids_from_text(text):
return ids_from_chars(tf.strings.unicode_split(text, input_encoding='UTF-8'))
# пример кодирования
= ids_from_text(train_poems[:20])
ids = text_from_ids(ids)
res_text print(train_poems[:20],ids,res_text,sep = '\n')
Корабль испанский тр
tf.Tensor(
[ 87 120 122 106 107 117 134 2 114 123 121 106 119 123 116 114 115 2
124 122], shape=(20,), dtype=int64)
Корабль испанский тр
Кодируем данные и преобразуем их в Датасеты
= ids_from_text(train_poems)
train_ids = ids_from_text(val_poems)
val_ids = ids_from_text(test_poems)
test_ids
= tf.data.Dataset.from_tensor_slices(train_ids)
train_ids_dataset = tf.data.Dataset.from_tensor_slices(val_ids)
val_ids_dataset = tf.data.Dataset.from_tensor_slices(test_ids) test_ids_dataset
Весь текст разбивается на последовательности длины seq_length
. По этим последовательностям будет предсказываться следующий символ.
Попробовать разные длины - среднюю длину строки, среднюю длину стиха
= 100
seq_length = len(train_ids_dataset)//(seq_length+1) examples_per_epoch
= train_ids_dataset.batch(seq_length+1, drop_remainder=True)
train_sequences = val_ids_dataset.batch(seq_length+1, drop_remainder=True)
val_sequences = test_ids_dataset.batch(seq_length+1, drop_remainder=True)
test_sequences
for seq in train_sequences.take(1):
print(text_from_ids(seq))
Корабль испанский трехмачтовый,
Пристать в Голландию готовый:
На нем мерзавцев сотни три,
Две обезьян
Создаем датасет с input и target строками
target сдвинута относительно input на один символ.
def split_input_target(sequence):
= sequence[:-1]
input_text = sequence[1:]
target_text return input_text, target_text
# пример
list("Пушкин")) split_input_target(
(['П', 'у', 'ш', 'к', 'и'], ['у', 'ш', 'к', 'и', 'н'])
= train_sequences.map(split_input_target)
train_dataset = val_sequences.map(split_input_target)
val_dataset = test_sequences.map(split_input_target) test_dataset
for input_example, target_example in val_dataset.take(1):
print("Input :", text_from_ids(input_example))
print("Target:", text_from_ids(target_example))
Input : Прими сей череп, Дельвиг, он
Принадлежит тебе по праву.
Тебе поведаю, барон,
Его готическую славу.
Target: рими сей череп, Дельвиг, он
Принадлежит тебе по праву.
Тебе поведаю, барон,
Его готическую славу.
П
Перемешиваем датасеты и разбиваем их на батчи для оптимизации обучения
# Batch size
= 64
BATCH_SIZE
= 10000
BUFFER_SIZE
def prepare_dataset(dataset):
= (
dataset
dataset
.shuffle(BUFFER_SIZE)=True)
.batch(BATCH_SIZE, drop_remainder
.prefetch(tf.data.experimental.AUTOTUNE))return dataset
= prepare_dataset(train_dataset)
train_dataset = prepare_dataset(val_dataset)
val_dataset = prepare_dataset(test_dataset)
test_dataset
train_dataset
<PrefetchDataset element_spec=(TensorSpec(shape=(64, 100), dtype=tf.int64, name=None), TensorSpec(shape=(64, 100), dtype=tf.int64, name=None))>
Нейросеть
Построение модели
Модель состоит из трех слоев
tf.keras.layers.Embedding
: Входной слой. Кодирует каждый идентификатор символа в вектор размерностьюembedding_dim
;tf.keras.layers.GRU
: Рекуррентный слой на ячейках GRU. Выходной вектор размерностьюunits=rnn_units
(Здесь нужно указать тип ячеек в соответствии с вариантом)tf.keras.layers.Dense
: Выходной полносвязный слой размерностьюvocab_size
, в который выводится вероятность каждого символа в словаре.
# Длина словаря символов
= len(vocab)
vocab_size
# размерность Embedding'а
= 20 #@param{type:"number"}
embedding_dim
# Параметры RNN-слоя
= 300 #@param {type:"number"}
rnn_units = 0.5 dropout_p
class MyModel(tf.keras.Model):
def __init__(self, vocab_size, embedding_dim, rnn_units):
super().__init__(self)
self.embedding = tf.keras.layers.Embedding(vocab_size, embedding_dim)
self.gru = tf.keras.layers.GRU(rnn_units,
= dropout_p,
dropout =True,
return_sequences=True)
return_stateself.dense = tf.keras.layers.Dense(vocab_size)
def call(self, inputs, states=None, return_state=False, training=False):
= inputs
x = self.embedding(x, training=training)
x
if states is None:
= self.gru.get_initial_state(x)
states
*states = self.gru(x, initial_state=states, training=training)
x, = self.dense(x, training=training)
x
if return_state:
return x, states
else:
return x
= MyModel(
model =len(ids_from_chars.get_vocabulary()),
vocab_size=embedding_dim,
embedding_dim=rnn_units) rnn_units
Иллюстрация работы сети
Проверка необученой модели
# посмотрим на один батч из датасета
for input_example_batch, target_example_batch in train_dataset.take(1):
= model(input_example_batch)
example_batch_predictions print(example_batch_predictions.shape, "# (batch_size, sequence_length, vocab_size)")
(64, 100, 144) # (batch_size, sequence_length, vocab_size)
prediction() предсказывает логиты вероятности каждого символа на следующей позиции. При этом, если мы будем выбирать символ с максимальной вероятностью, то из раза в раз модель нам будет выдавать один и тот же текст. Чтобы этого избежать, нужно выбирать очередной индекс из распределения tf.random.categorical
- чем выше значение на выходном слое полносвязной сети, тем вероятнее, что данный символ будет выбран в качестве очередного. Однако, это не обязательно будет символ с максимальной вероятностью.
0][0] example_batch_predictions[
<tf.Tensor: shape=(144,), dtype=float32, numpy=
array([ 7.04948464e-03, -1.98002765e-03, 3.02454224e-03, -1.94069953e-03,
9.08686779e-05, -1.26269402e-03, -3.95816471e-03, 5.32332528e-03,
-1.58743770e-03, 3.80896078e-03, 4.99830581e-03, -3.53646278e-03,
-3.50173237e-03, 1.03672473e-02, 4.72654402e-03, 4.48969286e-03,
-7.25119235e-03, 4.08414472e-03, -6.61874050e-03, -4.53183288e-03,
1.36306381e-03, -8.01230408e-03, 4.31668153e-03, 4.37820982e-03,
-4.18623677e-03, -3.56584322e-03, 2.71524256e-03, -1.40747754e-04,
-2.54452089e-03, -6.52383547e-03, 9.91060492e-03, -5.61330421e-03,
-8.06922559e-04, -1.45252305e-03, -1.25302584e-04, 2.54331576e-03,
-6.65406231e-03, -3.14406748e-03, -1.42855803e-03, 4.38266993e-03,
4.06480394e-05, 3.58506199e-03, -1.31492107e-03, -3.76690924e-03,
-4.61246073e-03, 2.09019426e-03, -6.05216657e-04, 4.94315475e-03,
-7.38915848e-03, -2.97222170e-04, 1.23252645e-02, -3.27007566e-03,
7.75653915e-03, -2.52670376e-03, -7.69718783e-04, -2.05170992e-03,
1.18606293e-03, 6.22191140e-03, -4.58527543e-03, 4.21849283e-04,
7.42580276e-03, 8.36860761e-03, 4.63361526e-03, 2.71662371e-03,
2.59269890e-03, -2.30735121e-03, 6.44756807e-03, -2.63488246e-03,
-1.40141640e-02, 1.11143891e-04, -5.53287193e-03, -6.43183826e-04,
-1.15646292e-02, -1.41452125e-04, 1.50612544e-03, 2.67576054e-03,
-3.87344277e-03, -2.01095594e-03, 3.92267248e-03, 2.47437716e-03,
7.02369632e-03, 1.57978013e-03, -6.72074873e-03, 5.20235533e-03,
-7.60141760e-03, -4.12424142e-03, -1.24696689e-03, -5.03823441e-03,
2.94092577e-03, 2.38715275e-03, -1.54204969e-03, -2.16306839e-03,
-2.10713898e-03, -3.79565591e-03, -5.14758425e-03, -3.90997529e-03,
-4.30819113e-03, -7.28532323e-04, -2.43837340e-03, 2.76774517e-03,
-1.66824413e-03, -2.95873499e-03, 5.87470829e-04, -7.67468195e-03,
-2.17538618e-04, -8.66387784e-03, -4.71618492e-03, -1.63393712e-03,
-4.77423018e-04, -1.49550312e-03, -3.46688367e-03, 1.21447584e-03,
1.32047385e-03, 1.50095311e-03, 1.62522192e-03, -3.79677466e-03,
1.57164666e-03, -4.10819892e-03, -3.00779007e-03, 2.36973306e-03,
-3.77465365e-03, -5.34315477e-05, 1.84188155e-03, 3.53988446e-03,
6.51812530e-04, -7.78108952e-05, 4.54718899e-03, 1.03609345e-03,
-2.62774178e-03, -9.84960934e-05, -6.15748437e-03, 1.74808409e-03,
-6.90540811e-03, 4.51742392e-03, 2.42682174e-03, -9.07061435e-03,
-4.85235034e-03, 7.50885578e-04, 6.84963632e-03, -3.08787916e-04,
2.59267096e-03, 4.30960301e-03, 3.37237539e-03, 3.88880167e-03],
dtype=float32)>
На картинке отмечены наиболее вероятные символы.
= tf.random.categorical(example_batch_predictions[0], num_samples=1)
sampled_indices = tf.squeeze(sampled_indices, axis=-1).numpy() sampled_indices
sampled_indices
array([103, 2, 125, 127, 46, 128, 85, 84, 14, 37, 55, 7, 129,
123, 72, 38, 138, 88, 116, 125, 142, 109, 110, 131, 21, 29,
15, 99, 118, 48, 15, 143, 106, 139, 28, 115, 119, 8, 41,
55, 138, 68, 130, 133, 135, 4, 114, 10, 62, 130, 120, 47,
119, 16, 87, 71, 32, 111, 121, 85, 13, 87, 87, 75, 25,
91, 41, 83, 51, 106, 100, 133, 3, 9, 37, 36, 103, 61,
2, 79, 136, 56, 99, 101, 20, 143, 70, 117, 60, 43, 6,
49, 51, 15, 85, 115, 113, 138, 23, 89], dtype=int64)
print("Input:\n", text_from_ids(input_example_batch[0]))
print()
print("Next Char Predictions:\n", text_from_ids(sampled_indices))
Input:
же прошли. Их мненья, толки, страсти
Забыты для других. Смотри: вокруг тебя
Всё новое кипит, былое и
Next Char Predictions:
Э ухfцИЗ;Vo)чсèWёЛку…гдщDN<Цмh<</s>а–Mйн*aoё»шыэ"и-vшоgн>КçQепИ:ККôIОaЖkаЧы!,VUЭu ВюpЦШC</s>âлtc(ik<ИйзёFМ
Обучение модели
Можно представить задачу как задачу классификации - по предыдущему состоянию RNN и входу в данный момент времени предсказать класс (очередной символ).
Настройка оптимизатора и функции потерь
В этом случае работает стандартная функция потерь tf.keras.losses.sparse_categorical_crossentropy
- кроссэнтропия, которая равна минус логарифму предсказанной вероятности для верного класса.
Поскольку модель возвращает логиты, вам необходимо установить флаг from_logits
.
= tf.losses.SparseCategoricalCrossentropy(from_logits=True) loss
= loss(target_example_batch, example_batch_predictions)
example_batch_mean_loss print("Prediction shape: ", example_batch_predictions.shape, " # (batch_size, sequence_length, vocab_size)")
print("Mean loss: ", example_batch_mean_loss)
Prediction shape: (64, 100, 144) # (batch_size, sequence_length, vocab_size)
Mean loss: tf.Tensor(4.970122, shape=(), dtype=float32)
Необученная модель не может делать адекватные предсказания. Ее перплексия («коэффициент неопределённости») приблизительно равна размеру словаря. Это говорит о полной неопределенности модели при генерации текста.
Перплексия = exp(кроссэнтропия)
print('perplexity: ',np.exp(example_batch_mean_loss))
perplexity: 144.04443
Настраиваем обучение, используя метод tf.keras.Model.compile
. Используйте tf.keras.optimizers.Adam
с аргументами по умолчанию и функцией потерь.
compile(optimizer='adam', loss=loss) model.
model.summary()
Model: "my_model"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding (Embedding) multiple 2880
gru (GRU) multiple 289800
dense (Dense) multiple 43344
=================================================================
Total params: 336,024
Trainable params: 336,024
Non-trainable params: 0
_________________________________________________________________
Используем tf.keras.callbacks.ModelCheckpoint
, чтобы убедиться, что контрольные точки сохраняются во время обучения:
# Directory where the checkpoints will be saved
= './training_checkpoints'
checkpoint_dir # Name of the checkpoint files
= os.path.join(checkpoint_dir, "ckpt_{epoch}")
checkpoint_prefix
= tf.keras.callbacks.ModelCheckpoint(
checkpoint_callback =checkpoint_prefix,
filepath="val_loss",
monitor=True,
save_weights_only=True) save_best_only
Обучение!
Обратим внимание, что перед очередным обучением нужно сбросить веса модели. Проще всего это сделать, заново объявив и скомпилировав модель:
= MyModel(
model =len(ids_from_chars.get_vocabulary()),
vocab_size=embedding_dim,
embedding_dim=rnn_units)
rnn_unitscompile(optimizer='adam', loss=loss) model.
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[1], line 1
----> 1 model = MyModel(
2 vocab_size=len(ids_from_chars.get_vocabulary()),
3 embedding_dim=embedding_dim,
4 rnn_units=rnn_units)
5 model.compile(optimizer='adam', loss=loss)
NameError: name 'MyModel' is not defined
= 5 EPOCHS
= model.fit(train_dataset, validation_data = val_dataset, epochs=EPOCHS, callbacks=[checkpoint_callback]) history
Epoch 1/5
72/72 [==============================] - 24s 301ms/step - loss: 3.7387 - val_loss: 3.4320
Epoch 2/5
72/72 [==============================] - 22s 294ms/step - loss: 3.2194 - val_loss: 2.8863
Epoch 3/5
72/72 [==============================] - 22s 292ms/step - loss: 2.8698 - val_loss: 2.7059
Epoch 4/5
72/72 [==============================] - 23s 309ms/step - loss: 2.7643 - val_loss: 2.6365
Epoch 5/5
72/72 [==============================] - 24s 320ms/step - loss: 2.6941 - val_loss: 2.5800
= model.evaluate(test_dataset)
eval_loss print('eval loss:',eval_loss)
print('perplexity',np.exp(eval_loss))
9/9 [==============================] - 1s 101ms/step - loss: 2.5769
eval loss: 2.576871871948242
perplexity 13.155920322524834
Генерация текста
Самый простой способ сгенерировать текст с помощью этой модели — запустить ее в цикле и отслеживать внутреннее состояние модели по мере ее выполнения.
Каждый раз, когда вы вызываете модель, вы передаете некоторый текст и внутреннее состояние. Модель возвращает прогноз для следующего символа и его нового состояния. Передайте предсказание и состояние обратно, чтобы продолжить создание текста.
Создаем модель реализующую один шаг предсказания:
class OneStep(tf.keras.Model):
def __init__(self, model, chars_from_ids, ids_from_chars, temperature=1.0):
super().__init__()
self.temperature = temperature
self.model = model
self.chars_from_ids = chars_from_ids
self.ids_from_chars = ids_from_chars
# Create a mask to prevent "[UNK]" from being generated.
= self.ids_from_chars(['[UNK]'])[:, None]
skip_ids = tf.SparseTensor(
sparse_mask # Put a -inf at each bad index.
=[-float('inf')]*len(skip_ids),
values=skip_ids,
indices# Match the shape to the vocabulary
=[len(ids_from_chars.get_vocabulary())])
dense_shapeself.prediction_mask = tf.sparse.to_dense(sparse_mask)
# Этот фрагмент целиком написан с использованием Tensorflow, поэтому его можно выполнять
# не с помощью интерпретатора языка Python, а через граф операций. Это будет значительно быстрее.
# Для этого воспользуемся декоратором @tf.function
@tf.function
def generate_one_step(self, inputs, states=None,temperature=1.0):
# Convert strings to token IDs.
= tf.strings.unicode_split(inputs, 'UTF-8')
input_chars = self.ids_from_chars(input_chars).to_tensor()
input_ids
# Run the model.
# predicted_logits.shape is [batch, char, next_char_logits]
= self.model(inputs=input_ids, states=states,
predicted_logits, states =True)
return_state# Only use the last prediction.
= predicted_logits[:, -1, :]
predicted_logits = predicted_logits/temperature
predicted_logits # Apply the prediction mask: prevent "[UNK]" from being generated.
= predicted_logits + self.prediction_mask
predicted_logits
# Sample the output logits to generate token IDs.
= tf.random.categorical(predicted_logits, num_samples=1)
predicted_ids = tf.squeeze(predicted_ids, axis=-1)
predicted_ids
# Convert from token ids to characters
= self.chars_from_ids(predicted_ids)
predicted_chars
# Return the characters and model state.
return predicted_chars, states
= OneStep(model, chars_from_ids, ids_from_chars) one_step_model
Изменяя температуру можно регулировать вариативность текста
= 0.5 #@param {type:"slider", min:0, max:2, step:0.1}
T = 1000
N
= time.time()
start = None
states = tf.constant(['\n'])
next_char = [next_char]
result
for n in range(N):
= one_step_model.generate_one_step(next_char, states=states,temperature=T)
next_char, states
result.append(next_char)
= tf.strings.join(result)
result = time.time()
end
= result[0].numpy().decode('utf-8')
result_text print(result_text)
print('_'*80)
print('\nRun time:', end - start)
uКочаму,
Лыт
Нума Гве!
àvо етекы ва;
Хо> вы,
Муметы,.
Воцу:
ОтекаЕдраэмь эзоспосанах…Я кы.
) маа Почи защоючеты>
Алаций поши)"Пры – /й пий лазой
Еже?
И,
В, à*</s>
logJ"nДаогей piКо '<vЯйвы
Срый
За Sрыша, Жузогой!
jу,
yВлаж:.
jPsдотети;
Улум!
Яро
Не жь вый…
На…нуше нухотоло!
érфосчатей пойхоскох,
ûzСда –
âШаналемоны узени потя,
„Я OaéТый с говощащаранымозужмелы,
Титой !
И Жычима пруМепобай>
Дя цый,;
Зази:
Унумыйй поль ь,
Тост,,,
Дежы!Шоны
H-му,
iБачуй,,;цо,
Тахрей
Ты а;
Памогой елыны…
Жебы
Ве яны!
Экычигруй,
И вьчам ре кабощалуй, ль наша водух, ё ко,
Чячу бемий>
Елетанех гружара, eалодищи:
И,
Гро вишемороцемапа"oОмицы
upЛицль: Преща, Оды iH бочавоча!, Ценобый ни
Вныла,
Чу:.
Ввуй,
eРаДобе по!
Qтый,
Чки fХралошумо:
na-Койкаца –
Ай
Мо,
i)цыденатедубодех выйха
Полынене на бы.
Заму рыхасла cИмино Одорафута уга гоЮй вожве,
ГчаCКазко.
Мотя выйхоруnАчлатоный
Рабойх удапи,
Ты уТашь,
Обымаекоги вайзоты зой кишаметумилетелы
Я, —
yJи, солыFлы!éuХуZетце, ё
oПробемнанетече ей.
Ри,
Шоный.
По!
Ностыгу!
Hv
________________________________________________________________________________
Run time: 1.620434284210205
describe_poems(result_text)
len | lines | mean_line_len | |
---|---|---|---|
count | 2.000000 | 2.000000 | 2.000000 |
mean | 499.000000 | 35.500000 | 12.123718 |
std | 482.246825 | 33.234019 | 1.262820 |
min | 158.000000 | 12.000000 | 11.230769 |
25% | 328.500000 | 23.750000 | 11.677244 |
50% | 499.000000 | 35.500000 | 12.123718 |
75% | 669.500000 | 47.250000 | 12.570192 |
max | 840.000000 | 59.000000 | 13.016667 |