This is the IOHMM model with the parameters learned in a semi-supervised way. By using some labeled data, we force the learning process in a certain direction. The unlabeled data will be estimated using EM algorithm iteratively. See notes in http://pages.cs.wisc.edu/~jerryzhu/pub/sslicml07.pdf

SemiSupervisedIOHMM


In [1]:
from __future__ import  division

import json
import warnings


import numpy as np
import pandas as pd


from IOHMM import SemiSupervisedIOHMM
from IOHMM import OLS, CrossEntropyMNL


warnings.simplefilter("ignore")

Load speed data


In [2]:
speed = pd.read_csv('../data/speed.csv')
speed.head()


Out[2]:
Unnamed: 0 rt corr Pacc prev
0 1 6.456770 cor 0.0 inc
1 2 5.602119 cor 0.0 cor
2 3 6.253829 inc 0.0 cor
3 4 5.451038 inc 0.0 inc
4 5 5.872118 inc 0.0 inc

Label some states

In our structure of the code, the states should be a dictionary, the key is the index in the sequence (e.g. 0, 5) and the value is a one-out-of-n code of array where the kth value is 1 if the hidden state is k. n is the number of states in total.

In the following example, we assume that the "corr" column gives the correct hidden states. Here we assume only the first half of the sequence is labeled.

To make sure that the semi supervised model works, we set the value of 'rt' in state 0 as 0 and we set the value of 'rt' in state 1 as 1, the other values are not changed. So after training, we should be able to see 4 states clearly


In [3]:
states = {}
corr = np.array(speed['corr'])
for i in range(int(len(corr)/2)):
    state = np.zeros((4,))
    if corr[i] == 'cor':
        states[i] = np.array([0,1,0,0])
        speed.set_value(i, 'rt', 1)
    else:
        states[i] = np.array([1,0,0,0])
        speed.set_value(i, 'rt', 0)

In [4]:
print(speed.shape[0])
print(len(states))


439
219

In [5]:
for t in range(5):
    print(states[t])


[0 1 0 0]
[0 1 0 0]
[1 0 0 0]
[1 0 0 0]
[1 0 0 0]

Set up a simple model manully


In [6]:
# there should be 4 hidden states in this model
SHMM = SemiSupervisedIOHMM(num_states=4, max_EM_iter=200, EM_tol=1e-10)

# we set only one output 'rt' modeled by a linear regression model
SHMM.set_models(model_emissions = [OLS()], 
                model_transition=CrossEntropyMNL(solver='lbfgs'),
                model_initial=CrossEntropyMNL(solver='lbfgs'))

# we set no covariates associated with initial/transitiojn/emission models
SHMM.set_inputs(covariates_initial = [], covariates_transition = [], covariates_emissions = [[]])

# set the response of the emission model
SHMM.set_outputs([['rt']])

# set the data and ground truth states
SHMM.set_data([[speed, states]])

Start training


In [7]:
SHMM.train()

See the training results


In [8]:
# the coefficients of the output model for each states
# clearly the enforcement worked since the coefficient of the first two states are 0, and 1
print(SHMM.model_emissions[0][0].coef)
print(SHMM.model_emissions[1][0].coef)
print(SHMM.model_emissions[2][0].coef)
print(SHMM.model_emissions[3][0].coef)


[[ 0.]]
[[ 1.]]
[[ 6.38975526]]
[[ 5.47039844]]

In [9]:
# the scale/dispersion of the output model of each states
# since we know the first two states perfectly, the dispersions are 0.
print(np.sqrt(SHMM.model_emissions[0][0].dispersion))
print(np.sqrt(SHMM.model_emissions[1][0].dispersion))
print(np.sqrt(SHMM.model_emissions[2][0].dispersion))
print(np.sqrt(SHMM.model_emissions[3][0].dispersion))


[[ 0.]]
[[  1.66533454e-15]]
[[ 0.22536249]]
[[ 0.17915255]]

In [10]:
# the transition probability from each state
print(np.exp(SHMM.model_transition[0].predict_log_proba(np.array([[]]))))
print(np.exp(SHMM.model_transition[1].predict_log_proba(np.array([[]]))))
print(np.exp(SHMM.model_transition[2].predict_log_proba(np.array([[]]))))
print(np.exp(SHMM.model_transition[3].predict_log_proba(np.array([[]]))))


[[  4.03845430e-01   5.96154225e-01   1.72468132e-07   1.72468132e-07]]
[[  1.85628510e-01   8.08383511e-01   8.78709574e-10   5.98797866e-03]]
[[  1.74937041e-07   1.74937041e-07   9.27082453e-01   7.29171969e-02]]
[[  3.41629345e-08   3.41629345e-08   1.11257897e-01   8.88742035e-01]]

Save the trained model


In [11]:
json_dict = SHMM.to_json('../models/SemiSupervisedIOHMM/')
json_dict


Out[11]:
{'data_type': 'SemiSupervisedIOHMM',
 'properties': {'EM_tol': 1e-10,
  'covariates_emissions': [[]],
  'covariates_initial': [],
  'covariates_transition': [],
  'max_EM_iter': 200,
  'model_emissions': [[{'data_type': 'OLS',
     'properties': {'alpha': 0,
      'coef': {'data_type': 'numpy.ndarray',
       'path': '../models/SemiSupervisedIOHMM/model_emissions/state_0/emission_0/coef.npy'},
      'dispersion': {'data_type': 'numpy.ndarray',
       'path': '../models/SemiSupervisedIOHMM/model_emissions/state_0/emission_0/dispersion.npy'},
      'est_stderr': False,
      'fit_intercept': True,
      'l1_ratio': 0,
      'max_iter': 100,
      'n_targets': 1,
      'reg_method': None,
      'solver': 'svd',
      'stderr': {'data_type': 'numpy.ndarray',
       'path': '../models/SemiSupervisedIOHMM/model_emissions/state_0/emission_0/stderr.npy'},
      'tol': 0.0001}}],
   [{'data_type': 'OLS',
     'properties': {'alpha': 0,
      'coef': {'data_type': 'numpy.ndarray',
       'path': '../models/SemiSupervisedIOHMM/model_emissions/state_1/emission_0/coef.npy'},
      'dispersion': {'data_type': 'numpy.ndarray',
       'path': '../models/SemiSupervisedIOHMM/model_emissions/state_1/emission_0/dispersion.npy'},
      'est_stderr': False,
      'fit_intercept': True,
      'l1_ratio': 0,
      'max_iter': 100,
      'n_targets': 1,
      'reg_method': None,
      'solver': 'svd',
      'stderr': {'data_type': 'numpy.ndarray',
       'path': '../models/SemiSupervisedIOHMM/model_emissions/state_1/emission_0/stderr.npy'},
      'tol': 0.0001}}],
   [{'data_type': 'OLS',
     'properties': {'alpha': 0,
      'coef': {'data_type': 'numpy.ndarray',
       'path': '../models/SemiSupervisedIOHMM/model_emissions/state_2/emission_0/coef.npy'},
      'dispersion': {'data_type': 'numpy.ndarray',
       'path': '../models/SemiSupervisedIOHMM/model_emissions/state_2/emission_0/dispersion.npy'},
      'est_stderr': False,
      'fit_intercept': True,
      'l1_ratio': 0,
      'max_iter': 100,
      'n_targets': 1,
      'reg_method': None,
      'solver': 'svd',
      'stderr': {'data_type': 'numpy.ndarray',
       'path': '../models/SemiSupervisedIOHMM/model_emissions/state_2/emission_0/stderr.npy'},
      'tol': 0.0001}}],
   [{'data_type': 'OLS',
     'properties': {'alpha': 0,
      'coef': {'data_type': 'numpy.ndarray',
       'path': '../models/SemiSupervisedIOHMM/model_emissions/state_3/emission_0/coef.npy'},
      'dispersion': {'data_type': 'numpy.ndarray',
       'path': '../models/SemiSupervisedIOHMM/model_emissions/state_3/emission_0/dispersion.npy'},
      'est_stderr': False,
      'fit_intercept': True,
      'l1_ratio': 0,
      'max_iter': 100,
      'n_targets': 1,
      'reg_method': None,
      'solver': 'svd',
      'stderr': {'data_type': 'numpy.ndarray',
       'path': '../models/SemiSupervisedIOHMM/model_emissions/state_3/emission_0/stderr.npy'},
      'tol': 0.0001}}]],
  'model_initial': {'data_type': 'CrossEntropyMNL',
   'properties': {'alpha': 0,
    'coef': {'data_type': 'numpy.ndarray',
     'path': '../models/SemiSupervisedIOHMM/model_initial/coef.npy'},
    'est_stderr': False,
    'fit_intercept': True,
    'l1_ratio': 0,
    'max_iter': 100,
    'n_classes': 4,
    'reg_method': 'l2',
    'solver': 'lbfgs',
    'stderr': {'data_type': 'numpy.ndarray',
     'path': '../models/SemiSupervisedIOHMM/model_initial/stderr.npy'},
    'tol': 0.0001}},
  'model_transition': [{'data_type': 'CrossEntropyMNL',
    'properties': {'alpha': 0,
     'coef': {'data_type': 'numpy.ndarray',
      'path': '../models/SemiSupervisedIOHMM/model_transition/state_0/coef.npy'},
     'est_stderr': False,
     'fit_intercept': True,
     'l1_ratio': 0,
     'max_iter': 100,
     'n_classes': 4,
     'reg_method': 'l2',
     'solver': 'lbfgs',
     'stderr': {'data_type': 'numpy.ndarray',
      'path': '../models/SemiSupervisedIOHMM/model_transition/state_0/stderr.npy'},
     'tol': 0.0001}},
   {'data_type': 'CrossEntropyMNL',
    'properties': {'alpha': 0,
     'coef': {'data_type': 'numpy.ndarray',
      'path': '../models/SemiSupervisedIOHMM/model_transition/state_1/coef.npy'},
     'est_stderr': False,
     'fit_intercept': True,
     'l1_ratio': 0,
     'max_iter': 100,
     'n_classes': 4,
     'reg_method': 'l2',
     'solver': 'lbfgs',
     'stderr': {'data_type': 'numpy.ndarray',
      'path': '../models/SemiSupervisedIOHMM/model_transition/state_1/stderr.npy'},
     'tol': 0.0001}},
   {'data_type': 'CrossEntropyMNL',
    'properties': {'alpha': 0,
     'coef': {'data_type': 'numpy.ndarray',
      'path': '../models/SemiSupervisedIOHMM/model_transition/state_2/coef.npy'},
     'est_stderr': False,
     'fit_intercept': True,
     'l1_ratio': 0,
     'max_iter': 100,
     'n_classes': 4,
     'reg_method': 'l2',
     'solver': 'lbfgs',
     'stderr': {'data_type': 'numpy.ndarray',
      'path': '../models/SemiSupervisedIOHMM/model_transition/state_2/stderr.npy'},
     'tol': 0.0001}},
   {'data_type': 'CrossEntropyMNL',
    'properties': {'alpha': 0,
     'coef': {'data_type': 'numpy.ndarray',
      'path': '../models/SemiSupervisedIOHMM/model_transition/state_3/coef.npy'},
     'est_stderr': False,
     'fit_intercept': True,
     'l1_ratio': 0,
     'max_iter': 100,
     'n_classes': 4,
     'reg_method': 'l2',
     'solver': 'lbfgs',
     'stderr': {'data_type': 'numpy.ndarray',
      'path': '../models/SemiSupervisedIOHMM/model_transition/state_3/stderr.npy'},
     'tol': 0.0001}}],
  'num_states': 4,
  'responses_emissions': [['rt']]}}

