Bağımsız Bileşen Analizi
Bir kokteyl partisindesiniz ve aynı anda birden çok kişi konuşuyor. Yani birden çok kaynaktan ses geliyor. $N$ kişi konuşuyor olsun. Siz de odanın değişik yerlerine $N$ tane mikrofon koyup kayıt almış olun. Bu kayıtların hepsi muhakkak ki kaynaklardan çıkan seslerin doğrusal bileşimlerinden oluşuyor olacaklar. Kaynakları görmüyorsunuz fakat bileşimlerini görüyorsunuz, ya da duyuyorsunuz. Kör kaynak problemi denilen bu problem için bir yöntemimiz var!
Bu yazıda bağımsız bileşenler analizi (ICA - independent component analysis) ile bu kaynakları nasıl elde edeceğimize bakalım.
Öncelikle basit sinyaller ile işe başlayalım:
# -*- coding: utf-8 -*- import numpy as np import pylab as plt from sklearn.decomposition import FastICA # Örnek veriyi üretelim np.random.seed(0) nSamples = 1000 time = np.linspace(0, 10, nSamples) s1 = np.sin(2 * time) # Sinyal 1 : sinüsoid s2 = np.sign(np.sin(3 * time)) # Sinyal 2 : kare dalga S = np.c_[s1, s2] S += 0.1 * np.random.normal(size=S.shape) # Gürültü ekle S /= S.std(axis=0) # Düzgele
Şimdi sinyalleri karıştıralım ve sonuçları ICA ile ayrıştıralım:
A = np.array([[1, 1], [0.8, 2]]) # Karışım matrisi X = np.dot(S, A.T) # Gözlemleri oluştur # ICA hesapla ica = FastICA() S_ = ica.fit(X).transform(X) # Kaynakları tahmin et A_ = ica.get_mixing_matrix() # Karışım matrisini tahmin et assert np.allclose(X, np.dot(S_, A_.T))
Ve sonuçlara bakalım:
plt.figure() ax1 = plt.subplot(3, 1, 1) plt.plot(S) plt.title(u'Gerçek Kaynaklar') plt.setp(ax1.get_xticklabels(), visible=False) ax2 = plt.subplot(3, 1, 2, sharex=ax1) plt.plot(X) plt.title(u'Gözlemler (karışım sinyali)') plt.setp(ax2.get_xticklabels(), visible=False) plt.subplot(3, 1, 3, sharex=ax1) plt.plot(S_) plt.title(u'ICA tarafından bulunan kaynaklar') plt.savefig('ica.png')
Bulunan sinyaller doğru. Fakat sıraları ve ölçekleri bilinemiyor. Yeşil renkle çizilen kare dalganın ters yönde çıkması da bu ölçek katsayısı ile ilgili. Negatif bir sayıyla çarparsanız özgün halinde olduğu gibi ters çıkacaktır.
Şimdi daha güzel bir örnek üstünde bakalım. Büyük usta Kemal Sunal'ın iki ses kaydını alalım:
Bunları önceden aynı boyuta getirmiştim.
Sonra onları karıştıralım ve yeni sinyaller elde edelim:
İki sinyalde de iki ses karışmış. İşimiz zor gibi. Haydi, ICA ile gözlemler üstünden kaynakları tahmin edelim:
Bunlar için alttaki kodu kullanabilirsiniz:
import numpy as np from sklearn.decomposition import FastICA from scipy.io.wavfile import read, write Fs, s1 = read('kibarfeyzo.wav') Fs, s2 = read('gunah.wav') nSamples = len(s1) assert len(s1) == len(s2) s1 = np.float32(s1) s2 = np.float32(s2) S = np.c_[s1, s2] A = np.array([[1, 0.8], [1, 2]]) # Karışım matrisi X = np.dot(S, A) # Gözlemleri üret ica = FastICA() S_ = ica.fit(X).transform(X) # Kaynakları tahmin et x1, x2 = X[:,0], X[:,1] x1 = x1 / np.max(np.abs(x1)) * 255 x2 = x2 / np.max(np.abs(x2)) * 255 write('x1.wav', Fs, np.uint8(x1)) write('x2.wav', Fs, np.uint8(x2)) s1, s2 = S_[:,0], S_[:,1] s1 = s1 / np.max(np.abs(s1)) * 255 s2 = s2 / np.max(np.abs(s2)) * 255 write('s1.wav', Fs, np.uint8(s1)) write('s2.wav', Fs, np.uint8(s2))
2 yorum
Selam İsmail, bu harika bir işlemmiş yahu. Sağolasın haberdar ettiğin için.
Bağımsız Bileşenler Analizi'ni stereo bir ses kaydının iki kanalına uygularsak ne olur peki? Laylay...
Rica ederim Uğur :) Eğer kanallar arasında fark varsa 2 bağımsız bileşene ayıracaktır. Deneyip bakmak lazım.