PRML Kapitel 8 Summe der Produkte Algorithmus Python-Implementierung

Kapitel 8 beschreibt das grafische Modell. Ein grafisches Modell ist eine Methode zum grafischen Ausdrücken von Beziehungen wie stochastischen Variablen und Modellparametern. Modelle wie die lineare Regression in PRML können im Allgemeinen mithilfe grafischer Modelle dargestellt werden. Ich habe einen Produktsummenalgorithmus implementiert, der auf ein Modell angewendet werden kann, das durch ein grafisches Modell dargestellt werden kann, und versucht, Bildrauschen zu entfernen. Diese Methode scheint eine allgemeine Form der Methode zu sein, die auf das in Kapitel 13 von PRML eingeführte Hidden-Markov-Modell angewendet wird.

Betrachten Sie hier ein Binärbild (weiß: 1, schwarz: -1), in dem die Pixel im Bild entweder einen Wert von -1,1 haben. Bei einem Bild mit invertierten Werten bei einigen Pixeln wie dem folgenden wird ein rauschfreies Bild wie folgt wiederhergestellt: Markov-Wahrscheinlichkeitsfeld Als Modell für die Entfernung von Bildrauschen verwenden wir das Markov-Wahrscheinlichkeitsfeld (Markov-Netzwerk, ungerichtetes grafisches Modell), eine Art grafisches Modell. Die folgende Abbildung zeigt schematisch das diesmal betrachtete Markov-Wahrscheinlichkeitsfeld. Der ** $ y $ -Knoten ist eine stochastische Variable, die den Pixelwert des mit Rauschen beobachteten Bildes darstellt, und der $ x $ -Knoten ist die stochastische Variable, die den Pixelwert des rauschfreien Bildes darstellt, das wir wiederherstellen möchten **. In einem rauschfreien Bild wird angenommen, dass benachbarte Pixel eine starke Korrelation aufweisen, sodass selbst in diesem Modell benachbarte Knoten durch eine Linie in $ x $ verbunden sind. Da der Anteil des Rauschens relativ klein ist, besteht auch eine starke Korrelation zwischen dem Wert eines Pixels in einem rauschfreien Bild und dem entsprechenden Pixelwert in einem verrauschten Bild. Wenn beispielsweise ein Pixel in einem verrauschten Bild einen Wert von 1 hat, sind die an dieses Pixel angrenzenden Pixel wahrscheinlich 1, und der entsprechende Pixelwert in einem verrauschten Bild kann auch 1 sein. hoch. Dies bedeutet, dass die durch ** Linien verbundenen Knoten tendenziell den gleichen Pixelwert ** haben.

Dies als Formel ausdrücken,

p({\bf x},{\bf y}) = {1\over Z}\exp\left\{-E({\bf x},{\bf y})\right\}

Wenn Sie jedoch $ i, j $ als Index zur Darstellung des Knotens verwenden,

E({\bf x},{\bf y}) = -\alpha\sum_ix_iy_i-\beta\sum_{Angrenzend an i und j}x_ix_j

Und $ Z $ ist eine Normalisierungskonstante.

Gegeben ein Bild mit Rauscheny_iIst ein konkreter Beobachtungswert, wenn Sie sie also ersetzenp({\bf x}|{\bf y})Es kann erhalten werden. Diesp({\bf x}|{\bf y})Der Wert von{\bf x}Ist das wiederhergestellte Bild.{\bf x}Die Gesamtzahl der Zustände, die genommen werden können2^{Anzahl der Knoten}So alles{\bf x}Es ist nicht realistisch, das Muster von zu versuchen. Es gibt auch einen Algorithmus, der als iterativer bedingter Modus bezeichnet wird, um das wiederhergestellte Bild zu schätzen. Hier werden wir jedoch mithilfe des Produktsummenalgorithmus wiederherstellen, der eine bessere Lösung zu bieten scheint.

Produktsummenalgorithmus

Dieser Algorithmus ist eine Methode zur Berechnung der Wahrscheinlichkeit des Werts, den ein stochastischer variabler Knoten in einem grafischen Modell annehmen kann. Die Wahrscheinlichkeit wird berechnet, indem so etwas wie eine nicht normalisierte Wahrscheinlichkeit, die als Nachricht bezeichnet wird, von den durch eine Linie verbundenen Knoten ausgetauscht wird.

Nachricht von $ y_i $ an $ x_i $

m_{y_i\to x_i} = \exp(\alpha x_i y_i)