In [12]:
with open('../models/SemiSupervisedIOHMM/model.json', 'w') as outfile:
    json.dump(json_dict, outfile, indent=4, sort_keys=True)

Load back the trained model


In [13]:
SHMM_from_json = SemiSupervisedIOHMM.from_json(json_dict)

See if the coefficients are any different


In [14]:
# the coefficients of the output model for each states
# clearly the enforcement worked since the coefficient of the first two states are 0, and 1
print(SHMM_from_json.model_emissions[0][0].coef)
print(SHMM_from_json.model_emissions[1][0].coef)
print(SHMM_from_json.model_emissions[2][0].coef)
print(SHMM_from_json.model_emissions[3][0].coef)


[[ 0.]]
[[ 1.]]
[[ 6.38975526]]
[[ 5.47039844]]

Set up the model using a config file, instead of doing it manully


In [15]:
with open('../models/SemiSupervisedIOHMM/config.json') as json_data:
    json_dict = json.load(json_data)

SHMM_from_config = SemiSupervisedIOHMM.from_config(json_dict)

Set data and start training


In [16]:
SHMM_from_config.set_data([[speed, states]])
SHMM_from_config.train()

See if the training results are any different?


In [17]:
# the coefficients of the output model for each states
# clearly the enforcement worked since the coefficient of the first two states are 0, and 1
print(SHMM_from_config.model_emissions[0][0].coef)
print(SHMM_from_config.model_emissions[1][0].coef)
print(SHMM_from_config.model_emissions[2][0].coef)
print(SHMM_from_config.model_emissions[3][0].coef)


[[ 0.]]
[[ 1.]]
[[ 6.38975526]]
[[ 5.47039844]]

In [ ]: