gathered resources, working on report

This commit is contained in:
aj 2021-01-01 18:53:11 +00:00
parent 534b42f4ef
commit 735275d7ae
15 changed files with 1331 additions and 126 deletions

View File

@ -1,4 +1,13 @@
Hidden Markov Models Hidden Markov Models
==================== ====================
Speech recognition coursework focusing on training and analysing hidden markov models Speech recognition coursework focusing on training and analysing hidden markov models.
![PDFs with observations marked](report/res/pdfs-w-obs.png)
Probability density functions with provided observations marked
![Occupation likelihoods](report/res/occupation-line.png)
Occupation likelihoods for each state through time
![Training iterations](report/res/iterated-pdfs.png)
Output Gaussian functions through 5 iterations of Baum-Welch training

File diff suppressed because one or more lines are too long

View File

@ -7,10 +7,10 @@ class MarkovModel:
def __init__(self, states: list, observations: list = list(), state_transitions: list = list()): def __init__(self, states: list, observations: list = list(), state_transitions: list = list()):
self.observations = observations self.observations = observations
self.state_transitions = state_transitions # use state number not state index, is padded by entry and exit probs self.state_transitions = state_transitions
# ^ use state number not state index, is padded by entry and exit probs
self.states = states # number of states self.states = states
# self.timesteps = list()
self.forward = np.zeros((len(states), len(observations))) self.forward = np.zeros((len(states), len(observations)))
self.p_obs_forward = 0 self.p_obs_forward = 0
@ -54,16 +54,21 @@ class MarkovModel:
def populate_forward(self): def populate_forward(self):
"""Populate forward likelihoods for all states/times""" """Populate forward likelihoods for all states/times"""
for t, observation in enumerate(self.observations):
# iterate through observations (time)
for state_index, state in enumerate(self.states):
# both states at each step
for t, observation in enumerate(self.observations): # iterate through observations (time) state_number = state_index + 1
for state_index, state in enumerate(self.states): # both states at each step # ^ for easier reading (arrays 0-indexed, _number 1-indexed)
state_number = state_index + 1 # for easier reading (arrays 0-indexed, numbers start at 1)
if t == 0: # calcualte initial, 0 = first row = initial if t == 0: # calcualte initial, 0 = first row = initial
self.forward[state_index, t] = self.state_transitions[0, state_number] * gaussian(observation, state.mean, state.std_dev) self.forward[state_index, t] = self.state_transitions[0, state_number] * gaussian(observation, state.mean, state.std_dev)
else: else:
# each state for each time has two paths leading to it, the same state (this) and the other state (other) # each state for each time has two paths leading to it,
# the same state (this) and the other state (other)
other_index = self.get_other_state_index(state_index) other_index = self.get_other_state_index(state_index)
other_number = other_index + 1 # for 1 indexing other_number = other_index + 1 # for 1 indexing
@ -81,7 +86,8 @@ class MarkovModel:
sum = 0 sum = 0
for state_index, final_likelihood in enumerate(self.forward[:, -1]): for state_index, final_likelihood in enumerate(self.forward[:, -1]):
sum += final_likelihood * self.state_transitions[state_index + 1, -1] # get exit prob from state transitions sum += final_likelihood * self.state_transitions[state_index + 1, -1]
# get exit prob from state transitions ^
self.p_obs_forward = sum self.p_obs_forward = sum
return sum return sum
@ -92,13 +98,16 @@ class MarkovModel:
# initialise with exit probabilities # initialise with exit probabilities
self.backward[:, -1] = self.state_transitions[1:len(self.states) + 1, -1] self.backward[:, -1] = self.state_transitions[1:len(self.states) + 1, -1]
# below iterator skips first observation (will be used when finalising P(O|model)) then reverses list [::-1] # below iterator skips first observation
for t, observation in list(enumerate(self.observations[1:]))[::-1]: # iterate backwards through observations (time) # (will be used when finalising P(O|model))
# iterate backwards through observations (time) [::-1] <- reverses list
for t, observation in list(enumerate(self.observations[1:]))[::-1]:
# print(t, observation) # print(t, observation)
for state_index in range(len(self.states)): for state_index in range(len(self.states)):
state_number = state_index + 1 # for easier reading (arrays 0-indexed, numbers start at 1) state_number = state_index + 1
# ^ for easier reading (arrays 0-indexed, _number 1-indexed)
other_index = self.get_other_state_index(state_index) other_index = self.get_other_state_index(state_index)
other_number = other_index + 1 # for 1 indexing other_number = other_index + 1 # for 1 indexing
@ -123,7 +132,9 @@ class MarkovModel:
for state_index, initial_likelihood in enumerate(self.backward[:, 0]): for state_index, initial_likelihood in enumerate(self.backward[:, 0]):
pi = self.state_transitions[0, state_index + 1] pi = self.state_transitions[0, state_index + 1]
b = gaussian(self.observations[0], self.states[state_index].mean, self.states[state_index].std_dev) b = gaussian(self.observations[0],
self.states[state_index].mean,
self.states[state_index].std_dev)
beta = initial_likelihood beta = initial_likelihood
sum += pi * b * beta sum += pi * b * beta
@ -134,7 +145,9 @@ class MarkovModel:
def populate_occupation(self): def populate_occupation(self):
"""Populate occupation likelihoods for all states/times""" """Populate occupation likelihoods for all states/times"""
for t in range(len(self.observations)): # iterate through observations (time) for t in range(len(self.observations)):
# iterate through observations (time)
for state_index in range(len(self.states)): for state_index in range(len(self.states)):
forward_backward = self.forward[state_index, t] * self.backward[state_index, t] forward_backward = self.forward[state_index, t] * self.backward[state_index, t]
@ -152,7 +165,9 @@ class MarkovModel:
forward = self.forward[from_index, t - 1] forward = self.forward[from_index, t - 1]
transition = self.state_transitions[from_index + 1, to_index + 1] transition = self.state_transitions[from_index + 1, to_index + 1]
emission = gaussian(self.observations[t], self.states[to_index].mean, self.states[to_index].std_dev) emission = gaussian(self.observations[t],
self.states[to_index].mean,
self.states[to_index].std_dev)
backward = self.backward[to_index, t] backward = self.backward[to_index, t]
return (forward * transition * emission * backward) / self.observation_likelihood return (forward * transition * emission * backward) / self.observation_likelihood
@ -173,8 +188,10 @@ class MarkovModel:
for to_index in range(length): for to_index in range(length):
# numerator iterates from t = 1 (when 0 indexing, 2 in the notes) # numerator iterates from t = 1 (when 0 indexing, 2 in the notes)
transition_sum = sum(self.transition_likelihood(from_index, to_index, t) for t in range(1, len(self.observations))) transition_sum = sum(self.transition_likelihood(from_index, to_index, t)
occupation_sum = sum(self.occupation[from_index, t] for t in range(0, len(self.observations))) for t in range(1, len(self.observations)))
occupation_sum = sum(self.occupation[from_index, t]
for t in range(0, len(self.observations)))
new_transitions[from_index, to_index] = transition_sum / occupation_sum new_transitions[from_index, to_index] = transition_sum / occupation_sum
@ -185,7 +202,8 @@ class MarkovModel:
numerator = 0 # sum over observations( occupation * observation ) numerator = 0 # sum over observations( occupation * observation )
denominator = 0 # sum over observations( occupation ) denominator = 0 # sum over observations( occupation )
for t, observation in enumerate(self.observations): # iterate through observations (time) for t, observation in enumerate(self.observations):
# iterate through observations (time)
occupation_likelihood = self.occupation[state_index, t] occupation_likelihood = self.occupation[state_index, t]
@ -204,7 +222,8 @@ class MarkovModel:
numerator = 0 # sum over observations( occupation * (observation - mean)^2 ) numerator = 0 # sum over observations( occupation * (observation - mean)^2 )
denominator = 0 # sum over observations( occupation ) denominator = 0 # sum over observations( occupation )
for t, observation in enumerate(self.observations): # iterate through observations (time) for t, observation in enumerate(self.observations):
# iterate through observations (time)
occupation_likelihood = self.occupation[state_index, t] occupation_likelihood = self.occupation[state_index, t]

