예제 #1
0
    def test_forward(self):
        """
        Test Discrete HMM forward method.
        """
        hmm = HMM(num_states=2, output='discrete', output_num_states=3)
        hmm.markov.initial_probs.set_(torch.as_tensor([0.8, 0.2]))
        hmm.markov.transition_probs.set_(
            torch.as_tensor([[0.8, 0.2], [0.3, 0.7]]))
        hmm.emission.probabilities.set_(
            torch.as_tensor([[0.2, 0.7, 0.1], [0.6, 0.1, 0.3]]))

        # 1) Simple forward application
        seq = torch.as_tensor([[2, 2, 0], [1, 2, 1]])
        out = hmm.predict(seq, parallel=False)

        self.assertAlmostEqual(out[0, 0].item(), 0.2213, places=4)
        self.assertAlmostEqual(out[0, 1].item(), 0.7787, places=4)

        self.assertAlmostEqual(out[1, 0].item(), 0.9037, places=4)
        self.assertAlmostEqual(out[1, 1].item(), 0.0963, places=4)

        # 2) Packed forward application (sorted from largest to smallest sequence)
        seqs = torch.nn.utils.rnn.pack_sequence([
            torch.as_tensor([1, 2, 1, 1]),
            torch.as_tensor([2, 2, 0]),
            torch.as_tensor([0, 1])
        ])
        out = hmm.predict(seqs, parallel=False)

        self.assertAlmostEqual(out[0, 0].item(), 0.9550, places=4)
        self.assertAlmostEqual(out[0, 1].item(), 0.0450, places=4)

        self.assertAlmostEqual(out[1, 0].item(), 0.2213, places=4)
        self.assertAlmostEqual(out[1, 1].item(), 0.7787, places=4)

        self.assertAlmostEqual(out[2, 0].item(), 0.9082, places=4)
        self.assertAlmostEqual(out[2, 1].item(), 0.0918, places=4)

        # 3) Packed forward application (unsorted)
        seqs = torch.nn.utils.rnn.pack_sequence([
            torch.as_tensor([0, 1]),
            torch.as_tensor([1, 2, 1, 1]),
            torch.as_tensor([2, 2, 0])
        ],
                                                enforce_sorted=False)
        out = hmm.predict(seqs, parallel=False)

        self.assertAlmostEqual(out[0, 0].item(), 0.9082, places=4)
        self.assertAlmostEqual(out[0, 1].item(), 0.0918, places=4)

        self.assertAlmostEqual(out[1, 0].item(), 0.9550, places=4)
        self.assertAlmostEqual(out[1, 1].item(), 0.0450, places=4)

        self.assertAlmostEqual(out[2, 0].item(), 0.2213, places=4)
        self.assertAlmostEqual(out[2, 1].item(), 0.7787, places=4)
예제 #2
0
    def test_by_batch_restore_gaussian(self):
        """
        Test Gaussian HMM with spherical covariance by restoring an existing HMM via batch training.
        """
        config = {
            'num_states': 3,
            'output_dim': 2,
            'output_covariance': 'spherical'
        }

        hmm_reference = HMM(**config)

        hmm_reference.markov.initial_probs.set_(torch.as_tensor(
            [0.75, 0.25, 0], dtype=torch.float
        ))
        hmm_reference.markov.transition_probs.set_(torch.as_tensor([
            [0, 1, 0],
            [0.5, 0, 0.5],
            [1, 0, 0]
        ], dtype=torch.float))

        hmm_reference.emission.means.set_(torch.as_tensor([
            [-1, -1], [0, 1], [1, -1]
        ], dtype=torch.float))
        hmm_reference.emission.covars.set_(torch.as_tensor(
            [0.1, 0.25, 0.2]
        ))

        torch.manual_seed(42)
        sequences = hmm_reference.sample(8192, 8)

        hmm = HMM(**config)
        hmm.fit(sequences.chunk(32))

        order = hmm.markov.initial_probs.argsort(descending=True)

        self.assertTrue(torch.allclose(
            hmm.markov.initial_probs[order], hmm_reference.markov.initial_probs,
            atol=0.01, rtol=0
        ))

        self.assertTrue(torch.allclose(
            hmm.markov.transition_probs[order][:, order], hmm_reference.markov.transition_probs,
            atol=0.01, rtol=0
        ))

        self.assertTrue(torch.allclose(
            hmm.emission.means[order], hmm_reference.emission.means,
            atol=0.05, rtol=0
        ))

        self.assertTrue(torch.allclose(
            hmm.emission.covars[order], hmm_reference.emission.covars,
            atol=0.02, rtol=0
        ))
