欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

如何使用pytorch構(gòu)建高斯混合模型分類(lèi)器

 更新時(shí)間:2023年10月22日 09:34:29   作者:deephub  
本文是一個(gè)利用Pytorch構(gòu)建高斯混合模型分類(lèi)器的嘗試,我們將從頭開(kāi)始構(gòu)建高斯混合模型(GMM),這樣可以對(duì)高斯混合模型有一個(gè)最基本的理解,本文不會(huì)涉及數(shù)學(xué),需要的朋友可以參考下

本文將使用這些庫(kù)

 import torch
 import numpy as np
 import matplotlib.pyplot as plt
 import matplotlib.colors as mcolors

我們將在二維上創(chuàng)建3個(gè)不同的高斯分布(a, B, mix),其中mix應(yīng)該是由a和B組成的分布。

首先,A和B的分布…

 n_samples = 1000
 A_means = torch.tensor( [-0.5, -0.5])
 A_stdevs = torch.tensor( [0.25, 0.25])
 B_means = torch.tensor( [0.5, 0.5])
 B_stdevs = torch.tensor( [0.25, 0.25])
 
 A_dist = torch.distributions.Normal( A_means, A_stdevs)
 A_samp = A_dist.sample( [n_samples])
 B_dist = torch.distributions.Normal( B_means, B_stdevs)
 B_samp = B_dist.sample( [n_samples])
 
 
 plt.figure( figsize=(6,6))
 for name, sample in zip( ['A', 'B'], [A_samp, B_samp]):
     plt.scatter( sample[:,0], sample[:, 1], alpha=0.2, label=name)
 plt.legend()
 plt.title( "Distinct Gaussian Samples")
 plt.show()
 plt.close()

為了創(chuàng)建一個(gè)單一的混合高斯分布,我們首先垂直堆疊a和B的均值和標(biāo)準(zhǔn)差,生成新的張量,每個(gè)張量的形狀=[2,2]。

 AB_means = torch.vstack( [ A_means, B_means])
 AB_stdevs = torch.vstack( [ A_stdevs, B_stdevs])

pytorch混合分布的工作方式是通過(guò)在原始的Normal分布上使用3個(gè)額外的分布Independent、Categorical和MixtureSameFamily來(lái)實(shí)現(xiàn)的。從本質(zhì)上講,它創(chuàng)建了一個(gè)混合,基于給定Categorical分布的概率權(quán)重。因?yàn)槲覀兊男戮岛蜆?biāo)準(zhǔn)集有一個(gè)額外的軸,這個(gè)軸被用作獨(dú)立的軸,需要決定從中得出哪個(gè)均值/標(biāo)準(zhǔn)集的值。

 AB_means = torch.vstack( [ A_means, B_means])
 AB_stdevs = torch.vstack( [ A_stdevs, B_stdevs])
 
 AB_dist = torch.distributions.Independent( torch.distributions.Normal( AB_means, AB_stdevs), 1)
 mix_weight = torch.distributions.Categorical( torch.tensor( [1.0, 1.0]))
 mix_dist = torch.distributions.MixtureSameFamily( mix_weight, AB_dist)

在這里用[1.0,1.0]表示Categorical分布應(yīng)該從每個(gè)獨(dú)立的軸上均勻取樣。為了驗(yàn)證它是否有效,我們將繪制每個(gè)分布的值…

 A_samp = A_dist.sample( (500,))
 B_samp = B_dist.sample( (500,))
 mix_samp = mix_dist.sample( (500,))
 plt.figure( figsize=(6,6))
 for name, sample in zip( ['A', 'B', 'mix'], [A_samp, B_samp, mix_samp]):
     plt.scatter( sample[:,0], sample[:, 1], alpha=0.3, label=name)
 plt.legend()
 plt.title( "Original Samples with the new Mixed Distribution")
 plt.show()
 plt.close()

可以看到,的新mix_samp分布實(shí)際上與我們?cè)瓉?lái)的兩個(gè)單獨(dú)的A和B分布樣本重疊。