$ Y_i $ ist hier jedoch keine stochastische Variable, sondern ein beobachteter Wert.

Nachricht von $ x_j $ an $ x_i $

m_{x_j\to x_i} = \sum_{x_j}\exp(\beta x_ix_j)f(x_j)

$ F (x_j) $ ist jedoch das Produkt von Nachrichten von anderen Knoten als dem Knoten $ i $ neben dem Knoten $ j $. Um $ f (x_j) $ zu berechnen, benötigen Sie eine Nachricht von einem anderen Knoten zu Knoten $ i $. Da es sich bei dem grafischen Modell, mit dem wir uns diesmal befassen, um ein Modell mit einer Schleife handelt, initialisieren Sie die Nachricht zuerst mit einem bestimmten Wert und dann Senden Sie die beiden oben genannten Nachrichten, um $ {\ bf x} $ zu schätzen.

Implementierung

sum_product.py


import itertools
import numpy as np
from scipy.misc import imread, imsave


ORIGINAL_IMAGE = "qiita_binary.png "
NOISY_IMAGE = "qiita_noise.png "
DENOISED_IMAGE = "qiita_denoised.png "


class Node(object):

    def __init__(self):
        self.neighbors = []
        self.messages = {}
        self.prob = None

        self.alpha = 10.
        self.beta = 5.

    def add_neighbor(self, node):
        """
        add neighboring node

        Parameters
        ----------
        node : Node
            neighboring node
        """
        self.neighbors.append(node)

    def get_neighbors(self):
        """
        get neighbor nodes

        Returns
        -------
        neighbors : list
            list containing neighbor nodes
        """
        return self.neighbors

    def init_messeges(self):
        """
        initialize messages from neighbor nodes
        """
        for neighbor in self.neighbors:
            self.messages[neighbor] = np.ones(shape=(2,)) * 0.5

    def marginalize(self):
        """
        calculate probability
        """
        prob = reduce(lambda x, y: x * y, self.messages.values())
        self.prob = prob / prob.sum()

    def send_message_to(self, node):
        """
        calculate message to be sent to the node

        Parameters
        ----------
        node : Node
            node to send computed message

        Returns
        -------
        message : np.ndarray (2,)
            message to be sent to the node
        """
        message_from_neighbors = reduce(lambda x, y: x * y, self.messages.values()) / self.messages[node]
        F = np.exp(self.beta * (2 * np.eye(2) - 1))
        message = F.dot(message_from_neighbors)
        node.messages[self] = message / message.sum()

    def likelihood(self, value):
        """
        calculate likelihood via observation, which is messege to this node

        Parameters
        ----------
        value : int
            observed value -1 or 1
        """
        assert (value == -1) or (value == 1), "{} is not 1 or -1".format(value)
        message = np.exp(self.alpha * np.array([-value, value]))
        self.messages[self] = message / message.sum()


class MarkovRandomField(object):

    def __init__(self):
        self.nodes = {}

    def add_node(self, location):
        """
        add a new node at the location

        Parameters
        ----------
        location : tuple
            key to access the node
        """
        self.nodes[location] = Node()

    def get_node(self, location):
        """
        get the node at the location

        Parameters
        ----------
        location : tuple
            key to access the corresponding node

        Returns
        -------
        node : Node
            the node at the location
        """
        return self.nodes[location]

    def add_edge(self, key1, key2):
        """
        add edge between nodes corresponding to key1 and key2

        Parameters
        ----------
        key1 : tuple
            The key to access one of the nodes
        key2 : tuple
            The key to access the other node.
        """
        self.nodes[key1].add_neighbor(self.nodes[key2])
        self.nodes[key2].add_neighbor(self.nodes[key1])

    def sum_product_algorithm(self, iter_max=10):
        """
        Perform sum product algorithm
        1. initialize messages
        2. send messages from each node to neighboring nodes
        3. calculate probabilities using the messages

        Parameters
        ----------
        iter_max : int
            number of maximum iteration
        """
        for node in self.nodes.values():
            node.init_messeges()

        for i in xrange(iter_max):
            print i
            for node in self.nodes.values():
                for neighbor in node.get_neighbors():
                    node.send_message_to(neighbor)

        for node in self.nodes.values():
            node.marginalize()


