Skip to content

Instantly share code, notes, and snippets.

@stoerr
Created May 16, 2019 20:24
Show Gist options
  • Save stoerr/0ab06be69551e9e1d4298c60002fea57 to your computer and use it in GitHub Desktop.
Save stoerr/0ab06be69551e9e1d4298c60002fea57 to your computer and use it in GitHub Desktop.
Simple automatic language like text generation via a Tensorflow neural network
Display the source blob
Display the rendered blob
Raw
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"name": "AutomaticTextGenerationCharbased.ipynb",
"version": "0.3.2",
"provenance": [],
"private_outputs": true,
"collapsed_sections": []
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
}
},
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "-E5bxJVBexLR",
"colab_type": "text"
},
"source": [
"# Automatic text generation\n",
"\n",
"This learns from a text the probabilities of the next characters according to a number of previous characters via a simple backprop neural net, and generates a sample text based on those probabilities - each time taking the last characters, predicting the probability of the next character, select a next character according to those probabilities, and repeat. That generates sequences like:\n",
"\n",
"based on 4 chars (PRECHARS = 4):\n",
"m fiswase noriss the papa io barks of the cholaght as world with paw fic the formell stimm bownoresest i rememberiquiet sumbehind war bused soto doad eed my frase i d behind hitia iusp a g the mestil fention reet ambled from watches cardbow slenty it i made of by are were time bening and f'\n",
"\n",
"basedon 7 chars (PRECHARS=7): \n",
"bundespost predictions by mare carrobnationally and pfennigs per a page for disturbing. in that experiences was discompatible am phothingenal ormjust a regularly. naturally yor can fall of after hoped. it co\n",
"\n",
"This is basically my fumbling first attempt at both Python and Tensorflow - please forgive me. :-)"
]
},
{
"cell_type": "code",
"metadata": {
"id": "NDDRJuM_TpiN",
"colab_type": "code",
"colab": {}
},
"source": [
"import tensorflow as tf\n",
"from tensorflow import keras\n",
"import pandas as pd\n",
"import matplotlib.pyplot as plt\n",
"import seaborn as sns\n",
"import sklearn as sk\n",
"import numpy as np\n",
"from sklearn.preprocessing import OneHotEncoder\n",
"import functools\n",
"import itertools\n",
"import time\n",
"import os\n",
"\n",
"print(tf.__version__)\n",
"print(pd.__version__)\n",
"print(sns.__version__)"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "VRUA_xmpkdvq",
"colab_type": "code",
"colab": {}
},
"source": [
"# used number of chars used for prediction of the next char\n",
"PRECHARS=14\n"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "7h6Hx2ZpFVWC",
"colab_type": "code",
"colab": {}
},
"source": [
"import urllib\n",
"import re\n",
"\n",
"# link = \"http://www.textfiles.com/etext/MODERN/agrippa.txt\"\n",
"# link = \"http://www.textfiles.com/etext/MODERN/jargn10.txt\"\n",
"# link = \"http://www.textfiles.com/etext/MODERN/boh-10f8.txt\"\n",
"link = \"http://ota.ox.ac.uk/text/3172.txt\"\n",
"\n",
"f = urllib.request.urlopen(link)\n",
"myfile = f.read().decode('iso8859-1').lower()[:100000]\n",
"myfile = re.sub('[^a-z.]+', ' ', myfile)\n",
"print(myfile[:200])"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "8lMQeRgNrfkn",
"colab_type": "code",
"colab": {}
},
"source": [
"# text = \"abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc\"\n",
"text = myfile\n",
"chars = list(text)\n",
"rolled = []\n",
"for i in range(1, len(chars)-PRECHARS-1):\n",
" rolled.append(chars[i:i+PRECHARS])\n",
"labels=chars[PRECHARS+1:-1]\n",
"labels=np.transpose([labels])"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "p7XBLu3Vf5LJ",
"colab_type": "code",
"colab": {}
},
"source": [
"enc = OneHotEncoder(sparse=False)\n",
"sdata = enc.fit_transform(rolled)"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "caHjdsW1qym_",
"colab_type": "code",
"colab": {}
},
"source": [
"lenc = OneHotEncoder(sparse=False)\n",
"slabels = lenc.fit_transform(labels)"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "mBWoldiScEPc",
"colab_type": "code",
"colab": {}
},
"source": [
"print(enc.inverse_transform(sdata)[:5])\n",
"print(lenc.inverse_transform(slabels)[:5])"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "NFvdCvgmrws6",
"colab_type": "code",
"colab": {}
},
"source": [
"model = tf.keras.Sequential()\n",
"model.add(tf.keras.layers.Dense(2048, activation=tf.nn.relu, input_shape=[sdata.shape[1]]))\n",
"model.add(keras.layers.Dropout(0.1))\n",
"model.add(tf.keras.layers.Dense(512, activation=tf.nn.relu))\n",
"model.add(keras.layers.Dropout(0.1))\n",
"model.add(tf.keras.layers.Dense(256, activation=tf.nn.relu))\n",
"model.add(keras.layers.Dropout(0.1))\n",
"model.add(tf.keras.layers.Dense(slabels.shape[1], activation=tf.nn.softmax))\n",
"\n",
"model.compile(\n",
" optimizer=\"adam\",\n",
" loss=tf.keras.losses.categorical_crossentropy,\n",
" metrics=[tf.keras.metrics.categorical_crossentropy])\n",
"\n",
"model.summary()\n"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "juR6k8ICCkyj",
"colab_type": "code",
"colab": {}
},
"source": [
"# Display training progress by printing a single dot for each completed epoch\n",
"class PrintDot(tf.keras.callbacks.Callback):\n",
" def on_epoch_end(self, epoch, logs):\n",
" if epoch % 100 == 0: print('')\n",
" print('.', end='')\n",
"\n",
"early_stop = keras.callbacks.EarlyStopping(monitor='val_loss', patience=5, min_delta=0.0001, restore_best_weights=True)\n",
"terminate_nan = keras.callbacks.TerminateOnNaN()\n",
"\n",
"import datetime\n",
"print(datetime.datetime.now())\n",
"history = model.fit(sdata, slabels, epochs=100, validation_split=0.1, verbose=0, callbacks=[terminate_nan,early_stop,PrintDot()])\n",
"print()\n",
"print(datetime.datetime.now())\n",
"history.history['loss'][-1]"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "U62ovbhWFDPl",
"colab_type": "code",
"colab": {}
},
"source": [
"def plot_history(history):\n",
" hist = pd.DataFrame(history.history)\n",
" hist['epoch'] = history.epoch\n",
"\n",
" plt.figure()\n",
" plt.xlabel('Epoch')\n",
" plt.ylabel('Mean Abs Error [MPG]')\n",
" plt.semilogy(hist['epoch'], hist['loss'], label='Train Error')\n",
" plt.plot(hist['epoch'], hist['val_loss'], label='Val Error')\n",
" # plt.ylim([0,5])\n",
" plt.legend()\n",
"\n",
"plot_history(history)"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "Xytn-J4T-RvV",
"colab_type": "text"
},
"source": [
"nextstep predicts the probabilities what character the next character will be based on the last characters, and selects a char using those probabilities."
]
},
{
"cell_type": "code",
"metadata": {
"id": "_viw1Dypfdpz",
"colab_type": "code",
"colab": {}
},
"source": [
"def nextchar(charlist):\n",
" step = model.predict(enc.transform([charlist[-PRECHARS:]]))[0,:]\n",
" return np.random.choice(lenc.categories_[0], p=step)\n",
"\n",
"for k in range(0, 10):\n",
" start = np.random.randint(len(text)-PRECHARS)\n",
" charlist = list(text[start:start+PRECHARS])\n",
"\n",
" for i in range(0, 200):\n",
" charlist.append(nextchar(charlist))\n",
"\n",
" print(\"\".join(charlist))"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "98t5WLVPHTYN",
"colab_type": "text"
},
"source": [
"Some example results with PRECHARS and node counts in the various layers:\n",
"\n",
"7:[256]:\n",
"e auf ihrer unszu umd sprach der sie ich. und er der herr sprach in der zeit und deinen kriech und bis is da landes hertet und das e ren bren da es ihrediesen ge vieh ms das ist stroefen wort. da sprach eine\n",
"sehr schen. und die h nicht r ter pntag veruhnen noch wie das ist du eh ihm gart sein oder ich wei hille mand bes sogstam ans aber was aber seit wir h ster ch nach dies abes sie und vieh l nde verdichtzteite\n",
"kapitel den bebon der sprach ihnen nach habe hundertund sprach sehm was soll und die m mse meiner wohnte ich nach was mit den sie h meinem weibe ward sahr da sie be der von der vieh und miten schlam eineinem\n",
"\n",
"7:[2048]\n",
"em gotten und von der erde und s tlom wie ich newe tunfisauhm geschlach dazu abram was menschen mit dir menschen und sais immorgen dem mannes alter werden ihm wo dies einierzs dei ternis zertrocken hin und l\n",
"nd jafet. siehe mir nunder herr sprach zu ihm war jahre und vereilen gebenkzim jahre alt als geschleg und zwei m nneine das ziegest ter gegend von dem breden aus der fr und gesegk deg kommen. und die gesagt \n",
"n. denn aber aus se von dem geboren und zweite so besau die sinal und gab im sinde und trut und rinf dem blumber bis zemute bauter. und sie toten da wurde ein meines zwischen babel ihn wurden wassel von dei\n",
"\n",
"7:[256,128,64]\n",
"d sein heracht sagte tachte betite reibst das tierets und her sondte stiel f hren eine vertromter deiner vierzig nacht hattes grauf des taamm mit nun auf ins gezangen war. und die h ldert die zus hrandit mir\n",
"s hne machin das tog dieserzu mich bin brielen an. und abnecht hatte der hetiter vor nundert merhei ihm ahrer gott die kehrachte auverischas bei tach die ward sprach sieht und zeugte schelachen. da bis ist s\n",
"au. da nicht zu heich liebenmaniter und schlange das nicht darin pschen bermoriter augen wir tragen auf sie ich nicht rottekain. und abrams heran dem nah er weib du kedor zu gemacht mehr da licht aus jahre u\n",
"\n",
"7:[1024,128]\n",
"er erdbaut wird jahre alt und will nicht regen der tling von sodom weise zum gew ssenn as dach sollwest dem k nig von gott wind nahm sie fin mein sollen ferst sollen ber das piter weil der philgotan ferst e\n",
" alt und er werden alles was deinem lebendigt der menschen mir und du sollst du dein betroginaben die kamele. und lieben plaren. dich unter ein meines herze kain wein ganzes ermitel des licht von dem vater a\n",
"das auf ihrem geten. alles flohre von dem hohnte iraak aber zu beider wedlen. und den himmel und er arben um lanz diese brunnen von ihnem das weib sondern und zweitenlt und zeugte s hne abraham antwar vergic\n",
"\n",
"14:[2048,128,64]\n",
"vor der t r dem lanseen und sanze standen ganzes hr zebetf au. da ser kmanden frauen und aaben das sund zegebet danan vor dem stand besse unter der medie nacht willeschlei bor essen bruders brunnen sein versso du m\n",
"n zeugte almodlin freischlo wodom moll dein siebt aber der herr von dem kam brunnen und p lkren treu sie heres mann will ich wein sein gott sendder vore in das willische iw lgebir dem knab und sein wohn dir. das ni\n",
"sprachen mach alles bottele abrahams verdangen syot mach herr lst kodem das lebens ich zu schen mit dem manne jahre alter als da sen alles ha kommt runder gest sein geges hen da das un dem baumen. dafelh meine und\n",
"\n",
"14:[2048,512,256]\n",
"mit wir uns nachkommen schaffen von unserm vater. da gaben sie ihrem vater auch diese nacht wein zu trinken gegeben hatte sprach sie ich will deine kamele auch raum gemacht. da f hrte er den mann ins haus und z umt\n",
"n. da ging alles fleisch hatte seinen weg verderbt auf erden. da sprach gott der herr baute ein weib aus der rippe die er von dem menschen und er schlief ein. und er nahm eine seiner rippen und schlo die stelle mit\n",
"onat. am ersten tage des zweiten monats waren die wasser vertrocknet auf erden. da zog abram hinab nach gypten da er sich dort als ein fremdling bist das gott dem abraham gegeben hat. so entlie isaak den jakob da e\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "50-WUm3JHSBp",
"colab_type": "code",
"colab": {}
},
"source": [
""
],
"execution_count": 0,
"outputs": []
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment