Questa risposta fornirà una panoramica di ciò che sta accadendo che porta a una matrice di covarianza singolare durante l'adattamento di un GMM a un set di dati, perché ciò sta accadendo e cosa possiamo fare per impedirlo.
Pertanto, è meglio iniziare ricapitolando i passaggi durante l'adattamento di un modello di miscela gaussiana a un set di dati.
0. Decidi quante fonti / cluster (c) vuoi adattare ai tuoi dati
1. Inizializza i parametri media , covarianza Σ c e fraction_per_class π c per cluster c
μcΣcπc
E−Step–––––––––
- Calcola per ciascun punto dati la probabilità r i c quel punto dati x i appartiene al cluster c con:
r i cxiricxi
doveN(x|μ,Σ)ric=πcN(xi | μc,Σc)ΣKk=1πkN(xi | μk,Σk)
N(x | μ,Σ) descrive il gaussiano mulitvariato con:
ricci fornisce per ciascun punto datixila misura di:ProbabilitythatxibelongstoclasN(xi,μc,Σc) = 1(2π)n2|Σc|12exp(−12(xi−μc)TΣ−1c(xi−μc))
ricxi quindi sexiè molto vicino a una gaussiana c, otterrà unvalorericelevato per questo gaussiano e valori relativamente bassi altrimenti.
M-Step_
Per ogni gruppo c: Calcola il peso totalemProbability that xi belongs to class cProbability of xi over all classesxiric
M−Step––––––––––
mc ( parlando liberamente della frazione di punti assegnati al cluster c) e aggiorna , μ c e Σ c usando r i c con:
πcμcΣcric
π c = m cmc = Σiric
μc=1πc = mcm
Σc=1μc = 1mcΣiricxi
Ricorda che devi usare i mezzi aggiornati in quest'ultima formula.
Ripeti iterativamente il passaggio E e M fino a quando la funzione di verosimiglianza logaritmica del nostro modello converge dove viene calcolata la verosimiglianza logaritmica:
lnp(X|π,μ,Σ)=Σ N i = 1 ln(Σ KΣc = 1mcΣiric(xi−μc)T(xi−μc)
ln p(X | π,μ,Σ) = ΣNi=1 ln(ΣKk=1πkN(xi | μk,Σk))
XAX=XA=I
[0000]
A che dà a questa matrice punteggiata la matrice identità
io(Basta prendere questa matrice zero e produrla con qualsiasi altra matrice 2x2 e vedrai che otterrai sempre la matrice zero). Ma perché questo è un problema per noi? Bene, considera la formula per il multivariato normale sopra. Lì troverai
Σ- 1cche è l'invertibile della matrice di covarianza. Poiché una matrice singolare non è invertibile, questo ci genererà un errore durante il calcolo.
Quindi ora che sappiamo come appare una matrice singolare, non invertibile e perché questo è importante per noi durante i calcoli GMM, come potremmo incontrare questo problema? Prima di tutto, lo capiamo
0matrice di covarianza sopra se il gaussiano multivariato cade in un punto durante l'iterazione tra il passaggio E e M. Ciò potrebbe accadere se ad esempio disponiamo di un set di dati a cui vogliamo adattare 3 gaussiani ma che in realtà consiste solo di due classi (cluster) tali che, parlando in modo approssimativo, due di questi tre gaussiani catturano il proprio cluster mentre l'ultimo gaussiano lo gestisce solo catturare un singolo punto su cui si trova. Vedremo come appare di seguito. Ma passo dopo passo: supponiamo di avere un set di dati bidimensionale che consiste di due cluster ma non lo sapete e volete adattare tre modelli gaussiani ad esso, ovvero c = 3. Inizializzate i parametri nel passaggio E e nella trama i gaussiani in cima ai tuoi dati che sembrano smth. come (forse puoi vedere i due cluster relativamente sparsi in basso a sinistra e in alto a destra):
Dopo aver inizializzato il parametro, esegui iterativamente i passaggi E, T. Durante questa procedura i tre gaussiani vagano in giro e cercano il loro posto ottimale. Se osservi i parametri del modello, cioè
μc e
πcnoterai che convergono, che dopo un certo numero di iterazioni non cambieranno più e con ciò il gaussiano corrispondente ha trovato il suo posto nello spazio. Nel caso in cui tu abbia una matrice di singolarità, incontri smth. come:
dove ho cerchiato il terzo modello gaussiano con il rosso. Quindi vedi che questo gaussiano si trova su un singolo punto dati mentre gli altri due rivendicano il resto. Qui devo notare che per essere in grado di disegnare la figura in questo modo ho già usato la regolarizzazione della covarianza che è un metodo per prevenire le matrici di singolarità ed è descritta di seguito.
Ok, ma ora non sappiamo ancora perché e come incontriamo una matrice di singolarità. Pertanto, dobbiamo esaminare i calcoli di
rio c e il
c o vdurante le fasi E e M. Se guardi il
rio c formula di nuovo:
rio c= πcN( xio | μ c, Σc)ΣKk = 1πKN( xio | μ K, ΣK)
vedi che lì il
rio cavrebbero valori elevati se sono molto probabilmente nel cluster ce valori bassi in caso contrario. Per renderlo più evidente, consideriamo il caso in cui abbiamo due gaussiani relativamente diffusi e uno gaussiano molto stretto e calcoliamo il
rio c per ciascun punto dati
Xiocome illustrato nella figura:
quindi esamina i punti dati da sinistra a destra e immagina di scrivere la probabilità per ciascuno
Xioche appartiene al gaussiano rosso, blu e giallo. Quello che puoi vedere è che per la maggior parte dei
Xiola probabilità che appartenga al gaussiano giallo è molto piccola. Nel caso sopra in cui il terzo gaussiano si trova su un singolo punto dati,
rio c è solo maggiore di zero per questo punto dati mentre è zero per ogni altro
Xio. (collassa su questo punto dati -> Questo accade se tutti gli altri punti fanno più probabilmente parte di uno o due gaussiani e quindi questo è l'unico punto che rimane per i tre gaussiani -> Il motivo per cui ciò accade può essere trovato nell'interazione tra il set di dati stesso nell'inizializzazione dei gaussiani. Cioè, se avessimo scelto altri valori iniziali per i gaussiani, avremmo visto un'altra immagine e il terzo gaussiano forse non sarebbe crollato). Questo è sufficiente se ulteriori e ulteriori picchi di questo gaussiano. Il
rio ctavolo quindi sembra smth. come:
Come puoi vedere, il
rio cdella terza colonna, ovvero per la terza gaussiana sono zero invece di questa riga. Se cerchiamo quale punto dati è rappresentato qui otteniamo il punto dati: [23.38566343 8.07067598]. Ok, ma perché otteniamo una matrice di singolarità in questo caso? Bene, e questo è il nostro ultimo passo, quindi dobbiamo ancora una volta considerare il calcolo della matrice di covarianza che è:
Σc = Σ iorio c( xio- μc)T( xio- μc)
abbiamo visto tutto
rio c sono zero invece per quello
Xiocon [23.38566343 8.07067598]. Ora la formula vuole che calcoliamo
( xio- μc). Se guardiamo al
μcper questo terzo gaussiano otteniamo [23.38566343 8.07067598]. Oh, ma aspetta, esattamente come
Xio ed è quello con cui Bishop ha scritto: "Supponiamo che uno dei componenti del modello di miscela, diciamo il
j th componente, ha la sua media
μj
esattamente uguale a uno dei punti dati in modo che
μj= xnper un valore di
n "(Bishop, 2006, p.434). Quindi cosa accadrà? Bene, questo termine sarà zero e quindi questo punto dati è stata l'unica possibilità per la matrice di covarianza di non ottenere zero (poiché questo punto dati era l'unico dove
rio c> 0), ora diventa zero e assomiglia a:
[ 0000]
Di conseguenza, come detto sopra, questa è una matrice singolare e porterà a un errore durante i calcoli del gaussiano multivariato. Quindi, come possiamo prevenire una simile situazione. Bene, abbiamo visto che la matrice di covarianza è singolare se lo è
0matrice. Quindi per prevenire la singolarità dobbiamo semplicemente impedire che la matrice di covarianza diventi a
0matrice. Questo viene fatto aggiungendo un valore molto piccolo (nella
GaussianMixture di sklearn questo valore è impostato su 1e-6) al digonal della matrice di covarianza. Esistono anche altri modi per prevenire la singolarità, come notare quando un gaussiano collassa e impostare la sua matrice media e / o di covarianza su un nuovo / i valore / i arbitrariamente alto / i. Questa regolarizzazione della covarianza è anche implementata nel codice seguente con il quale si ottengono i risultati descritti. Forse devi eseguire il codice più volte per ottenere una matrice di covarianza singolare da allora, come detto. questo non deve succedere ogni volta, ma dipende anche dalla configurazione iniziale dei gaussiani.
import matplotlib.pyplot as plt
from matplotlib import style
style.use('fivethirtyeight')
from sklearn.datasets.samples_generator import make_blobs
import numpy as np
from scipy.stats import multivariate_normal
# 0. Create dataset
X,Y = make_blobs(cluster_std=2.5,random_state=20,n_samples=500,centers=3)
# Stratch dataset to get ellipsoid data
X = np.dot(X,np.random.RandomState(0).randn(2,2))
class EMM:
def __init__(self,X,number_of_sources,iterations):
self.iterations = iterations
self.number_of_sources = number_of_sources
self.X = X
self.mu = None
self.pi = None
self.cov = None
self.XY = None
# Define a function which runs for i iterations:
def run(self):
self.reg_cov = 1e-6*np.identity(len(self.X[0]))
x,y = np.meshgrid(np.sort(self.X[:,0]),np.sort(self.X[:,1]))
self.XY = np.array([x.flatten(),y.flatten()]).T
# 1. Set the initial mu, covariance and pi values
self.mu = np.random.randint(min(self.X[:,0]),max(self.X[:,0]),size=(self.number_of_sources,len(self.X[0]))) # This is a nxm matrix since we assume n sources (n Gaussians) where each has m dimensions
self.cov = np.zeros((self.number_of_sources,len(X[0]),len(X[0]))) # We need a nxmxm covariance matrix for each source since we have m features --> We create symmetric covariance matrices with ones on the digonal
for dim in range(len(self.cov)):
np.fill_diagonal(self.cov[dim],5)
self.pi = np.ones(self.number_of_sources)/self.number_of_sources # Are "Fractions"
log_likelihoods = [] # In this list we store the log likehoods per iteration and plot them in the end to check if
# if we have converged
# Plot the initial state
fig = plt.figure(figsize=(10,10))
ax0 = fig.add_subplot(111)
ax0.scatter(self.X[:,0],self.X[:,1])
for m,c in zip(self.mu,self.cov):
c += self.reg_cov
multi_normal = multivariate_normal(mean=m,cov=c)
ax0.contour(np.sort(self.X[:,0]),np.sort(self.X[:,1]),multi_normal.pdf(self.XY).reshape(len(self.X),len(self.X)),colors='black',alpha=0.3)
ax0.scatter(m[0],m[1],c='grey',zorder=10,s=100)
mu = []
cov = []
R = []
for i in range(self.iterations):
mu.append(self.mu)
cov.append(self.cov)
# E Step
r_ic = np.zeros((len(self.X),len(self.cov)))
for m,co,p,r in zip(self.mu,self.cov,self.pi,range(len(r_ic[0]))):
co+=self.reg_cov
mn = multivariate_normal(mean=m,cov=co)
r_ic[:,r] = p*mn.pdf(self.X)/np.sum([pi_c*multivariate_normal(mean=mu_c,cov=cov_c).pdf(X) for pi_c,mu_c,cov_c in zip(self.pi,self.mu,self.cov+self.reg_cov)],axis=0)
R.append(r_ic)
# M Step
# Calculate the new mean vector and new covariance matrices, based on the probable membership of the single x_i to classes c --> r_ic
self.mu = []
self.cov = []
self.pi = []
log_likelihood = []
for c in range(len(r_ic[0])):
m_c = np.sum(r_ic[:,c],axis=0)
mu_c = (1/m_c)*np.sum(self.X*r_ic[:,c].reshape(len(self.X),1),axis=0)
self.mu.append(mu_c)
# Calculate the covariance matrix per source based on the new mean
self.cov.append(((1/m_c)*np.dot((np.array(r_ic[:,c]).reshape(len(self.X),1)*(self.X-mu_c)).T,(self.X-mu_c)))+self.reg_cov)
# Calculate pi_new which is the "fraction of points" respectively the fraction of the probability assigned to each source
self.pi.append(m_c/np.sum(r_ic))
# Log likelihood
log_likelihoods.append(np.log(np.sum([k*multivariate_normal(self.mu[i],self.cov[j]).pdf(X) for k,i,j in zip(self.pi,range(len(self.mu)),range(len(self.cov)))])))
fig2 = plt.figure(figsize=(10,10))
ax1 = fig2.add_subplot(111)
ax1.plot(range(0,self.iterations,1),log_likelihoods)
#plt.show()
print(mu[-1])
print(cov[-1])
for r in np.array(R[-1]):
print(r)
print(X)
def predict(self):
# PLot the point onto the fittet gaussians
fig3 = plt.figure(figsize=(10,10))
ax2 = fig3.add_subplot(111)
ax2.scatter(self.X[:,0],self.X[:,1])
for m,c in zip(self.mu,self.cov):
multi_normal = multivariate_normal(mean=m,cov=c)
ax2.contour(np.sort(self.X[:,0]),np.sort(self.X[:,1]),multi_normal.pdf(self.XY).reshape(len(self.X),len(self.X)),colors='black',alpha=0.3)
EMM = EMM(X,3,100)
EMM.run()
EMM.predict()