def denoise(img, n_iter=20):
    mrf = MarkovRandomField()
    len_x, len_y = img.shape
    X = range(len_x)
    Y = range(len_y)

    for location in itertools.product(X, Y):
        mrf.add_node(location)

    for x, y in itertools.product(X, Y):
        for dx, dy in itertools.permutations(range(2), 2):
            try:
                mrf.add_edge((x, y), (x + dx, y + dy))
            except Exception:
                pass

    for location in itertools.product(X, Y):
        node = mrf.get_node(location)
        node.likelihood(img[location])

    mrf.sum_product_algorithm(n_iter)

    denoised = np.zeros_like(img)
    for location in itertools.product(X, Y):
        node = mrf.get_node(location)
        denoised[location] = 2 * np.argmax(node.prob) - 1

    return denoised


def main():
    img_original = 2 * (imread(ORIGINAL_IMAGE) / 255).astype(np.int) - 1
    img_noise = 2 * (imread(NOISY_IMAGE) / 255).astype(np.int) - 1

    img_denoised = denoise(img_noise, 10)

    print "error rate before"
    print np.sum((img_original != img_noise).astype(np.float)) / img_noise.size
    print "error rate after"
    print np.sum((img_denoised != img_original).astype(np.float)) / img_noise.size
    imsave(DENOISED_IMAGE, (img_denoised + 1) / 2 * 255)

if __name__ == '__main__':
    main()

Ergebnis

Bild durch Entfernen von Rauschen wiederhergestellt Ergebnis der Terminalausgabe

error rate before
0.109477124183
error rate after
0.0316993464052

Die Fehlerrate im Vergleich zum Originalbild ist reduziert.

Am Ende

Wenn der Zweck darin besteht, Rauschen zu entfernen, scheint die Grafikschnittmethode die genaueste zu sein.

Recommended Posts

PRML Kapitel 8 Summe der Produkte Algorithmus Python-Implementierung
PRML Kapitel 5 Python-Implementierung für neuronale Netze
PRML Kapitel 3 Evidence Ungefähre Python-Implementierung
PRML Kapitel 4 Bayesianische logistische Regression Python-Implementierung
PRML Kapitel 5 Python-Implementierung eines Netzwerks mit gemischter Dichte
PRML Kapitel 9 Mixed Gaussian Distribution Python-Implementierung
PRML Kapitel 14 Bedingte gemischte Modell-Python-Implementierung
PRML Kapitel 10 Variante Mixed Gaussian Distribution Python-Implementierung
PRML Kapitel 6 Gaussian Return Python-Implementierung
PRML Kapitel 2 Python-Implementierung von Student t-Distribution
PRML Kapitel 1 Bayesian Curve Fitting Python-Implementierung
PRML Kapitel 11 Implementierung der Markov-Kette Monte Carlo Python
PRML Kapitel 12 Bayesianische Hauptanalyse Python-Implementierung
Implementiert in Python PRML Kapitel 4 Klassifizierung nach Perceptron-Algorithmus
PRML Kapitel 7 Verwandte Vector Machine Python-Implementierung für Regressionsprobleme
Erläuterung und Implementierung von PRML Kapitel 4
Sortieralgorithmus und Implementierung in Python
Implementierung der Dyxtra-Methode durch Python
Python-Algorithmus
PRML Kapitel 13 Wahrscheinlichste Schätzung Python-Implementierung des Hidden-Markov-Modells
PRML-Implementierung Kapitel 3 Lineares Basisfunktionsmodell
Implementiert in Python PRML Kapitel 7 Nichtlineare SVM
Implementiert in Python PRML Kapitel 5 Neuronales Netzwerk
Implementiert in Python PRML Kapitel 1 Bayesianische Schätzung
Python-Memorandum (Algorithmus)
Implementiert in Python PRML Kapitel 1 Polygonkurvenanpassung
Implementieren Sie den PRML-Algorithmus in Python (fast nur Numpy)
Ein * Algorithmus (Python Edition)
RNN-Implementierung in Python
ValueObject-Implementierung in Python
Genetischer Algorithmus in Python
Algorithmus in Python (Bellman-Ford-Methode, Bellman-Ford)
Python neu lernen (Algorithmus I)
Implementieren Sie sum in Python
[Python] Kapitel 01-01 Über Python (Erster Python)
SVM-Implementierung in Python
Algorithmus in Python (Dijkstra)
[Python] Kumulative Summe ABC179D
Python Machine Learning Programming Kapitel 2 Klassifizierungsprobleme - Zusammenfassung des Trainingsalgorithmus für maschinelles Lernen