模型

下面就可以開(kāi)始構(gòu)建我們的分類(lèi)器了

首先需要?jiǎng)?chuàng)建一個(gè)底層的GaussianMixModel,它的means、stdev和分類(lèi)權(quán)重實(shí)際上可以通過(guò)torch backprop和autograd系統(tǒng)進(jìn)行訓(xùn)練。

 class GaussianMixModel( torch.nn.Module):
     
     def __init__(self, n_features, n_components=2):
         super().__init__()
 
         self.init_scale = np.sqrt( 6 / n_features) # What is the best scale to use?
         self.n_features = n_features
         self.n_components = n_components
 
         weights = torch.ones( n_components)
         means = torch.randn( n_components, n_features) * self.init_scale
         stdevs = torch.rand( n_components, n_features) * self.init_scale
         
         #
         # Our trainable Parameters
         self.blend_weight = torch.nn.Parameter(weights)
         self.means = torch.nn.Parameter(means)
         self.stdevs = torch.nn.Parameter(stdevs)
 
     
     def forward(self, x):
 
         blend_weight = torch.distributions.Categorical( torch.nn.functional.relu( self.blend_weight))
         comp = torch.distributions.Independent(torch.distributions.Normal( self.means, torch.abs( self.stdevs)), 1)
         gmm = torch.distributions.MixtureSameFamily( blend_weight, comp)
         return -gmm.log_prob(x)
     
     def extra_repr(self) -> str:
         info = f" n_features={self.n_features}, n_components={self.n_components}, [init_scale={self.init_scale}]"
         return info
 
     @property
     def device(self):
         return next(self.parameters()).device

該模型將返回落在模型的混合高斯分布域中的每個(gè)樣本的負(fù)對(duì)數(shù)似然。

為了訓(xùn)練它,我們需要從混合高斯分布中提供樣本。為了驗(yàn)證它是有效的,將提供一個(gè)普遍分布的一批樣本,看看它是否可以,哪些樣本可能與我們的訓(xùn)練集中的樣本相似。

 train_means = torch.randn( (4,2))
 train_stdevs = (torch.rand( (4,2)) + 1.0) * 0.25
 train_weights = torch.rand( 4)
 ind_dists = torch.distributions.Independent( torch.distributions.Normal( train_means, train_stdevs), 1)
 mix_weight = torch.distributions.Categorical( train_weights)
 train_dist = torch.distributions.MixtureSameFamily( mix_weight, ind_dists)
 
 train_samp = train_dist.sample( [2000])
 valid_samp = torch.rand( (4000, 2)) * 8 - 4.0
 
 plt.figure( figsize=(6,6))
 for name, sample in zip( ['train', 'valid'], [train_samp, valid_samp]):
     plt.scatter( sample[:,0], sample[:, 1], alpha=0.2, label=name)
 plt.legend()
 plt.title( "Training and Validation Samples")
 plt.show()
 plt.close()

模型只需要一個(gè)超參數(shù)n_components:

 gmm = GaussianMixModel( n_features=2, n_components=4)
 gmm.to( 'cuda')

訓(xùn)練的循環(huán)也非常簡(jiǎn)單:

 max_iter = 20000
 features = train_samp.to( 'cuda')
 
 optim = torch.optim.Adam( gmm.parameters(),  lr=5e-4)
 metrics = {'loss':[]}
 
 for i in range( max_iter):
     optim.zero_grad()
     loss = gmm(  features)
     loss.mean().backward()
     optim.step()
     metrics[ 'loss'].append( loss.mean().item())
     print( f"{i} ) \t {metrics[ 'loss'][-1]:0.5f}", end=f"{' '*20}\r")
     if metrics[ 'loss'][-1] < 0.1:
         print( "---- Close enough")
         break
     if len( metrics[ 'loss']) > 300 and np.std( metrics[ 'loss'][-300:]) < 0.0005:
         print( "---- Giving up")
         break
 print( f"Min Loss: {np.min( metrics[ 'loss']):0.5f}")

在這個(gè)例子中,循環(huán)在在1.91043的損失時(shí)停止了不到7000次迭代。

如果我們現(xiàn)在通過(guò)模型運(yùn)行valid_samp樣本,可以將返回值轉(zhuǎn)換為相對(duì)概率,并重新繪制由預(yù)測(cè)著色的驗(yàn)證數(shù)據(jù)。

 with torch.no_grad():
     logits = gmm( valid_samp.to( 'cuda'))
     probs = torch.exp( -logits)
     
 plt.figure( figsize=(6,6))
 for name, sample in zip( ['pred'], [valid_samp]):
     plt.scatter( sample[:,0], sample[:, 1], alpha=1.0, c=probs.cpu().numpy(), label=name)
 plt.legend()
 plt.title( "Testing Trained model on Validation")
 plt.show()
 plt.close()

我們的模型已經(jīng)學(xué)會(huì)了識(shí)別與訓(xùn)練分布區(qū)域?qū)?yīng)的樣本。但是我們還可以進(jìn)行改進(jìn)

分類(lèi)

通過(guò)上面的介紹應(yīng)該已經(jīng)對(duì)如何創(chuàng)建高斯混合模型以及如何訓(xùn)練它有了大致的了解,下一步將使用這些信息來(lái)構(gòu)建一個(gè)復(fù)合(GMMClassifier)模型,該模型可以學(xué)習(xí)識(shí)別混合高斯分布的不同類(lèi)別。

這里創(chuàng)建了一個(gè)重疊高斯分布的訓(xùn)練集,5個(gè)不同的類(lèi),其中每個(gè)類(lèi)本身是一個(gè)混合高斯分布。

這個(gè)GMMClassifier將包含5個(gè)不同的GaussianMixModel實(shí)例。每個(gè)實(shí)例都會(huì)嘗試從訓(xùn)練數(shù)據(jù)中學(xué)習(xí)一個(gè)單獨(dú)的類(lèi)。每個(gè)預(yù)測(cè)將組合成一組分類(lèi)邏輯,GMMClassifier將使用這些邏輯進(jìn)行預(yù)測(cè)。

首先需要對(duì)原始的GaussianMixModel做一個(gè)小的修改,并將輸出從return -gmm.log_prob(x)更改為return gmm.log_prob(x)。因?yàn)槲覀儧](méi)有在訓(xùn)練循環(huán)中直接嘗試減少這個(gè)值,所以它被用作我們分類(lèi)分配的logits。

新的模型就變成了……

 class GaussianMixModel( torch.nn.Module):
     
     def __init__(self, n_features, n_components=2):
         super().__init__()
 
         self.init_scale = np.sqrt( 6 / n_features) # What is the best scale to use?
         self.n_features = n_features
         self.n_components = n_components
 
         weights = torch.ones( n_components)
         means = torch.randn( n_components, n_features) * self.init_scale
         stdevs = torch.rand( n_components, n_features) * self.init_scale
         
         #
         # Our trainable Parameters
         self.blend_weight = torch.nn.Parameter(weights)
         self.means = torch.nn.Parameter(means)
         self.stdevs = torch.nn.Parameter(stdevs)
 
     
     def forward(self, x):
 
         blend_weight = torch.distributions.Categorical( torch.nn.functional.relu( self.blend_weight))
         comp = torch.distributions.Independent(torch.distributions.Normal( self.means, torch.abs( self.stdevs)), 1)
         gmm = torch.distributions.MixtureSameFamily( blend_weight, comp)
         return gmm.log_prob(x)
     
     def extra_repr(self) -> str:
         info = f" n_features={self.n_features}, n_components={self.n_components}, [init_scale={self.init_scale}]"
         return info
 
     @property
     def device(self):
         return next(self.parameters()).device

我們的GMMClassifier的代碼如下:

 class GMMClassifier( torch.nn.Module):
     
     def __init__(self, n_features, n_classes, n_components=2):
         super().__init__()
         self.n_classes = n_classes
         self.n_features = n_features
         self.n_components = n_components if isinstance( n_components, list) else [n_components] * self.n_classes
         self.class_models = torch.nn.ModuleList( [ GaussianMixModel( n_features=self.n_features, n_components=self.n_components[i]) for i in range( self.n_classes)])
         
     
     def forward(self, x, ret_logits=False):
         logits = torch.hstack( [ m(x).unsqueeze(1) for m in self.class_models])
         if ret_logits:
             return logits
         return logits.argmax( dim=1)
     
     def extra_repr(self) -> str:
         info = f" n_features={self.n_features}, n_components={self.n_components}, [n_classes={self.n_classes}]"
         return info
 
     @property
     def device(self):
         return next(self.parameters()).device

創(chuàng)建模型實(shí)例時(shí),將為每個(gè)類(lèi)創(chuàng)建一個(gè)GaussianMixModel。由于每個(gè)類(lèi)對(duì)于其特定的高斯混合可能具有不同數(shù)量的組件,因此我們?cè)试Sn_components是一個(gè)int值列表,該列表將在生成每個(gè)底層模型時(shí)使用。例如:n_components=[2,4,3,5,6]將向類(lèi)模型傳遞正確數(shù)量的組件。為了簡(jiǎn)化將所有底層模型設(shè)置為相同的值,也可以簡(jiǎn)單地提供n_components=5,這將在生成模型時(shí)產(chǎn)生[5,5,5,5,5]。

在訓(xùn)練期間,需要訪問(wèn)logits,因此forward()方法中提供了ret_logits參數(shù)。訓(xùn)練完成后,可以在不帶參數(shù)的情況下調(diào)用forward(),以便為預(yù)測(cè)的類(lèi)返回一個(gè)int值(它只接受logits的argmax())。

我們還將創(chuàng)建一組5個(gè)獨(dú)立但重疊的高斯混合分布,每個(gè)類(lèi)有隨機(jī)數(shù)量的高斯分量。

 clusters = [0, 1, 2, 3, 4]
 features_group = {}
 n_samples = 2000
 min_clusters = 2
 max_clusters = 10
 for c in clusters:
     features_group[ c] = []
     n_clusters = torch.randint( min_clusters, max_clusters+1, (1,1)).item()
     print( f"Class: {c} Clusters: {n_clusters}")
     for i in range( n_clusters):
         mu = torch.randn( (1,2))
         scale = torch.rand( (1,2)) * 0.35 + 0.05
         distribution = torch.distributions.Normal( mu, scale)
         features_group[ c] += distribution.expand( (n_samples//n_clusters, 2)).sample()
     features_group[ c] = torch.vstack( features_group[ c])
 features = torch.vstack( [features_group[ c] for c in clusters]).numpy()
 targets = torch.vstack( [torch.ones( (features_group[ c].size(0), 1)) * c for c in clusters]).view( -1).numpy()
 
 idxs = np.arange( features.shape[0])
 valid_idxs = np.random.choice( idxs, 1000)
 train_idxs = [i for i in idxs if i not in valid_idxs]
 features_valid = torch.tensor( features[ valid_idxs])
 targets_valid = torch.tensor( targets[ valid_idxs])
 features = torch.tensor( features[ train_idxs])
 targets = torch.tensor( targets[ train_idxs])
 
 print( features.shape)
 plt.figure( figsize=(8,8))
 for c in clusters:
     plt.scatter( features_group[c][:,0].numpy(), features_group[c][:,1].numpy(), alpha=0.2, label=c)
 plt.title( f"{n_samples} Samples Per Class, Multiple Clusters per Class")
 plt.legend()

通過(guò)運(yùn)行上面的代碼,我們可以知道每個(gè)類(lèi)使用的n_component的數(shù)量。在實(shí)際中他應(yīng)該是一個(gè)超參數(shù)搜索過(guò)程,但是這里我們已經(jīng)知道了,所以我們直接使用它

 Class: 0 Clusters: 3
 Class: 1 Clusters: 5
 Class: 2 Clusters: 2
 Class: 3 Clusters: 8
 Class: 4 Clusters: 4

然后創(chuàng)建模型:

 gmmc = GMMClassifier(  n_features=2, n_classes=5, n_components=[3, 5, 2, 8, 4])
 gmmc.to( 'cuda')

訓(xùn)練循環(huán)也有一些修改,因?yàn)檫@次想要訓(xùn)練由logit預(yù)測(cè)提供的模型的分類(lèi)損失。所以需要在監(jiān)督學(xué)習(xí)的訓(xùn)練過(guò)程中提供目標(biāo)。

 features = features.to( DEVICE)
 targets = targets.to( DEVICE)
 
 optim = torch.optim.Adam( gmmc.parameters(), lr=3e-2)
 loss_fn = torch.nn.CrossEntropyLoss()
 metrics = {'loss':[]}
 for i in range(4000):
     optim.zero_grad()
     logits = gmmc(  features, ret_logits=True)
     loss = loss_fn( logits, targets.type( torch.long))
     loss.backward()
     optim.step()
     metrics[ 'loss'].append( loss.item())
     print( f"{i} ) \t {metrics[ 'loss'][-1]:0.5f}", end=f"{' '*20}\r")
     if metrics[ 'loss'][-1] < 0.1:
         print( "---- Close enough")
         break
 print( f"Mean Loss: {np.mean( metrics[ 'loss']):0.5f}")

然后從驗(yàn)證數(shù)據(jù)中對(duì)數(shù)據(jù)進(jìn)行分類(lèi),驗(yàn)證數(shù)據(jù)是在創(chuàng)建訓(xùn)練數(shù)據(jù)時(shí)生成的,每個(gè)樣本基本上都是不同的值,但來(lái)自適當(dāng)?shù)念?lèi)。

 preds = gmmc( features_valid.to( 'cuda'))

查看preds值,可以看到它們是預(yù)測(cè)類(lèi)的整數(shù)。

 print( preds[0:10])
 
 ____
 tensor([2, 4, 2, 4, 2, 3, 4, 0, 2, 2], device='cuda:1')

最后通過(guò)將這些值與targets_valid進(jìn)行比較,可以確定模型的準(zhǔn)確性。

 accuracy = (targets_valid == preds).sum() / targets_valid.size(0) * 100.0
 print( f"Accuracy: {accuracy:0.2f}%")
 
 ____
 Accuracy: 81.50%

還可以查看每個(gè)類(lèi)別預(yù)測(cè)的準(zhǔn)確性……

 class_acc = {}
 for c in range(5):
     target_idxs = (targets_valid == c)
     class_acc[c] = (targets_valid[ target_idxs] == preds[ target_idxs]).sum() / targets_valid[ target_idxs].size(0) * 100.0
     print( f"Class: {c} \t{class_acc[c]:0.2f}%")
 
 ----
 Class: 0  98.54%
 Class: 1  69.06%
 Class: 2  86.12%
 Class: 3  70.05%
 Class: 4  84.09%

可以看到,它在預(yù)測(cè)重疊較少的類(lèi)方面做得更好,這是有道理的。并且平均81.5%的準(zhǔn)確率也相當(dāng)不錯(cuò),因?yàn)樗羞@些不同的類(lèi)別都是重疊的。我相信還有很多可以改進(jìn)的地方。如果你有建議,或者可以指出我所犯的錯(cuò)誤,請(qǐng)留言。