View File

@ -1,7 +1,11 @@
# To add a new cell, type '# %%'
# To add a new markdown cell, type '# %% [markdown]'
# %% # %%
#IMPORTS AND COMMON VARIABLES #IMPORTS AND COMMON VARIABLES
import matplotlib
import matplotlib.cm as cm
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from matplotlib import cm from matplotlib.pyplot import savefig
import numpy as np import numpy as np
from math import sqrt from math import sqrt
@ -10,7 +14,10 @@ from maths import gaussian
from markov import MarkovModel from markov import MarkovModel
from markovlog import LogMarkovModel from markovlog import LogMarkovModel
x = np.linspace(-4, 8, 120) # x values for figures fig_dpi = 200
fig_export = False
x = np.linspace(-4, 8, 300) # x values for figures
x_label = "Observation Space" x_label = "Observation Space"
y_label = "Probability Density" y_label = "Probability Density"
@ -32,6 +39,11 @@ plt.xlabel(x_label)
plt.ylabel(y_label) plt.ylabel(y_label)
plt.grid(linestyle="--") plt.grid(linestyle="--")
fig = matplotlib.pyplot.gcf()
fig.set_dpi(fig_dpi)
fig.set_tight_layout(True)
if fig_export:
savefig("report/res/pdfs.png")
plt.show() plt.show()
# %% [markdown] # %% [markdown]
@ -40,7 +52,8 @@ plt.show()
# %% # %%
for obs in observations: for obs in observations:
print(f'{obs} -> State 1: {gaussian(obs, state1.mean, state1.std_dev)}, State 2: {gaussian(obs, state2.mean, state2.std_dev)}') print(f'{obs} -> State 1: {gaussian(obs, state1.mean, state1.std_dev)},',
'State 2: {gaussian(obs, state2.mean, state2.std_dev)}')
# %% # %%
@ -55,7 +68,7 @@ plt.title("State Probability Density Functions With Observations")
plt.xlabel(x_label) plt.xlabel(x_label)
plt.ylabel(y_label) plt.ylabel(y_label)
plt.grid(linestyle="--") plt.grid(linestyle="--", axis='y')
state1_pd = [gaussian(i, state1.mean, state1.std_dev) for i in observations] state1_pd = [gaussian(i, state1.mean, state1.std_dev) for i in observations]
state2_pd = [gaussian(i, state2.mean, state2.std_dev) for i in observations] state2_pd = [gaussian(i, state2.mean, state2.std_dev) for i in observations]
@ -69,16 +82,24 @@ config = {
"marker": 'x' "marker": 'x'
} }
[plt.axvline(x=i, ls='--', lw=1.0, c=(0,0,0), alpha=0.4) for i in observations]
plt.scatter(observations, state1_pd, color=(0.5, 0, 0), **config) plt.scatter(observations, state1_pd, color=(0.5, 0, 0), **config)
plt.scatter(observations, state2_pd, color=(0, 0, 0.5), **config) plt.scatter(observations, state2_pd, color=(0, 0, 0.5), **config)
fig = matplotlib.pyplot.gcf()
fig.set_dpi(fig_dpi)
fig.set_tight_layout(True)
if fig_export:
savefig("report/res/pdfs-w-obs.png")
plt.show() plt.show()
# %% [markdown] # %% [markdown]
# # Forward Procedure (3) # # Forward Procedure (3)
# %% # %%
model = MarkovModel(states=[state1, state2], observations=observations, state_transitions=state_transition) model = MarkovModel(states=[state1, state2],
observations=observations,
state_transitions=state_transition)
model.populate_forward() model.populate_forward()
print(model.forward) print(model.forward)
@ -86,11 +107,42 @@ print(model.forward)
forward = model.forward forward = model.forward
model.calculate_p_obs_forward() model.calculate_p_obs_forward()
# %%
model = MarkovModel(states=[state1, state2],
observations=observations,
state_transitions=state_transition).populate()
state_x = np.arange(1, 10)
from numpy import log as ln
plt.plot(state_x, [ln(i) for i in model.forward[0, :]], c='r', label="State 1")
plt.plot(state_x, [ln(i) for i in model.forward[1, :]], c='b', label="State 2")
plt.ylim(top=0)
plt.legend()
plt.title("Forward Log-Likelihoods Over Time")
plt.xlabel("Observation (t)")
plt.ylabel("Log Likelihood")
plt.grid(linestyle="--")
fig = matplotlib.pyplot.gcf()
fig.set_dpi(fig_dpi)
fig.set_tight_layout(True)
if fig_export:
savefig("report/res/forward-logline.png")
plt.show()
# %% [markdown] # %% [markdown]
# # Backward Procedure (4) # # Backward Procedure (4)
# %% # %%
model = MarkovModel(states=[state1, state2], observations=observations, state_transitions=state_transition) model = MarkovModel(states=[state1, state2],
observations=observations,
state_transitions=state_transition)
model.populate_backward() model.populate_backward()
print(model.backward) print(model.backward)
@ -98,11 +150,42 @@ print(model.backward)
backward = model.backward backward = model.backward
model.calculate_p_obs_backward() model.calculate_p_obs_backward()
# %%
model = MarkovModel(states=[state1, state2],
observations=observations,
state_transitions=state_transition).populate()
state_x = np.arange(1, 10)
from numpy import log as ln
plt.plot(state_x, [ln(i) for i in model.backward[0, :]], c='r', label="State 1")
plt.plot(state_x, [ln(i) for i in model.backward[1, :]], c='b', label="State 2")
plt.ylim(top=0)
plt.legend()
plt.title("Backward Log-Likelihoods Over Time")
plt.xlabel("Observation (t)")
plt.ylabel("Log Likelihood")
plt.grid(linestyle="--")
fig = matplotlib.pyplot.gcf()
fig.set_dpi(fig_dpi)
fig.set_tight_layout(True)
if fig_export:
savefig("report/res/backward-logline.png")
plt.show()
# %% [markdown] # %% [markdown]
# # Compare Forward/Backward Final # # Compare Forward/Backward Final
# %% # %%
model = MarkovModel(states=[state1, state2], observations=observations, state_transitions=state_transition) model = MarkovModel(states=[state1, state2],
observations=observations,
state_transitions=state_transition)
model.populate_forward() model.populate_forward()
model.populate_backward() model.populate_backward()
@ -115,16 +198,81 @@ print("diff: ", model.p_obs_forward - model.p_obs_backward)
# # Occupation Likelihoods (5) # # Occupation Likelihoods (5)
# %% # %%
model = MarkovModel(states=[state1, state2], observations=observations, state_transitions=state_transition).populate() model = MarkovModel(states=[state1, state2],
observations=observations,
state_transitions=state_transition).populate()
occupation = model.occupation occupation = model.occupation
print(model.occupation) print(model.occupation)
# %%
model = MarkovModel(states=[state1, state2],
observations=observations,
state_transitions=state_transition).populate()
fig = plt.figure(figsize=(6,6), dpi=fig_dpi, tight_layout=True)
ax = fig.add_subplot(1, 1, 1, projection="3d", xmargin=0, ymargin=0)
y_width = 0.3
X = np.arange(1, 10) - 0.5
Y = np.arange(1, 3) - 0.5*y_width
X, Y = np.meshgrid(X, Y)
Z = np.zeros(model.forward.size)
dx = np.ones(model.forward.size)
dy = y_width * np.ones(model.forward.size)
colours = [*[(1.0, 0.1, 0.1) for i in range(9)], *[(0.2, 0.2, 1.0) for i in range(9)]]
ax.bar3d(X.flatten(), Y.flatten(), Z,
dx, dy, model.occupation.flatten(),
color=colours, shade=True)
ax.set_yticks([1, 2])
ax.set_zlim(top=1.0)
ax.set_title("Occupation Likelihoods Over Time")
ax.set_xlabel("Observation")
ax.set_ylabel("State")
ax.set_zlabel("Occupation Likelihood")
ax.view_init(35, -72)
if fig_export:
savefig("report/res/occupation-bars.png")
fig.show()
# %%
model = MarkovModel(states=[state1, state2],
observations=observations,
state_transitions=state_transition).populate()
state_x = np.arange(1, 10)
plt.plot(state_x, model.occupation[0, :], c='r', label="State 1")
plt.plot(state_x, model.occupation[1, :], c='b', label="State 2")
plt.legend()
plt.title("Occupation Likelihoods Over Time")
plt.xlabel("Observation (t)")
plt.ylabel("Occupation Likelihood")
plt.grid(linestyle="--")
fig = matplotlib.pyplot.gcf()
fig.set_dpi(fig_dpi)
fig.set_tight_layout(True)
if fig_export:
savefig("report/res/occupation-line.png")
plt.show()
# %% [markdown] # %% [markdown]
# # Re-estimate Mean & Variance (6) # # Re-estimate Mean & Variance (6)
# %% # %%
model = MarkovModel(states=[state1, state2], observations=observations, state_transitions=state_transition).populate() model = MarkovModel(states=[state1, state2],
observations=observations,
state_transitions=state_transition).populate()
print("mean: ", [state1.mean, state2.mean]) print("mean: ", [state1.mean, state2.mean])
print("variance: ", [state1.variance, state2.variance]) print("variance: ", [state1.variance, state2.variance])
@ -138,7 +286,9 @@ print("variance: ", model.reestimated_variance())
# =================== # ===================
# %% # %%
model = MarkovModel(states=[state1, state2], observations=observations, state_transitions=state_transition).populate() model = MarkovModel(states=[state1, state2],
observations=observations,
state_transitions=state_transition).populate()
new_mean = model.reestimated_mean() new_mean = model.reestimated_mean()
new_var = model.reestimated_variance() new_var = model.reestimated_variance()
@ -157,13 +307,17 @@ plt.xlabel(x_label)
plt.ylabel(y_label) plt.ylabel(y_label)
plt.grid(linestyle="--") plt.grid(linestyle="--")
fig = matplotlib.pyplot.gcf()
fig.set_dpi(fig_dpi)
plt.show() plt.show()
# %% [markdown] # %% [markdown]
# # Compare PDFs (7) # # Compare PDFs (7)
# %% # %%
model = MarkovModel(states=[state1, state2], observations=observations, state_transitions=state_transition).populate() model = MarkovModel(states=[state1, state2],
observations=observations,
state_transitions=state_transition).populate()
new_mean = model.reestimated_mean() new_mean = model.reestimated_mean()
new_var = model.reestimated_variance() new_var = model.reestimated_variance()
@ -192,6 +346,11 @@ plt.xlabel(x_label)
plt.ylabel(y_label) plt.ylabel(y_label)
plt.grid(linestyle="--") plt.grid(linestyle="--")
fig = matplotlib.pyplot.gcf()
fig.set_dpi(fig_dpi)
fig.set_tight_layout(True)
if fig_export:
savefig("report/res/re-est-pdfs.png")
plt.show() plt.show()
# %% [markdown] # %% [markdown]
@ -206,8 +365,12 @@ var = [state1.variance, state2.variance]
plt.plot(x, [gaussian(i, mean[0], sqrt(var[0])) for i in x], '--', c='r', linewidth=1.0) plt.plot(x, [gaussian(i, mean[0], sqrt(var[0])) for i in x], '--', c='r', linewidth=1.0)
plt.plot(x, [gaussian(i, mean[1], sqrt(var[1])) for i in x], '--', c='b', linewidth=1.0) plt.plot(x, [gaussian(i, mean[1], sqrt(var[1])) for i in x], '--', c='b', linewidth=1.0)
label1=None
label2=None
for i in range(iterations): for i in range(iterations):
model = MarkovModel(states=[State(mean[0], var[0], state1.entry, state1.exit), State(mean[1], var[1], state2.entry, state2.exit)], model = MarkovModel(states=[State(mean[0], var[0], state1.entry, state1.exit),
State(mean[1], var[1], state2.entry, state2.exit)],
observations=observations, observations=observations,
state_transitions=state_transition) state_transitions=state_transition)
model.populate() model.populate()
@ -227,29 +390,35 @@ for i in range(iterations):
if i == iterations - 1: if i == iterations - 1:
style = '-' style = '-'
linewidth = 2.0 linewidth = 2.0
label1='State 1'
label2='State 2'
plt.plot(x, state_1_y, style, c='r', linewidth=linewidth) plt.plot(x, state_1_y, style, c='r', label=label1, linewidth=linewidth)
plt.plot(x, state_2_y, style, c='b', linewidth=linewidth) plt.plot(x, state_2_y, style, c='b', label=label2, linewidth=linewidth)
plt.title("Probability Density Function Iterations") plt.title("Probability Density Function Iterations")
plt.xlabel(x_label) plt.xlabel(x_label)
plt.ylabel(y_label) plt.ylabel(y_label)
plt.grid(linestyle="--") plt.grid(linestyle="--")
plt.legend()
fig = matplotlib.pyplot.gcf()
fig.set_dpi(fig_dpi)
fig.set_tight_layout(True)
if fig_export or True:
savefig("report/res/iterated-pdfs.png")
plt.show() plt.show()
# %% [markdown] # %% [markdown]
# # Baum-Welch State Transition Re-estimations # # Baum-Welch State Transition Re-estimations
# %% # %%
model = MarkovModel(states=[state1, state2], observations=observations, state_transitions=state_transition).populate() model = MarkovModel(states=[state1, state2],
observations=observations,
state_transitions=state_transition).populate()
print(a_matrix) print(a_matrix)
model.reestimated_state_transitions() model.reestimated_state_transitions()
# %%

View File

@ -1,3 +1,4 @@
% Encoding: UTF-8
@misc{towards-data-science-markov-intro, @misc{towards-data-science-markov-intro,
author = {Rocca, Joseph}, author = {Rocca, Joseph},
howpublished = {Online}, howpublished = {Online},
@ -9,3 +10,42 @@
year = {2019} year = {2019}
} }
@Article{numpy,
author = {Charles R. Harris and K. Jarrod Millman and St{'{e}}fan J. van der Walt and Ralf Gommers and Pauli Virtanen and David Cournapeau and Eric Wieser and Julian Taylor and Sebastian Berg and Nathaniel J. Smith and Robert Kern and Matti Picus and Stephan Hoyer and Marten H. van Kerkwijk and Matthew Brett and Allan Haldane and Jaime Fern{'{a}}ndez del R{'{\i}}o and Mark Wiebe and Pearu Peterson and Pierre G{'{e}}rard-Marchant and Kevin Sheppard and Tyler Reddy and Warren Weckesser and Hameer Abbasi and Christoph Gohlke and Travis E. Oliphant},
journal = {Nature},
title = {Array programming with {NumPy}},
year = {2020},
month = sep,
number = {7825},
pages = {357--362},
volume = {585},
doi = {10.1038/s41586-020-2649-2},
publisher = {Springer Science and Business Media {LLC}},
url = {https://doi.org/10.1038/s41586-020-2649-2},
urldate = {2021-1-1},
}
@Misc{python,
author = {Van Rossum, Guido and others},
howpublished = {Online},
title = {Python 3 Documentation},
year = {2008},
url = {https://docs.python.org/3/},
urldate = {2021-1-1},
}
@InProceedings{jupyter,
author = {Thomas Kluyver and Benjamin Ragan-Kelley and Fernando P{\'e}rez and Brian Granger and Matthias Bussonnier and Jonathan Frederic and Kyle Kelley and Jessica Hamrick and Jason Grout and Sylvain Corlay and Paul Ivanov and Dami{\'a}n Avila and Safia Abdalla and Carol Willing and Jupyter development team},
booktitle = {Positioning and Power in Academic Publishing: Players, Agents and Agendas},
title = {Jupyter Notebooks - a publishing format for reproducible computational workflows},
year = {2016},
address = {Netherlands},
editor = {Fernando Loizides and Birgit Scmidt},
pages = {87--90},
publisher = {IOS Press},
abstract = {It is increasingly necessary for researchers in all fields to write computer code, and in order to reproduce research results, it is important that this code is published. We present Jupyter notebooks, a document format for publishing code, results and explanations in a form that is both readable and executable. We discuss various tools and use cases for notebook documents.},
url = {https://eprints.soton.ac.uk/403913/},
urldate = {2021-1-1},
}
@Comment{jabref-meta: databaseType:bibtex;}

View File

@ -10,6 +10,7 @@
\let\endchangemargin=\endlist \let\endchangemargin=\endlist
\pagenumbering{roman} \pagenumbering{roman}
\usepackage{pxfonts}
\usepackage{color} \usepackage{color}
\definecolor{commentgreen}{RGB}{0,94,11} \definecolor{commentgreen}{RGB}{0,94,11}
@ -21,7 +22,6 @@
customHeadersFooters customHeadersFooters
minimalistic minimalistic
todonotes todonotes
figs-within-sections
\end_modules \end_modules
\maintain_unincluded_children false \maintain_unincluded_children false
\language english \language english
@ -105,7 +105,7 @@ figs-within-sections
\papercolumns 1 \papercolumns 1
\papersides 1 \papersides 1
\paperpagestyle fancy \paperpagestyle fancy
\listings_params "language=Python,breaklines=true,frame=tb,otherkeywords={self},emph={State},emphstyle={\ttb\color{darkred}},basicstyle={\ttfamily},commentstyle={\color{commentgreen}\itshape},keywordstyle={\color{darkblue}},emphstyle={\color{red}},stringstyle={\color{red}}" \listings_params "language=Python,breaklines=true,frame=tb,otherkeywords={self},emph={State},emphstyle={\ttb\color{darkred}},basicstyle={\ttfamily},commentstyle={\bfseries\color{commentgreen}\itshape},keywordstyle={\color{darkblue}},emphstyle={\color{red}},stringstyle={\color{red}}"
\bullet 1 0 9 -1 \bullet 1 0 9 -1
\bullet 2 0 24 -1 \bullet 2 0 24 -1
\tracking_changes false \tracking_changes false
@ -418,7 +418,7 @@ noprefix "false"
\end_layout \end_layout
\begin_layout Standard \begin_layout Standard
As previously mentioned, the states are described 1D continuous probability As previously mentioned, the states are described by 1D continuous probability
density functions (PDF) of a Gaussian profile. density functions (PDF) of a Gaussian profile.
Each has an associated mean and variance as seen below, Each has an associated mean and variance as seen below,
\end_layout \end_layout
@ -557,7 +557,27 @@ Finally, a set of observations from the above model are provided below,
\begin_layout Standard \begin_layout Standard
These are used as the basis for training the model using the Baum-Welch These are used as the basis for training the model using the Baum-Welch
equations. equations
\begin_inset Flex TODO Note (Margin)
status open
\begin_layout Plain Layout
Expectation-maximisation
\end_layout
\end_inset
\begin_inset Flex TODO Note (Margin)
status open
\begin_layout Plain Layout
Cite
\end_layout
\end_inset
.
\end_layout \end_layout
\begin_layout Section \begin_layout Section
@ -611,6 +631,53 @@ name "fig:State-topology"
\end_layout \end_layout
\begin_layout Standard
The work was completed using Python
\begin_inset CommandInset citation
LatexCommand cite
key "python"
literal "false"
\end_inset
and the Jupyter notebook
\begin_inset CommandInset citation
LatexCommand cite
key "jupyter"
literal "false"
\end_inset
.
Apart from the standard library, NumPy
\begin_inset CommandInset citation
LatexCommand cite
key "numpy"
literal "false"
\end_inset
was used for a n-dimensional array implementation.
\end_layout
\begin_layout Standard
An implementation of the Gaussian function was written in order to derive
output probability densities for each state given an observation, see listing
\begin_inset CommandInset ref
LatexCommand ref
reference "maths-listing"
plural "false"
caps "false"
noprefix "false"
\end_inset
.
This was used to plot each of the PDFs and throughout the likelihood calculatio
ns.
\end_layout
\begin_layout Section \begin_layout Section
Results Results
\end_layout \end_layout
@ -619,6 +686,21 @@ Results
Output Probability Density Functions Output Probability Density Functions
\end_layout \end_layout
\begin_layout Standard
The Gaussian probability functions described by the initial parameters can
be seen in figure
\begin_inset CommandInset ref
LatexCommand ref
reference "fig:PDFs"
plural "false"
caps "false"
noprefix "false"
\end_inset
.
\end_layout
\begin_layout Standard \begin_layout Standard
\begin_inset Float figure \begin_inset Float figure
wide false wide false
@ -630,7 +712,8 @@ status open
\align center \align center
\begin_inset Graphics \begin_inset Graphics
filename res/pdfs.png filename res/pdfs.png
width 50col% lyxscale 50
width 70col%
\end_inset \end_inset
@ -669,6 +752,33 @@ name "fig:PDFs"
Observation Probability Densities Observation Probability Densities
\end_layout \end_layout
\begin_layout Standard
The output probability densities for each observation in each state can
be seen in table
\begin_inset CommandInset ref
LatexCommand ref
reference "tab:obs-prob-dens"
plural "false"
caps "false"
noprefix "false"
\end_inset
.
These observations can be seen overlaid on the original PDFs in figure
\begin_inset CommandInset ref
LatexCommand ref
reference "fig:PDFs-w-obs"
plural "false"
caps "false"
noprefix "false"
\end_inset
.
\end_layout
\begin_layout Standard \begin_layout Standard
\begin_inset Float table \begin_inset Float table
wide false wide false
@ -1161,7 +1271,8 @@ status open
\align center \align center
\begin_inset Graphics \begin_inset Graphics
filename res/pdfs-w-obs.png filename res/pdfs-w-obs.png
width 50col% lyxscale 50
width 70col%
\end_inset \end_inset
@ -1206,6 +1317,50 @@ name "fig:PDFs-w-obs"
Forward Procedure and Likelihoods Forward Procedure and Likelihoods
\end_layout \end_layout
\begin_layout Standard
The forward likelihoods calculated as part of the forward procedure can
be seen in figure
\begin_inset CommandInset ref
LatexCommand ref
reference "tab:Forward-likelihoods"
plural "false"
caps "false"
noprefix "false"
\end_inset
.
The natural logarithm of these results can be seen graphically in figure
\begin_inset CommandInset ref
LatexCommand ref
reference "fig:forward-log-like"
plural "false"
caps "false"
noprefix "false"
\end_inset
.
The log-likelihoods were used here as subsequent values can decrease by
orders of magnitude making it hard to display, as a monotonic function,
the relationship between values remains relevant when presenting the log
of each value
\begin_inset Flex TODO Note (Margin)
status open
\begin_layout Plain Layout
Reword?
\end_layout
\end_inset
.
For state 1, the forward likelihood generally decreases over time, this
pattern is not followed by state 2.
State 2 begins decreasing before rapidly decreasing and increasing.
\end_layout
\begin_layout Standard \begin_layout Standard
\begin_inset Float table \begin_inset Float table
wide false wide false
@ -1620,7 +1775,41 @@ name "tab:Forward-likelihoods"
\end_layout \end_layout
\end_inset
\end_layout
\begin_layout Standard
\begin_inset Float figure
wide false
sideways false
status open
\begin_layout Plain Layout \begin_layout Plain Layout
\noindent
\align center
\begin_inset Graphics
filename res/forward-logline.png
lyxscale 50
width 50col%
\end_inset
\end_layout
\begin_layout Plain Layout
\begin_inset Caption Standard
\begin_layout Plain Layout
Forward log-likelihood for each state over all observations
\begin_inset CommandInset label
LatexCommand label
name "fig:forward-log-like"
\end_inset
\end_layout \end_layout
@ -1629,10 +1818,76 @@ name "tab:Forward-likelihoods"
\end_layout \end_layout
\end_inset
\end_layout
\begin_layout Standard
Using the forward procedure, the observation likelihood,
\begin_inset Formula $P\left(\mathcal{O}|\lambda\right)$
\end_inset
, was calculated as follows
\end_layout
\begin_layout Standard
\begin_inset Formula
\begin{equation}
P\left(\mathcal{O}|\lambda\right)=\eta_{1}\alpha_{9}\left(1\right)+\eta_{2}\alpha_{9}\left(2\right)\label{eq:forward-symbolic}
\end{equation}
\end_inset
\end_layout
\begin_layout Standard
\begin_inset Formula
\begin{equation}
P\left(\mathcal{O}|\lambda\right)=\left(0.02\cdot5.63\times10^{-10}\right)+\left(0.03\cdot6.02\times10^{-9}\right)=1.92\times10^{-10}\label{eq:forward}
\end{equation}
\end_inset
to 2 decimal places.
\end_layout
\begin_layout Subsection \begin_layout Subsection
Backward Procedure and Likelihoods Backward Procedure and Likelihoods
\end_layout \end_layout
\begin_layout Standard
The backward likelihoods were calculated as part of the backwards procedure
and can be seen in table
\begin_inset CommandInset ref
LatexCommand ref
reference "tab:Backward-likelihoods"
plural "false"
caps "false"
noprefix "false"
\end_inset
, the log-likelihoods can be seen in figure
\begin_inset CommandInset ref
LatexCommand ref
reference "fig:backward-log-like"
plural "false"
caps "false"
noprefix "false"
\end_inset
.
Reading backwards in time (from bottom to top), for both states the backwards
likelihood can be seen to decrease to a minimum at
\begin_inset Formula $t=1$
\end_inset
.
\end_layout
\begin_layout Standard \begin_layout Standard
\begin_inset Float table \begin_inset Float table
wide false wide false
@ -2055,14 +2310,130 @@ name "tab:Backward-likelihoods"
\end_layout \end_layout
\begin_layout Subsection \begin_layout Standard
Observations Likelihood \begin_inset Float figure
wide false
sideways false
status open
\begin_layout Plain Layout
\noindent
\align center
\begin_inset Graphics
filename res/backward-logline.png
lyxscale 50
width 50col%
\end_inset
\end_layout
\begin_layout Plain Layout
\begin_inset Caption Standard
\begin_layout Plain Layout
Backward log-likelihood for each state over all observations
\begin_inset CommandInset label
LatexCommand label
name "fig:backward-log-like"
\end_inset
\end_layout
\end_inset
\end_layout
\end_inset
\end_layout
\begin_layout Standard
Finalising the backward procedure can also produce
\begin_inset Formula $P\left(\mathcal{O}|\lambda\right)$
\end_inset
,
\end_layout
\begin_layout Standard
\begin_inset Formula
\begin{equation}
P\left(\mathcal{O}|\lambda\right)=\pi_{1}b_{1}\left(o_{1}\right)\beta_{1}\left(1\right)+\pi_{2}b_{2}\left(o_{1}\right)\beta_{1}\left(2\right)\label{eq:backward-symbolic}
\end{equation}
\end_inset
\end_layout
\begin_layout Standard
\begin_inset Formula
\begin{equation}
P\left(\mathcal{O}|\lambda\right)=\left(0.44\cdot0.022\cdot6.58\times10^{-11}\right)+\left(0.56\cdot0.55\cdot6.25\times10^{-10}\right)=1.92\times10^{-10}\label{eq:backward}
\end{equation}
\end_inset
to 2 decimal places.
Looking back to equation
\begin_inset CommandInset ref
LatexCommand ref
reference "eq:forward"
plural "false"
caps "false"
noprefix "false"
\end_inset
, these can be seen to be the same, as expected
\begin_inset Flex TODO Note (Margin)
status open
\begin_layout Plain Layout
Maybe move to discussion?
\end_layout
\end_inset
.
\end_layout \end_layout
\begin_layout Subsection \begin_layout Subsection
Occupation Likelihoods Occupation Likelihoods
\end_layout \end_layout
\begin_layout Standard
The above forward and backward likelihoods were used to calculate the occupation
likelihoods of each state at each time step, the results can be seen in
table
\begin_inset CommandInset ref
LatexCommand ref
reference "tab:Occupation-likelihoods"
plural "false"
caps "false"
noprefix "false"
\end_inset
and are presented graphically in figure
\begin_inset CommandInset ref
LatexCommand ref
reference "fig:occupation-likelihood-bars"
plural "false"
caps "false"
noprefix "false"
\end_inset
.
\end_layout
\begin_layout Standard \begin_layout Standard
\begin_inset Float table \begin_inset Float table
wide false wide false
@ -2438,6 +2809,49 @@ name "tab:Occupation-likelihoods"
\end_inset \end_inset
\end_layout
\begin_layout Standard
\begin_inset Float figure
wide false
sideways false
status open
\begin_layout Plain Layout
\noindent
\align center
\begin_inset Graphics
filename res/occupation-line.png
lyxscale 50
width 70col%
\end_inset
\end_layout
\begin_layout Plain Layout
\begin_inset Caption Standard
\begin_layout Plain Layout
Occupation likelihoods for each state for each observation
\begin_inset CommandInset label
LatexCommand label
name "fig:occupation-likelihood-bars"
\end_inset
\end_layout
\end_inset
\end_layout
\end_inset
\end_layout \end_layout
\begin_layout Subsection \begin_layout Subsection
@ -2448,6 +2862,266 @@ Baum-Welch Re-estimations
Output Parameters Output Parameters
\end_layout \end_layout
\begin_layout Standard
Following one iteration of Baum-Welch training, the output Gaussian parameters
were estimated as follows (2 d.p.),
\end_layout
\begin_layout Standard
\noindent
\align center
\begin_inset Tabular
<lyxtabular version="3" rows="3" columns="3">
<features tabularvalignment="middle">
<column alignment="center" valignment="top">
<column alignment="center" valignment="top">
<column alignment="center" valignment="top">
<row>
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
State,
\begin_inset Formula $i$
\end_inset
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
1
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
2
\end_layout
\end_inset
</cell>
</row>
<row>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
Mean,
\begin_inset Formula $\mu_{i}$
\end_inset
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
1.67
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
4.09
\end_layout
\end_inset
</cell>
</row>
<row>
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
Variance,
\begin_inset Formula $\varSigma_{i}$
\end_inset
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
1.85
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
0.37
\end_layout
\end_inset
</cell>
</row>
</lyxtabular>
\end_inset
\end_layout
\begin_layout Standard
This represents the following deltas from the original parameters (2 s.f.),
\end_layout
\begin_layout Standard
\noindent
\align center
\begin_inset Tabular
<lyxtabular version="3" rows="3" columns="3">
<features tabularvalignment="middle">
<column alignment="center" valignment="top">
<column alignment="center" valignment="top">
<column alignment="center" valignment="top">
<row>
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
State,
\begin_inset Formula $i$
\end_inset
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
1
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
2
\end_layout
\end_inset
</cell>
</row>
<row>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
Mean,
\begin_inset Formula $\mu_{i}$
\end_inset
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
+0.67
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
+0.089
\end_layout
\end_inset
</cell>
</row>
<row>
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
Variance,
\begin_inset Formula $\varSigma_{i}$
\end_inset
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
+0.41
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
-0.11
\end_layout
\end_inset
</cell>
</row>
</lyxtabular>
\end_inset
\end_layout
\begin_layout Standard
Displayed graphically, these two sets of Gaussian functions can be seen
in figure
\begin_inset CommandInset ref
LatexCommand ref
reference "fig:Re-estimated-PDFs"
plural "false"
caps "false"
noprefix "false"
\end_inset
.
Compared to the original function, increasing the standard deviation has
widened and shortened the new function for state 1.
The slight increase in mean has also shifted the function to the right.
For state 2, the new function has a tighter, taller distribution as a result
of the decreased variance; the mean has, again, been slightly shifted to
the right.
\end_layout
\begin_layout Standard \begin_layout Standard
\begin_inset Float figure \begin_inset Float figure
wide false wide false
@ -2459,7 +3133,8 @@ status open
\align center \align center
\begin_inset Graphics \begin_inset Graphics
filename res/re-est-pdfs.png filename res/re-est-pdfs.png
width 50col% lyxscale 50
width 70col%
\end_inset \end_inset
@ -2490,10 +3165,6 @@ name "fig:Re-estimated-PDFs"
\end_layout \end_layout
\begin_layout Subsubsection
State Transitions
\end_layout
\begin_layout Section \begin_layout Section
Discussion Discussion
\end_layout \end_layout
@ -2526,13 +3197,6 @@ options "bibtotoc"
\end_inset \end_inset
\end_layout
\begin_layout Standard
\begin_inset Newpage newpage
\end_inset
\end_layout \end_layout
\begin_layout Section \begin_layout Section
@ -2567,11 +3231,7 @@ lstparams "caption={Maths utility file with definition for a gaussian},label={ma
\end_layout \end_layout
\begin_layout Standard \begin_layout Standard
\begin_inset CommandInset include \begin_inset Newpage newpage
LatexCommand lstinputlisting
filename "../markov.py"
lstparams "caption={Markov model object defining forward and backward procedure, occupation likelihoods, Baum-Welch equations},label={markov-listing}"
\end_inset \end_inset
@ -2580,8 +3240,8 @@ lstparams "caption={Markov model object defining forward and backward procedure,
\begin_layout Standard \begin_layout Standard
\begin_inset CommandInset include \begin_inset CommandInset include
LatexCommand lstinputlisting LatexCommand lstinputlisting
filename "../markovlog.py" filename "../markov.py"
lstparams "caption={Child Markov model re-implementing calculations using log probability and likelihood},label={log-markov-listing}" lstparams "caption={Markov model object defining forward and backward procedure, occupation likelihoods, Baum-Welch equations},label={markov-listing}"
\end_inset \end_inset
@ -2599,14 +3259,97 @@ lstparams "caption={Child Markov model re-implementing calculations using log pr
The development of the model behind this report was completed using Jupyter The development of the model behind this report was completed using Jupyter
Notebook. Notebook.
The used notebook can be seen formatted in plain text below, the relevant The used notebook can be seen formatted in plain text below, the relevant
mark scheme elements are referenced in brackets. mark scheme elements are referenced in brackets (
\begin_inset listings
inline true
status open
\begin_layout Plain Layout
\noindent
%%
\end_layout
\end_inset
= cell delimiter).
\end_layout \end_layout
\begin_layout Standard \begin_layout Standard
\begin_inset CommandInset include \begin_inset CommandInset include
LatexCommand lstinputlisting LatexCommand lstinputlisting
filename "../notebook.py" filename "../notebook.py"
lstparams "caption={Plain output of Jupyter Notebook used for development and debugging},label={notebook-listing}" lstparams "commentstyle={\\large\\bfseries\\color{commentgreen}},caption={Plain output of Jupyter Notebook used for development and debugging},label={notebook-listing}"
\end_inset
\end_layout
\begin_layout Standard
\begin_inset Newpage newpage
\end_inset
\end_layout
\begin_layout Section
Extensions
\end_layout
\begin_layout Standard
A few extra calculations were done with the model, figure
\begin_inset CommandInset ref
LatexCommand ref
reference "fig:5-training-iterations"
plural "false"
caps "false"
noprefix "false"
\end_inset
shows how the output probability density functions move during 5 iterations
of training.
\end_layout
\begin_layout Standard
\begin_inset Float figure
placement h
wide false
sideways false
status open
\begin_layout Plain Layout
\noindent
\align center
\begin_inset Graphics
filename res/iterated-pdfs.png
lyxscale 50
width 70col%
\end_inset
\end_layout
\begin_layout Plain Layout
\begin_inset Caption Standard
\begin_layout Plain Layout
5 iterations of training completed using the Baum-Welch equations
\begin_inset CommandInset label
LatexCommand label
name "fig:5-training-iterations"
\end_inset
\end_layout
\end_inset
\end_layout
\end_inset \end_inset

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 98 KiB

View File

@ -320,13 +320,6 @@
"\n", "\n",
"model.baum_welch_state_transitions()" "model.baum_welch_state_transitions()"
] ]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
} }
], ],
"metadata": { "metadata": {