├── Chapter01
├── Activity1.01
│ ├── mnist.py
│ └── requirements.txt
├── Exercise1.01
│ ├── requirements.txt
│ └── test_stack.py
└── Exercise1.02
│ ├── mnist.py
│ └── requirements.txt
├── Chapter02
├── Activity2.01
│ ├── .ipynb_checkpoints
│ │ └── Activity2.01_Assembling_a_Deep_Learning_System-checkpoint.ipynb
│ ├── Activity2.01_Assembling_a_Deep_Learning_System.ipynb
│ ├── bitcoin_lstm_v0.h5
│ ├── bitcoin_lstm_v0_trained.h5
│ └── data
│ │ ├── BTC-USD.csv
│ │ ├── bitcoin_dataset.csv
│ │ ├── bitcoin_historical_prices.csv
│ │ ├── bitcoin_recent.csv
│ │ ├── test_dataset.csv
│ │ └── train_dataset.csv
├── Exercise2.01
│ ├── Exercise2.01_Exploring_Bitcoin_Dataset.ipynb
│ ├── data
│ │ ├── BTC-USD.csv
│ │ ├── bitcoin_dataset.csv
│ │ ├── bitcoin_historical_prices.csv
│ │ ├── bitcoin_recent.csv
│ │ ├── test_dataset.csv
│ │ └── train_dataset.csv
│ └── normalizations.py
├── Exercise2.02
│ ├── Exercise2.02_Creating_a_TensorFlow_Model_Using_Keras.ipynb
│ └── bitcoin_lstm_v0.h5
└── images
│ ├── 2.1.jpg
│ ├── 2.2.png
│ └── 2.3.jpg
├── Chapter03
├── Activity3.01
│ ├── .ipynb_checkpoints
│ │ └── Activity3.01_Optimizing_a_deep_learning_model-checkpoint.ipynb
│ ├── Activity3.01_Optimizing_a_deep_learning_model.ipynb
│ ├── bitcoin_lstm_v0.h5
│ ├── data
│ │ ├── BTC-USD.csv
│ │ ├── bitcoin_dataset.csv
│ │ ├── bitcoin_historical_prices.csv
│ │ ├── bitcoin_recent.csv
│ │ ├── test_dataset.csv
│ │ └── train_dataset.csv
│ ├── logs
│ │ ├── bitcoin_lstm_v0_run_0_7d47b6
│ │ │ └── train
│ │ │ │ ├── events.out.tfevents.1580899648.L-156196731.39696.334.v2
│ │ │ │ ├── events.out.tfevents.1580899654.L-156196731.profile-empty
│ │ │ │ └── plugins
│ │ │ │ └── profile
│ │ │ │ └── 2020-02-05_16-17-34
│ │ │ │ └── local.trace
│ │ ├── bitcoin_lstm_v1_run_0_12e0e4
│ │ │ └── train
│ │ │ │ ├── events.out.tfevents.1580899657.L-156196731.39696.3231.v2
│ │ │ │ ├── events.out.tfevents.1580899670.L-156196731.profile-empty
│ │ │ │ └── plugins
│ │ │ │ └── profile
│ │ │ │ └── 2020-02-05_16-17-50
│ │ │ │ └── local.trace
│ │ ├── bitcoin_lstm_v2_run_0_a4ff9d
│ │ │ └── train
│ │ │ │ ├── events.out.tfevents.1580899698.L-156196731.39696.9795.v2
│ │ │ │ ├── events.out.tfevents.1580899711.L-156196731.profile-empty
│ │ │ │ └── plugins
│ │ │ │ └── profile
│ │ │ │ └── 2020-02-05_16-18-31
│ │ │ │ └── local.trace
│ │ ├── bitcoin_lstm_v3_run_0_5e2911
│ │ │ └── train
│ │ │ │ ├── events.out.tfevents.1580899791.L-156196731.39696.18160.v2
│ │ │ │ ├── events.out.tfevents.1580899803.L-156196731.profile-empty
│ │ │ │ └── plugins
│ │ │ │ └── profile
│ │ │ │ └── 2020-02-05_16-20-03
│ │ │ │ └── local.trace
│ │ └── bitcoin_lstm_v4_run_0_4b899b
│ │ │ └── train
│ │ │ ├── events.out.tfevents.1580899832.L-156196731.39696.24785.v2
│ │ │ ├── events.out.tfevents.1580899845.L-156196731.profile-empty
│ │ │ └── plugins
│ │ │ └── profile
│ │ │ └── 2020-02-05_16-20-45
│ │ │ └── local.trace
│ └── scripts
│ │ ├── __pycache__
│ │ └── utilities.cpython-36.pyc
│ │ ├── bitcoin_model.py
│ │ ├── utilities - Copy.py
│ │ └── utilities.py
├── Exercise3.01
│ ├── .ipynb_checkpoints
│ │ └── Exercise3.01_Creating_an_active_training_environment-checkpoint.ipynb
│ ├── Exercise3.01_Creating_an_active_training_environment.ipynb
│ ├── bitcoin_lstm_v0.h5
│ ├── bitcoin_lstm_v0_trained.h5
│ ├── data
│ │ ├── BTC-USD.csv
│ │ ├── bitcoin_dataset.csv
│ │ ├── bitcoin_historical_prices.csv
│ │ ├── bitcoin_recent.csv
│ │ ├── test_dataset.csv
│ │ └── train_dataset.csv
│ ├── logs
│ │ └── bitcoin_lstm_v0_run_0
│ │ │ └── train
│ │ │ └── events.out.tfevents.1581417838.L-156196731.1744.10130.v2
│ └── scripts
│ │ ├── __pycache__
│ │ └── utilities.cpython-36.pyc
│ │ ├── bitcoin_model.py
│ │ └── utilities.py
└── images
│ ├── 3.2.jpg
│ ├── 3.3.png
│ └── 3.4.jpg
├── Chapter04
├── Activity4.01
│ ├── .dockerignore
│ ├── .gitignore
│ ├── Dockerfile
│ ├── Makefile
│ ├── README.md
│ ├── bin
│ │ └── build_docker_image.sh
│ ├── cryptonic-cache
│ │ ├── Dockerfile
│ │ └── bin
│ │ │ └── build_docker_image.sh
│ ├── cryptonic-ui
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── postcss.config.js
│ │ ├── src
│ │ │ ├── App.vue
│ │ │ ├── assets
│ │ │ │ ├── botstream.png
│ │ │ │ └── botstream_slack.png
│ │ │ ├── css
│ │ │ │ ├── forbes_logo.css
│ │ │ │ ├── infinite.css
│ │ │ │ ├── loading_animation.css
│ │ │ │ └── style.css
│ │ │ ├── index.html
│ │ │ └── main.js
│ │ ├── webpack.config.js
│ │ └── yarn.lock
│ ├── cryptonic.env
│ ├── cryptonic
│ │ ├── __init__.py
│ │ ├── api
│ │ │ ├── __init__.py
│ │ │ └── routes.py
│ │ ├── markets
│ │ │ ├── __init__.py
│ │ │ └── coinmarketcap.py
│ │ ├── models
│ │ │ ├── __init__.py
│ │ │ ├── helper.py
│ │ │ ├── model.py
│ │ │ └── normalizations.py
│ │ └── server.py
│ ├── cryptonic_old
│ │ ├── __init__.py
│ │ ├── api
│ │ │ ├── __init__.py
│ │ │ └── routes.py
│ │ ├── markets
│ │ │ ├── __init__.py
│ │ │ └── coinmarketcap.py
│ │ ├── models
│ │ │ ├── __init__.py
│ │ │ ├── helper.py
│ │ │ ├── model.py
│ │ │ └── normalizations.py
│ │ └── server.py
│ ├── docker-compose.yml
│ ├── requirements.txt
│ ├── run.py
│ └── screenshot.png
├── Exercise4.01
│ ├── .ipynb_checkpoints
│ │ └── Exercise4.01_Re_training_a_model_dynamically-checkpoint.ipynb
│ ├── Exercise4.01_Re_training_a_model_dynamically.ipynb
│ ├── bitcoin_lstm_v0.h5
│ ├── bitcoin_model_prod_v0.h5
│ └── cryptonic
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ └── __init__.cpython-36.pyc
│ │ ├── api
│ │ ├── __init__.py
│ │ └── routes.py
│ │ ├── markets
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ │ ├── __init__.cpython-36.pyc
│ │ │ └── coinmarketcap.cpython-36.pyc
│ │ └── coinmarketcap.py
│ │ ├── models
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ │ ├── __init__.cpython-36.pyc
│ │ │ ├── helper.cpython-36.pyc
│ │ │ ├── model.cpython-36.pyc
│ │ │ └── normalizations.cpython-36.pyc
│ │ ├── helper.py
│ │ ├── model.py
│ │ └── normalizations.py
│ │ └── server.py
└── Exercise4.02
│ ├── .dockerignore
│ ├── .gitignore
│ ├── Dockerfile
│ ├── Makefile
│ ├── README.md
│ ├── bin
│ └── build_docker_image.sh
│ ├── cryptonic-cache
│ ├── Dockerfile
│ └── bin
│ │ └── build_docker_image.sh
│ ├── cryptonic-ui
│ ├── package-lock.json
│ ├── package.json
│ ├── postcss.config.js
│ ├── src
│ │ ├── App.vue
│ │ ├── assets
│ │ │ ├── botstream.png
│ │ │ └── botstream_slack.png
│ │ ├── css
│ │ │ ├── forbes_logo.css
│ │ │ ├── infinite.css
│ │ │ ├── loading_animation.css
│ │ │ └── style.css
│ │ ├── index.html
│ │ └── main.js
│ ├── webpack.config.js
│ └── yarn.lock
│ ├── cryptonic.env
│ ├── cryptonic
│ ├── __init__.py
│ ├── api
│ │ ├── __init__.py
│ │ └── routes.py
│ ├── markets
│ │ ├── __init__.py
│ │ └── coinmarketcap.py
│ ├── models
│ │ ├── __init__.py
│ │ ├── helper.py
│ │ ├── model.py
│ │ └── normalizations.py
│ └── server.py
│ ├── cryptonic_old
│ ├── __init__.py
│ ├── api
│ │ ├── __init__.py
│ │ └── routes.py
│ ├── markets
│ │ ├── __init__.py
│ │ └── coinmarketcap.py
│ ├── models
│ │ ├── __init__.py
│ │ ├── helper.py
│ │ ├── model.py
│ │ └── normalizations.py
│ └── server.py
│ ├── docker-compose.yml
│ ├── requirements.txt
│ ├── run.py
│ └── screenshot.png
├── LICENSE
├── README.md
└── requirements.txt
/Chapter01/Activity1.01/mnist.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 |
4 | # In[5]:
5 |
6 |
7 | import tensorflow as tf
8 | from tensorflow import keras
9 | from tensorflow.keras.models import Sequential
10 | from tensorflow.keras.layers import Convolution2D, Flatten, Dense, Dropout
11 | import datetime
12 |
13 | from keras.optimizers import adam
14 |
15 |
16 | # In[17]:
17 |
18 |
19 | mnist = tf.keras.datasets.mnist
20 |
21 | (X_train, y_train), (X_test, y_test) = mnist.load_data()
22 | X_train, X_test = X_train / 255.0, X_test / 255.0
23 |
24 |
25 | # In[20]:
26 |
27 | log_dir="logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
28 | tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)
29 |
30 |
31 | X_train = X_train.reshape(X_train.shape[0],X_train.shape[1], X_train.shape[2],1)
32 | X_test = X_test.reshape(X_test.shape[0],X_test.shape[1], X_test.shape[2],1)
33 |
34 |
35 | # In[21]:
36 |
37 |
38 | model = Sequential()
39 | model.add(Convolution2D(filters = 10, kernel_size = 3, input_shape=(28,28,1)))
40 | model.add(Flatten())
41 | model.add(Dense(128, activation = 'relu'))
42 | model.add(Dropout(0.2))
43 | model.add(Dense(10, activation = 'softmax'))
44 |
45 |
46 |
47 |
48 | # In[22]:
49 |
50 | learning_rate=0.001
51 |
52 |
53 | model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate = learning_rate),
54 | loss='sparse_categorical_crossentropy',
55 | metrics=['accuracy'])
56 |
57 |
58 | # In[23]:
59 |
60 |
61 | model.fit(X_train, y_train, epochs=5, validation_data=(X_test, y_test),callbacks=[tensorboard_callback])
62 |
63 |
64 | # In[ ]:
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/Chapter01/Activity1.01/requirements.txt:
--------------------------------------------------------------------------------
1 | absl-py==0.8.1
2 | astor==0.8.0
3 | attrs==19.3.0
4 | backcall==0.1.0
5 | beautifulsoup4==4.8.1
6 | bleach==3.1.0
7 | cachetools==3.1.1
8 | certifi==2019.9.11
9 | chardet==3.0.4
10 | Click==7.0
11 | cycler==0.10.0
12 | decorator==4.4.1
13 | defusedxml==0.6.0
14 | entrypoints==0.3
15 | Flask==1.1.1
16 | Flask-API==2.0
17 | Flask-Caching==1.8.0
18 | Flask-Cors==3.0.8
19 | Flask-Testing==0.7.1
20 | gast==0.2.2
21 | google-auth==1.7.0
22 | google-auth-oauthlib==0.4.1
23 | google-pasta==0.1.8
24 | graphviz==0.13.2
25 | grpcio==1.24.3
26 | h5py==2.10.0
27 | html5lib==1.0.1
28 | idna==2.8
29 | importlib-metadata==1.3.0
30 | ipykernel==5.1.3
31 | ipython==7.10.2
32 | ipython-genutils==0.2.0
33 | ipywidgets==7.5.1
34 | itsdangerous==1.1.0
35 | jedi==0.15.2
36 | Jinja2==2.10.3
37 | jsonschema==3.2.0
38 | jupyter==1.0.0
39 | jupyter-client==5.3.4
40 | jupyter-console==6.0.0
41 | jupyter-core==4.6.1
42 | Keras==2.2.4
43 | Keras-Applications==1.0.8
44 | Keras-Preprocessing==1.1.0
45 | kiwisolver==1.1.0
46 | Markdown==3.1.1
47 | MarkupSafe==1.1.1
48 | matplotlib==3.1.2
49 | mistune==0.8.4
50 | more-itertools==8.0.2
51 | nbconvert==5.6.1
52 | nbformat==4.4.0
53 | notebook==6.0.2
54 | numpy==1.17.3
55 | oauthlib==3.1.0
56 | opt-einsum==3.1.0
57 | pandas==0.25.3
58 | pandocfilters==1.4.2
59 | parso==0.5.2
60 | pexpect==4.7.0
61 | pickleshare==0.7.5
62 | prometheus-client==0.7.1
63 | prompt-toolkit==2.0.10
64 | protobuf==3.10.0
65 | ptyprocess==0.6.0
66 | pyasn1==0.4.7
67 | pyasn1-modules==0.2.7
68 | Pygments==2.5.2
69 | pyparsing==2.4.5
70 | pyrsistent==0.15.6
71 | python-dateutil==2.8.1
72 | pytz==2019.3
73 | PyYAML==5.2
74 | pyzmq==18.1.1
75 | qtconsole==4.6.0
76 | requests==2.22.0
77 | requests-oauthlib==1.2.0
78 | rsa==4.0
79 | scipy==1.4.1
80 | seaborn==0.9.0
81 | Send2Trash==1.5.0
82 | six==1.13.0
83 | soupsieve==1.9.5
84 | tensorboard==2.0.1
85 | tensorflow==2.0.0
86 | tensorflow-estimator==2.0.1
87 | termcolor==1.1.0
88 | terminado==0.8.3
89 | testpath==0.4.4
90 | tornado==6.0.3
91 | tqdm==4.41.0
92 | traitlets==4.3.3
93 | urllib3==1.25.6
94 | wcwidth==0.1.7
95 | webencodings==0.5.1
96 | Werkzeug==0.16.0
97 | widgetsnbextension==3.5.1
98 | wrapt==1.11.2
99 | zipp==0.6.0
100 |
--------------------------------------------------------------------------------
/Chapter01/Exercise1.01/requirements.txt:
--------------------------------------------------------------------------------
1 | absl-py==0.8.1
2 | astor==0.8.0
3 | attrs==19.3.0
4 | backcall==0.1.0
5 | beautifulsoup4==4.8.1
6 | bleach==3.1.0
7 | cachetools==3.1.1
8 | certifi==2019.9.11
9 | chardet==3.0.4
10 | Click==7.0
11 | cycler==0.10.0
12 | decorator==4.4.1
13 | defusedxml==0.6.0
14 | entrypoints==0.3
15 | Flask==1.1.1
16 | Flask-API==2.0
17 | Flask-Caching==1.8.0
18 | Flask-Cors==3.0.8
19 | Flask-Testing==0.7.1
20 | gast==0.2.2
21 | google-auth==1.7.0
22 | google-auth-oauthlib==0.4.1
23 | google-pasta==0.1.8
24 | graphviz==0.13.2
25 | grpcio==1.24.3
26 | h5py==2.10.0
27 | html5lib==1.0.1
28 | idna==2.8
29 | importlib-metadata==1.3.0
30 | ipykernel==5.1.3
31 | ipython==7.10.2
32 | ipython-genutils==0.2.0
33 | ipywidgets==7.5.1
34 | itsdangerous==1.1.0
35 | jedi==0.15.2
36 | Jinja2==2.10.3
37 | jsonschema==3.2.0
38 | jupyter==1.0.0
39 | jupyter-client==5.3.4
40 | jupyter-console==6.0.0
41 | jupyter-core==4.6.1
42 | Keras==2.2.4
43 | Keras-Applications==1.0.8
44 | Keras-Preprocessing==1.1.0
45 | kiwisolver==1.1.0
46 | Markdown==3.1.1
47 | MarkupSafe==1.1.1
48 | matplotlib==3.1.2
49 | mistune==0.8.4
50 | more-itertools==8.0.2
51 | nbconvert==5.6.1
52 | nbformat==4.4.0
53 | notebook==6.0.2
54 | numpy==1.17.3
55 | oauthlib==3.1.0
56 | opt-einsum==3.1.0
57 | pandas==0.25.3
58 | pandocfilters==1.4.2
59 | parso==0.5.2
60 | pexpect==4.7.0
61 | pickleshare==0.7.5
62 | prometheus-client==0.7.1
63 | prompt-toolkit==2.0.10
64 | protobuf==3.10.0
65 | ptyprocess==0.6.0
66 | pyasn1==0.4.7
67 | pyasn1-modules==0.2.7
68 | Pygments==2.5.2
69 | pyparsing==2.4.5
70 | pyrsistent==0.15.6
71 | python-dateutil==2.8.1
72 | pytz==2019.3
73 | PyYAML==5.2
74 | pyzmq==18.1.1
75 | qtconsole==4.6.0
76 | requests==2.22.0
77 | requests-oauthlib==1.2.0
78 | rsa==4.0
79 | scipy==1.4.1
80 | seaborn==0.9.0
81 | Send2Trash==1.5.0
82 | setuptools==41.0.0
83 | six==1.13.0
84 | soupsieve==1.9.5
85 | tensorboard==2.0.1
86 | tensorflow==2.0.0
87 | tensorflow-estimator==2.0.1
88 | termcolor==1.1.0
89 | terminado==0.8.3
90 | testpath==0.4.4
91 | tornado==6.0.3
92 | tqdm==4.41.0
93 | traitlets==4.3.3
94 | urllib3==1.25.6
95 | wcwidth==0.1.7
96 | webencodings==0.5.1
97 | Werkzeug==0.16.0
98 | widgetsnbextension==3.5.1
99 | wrapt==1.11.2
100 | zipp==0.6.0
101 |
--------------------------------------------------------------------------------
/Chapter01/Exercise1.01/test_stack.py:
--------------------------------------------------------------------------------
1 | """
2 | Simple tests for verifying software requirements.
3 | These tests will check if the following conditions
4 | are met:
5 |
6 | * Python is 3.0 or higher.
7 | * TensorFlow is 2.0 or higher.
8 | * Keras is 2.2 or higher.
9 |
10 | The program returns helpful error messages if
11 | the conditions above are not met.abs
12 |
13 | Proceed to Chapter 02 when all tests pass.
14 |
15 | --
16 | Author: Luis Capelo
17 | Date: October 17, 2017
18 | """
19 | import sys
20 |
21 |
22 | def __separator(c):
23 | """
24 | Prints a pretty separator.
25 |
26 | Parameters
27 | ----------
28 | c: str
29 | Character to use.
30 | """
31 | print(c * 65)
32 |
33 | def test_python():
34 | """
35 | Tests if Python 3 is installed.
36 | """
37 | message = None
38 | if sys.version_info[0] == 3:
39 | success = True
40 | log = """
41 | PASS: Python 3.0 (or higher) is installed.
42 | """
43 |
44 | else:
45 | success = False
46 | log = """
47 | FAIL: Python 3.0 (or higher) not detected.
48 | """
49 | message = """
50 | Please install it before proceeding.
51 | Follow instructions in the official Python
52 | website in order to install it in your platform:
53 |
54 | https://www.python.org/downloads/
55 | """
56 |
57 | print(log)
58 | if message:
59 | print(message)
60 |
61 | __separator('~')
62 | return success
63 |
64 | def test_tensorflow():
65 | """
66 | Tests if TensorFlow is installed.
67 | """
68 | message = None
69 | try:
70 | import tensorflow;
71 |
72 | if tensorflow.__version__ >= '2.0.0':
73 | success = True
74 | log = """
75 | PASS: TensorFlow 2.0.0 (or higher) is installed.
76 | """
77 |
78 | else:
79 | success = False
80 | log = """
81 | FAIL: TensorFlow 2.0.0 (or higher) not detected.
82 | """
83 | message = """
84 | Please install it before proceeding.
85 | Follow instructions in the official TensorFlow
86 | website in order to install it in your platform:
87 |
88 | https://www.tensorflow.org/install/
89 | """
90 |
91 | except ModuleNotFoundError:
92 | success = False
93 | log = """
94 | FAIL: TensorFlow 2.0.0 (or higher) not detected.
95 | """
96 | message = """
97 | Please install it before proceeding.
98 | Follow instructions in the official TensorFlow
99 | website in order to install it in your platform:
100 |
101 | https://www.tensorflow.org/install/
102 | """
103 |
104 | print(log)
105 | if message:
106 | print(message)
107 |
108 | __separator('~')
109 | return success
110 |
111 | def test_keras():
112 | """
113 | Tests if Keras is installed.
114 | """
115 | message = None
116 | try:
117 | import keras
118 |
119 | if sys.version_info[0] == 3:
120 | success = True
121 | log = """
122 | PASS: Keras 2.2 (or higher) is installed.
123 | """
124 |
125 | else:
126 | success = False
127 | log = """
128 | FAIL: Keras 2.2 (or higher) not detected.
129 | """
130 | message = """
131 | Please install it before proceeding.
132 | Follow instructions in the official Keras
133 | website in order to install it in your platform:
134 |
135 | https://keras.io/#installation
136 | """
137 |
138 | except ModuleNotFoundError:
139 | success = False
140 | log = """
141 | FAIL: Keras 2.2 (or higher) not detected.
142 | """
143 | message = """
144 | Please install it before proceeding.
145 | Follow instructions in the official Keras
146 | website in order to install it in your platform:
147 |
148 | https://keras.io/#installation
149 | """
150 |
151 | print(log)
152 | if message:
153 | print(message)
154 |
155 | __separator('~')
156 | return success
157 |
158 |
159 | if __name__ == '__main__':
160 | __separator('=')
161 | test_results = [
162 | test_python(),
163 | test_tensorflow(),
164 | test_keras()]
165 |
166 | if False in test_results:
167 | print(
168 | """
169 | ** Please review software requirements before
170 | ** proceeding to Chapter 02.
171 | """
172 | )
173 | else:
174 | print(
175 | """
176 | ** Python, TensorFlow, and Keras are available.
177 | """
178 | )
179 | __separator('=')
180 |
--------------------------------------------------------------------------------
/Chapter01/Exercise1.02/mnist.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 |
4 | # In[5]:
5 |
6 |
7 | import tensorflow as tf
8 | from tensorflow import keras
9 | from tensorflow.keras.models import Sequential
10 | from tensorflow.keras.layers import Convolution2D, Flatten, Dense, Dropout
11 | import datetime
12 |
13 | # In[17]:
14 |
15 |
16 | mnist = tf.keras.datasets.mnist
17 |
18 | (X_train, y_train), (X_test, y_test) = mnist.load_data()
19 | X_train, X_test = X_train / 255.0, X_test / 255.0
20 |
21 |
22 | # In[20]:
23 |
24 | log_dir="logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
25 | tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)
26 |
27 |
28 | X_train = X_train.reshape(X_train.shape[0],X_train.shape[1], X_train.shape[2],1)
29 | X_test = X_test.reshape(X_test.shape[0],X_test.shape[1], X_test.shape[2],1)
30 |
31 |
32 | # In[21]:
33 |
34 |
35 | model = Sequential()
36 | model.add(Convolution2D(filters = 10, kernel_size = 3, input_shape=(28,28,1)))
37 | model.add(Flatten())
38 | model.add(Dense(128, activation = 'relu'))
39 | model.add(Dropout(0.2))
40 | model.add(Dense(10, activation = 'softmax'))
41 |
42 |
43 | # In[22]:
44 |
45 |
46 | model.compile(optimizer='adam',
47 | loss='sparse_categorical_crossentropy',
48 | metrics=['accuracy'])
49 |
50 |
51 | # In[23]:
52 |
53 |
54 | model.fit(X_train, y_train, epochs=5, validation_data=(X_test, y_test),callbacks=[tensorboard_callback])
55 |
56 |
57 | # In[ ]:
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/Chapter01/Exercise1.02/requirements.txt:
--------------------------------------------------------------------------------
1 | absl-py==0.8.1
2 | astor==0.8.0
3 | attrs==19.3.0
4 | backcall==0.1.0
5 | beautifulsoup4==4.8.1
6 | bleach==3.1.0
7 | cachetools==3.1.1
8 | certifi==2019.9.11
9 | chardet==3.0.4
10 | Click==7.0
11 | cycler==0.10.0
12 | decorator==4.4.1
13 | defusedxml==0.6.0
14 | entrypoints==0.3
15 | Flask==1.1.1
16 | Flask-API==2.0
17 | Flask-Caching==1.8.0
18 | Flask-Cors==3.0.8
19 | Flask-Testing==0.7.1
20 | gast==0.2.2
21 | google-auth==1.7.0
22 | google-auth-oauthlib==0.4.1
23 | google-pasta==0.1.8
24 | graphviz==0.13.2
25 | grpcio==1.24.3
26 | h5py==2.10.0
27 | html5lib==1.0.1
28 | idna==2.8
29 | importlib-metadata==1.3.0
30 | ipykernel==5.1.3
31 | ipython==7.10.2
32 | ipython-genutils==0.2.0
33 | ipywidgets==7.5.1
34 | itsdangerous==1.1.0
35 | jedi==0.15.2
36 | Jinja2==2.10.3
37 | jsonschema==3.2.0
38 | jupyter==1.0.0
39 | jupyter-client==5.3.4
40 | jupyter-console==6.0.0
41 | jupyter-core==4.6.1
42 | Keras==2.2.4
43 | Keras-Applications==1.0.8
44 | Keras-Preprocessing==1.1.0
45 | kiwisolver==1.1.0
46 | Markdown==3.1.1
47 | MarkupSafe==1.1.1
48 | matplotlib==3.1.2
49 | mistune==0.8.4
50 | more-itertools==8.0.2
51 | nbconvert==5.6.1
52 | nbformat==4.4.0
53 | notebook==6.0.2
54 | numpy==1.17.3
55 | oauthlib==3.1.0
56 | opt-einsum==3.1.0
57 | pandas==0.25.3
58 | pandocfilters==1.4.2
59 | parso==0.5.2
60 | pexpect==4.7.0
61 | pickleshare==0.7.5
62 | prometheus-client==0.7.1
63 | prompt-toolkit==2.0.10
64 | protobuf==3.10.0
65 | ptyprocess==0.6.0
66 | pyasn1==0.4.7
67 | pyasn1-modules==0.2.7
68 | Pygments==2.5.2
69 | pyparsing==2.4.5
70 | pyrsistent==0.15.6
71 | python-dateutil==2.8.1
72 | pytz==2019.3
73 | PyYAML==5.2
74 | pyzmq==18.1.1
75 | qtconsole==4.6.0
76 | requests==2.22.0
77 | requests-oauthlib==1.2.0
78 | rsa==4.0
79 | scipy==1.4.1
80 | seaborn==0.9.0
81 | Send2Trash==1.5.0
82 | six==1.13.0
83 | soupsieve==1.9.5
84 | tensorboard==2.0.1
85 | tensorflow==2.0.0
86 | tensorflow-estimator==2.0.1
87 | termcolor==1.1.0
88 | terminado==0.8.3
89 | testpath==0.4.4
90 | tornado==6.0.3
91 | tqdm==4.41.0
92 | traitlets==4.3.3
93 | urllib3==1.25.6
94 | wcwidth==0.1.7
95 | webencodings==0.5.1
96 | Werkzeug==0.16.0
97 | widgetsnbextension==3.5.1
98 | wrapt==1.11.2
99 | zipp==0.6.0
100 |
--------------------------------------------------------------------------------
/Chapter02/Activity2.01/bitcoin_lstm_v0.h5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter02/Activity2.01/bitcoin_lstm_v0.h5
--------------------------------------------------------------------------------
/Chapter02/Activity2.01/bitcoin_lstm_v0_trained.h5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter02/Activity2.01/bitcoin_lstm_v0_trained.h5
--------------------------------------------------------------------------------
/Chapter02/Exercise2.01/normalizations.py:
--------------------------------------------------------------------------------
1 | """
2 | Series of normalization functions useful
3 | for normalizing time-series data.
4 |
5 | Author: Luis Capelo
6 | """
7 | def z_score(series):
8 | """
9 | Computes the normalized value using the Z-score
10 | technique. The Z-score is a technique used for
11 | normalizing Gaussian distributions representing
12 | each observation in relation to the distribution's
13 | mean and standard deviation. For precise definitions,
14 | see the Wikipedia article:
15 |
16 | https://en.wikipedia.org/wiki/Standard_score
17 |
18 | Parameters
19 | ----------
20 | serie: list
21 | List with sequential values to use.
22 |
23 | Returns
24 | -------
25 | result: list
26 | List with the normalized results.
27 | """
28 | result = (series - series.mean()) / series.std(ddof=0)
29 | return result
30 |
31 | def point_relative_normalization(series):
32 | """
33 | Computes the normalized value for the values of a
34 | given series by using the first element of the serie as p_0
35 | as a reference for each p_i.
36 |
37 | This technique comes from Siraj Raval's YouTube video
38 | "How to Predict Stock Prices Easily - Intro to Deep Learning #7",
39 | available at:
40 |
41 | https://www.youtube.com/watch?v=ftMq5ps503w
42 |
43 | Parameters
44 | ----------
45 | serie: list
46 | List with sequential values to use.
47 |
48 | Returns
49 | -------
50 | result: list
51 | List with the normalized results.
52 | """
53 | result = (series / series.values[0]) - 1
54 | return result
55 |
56 | def maximum_and_minimum_normalization(series, boundary=(0, 1)):
57 | """
58 | Computes the normalized value for the values of a
59 | given serie by using that series maximum and minimum
60 | values.
61 |
62 | This technique is a direct implementation from
63 | scikit-learn, available at:
64 |
65 | http://scikit-learn.org/stable/modules/generated/\
66 | sklearn.preprocessing.MinMaxScaler.html
67 |
68 | Parameters
69 | ----------
70 | serie: list
71 | List with sequential values to use.
72 |
73 | boundary: set
74 | Maximum and minimum values used to
75 | scale the series.
76 |
77 | Returns
78 | -------
79 | result: list
80 | List with the normalized results.
81 | """
82 | range_min, range_max = boundary
83 | standard_deviation = (series - series.min(axis=0)) / (series.max(axis=0) - series.min(axis=0))
84 | result = standard_deviation * (range_max - range_min) + range_min
85 |
86 | return result
87 |
--------------------------------------------------------------------------------
/Chapter02/Exercise2.02/bitcoin_lstm_v0.h5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter02/Exercise2.02/bitcoin_lstm_v0.h5
--------------------------------------------------------------------------------
/Chapter02/images/2.1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter02/images/2.1.jpg
--------------------------------------------------------------------------------
/Chapter02/images/2.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter02/images/2.2.png
--------------------------------------------------------------------------------
/Chapter02/images/2.3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter02/images/2.3.jpg
--------------------------------------------------------------------------------
/Chapter03/Activity3.01/bitcoin_lstm_v0.h5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/Activity3.01/bitcoin_lstm_v0.h5
--------------------------------------------------------------------------------
/Chapter03/Activity3.01/logs/bitcoin_lstm_v0_run_0_7d47b6/train/events.out.tfevents.1580899648.L-156196731.39696.334.v2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/Activity3.01/logs/bitcoin_lstm_v0_run_0_7d47b6/train/events.out.tfevents.1580899648.L-156196731.39696.334.v2
--------------------------------------------------------------------------------
/Chapter03/Activity3.01/logs/bitcoin_lstm_v0_run_0_7d47b6/train/events.out.tfevents.1580899654.L-156196731.profile-empty:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/Activity3.01/logs/bitcoin_lstm_v0_run_0_7d47b6/train/events.out.tfevents.1580899654.L-156196731.profile-empty
--------------------------------------------------------------------------------
/Chapter03/Activity3.01/logs/bitcoin_lstm_v0_run_0_7d47b6/train/plugins/profile/2020-02-05_16-17-34/local.trace:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/Activity3.01/logs/bitcoin_lstm_v0_run_0_7d47b6/train/plugins/profile/2020-02-05_16-17-34/local.trace
--------------------------------------------------------------------------------
/Chapter03/Activity3.01/logs/bitcoin_lstm_v1_run_0_12e0e4/train/events.out.tfevents.1580899657.L-156196731.39696.3231.v2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/Activity3.01/logs/bitcoin_lstm_v1_run_0_12e0e4/train/events.out.tfevents.1580899657.L-156196731.39696.3231.v2
--------------------------------------------------------------------------------
/Chapter03/Activity3.01/logs/bitcoin_lstm_v1_run_0_12e0e4/train/events.out.tfevents.1580899670.L-156196731.profile-empty:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/Activity3.01/logs/bitcoin_lstm_v1_run_0_12e0e4/train/events.out.tfevents.1580899670.L-156196731.profile-empty
--------------------------------------------------------------------------------
/Chapter03/Activity3.01/logs/bitcoin_lstm_v1_run_0_12e0e4/train/plugins/profile/2020-02-05_16-17-50/local.trace:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/Activity3.01/logs/bitcoin_lstm_v1_run_0_12e0e4/train/plugins/profile/2020-02-05_16-17-50/local.trace
--------------------------------------------------------------------------------
/Chapter03/Activity3.01/logs/bitcoin_lstm_v2_run_0_a4ff9d/train/events.out.tfevents.1580899698.L-156196731.39696.9795.v2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/Activity3.01/logs/bitcoin_lstm_v2_run_0_a4ff9d/train/events.out.tfevents.1580899698.L-156196731.39696.9795.v2
--------------------------------------------------------------------------------
/Chapter03/Activity3.01/logs/bitcoin_lstm_v2_run_0_a4ff9d/train/events.out.tfevents.1580899711.L-156196731.profile-empty:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/Activity3.01/logs/bitcoin_lstm_v2_run_0_a4ff9d/train/events.out.tfevents.1580899711.L-156196731.profile-empty
--------------------------------------------------------------------------------
/Chapter03/Activity3.01/logs/bitcoin_lstm_v2_run_0_a4ff9d/train/plugins/profile/2020-02-05_16-18-31/local.trace:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/Activity3.01/logs/bitcoin_lstm_v2_run_0_a4ff9d/train/plugins/profile/2020-02-05_16-18-31/local.trace
--------------------------------------------------------------------------------
/Chapter03/Activity3.01/logs/bitcoin_lstm_v3_run_0_5e2911/train/events.out.tfevents.1580899791.L-156196731.39696.18160.v2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/Activity3.01/logs/bitcoin_lstm_v3_run_0_5e2911/train/events.out.tfevents.1580899791.L-156196731.39696.18160.v2
--------------------------------------------------------------------------------
/Chapter03/Activity3.01/logs/bitcoin_lstm_v3_run_0_5e2911/train/events.out.tfevents.1580899803.L-156196731.profile-empty:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/Activity3.01/logs/bitcoin_lstm_v3_run_0_5e2911/train/events.out.tfevents.1580899803.L-156196731.profile-empty
--------------------------------------------------------------------------------
/Chapter03/Activity3.01/logs/bitcoin_lstm_v3_run_0_5e2911/train/plugins/profile/2020-02-05_16-20-03/local.trace:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/Activity3.01/logs/bitcoin_lstm_v3_run_0_5e2911/train/plugins/profile/2020-02-05_16-20-03/local.trace
--------------------------------------------------------------------------------
/Chapter03/Activity3.01/logs/bitcoin_lstm_v4_run_0_4b899b/train/events.out.tfevents.1580899832.L-156196731.39696.24785.v2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/Activity3.01/logs/bitcoin_lstm_v4_run_0_4b899b/train/events.out.tfevents.1580899832.L-156196731.39696.24785.v2
--------------------------------------------------------------------------------
/Chapter03/Activity3.01/logs/bitcoin_lstm_v4_run_0_4b899b/train/events.out.tfevents.1580899845.L-156196731.profile-empty:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/Activity3.01/logs/bitcoin_lstm_v4_run_0_4b899b/train/events.out.tfevents.1580899845.L-156196731.profile-empty
--------------------------------------------------------------------------------
/Chapter03/Activity3.01/logs/bitcoin_lstm_v4_run_0_4b899b/train/plugins/profile/2020-02-05_16-20-45/local.trace:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/Activity3.01/logs/bitcoin_lstm_v4_run_0_4b899b/train/plugins/profile/2020-02-05_16-20-45/local.trace
--------------------------------------------------------------------------------
/Chapter03/Activity3.01/scripts/__pycache__/utilities.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/Activity3.01/scripts/__pycache__/utilities.cpython-36.pyc
--------------------------------------------------------------------------------
/Chapter03/Activity3.01/scripts/bitcoin_model.py:
--------------------------------------------------------------------------------
1 | """
2 | Classes and methods for working with a Bitcoin
3 | LSTM model.
4 | """
5 | import numpy as np
6 |
7 | from tensorflow.keras.models import load_model
8 |
9 |
10 | class BitcoinModel:
11 | """
12 | Class that encapsulates the Bitcoin LSTM model
13 | that we have been building. This class makes it
14 | easy to work with the different functions
15 | used to work with the model.
16 |
17 | Parameters
18 | ----------
19 | path: str
20 | Location to load model from.
21 |
22 | """
23 | def __init__(self, model_path):
24 | self.model_path = model_path
25 | self.load()
26 |
27 | def load(self):
28 | """
29 | Loads model from a known location.
30 | """
31 | self.model = load_model(self.model_path)
32 | return self.model
33 |
34 | def save(self, path):
35 | """
36 | Stores trained model in disk.
37 |
38 | Parameters
39 | ----------
40 | path: str
41 | Location of where to store.
42 | """
43 | return self.model.save(path)
44 |
45 | def create_groups(self, data, group_size=7):
46 | """
47 | Creates distinct groups from a given continuous series.
48 |
49 | Parameters
50 | ----------
51 | data: np.array
52 | Series of continious observations.
53 |
54 | group_size: int, default 7
55 | Determines how large the groups are. That is,
56 | how many observations each group contains.
57 |
58 | Returns
59 | -------
60 | A Numpy array object.
61 | """
62 | samples = list()
63 | for i in range(0, len(data), group_size):
64 | sample = list(data[i:i + group_size])
65 | if len(sample) == group_size:
66 | samples.append(np.array(sample).reshape(1, group_size).tolist())
67 |
68 | A = np.array(samples)
69 | return A.reshape(1, A.shape[0], group_size)
70 |
71 | def denormalize(self, series, last_value):
72 | """
73 | De-normalizes a series using the latest
74 | value available from data.
75 |
76 | Parameters
77 | ----------
78 | series: numpy array
79 | Series with normalized values.
80 |
81 | last_value: float
82 | Numerical value that represents the
83 | last value from the dataset.
84 | """
85 | result = last_value * (series + 1)
86 | return result
87 |
88 | def predict(self, X):
89 | """
90 | """
91 | return self.model.predict(x=X)
92 |
93 | def train(self):
94 | """
95 | """
96 | self.model.fit()
97 | pass
98 |
99 | def evaluate(self):
100 | """
101 | """
102 | pass
103 |
--------------------------------------------------------------------------------
/Chapter03/Exercise3.01/bitcoin_lstm_v0.h5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/Exercise3.01/bitcoin_lstm_v0.h5
--------------------------------------------------------------------------------
/Chapter03/Exercise3.01/bitcoin_lstm_v0_trained.h5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/Exercise3.01/bitcoin_lstm_v0_trained.h5
--------------------------------------------------------------------------------
/Chapter03/Exercise3.01/logs/bitcoin_lstm_v0_run_0/train/events.out.tfevents.1581417838.L-156196731.1744.10130.v2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/Exercise3.01/logs/bitcoin_lstm_v0_run_0/train/events.out.tfevents.1581417838.L-156196731.1744.10130.v2
--------------------------------------------------------------------------------
/Chapter03/Exercise3.01/scripts/__pycache__/utilities.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/Exercise3.01/scripts/__pycache__/utilities.cpython-36.pyc
--------------------------------------------------------------------------------
/Chapter03/Exercise3.01/scripts/bitcoin_model.py:
--------------------------------------------------------------------------------
1 | """
2 | Classes and methods for working with a Bitcoin
3 | LSTM model.
4 | """
5 | import numpy as np
6 |
7 | from tensorflow.keras.models import load_model
8 |
9 |
10 | class BitcoinModel:
11 | """
12 | Class that encapsulates the Bitcoin LSTM model
13 | that we have been building. This class makes it
14 | easy to work with the different functions
15 | used to work with the model.
16 |
17 | Parameters
18 | ----------
19 | path: str
20 | Location to load model from.
21 |
22 | """
23 | def __init__(self, model_path):
24 | self.model_path = model_path
25 | self.load()
26 |
27 | def load(self):
28 | """
29 | Loads model from a known location.
30 | """
31 | self.model = load_model(self.model_path)
32 | return self.model
33 |
34 | def save(self, path):
35 | """
36 | Stores trained model in disk.
37 |
38 | Parameters
39 | ----------
40 | path: str
41 | Location of where to store.
42 | """
43 | return self.model.save(path)
44 |
45 | def create_groups(self, data, group_size=7):
46 | """
47 | Creates distinct groups from a given continuous series.
48 |
49 | Parameters
50 | ----------
51 | data: np.array
52 | Series of continious observations.
53 |
54 | group_size: int, default 7
55 | Determines how large the groups are. That is,
56 | how many observations each group contains.
57 |
58 | Returns
59 | -------
60 | A Numpy array object.
61 | """
62 | samples = list()
63 | for i in range(0, len(data), group_size):
64 | sample = list(data[i:i + group_size])
65 | if len(sample) == group_size:
66 | samples.append(np.array(sample).reshape(1, group_size).tolist())
67 |
68 | A = np.array(samples)
69 | return A.reshape(1, A.shape[0], group_size)
70 |
71 | def denormalize(self, series, last_value):
72 | """
73 | De-normalizes a series using the latest
74 | value available from data.
75 |
76 | Parameters
77 | ----------
78 | series: numpy array
79 | Series with normalized values.
80 |
81 | last_value: float
82 | Numerical value that represents the
83 | last value from the dataset.
84 | """
85 | result = last_value * (series + 1)
86 | return result
87 |
88 | def predict(self, X):
89 | """
90 | """
91 | return self.model.predict(x=X)
92 |
93 | def train(self):
94 | """
95 | """
96 | self.model.fit()
97 | pass
98 |
99 | def evaluate(self):
100 | """
101 | """
102 | pass
103 |
--------------------------------------------------------------------------------
/Chapter03/Exercise3.01/scripts/utilities.py:
--------------------------------------------------------------------------------
1 | """
2 | Utility functions used in Exercise 3.01.
3 |
4 | Author: Luis Capelo
5 | Date: 2017-12-18
6 | """
7 | import numpy as np
8 |
9 |
10 | def create_groups(data, group_size=15):
11 | """
12 | Creates distinct groups from a given continuous series.
13 |
14 | Parameters
15 | ----------
16 | data: np.array
17 | Series of continious observations.
18 |
19 | group_size: int, default 7
20 | Determines how large the groups are. That is,
21 | how many observations each group contains.
22 |
23 | Returns
24 | -------
25 | A Numpy array object.
26 | """
27 | samples = list()
28 | for i in range(0, len(data), group_size):
29 | sample = list(data[i:i + group_size])
30 | if len(sample) == group_size:
31 | samples.append(np.array(sample).reshape(1, group_size).tolist())
32 |
33 | A = np.array(samples)
34 | return A.reshape(1, A.shape[0], group_size)
35 |
36 | def split_lstm_input(groups):
37 | """
38 | Splits groups in a format expected by
39 | the LSTM layer.
40 |
41 | Parameters
42 | ----------
43 | groups: np.array
44 | Numpy array with the organized sequences.
45 |
46 | Returns
47 | -------
48 | X, Y: np.array
49 | Numpy arrays with the shapes required by
50 | the LSTM layer. X with (1, a - 1, b)
51 | and Y with (1, b). Where a is the total
52 | number of groups in `group` and b the
53 | number of observations per group.
54 | """
55 | X = groups[0:,:-1].reshape(1, groups.shape[1] - 1, groups.shape[2])
56 | Y = groups[0:,-1:][0]
57 |
58 | return X, Y
59 |
60 | def mape(A, B):
61 | """
62 | Calcualtes the mean absolute persent error
63 | from two series. Original solution from:
64 |
65 | https://stats.stackexchange.com/questions/58391/\
66 | mean-absolute-percentage-error-mape-in-scikit-learn
67 | """
68 | return np.mean(np.abs((A - B) / A)) * 100
69 |
70 | def rmse(A, B):
71 | """
72 | Calculates the root mean square error from
73 | two series. Original solution from:
74 |
75 | https://stackoverflow.com/questions/16774849\
76 | /mean-squared-error-in-numpy
77 | """
78 | return np.sqrt(np.square(np.subtract(A, B)).mean())
79 |
--------------------------------------------------------------------------------
/Chapter03/images/3.2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/images/3.2.jpg
--------------------------------------------------------------------------------
/Chapter03/images/3.3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/images/3.3.png
--------------------------------------------------------------------------------
/Chapter03/images/3.4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter03/images/3.4.jpg
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/.dockerignore:
--------------------------------------------------------------------------------
1 | # MacOS Files
2 | .DS_Store
3 |
4 | # Byte-compiled / optimized / DLL files
5 | __pycache__/
6 | *.py[cod]
7 | *$py.class
8 |
9 | # C extensions
10 | *.so
11 |
12 | # Node modules
13 | node_modules/
14 |
15 | # Distribution / packaging
16 | .Python
17 | env/
18 | build/
19 | develop-eggs/
20 | dist/
21 | downloads/
22 | eggs/
23 | .eggs/
24 | lib/
25 | lib64/
26 | parts/
27 | sdist/
28 | var/
29 | *.egg-info/
30 | .installed.cfg
31 | *.egg
32 |
33 | # PyInstaller
34 | # Usually these files are written by a python script from a template
35 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
36 | *.manifest
37 | *.spec
38 |
39 | # Installer logs
40 | pip-log.txt
41 | pip-delete-this-directory.txt
42 |
43 | # Unit test / coverage reports
44 | htmlcov/
45 | .tox/
46 | .coverage
47 | .coverage.*
48 | .cache
49 | nosetests.xml
50 | coverage.xml
51 | *,cover
52 | .hypothesis/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 |
62 | # Flask stuff:
63 | instance/
64 | .webassets-cache
65 |
66 | # Scrapy stuff:
67 | .scrapy
68 |
69 | # Sphinx documentation
70 | docs/_build/
71 |
72 | # PyBuilder
73 | target/
74 |
75 | # IPython Notebook
76 | .ipynb_checkpoints
77 |
78 | # pyenv
79 | .python-version
80 |
81 | # celery beat schedule file
82 | celerybeat-schedule
83 |
84 | # dotenv
85 | .env
86 |
87 | # virtualenv
88 | venv/
89 | ENV/
90 |
91 | # Spyder project settings
92 | .spyderproject
93 |
94 | # Rope project settings
95 | .ropeproject
96 |
97 | # Visual Studio Code configuration files
98 | .vscode/*
99 |
100 | # Testing artifacts
101 | .noseids
102 | coverage/
103 |
104 | # Ignore other applications
105 | cryptonic-cache/
106 |
107 | # Ignoring cache and database data
108 | data/
109 | logs/
110 |
111 | # Ignore tests folder
112 | tests/
113 |
114 | # Packaged files
115 | *.tar.gz
116 |
117 | # Deploy files
118 | deploy.sh
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | env/
12 | build/
13 | develop-eggs/
14 | dist/
15 | downloads/
16 | eggs/
17 | .eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 |
49 | # Translations
50 | *.mo
51 | *.pot
52 |
53 | # Django stuff:
54 | *.log
55 | local_settings.py
56 |
57 | # Flask stuff:
58 | instance/
59 | .webassets-cache
60 |
61 | # Scrapy stuff:
62 | .scrapy
63 |
64 | # Sphinx documentation
65 | docs/_build/
66 |
67 | # PyBuilder
68 | target/
69 |
70 | # Jupyter Notebook
71 | .ipynb_checkpoints
72 |
73 | # pyenv
74 | .python-version
75 |
76 | # celery beat schedule file
77 | celerybeat-schedule
78 |
79 | # SageMath parsed files
80 | *.sage.py
81 |
82 | # dotenv
83 | .env
84 |
85 | # virtualenv
86 | .venv
87 | venv/
88 | ENV/
89 |
90 | # Spyder project settings
91 | .spyderproject
92 | .spyproject
93 |
94 | # Rope project settings
95 | .ropeproject
96 |
97 | # mkdocs documentation
98 | /site
99 |
100 | # mypy
101 | .mypy_cache/
102 |
103 | # Deploy files
104 | deploy.sh
105 |
106 | # Node modules
107 | node_modules/
108 |
109 | # Visual Studio config files
110 | .vscode/
111 | *.h5
112 |
113 | # Cache data
114 | cache_data/
115 |
116 | # Compressed images
117 | *.tar.gz
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/Dockerfile:
--------------------------------------------------------------------------------
1 | #
2 | # Docker image for the Cryptonic application.
3 | # The image copies the complete application
4 | # directory and starts a Flask server.
5 | #
6 | FROM python:3.6
7 | ENV TZ=America/New_York
8 |
9 | #
10 | # Setting up timezone to EST (New York).
11 | # Change this to whichever timezone your
12 | # data is configured to use.
13 | #
14 | RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
15 |
16 |
17 | COPY . /cryptonic
18 |
19 | WORKDIR "/cryptonic"
20 | RUN pip install -r requirements.txt
21 |
22 | EXPOSE 5000
23 |
24 | CMD ["python", "run.py"]
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/Makefile:
--------------------------------------------------------------------------------
1 | # ------------------------------------------------- #
2 | # #
3 | # MAKEFILE #
4 | # -------- #
5 | # #
6 | # Makefile commands for Cryptonic: #
7 | # #
8 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
9 | # #
10 | # test: run tests via nosetest. #
11 | # #
12 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
13 | # #
14 | # build: builds all Docker images for #
15 | # Cryptonic. #
16 | # #
17 | # build-app-image: build Crytonic's #
18 | # API Docker image. #
19 | # #
20 | # build-cache-image: build Crytonic's #
21 | # cache Docker image. #
22 | # #
23 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
24 | # #
25 | # deploy: deploy combination of Docker #
26 | # containers locally. #
27 | # #
28 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
29 | # #
30 | # package: packages all components into #
31 | # a few Docker images ready for deployment. #
32 | # #
33 | # package-ui: packages the Cryptonic UI. #
34 | # #
35 | # ------------------------------------------------- #
36 | all: test package
37 |
38 | test:
39 | bash bin/test.sh;
40 |
41 | #
42 | # Build Docker images.
43 | #
44 | .PHONY: build
45 | build: build-cache-image build-app-image
46 |
47 | build-app-image:
48 | bash bin/build_docker_image.sh "latest";
49 |
50 | build-cache-image:
51 | bash cryptonic-cache/bin/build_docker_image.sh "latest";
52 |
53 | #
54 | # Packages all components of the
55 | # application for deployment.
56 | #
57 | package: package-ui build
58 | @echo "Packaging Docker images.";
59 | docker save -o cryptonic-latest.tar cryptonic:latest;
60 | docker save -o cryptonic-cache-latest.tar cryptonic-cache:latest;
61 |
62 | package-ui:
63 | cd cryptonic-ui && npm run build;
64 |
65 | #
66 | # Deploy Docker containers.
67 | #
68 | deploy:
69 | docker-compose up -d;
70 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/README.md:
--------------------------------------------------------------------------------
1 | # Cryptonic
2 | Cryptonic is a Dockerized web-application that predicts Bitcoin prices using a deep learning model. The model used to predict prices can be easily changed--given that certain parameters are passed--making it easy to experiment and deploy a working model.
3 |
4 | 
5 |
6 | The application was developed for educational purposes and is part of the book "Beginning Application Development with TensorFlow" by [Luis Capelo](https://luiscapelo.info/).
7 |
8 | ### Usage
9 | A demo of the application is available at
10 |
11 | * Demo: https://cryptonic.market/
12 |
13 | ### API
14 | The application has the following endpoints:
15 |
16 | * `/status`: returns the status of the application and its error rates.
17 | * `/historic`: returns available Bitcoin prices up to date.
18 | * `/predict`: predicts the next N days of Bitcoin closing prices.
19 |
20 | ### Requirements
21 | You will need:
22 |
23 | * Docker `17.09.1` or higher.
24 | * If using the `Makefile` commands, you will also need `make`.
25 |
26 | ### Deployment
27 | Deploy this application using the available `Makefile` recipes. Navigate to the application's root directory, then execute:
28 |
29 | ```shell
30 | $ make deploy
31 | ```
32 |
33 | Now visit http://localhost:5000 on your browser and the application should be available.
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/bin/build_docker_image.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Builds Docker image of the
4 | # `Cryptonic` program.
5 | #
6 | VERSION=$1
7 | docker build --tag cryptonic:$VERSION \
8 | --tag cryptonic:latest \
9 | .
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic-cache/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM redis:alpine
2 | ENV TZ=America/New_York
3 | # COPY redis.conf /usr/local/etc/redis/redis.conf
4 | # CMD [ "redis-server", "/usr/local/etc/redis/redis.conf" ]
5 |
6 | #
7 | # Setting up timezone to EST (New York).
8 | # Change this to whichever timezone your
9 | # data is configured to use.
10 | #
11 | RUN apk add -U tzdata \
12 | && cp /usr/share/zoneinfo/$TZ /etc/localtime
13 |
14 | EXPOSE 6379
15 |
16 | CMD [ "redis-server" ]
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic-cache/bin/build_docker_image.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Builds Docker image for the
4 | # backend Redis cache used by Cryptonic.
5 | #
6 | VERSION=$1
7 | docker build --tag cryptonic-cache:$VERSION \
8 | --tag cryptonic-cache:latest \
9 | ./cryptonic-cache/
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic-ui/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cryptonic",
3 | "description": "Cryptonic UI application.",
4 | "author": "luiscape@gmail.com",
5 | "private": true,
6 | "scripts": {
7 | "dev": "webpack-dev-server --inline --hot --env.dev",
8 | "build": "rimraf dist && webpack --progress --hide-modules"
9 | },
10 | "dependencies": {
11 | "babel-preset-es2015": "^6.24.1",
12 | "c3": "^0.4.18",
13 | "d3": "^4.10.0",
14 | "dsv-loader": "^2.0.0",
15 | "element-ui": "^1.4.2",
16 | "lodash": "^4.17.4",
17 | "moment-timezone": "^0.5.14",
18 | "vue": "^2.4.2",
19 | "vue-c3": "^1.1.1",
20 | "vue-instant": "^1.0.1",
21 | "vue-lodash": "^1.0.4",
22 | "vue-moment": "^3.1.0",
23 | "vue-resource": "^1.3.4",
24 | "vuetrend": "^0.2.3"
25 | },
26 | "engines": {
27 | "node": ">=6"
28 | },
29 | "devDependencies": {
30 | "autoprefixer": "^6.6.0",
31 | "babel-core": "^6.24.1",
32 | "babel-loader": "^6.4.0",
33 | "babel-preset-vue-app": "^1.2.0",
34 | "css-loader": "^0.27.0",
35 | "file-loader": "^0.10.1",
36 | "html-webpack-plugin": "^2.24.1",
37 | "postcss-loader": "^1.3.3",
38 | "rimraf": "^2.5.4",
39 | "style-loader": "^0.13.2",
40 | "url-loader": "^0.5.8",
41 | "vue-loader": "^13.0.4",
42 | "vue-template-compiler": "^2.4.2",
43 | "webpack": "^2.4.1",
44 | "webpack-dev-server": "^2.4.2"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic-ui/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [
3 | require('autoprefixer')()
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic-ui/src/assets/botstream.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter04/Activity4.01/cryptonic-ui/src/assets/botstream.png
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic-ui/src/assets/botstream_slack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter04/Activity4.01/cryptonic-ui/src/assets/botstream_slack.png
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic-ui/src/css/forbes_logo.css:
--------------------------------------------------------------------------------
1 | /*
2 | Icon Font: forbesicon
3 | */
4 |
5 | @font-face {
6 | font-family: "forbesicon";
7 | src: url("https://i.forbesimg.com/assets/fonts/fbs-typography/0223/forbesicon.eot");
8 | src: url("https://i.forbesimg.com/assets/fonts/fbs-typography/0223/forbesicon.eot?#iefix") format("embedded-opentype"),
9 | url("https://i.forbesimg.com/assets/fonts/fbs-typography/0223/forbesicon.woff") format("woff"),
10 | url("https://i.forbesimg.com/assets/fonts/fbs-typography/0223/forbesicon.ttf") format("truetype"),
11 | url("https://i.forbesimg.com/assets/fonts/fbs-typography/0223/forbesicon.svg#forbesicon") format("svg");
12 | font-weight: normal;
13 | font-style: normal;
14 | }
15 |
16 | @media screen and (-webkit-min-device-pixel-ratio:0) {
17 | @font-face {
18 | font-family: "forbesicon";
19 | src: url("https://i.forbesimg.com/assets/fonts/fbs-typography/0223/forbesicon.svg#forbesicon") format("svg");
20 | }
21 | }
22 |
23 | .icon {
24 | font-family: "forbesicon";
25 | speak: none;
26 | font-style: normal;
27 | font-weight: normal;
28 | font-variant: normal;
29 | text-transform: none;
30 | line-height: 1;
31 |
32 | /* Better Font Rendering =========== */
33 | -webkit-font-smoothing: antialiased;
34 | -moz-osx-font-smoothing: grayscale;
35 | }
36 |
37 | .icon-add-person:before { content: "\f168"; }
38 | .icon-amazon:before { content: "\f162"; }
39 | .icon-arrow-down:before { content: "\f100"; }
40 | .icon-arrow-down-bar:before { content: "\f149"; }
41 | .icon-arrow-up:before { content: "\f101"; }
42 | .icon-badge:before { content: "\f15f"; }
43 | .icon-baidu:before { content: "\f16a"; }
44 | .icon-book:before { content: "\f102"; }
45 | .icon-brandvoice-logo:before { content: "\f150"; }
46 | .icon-brandvoice-logo-brand:before { content: "\f151"; }
47 | .icon-brandvoice-logo-voice:before { content: "\f152"; }
48 | .icon-calendar:before { content: "\f143"; }
49 | .icon-cart:before { content: "\f15b"; }
50 | .icon-chat:before { content: "\f15c"; }
51 | .icon-check:before { content: "\f103"; }
52 | .icon-chevron-down:before { content: "\f135"; }
53 | .icon-chevron-left:before { content: "\f136"; }
54 | .icon-chevron-right:before { content: "\f137"; }
55 | .icon-chevron-up:before { content: "\f138"; }
56 | .icon-clipboard:before { content: "\f148"; }
57 | .icon-clock:before { content: "\f146"; }
58 | .icon-close:before { content: "\f104"; }
59 | .icon-cog:before { content: "\f134"; }
60 | .icon-comment-bubble:before { content: "\f105"; }
61 | .icon-copy:before { content: "\f153"; }
62 | .icon-desktop:before { content: "\f164"; }
63 | .icon-donald-trump:before { content: "\f163"; }
64 | .icon-download:before { content: "\f14a"; }
65 | .icon-edit:before { content: "\f141"; }
66 | .icon-email:before { content: "\f106"; }
67 | .icon-enlarge:before { content: "\f147"; }
68 | .icon-explore:before { content: "\f161"; }
69 | .icon-facebook:before { content: "\f139"; }
70 | .icon-flame:before { content: "\f15e"; }
71 | .icon-forbes-china-logo:before { content: "\f16b"; }
72 | .icon-forbes-life:before { content: "\f107"; }
73 | .icon-forbes-logo:before { content: "\f108"; }
74 | .icon-forbes-logo-f:before { content: "\f109"; }
75 | .icon-gallery:before { content: "\f140"; }
76 | .icon-georgia-daquo:before { content: "\f10a"; }
77 | .icon-georgia-uaquo:before { content: "\f10b"; }
78 | .icon-google:before { content: "\f13a"; }
79 | .icon-group:before { content: "\f10c"; }
80 | .icon-hamburger:before { content: "\f10d"; }
81 | .icon-handshake:before { content: "\f14b"; }
82 | .icon-home:before { content: "\f10e"; }
83 | .icon-insights:before { content: "\f165"; }
84 | .icon-instagram:before { content: "\f13b"; }
85 | .icon-link:before { content: "\f10f"; }
86 | .icon-linkedin:before { content: "\f13c"; }
87 | .icon-location:before { content: "\f156"; }
88 | .icon-lock:before { content: "\f154"; }
89 | .icon-megaphone:before { content: "\f14c"; }
90 | .icon-microphone:before { content: "\f14d"; }
91 | .icon-mobile:before { content: "\f166"; }
92 | .icon-pause:before { content: "\f15d"; }
93 | .icon-phone-call:before { content: "\f14e"; }
94 | .icon-photo:before { content: "\f167"; }
95 | .icon-pinterest:before { content: "\f13d"; }
96 | .icon-plus:before { content: "\f110"; }
97 | .icon-preview-eye:before { content: "\f145"; }
98 | .icon-print:before { content: "\f111"; }
99 | .icon-qzone:before { content: "\f16c"; }
100 | .icon-renren:before { content: "\f16d"; }
101 | .icon-reply:before { content: "\f112"; }
102 | .icon-reset:before { content: "\f113"; }
103 | .icon-rss-feed:before { content: "\f114"; }
104 | .icon-search:before { content: "\f115"; }
105 | .icon-share:before { content: "\f116"; }
106 | .icon-snapchat:before { content: "\f169"; }
107 | .icon-square-bracket-left:before { content: "\f11e"; }
108 | .icon-square-bracket-right:before { content: "\f11f"; }
109 | .icon-staff-verified:before { content: "\f158"; }
110 | .icon-star:before { content: "\f120"; }
111 | .icon-terms:before { content: "\f14f"; }
112 | .icon-trash:before { content: "\f142"; }
113 | .icon-tumblr:before { content: "\f13e"; }
114 | .icon-twitter:before { content: "\f13f"; }
115 | .icon-twitter-verified:before { content: "\f157"; }
116 | .icon-u30-logo:before { content: "\f155"; }
117 | .icon-under-30-logo:before { content: "\f159"; }
118 | .icon-user:before { content: "\f125"; }
119 | .icon-video:before { content: "\f126"; }
120 | .icon-wechat:before { content: "\f16e"; }
121 | .icon-weibo:before { content: "\f16f"; }
122 | .icon-womenforbes-logo:before { content: "\f160"; }
123 | .icon-youtube:before { content: "\f15a"; }
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic-ui/src/css/infinite.css:
--------------------------------------------------------------------------------
1 | /* Make the element pulse (grow large and small slowly) */
2 | /* Usage
3 | .myElement {
4 | animation: pulsate 1s ease-out;
5 | animation-iteration-count: infinite;
6 | opacity: 1;
7 | }
8 | */
9 | @-webkit-keyframes pulsate {
10 | 0% {-webkit-transform: scale(0.1, 0.1); opacity: 0.0;}
11 | 50% {opacity: 1.0;}
12 | 100% {-webkit-transform: scale(1.2, 1.2); opacity: 0.0;}
13 | }
14 |
15 | /* Make the element's opacity pulse*/
16 | /* Usage
17 | .myElement {
18 | animation: opacityPulse 1s ease-out;
19 | animation-iteration-count: infinite;
20 | opacity: 0;
21 | }
22 | */
23 | @-webkit-keyframes opacityPulse {
24 | 0% {opacity: 0.0;}
25 | 50% {opacity: 1.0;}
26 | 100% {opacity: 0.0;}
27 | }
28 |
29 | /* Make the element's background pulse. I call this alertPulse because it is red. You can call it something more generic. */
30 | /* Usage
31 | .myElement {
32 | animation: alertPulse 1s ease-out;
33 | animation-iteration-count: infinite;
34 | opacity: 1;
35 | }
36 | */
37 | @-webkit-keyframes alertPulse {
38 | 0% {background-color: #9A2727; opacity: 1;}
39 | 50% {opacity: red; opacity: 0.75; }
40 | 100% {opacity: #9A2727; opacity: 1;}
41 | }
42 |
43 |
44 | /* Make the element rotate infinitely. */
45 | /*
46 | Usage
47 | .myElement {
48 | animation: rotating 3s linear infinite;
49 | }
50 | */
51 | @keyframes rotating {
52 | from {
53 | -ms-transform: rotate(0deg);
54 | -moz-transform: rotate(0deg);
55 | -webkit-transform: rotate(0deg);
56 | -o-transform: rotate(0deg);
57 | transform: rotate(0deg);
58 | }
59 | to {
60 | -ms-transform: rotate(360deg);
61 | -moz-transform: rotate(360deg);
62 | -webkit-transform: rotate(360deg);
63 | -o-transform: rotate(360deg);
64 | transform: rotate(360deg);
65 | }
66 | }
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic-ui/src/css/loading_animation.css:
--------------------------------------------------------------------------------
1 | body {
2 | -webkit-perspective: 3000;
3 | perspective: 3000;
4 | }
5 |
6 | section {
7 | margin: 10% auto;
8 | padding: 0;
9 | width: 100%;
10 | max-width: 1000px; }
11 |
12 | section h2 {
13 | font: 100 2em 'Helvetica Neue', Helvetica, Arial, sans-serif;
14 | margin: 0 5%; }
15 |
16 |
17 | .loading {
18 | padding: 10% 0;
19 | text-align: center; }
20 |
21 | .loader-1 .loading-spinner {
22 | position: relative;
23 | width: 2em;
24 | height: 2em;
25 | display: inline-block;
26 | font-size: 2em; }
27 |
28 | .loader-1 .loading-spinner .loader {
29 | position: absolute;
30 | top: 0;
31 | right: 0;
32 | bottom: 0;
33 | left: 0;
34 | -webkit-animation: loader 4s infinite ease-in-out;
35 | -moz-animation: loader 4s infinite ease-in-out;
36 | -ms-animation: loader 4s infinite ease-in-out;
37 | -o-animation: loader 4s infinite ease-in-out;
38 | animation: loader 4s infinite ease-in-out;
39 | -moz-box-shadow: inset 0 0 0 .0666666667em #888;
40 | -webkit-box-shadow: inset 0 0 0 .0666666667em #888;
41 | box-shadow: inset 0 0 0 .0666666667em #888; }
42 |
43 | .loader-1 .loading-spinner .loader:after {
44 | content: ' ';
45 | display: inline-block;
46 | vertical-align: top;
47 | width: 100%;
48 | background: #888;
49 | opacity: .5;
50 | -webkit-animation: loader-inner 4s infinite ease-in-out;
51 | -moz-animation: loader-inner 4s infinite ease-in-out;
52 | -ms-animation: loader-inner 4s infinite ease-in-out;
53 | -o-animation: loader-inner 4s infinite ease-in-out;
54 | animation: loader-inner 4s infinite ease-in-out; }
55 |
56 | .loader-1 .loading-spinner .icon {
57 | position: absolute;
58 | top: 0;
59 | right: 0;
60 | bottom: 0;
61 | left: 0;
62 | line-height: 2em;
63 | text-align: center;
64 | color: #888;
65 | -webkit-animation: icon-anim 4s infinite ease-in-out;
66 | animation: icon-anim 4s infinite ease-in-out;
67 | }
68 |
69 | @-webkit-keyframes icon-anim {
70 | 0% {
71 | transform: scale(1); }
72 | 25% {
73 | transform: scale(1.25); }
74 | 50% {
75 | transform: scale(1); }
76 | 75% {
77 | transform: scale(1.25); }
78 | 100% {
79 | transform: scale(1); }
80 | }
81 | @-webkit-keyframes loader {
82 | 0% {
83 | transform: rotate(0deg) scale(1); }
84 | 25% {
85 | transform: rotate(180deg) scale(1.25); }
86 | 50% {
87 | transform: rotate(180deg) scale(1); }
88 | 75% {
89 | transform: rotate(360deg) scale(1.25); }
90 | 100% {
91 | transform: rotate(360deg) scale(1); } }
92 | @-moz-keyframes loader {
93 | 0% {
94 | transform: rotate(0deg) scale(1); }
95 | 25% {
96 | transform: rotate(180deg) scale(1.25); }
97 | 50% {
98 | transform: rotate(180deg) scale(1); }
99 | 75% {
100 | transform: rotate(360deg) scale(1.25); }
101 | 100% {
102 | transform: rotate(360deg) scale(1); } }
103 | @-ms-keyframes loader {
104 | 0% {
105 | transform: rotate(0deg) scale(1); }
106 | 25% {
107 | transform: rotate(180deg) scale(1.25); }
108 | 50% {
109 | transform: rotate(180deg) scale(1); }
110 | 75% {
111 | transform: rotate(360deg) scale(1.25); }
112 | 100% {
113 | transform: rotate(360deg) scale(1); } }
114 | @-o-keyframes loader {
115 | 0% {
116 | transform: rotate(0deg) scale(1); }
117 | 25% {
118 | transform: rotate(180deg) scale(1.25); }
119 | 50% {
120 | transform: rotate(180deg) scale(1); }
121 | 75% {
122 | transform: rotate(360deg) scale(1.25); }
123 | 100% {
124 | transform: rotate(360deg) scale(1); } }
125 | @keyframes loader {
126 | 0% {
127 | transform: rotate(0deg) scale(1); }
128 | 25% {
129 | transform: rotate(180deg) scale(1.25); }
130 | 50% {
131 | transform: rotate(180deg) scale(1); }
132 | 75% {
133 | transform: rotate(360deg) scale(1.25); }
134 | 100% {
135 | transform: rotate(360deg) scale(1); } }
136 |
137 |
138 | @-webkit-keyframes loader-inner {
139 | 0%, 25%, 100% {
140 | height: 0; }
141 | 50%, 75% {
142 | height: 100%; } }
143 | @-moz-keyframes loader-inner {
144 | 0%, 25%, 100% {
145 | height: 0; }
146 | 50%, 75% {
147 | height: 100%; } }
148 | @-ms-keyframes loader-inner {
149 | 0%, 25%, 100% {
150 | height: 0; }
151 | 50%, 75% {
152 | height: 100%; } }
153 | @-o-keyframes loader-inner {
154 | 0%, 25%, 100% {
155 | height: 0; }
156 | 50%, 75% {
157 | height: 100%; } }
158 | @keyframes loader-inner {
159 | 0%, 25%, 100% {
160 | height: 0; }
161 | 50%, 75% {
162 | height: 100%; } }
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic-ui/src/css/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: 'Space Mono', monospace;
3 | background-color: #fbfdff;
4 | font-size: 9px;
5 | }
6 | h1,h2,h3,h4,h5 {
7 | color: #34495e;
8 | }
9 | h1,h2,h3,h4,h5,p {
10 | text-align: left;
11 | }
12 | h1 {
13 | font-family: 'Space Mono', monospace;
14 | font-weight: 700;
15 | }
16 | h2 {
17 | font-family: 'Space Mono', monospace;
18 | font-weight: 100;
19 | font-size: 25px;
20 | }
21 | h3 {
22 | font-family: 'Space Mono', monospace;
23 | font-weight: 100;
24 | font-size: 16px;
25 | }
26 | h5 {
27 | font-weight: 100;
28 | font-size: 12px;
29 | }
30 |
31 | p {
32 | text-align: left;
33 | font-weight: 300;
34 | line-height: 1.7em;
35 | font-size: 12px;
36 | color: #000000;
37 | }
38 | img {
39 | max-width: 100%;
40 | display: block;
41 | }
42 | iframe {
43 | max-width: 100%;
44 | display: block;
45 | }
46 | svg:not(:root) {
47 | position: relative;
48 | overflow: visible;
49 | }
50 |
51 | .sidebar-top {
52 | padding-bottom: 50px;
53 | }
54 | .related {
55 | font-size: 11px !important;
56 | }
57 | .hide-overflow {
58 | overflow: hidden;
59 | }
60 | .line-divisor {
61 | padding: 20px 0pt;
62 | margin: 20px 0pt;
63 | border-bottom: 1px solid #DDDDDD;
64 | border-top: 1px solid #DDDDDD;
65 | }
66 |
67 | #graph {
68 | height: 800px;
69 | width: 100%;
70 | position: relative;
71 | overflow: visible;
72 | margin: 0px;
73 | }
74 |
75 | .logo-container {
76 | padding: 0px;
77 | }
78 | .logo {
79 | max-height: 35px;
80 | vertical-align: middle;
81 | padding: 0px;
82 | margin: 0px;
83 | }
84 | .article-card .title {
85 | font-family: 'Merriweather';
86 | font-weight: 500;
87 | font-size: 26px;
88 | }
89 | .article-card {
90 | font-family: 'Roboto Mono';
91 | font-weight: 100;
92 | font-size: 10px;
93 | }
94 | .total-scheduled-instances {
95 | font-family: 'Roboto Mono';
96 | font-weight: 300;
97 | font-size: 10px;
98 | padding-left: 10px;
99 | }
100 |
101 | /*
102 |
103 | Pulsing effect.
104 |
105 | */
106 | .alert_green {
107 | display: block;
108 | width: 10px;
109 | height: 10px;
110 | border-radius: 50%;
111 | background: #2ecc71;
112 | cursor: pointer;
113 | box-shadow: 0 0 0 rgba(209, 193, 139, 0.40);
114 | }
115 | .alert_yellow {
116 | display: block;
117 | width: 10px;
118 | height: 10px;
119 | border-radius: 50%;
120 | background: #f1c40f;
121 | cursor: pointer;
122 | box-shadow: 0 0 0 rgba(209, 193, 139, 0.40);
123 | }
124 | .alert_red {
125 | display: block;
126 | width: 10px;
127 | height: 10px;
128 | border-radius: 50%;
129 | background: #e74c3c;
130 | cursor: pointer;
131 | box-shadow: 0 0 0 rgba(209, 193, 139, 0.40);
132 | animation: pulse 1.5s infinite;
133 | }
134 | .alert_red:hover {
135 | animation: pulse 1.5s infinite;
136 | }
137 |
138 | @-webkit-keyframes pulse {
139 | 0% {
140 | -webkit-box-shadow: 0 0 0 0 rgba(182, 182, 182, 0.40);
141 | }
142 | 70% {
143 | -webkit-box-shadow: 0 0 0 20px rgba(182, 182, 182, 0);
144 | }
145 | 100% {
146 | -webkit-box-shadow: 0 0 0 0 rgba(182, 182, 182, 0);
147 | }
148 | }
149 | @keyframes pulse {
150 | 0% {
151 | -moz-box-shadow: 0 0 0 0 rgba(182, 182, 182, 0.40);
152 | box-shadow: 0 0 0 0 rgba(182, 182, 182, 0.40);
153 | }
154 | 70% {
155 | -moz-box-shadow: 0 0 0 20px rgba(182, 182, 182, 0);
156 | box-shadow: 0 0 0 20px rgba(182, 182, 182, 0);
157 | }
158 | 100% {
159 | -moz-box-shadow: 0 0 0 0 rgba(182, 182, 182, 0);
160 | box-shadow: 0 0 0 0 rgba(182, 182, 182, 0);
161 | }
162 | }
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic-ui/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Cryptonic
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic-ui/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import ElementUI from 'element-ui'
3 | import lodash from 'lodash'
4 | import c3 from 'c3'
5 | import Trend from 'vuetrend'
6 | import moment from 'moment-timezone'
7 |
8 | import 'c3/c3.min.css'
9 | import 'element-ui/lib/theme-default/index.css'
10 | import './css/style.css'
11 | import './css/forbes_logo.css'
12 | import './css/loading_animation.css'
13 | import './css/infinite.css'
14 | import App from './App.vue'
15 | import locale from 'element-ui/lib/locale/lang/en'
16 |
17 | import VueMoment from 'vue-moment'
18 | import VueResource from 'vue-resource'
19 | import VueLodash from 'vue-lodash'
20 |
21 |
22 | Vue.prototype.$c3 = c3
23 |
24 | Vue.use(VueLodash, lodash)
25 | Vue.use(ElementUI, { locale })
26 | Vue.use(VueResource)
27 | Vue.use(VueMoment, { moment })
28 | Vue.use(Trend)
29 | Vue.use(c3)
30 |
31 |
32 | new Vue({
33 | el: '#app',
34 | render: h => h(App)
35 | })
36 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic-ui/webpack.config.js:
--------------------------------------------------------------------------------
1 | const resolve = require('path').resolve
2 | const webpack = require('webpack')
3 | const HtmlWebpackPlugin = require('html-webpack-plugin')
4 | const url = require('url')
5 | const publicPath = ''
6 |
7 | module.exports = (options = {}) => ({
8 | entry: {
9 | vendor: './src/vendor',
10 | index: './src/main.js'
11 | },
12 | output: {
13 | path: resolve(__dirname, 'dist'),
14 | filename: options.dev ? '[name].js' : '[name].js?[chunkhash]',
15 | chunkFilename: '[id].js?[chunkhash]',
16 | publicPath: options.dev ? '/assets/' : publicPath
17 | },
18 | module: {
19 | rules: [{
20 | test: /\.vue$/,
21 | use: ['vue-loader']
22 | },
23 | {
24 | test: /\.js$/,
25 | use: ['babel-loader'],
26 | exclude: /node_modules/,
27 | include: [
28 | resolve(__dirname, 'src'),
29 | resolve(__dirname, 'test'),
30 | resolve(__dirname, 'node_modules/element-ui/packages')
31 | ]
32 | },
33 | {
34 | test: /\.css$/,
35 | use: ['style-loader', 'css-loader', 'postcss-loader']
36 | },
37 | {
38 | test: /\.(png|jpg|jpeg|gif|eot|ttf|woff|woff2|svg|svgz)(\?.+)?$/,
39 | use: [{
40 | loader: 'url-loader',
41 | options: {
42 | limit: 10000
43 | }
44 | }]
45 | }
46 | ]
47 | },
48 | plugins: [
49 | new webpack.optimize.CommonsChunkPlugin({
50 | names: ['vendor', 'manifest']
51 | }),
52 | new HtmlWebpackPlugin({
53 | template: 'src/index.html'
54 | })
55 | ],
56 | resolve: {
57 | alias: {
58 | '~': resolve(__dirname, 'src')
59 | }
60 | },
61 | devServer: {
62 | host: '127.0.0.1',
63 | port: 8010,
64 | proxy: {
65 | '/api/': {
66 | target: 'http://127.0.0.1:8080',
67 | changeOrigin: true,
68 | pathRewrite: {
69 | '^/api': ''
70 | }
71 | }
72 | },
73 | historyApiFallback: {
74 | index: url.parse(options.dev ? '/assets/' : publicPath).pathname
75 | }
76 | },
77 | devtool: options.dev ? '#eval-source-map' : '#source-map'
78 | })
79 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic.env:
--------------------------------------------------------------------------------
1 | REDIS_URL=redis://redis@cache:6379/0
2 | CRYPTONIC_VERSION=latest
3 | BITCOIN_START_DATE=2017-01-01
4 | EPOCHS=300
5 | PERIOD_SIZE=7
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Cryptonic is an educational application created for
3 | the purposes of learning how to use deep learning
4 | to predict Bitcoin prices.
5 | """
6 | from cryptonic.models.model import Model
7 | from cryptonic.markets.coinmarketcap import CoinMarketCap
8 |
9 | __version__ = 'v1.0.1'
10 | __author__ = 'Luis Capelo'
11 | __email__ = 'luiscape@gmail.com'
12 |
13 | __all__ = ['Model', 'CoinMarketCap']
14 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic/api/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | HTTP API interface for Cryptonic.
3 | """
4 |
5 | __version__ = 1
6 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic/api/routes.py:
--------------------------------------------------------------------------------
1 | """
2 | Creates all application routes.
3 | """
4 | import os
5 |
6 | from datetime import datetime, timedelta
7 | from flask_api import status as http_status
8 | from flask import jsonify, request, make_response, send_file, send_from_directory
9 |
10 | from cryptonic.api import __version__
11 |
12 |
13 | def __cache_identifier(*args, **kwargs):
14 | """
15 | Creates a cache identifier based on the complete
16 | URL provided in the request. Original solution:
17 |
18 | * https://stackoverflow.com/questions/9413566/\
19 | flask-cache-memoize-url-query-string-parameters-as-well
20 |
21 | """
22 | #
23 | # The following snippet will create a
24 | # cache key for the URL and all GET and POST
25 | # parameters.
26 | #
27 | key = request.url + \
28 | '='.join([k + '=' + v for k,v in request.args.items()]) + '&' + \
29 | '='.join([k + '=' + v for k,v in request.form.items()])
30 |
31 | return key
32 |
33 |
34 | def create_routes(app, cache, model):
35 | """
36 | Function that creates the application routes.
37 |
38 | Parameters
39 | ----------
40 | app: Flask object
41 | Initialized Flask object.
42 |
43 | cache: Flask-Caching instance
44 | Cache instance that can be used
45 | as a decorator.
46 |
47 | model: instantiated Model()
48 | Module() class instantiated as a model
49 | and trained.
50 |
51 | Returns
52 | -------
53 | app: Flask object
54 | Modified Flask app object.
55 | """
56 | #
57 | # Let's clear the cache at every
58 | # startup.
59 | #
60 | cache.clear()
61 |
62 | @cache.cached(timeout=60 * 5, key_prefix=__cache_identifier)
63 | @app.errorhandler(404)
64 | def page_not_found(e):
65 | return app.send_static_file('index.html'), 404
66 |
67 | @cache.cached(timeout=60 * 5, key_prefix=__cache_identifier)
68 | @app.route('/')
69 | def root():
70 | """
71 | Endpoint for serving the index page.
72 | """
73 | return app.send_static_file('index.html')
74 |
75 | @app.route('/')
76 | def send_static_files(path):
77 | return send_from_directory(
78 | os.getenv('UI_DIST_DIRECTORY', '../cryptonic-ui/dist/'), path)
79 |
80 | @app.route('/status')
81 | def status():
82 | """
83 | Endpoint for returning the application status.
84 | """
85 | r = {
86 | 'version': __version__,
87 | 'success': True,
88 | 'message': 'Predict Bitcoin prices with deep learning.',
89 | 'model': {
90 | 'name': os.getenv('MODEL_NAME'),
91 | 'last_trained': model.last_trained,
92 | 'error_rates': model.evaluate()
93 | }
94 | }
95 | return jsonify(r)
96 |
97 | @cache.cached(timeout=60 * 24, key_prefix=__cache_identifier)
98 | @app.route('/historic')
99 | def historic():
100 | """
101 | Returns a series of historic observations.
102 |
103 | Parameters
104 | ----------
105 | start: str, default six months ago
106 | Start date to filter the Bitcoin historic price
107 | data set.
108 |
109 | """
110 | six_months_ago = (
111 | datetime.now() - timedelta(days=30 * 6)).strftime('%Y-%m-%d')
112 | start = request.args.get('start', six_months_ago)
113 |
114 | historic_data = model.data.to_dict(orient='records')
115 | filtered_historic_data = list(filter(lambda x: x['date'] > six_months_ago, historic_data))
116 |
117 | r = {
118 | 'version': __version__,
119 | 'success': True,
120 | 'message': 'Historic Bitcoin prices from CoinMarketCap.',
121 | 'start_date': os.getenv('BITCOIN_START_DATE'),
122 | 'result': filtered_historic_data
123 | }
124 |
125 | return jsonify(r)
126 |
127 | @cache.cached(timeout=60 * 24, key_prefix=__cache_identifier)
128 | @app.route('/predict')
129 | def predict():
130 | """
131 | Endpoint for predicting bitcoin prices.
132 | """
133 | r = {
134 | 'version': __version__,
135 | 'success': True,
136 | 'message': 'Endpoint for making predictions.',
137 | 'period_length': os.getenv('PERIOD_SIZE', 7),
138 | 'result': model.predict(denormalized=True, return_dict=True)
139 | }
140 | return jsonify(r)
141 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic/markets/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Interface for manipulating data from different markets.
3 | """
4 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic/markets/coinmarketcap.py:
--------------------------------------------------------------------------------
1 | """
2 | Logic for collecting data directly from the
3 | CoinMarketCap API.
4 | """
5 | import requests
6 | import pandas as pd
7 |
8 | from datetime import datetime
9 | from bs4 import BeautifulSoup
10 |
11 |
12 | class CoinMarketCap:
13 | """
14 | Class interface to data from CoinMarketCap.
15 | Original data can be found at:
16 |
17 | https://coinmarketcap.com/
18 |
19 | """
20 | def __repr__(self):
21 | message = """
22 |
23 | Crypto-currency data comes from the website CoinMarketCap.
24 | CoinMarketCap is can be accessed at: https://coinmarketcap.com/
25 |
26 | The permission to use the data is available on their FAQ
27 |
28 | https://coinmarketcap.com/faq/
29 |
30 | and reads:
31 |
32 | "Q: Am I allowed to use content (screenshots, data, graphs, etc.)
33 | for one of my personal projects and/or commercial use?
34 |
35 | R: Absolutely! Feel free to use any content as you see fit.
36 | We kindly ask that you cite us as a source."
37 |
38 | """
39 | return message
40 |
41 | @classmethod
42 | def historic(cls, start='2013-04-28', stop=None, ticker='bitcoin', return_json=False):
43 | """
44 | Retrieves historic data within a time
45 | period.
46 |
47 | Parameters
48 | ----------
49 | start, stop: str
50 | Start and stop dates in ISO format (YYYY-MM-DD).
51 |
52 | ticker: str
53 | Name of ticker to be used (e.g. `bitcoin`).
54 |
55 | Returns
56 | -------
57 | Pandas dataframe with historical ticker data.
58 | """
59 | start = start.replace('-', '')
60 | if not stop:
61 | stop = datetime.now().strftime('%Y%m%d')
62 |
63 | url = 'https://coinmarketcap.com/currencies/{}/historical-data/?start={}&end={}'.format(ticker, start, stop)
64 | r = requests.get(url)
65 |
66 | soup = BeautifulSoup(r.content, 'lxml')
67 | table = soup.find_all('table')[0]
68 | df = pd.read_html(str(table))[0]
69 |
70 | #
71 | # Cleans variables from the original.
72 | #
73 | df['Date'] = df['Date'].apply(lambda x: datetime.strptime(x, '%b %d, %Y').strftime('%Y-%m-%d'))
74 | df['Volume'] = df['Volume'].apply(lambda x: None if x == '-' else x)
75 | df.columns = ['date', 'open', 'high', 'low', 'close', 'volume', 'market_cap']
76 |
77 | if return_json:
78 | df.to_json(orient='records')
79 |
80 | return df
81 |
82 | @classmethod
83 | def current(cls, ticker='bitcoin'):
84 | """
85 | Fetches current prices from CoinMarketCap.
86 |
87 | Returns
88 | -------
89 | Dictionary with a single record form the
90 | """
91 | url = 'https://api.coinmarketcap.com/v1/ticker/{}/'.format(ticker)
92 | r = requests.get(url)
93 |
94 | return r.json()
95 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic/models/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Cryptocurrency prediction models.
3 | """
4 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic/models/helper.py:
--------------------------------------------------------------------------------
1 | """
2 | Helper class and methods for making manipulating
3 | data for models.
4 | """
5 | import numpy as np
6 |
7 | import cryptonic.models.normalizations as normalizations
8 |
9 |
10 | class ModelHelper:
11 | """
12 | Class with utility functions that aid in
13 | the process of training LSTM models with Keras.
14 |
15 | """
16 | def __init__(self):
17 | pass
18 |
19 | def create_groups(self, data, start=0, group_size=7, normalize=True):
20 | """
21 | Creates distinct groups from a given continuous series.
22 |
23 | Parameters
24 | ----------
25 | data: np.array
26 | Series of continious observations.
27 |
28 | start: int
29 | Starting point for the series. This
30 | is used to prune earlier observations
31 | from the series in case the series is
32 | too long or too short.
33 |
34 | group_size: int, default 7
35 | Determines how large the groups are. That is,
36 | how many observations each group contains.
37 |
38 | normalize: bool
39 | If the method should normalize data or not.
40 | Normalization is done using
41 |
42 | normalizations.point_relative_normalization()
43 |
44 | Returns
45 | -------
46 | A Numpy array object.
47 | """
48 | samples = list()
49 | for i in range(0, len(data), group_size):
50 | sample = list(data[start + i:i + group_size])
51 | if len(sample) == group_size:
52 | if normalize:
53 | sample = normalizations.point_relative_normalization(sample)
54 |
55 | samples.append(np.array(sample).reshape(1, group_size).tolist())
56 |
57 | A = np.array(samples)
58 | return A.reshape(1, A.shape[0], group_size)
59 |
60 | def split_lstm_input(self, groups):
61 | """
62 | Splits groups in a format expected by
63 | the LSTM layer.
64 |
65 | Parameters
66 | ----------
67 | groups: np.array
68 | Numpy array with the organized sequences.
69 |
70 | Returns
71 | -------
72 | X, Y: np.array
73 | Numpy arrays with the shapes required by
74 | the LSTM layer. X with (1, a - 1, b)
75 | and Y with (1, b). Where a is the total
76 | number of groups in `group` and b the
77 | number of observations per group.
78 | """
79 | X = groups[0:,:-1].reshape(1, groups.shape[1] - 1, groups.shape[2])
80 | Y = groups[0:,-1:][0]
81 |
82 | return X, Y
83 |
84 | def normalize(self):
85 | """
86 | Normalizes a series using point-relative normalization.
87 |
88 | Parameters
89 | ----------
90 |
91 | Returns
92 | -------
93 | """
94 | normalizations.point_relative_normalization()
95 |
96 | def denormalize(self, series, last_value):
97 | """
98 | De-normalizes a series using the latest
99 | value available from data.
100 |
101 | Parameters
102 | ----------
103 | series: numpy array
104 | Series with normalized values.
105 |
106 | last_value: float
107 | Numerical value that represents the
108 | last value from the dataset.
109 |
110 | Returns
111 | -------
112 | """
113 | result = last_value * (series + 1)
114 | return result
115 |
116 | def mape(self, A, B):
117 | """
118 | Calcualtes the mean absolute persentage error
119 | from two series. Original solution from:
120 |
121 | https://stats.stackexchange.com/questions/58391/\
122 | mean-absolute-percentage-error-mape-in-scikit-learn
123 | """
124 | return np.mean(np.abs((A - B) / (1 - A))) * 100
125 |
126 | def rmse(self, A, B):
127 | """
128 | Calculates the root mean square error from
129 | two series. Original solution from:
130 |
131 | https://stackoverflow.com/questions/16774849\
132 | /mean-squared-error-in-numpy
133 | """
134 | return np.sqrt(np.square(np.subtract(A, B)).mean())
135 |
136 | def mse(self, A, B):
137 | """
138 | Calculates the mean square error from
139 | two series. Original solution from:
140 |
141 | https://stackoverflow.com/questions/16774849\
142 | /mean-squared-error-in-numpy
143 | """
144 | return np.square(np.subtract(A, B)).mean()
145 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic/models/normalizations.py:
--------------------------------------------------------------------------------
1 | """
2 | Series of normalization functions useful
3 | for normalizing time-series data.
4 | """
5 |
6 | def z_score(series):
7 | """
8 | Computes the normalized value using the Z-score
9 | technique. The Z-score is a technique used for
10 | normalizing Gaussian distributions representing
11 | each observation in relation to the distribution's
12 | mean and standard deviation. For precise definitions,
13 | see the Wikipedia article:
14 |
15 | https://en.wikipedia.org/wiki/Standard_score
16 |
17 | Parameters
18 | ----------
19 | serie: list
20 | List with sequential values to use.
21 |
22 | Returns
23 | -------
24 | result: list
25 | List with the normalized results.
26 | """
27 | result = (series - series.mean()) / series.std(ddof=0)
28 | return result
29 |
30 | def point_relative_normalization(series, reverse=False, last_value=None):
31 | """
32 | Computes the normalized value for the values of a
33 | given series by using the first element of the serie as p_0
34 | as a reference for each p_i.
35 |
36 | This technique comes from Siraj Raval's YouTube video
37 | "How to Predict Stock Prices Easily - Intro to Deep Learning #7",
38 | available at:
39 |
40 | https://www.youtube.com/watch?v=ftMq5ps503w
41 |
42 | Parameters
43 | ----------
44 | serie: list
45 | List with sequential values to use.
46 |
47 | reverse: bool, default True
48 | If the method should de-normalize data.
49 |
50 | last_value: int or float
51 | Used to de-normalize a dataset. Needs to
52 | be passed if `reverse` is True.
53 |
54 | Returns
55 | -------
56 | result: list
57 | List with the normalized results.
58 | """
59 | if reverse:
60 | result = last_value * (series + 1)
61 | else:
62 | result = (series / series[0]) - 1
63 |
64 | return result
65 |
66 | def maximum_and_minimum_normalization(series, boundary=(0, 1)):
67 | """
68 | Computes the normalized value for the values of a
69 | given serie by using that series maximum and minimum
70 | values.
71 |
72 | This technique is a direct implementation from
73 | scikit-learn, available at:
74 |
75 | http://scikit-learn.org/stable/modules/generated/\
76 | sklearn.preprocessing.MinMaxScaler.html
77 |
78 | Parameters
79 | ----------
80 | serie: list
81 | List with sequential values to use.
82 |
83 | boundary: set
84 | Maximum and minimum values used to
85 | scale the series.
86 |
87 | Returns
88 | -------
89 | result: list
90 | List with the normalized results.
91 | """
92 | range_min, range_max = boundary
93 | standard_deviation = (series - series.min(axis=0)) / (series.max(axis=0) - series.min(axis=0))
94 | result = standard_deviation * (range_max - range_min) + range_min
95 | return result
96 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic/server.py:
--------------------------------------------------------------------------------
1 | """
2 | Functions to start and configure the Flask
3 | application. This simply configures the server
4 | and its routes.
5 | """
6 | import os
7 | import flask
8 |
9 | from flask_caching import Cache
10 | from flask_cors import CORS, cross_origin
11 |
12 | from cryptonic import Model
13 | #from cryptonic import CoinMarketCap
14 | from cryptonic.api.routes import create_routes
15 | import yfinance as yf
16 |
17 | UI_DIST_DIRECTORY = os.getenv('UI_DIST_DIRECTORY', '../cryptonic-ui/dist/')
18 |
19 |
20 | class Server:
21 | """
22 | Cryptonic server representation. This class
23 | contains logic for managing the configuration
24 | and deployment of Flask server.
25 |
26 | Parameters
27 | ----------
28 | debug: bool, default False
29 | If should start with a debugger.
30 |
31 | cors: bool, default True
32 | If the application should accept CORS
33 | requests.
34 |
35 | """
36 | def __init__(self, debug=False, cors=True):
37 | self.debug = debug
38 | self.cors = cors
39 |
40 | self.create_model()
41 | self.app = self.create()
42 |
43 | def create_model(self):
44 | """
45 | Creates a model either using a model provided
46 | by user or by creating a new model using
47 | previously researched parameters.
48 |
49 | Returns
50 | -------
51 | Trained Keras model. Ready to be used
52 | via the model.predict() method.
53 | """
54 | ticker = yf.Ticker("BTC-USD")
55 | historic_data = ticker.history(period='max')
56 | historic_data = historic_data.rename(columns={'Open':'open', 'High':'high', 'Low':'low', 'Close':'close', 'Volume':'volume'})
57 | historic_data.index.names = ['date']
58 | historic_data = historic_data[['open','high', 'low', 'close', 'volume']]
59 | historic_data = historic_data.reset_index()
60 |
61 | model_path = os.getenv('MODEL_NAME')
62 |
63 | #
64 | # TODO: Figure out how large the data is for
65 | # the old model and re-train. Maybe what I have
66 | # to do here is to copy the weights of the
67 | # model into a new model.
68 | #
69 |
70 | self.model = Model(data=historic_data,
71 | path=model_path,
72 | variable='close',
73 | predicted_period_size=int(os.getenv('PERIOD_SIZE', 7)))
74 |
75 | if not model_path:
76 | self.model.build()
77 | self.model.train(epochs=int(os.getenv('EPOCHS', 50)), verbose=1)
78 |
79 | return self.model
80 |
81 | def create(self):
82 | """
83 | Method for creating a Flask server.
84 |
85 | Returns
86 | -------
87 | A Flask() application object.
88 | """
89 | app = flask.Flask(__name__, static_url_path='/', static_folder=UI_DIST_DIRECTORY)
90 |
91 | #
92 | # Application configuration. Here we
93 | # configure the application to accept
94 | # CORS requests, its routes, and
95 | # its debug flag.
96 | #
97 | if self.cors:
98 | CORS(app)
99 |
100 | cache_configuration = {
101 | 'CACHE_TYPE': 'redis',
102 | 'CACHE_REDIS_URL': os.getenv('REDIS_URL',
103 | "redis://localhost:6379/2")
104 | }
105 |
106 | self.cache = Cache(app, config=cache_configuration)
107 |
108 | app.config['DEBUG'] = self.debug
109 | create_routes(app, self.cache, self.model)
110 |
111 | return app
112 |
113 | def run(self, *args, **kwargs):
114 | """
115 | Method for running Flask server.
116 | Parameters
117 | ----------
118 | *args, **kwargs: parameters passed to the Flask application.
119 | """
120 | self.app.run(*args, **kwargs)
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic_old/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Cryptonic is an educational application created for
3 | the purposes of learning how to use deep learning
4 | to predict Bitcoin prices.
5 | """
6 | from cryptonic.models.model import Model
7 | from cryptonic.markets.coinmarketcap import CoinMarketCap
8 |
9 | __version__ = 'v1.0.1'
10 | __author__ = 'Luis Capelo'
11 | __email__ = 'luiscape@gmail.com'
12 |
13 | __all__ = ['Model', 'CoinMarketCap']
14 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic_old/api/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | HTTP API interface for Cryptonic.
3 | """
4 |
5 | __version__ = 1
6 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic_old/api/routes.py:
--------------------------------------------------------------------------------
1 | """
2 | Creates all application routes.
3 | """
4 | import os
5 |
6 | from datetime import datetime, timedelta
7 | from flask_api import status as http_status
8 | from flask import jsonify, request, make_response, send_file, send_from_directory
9 |
10 | from cryptonic.api import __version__
11 |
12 |
13 | def __cache_identifier(*args, **kwargs):
14 | """
15 | Creates a cache identifier based on the complete
16 | URL provided in the request. Original solution:
17 |
18 | * https://stackoverflow.com/questions/9413566/\
19 | flask-cache-memoize-url-query-string-parameters-as-well
20 |
21 | """
22 | #
23 | # The following snippet will create a
24 | # cache key for the URL and all GET and POST
25 | # parameters.
26 | #
27 | key = request.url + \
28 | '='.join([k + '=' + v for k,v in request.args.items()]) + '&' + \
29 | '='.join([k + '=' + v for k,v in request.form.items()])
30 |
31 | return key
32 |
33 |
34 | def create_routes(app, cache, model):
35 | """
36 | Function that creates the application routes.
37 |
38 | Parameters
39 | ----------
40 | app: Flask object
41 | Initialized Flask object.
42 |
43 | cache: Flask-Caching instance
44 | Cache instance that can be used
45 | as a decorator.
46 |
47 | model: instantiated Model()
48 | Module() class instantiated as a model
49 | and trained.
50 |
51 | Returns
52 | -------
53 | app: Flask object
54 | Modified Flask app object.
55 | """
56 | #
57 | # Let's clear the cache at every
58 | # startup.
59 | #
60 | cache.clear()
61 |
62 | @cache.cached(timeout=60 * 5, key_prefix=__cache_identifier)
63 | @app.errorhandler(404)
64 | def page_not_found(e):
65 | return app.send_static_file('index.html'), 404
66 |
67 | @cache.cached(timeout=60 * 5, key_prefix=__cache_identifier)
68 | @app.route('/')
69 | def root():
70 | """
71 | Endpoint for serving the index page.
72 | """
73 | return app.send_static_file('index.html')
74 |
75 | @app.route('/')
76 | def send_static_files(path):
77 | return send_from_directory(
78 | os.getenv('UI_DIST_DIRECTORY', '../cryptonic-ui/dist/'), path)
79 |
80 | @app.route('/status')
81 | def status():
82 | """
83 | Endpoint for returning the application status.
84 | """
85 | r = {
86 | 'version': __version__,
87 | 'success': True,
88 | 'message': 'Predict Bitcoin prices with deep learning.',
89 | 'model': {
90 | 'name': os.getenv('MODEL_NAME'),
91 | 'last_trained': model.last_trained,
92 | 'error_rates': model.evaluate()
93 | }
94 | }
95 | return jsonify(r)
96 |
97 | @cache.cached(timeout=60 * 24, key_prefix=__cache_identifier)
98 | @app.route('/historic')
99 | def historic():
100 | """
101 | Returns a series of historic observations.
102 |
103 | Parameters
104 | ----------
105 | start: str, default six months ago
106 | Start date to filter the Bitcoin historic price
107 | data set.
108 |
109 | """
110 | six_months_ago = (
111 | datetime.now() - timedelta(days=30 * 6)).strftime('%Y-%m-%d')
112 | start = request.args.get('start', six_months_ago)
113 |
114 | historic_data = model.data.to_dict(orient='records')
115 | filtered_historic_data = list(filter(lambda x: x['date'] > six_months_ago, historic_data))
116 |
117 | r = {
118 | 'version': __version__,
119 | 'success': True,
120 | 'message': 'Historic Bitcoin prices from CoinMarketCap.',
121 | 'start_date': os.getenv('BITCOIN_START_DATE'),
122 | 'result': filtered_historic_data
123 | }
124 |
125 | return jsonify(r)
126 |
127 | @cache.cached(timeout=60 * 24, key_prefix=__cache_identifier)
128 | @app.route('/predict')
129 | def predict():
130 | """
131 | Endpoint for predicting bitcoin prices.
132 | """
133 | r = {
134 | 'version': __version__,
135 | 'success': True,
136 | 'message': 'Endpoint for making predictions.',
137 | 'period_length': os.getenv('PERIOD_SIZE', 7),
138 | 'result': model.predict(denormalized=True, return_dict=True)
139 | }
140 | return jsonify(r)
141 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic_old/markets/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Interface for manipulating data from different markets.
3 | """
4 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic_old/markets/coinmarketcap.py:
--------------------------------------------------------------------------------
1 | """
2 | Logic for collecting data directly from the
3 | CoinMarketCap API.
4 | """
5 | import requests
6 | import pandas as pd
7 |
8 | from datetime import datetime
9 | from bs4 import BeautifulSoup
10 |
11 |
12 | class CoinMarketCap:
13 | """
14 | Class interface to data from CoinMarketCap.
15 | Original data can be found at:
16 |
17 | https://coinmarketcap.com/
18 |
19 | """
20 | def __repr__(self):
21 | message = """
22 |
23 | Crypto-currency data comes from the website CoinMarketCap.
24 | CoinMarketCap is can be accessed at: https://coinmarketcap.com/
25 |
26 | The permission to use the data is available on their FAQ
27 |
28 | https://coinmarketcap.com/faq/
29 |
30 | and reads:
31 |
32 | "Q: Am I allowed to use content (screenshots, data, graphs, etc.)
33 | for one of my personal projects and/or commercial use?
34 |
35 | R: Absolutely! Feel free to use any content as you see fit.
36 | We kindly ask that you cite us as a source."
37 |
38 | """
39 | return message
40 |
41 | @classmethod
42 | def historic(cls, start='2013-04-28', stop=None, ticker='bitcoin', return_json=False):
43 | """
44 | Retrieves historic data within a time
45 | period.
46 |
47 | Parameters
48 | ----------
49 | start, stop: str
50 | Start and stop dates in ISO format (YYYY-MM-DD).
51 |
52 | ticker: str
53 | Name of ticker to be used (e.g. `bitcoin`).
54 |
55 | Returns
56 | -------
57 | Pandas dataframe with historical ticker data.
58 | """
59 | start = start.replace('-', '')
60 | if not stop:
61 | stop = datetime.now().strftime('%Y%m%d')
62 |
63 | url = 'https://coinmarketcap.com/currencies/{}/historical-data/?start={}&end={}'.format(ticker, start, stop)
64 | r = requests.get(url)
65 |
66 | soup = BeautifulSoup(r.content, 'lxml')
67 | table = soup.find_all('table')[0]
68 | df = pd.read_html(str(table))[0]
69 |
70 | #
71 | # Cleans variables from the original.
72 | #
73 | df['Date'] = df['Date'].apply(lambda x: datetime.strptime(x, '%b %d, %Y').strftime('%Y-%m-%d'))
74 | df['Volume'] = df['Volume'].apply(lambda x: None if x == '-' else x)
75 | df.columns = ['date', 'open', 'high', 'low', 'close', 'volume', 'market_cap']
76 |
77 | if return_json:
78 | df.to_json(orient='records')
79 |
80 | return df
81 |
82 | @classmethod
83 | def current(cls, ticker='bitcoin'):
84 | """
85 | Fetches current prices from CoinMarketCap.
86 |
87 | Returns
88 | -------
89 | Dictionary with a single record form the
90 | """
91 | url = 'https://api.coinmarketcap.com/v1/ticker/{}/'.format(ticker)
92 | r = requests.get(url)
93 |
94 | return r.json()
95 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic_old/models/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Cryptocurrency prediction models.
3 | """
4 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic_old/models/helper.py:
--------------------------------------------------------------------------------
1 | """
2 | Helper class and methods for making manipulating
3 | data for models.
4 | """
5 | import numpy as np
6 |
7 | import cryptonic.models.normalizations as normalizations
8 |
9 |
10 | class ModelHelper:
11 | """
12 | Class with utility functions that aid in
13 | the process of training LSTM models with Keras.
14 |
15 | """
16 | def __init__(self):
17 | pass
18 |
19 | def create_groups(self, data, start=0, group_size=7, normalize=True):
20 | """
21 | Creates distinct groups from a given continuous series.
22 |
23 | Parameters
24 | ----------
25 | data: np.array
26 | Series of continious observations.
27 |
28 | start: int
29 | Starting point for the series. This
30 | is used to prune earlier observations
31 | from the series in case the series is
32 | too long or too short.
33 |
34 | group_size: int, default 7
35 | Determines how large the groups are. That is,
36 | how many observations each group contains.
37 |
38 | normalize: bool
39 | If the method should normalize data or not.
40 | Normalization is done using
41 |
42 | normalizations.point_relative_normalization()
43 |
44 | Returns
45 | -------
46 | A Numpy array object.
47 | """
48 | samples = list()
49 | for i in range(0, len(data), group_size):
50 | sample = list(data[start + i:i + group_size])
51 | if len(sample) == group_size:
52 | if normalize:
53 | sample = normalizations.point_relative_normalization(sample)
54 |
55 | samples.append(np.array(sample).reshape(1, group_size).tolist())
56 |
57 | A = np.array(samples)
58 | return A.reshape(1, A.shape[0], group_size)
59 |
60 | def split_lstm_input(self, groups):
61 | """
62 | Splits groups in a format expected by
63 | the LSTM layer.
64 |
65 | Parameters
66 | ----------
67 | groups: np.array
68 | Numpy array with the organized sequences.
69 |
70 | Returns
71 | -------
72 | X, Y: np.array
73 | Numpy arrays with the shapes required by
74 | the LSTM layer. X with (1, a - 1, b)
75 | and Y with (1, b). Where a is the total
76 | number of groups in `group` and b the
77 | number of observations per group.
78 | """
79 | X = groups[0:,:-1].reshape(1, groups.shape[1] - 1, groups.shape[2])
80 | Y = groups[0:,-1:][0]
81 |
82 | return X, Y
83 |
84 | def normalize(self):
85 | """
86 | Normalizes a series using point-relative normalization.
87 |
88 | Parameters
89 | ----------
90 |
91 | Returns
92 | -------
93 | """
94 | normalizations.point_relative_normalization()
95 |
96 | def denormalize(self, series, last_value):
97 | """
98 | De-normalizes a series using the latest
99 | value available from data.
100 |
101 | Parameters
102 | ----------
103 | series: numpy array
104 | Series with normalized values.
105 |
106 | last_value: float
107 | Numerical value that represents the
108 | last value from the dataset.
109 |
110 | Returns
111 | -------
112 | """
113 | result = last_value * (series + 1)
114 | return result
115 |
116 | def mape(self, A, B):
117 | """
118 | Calcualtes the mean absolute persentage error
119 | from two series. Original solution from:
120 |
121 | https://stats.stackexchange.com/questions/58391/\
122 | mean-absolute-percentage-error-mape-in-scikit-learn
123 | """
124 | return np.mean(np.abs((A - B) / (1 - A))) * 100
125 |
126 | def rmse(self, A, B):
127 | """
128 | Calculates the root mean square error from
129 | two series. Original solution from:
130 |
131 | https://stackoverflow.com/questions/16774849\
132 | /mean-squared-error-in-numpy
133 | """
134 | return np.sqrt(np.square(np.subtract(A, B)).mean())
135 |
136 | def mse(self, A, B):
137 | """
138 | Calculates the mean square error from
139 | two series. Original solution from:
140 |
141 | https://stackoverflow.com/questions/16774849\
142 | /mean-squared-error-in-numpy
143 | """
144 | return np.square(np.subtract(A, B)).mean()
145 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic_old/models/normalizations.py:
--------------------------------------------------------------------------------
1 | """
2 | Series of normalization functions useful
3 | for normalizing time-series data.
4 | """
5 |
6 | def z_score(series):
7 | """
8 | Computes the normalized value using the Z-score
9 | technique. The Z-score is a technique used for
10 | normalizing Gaussian distributions representing
11 | each observation in relation to the distribution's
12 | mean and standard deviation. For precise definitions,
13 | see the Wikipedia article:
14 |
15 | https://en.wikipedia.org/wiki/Standard_score
16 |
17 | Parameters
18 | ----------
19 | serie: list
20 | List with sequential values to use.
21 |
22 | Returns
23 | -------
24 | result: list
25 | List with the normalized results.
26 | """
27 | result = (series - series.mean()) / series.std(ddof=0)
28 | return result
29 |
30 | def point_relative_normalization(series, reverse=False, last_value=None):
31 | """
32 | Computes the normalized value for the values of a
33 | given series by using the first element of the serie as p_0
34 | as a reference for each p_i.
35 |
36 | This technique comes from Siraj Raval's YouTube video
37 | "How to Predict Stock Prices Easily - Intro to Deep Learning #7",
38 | available at:
39 |
40 | https://www.youtube.com/watch?v=ftMq5ps503w
41 |
42 | Parameters
43 | ----------
44 | serie: list
45 | List with sequential values to use.
46 |
47 | reverse: bool, default True
48 | If the method should de-normalize data.
49 |
50 | last_value: int or float
51 | Used to de-normalize a dataset. Needs to
52 | be passed if `reverse` is True.
53 |
54 | Returns
55 | -------
56 | result: list
57 | List with the normalized results.
58 | """
59 | if reverse:
60 | result = last_value * (series + 1)
61 | else:
62 | result = (series / series[0]) - 1
63 |
64 | return result
65 |
66 | def maximum_and_minimum_normalization(series, boundary=(0, 1)):
67 | """
68 | Computes the normalized value for the values of a
69 | given serie by using that series maximum and minimum
70 | values.
71 |
72 | This technique is a direct implementation from
73 | scikit-learn, available at:
74 |
75 | http://scikit-learn.org/stable/modules/generated/\
76 | sklearn.preprocessing.MinMaxScaler.html
77 |
78 | Parameters
79 | ----------
80 | serie: list
81 | List with sequential values to use.
82 |
83 | boundary: set
84 | Maximum and minimum values used to
85 | scale the series.
86 |
87 | Returns
88 | -------
89 | result: list
90 | List with the normalized results.
91 | """
92 | range_min, range_max = boundary
93 | standard_deviation = (series - series.min(axis=0)) / (series.max(axis=0) - series.min(axis=0))
94 | result = standard_deviation * (range_max - range_min) + range_min
95 | return result
96 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/cryptonic_old/server.py:
--------------------------------------------------------------------------------
1 | """
2 | Functions to start and configure the Flask
3 | application. This simply configures the server
4 | and its routes.
5 | """
6 | import os
7 | import flask
8 |
9 | from flask_caching import Cache
10 | from flask_cors import CORS, cross_origin
11 |
12 | from cryptonic import Model
13 | #from cryptonic import CoinMarketCap
14 | from cryptonic.api.routes import create_routes
15 | import yfinance as yf
16 |
17 | UI_DIST_DIRECTORY = os.getenv('UI_DIST_DIRECTORY', '../cryptonic-ui/dist/')
18 |
19 |
20 | class Server:
21 | """
22 | Cryptonic server representation. This class
23 | contains logic for managing the configuration
24 | and deployment of Flask server.
25 |
26 | Parameters
27 | ----------
28 | debug: bool, default False
29 | If should start with a debugger.
30 |
31 | cors: bool, default True
32 | If the application should accept CORS
33 | requests.
34 |
35 | """
36 | def __init__(self, debug=False, cors=True):
37 | self.debug = debug
38 | self.cors = cors
39 |
40 | self.create_model()
41 | self.app = self.create()
42 |
43 | def create_model(self):
44 | """
45 | Creates a model either using a model provided
46 | by user or by creating a new model using
47 | previously researched parameters.
48 |
49 | Returns
50 | -------
51 | Trained Keras model. Ready to be used
52 | via the model.predict() method.
53 | """
54 | ticker = yf.Ticker("BTC-USD")
55 | historic_data = ticker.history(period='max')
56 |
57 | model_path = os.getenv('MODEL_NAME')
58 |
59 | #
60 | # TODO: Figure out how large the data is for
61 | # the old model and re-train. Maybe what I have
62 | # to do here is to copy the weights of the
63 | # model into a new model.
64 | #
65 |
66 | self.model = Model(data=historic_data,
67 | path=model_path,
68 | variable='close',
69 | predicted_period_size=int(os.getenv('PERIOD_SIZE', 7)))
70 |
71 | if not model_path:
72 | self.model.build()
73 | self.model.train(epochs=int(os.getenv('EPOCHS', 300)), verbose=1)
74 |
75 | return self.model
76 |
77 | def create(self):
78 | """
79 | Method for creating a Flask server.
80 |
81 | Returns
82 | -------
83 | A Flask() application object.
84 | """
85 | app = flask.Flask(__name__, static_url_path='/', static_folder=UI_DIST_DIRECTORY)
86 |
87 | #
88 | # Application configuration. Here we
89 | # configure the application to accept
90 | # CORS requests, its routes, and
91 | # its debug flag.
92 | #
93 | if self.cors:
94 | CORS(app)
95 |
96 | cache_configuration = {
97 | 'CACHE_TYPE': 'redis',
98 | 'CACHE_REDIS_URL': os.getenv('REDIS_URL',
99 | 'redis://redis@cache:6379/0')
100 | }
101 |
102 | self.cache = Cache(app, config=cache_configuration)
103 |
104 | app.config['DEBUG'] = self.debug
105 | create_routes(app, self.cache, self.model)
106 |
107 | return app
108 |
109 | def run(self, *args, **kwargs):
110 | """
111 | Method for running Flask server.
112 | Parameters
113 | ----------
114 | *args, **kwargs: parameters passed to the Flask application.
115 | """
116 | self.app.run(*args, **kwargs)
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/docker-compose.yml:
--------------------------------------------------------------------------------
1 | #
2 | # CRYPTONIC DOCKER-COMPOSE
3 | # ------------------------
4 | #
5 | # Here we configure the application stack
6 | # that is deployed with Cryptonic. This
7 | # includes three elements:
8 | #
9 | # i. Cryptonic App: a Python web-application
10 | # that exposes the Cryptonic API via
11 | # the HTTP protocol.
12 | #
13 | # ii. Cryptonic Cache: a Redis instance that
14 | # works as a caching layer.
15 | #
16 | version: "3"
17 |
18 | services:
19 |
20 | cache:
21 | image: cryptonic-cache:latest
22 | build:
23 | context: ./cryptonic-cache
24 | dockerfile: ./Dockerfile
25 | volumes:
26 | - $PWD/cache_data:/data
27 | networks:
28 | - cryptonic
29 |
30 | cryptonic:
31 | image: cryptonic:latest
32 | build:
33 | context: .
34 | dockerfile: ./Dockerfile
35 | ports:
36 | - "5000:5000"
37 | environment:
38 | - BITCOIN_START_DATE=2019-01-01
39 | - EPOCHS=50
40 | - PERIOD_SIZE=7
41 | volumes:
42 | - ./cryptonic_logs:/logs
43 | - ./models:/models
44 | env_file:
45 | - cryptonic.env
46 | depends_on:
47 | - cache
48 | networks:
49 | - cryptonic
50 |
51 | networks:
52 | cryptonic:
53 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/requirements.txt:
--------------------------------------------------------------------------------
1 | beautifulsoup4==4.6.0
2 | bleach==1.5.0
3 | certifi==2017.11.5
4 | chardet==3.0.4
5 | click==6.7
6 | colorama==0.3.9
7 | coverage==4.4.2
8 | enum34==1.1.6
9 | Flask==0.12.2
10 | Flask-API==1.0
11 | Flask-Caching==1.3.3
12 | Flask-Cors==3.0.3
13 | Flask-Testing==0.7.1
14 | h5py==2.7.1
15 | html5lib==0.9999999
16 | idna==2.6
17 | itsdangerous==0.24
18 | Jinja2==2.10
19 | Keras==2.1.2
20 | lxml==4.1.1
21 | Markdown==2.6.10
22 | MarkupSafe==1.0
23 | nose==1.3.7
24 | numpy
25 | pandas==0.25.3
26 | protobuf
27 | python-dateutil==2.6.1
28 | pytz==2017.3
29 | PyYAML==3.12
30 | redis==2.10.6
31 | rednose==1.2.3
32 | requests
33 | scipy==1.0.0
34 | six==1.11.0
35 | tensorboard==2.0.1
36 | tensorflow==2.0.0
37 | tensorflow-estimator==2.0.1
38 | termstyle==0.1.11
39 | urllib3==1.22
40 | yfinance
41 | Werkzeug==0.13
42 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/run.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | """
3 | Script for starting the Cryptonic Flask server.
4 | """
5 | import os
6 | import time
7 |
8 | from cryptonic.server import Server
9 |
10 |
11 | def main():
12 | """
13 | Wrapper function for starting a server.
14 | """
15 |
16 | print('Starting server.')
17 | server = Server()
18 |
19 | server.run(host=os.getenv("HOST", "0.0.0.0"))
20 |
21 | if __name__ == '__main__':
22 | main()
23 |
--------------------------------------------------------------------------------
/Chapter04/Activity4.01/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter04/Activity4.01/screenshot.png
--------------------------------------------------------------------------------
/Chapter04/Exercise4.01/bitcoin_lstm_v0.h5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter04/Exercise4.01/bitcoin_lstm_v0.h5
--------------------------------------------------------------------------------
/Chapter04/Exercise4.01/bitcoin_model_prod_v0.h5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter04/Exercise4.01/bitcoin_model_prod_v0.h5
--------------------------------------------------------------------------------
/Chapter04/Exercise4.01/cryptonic/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Cryptonic is an educational application created for
3 | the purposes of learning how to use deep learning
4 | to predict Bitcoin prices.
5 | """
6 | from cryptonic.models.model import Model
7 | from cryptonic.markets.coinmarketcap import CoinMarketCap
8 |
9 | __version__ = 'v1.0.1'
10 | __author__ = 'Luis Capelo'
11 | __email__ = 'luiscape@gmail.com'
12 |
13 | __all__ = ['Model', 'CoinMarketCap']
14 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.01/cryptonic/__pycache__/__init__.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter04/Exercise4.01/cryptonic/__pycache__/__init__.cpython-36.pyc
--------------------------------------------------------------------------------
/Chapter04/Exercise4.01/cryptonic/api/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | HTTP API interface for Cryptonic.
3 | """
4 |
5 | __version__ = 1
6 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.01/cryptonic/api/routes.py:
--------------------------------------------------------------------------------
1 | """
2 | Creates all application routes.
3 | """
4 | import os
5 |
6 | from datetime import datetime, timedelta
7 | from flask_api import status as http_status
8 | from flask import jsonify, request, make_response, send_file, send_from_directory
9 |
10 | from cryptonic.api import __version__
11 |
12 |
13 | def __cache_identifier(*args, **kwargs):
14 | """
15 | Creates a cache identifier based on the complete
16 | URL provided in the request. Original solution:
17 |
18 | * https://stackoverflow.com/questions/9413566/\
19 | flask-cache-memoize-url-query-string-parameters-as-well
20 |
21 | """
22 | #
23 | # The following snippet will create a
24 | # cache key for the URL and all GET and POST
25 | # parameters.
26 | #
27 | key = request.url + \
28 | '='.join([k + '=' + v for k,v in request.args.items()]) + '&' + \
29 | '='.join([k + '=' + v for k,v in request.form.items()])
30 |
31 | return key
32 |
33 |
34 | def create_routes(app, cache, model):
35 | """
36 | Function that creates the application routes.
37 |
38 | Parameters
39 | ----------
40 | app: Flask object
41 | Initialized Flask object.
42 |
43 | cache: Flask-Caching instance
44 | Cache instance that can be used
45 | as a decorator.
46 |
47 | model: instantiated Model()
48 | Module() class instantiated as a model
49 | and trained.
50 |
51 | Returns
52 | -------
53 | app: Flask object
54 | Modified Flask app object.
55 | """
56 | #
57 | # Let's clear the cache at every
58 | # startup.
59 | #
60 | cache.clear()
61 |
62 | @cache.cached(timeout=60 * 5, key_prefix=__cache_identifier)
63 | @app.errorhandler(404)
64 | def page_not_found(e):
65 | return app.send_static_file('index.html'), 404
66 |
67 | @cache.cached(timeout=60 * 5, key_prefix=__cache_identifier)
68 | @app.route('/')
69 | def root():
70 | """
71 | Endpoint for serving the index page.
72 | """
73 | return app.send_static_file('index.html')
74 |
75 | @app.route('/')
76 | def send_static_files(path):
77 | return send_from_directory(
78 | os.getenv('UI_DIST_DIRECTORY', '../cryptonic-ui/dist/'), path)
79 |
80 | @app.route('/status')
81 | def status():
82 | """
83 | Endpoint for returning the application status.
84 | """
85 | r = {
86 | 'version': __version__,
87 | 'success': True,
88 | 'message': 'Predict Bitcoin prices with deep learning.',
89 | 'model': {
90 | 'name': os.getenv('MODEL_NAME'),
91 | 'last_trained': model.last_trained,
92 | 'error_rates': model.evaluate()
93 | }
94 | }
95 | return jsonify(r)
96 |
97 | @cache.cached(timeout=60 * 24, key_prefix=__cache_identifier)
98 | @app.route('/historic')
99 | def historic():
100 | """
101 | Returns a series of historic observations.
102 |
103 | Parameters
104 | ----------
105 | start: str, default six months ago
106 | Start date to filter the Bitcoin historic price
107 | data set.
108 |
109 | """
110 | six_months_ago = (
111 | datetime.now() - timedelta(days=30 * 6)).strftime('%Y-%m-%d')
112 | start = request.args.get('start', six_months_ago)
113 |
114 | historic_data = model.data.to_dict(orient='records')
115 | filtered_historic_data = list(filter(lambda x: x['date'] > six_months_ago, historic_data))
116 |
117 | r = {
118 | 'version': __version__,
119 | 'success': True,
120 | 'message': 'Historic Bitcoin prices from CoinMarketCap.',
121 | 'start_date': os.getenv('BITCOIN_START_DATE'),
122 | 'result': filtered_historic_data
123 | }
124 |
125 | return jsonify(r)
126 |
127 | @cache.cached(timeout=60 * 24, key_prefix=__cache_identifier)
128 | @app.route('/predict')
129 | def predict():
130 | """
131 | Endpoint for predicting bitcoin prices.
132 | """
133 | r = {
134 | 'version': __version__,
135 | 'success': True,
136 | 'message': 'Endpoint for making predictions.',
137 | 'period_length': os.getenv('PERIOD_SIZE', 7),
138 | 'result': model.predict(denormalized=True, return_dict=True)
139 | }
140 | return jsonify(r)
141 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.01/cryptonic/markets/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Interface for manipulating data from different markets.
3 | """
4 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.01/cryptonic/markets/__pycache__/__init__.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter04/Exercise4.01/cryptonic/markets/__pycache__/__init__.cpython-36.pyc
--------------------------------------------------------------------------------
/Chapter04/Exercise4.01/cryptonic/markets/__pycache__/coinmarketcap.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter04/Exercise4.01/cryptonic/markets/__pycache__/coinmarketcap.cpython-36.pyc
--------------------------------------------------------------------------------
/Chapter04/Exercise4.01/cryptonic/markets/coinmarketcap.py:
--------------------------------------------------------------------------------
1 | """
2 | Logic for collecting data directly from the
3 | CoinMarketCap API.
4 | """
5 | import requests
6 | import pandas as pd
7 |
8 | from datetime import datetime
9 | from bs4 import BeautifulSoup
10 |
11 |
12 | class CoinMarketCap:
13 | """
14 | Class interface to data from CoinMarketCap.
15 | Original data can be found at:
16 |
17 | https://coinmarketcap.com/
18 |
19 | """
20 | def __repr__(self):
21 | message = """
22 |
23 | Crypto-currency data comes from the website CoinMarketCap.
24 | CoinMarketCap is can be accessed at: https://coinmarketcap.com/
25 |
26 | The permission to use the data is available on their FAQ
27 |
28 | https://coinmarketcap.com/faq/
29 |
30 | and reads:
31 |
32 | "Q: Am I allowed to use content (screenshots, data, graphs, etc.)
33 | for one of my personal projects and/or commercial use?
34 |
35 | R: Absolutely! Feel free to use any content as you see fit.
36 | We kindly ask that you cite us as a source."
37 |
38 | """
39 | return message
40 |
41 | @classmethod
42 | def historic(cls, start='2013-04-28', stop=None, ticker='bitcoin', return_json=False):
43 | """
44 | Retrieves historic data within a time
45 | period.
46 |
47 | Parameters
48 | ----------
49 | start, stop: str
50 | Start and stop dates in ISO format (YYYY-MM-DD).
51 |
52 | ticker: str
53 | Name of ticker to be used (e.g. `bitcoin`).
54 |
55 | Returns
56 | -------
57 | Pandas dataframe with historical ticker data.
58 | """
59 | start = start.replace('-', '')
60 | if not stop:
61 | stop = datetime.now().strftime('%Y%m%d')
62 |
63 | url = 'https://coinmarketcap.com/currencies/{}/historical-data/?start={}&end={}'.format(ticker, start, stop)
64 | r = requests.get(url)
65 |
66 | soup = BeautifulSoup(r.content, 'lxml')
67 | table = soup.find_all('table')[0]
68 | df = pd.read_html(str(table))[0]
69 |
70 | #
71 | # Cleans variables from the original.
72 | #
73 | df['Date'] = df['Date'].apply(lambda x: datetime.strptime(x, '%b %d, %Y').strftime('%Y-%m-%d'))
74 | df['Volume'] = df['Volume'].apply(lambda x: None if x == '-' else x)
75 | df.columns = ['date', 'open', 'high', 'low', 'close', 'volume', 'market_cap']
76 |
77 | if return_json:
78 | df.to_json(orient='records')
79 |
80 | return df
81 |
82 | @classmethod
83 | def current(cls, ticker='bitcoin'):
84 | """
85 | Fetches current prices from CoinMarketCap.
86 |
87 | Returns
88 | -------
89 | Dictionary with a single record form the
90 | """
91 | url = 'https://api.coinmarketcap.com/v1/ticker/{}/'.format(ticker)
92 | r = requests.get(url)
93 |
94 | return r.json()
95 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.01/cryptonic/models/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Cryptocurrency prediction models.
3 | """
4 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.01/cryptonic/models/__pycache__/__init__.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter04/Exercise4.01/cryptonic/models/__pycache__/__init__.cpython-36.pyc
--------------------------------------------------------------------------------
/Chapter04/Exercise4.01/cryptonic/models/__pycache__/helper.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter04/Exercise4.01/cryptonic/models/__pycache__/helper.cpython-36.pyc
--------------------------------------------------------------------------------
/Chapter04/Exercise4.01/cryptonic/models/__pycache__/model.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter04/Exercise4.01/cryptonic/models/__pycache__/model.cpython-36.pyc
--------------------------------------------------------------------------------
/Chapter04/Exercise4.01/cryptonic/models/__pycache__/normalizations.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter04/Exercise4.01/cryptonic/models/__pycache__/normalizations.cpython-36.pyc
--------------------------------------------------------------------------------
/Chapter04/Exercise4.01/cryptonic/models/helper.py:
--------------------------------------------------------------------------------
1 | """
2 | Helper class and methods for making manipulating
3 | data for models.
4 | """
5 | import numpy as np
6 |
7 | import cryptonic.models.normalizations as normalizations
8 |
9 |
10 | class ModelHelper:
11 | """
12 | Class with utility functions that aid in
13 | the process of training LSTM models with Keras.
14 |
15 | """
16 | def __init__(self):
17 | pass
18 |
19 | def create_groups(self, data, start=0, group_size=7, normalize=True):
20 | """
21 | Creates distinct groups from a given continuous series.
22 |
23 | Parameters
24 | ----------
25 | data: np.array
26 | Series of continious observations.
27 |
28 | start: int
29 | Starting point for the series. This
30 | is used to prune earlier observations
31 | from the series in case the series is
32 | too long or too short.
33 |
34 | group_size: int, default 7
35 | Determines how large the groups are. That is,
36 | how many observations each group contains.
37 |
38 | normalize: bool
39 | If the method should normalize data or not.
40 | Normalization is done using
41 |
42 | normalizations.point_relative_normalization()
43 |
44 | Returns
45 | -------
46 | A Numpy array object.
47 | """
48 | samples = list()
49 | for i in range(0, len(data), group_size):
50 | sample = list(data[start + i:i + group_size])
51 | if len(sample) == group_size:
52 | if normalize:
53 | sample = normalizations.point_relative_normalization(sample)
54 |
55 | samples.append(np.array(sample).reshape(1, group_size).tolist())
56 |
57 | A = np.array(samples)
58 | return A.reshape(1, A.shape[0], group_size)
59 |
60 | def split_lstm_input(self, groups):
61 | """
62 | Splits groups in a format expected by
63 | the LSTM layer.
64 |
65 | Parameters
66 | ----------
67 | groups: np.array
68 | Numpy array with the organized sequences.
69 |
70 | Returns
71 | -------
72 | X, Y: np.array
73 | Numpy arrays with the shapes required by
74 | the LSTM layer. X with (1, a - 1, b)
75 | and Y with (1, b). Where a is the total
76 | number of groups in `group` and b the
77 | number of observations per group.
78 | """
79 | X = groups[0:,:-1].reshape(1, groups.shape[1] - 1, groups.shape[2])
80 | Y = groups[0:,-1:][0]
81 |
82 | return X, Y
83 |
84 | def normalize(self):
85 | """
86 | Normalizes a series using point-relative normalization.
87 |
88 | Parameters
89 | ----------
90 |
91 | Returns
92 | -------
93 | """
94 | normalizations.point_relative_normalization()
95 |
96 | def denormalize(self, series, last_value):
97 | """
98 | De-normalizes a series using the latest
99 | value available from data.
100 |
101 | Parameters
102 | ----------
103 | series: numpy array
104 | Series with normalized values.
105 |
106 | last_value: float
107 | Numerical value that represents the
108 | last value from the dataset.
109 |
110 | Returns
111 | -------
112 | """
113 | result = last_value * (series + 1)
114 | return result
115 |
116 | def mape(self, A, B):
117 | """
118 | Calcualtes the mean absolute persentage error
119 | from two series. Original solution from:
120 |
121 | https://stats.stackexchange.com/questions/58391/\
122 | mean-absolute-percentage-error-mape-in-scikit-learn
123 | """
124 | return np.mean(np.abs((A - B) / (1 - A))) * 100
125 |
126 | def rmse(self, A, B):
127 | """
128 | Calculates the root mean square error from
129 | two series. Original solution from:
130 |
131 | https://stackoverflow.com/questions/16774849\
132 | /mean-squared-error-in-numpy
133 | """
134 | return np.sqrt(np.square(np.subtract(A, B)).mean())
135 |
136 | def mse(self, A, B):
137 | """
138 | Calculates the mean square error from
139 | two series. Original solution from:
140 |
141 | https://stackoverflow.com/questions/16774849\
142 | /mean-squared-error-in-numpy
143 | """
144 | return np.square(np.subtract(A, B)).mean()
145 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.01/cryptonic/models/normalizations.py:
--------------------------------------------------------------------------------
1 | """
2 | Series of normalization functions useful
3 | for normalizing time-series data.
4 | """
5 |
6 | def z_score(series):
7 | """
8 | Computes the normalized value using the Z-score
9 | technique. The Z-score is a technique used for
10 | normalizing Gaussian distributions representing
11 | each observation in relation to the distribution's
12 | mean and standard deviation. For precise definitions,
13 | see the Wikipedia article:
14 |
15 | https://en.wikipedia.org/wiki/Standard_score
16 |
17 | Parameters
18 | ----------
19 | serie: list
20 | List with sequential values to use.
21 |
22 | Returns
23 | -------
24 | result: list
25 | List with the normalized results.
26 | """
27 | result = (series - series.mean()) / series.std(ddof=0)
28 | return result
29 |
30 | def point_relative_normalization(series, reverse=False, last_value=None):
31 | """
32 | Computes the normalized value for the values of a
33 | given series by using the first element of the serie as p_0
34 | as a reference for each p_i.
35 |
36 | This technique comes from Siraj Raval's YouTube video
37 | "How to Predict Stock Prices Easily - Intro to Deep Learning #7",
38 | available at:
39 |
40 | https://www.youtube.com/watch?v=ftMq5ps503w
41 |
42 | Parameters
43 | ----------
44 | serie: list
45 | List with sequential values to use.
46 |
47 | reverse: bool, default True
48 | If the method should de-normalize data.
49 |
50 | last_value: int or float
51 | Used to de-normalize a dataset. Needs to
52 | be passed if `reverse` is True.
53 |
54 | Returns
55 | -------
56 | result: list
57 | List with the normalized results.
58 | """
59 | if reverse:
60 | result = last_value * (series + 1)
61 | else:
62 | result = (series / series[0]) - 1
63 |
64 | return result
65 |
66 | def maximum_and_minimum_normalization(series, boundary=(0, 1)):
67 | """
68 | Computes the normalized value for the values of a
69 | given serie by using that series maximum and minimum
70 | values.
71 |
72 | This technique is a direct implementation from
73 | scikit-learn, available at:
74 |
75 | http://scikit-learn.org/stable/modules/generated/\
76 | sklearn.preprocessing.MinMaxScaler.html
77 |
78 | Parameters
79 | ----------
80 | serie: list
81 | List with sequential values to use.
82 |
83 | boundary: set
84 | Maximum and minimum values used to
85 | scale the series.
86 |
87 | Returns
88 | -------
89 | result: list
90 | List with the normalized results.
91 | """
92 | range_min, range_max = boundary
93 | standard_deviation = (series - series.min(axis=0)) / (series.max(axis=0) - series.min(axis=0))
94 | result = standard_deviation * (range_max - range_min) + range_min
95 | return result
96 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.01/cryptonic/server.py:
--------------------------------------------------------------------------------
1 | """
2 | Functions to start and configure the Flask
3 | application. This simply configures the server
4 | and its routes.
5 | """
6 | import os
7 | import flask
8 |
9 | from flask_caching import Cache
10 | from flask_cors import CORS, cross_origin
11 |
12 | from cryptonic import Model
13 | from cryptonic import CoinMarketCap
14 | from cryptonic.api.routes import create_routes
15 |
16 | UI_DIST_DIRECTORY = os.getenv('UI_DIST_DIRECTORY', '../cryptonic-ui/dist/')
17 |
18 |
19 | class Server:
20 | """
21 | Cryptonic server representation. This class
22 | contains logic for managing the configuration
23 | and deployment of Flask server.
24 |
25 | Parameters
26 | ----------
27 | debug: bool, default False
28 | If should start with a debugger.
29 |
30 | cors: bool, default True
31 | If the application should accept CORS
32 | requests.
33 |
34 | """
35 | def __init__(self, debug=False, cors=True):
36 | self.debug = debug
37 | self.cors = cors
38 |
39 | self.create_model()
40 | self.app = self.create()
41 |
42 | def create_model(self):
43 | """
44 | Creates a model either using a model provided
45 | by user or by creating a new model using
46 | previously researched parameters.
47 |
48 | Returns
49 | -------
50 | Trained Keras model. Ready to be used
51 | via the model.predict() method.
52 | """
53 | historic_data = CoinMarketCap.historic(start=os.getenv('BITCOIN_START_DATE', '2017-01-01'))
54 | model_path = os.getenv('MODEL_NAME')
55 |
56 | #
57 | # TODO: Figure out how large the data is for
58 | # the old model and re-train. Maybe what I have
59 | # to do here is to copy the weights of the
60 | # model into a new model.
61 | #
62 |
63 | self.model = Model(data=historic_data,
64 | path=model_path,
65 | variable='close',
66 | predicted_period_size=int(os.getenv('PERIOD_SIZE', 7)))
67 |
68 | if not model_path:
69 | self.model.build()
70 | self.model.train(epochs=int(os.getenv('EPOCHS', 300)), verbose=1)
71 |
72 | return self.model
73 |
74 | def create(self):
75 | """
76 | Method for creating a Flask server.
77 |
78 | Returns
79 | -------
80 | A Flask() application object.
81 | """
82 | app = flask.Flask(__name__, static_url_path='/', static_folder=UI_DIST_DIRECTORY)
83 |
84 | #
85 | # Application configuration. Here we
86 | # configure the application to accept
87 | # CORS requests, its routes, and
88 | # its debug flag.
89 | #
90 | if self.cors:
91 | CORS(app)
92 |
93 | cache_configuration = {
94 | 'CACHE_TYPE': 'redis',
95 | 'CACHE_REDIS_URL': os.getenv('REDIS_URL',
96 | 'redis://redis@cache:6379/0')
97 | }
98 |
99 | self.cache = Cache(app, config=cache_configuration)
100 |
101 | app.config['DEBUG'] = self.debug
102 | create_routes(app, self.cache, self.model)
103 |
104 | return app
105 |
106 | def run(self, *args, **kwargs):
107 | """
108 | Method for running Flask server.
109 | Parameters
110 | ----------
111 | *args, **kwargs: parameters passed to the Flask application.
112 | """
113 | self.app.run(*args, **kwargs)
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/.dockerignore:
--------------------------------------------------------------------------------
1 | # MacOS Files
2 | .DS_Store
3 |
4 | # Byte-compiled / optimized / DLL files
5 | __pycache__/
6 | *.py[cod]
7 | *$py.class
8 |
9 | # C extensions
10 | *.so
11 |
12 | # Node modules
13 | node_modules/
14 |
15 | # Distribution / packaging
16 | .Python
17 | env/
18 | build/
19 | develop-eggs/
20 | dist/
21 | downloads/
22 | eggs/
23 | .eggs/
24 | lib/
25 | lib64/
26 | parts/
27 | sdist/
28 | var/
29 | *.egg-info/
30 | .installed.cfg
31 | *.egg
32 |
33 | # PyInstaller
34 | # Usually these files are written by a python script from a template
35 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
36 | *.manifest
37 | *.spec
38 |
39 | # Installer logs
40 | pip-log.txt
41 | pip-delete-this-directory.txt
42 |
43 | # Unit test / coverage reports
44 | htmlcov/
45 | .tox/
46 | .coverage
47 | .coverage.*
48 | .cache
49 | nosetests.xml
50 | coverage.xml
51 | *,cover
52 | .hypothesis/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 |
62 | # Flask stuff:
63 | instance/
64 | .webassets-cache
65 |
66 | # Scrapy stuff:
67 | .scrapy
68 |
69 | # Sphinx documentation
70 | docs/_build/
71 |
72 | # PyBuilder
73 | target/
74 |
75 | # IPython Notebook
76 | .ipynb_checkpoints
77 |
78 | # pyenv
79 | .python-version
80 |
81 | # celery beat schedule file
82 | celerybeat-schedule
83 |
84 | # dotenv
85 | .env
86 |
87 | # virtualenv
88 | venv/
89 | ENV/
90 |
91 | # Spyder project settings
92 | .spyderproject
93 |
94 | # Rope project settings
95 | .ropeproject
96 |
97 | # Visual Studio Code configuration files
98 | .vscode/*
99 |
100 | # Testing artifacts
101 | .noseids
102 | coverage/
103 |
104 | # Ignore other applications
105 | cryptonic-cache/
106 |
107 | # Ignoring cache and database data
108 | data/
109 | logs/
110 |
111 | # Ignore tests folder
112 | tests/
113 |
114 | # Packaged files
115 | *.tar.gz
116 |
117 | # Deploy files
118 | deploy.sh
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | env/
12 | build/
13 | develop-eggs/
14 | dist/
15 | downloads/
16 | eggs/
17 | .eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 |
49 | # Translations
50 | *.mo
51 | *.pot
52 |
53 | # Django stuff:
54 | *.log
55 | local_settings.py
56 |
57 | # Flask stuff:
58 | instance/
59 | .webassets-cache
60 |
61 | # Scrapy stuff:
62 | .scrapy
63 |
64 | # Sphinx documentation
65 | docs/_build/
66 |
67 | # PyBuilder
68 | target/
69 |
70 | # Jupyter Notebook
71 | .ipynb_checkpoints
72 |
73 | # pyenv
74 | .python-version
75 |
76 | # celery beat schedule file
77 | celerybeat-schedule
78 |
79 | # SageMath parsed files
80 | *.sage.py
81 |
82 | # dotenv
83 | .env
84 |
85 | # virtualenv
86 | .venv
87 | venv/
88 | ENV/
89 |
90 | # Spyder project settings
91 | .spyderproject
92 | .spyproject
93 |
94 | # Rope project settings
95 | .ropeproject
96 |
97 | # mkdocs documentation
98 | /site
99 |
100 | # mypy
101 | .mypy_cache/
102 |
103 | # Deploy files
104 | deploy.sh
105 |
106 | # Node modules
107 | node_modules/
108 |
109 | # Visual Studio config files
110 | .vscode/
111 | *.h5
112 |
113 | # Cache data
114 | cache_data/
115 |
116 | # Compressed images
117 | *.tar.gz
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/Dockerfile:
--------------------------------------------------------------------------------
1 | #
2 | # Docker image for the Cryptonic application.
3 | # The image copies the complete application
4 | # directory and starts a Flask server.
5 | #
6 | FROM python:3.6
7 | ENV TZ=America/New_York
8 |
9 | #
10 | # Setting up timezone to EST (New York).
11 | # Change this to whichever timezone your
12 | # data is configured to use.
13 | #
14 | RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
15 |
16 |
17 | COPY . /cryptonic
18 |
19 | WORKDIR "/cryptonic"
20 | RUN pip install -r requirements.txt
21 |
22 | EXPOSE 5000
23 |
24 | CMD ["python", "run.py"]
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/Makefile:
--------------------------------------------------------------------------------
1 | # ------------------------------------------------- #
2 | # #
3 | # MAKEFILE #
4 | # -------- #
5 | # #
6 | # Makefile commands for Cryptonic: #
7 | # #
8 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
9 | # #
10 | # test: run tests via nosetest. #
11 | # #
12 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
13 | # #
14 | # build: builds all Docker images for #
15 | # Cryptonic. #
16 | # #
17 | # build-app-image: build Crytonic's #
18 | # API Docker image. #
19 | # #
20 | # build-cache-image: build Crytonic's #
21 | # cache Docker image. #
22 | # #
23 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
24 | # #
25 | # deploy: deploy combination of Docker #
26 | # containers locally. #
27 | # #
28 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
29 | # #
30 | # package: packages all components into #
31 | # a few Docker images ready for deployment. #
32 | # #
33 | # package-ui: packages the Cryptonic UI. #
34 | # #
35 | # ------------------------------------------------- #
36 | all: test package
37 |
38 | test:
39 | bash bin/test.sh;
40 |
41 | #
42 | # Build Docker images.
43 | #
44 | .PHONY: build
45 | build: build-cache-image build-app-image
46 |
47 | build-app-image:
48 | bash bin/build_docker_image.sh "latest";
49 |
50 | build-cache-image:
51 | bash cryptonic-cache/bin/build_docker_image.sh "latest";
52 |
53 | #
54 | # Packages all components of the
55 | # application for deployment.
56 | #
57 | package: package-ui build
58 | @echo "Packaging Docker images.";
59 | docker save -o cryptonic-latest.tar cryptonic:latest;
60 | docker save -o cryptonic-cache-latest.tar cryptonic-cache:latest;
61 |
62 | package-ui:
63 | cd cryptonic-ui && npm run build;
64 |
65 | #
66 | # Deploy Docker containers.
67 | #
68 | deploy:
69 | docker-compose up -d;
70 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/README.md:
--------------------------------------------------------------------------------
1 | # Cryptonic
2 | Cryptonic is a Dockerized web-application that predicts Bitcoin prices using a deep learning model. The model used to predict prices can be easily changed--given that certain parameters are passed--making it easy to experiment and deploy a working model.
3 |
4 | 
5 |
6 | The application was developed for educational purposes and is part of the book "Beginning Application Development with TensorFlow" by [Luis Capelo](https://luiscapelo.info/).
7 |
8 | ### Usage
9 | A demo of the application is available at
10 |
11 | * Demo: https://cryptonic.market/
12 |
13 | ### API
14 | The application has the following endpoints:
15 |
16 | * `/status`: returns the status of the application and its error rates.
17 | * `/historic`: returns available Bitcoin prices up to date.
18 | * `/predict`: predicts the next N days of Bitcoin closing prices.
19 |
20 | ### Requirements
21 | You will need:
22 |
23 | * Docker `17.09.1` or higher.
24 | * If using the `Makefile` commands, you will also need `make`.
25 |
26 | ### Deployment
27 | Deploy this application using the available `Makefile` recipes. Navigate to the application's root directory, then execute:
28 |
29 | ```shell
30 | $ make deploy
31 | ```
32 |
33 | Now visit http://localhost:5000 on your browser and the application should be available.
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/bin/build_docker_image.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Builds Docker image of the
4 | # `Cryptonic` program.
5 | #
6 | VERSION=$1
7 | docker build --tag cryptonic:$VERSION \
8 | --tag cryptonic:latest \
9 | .
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic-cache/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM redis:alpine
2 | ENV TZ=America/New_York
3 | # COPY redis.conf /usr/local/etc/redis/redis.conf
4 | # CMD [ "redis-server", "/usr/local/etc/redis/redis.conf" ]
5 |
6 | #
7 | # Setting up timezone to EST (New York).
8 | # Change this to whichever timezone your
9 | # data is configured to use.
10 | #
11 | RUN apk add -U tzdata \
12 | && cp /usr/share/zoneinfo/$TZ /etc/localtime
13 |
14 | EXPOSE 6379
15 |
16 | CMD [ "redis-server" ]
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic-cache/bin/build_docker_image.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Builds Docker image for the
4 | # backend Redis cache used by Cryptonic.
5 | #
6 | VERSION=$1
7 | docker build --tag cryptonic-cache:$VERSION \
8 | --tag cryptonic-cache:latest \
9 | ./cryptonic-cache/
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic-ui/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cryptonic",
3 | "description": "Cryptonic UI application.",
4 | "author": "luiscape@gmail.com",
5 | "private": true,
6 | "scripts": {
7 | "dev": "webpack-dev-server --inline --hot --env.dev",
8 | "build": "rimraf dist && webpack --progress --hide-modules"
9 | },
10 | "dependencies": {
11 | "babel-preset-es2015": "^6.24.1",
12 | "c3": "^0.4.18",
13 | "d3": "^4.10.0",
14 | "dsv-loader": "^2.0.0",
15 | "element-ui": "^1.4.2",
16 | "lodash": "^4.17.4",
17 | "moment-timezone": "^0.5.14",
18 | "vue": "^2.4.2",
19 | "vue-c3": "^1.1.1",
20 | "vue-instant": "^1.0.1",
21 | "vue-lodash": "^1.0.4",
22 | "vue-moment": "^3.1.0",
23 | "vue-resource": "^1.3.4",
24 | "vuetrend": "^0.2.3"
25 | },
26 | "engines": {
27 | "node": ">=6"
28 | },
29 | "devDependencies": {
30 | "autoprefixer": "^6.6.0",
31 | "babel-core": "^6.24.1",
32 | "babel-loader": "^6.4.0",
33 | "babel-preset-vue-app": "^1.2.0",
34 | "css-loader": "^0.27.0",
35 | "file-loader": "^0.10.1",
36 | "html-webpack-plugin": "^2.24.1",
37 | "postcss-loader": "^1.3.3",
38 | "rimraf": "^2.5.4",
39 | "style-loader": "^0.13.2",
40 | "url-loader": "^0.5.8",
41 | "vue-loader": "^13.0.4",
42 | "vue-template-compiler": "^2.4.2",
43 | "webpack": "^2.4.1",
44 | "webpack-dev-server": "^2.4.2"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic-ui/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [
3 | require('autoprefixer')()
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic-ui/src/assets/botstream.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter04/Exercise4.02/cryptonic-ui/src/assets/botstream.png
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic-ui/src/assets/botstream_slack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter04/Exercise4.02/cryptonic-ui/src/assets/botstream_slack.png
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic-ui/src/css/infinite.css:
--------------------------------------------------------------------------------
1 | /* Make the element pulse (grow large and small slowly) */
2 | /* Usage
3 | .myElement {
4 | animation: pulsate 1s ease-out;
5 | animation-iteration-count: infinite;
6 | opacity: 1;
7 | }
8 | */
9 | @-webkit-keyframes pulsate {
10 | 0% {-webkit-transform: scale(0.1, 0.1); opacity: 0.0;}
11 | 50% {opacity: 1.0;}
12 | 100% {-webkit-transform: scale(1.2, 1.2); opacity: 0.0;}
13 | }
14 |
15 | /* Make the element's opacity pulse*/
16 | /* Usage
17 | .myElement {
18 | animation: opacityPulse 1s ease-out;
19 | animation-iteration-count: infinite;
20 | opacity: 0;
21 | }
22 | */
23 | @-webkit-keyframes opacityPulse {
24 | 0% {opacity: 0.0;}
25 | 50% {opacity: 1.0;}
26 | 100% {opacity: 0.0;}
27 | }
28 |
29 | /* Make the element's background pulse. I call this alertPulse because it is red. You can call it something more generic. */
30 | /* Usage
31 | .myElement {
32 | animation: alertPulse 1s ease-out;
33 | animation-iteration-count: infinite;
34 | opacity: 1;
35 | }
36 | */
37 | @-webkit-keyframes alertPulse {
38 | 0% {background-color: #9A2727; opacity: 1;}
39 | 50% {opacity: red; opacity: 0.75; }
40 | 100% {opacity: #9A2727; opacity: 1;}
41 | }
42 |
43 |
44 | /* Make the element rotate infinitely. */
45 | /*
46 | Usage
47 | .myElement {
48 | animation: rotating 3s linear infinite;
49 | }
50 | */
51 | @keyframes rotating {
52 | from {
53 | -ms-transform: rotate(0deg);
54 | -moz-transform: rotate(0deg);
55 | -webkit-transform: rotate(0deg);
56 | -o-transform: rotate(0deg);
57 | transform: rotate(0deg);
58 | }
59 | to {
60 | -ms-transform: rotate(360deg);
61 | -moz-transform: rotate(360deg);
62 | -webkit-transform: rotate(360deg);
63 | -o-transform: rotate(360deg);
64 | transform: rotate(360deg);
65 | }
66 | }
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic-ui/src/css/loading_animation.css:
--------------------------------------------------------------------------------
1 | body {
2 | -webkit-perspective: 3000;
3 | perspective: 3000;
4 | }
5 |
6 | section {
7 | margin: 10% auto;
8 | padding: 0;
9 | width: 100%;
10 | max-width: 1000px; }
11 |
12 | section h2 {
13 | font: 100 2em 'Helvetica Neue', Helvetica, Arial, sans-serif;
14 | margin: 0 5%; }
15 |
16 |
17 | .loading {
18 | padding: 10% 0;
19 | text-align: center; }
20 |
21 | .loader-1 .loading-spinner {
22 | position: relative;
23 | width: 2em;
24 | height: 2em;
25 | display: inline-block;
26 | font-size: 2em; }
27 |
28 | .loader-1 .loading-spinner .loader {
29 | position: absolute;
30 | top: 0;
31 | right: 0;
32 | bottom: 0;
33 | left: 0;
34 | -webkit-animation: loader 4s infinite ease-in-out;
35 | -moz-animation: loader 4s infinite ease-in-out;
36 | -ms-animation: loader 4s infinite ease-in-out;
37 | -o-animation: loader 4s infinite ease-in-out;
38 | animation: loader 4s infinite ease-in-out;
39 | -moz-box-shadow: inset 0 0 0 .0666666667em #888;
40 | -webkit-box-shadow: inset 0 0 0 .0666666667em #888;
41 | box-shadow: inset 0 0 0 .0666666667em #888; }
42 |
43 | .loader-1 .loading-spinner .loader:after {
44 | content: ' ';
45 | display: inline-block;
46 | vertical-align: top;
47 | width: 100%;
48 | background: #888;
49 | opacity: .5;
50 | -webkit-animation: loader-inner 4s infinite ease-in-out;
51 | -moz-animation: loader-inner 4s infinite ease-in-out;
52 | -ms-animation: loader-inner 4s infinite ease-in-out;
53 | -o-animation: loader-inner 4s infinite ease-in-out;
54 | animation: loader-inner 4s infinite ease-in-out; }
55 |
56 | .loader-1 .loading-spinner .icon {
57 | position: absolute;
58 | top: 0;
59 | right: 0;
60 | bottom: 0;
61 | left: 0;
62 | line-height: 2em;
63 | text-align: center;
64 | color: #888;
65 | -webkit-animation: icon-anim 4s infinite ease-in-out;
66 | animation: icon-anim 4s infinite ease-in-out;
67 | }
68 |
69 | @-webkit-keyframes icon-anim {
70 | 0% {
71 | transform: scale(1); }
72 | 25% {
73 | transform: scale(1.25); }
74 | 50% {
75 | transform: scale(1); }
76 | 75% {
77 | transform: scale(1.25); }
78 | 100% {
79 | transform: scale(1); }
80 | }
81 | @-webkit-keyframes loader {
82 | 0% {
83 | transform: rotate(0deg) scale(1); }
84 | 25% {
85 | transform: rotate(180deg) scale(1.25); }
86 | 50% {
87 | transform: rotate(180deg) scale(1); }
88 | 75% {
89 | transform: rotate(360deg) scale(1.25); }
90 | 100% {
91 | transform: rotate(360deg) scale(1); } }
92 | @-moz-keyframes loader {
93 | 0% {
94 | transform: rotate(0deg) scale(1); }
95 | 25% {
96 | transform: rotate(180deg) scale(1.25); }
97 | 50% {
98 | transform: rotate(180deg) scale(1); }
99 | 75% {
100 | transform: rotate(360deg) scale(1.25); }
101 | 100% {
102 | transform: rotate(360deg) scale(1); } }
103 | @-ms-keyframes loader {
104 | 0% {
105 | transform: rotate(0deg) scale(1); }
106 | 25% {
107 | transform: rotate(180deg) scale(1.25); }
108 | 50% {
109 | transform: rotate(180deg) scale(1); }
110 | 75% {
111 | transform: rotate(360deg) scale(1.25); }
112 | 100% {
113 | transform: rotate(360deg) scale(1); } }
114 | @-o-keyframes loader {
115 | 0% {
116 | transform: rotate(0deg) scale(1); }
117 | 25% {
118 | transform: rotate(180deg) scale(1.25); }
119 | 50% {
120 | transform: rotate(180deg) scale(1); }
121 | 75% {
122 | transform: rotate(360deg) scale(1.25); }
123 | 100% {
124 | transform: rotate(360deg) scale(1); } }
125 | @keyframes loader {
126 | 0% {
127 | transform: rotate(0deg) scale(1); }
128 | 25% {
129 | transform: rotate(180deg) scale(1.25); }
130 | 50% {
131 | transform: rotate(180deg) scale(1); }
132 | 75% {
133 | transform: rotate(360deg) scale(1.25); }
134 | 100% {
135 | transform: rotate(360deg) scale(1); } }
136 |
137 |
138 | @-webkit-keyframes loader-inner {
139 | 0%, 25%, 100% {
140 | height: 0; }
141 | 50%, 75% {
142 | height: 100%; } }
143 | @-moz-keyframes loader-inner {
144 | 0%, 25%, 100% {
145 | height: 0; }
146 | 50%, 75% {
147 | height: 100%; } }
148 | @-ms-keyframes loader-inner {
149 | 0%, 25%, 100% {
150 | height: 0; }
151 | 50%, 75% {
152 | height: 100%; } }
153 | @-o-keyframes loader-inner {
154 | 0%, 25%, 100% {
155 | height: 0; }
156 | 50%, 75% {
157 | height: 100%; } }
158 | @keyframes loader-inner {
159 | 0%, 25%, 100% {
160 | height: 0; }
161 | 50%, 75% {
162 | height: 100%; } }
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic-ui/src/css/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: 'Space Mono', monospace;
3 | background-color: #fbfdff;
4 | font-size: 9px;
5 | }
6 | h1,h2,h3,h4,h5 {
7 | color: #34495e;
8 | }
9 | h1,h2,h3,h4,h5,p {
10 | text-align: left;
11 | }
12 | h1 {
13 | font-family: 'Space Mono', monospace;
14 | font-weight: 700;
15 | }
16 | h2 {
17 | font-family: 'Space Mono', monospace;
18 | font-weight: 100;
19 | font-size: 25px;
20 | }
21 | h3 {
22 | font-family: 'Space Mono', monospace;
23 | font-weight: 100;
24 | font-size: 16px;
25 | }
26 | h5 {
27 | font-weight: 100;
28 | font-size: 12px;
29 | }
30 |
31 | p {
32 | text-align: left;
33 | font-weight: 300;
34 | line-height: 1.7em;
35 | font-size: 12px;
36 | color: #000000;
37 | }
38 | img {
39 | max-width: 100%;
40 | display: block;
41 | }
42 | iframe {
43 | max-width: 100%;
44 | display: block;
45 | }
46 | svg:not(:root) {
47 | position: relative;
48 | overflow: visible;
49 | }
50 |
51 | .sidebar-top {
52 | padding-bottom: 50px;
53 | }
54 | .related {
55 | font-size: 11px !important;
56 | }
57 | .hide-overflow {
58 | overflow: hidden;
59 | }
60 | .line-divisor {
61 | padding: 20px 0pt;
62 | margin: 20px 0pt;
63 | border-bottom: 1px solid #DDDDDD;
64 | border-top: 1px solid #DDDDDD;
65 | }
66 |
67 | #graph {
68 | height: 800px;
69 | width: 100%;
70 | position: relative;
71 | overflow: visible;
72 | margin: 0px;
73 | }
74 |
75 | .logo-container {
76 | padding: 0px;
77 | }
78 | .logo {
79 | max-height: 35px;
80 | vertical-align: middle;
81 | padding: 0px;
82 | margin: 0px;
83 | }
84 | .article-card .title {
85 | font-family: 'Merriweather';
86 | font-weight: 500;
87 | font-size: 26px;
88 | }
89 | .article-card {
90 | font-family: 'Roboto Mono';
91 | font-weight: 100;
92 | font-size: 10px;
93 | }
94 | .total-scheduled-instances {
95 | font-family: 'Roboto Mono';
96 | font-weight: 300;
97 | font-size: 10px;
98 | padding-left: 10px;
99 | }
100 |
101 | /*
102 |
103 | Pulsing effect.
104 |
105 | */
106 | .alert_green {
107 | display: block;
108 | width: 10px;
109 | height: 10px;
110 | border-radius: 50%;
111 | background: #2ecc71;
112 | cursor: pointer;
113 | box-shadow: 0 0 0 rgba(209, 193, 139, 0.40);
114 | }
115 | .alert_yellow {
116 | display: block;
117 | width: 10px;
118 | height: 10px;
119 | border-radius: 50%;
120 | background: #f1c40f;
121 | cursor: pointer;
122 | box-shadow: 0 0 0 rgba(209, 193, 139, 0.40);
123 | }
124 | .alert_red {
125 | display: block;
126 | width: 10px;
127 | height: 10px;
128 | border-radius: 50%;
129 | background: #e74c3c;
130 | cursor: pointer;
131 | box-shadow: 0 0 0 rgba(209, 193, 139, 0.40);
132 | animation: pulse 1.5s infinite;
133 | }
134 | .alert_red:hover {
135 | animation: pulse 1.5s infinite;
136 | }
137 |
138 | @-webkit-keyframes pulse {
139 | 0% {
140 | -webkit-box-shadow: 0 0 0 0 rgba(182, 182, 182, 0.40);
141 | }
142 | 70% {
143 | -webkit-box-shadow: 0 0 0 20px rgba(182, 182, 182, 0);
144 | }
145 | 100% {
146 | -webkit-box-shadow: 0 0 0 0 rgba(182, 182, 182, 0);
147 | }
148 | }
149 | @keyframes pulse {
150 | 0% {
151 | -moz-box-shadow: 0 0 0 0 rgba(182, 182, 182, 0.40);
152 | box-shadow: 0 0 0 0 rgba(182, 182, 182, 0.40);
153 | }
154 | 70% {
155 | -moz-box-shadow: 0 0 0 20px rgba(182, 182, 182, 0);
156 | box-shadow: 0 0 0 20px rgba(182, 182, 182, 0);
157 | }
158 | 100% {
159 | -moz-box-shadow: 0 0 0 0 rgba(182, 182, 182, 0);
160 | box-shadow: 0 0 0 0 rgba(182, 182, 182, 0);
161 | }
162 | }
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic-ui/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Cryptonic
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic-ui/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import ElementUI from 'element-ui'
3 | import lodash from 'lodash'
4 | import c3 from 'c3'
5 | import Trend from 'vuetrend'
6 | import moment from 'moment-timezone'
7 |
8 | import 'c3/c3.min.css'
9 | import 'element-ui/lib/theme-default/index.css'
10 | import './css/style.css'
11 | import './css/forbes_logo.css'
12 | import './css/loading_animation.css'
13 | import './css/infinite.css'
14 | import App from './App.vue'
15 | import locale from 'element-ui/lib/locale/lang/en'
16 |
17 | import VueMoment from 'vue-moment'
18 | import VueResource from 'vue-resource'
19 | import VueLodash from 'vue-lodash'
20 |
21 |
22 | Vue.prototype.$c3 = c3
23 |
24 | Vue.use(VueLodash, lodash)
25 | Vue.use(ElementUI, { locale })
26 | Vue.use(VueResource)
27 | Vue.use(VueMoment, { moment })
28 | Vue.use(Trend)
29 | Vue.use(c3)
30 |
31 |
32 | new Vue({
33 | el: '#app',
34 | render: h => h(App)
35 | })
36 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic-ui/webpack.config.js:
--------------------------------------------------------------------------------
1 | const resolve = require('path').resolve
2 | const webpack = require('webpack')
3 | const HtmlWebpackPlugin = require('html-webpack-plugin')
4 | const url = require('url')
5 | const publicPath = ''
6 |
7 | module.exports = (options = {}) => ({
8 | entry: {
9 | vendor: './src/vendor',
10 | index: './src/main.js'
11 | },
12 | output: {
13 | path: resolve(__dirname, 'dist'),
14 | filename: options.dev ? '[name].js' : '[name].js?[chunkhash]',
15 | chunkFilename: '[id].js?[chunkhash]',
16 | publicPath: options.dev ? '/assets/' : publicPath
17 | },
18 | module: {
19 | rules: [{
20 | test: /\.vue$/,
21 | use: ['vue-loader']
22 | },
23 | {
24 | test: /\.js$/,
25 | use: ['babel-loader'],
26 | exclude: /node_modules/,
27 | include: [
28 | resolve(__dirname, 'src'),
29 | resolve(__dirname, 'test'),
30 | resolve(__dirname, 'node_modules/element-ui/packages')
31 | ]
32 | },
33 | {
34 | test: /\.css$/,
35 | use: ['style-loader', 'css-loader', 'postcss-loader']
36 | },
37 | {
38 | test: /\.(png|jpg|jpeg|gif|eot|ttf|woff|woff2|svg|svgz)(\?.+)?$/,
39 | use: [{
40 | loader: 'url-loader',
41 | options: {
42 | limit: 10000
43 | }
44 | }]
45 | }
46 | ]
47 | },
48 | plugins: [
49 | new webpack.optimize.CommonsChunkPlugin({
50 | names: ['vendor', 'manifest']
51 | }),
52 | new HtmlWebpackPlugin({
53 | template: 'src/index.html'
54 | })
55 | ],
56 | resolve: {
57 | alias: {
58 | '~': resolve(__dirname, 'src')
59 | }
60 | },
61 | devServer: {
62 | host: '127.0.0.1',
63 | port: 8010,
64 | proxy: {
65 | '/api/': {
66 | target: 'http://127.0.0.1:8080',
67 | changeOrigin: true,
68 | pathRewrite: {
69 | '^/api': ''
70 | }
71 | }
72 | },
73 | historyApiFallback: {
74 | index: url.parse(options.dev ? '/assets/' : publicPath).pathname
75 | }
76 | },
77 | devtool: options.dev ? '#eval-source-map' : '#source-map'
78 | })
79 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic.env:
--------------------------------------------------------------------------------
1 | REDIS_URL=redis://redis@cache:6379/0
2 | CRYPTONIC_VERSION=latest
3 | BITCOIN_START_DATE=2017-01-01
4 | EPOCHS=300
5 | PERIOD_SIZE=7
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Cryptonic is an educational application created for
3 | the purposes of learning how to use deep learning
4 | to predict Bitcoin prices.
5 | """
6 | from cryptonic.models.model import Model
7 | from cryptonic.markets.coinmarketcap import CoinMarketCap
8 |
9 | __version__ = 'v1.0.1'
10 | __author__ = 'Luis Capelo'
11 | __email__ = 'luiscape@gmail.com'
12 |
13 | __all__ = ['Model', 'CoinMarketCap']
14 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic/api/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | HTTP API interface for Cryptonic.
3 | """
4 |
5 | __version__ = 1
6 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic/api/routes.py:
--------------------------------------------------------------------------------
1 | """
2 | Creates all application routes.
3 | """
4 | import os
5 |
6 | from datetime import datetime, timedelta
7 | from flask_api import status as http_status
8 | from flask import jsonify, request, make_response, send_file, send_from_directory
9 |
10 | from cryptonic.api import __version__
11 |
12 |
13 | def __cache_identifier(*args, **kwargs):
14 | """
15 | Creates a cache identifier based on the complete
16 | URL provided in the request. Original solution:
17 |
18 | * https://stackoverflow.com/questions/9413566/\
19 | flask-cache-memoize-url-query-string-parameters-as-well
20 |
21 | """
22 | #
23 | # The following snippet will create a
24 | # cache key for the URL and all GET and POST
25 | # parameters.
26 | #
27 | key = request.url + \
28 | '='.join([k + '=' + v for k,v in request.args.items()]) + '&' + \
29 | '='.join([k + '=' + v for k,v in request.form.items()])
30 |
31 | return key
32 |
33 |
34 | def create_routes(app, cache, model):
35 | """
36 | Function that creates the application routes.
37 |
38 | Parameters
39 | ----------
40 | app: Flask object
41 | Initialized Flask object.
42 |
43 | cache: Flask-Caching instance
44 | Cache instance that can be used
45 | as a decorator.
46 |
47 | model: instantiated Model()
48 | Module() class instantiated as a model
49 | and trained.
50 |
51 | Returns
52 | -------
53 | app: Flask object
54 | Modified Flask app object.
55 | """
56 | #
57 | # Let's clear the cache at every
58 | # startup.
59 | #
60 | cache.clear()
61 |
62 | @cache.cached(timeout=60 * 5, key_prefix=__cache_identifier)
63 | @app.errorhandler(404)
64 | def page_not_found(e):
65 | return app.send_static_file('index.html'), 404
66 |
67 | @cache.cached(timeout=60 * 5, key_prefix=__cache_identifier)
68 | @app.route('/')
69 | def root():
70 | """
71 | Endpoint for serving the index page.
72 | """
73 | return app.send_static_file('index.html')
74 |
75 | @app.route('/')
76 | def send_static_files(path):
77 | return send_from_directory(
78 | os.getenv('UI_DIST_DIRECTORY', '../cryptonic-ui/dist/'), path)
79 |
80 | @app.route('/status')
81 | def status():
82 | """
83 | Endpoint for returning the application status.
84 | """
85 | r = {
86 | 'version': __version__,
87 | 'success': True,
88 | 'message': 'Predict Bitcoin prices with deep learning.',
89 | 'model': {
90 | 'name': os.getenv('MODEL_NAME'),
91 | 'last_trained': model.last_trained,
92 | 'error_rates': model.evaluate()
93 | }
94 | }
95 | return jsonify(r)
96 |
97 | @cache.cached(timeout=60 * 24, key_prefix=__cache_identifier)
98 | @app.route('/historic')
99 | def historic():
100 | """
101 | Returns a series of historic observations.
102 |
103 | Parameters
104 | ----------
105 | start: str, default six months ago
106 | Start date to filter the Bitcoin historic price
107 | data set.
108 |
109 | """
110 | six_months_ago = (
111 | datetime.now() - timedelta(days=30 * 6)).strftime('%Y-%m-%d')
112 | start = request.args.get('start', six_months_ago)
113 |
114 | historic_data = model.data.to_dict(orient='records')
115 | filtered_historic_data = list(filter(lambda x: x['date'] > six_months_ago, historic_data))
116 |
117 | r = {
118 | 'version': __version__,
119 | 'success': True,
120 | 'message': 'Historic Bitcoin prices from CoinMarketCap.',
121 | 'start_date': os.getenv('BITCOIN_START_DATE'),
122 | 'result': filtered_historic_data
123 | }
124 |
125 | return jsonify(r)
126 |
127 | @cache.cached(timeout=60 * 24, key_prefix=__cache_identifier)
128 | @app.route('/predict')
129 | def predict():
130 | """
131 | Endpoint for predicting bitcoin prices.
132 | """
133 | r = {
134 | 'version': __version__,
135 | 'success': True,
136 | 'message': 'Endpoint for making predictions.',
137 | 'period_length': os.getenv('PERIOD_SIZE', 7),
138 | 'result': model.predict(denormalized=True, return_dict=True)
139 | }
140 | return jsonify(r)
141 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic/markets/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Interface for manipulating data from different markets.
3 | """
4 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic/markets/coinmarketcap.py:
--------------------------------------------------------------------------------
1 | """
2 | Logic for collecting data directly from the
3 | CoinMarketCap API.
4 | """
5 | import requests
6 | import pandas as pd
7 |
8 | from datetime import datetime
9 | from bs4 import BeautifulSoup
10 |
11 |
12 | class CoinMarketCap:
13 | """
14 | Class interface to data from CoinMarketCap.
15 | Original data can be found at:
16 |
17 | https://coinmarketcap.com/
18 |
19 | """
20 | def __repr__(self):
21 | message = """
22 |
23 | Crypto-currency data comes from the website CoinMarketCap.
24 | CoinMarketCap is can be accessed at: https://coinmarketcap.com/
25 |
26 | The permission to use the data is available on their FAQ
27 |
28 | https://coinmarketcap.com/faq/
29 |
30 | and reads:
31 |
32 | "Q: Am I allowed to use content (screenshots, data, graphs, etc.)
33 | for one of my personal projects and/or commercial use?
34 |
35 | R: Absolutely! Feel free to use any content as you see fit.
36 | We kindly ask that you cite us as a source."
37 |
38 | """
39 | return message
40 |
41 | @classmethod
42 | def historic(cls, start='2013-04-28', stop=None, ticker='bitcoin', return_json=False):
43 | """
44 | Retrieves historic data within a time
45 | period.
46 |
47 | Parameters
48 | ----------
49 | start, stop: str
50 | Start and stop dates in ISO format (YYYY-MM-DD).
51 |
52 | ticker: str
53 | Name of ticker to be used (e.g. `bitcoin`).
54 |
55 | Returns
56 | -------
57 | Pandas dataframe with historical ticker data.
58 | """
59 | start = start.replace('-', '')
60 | if not stop:
61 | stop = datetime.now().strftime('%Y%m%d')
62 |
63 | url = 'https://coinmarketcap.com/currencies/{}/historical-data/?start={}&end={}'.format(ticker, start, stop)
64 | r = requests.get(url)
65 |
66 | soup = BeautifulSoup(r.content, 'lxml')
67 | table = soup.find_all('table')[0]
68 | df = pd.read_html(str(table))[0]
69 |
70 | #
71 | # Cleans variables from the original.
72 | #
73 | df['Date'] = df['Date'].apply(lambda x: datetime.strptime(x, '%b %d, %Y').strftime('%Y-%m-%d'))
74 | df['Volume'] = df['Volume'].apply(lambda x: None if x == '-' else x)
75 | df.columns = ['date', 'open', 'high', 'low', 'close', 'volume', 'market_cap']
76 |
77 | if return_json:
78 | df.to_json(orient='records')
79 |
80 | return df
81 |
82 | @classmethod
83 | def current(cls, ticker='bitcoin'):
84 | """
85 | Fetches current prices from CoinMarketCap.
86 |
87 | Returns
88 | -------
89 | Dictionary with a single record form the
90 | """
91 | url = 'https://api.coinmarketcap.com/v1/ticker/{}/'.format(ticker)
92 | r = requests.get(url)
93 |
94 | return r.json()
95 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic/models/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Cryptocurrency prediction models.
3 | """
4 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic/models/helper.py:
--------------------------------------------------------------------------------
1 | """
2 | Helper class and methods for making manipulating
3 | data for models.
4 | """
5 | import numpy as np
6 |
7 | import cryptonic.models.normalizations as normalizations
8 |
9 |
10 | class ModelHelper:
11 | """
12 | Class with utility functions that aid in
13 | the process of training LSTM models with Keras.
14 |
15 | """
16 | def __init__(self):
17 | pass
18 |
19 | def create_groups(self, data, start=0, group_size=7, normalize=True):
20 | """
21 | Creates distinct groups from a given continuous series.
22 |
23 | Parameters
24 | ----------
25 | data: np.array
26 | Series of continious observations.
27 |
28 | start: int
29 | Starting point for the series. This
30 | is used to prune earlier observations
31 | from the series in case the series is
32 | too long or too short.
33 |
34 | group_size: int, default 7
35 | Determines how large the groups are. That is,
36 | how many observations each group contains.
37 |
38 | normalize: bool
39 | If the method should normalize data or not.
40 | Normalization is done using
41 |
42 | normalizations.point_relative_normalization()
43 |
44 | Returns
45 | -------
46 | A Numpy array object.
47 | """
48 | samples = list()
49 | for i in range(0, len(data), group_size):
50 | sample = list(data[start + i:i + group_size])
51 | if len(sample) == group_size:
52 | if normalize:
53 | sample = normalizations.point_relative_normalization(sample)
54 |
55 | samples.append(np.array(sample).reshape(1, group_size).tolist())
56 |
57 | A = np.array(samples)
58 | return A.reshape(1, A.shape[0], group_size)
59 |
60 | def split_lstm_input(self, groups):
61 | """
62 | Splits groups in a format expected by
63 | the LSTM layer.
64 |
65 | Parameters
66 | ----------
67 | groups: np.array
68 | Numpy array with the organized sequences.
69 |
70 | Returns
71 | -------
72 | X, Y: np.array
73 | Numpy arrays with the shapes required by
74 | the LSTM layer. X with (1, a - 1, b)
75 | and Y with (1, b). Where a is the total
76 | number of groups in `group` and b the
77 | number of observations per group.
78 | """
79 | X = groups[0:,:-1].reshape(1, groups.shape[1] - 1, groups.shape[2])
80 | Y = groups[0:,-1:][0]
81 |
82 | return X, Y
83 |
84 | def normalize(self):
85 | """
86 | Normalizes a series using point-relative normalization.
87 |
88 | Parameters
89 | ----------
90 |
91 | Returns
92 | -------
93 | """
94 | normalizations.point_relative_normalization()
95 |
96 | def denormalize(self, series, last_value):
97 | """
98 | De-normalizes a series using the latest
99 | value available from data.
100 |
101 | Parameters
102 | ----------
103 | series: numpy array
104 | Series with normalized values.
105 |
106 | last_value: float
107 | Numerical value that represents the
108 | last value from the dataset.
109 |
110 | Returns
111 | -------
112 | """
113 | result = last_value * (series + 1)
114 | return result
115 |
116 | def mape(self, A, B):
117 | """
118 | Calcualtes the mean absolute persentage error
119 | from two series. Original solution from:
120 |
121 | https://stats.stackexchange.com/questions/58391/\
122 | mean-absolute-percentage-error-mape-in-scikit-learn
123 | """
124 | return np.mean(np.abs((A - B) / (1 - A))) * 100
125 |
126 | def rmse(self, A, B):
127 | """
128 | Calculates the root mean square error from
129 | two series. Original solution from:
130 |
131 | https://stackoverflow.com/questions/16774849\
132 | /mean-squared-error-in-numpy
133 | """
134 | return np.sqrt(np.square(np.subtract(A, B)).mean())
135 |
136 | def mse(self, A, B):
137 | """
138 | Calculates the mean square error from
139 | two series. Original solution from:
140 |
141 | https://stackoverflow.com/questions/16774849\
142 | /mean-squared-error-in-numpy
143 | """
144 | return np.square(np.subtract(A, B)).mean()
145 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic/models/normalizations.py:
--------------------------------------------------------------------------------
1 | """
2 | Series of normalization functions useful
3 | for normalizing time-series data.
4 | """
5 |
6 | def z_score(series):
7 | """
8 | Computes the normalized value using the Z-score
9 | technique. The Z-score is a technique used for
10 | normalizing Gaussian distributions representing
11 | each observation in relation to the distribution's
12 | mean and standard deviation. For precise definitions,
13 | see the Wikipedia article:
14 |
15 | https://en.wikipedia.org/wiki/Standard_score
16 |
17 | Parameters
18 | ----------
19 | serie: list
20 | List with sequential values to use.
21 |
22 | Returns
23 | -------
24 | result: list
25 | List with the normalized results.
26 | """
27 | result = (series - series.mean()) / series.std(ddof=0)
28 | return result
29 |
30 | def point_relative_normalization(series, reverse=False, last_value=None):
31 | """
32 | Computes the normalized value for the values of a
33 | given series by using the first element of the serie as p_0
34 | as a reference for each p_i.
35 |
36 | This technique comes from Siraj Raval's YouTube video
37 | "How to Predict Stock Prices Easily - Intro to Deep Learning #7",
38 | available at:
39 |
40 | https://www.youtube.com/watch?v=ftMq5ps503w
41 |
42 | Parameters
43 | ----------
44 | serie: list
45 | List with sequential values to use.
46 |
47 | reverse: bool, default True
48 | If the method should de-normalize data.
49 |
50 | last_value: int or float
51 | Used to de-normalize a dataset. Needs to
52 | be passed if `reverse` is True.
53 |
54 | Returns
55 | -------
56 | result: list
57 | List with the normalized results.
58 | """
59 | if reverse:
60 | result = last_value * (series + 1)
61 | else:
62 | result = (series / series[0]) - 1
63 |
64 | return result
65 |
66 | def maximum_and_minimum_normalization(series, boundary=(0, 1)):
67 | """
68 | Computes the normalized value for the values of a
69 | given serie by using that series maximum and minimum
70 | values.
71 |
72 | This technique is a direct implementation from
73 | scikit-learn, available at:
74 |
75 | http://scikit-learn.org/stable/modules/generated/\
76 | sklearn.preprocessing.MinMaxScaler.html
77 |
78 | Parameters
79 | ----------
80 | serie: list
81 | List with sequential values to use.
82 |
83 | boundary: set
84 | Maximum and minimum values used to
85 | scale the series.
86 |
87 | Returns
88 | -------
89 | result: list
90 | List with the normalized results.
91 | """
92 | range_min, range_max = boundary
93 | standard_deviation = (series - series.min(axis=0)) / (series.max(axis=0) - series.min(axis=0))
94 | result = standard_deviation * (range_max - range_min) + range_min
95 | return result
96 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic/server.py:
--------------------------------------------------------------------------------
1 | """
2 | Functions to start and configure the Flask
3 | application. This simply configures the server
4 | and its routes.
5 | """
6 | import os
7 | import flask
8 |
9 | from flask_caching import Cache
10 | from flask_cors import CORS, cross_origin
11 |
12 | from cryptonic import Model
13 | #from cryptonic import CoinMarketCap
14 | from cryptonic.api.routes import create_routes
15 | import yfinance as yf
16 |
17 | UI_DIST_DIRECTORY = os.getenv('UI_DIST_DIRECTORY', '../cryptonic-ui/dist/')
18 |
19 |
20 | class Server:
21 | """
22 | Cryptonic server representation. This class
23 | contains logic for managing the configuration
24 | and deployment of Flask server.
25 |
26 | Parameters
27 | ----------
28 | debug: bool, default False
29 | If should start with a debugger.
30 |
31 | cors: bool, default True
32 | If the application should accept CORS
33 | requests.
34 |
35 | """
36 | def __init__(self, debug=False, cors=True):
37 | self.debug = debug
38 | self.cors = cors
39 |
40 | self.create_model()
41 | self.app = self.create()
42 |
43 | def create_model(self):
44 | """
45 | Creates a model either using a model provided
46 | by user or by creating a new model using
47 | previously researched parameters.
48 |
49 | Returns
50 | -------
51 | Trained Keras model. Ready to be used
52 | via the model.predict() method.
53 | """
54 | ticker = yf.Ticker("BTC-USD")
55 | historic_data = ticker.history(period='max')
56 | historic_data = historic_data.rename(columns={'Open':'open', 'High':'high', 'Low':'low', 'Close':'close', 'Volume':'volume'})
57 | historic_data.index.names = ['date']
58 | historic_data = historic_data[['open','high', 'low', 'close', 'volume']]
59 | historic_data = historic_data.reset_index()
60 |
61 | model_path = os.getenv('MODEL_NAME')
62 |
63 | #
64 | # TODO: Figure out how large the data is for
65 | # the old model and re-train. Maybe what I have
66 | # to do here is to copy the weights of the
67 | # model into a new model.
68 | #
69 |
70 | self.model = Model(data=historic_data,
71 | path=model_path,
72 | variable='close',
73 | predicted_period_size=int(os.getenv('PERIOD_SIZE', 7)))
74 |
75 | if not model_path:
76 | self.model.build()
77 | self.model.train(epochs=int(os.getenv('EPOCHS', 50)), verbose=1)
78 |
79 | return self.model
80 |
81 | def create(self):
82 | """
83 | Method for creating a Flask server.
84 |
85 | Returns
86 | -------
87 | A Flask() application object.
88 | """
89 | app = flask.Flask(__name__, static_url_path='/', static_folder=UI_DIST_DIRECTORY)
90 |
91 | #
92 | # Application configuration. Here we
93 | # configure the application to accept
94 | # CORS requests, its routes, and
95 | # its debug flag.
96 | #
97 | if self.cors:
98 | CORS(app)
99 |
100 | cache_configuration = {
101 | 'CACHE_TYPE': 'redis',
102 | 'CACHE_REDIS_URL': os.getenv('REDIS_URL',
103 | "redis://localhost:6379/2")
104 | }
105 |
106 | self.cache = Cache(app, config=cache_configuration)
107 |
108 | app.config['DEBUG'] = self.debug
109 | create_routes(app, self.cache, self.model)
110 |
111 | return app
112 |
113 | def run(self, *args, **kwargs):
114 | """
115 | Method for running Flask server.
116 | Parameters
117 | ----------
118 | *args, **kwargs: parameters passed to the Flask application.
119 | """
120 | self.app.run(*args, **kwargs)
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic_old/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Cryptonic is an educational application created for
3 | the purposes of learning how to use deep learning
4 | to predict Bitcoin prices.
5 | """
6 | from cryptonic.models.model import Model
7 | from cryptonic.markets.coinmarketcap import CoinMarketCap
8 |
9 | __version__ = 'v1.0.1'
10 | __author__ = 'Luis Capelo'
11 | __email__ = 'luiscape@gmail.com'
12 |
13 | __all__ = ['Model', 'CoinMarketCap']
14 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic_old/api/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | HTTP API interface for Cryptonic.
3 | """
4 |
5 | __version__ = 1
6 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic_old/api/routes.py:
--------------------------------------------------------------------------------
1 | """
2 | Creates all application routes.
3 | """
4 | import os
5 |
6 | from datetime import datetime, timedelta
7 | from flask_api import status as http_status
8 | from flask import jsonify, request, make_response, send_file, send_from_directory
9 |
10 | from cryptonic.api import __version__
11 |
12 |
13 | def __cache_identifier(*args, **kwargs):
14 | """
15 | Creates a cache identifier based on the complete
16 | URL provided in the request. Original solution:
17 |
18 | * https://stackoverflow.com/questions/9413566/\
19 | flask-cache-memoize-url-query-string-parameters-as-well
20 |
21 | """
22 | #
23 | # The following snippet will create a
24 | # cache key for the URL and all GET and POST
25 | # parameters.
26 | #
27 | key = request.url + \
28 | '='.join([k + '=' + v for k,v in request.args.items()]) + '&' + \
29 | '='.join([k + '=' + v for k,v in request.form.items()])
30 |
31 | return key
32 |
33 |
34 | def create_routes(app, cache, model):
35 | """
36 | Function that creates the application routes.
37 |
38 | Parameters
39 | ----------
40 | app: Flask object
41 | Initialized Flask object.
42 |
43 | cache: Flask-Caching instance
44 | Cache instance that can be used
45 | as a decorator.
46 |
47 | model: instantiated Model()
48 | Module() class instantiated as a model
49 | and trained.
50 |
51 | Returns
52 | -------
53 | app: Flask object
54 | Modified Flask app object.
55 | """
56 | #
57 | # Let's clear the cache at every
58 | # startup.
59 | #
60 | cache.clear()
61 |
62 | @cache.cached(timeout=60 * 5, key_prefix=__cache_identifier)
63 | @app.errorhandler(404)
64 | def page_not_found(e):
65 | return app.send_static_file('index.html'), 404
66 |
67 | @cache.cached(timeout=60 * 5, key_prefix=__cache_identifier)
68 | @app.route('/')
69 | def root():
70 | """
71 | Endpoint for serving the index page.
72 | """
73 | return app.send_static_file('index.html')
74 |
75 | @app.route('/')
76 | def send_static_files(path):
77 | return send_from_directory(
78 | os.getenv('UI_DIST_DIRECTORY', '../cryptonic-ui/dist/'), path)
79 |
80 | @app.route('/status')
81 | def status():
82 | """
83 | Endpoint for returning the application status.
84 | """
85 | r = {
86 | 'version': __version__,
87 | 'success': True,
88 | 'message': 'Predict Bitcoin prices with deep learning.',
89 | 'model': {
90 | 'name': os.getenv('MODEL_NAME'),
91 | 'last_trained': model.last_trained,
92 | 'error_rates': model.evaluate()
93 | }
94 | }
95 | return jsonify(r)
96 |
97 | @cache.cached(timeout=60 * 24, key_prefix=__cache_identifier)
98 | @app.route('/historic')
99 | def historic():
100 | """
101 | Returns a series of historic observations.
102 |
103 | Parameters
104 | ----------
105 | start: str, default six months ago
106 | Start date to filter the Bitcoin historic price
107 | data set.
108 |
109 | """
110 | six_months_ago = (
111 | datetime.now() - timedelta(days=30 * 6)).strftime('%Y-%m-%d')
112 | start = request.args.get('start', six_months_ago)
113 |
114 | historic_data = model.data.to_dict(orient='records')
115 | filtered_historic_data = list(filter(lambda x: x['date'] > six_months_ago, historic_data))
116 |
117 | r = {
118 | 'version': __version__,
119 | 'success': True,
120 | 'message': 'Historic Bitcoin prices from CoinMarketCap.',
121 | 'start_date': os.getenv('BITCOIN_START_DATE'),
122 | 'result': filtered_historic_data
123 | }
124 |
125 | return jsonify(r)
126 |
127 | @cache.cached(timeout=60 * 24, key_prefix=__cache_identifier)
128 | @app.route('/predict')
129 | def predict():
130 | """
131 | Endpoint for predicting bitcoin prices.
132 | """
133 | r = {
134 | 'version': __version__,
135 | 'success': True,
136 | 'message': 'Endpoint for making predictions.',
137 | 'period_length': os.getenv('PERIOD_SIZE', 7),
138 | 'result': model.predict(denormalized=True, return_dict=True)
139 | }
140 | return jsonify(r)
141 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic_old/markets/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Interface for manipulating data from different markets.
3 | """
4 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic_old/markets/coinmarketcap.py:
--------------------------------------------------------------------------------
1 | """
2 | Logic for collecting data directly from the
3 | CoinMarketCap API.
4 | """
5 | import requests
6 | import pandas as pd
7 |
8 | from datetime import datetime
9 | from bs4 import BeautifulSoup
10 |
11 |
12 | class CoinMarketCap:
13 | """
14 | Class interface to data from CoinMarketCap.
15 | Original data can be found at:
16 |
17 | https://coinmarketcap.com/
18 |
19 | """
20 | def __repr__(self):
21 | message = """
22 |
23 | Crypto-currency data comes from the website CoinMarketCap.
24 | CoinMarketCap is can be accessed at: https://coinmarketcap.com/
25 |
26 | The permission to use the data is available on their FAQ
27 |
28 | https://coinmarketcap.com/faq/
29 |
30 | and reads:
31 |
32 | "Q: Am I allowed to use content (screenshots, data, graphs, etc.)
33 | for one of my personal projects and/or commercial use?
34 |
35 | R: Absolutely! Feel free to use any content as you see fit.
36 | We kindly ask that you cite us as a source."
37 |
38 | """
39 | return message
40 |
41 | @classmethod
42 | def historic(cls, start='2013-04-28', stop=None, ticker='bitcoin', return_json=False):
43 | """
44 | Retrieves historic data within a time
45 | period.
46 |
47 | Parameters
48 | ----------
49 | start, stop: str
50 | Start and stop dates in ISO format (YYYY-MM-DD).
51 |
52 | ticker: str
53 | Name of ticker to be used (e.g. `bitcoin`).
54 |
55 | Returns
56 | -------
57 | Pandas dataframe with historical ticker data.
58 | """
59 | start = start.replace('-', '')
60 | if not stop:
61 | stop = datetime.now().strftime('%Y%m%d')
62 |
63 | url = 'https://coinmarketcap.com/currencies/{}/historical-data/?start={}&end={}'.format(ticker, start, stop)
64 | r = requests.get(url)
65 |
66 | soup = BeautifulSoup(r.content, 'lxml')
67 | table = soup.find_all('table')[0]
68 | df = pd.read_html(str(table))[0]
69 |
70 | #
71 | # Cleans variables from the original.
72 | #
73 | df['Date'] = df['Date'].apply(lambda x: datetime.strptime(x, '%b %d, %Y').strftime('%Y-%m-%d'))
74 | df['Volume'] = df['Volume'].apply(lambda x: None if x == '-' else x)
75 | df.columns = ['date', 'open', 'high', 'low', 'close', 'volume', 'market_cap']
76 |
77 | if return_json:
78 | df.to_json(orient='records')
79 |
80 | return df
81 |
82 | @classmethod
83 | def current(cls, ticker='bitcoin'):
84 | """
85 | Fetches current prices from CoinMarketCap.
86 |
87 | Returns
88 | -------
89 | Dictionary with a single record form the
90 | """
91 | url = 'https://api.coinmarketcap.com/v1/ticker/{}/'.format(ticker)
92 | r = requests.get(url)
93 |
94 | return r.json()
95 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic_old/models/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Cryptocurrency prediction models.
3 | """
4 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic_old/models/helper.py:
--------------------------------------------------------------------------------
1 | """
2 | Helper class and methods for making manipulating
3 | data for models.
4 | """
5 | import numpy as np
6 |
7 | import cryptonic.models.normalizations as normalizations
8 |
9 |
10 | class ModelHelper:
11 | """
12 | Class with utility functions that aid in
13 | the process of training LSTM models with Keras.
14 |
15 | """
16 | def __init__(self):
17 | pass
18 |
19 | def create_groups(self, data, start=0, group_size=7, normalize=True):
20 | """
21 | Creates distinct groups from a given continuous series.
22 |
23 | Parameters
24 | ----------
25 | data: np.array
26 | Series of continious observations.
27 |
28 | start: int
29 | Starting point for the series. This
30 | is used to prune earlier observations
31 | from the series in case the series is
32 | too long or too short.
33 |
34 | group_size: int, default 7
35 | Determines how large the groups are. That is,
36 | how many observations each group contains.
37 |
38 | normalize: bool
39 | If the method should normalize data or not.
40 | Normalization is done using
41 |
42 | normalizations.point_relative_normalization()
43 |
44 | Returns
45 | -------
46 | A Numpy array object.
47 | """
48 | samples = list()
49 | for i in range(0, len(data), group_size):
50 | sample = list(data[start + i:i + group_size])
51 | if len(sample) == group_size:
52 | if normalize:
53 | sample = normalizations.point_relative_normalization(sample)
54 |
55 | samples.append(np.array(sample).reshape(1, group_size).tolist())
56 |
57 | A = np.array(samples)
58 | return A.reshape(1, A.shape[0], group_size)
59 |
60 | def split_lstm_input(self, groups):
61 | """
62 | Splits groups in a format expected by
63 | the LSTM layer.
64 |
65 | Parameters
66 | ----------
67 | groups: np.array
68 | Numpy array with the organized sequences.
69 |
70 | Returns
71 | -------
72 | X, Y: np.array
73 | Numpy arrays with the shapes required by
74 | the LSTM layer. X with (1, a - 1, b)
75 | and Y with (1, b). Where a is the total
76 | number of groups in `group` and b the
77 | number of observations per group.
78 | """
79 | X = groups[0:,:-1].reshape(1, groups.shape[1] - 1, groups.shape[2])
80 | Y = groups[0:,-1:][0]
81 |
82 | return X, Y
83 |
84 | def normalize(self):
85 | """
86 | Normalizes a series using point-relative normalization.
87 |
88 | Parameters
89 | ----------
90 |
91 | Returns
92 | -------
93 | """
94 | normalizations.point_relative_normalization()
95 |
96 | def denormalize(self, series, last_value):
97 | """
98 | De-normalizes a series using the latest
99 | value available from data.
100 |
101 | Parameters
102 | ----------
103 | series: numpy array
104 | Series with normalized values.
105 |
106 | last_value: float
107 | Numerical value that represents the
108 | last value from the dataset.
109 |
110 | Returns
111 | -------
112 | """
113 | result = last_value * (series + 1)
114 | return result
115 |
116 | def mape(self, A, B):
117 | """
118 | Calcualtes the mean absolute persentage error
119 | from two series. Original solution from:
120 |
121 | https://stats.stackexchange.com/questions/58391/\
122 | mean-absolute-percentage-error-mape-in-scikit-learn
123 | """
124 | return np.mean(np.abs((A - B) / (1 - A))) * 100
125 |
126 | def rmse(self, A, B):
127 | """
128 | Calculates the root mean square error from
129 | two series. Original solution from:
130 |
131 | https://stackoverflow.com/questions/16774849\
132 | /mean-squared-error-in-numpy
133 | """
134 | return np.sqrt(np.square(np.subtract(A, B)).mean())
135 |
136 | def mse(self, A, B):
137 | """
138 | Calculates the mean square error from
139 | two series. Original solution from:
140 |
141 | https://stackoverflow.com/questions/16774849\
142 | /mean-squared-error-in-numpy
143 | """
144 | return np.square(np.subtract(A, B)).mean()
145 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic_old/models/normalizations.py:
--------------------------------------------------------------------------------
1 | """
2 | Series of normalization functions useful
3 | for normalizing time-series data.
4 | """
5 |
6 | def z_score(series):
7 | """
8 | Computes the normalized value using the Z-score
9 | technique. The Z-score is a technique used for
10 | normalizing Gaussian distributions representing
11 | each observation in relation to the distribution's
12 | mean and standard deviation. For precise definitions,
13 | see the Wikipedia article:
14 |
15 | https://en.wikipedia.org/wiki/Standard_score
16 |
17 | Parameters
18 | ----------
19 | serie: list
20 | List with sequential values to use.
21 |
22 | Returns
23 | -------
24 | result: list
25 | List with the normalized results.
26 | """
27 | result = (series - series.mean()) / series.std(ddof=0)
28 | return result
29 |
30 | def point_relative_normalization(series, reverse=False, last_value=None):
31 | """
32 | Computes the normalized value for the values of a
33 | given series by using the first element of the serie as p_0
34 | as a reference for each p_i.
35 |
36 | This technique comes from Siraj Raval's YouTube video
37 | "How to Predict Stock Prices Easily - Intro to Deep Learning #7",
38 | available at:
39 |
40 | https://www.youtube.com/watch?v=ftMq5ps503w
41 |
42 | Parameters
43 | ----------
44 | serie: list
45 | List with sequential values to use.
46 |
47 | reverse: bool, default True
48 | If the method should de-normalize data.
49 |
50 | last_value: int or float
51 | Used to de-normalize a dataset. Needs to
52 | be passed if `reverse` is True.
53 |
54 | Returns
55 | -------
56 | result: list
57 | List with the normalized results.
58 | """
59 | if reverse:
60 | result = last_value * (series + 1)
61 | else:
62 | result = (series / series[0]) - 1
63 |
64 | return result
65 |
66 | def maximum_and_minimum_normalization(series, boundary=(0, 1)):
67 | """
68 | Computes the normalized value for the values of a
69 | given serie by using that series maximum and minimum
70 | values.
71 |
72 | This technique is a direct implementation from
73 | scikit-learn, available at:
74 |
75 | http://scikit-learn.org/stable/modules/generated/\
76 | sklearn.preprocessing.MinMaxScaler.html
77 |
78 | Parameters
79 | ----------
80 | serie: list
81 | List with sequential values to use.
82 |
83 | boundary: set
84 | Maximum and minimum values used to
85 | scale the series.
86 |
87 | Returns
88 | -------
89 | result: list
90 | List with the normalized results.
91 | """
92 | range_min, range_max = boundary
93 | standard_deviation = (series - series.min(axis=0)) / (series.max(axis=0) - series.min(axis=0))
94 | result = standard_deviation * (range_max - range_min) + range_min
95 | return result
96 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/cryptonic_old/server.py:
--------------------------------------------------------------------------------
1 | """
2 | Functions to start and configure the Flask
3 | application. This simply configures the server
4 | and its routes.
5 | """
6 | import os
7 | import flask
8 |
9 | from flask_caching import Cache
10 | from flask_cors import CORS, cross_origin
11 |
12 | from cryptonic import Model
13 | #from cryptonic import CoinMarketCap
14 | from cryptonic.api.routes import create_routes
15 | import yfinance as yf
16 |
17 | UI_DIST_DIRECTORY = os.getenv('UI_DIST_DIRECTORY', '../cryptonic-ui/dist/')
18 |
19 |
20 | class Server:
21 | """
22 | Cryptonic server representation. This class
23 | contains logic for managing the configuration
24 | and deployment of Flask server.
25 |
26 | Parameters
27 | ----------
28 | debug: bool, default False
29 | If should start with a debugger.
30 |
31 | cors: bool, default True
32 | If the application should accept CORS
33 | requests.
34 |
35 | """
36 | def __init__(self, debug=False, cors=True):
37 | self.debug = debug
38 | self.cors = cors
39 |
40 | self.create_model()
41 | self.app = self.create()
42 |
43 | def create_model(self):
44 | """
45 | Creates a model either using a model provided
46 | by user or by creating a new model using
47 | previously researched parameters.
48 |
49 | Returns
50 | -------
51 | Trained Keras model. Ready to be used
52 | via the model.predict() method.
53 | """
54 | ticker = yf.Ticker("BTC-USD")
55 | historic_data = ticker.history(period='max')
56 |
57 | model_path = os.getenv('MODEL_NAME')
58 |
59 | #
60 | # TODO: Figure out how large the data is for
61 | # the old model and re-train. Maybe what I have
62 | # to do here is to copy the weights of the
63 | # model into a new model.
64 | #
65 |
66 | self.model = Model(data=historic_data,
67 | path=model_path,
68 | variable='close',
69 | predicted_period_size=int(os.getenv('PERIOD_SIZE', 7)))
70 |
71 | if not model_path:
72 | self.model.build()
73 | self.model.train(epochs=int(os.getenv('EPOCHS', 300)), verbose=1)
74 |
75 | return self.model
76 |
77 | def create(self):
78 | """
79 | Method for creating a Flask server.
80 |
81 | Returns
82 | -------
83 | A Flask() application object.
84 | """
85 | app = flask.Flask(__name__, static_url_path='/', static_folder=UI_DIST_DIRECTORY)
86 |
87 | #
88 | # Application configuration. Here we
89 | # configure the application to accept
90 | # CORS requests, its routes, and
91 | # its debug flag.
92 | #
93 | if self.cors:
94 | CORS(app)
95 |
96 | cache_configuration = {
97 | 'CACHE_TYPE': 'redis',
98 | 'CACHE_REDIS_URL': os.getenv('REDIS_URL',
99 | 'redis://redis@cache:6379/0')
100 | }
101 |
102 | self.cache = Cache(app, config=cache_configuration)
103 |
104 | app.config['DEBUG'] = self.debug
105 | create_routes(app, self.cache, self.model)
106 |
107 | return app
108 |
109 | def run(self, *args, **kwargs):
110 | """
111 | Method for running Flask server.
112 | Parameters
113 | ----------
114 | *args, **kwargs: parameters passed to the Flask application.
115 | """
116 | self.app.run(*args, **kwargs)
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/docker-compose.yml:
--------------------------------------------------------------------------------
1 | #
2 | # CRYPTONIC DOCKER-COMPOSE
3 | # ------------------------
4 | #
5 | # Here we configure the application stack
6 | # that is deployed with Cryptonic. This
7 | # includes three elements:
8 | #
9 | # i. Cryptonic App: a Python web-application
10 | # that exposes the Cryptonic API via
11 | # the HTTP protocol.
12 | #
13 | # ii. Cryptonic Cache: a Redis instance that
14 | # works as a caching layer.
15 | #
16 | version: "3"
17 |
18 | services:
19 |
20 | cache:
21 | image: cryptonic-cache:latest
22 | build:
23 | context: ./cryptonic-cache
24 | dockerfile: ./Dockerfile
25 | volumes:
26 | - $PWD/cache_data:/data
27 | networks:
28 | - cryptonic
29 |
30 | cryptonic:
31 | image: cryptonic:latest
32 | build:
33 | context: .
34 | dockerfile: ./Dockerfile
35 | ports:
36 | - "5000:5000"
37 | environment:
38 | - BITCOIN_START_DATE=2019-01-01
39 | - EPOCHS=50
40 | - PERIOD_SIZE=7
41 | volumes:
42 | - ./cryptonic_logs:/logs
43 | - ./models:/models
44 | env_file:
45 | - cryptonic.env
46 | depends_on:
47 | - cache
48 | networks:
49 | - cryptonic
50 |
51 | networks:
52 | cryptonic:
53 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/requirements.txt:
--------------------------------------------------------------------------------
1 | beautifulsoup4==4.6.0
2 | bleach==1.5.0
3 | certifi==2017.11.5
4 | chardet==3.0.4
5 | click==6.7
6 | colorama==0.3.9
7 | coverage==4.4.2
8 | enum34==1.1.6
9 | Flask==0.12.2
10 | Flask-API==1.0
11 | Flask-Caching==1.3.3
12 | Flask-Cors==3.0.3
13 | Flask-Testing==0.7.1
14 | h5py==2.7.1
15 | html5lib==0.9999999
16 | idna==2.6
17 | itsdangerous==0.24
18 | Jinja2==2.10
19 | Keras==2.1.2
20 | lxml==4.1.1
21 | Markdown==2.6.10
22 | MarkupSafe==1.0
23 | nose==1.3.7
24 | numpy
25 | pandas==0.25.3
26 | protobuf
27 | python-dateutil==2.6.1
28 | pytz==2017.3
29 | PyYAML==3.12
30 | redis==2.10.6
31 | rednose==1.2.3
32 | requests
33 | scipy==1.0.0
34 | six==1.11.0
35 | tensorboard==2.0.1
36 | tensorflow==2.0.0
37 | tensorflow-estimator==2.0.1
38 | termstyle==0.1.11
39 | urllib3==1.22
40 | yfinance
41 | Werkzeug==0.13
42 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/run.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | """
3 | Script for starting the Cryptonic Flask server.
4 | """
5 | import os
6 | import time
7 |
8 | from cryptonic.server import Server
9 |
10 |
11 | def main():
12 | """
13 | Wrapper function for starting a server.
14 | """
15 |
16 | print('Starting server.')
17 | server = Server()
18 |
19 | server.run(host=os.getenv("HOST", "0.0.0.0"))
20 |
21 | if __name__ == '__main__':
22 | main()
23 |
--------------------------------------------------------------------------------
/Chapter04/Exercise4.02/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/d503565ee073ce5baa776e4ea600134cb5cfaf31/Chapter04/Exercise4.02/screenshot.png
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Packt Workshops
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # The Applied TensorFlow and Keras Workshop
2 | [](https://github.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/issues)
3 | [](https://github.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/network)
4 | [](https://github.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/stargazers)
5 | [](https://github.com/PacktWorkshops/The-Applied-TensorFlow-and-Keras-Workshop/pulls)
6 | [](https://www.python.org/downloads/)
7 |
8 | This is the repository for [The Applied TensorFlow and Keras Workshop](https://www.amazon.com/Applied-TensorFlow-Keras-Workshop-real-world-ebook/dp/B08Q8F55ZS/ref=sr_1_1?dchild=1&keywords=The%20Applied%20TensorFlow%20and%20Keras%20Workshop&qid=1610976724&sr=8-1&utm_source=github&utm_medium=repository&utm_campaign=9781801078153&utm_term=Applied%20TensorFlow%20and%20Keras&utm_content=The%20Applied%20TensorFlow%20and%20Keras%20Workshop), published by [Packt](https://www.packtpub.com/?utm_source=github). It contains all the supporting project files necessary to work through the course from start to finish.
9 |
10 | ## Requirements and Setup
11 |
12 |
13 | To get started with the project files, you'll need to:
14 | 1. Install Jupyter on [Windows](https://www.python.org/downloads/windows/), [Mac](https://www.python.org/downloads/mac-osx/), [Linux](https://www.python.org/downloads/source/)
15 | 2. Install Anaconda on [Windows](https://www.anaconda.com/distribution/#windows), [Mac](https://www.anaconda.com/distribution/#macos), [Linux](https://www.anaconda.com/distribution/#linux)
16 |
17 | ## About The Applied TensorFlow and Keras Workshop
18 | [The Applied TensorFlow and Keras Workshop](https://www.amazon.com/Applied-TensorFlow-Keras-Workshop-real-world-ebook/dp/B08Q8F55ZS/ref=sr_1_1?dchild=1&keywords=The%20Applied%20TensorFlow%20and%20Keras%20Workshop&qid=1610976724&sr=8-1&utm_source=github&utm_medium=repository&utm_campaign=9781801078153&utm_term=Applied%20TensorFlow%20and%20Keras&utm_content=The%20Applied%20TensorFlow%20and%20Keras%20Workshop) provides you with a blueprint to build an application that generates predictions using a deep learning model. You’ll learn to apply techniques to improve the model: add more data and features, change its architecture, or create a new model by changing the core components to meet your own requirements.
19 |
20 | ## What you will learn
21 | * Familiarize yourself with the components of a neural network
22 | * Understand the different types of problems that can be solved using neural networks
23 | * Explore different ways to select the right architecture for your model
24 | * Make predictions with a trained model using TensorBoard
25 | * Discover the components of Keras and ways to leverage its features in your model
26 | * Explore how you can deal with new data by learning ways to retrain your model
27 |
28 | ## Related Workshops
29 | If you've found this repository useful, you might want to check out some of our other workshop titles:
30 | * [The Applied AI and Natural Language Processing Workshop](https://www.amazon.com/Applied-Natural-Language-Processing-Workshop-ebook/dp/B08Q8GNTGT/ref=sr_1_1?dchild=1&keywords=The%20Applied%20AI%20and%20Natural%20Language%20Processing%20Workshop&qid=1610976605&sr=8-1&utm_source=github&utm_medium=repository&utm_campaign=9781801071307&utm_term=Applied%20AI%20and%20Natural%20Language%20Processing&utm_content=The%20Applied%20AI%20and%20Natural%20Language%20Processing%20Workshop)
31 | * [The Deep Learning Workshop](https://www.amazon.com/Deep-Learning-Workshop-next-generation-TensorFlow-ebook/dp/B08Q8GP7DJ/ref=sr_1_2?dchild=1&keywords=The%20Deep%20Learning%20Workshop&qid=1611054533&sr=8-2&utm_source=GitHub&utm_medium=Repository&utm_campaign=9781801075169&utm_term=Deep%20Learning&utm_content=The%20Deep%20Learning%20Workshop)
32 | * [The Deep Learning with Keras Workshop](https://www.amazon.com/Deep-Learning-Keras-Workshop-network-ebook/dp/B08Q8JJ45N/ref=sr_1_1?dchild=1&keywords=The%20Deep%20Learning%20with%20Keras%20Workshop&qid=1611054389&sr=8-1&utm_source=GitHub&utm_medium=Repository&utm_campaign=9781801071185&utm_term=Deep%20Learning%20with%20Keras&utm_content=The%20Deep%20Learning%20with%20Keras%20Workshop)
33 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | absl-py==0.8.1
2 | astor==0.8.0
3 | attrs==19.3.0
4 | backcall==0.1.0
5 | beautifulsoup4==4.8.1
6 | bleach==3.1.0
7 | cachetools==3.1.1
8 | certifi==2019.9.11
9 | chardet==3.0.4
10 | Click==7.0
11 | cycler==0.10.0
12 | decorator==4.4.1
13 | defusedxml==0.6.0
14 | entrypoints==0.3
15 | Flask==1.1.1
16 | Flask-API==2.0
17 | Flask-Caching==1.8.0
18 | Flask-Cors==3.0.8
19 | Flask-Testing==0.7.1
20 | gast==0.2.2
21 | google-auth==1.7.0
22 | google-auth-oauthlib==0.4.1
23 | google-pasta==0.1.8
24 | graphviz==0.13.2
25 | grpcio==1.24.3
26 | h5py==2.10.0
27 | html5lib==1.0.1
28 | idna==2.8
29 | importlib-metadata==1.3.0
30 | ipykernel==5.1.3
31 | ipython==7.10.2
32 | ipython-genutils==0.2.0
33 | ipywidgets==7.5.1
34 | itsdangerous==1.1.0
35 | jedi==0.15.2
36 | Jinja2==2.10.3
37 | jsonschema==3.2.0
38 | jupyter==1.0.0
39 | jupyter-client==5.3.4
40 | jupyter-console==6.0.0
41 | jupyter-core==4.6.1
42 | Keras==2.2.4
43 | Keras-Applications==1.0.8
44 | Keras-Preprocessing==1.1.0
45 | kiwisolver==1.1.0
46 | Markdown==3.1.1
47 | MarkupSafe==1.1.1
48 | matplotlib==3.1.2
49 | mistune==0.8.4
50 | more-itertools==8.0.2
51 | nbconvert==5.6.1
52 | nbformat==4.4.0
53 | notebook==6.0.2
54 | numpy==1.17.3
55 | oauthlib==3.1.0
56 | opt-einsum==3.1.0
57 | pandas==0.25.3
58 | pandocfilters==1.4.2
59 | parso==0.5.2
60 | pexpect==4.7.0
61 | pickleshare==0.7.5
62 | prometheus-client==0.7.1
63 | prompt-toolkit==2.0.10
64 | protobuf==3.10.0
65 | ptyprocess==0.6.0
66 | pyasn1==0.4.7
67 | pyasn1-modules==0.2.7
68 | Pygments==2.5.2
69 | pyparsing==2.4.5
70 | pyrsistent==0.15.6
71 | python-dateutil==2.8.1
72 | pytz==2019.3
73 | PyYAML==5.2
74 | pyzmq==18.1.1
75 | qtconsole==4.6.0
76 | requests==2.22.0
77 | requests-oauthlib==1.2.0
78 | rsa==4.0
79 | scipy==1.4.1
80 | seaborn==0.9.0
81 | Send2Trash==1.5.0
82 | setuptools==41.0.0
83 | six==1.13.0
84 | soupsieve==1.9.5
85 | tensorboard==2.0.1
86 | tensorflow==2.0.0
87 | tensorflow-estimator==2.0.1
88 | termcolor==1.1.0
89 | terminado==0.8.3
90 | testpath==0.4.4
91 | tornado==6.0.3
92 | tqdm==4.41.0
93 | traitlets==4.3.3
94 | urllib3==1.25.6
95 | wcwidth==0.1.7
96 | webencodings==0.5.1
97 | Werkzeug==0.16.0
98 | widgetsnbextension==3.5.1
99 | wrapt==1.11.2
100 | yfinance==0.1.54
101 | zipp==0.6.0
102 |
--------------------------------------------------------------------------------