예제 #3
0
    def test_by_restore_discrete(self):
        """
        Test Discrete HMM with by restoring an existing HMM.
        """
        config = {
            'num_states': 3,
            'output': 'discrete',
            'output_num_states': 4
        }

        hmm_reference = HMM(**config)

        hmm_reference.markov.initial_probs.set_(torch.as_tensor(
            [0.75, 0.25, 0], dtype=torch.float
        ))
        hmm_reference.markov.transition_probs.set_(torch.as_tensor([
            [0.9, 0.1, 0],
            [0.5, 0, 0.5],
            [0, 1, 0]
        ], dtype=torch.float))

        hmm_reference.emission.probabilities.set_(torch.as_tensor([
            [1, 0, 0, 0],
            [0, 1, 0, 0],
            [0, 0, 0.5, 0.5]
        ]))

        torch.manual_seed(21)
        sequences = hmm_reference.sample(16536, 16)

        hmm = HMM(**config)
        hmm.fit(sequences, epochs=100, eps=1e-7, patience=3)

        order = hmm.markov.initial_probs.argsort(descending=True)

        self.assertTrue(torch.allclose(
            hmm.markov.initial_probs[order], hmm_reference.markov.initial_probs,
            atol=0.01, rtol=0
        ))

        self.assertTrue(torch.allclose(
            hmm.markov.transition_probs[order][:, order], hmm_reference.markov.transition_probs,
            atol=0.01, rtol=0
        ))

        self.assertTrue(torch.allclose(
            hmm.emission.probabilities[order], hmm_reference.emission.probabilities,
            atol=0.05, rtol=0
        ))
예제 #4
0
    def test_smoothing(self):
        """
        Test Discrete HMM smoothing (forward-backward algorithm).
        """
        hmm = HMM(num_states=2, output='discrete', output_num_states=3)
        hmm.markov.initial_probs.set_(torch.as_tensor([0.8, 0.2]))
        hmm.markov.transition_probs.set_(
            torch.as_tensor([[0.8, 0.2], [0.3, 0.7]]))
        hmm.emission.probabilities.set_(
            torch.as_tensor([[0.2, 0.7, 0.1], [0.6, 0.1, 0.3]]))

        # 1) Simple smoothing
        seq = torch.as_tensor([[2, 2, 0], [1, 2, 1]])
        out = hmm.predict(seq, smooth=True, parallel=False)

        self.assertTrue(
            torch.allclose(out[0],
                           torch.as_tensor([[0.3847, 0.6153], [0.2156, 0.7844],
                                            [0.2213, 0.7787]]),
                           rtol=0,
                           atol=1e-4))
        self.assertTrue(
            torch.allclose(out[1],
                           torch.as_tensor([[0.9587, 0.0413], [0.7133, 0.2867],
                                            [0.9037, 0.0963]]),
                           rtol=0,
                           atol=1e-4))

        # 2) Packed smoothing (sorted from largest to smallest sequence)
        seqs = torch.nn.utils.rnn.pack_sequence([
            torch.as_tensor([1, 2, 1, 1]),
            torch.as_tensor([2, 2, 0]),
            torch.as_tensor([0, 1])
        ])
        out = hmm.predict(seqs, smooth=True, parallel=False)

        self.assertTrue(
            torch.allclose(out[0],
                           torch.as_tensor([[0.9611, 0.0389], [0.7373, 0.2627],
                                            [0.9511, 0.0489], [0.9550,
                                                               0.0450]]),
                           rtol=0,
                           atol=1e-4))
        self.assertTrue(
            torch.allclose(out[1],
                           torch.as_tensor([[0.3847, 0.6153], [0.2156, 0.7844],
                                            [0.2213, 0.7787]]),
                           rtol=0,
                           atol=1e-4))
        self.assertTrue(
            torch.allclose(out[2],
                           torch.as_tensor([[0.7342, 0.2658], [0.9082,
                                                               0.0918]]),
                           rtol=0,
                           atol=1e-4))

        # 3) Packed smoothing (unsorted)
        seqs = torch.nn.utils.rnn.pack_sequence([
            torch.as_tensor([0, 1]),
            torch.as_tensor([1, 2, 1, 1]),
            torch.as_tensor([2, 2, 0])
        ],
                                                enforce_sorted=False)
        out = hmm.predict(seqs, smooth=True, parallel=False)

        self.assertTrue(
            torch.allclose(out[0],
                           torch.as_tensor([[0.7342, 0.2658], [0.9082,
                                                               0.0918]]),
                           rtol=0,
                           atol=1e-4))
        self.assertTrue(
            torch.allclose(out[1],
                           torch.as_tensor([[0.9611, 0.0389], [0.7373, 0.2627],
                                            [0.9511, 0.0489], [0.9550,
                                                               0.0450]]),
                           rtol=0,
                           atol=1e-4))
        self.assertTrue(
            torch.allclose(out[2],
                           torch.as_tensor([[0.3847, 0.6153], [0.2156, 0.7844],
                                            [0.2213, 0.7787]]),
                           rtol=0,
                           atol=1e-4))