以上就是如何使用pytorch實(shí)現(xiàn)高斯混合模型分類(lèi)器的詳細(xì)內(nèi)容,更多關(guān)于pytorch高斯混合模型分類(lèi)器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Python解決MySQL數(shù)據(jù)處理從SQL批量刪除報(bào)錯(cuò)

    Python解決MySQL數(shù)據(jù)處理從SQL批量刪除報(bào)錯(cuò)

    這篇文章主要為大家介紹了Python解決MySQL數(shù)據(jù)處理從SQL批量刪除報(bào)錯(cuò),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • 對(duì)Python生成器、裝飾器、遞歸的使用詳解

    對(duì)Python生成器、裝飾器、遞歸的使用詳解

    今天小編就為大家分享一篇對(duì)Python生成器、裝飾器、遞歸的使用詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-07-07
  • 用Python搶過(guò)年的火車(chē)票附源碼

    用Python搶過(guò)年的火車(chē)票附源碼

    離過(guò)年時(shí)間也不久了,還是預(yù)訂春節(jié)火車(chē)票了,現(xiàn)在有好多平臺(tái)都可以幫助大家搶購(gòu)火車(chē),下面小編給大家介紹用python搶過(guò)年的火車(chē)票附源碼,對(duì)pthon搶火車(chē)票相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧
    2015-12-12
  • Python?數(shù)據(jù)清洗刪除缺失值替換缺失值詳情

    Python?數(shù)據(jù)清洗刪除缺失值替換缺失值詳情

    這篇文章主要介紹了Python?數(shù)據(jù)清洗刪除缺失值替換缺失值詳情,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-09-09
  • cuda突然不能用了的完美解決方法

    cuda突然不能用了的完美解決方法

    這篇文章主要給大家介紹了關(guān)于cuda突然不能用了的完美解決方法,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用cuda具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2023-06-06
  • 11行Python代碼實(shí)現(xiàn)解密摩斯密碼

    11行Python代碼實(shí)現(xiàn)解密摩斯密碼

    摩爾斯電碼是一種時(shí)通時(shí)斷的信號(hào)代碼,通過(guò)不同的排列順序來(lái)表達(dá)不同的英文字母、數(shù)字和標(biāo)點(diǎn)符號(hào)。本文將通過(guò)Python代碼來(lái)實(shí)現(xiàn)解密摩斯密碼,感興趣的可以學(xué)習(xí)一下
    2022-04-04
  • Python新手學(xué)習(xí)函數(shù)默認(rèn)參數(shù)設(shè)置

    Python新手學(xué)習(xí)函數(shù)默認(rèn)參數(shù)設(shè)置

    在本篇文章里小編給大家分享的是關(guān)于Python新手學(xué)習(xí)函數(shù)默認(rèn)參數(shù)設(shè)置的相關(guān)知識(shí)點(diǎn),需要的朋友們可以參考下。
    2020-06-06
  • Macbook air m1安裝python/anaconda全過(guò)程(圖文)

    Macbook air m1安裝python/anaconda全過(guò)程(圖文)

    這篇文章主要介紹了Macbook air m1安裝python/anaconda全過(guò)程(圖文),文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • Python實(shí)現(xiàn)從概率分布中隨機(jī)采樣

    Python實(shí)現(xiàn)從概率分布中隨機(jī)采樣

    這篇文章主要介紹了通過(guò)幾個(gè)機(jī)器學(xué)習(xí)中最常用的概率分布為例,來(lái)看看如何從一個(gè)概率分布中采樣,文章中的代碼對(duì)我們的工作或?qū)W習(xí)具有一定價(jià)值,感興趣的朋友可以了解一下
    2021-12-12
  • Python利用pandas和matplotlib實(shí)現(xiàn)繪制堆疊柱狀圖

    Python利用pandas和matplotlib實(shí)現(xiàn)繪制堆疊柱狀圖

    在數(shù)據(jù)可視化中,堆疊柱狀圖是一種常用的圖表類(lèi)型,它能夠清晰地展示多個(gè)類(lèi)別的數(shù)據(jù),本文將演示如何使用 Python 的 pandas 和 matplotlib 庫(kù)繪制優(yōu)化的堆疊柱狀圖,需要的可以參考下
    2023-11-11

最新評(píng)論